imx6_anatop.c revision 266201
1/*- 2 * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> 3 * Copyright (c) 2014 Steven Lawrance <stl@koffein.net> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/10/sys/arm/freescale/imx/imx6_anatop.c 266201 2014-05-15 22:50:06Z ian $"); 30 31/* 32 * Analog PLL and power regulator driver for Freescale i.MX6 family of SoCs. 33 * Also, temperature montoring and cpu frequency control. It was Freescale who 34 * kitchen-sinked this device, not us. :) 35 * 36 * We don't really do anything with analog PLLs, but the registers for 37 * controlling them belong to the same block as the power regulator registers. 38 * Since the newbus hierarchy makes it hard for anyone other than us to get at 39 * them, we just export a couple public functions to allow the imx6 CCM clock 40 * driver to read and write those registers. 41 * 42 * We also don't do anything about power regulation yet, but when the need 43 * arises, this would be the place for that code to live. 44 * 45 * I have no idea where the "anatop" name comes from. It's in the standard DTS 46 * source describing i.MX6 SoCs, and in the linux and u-boot code which comes 47 * from Freescale, but it's not in the SoC manual. 48 * 49 * Note that temperature values throughout this code are handled in two types of 50 * units. Items with '_cnt' in the name use the hardware temperature count 51 * units (higher counts are lower temperatures). Items with '_val' in the name 52 * are deci-Celcius, which are converted to/from deci-Kelvins in the sysctl 53 * handlers (dK is the standard unit for temperature in sysctl). 54 */ 55 56#include <sys/param.h> 57#include <sys/systm.h> 58#include <sys/callout.h> 59#include <sys/kernel.h> 60#include <sys/sysctl.h> 61#include <sys/module.h> 62#include <sys/bus.h> 63#include <sys/rman.h> 64 65#include <dev/ofw/ofw_bus.h> 66#include <dev/ofw/ofw_bus_subr.h> 67 68#include <machine/bus.h> 69 70#include <arm/freescale/fsl_ocotpreg.h> 71#include <arm/freescale/fsl_ocotpvar.h> 72#include <arm/freescale/imx/imx6_anatopreg.h> 73#include <arm/freescale/imx/imx6_anatopvar.h> 74 75static struct resource_spec imx6_anatop_spec[] = { 76 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 77 { SYS_RES_IRQ, 0, RF_ACTIVE }, 78 { -1, 0 } 79}; 80#define MEMRES 0 81#define IRQRES 1 82 83struct imx6_anatop_softc { 84 device_t dev; 85 struct resource *res[2]; 86 uint32_t cpu_curhz; 87 uint32_t cpu_curmhz; 88 uint32_t cpu_minhz; 89 uint32_t cpu_maxhz; 90 uint32_t refosc_hz; 91 void *temp_intrhand; 92 uint32_t temp_high_val; 93 uint32_t temp_high_cnt; 94 uint32_t temp_last_cnt; 95 uint32_t temp_room_cnt; 96 struct callout temp_throttle_callout; 97 sbintime_t temp_throttle_delay; 98 uint32_t temp_throttle_reset_cnt; 99 uint32_t temp_throttle_trigger_cnt; 100 uint32_t temp_throttle_val; 101}; 102 103static struct imx6_anatop_softc *imx6_anatop_sc; 104 105/* 106 * Table of CPU max frequencies. This is indexed by the max frequency value 107 * (0-3) from the ocotp CFG3 register. 108 */ 109static uint32_t imx6_cpu_maxhz_tab[] = { 110 792000000, 852000000, 996000000, 1200000000 111}; 112 113#define TZ_ZEROC 2732 /* deci-Kelvin <-> deci-Celcius offset. */ 114 115uint32_t 116imx6_anatop_read_4(bus_size_t offset) 117{ 118 119 KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_read_4 sc NULL")); 120 121 return (bus_read_4(imx6_anatop_sc->res[MEMRES], offset)); 122} 123 124void 125imx6_anatop_write_4(bus_size_t offset, uint32_t value) 126{ 127 128 KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_write_4 sc NULL")); 129 130 bus_write_4(imx6_anatop_sc->res[MEMRES], offset, value); 131} 132 133static inline uint32_t 134cpufreq_hz_from_div(struct imx6_anatop_softc *sc, uint32_t div) 135{ 136 137 return (sc->refosc_hz * (div / 2)); 138} 139 140static inline uint32_t 141cpufreq_hz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_hz) 142{ 143 144 return (cpu_hz / (sc->refosc_hz / 2)); 145} 146 147static inline uint32_t 148cpufreq_actual_hz(struct imx6_anatop_softc *sc, uint32_t cpu_hz) 149{ 150 151 return (cpufreq_hz_from_div(sc, cpufreq_hz_to_div(sc, cpu_hz))); 152} 153 154static void 155cpufreq_set_clock(struct imx6_anatop_softc * sc, uint32_t cpu_newhz) 156{ 157 uint32_t div, timeout, wrk32; 158 const uint32_t mindiv = 54; 159 const uint32_t maxdiv = 108; 160 161 /* 162 * Clip the requested frequency to the configured max, then clip the 163 * resulting divisor to the documented min/max values. 164 */ 165 cpu_newhz = min(cpu_newhz, sc->cpu_maxhz); 166 div = cpufreq_hz_to_div(sc, cpu_newhz); 167 if (div < mindiv) 168 div = mindiv; 169 else if (div > maxdiv) 170 div = maxdiv; 171 sc->cpu_curhz = cpufreq_hz_from_div(sc, div); 172 sc->cpu_curmhz = sc->cpu_curhz / 1000000; 173 174 /* 175 * I can't find a documented procedure for changing the ARM PLL divisor, 176 * but some trial and error came up with this: 177 * - Set the bypass clock source to REF_CLK_24M (source #0). 178 * - Set the PLL into bypass mode; cpu should now be running at 24mhz. 179 * - Change the divisor. 180 * - Wait for the LOCK bit to come on; it takes ~50 loop iterations. 181 * - Turn off bypass mode; cpu should now be running at cpu_newhz. 182 */ 183 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 184 IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK); 185 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_SET, 186 IMX6_ANALOG_CCM_PLL_ARM_BYPASS); 187 188 wrk32 = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM); 189 wrk32 &= ~IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; 190 wrk32 |= div; 191 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM, wrk32); 192 193 timeout = 10000; 194 while ((imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & 195 IMX6_ANALOG_CCM_PLL_ARM_LOCK) == 0) 196 if (--timeout == 0) 197 panic("imx6_set_cpu_clock(): PLL never locked"); 198 199 imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 200 IMX6_ANALOG_CCM_PLL_ARM_BYPASS); 201} 202 203static void 204cpufreq_initialize(struct imx6_anatop_softc *sc) 205{ 206 uint32_t cfg3speed; 207 struct sysctl_ctx_list *ctx; 208 209 ctx = device_get_sysctl_ctx(sc->dev); 210 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 211 OID_AUTO, "cpu_mhz", CTLFLAG_RD, &sc->cpu_curmhz, 0, 212 "CPU frequency in MHz"); 213 214 /* 215 * XXX 24mhz shouldn't be hard-coded, should get this from imx6_ccm 216 * (even though in the real world it will always be 24mhz). Oh wait a 217 * sec, I never wrote imx6_ccm. 218 */ 219 sc->refosc_hz = 24000000; 220 221 /* 222 * Get the maximum speed this cpu can be set to. The values in the 223 * OCOTP CFG3 register are not documented in the reference manual. 224 * The following info was in an archived email found via web search: 225 * - 2b'11: 1200000000Hz; 226 * - 2b'10: 996000000Hz; 227 * - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. 228 * - 2b'00: 792000000Hz; 229 */ 230 cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & 231 FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT; 232 233 sc->cpu_minhz = cpufreq_actual_hz(sc, imx6_cpu_maxhz_tab[0]); 234 sc->cpu_maxhz = cpufreq_actual_hz(sc, imx6_cpu_maxhz_tab[cfg3speed]); 235 236 /* 237 * Set the CPU to maximum speed. 238 * 239 * We won't have thermal throttling until interrupts are enabled, but we 240 * want to run at full speed through all the device init stuff. This 241 * basically assumes that a single core can't overheat before interrupts 242 * are enabled; empirical testing shows that to be a safe assumption. 243 */ 244 cpufreq_set_clock(sc, sc->cpu_maxhz); 245 device_printf(sc->dev, "CPU frequency %uMHz\n", sc->cpu_curmhz); 246} 247 248static inline uint32_t 249temp_from_count(struct imx6_anatop_softc *sc, uint32_t count) 250{ 251 252 return (((sc->temp_high_val - (count - sc->temp_high_cnt) * 253 (sc->temp_high_val - 250) / 254 (sc->temp_room_cnt - sc->temp_high_cnt)))); 255} 256 257static inline uint32_t 258temp_to_count(struct imx6_anatop_softc *sc, uint32_t temp) 259{ 260 261 return ((sc->temp_room_cnt - sc->temp_high_cnt) * 262 (sc->temp_high_val - temp) / (sc->temp_high_val - 250) + 263 sc->temp_high_cnt); 264} 265 266static void 267temp_update_count(struct imx6_anatop_softc *sc) 268{ 269 uint32_t val; 270 271 val = imx6_anatop_read_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0); 272 if (!(val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_VALID)) 273 return; 274 sc->temp_last_cnt = 275 (val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >> 276 IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT; 277} 278 279static int 280temp_sysctl_handler(SYSCTL_HANDLER_ARGS) 281{ 282 struct imx6_anatop_softc *sc = arg1; 283 uint32_t t; 284 285 temp_update_count(sc); 286 287 t = temp_from_count(sc, sc->temp_last_cnt) + TZ_ZEROC; 288 289 return (sysctl_handle_int(oidp, &t, 0, req)); 290} 291 292static int 293temp_throttle_sysctl_handler(SYSCTL_HANDLER_ARGS) 294{ 295 struct imx6_anatop_softc *sc = arg1; 296 int err; 297 uint32_t temp; 298 299 temp = sc->temp_throttle_val + TZ_ZEROC; 300 err = sysctl_handle_int(oidp, &temp, 0, req); 301 if (temp < TZ_ZEROC) 302 return (ERANGE); 303 temp -= TZ_ZEROC; 304 if (err != 0 || req->newptr == NULL || temp == sc->temp_throttle_val) 305 return (err); 306 307 /* Value changed, update counts in softc and hardware. */ 308 sc->temp_throttle_val = temp; 309 sc->temp_throttle_trigger_cnt = temp_to_count(sc, sc->temp_throttle_val); 310 sc->temp_throttle_reset_cnt = temp_to_count(sc, sc->temp_throttle_val - 100); 311 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_CLR, 312 IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_MASK); 313 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_SET, 314 (sc->temp_throttle_trigger_cnt << 315 IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT)); 316 return (err); 317} 318 319static void 320tempmon_gofast(struct imx6_anatop_softc *sc) 321{ 322 323 if (sc->cpu_curhz < sc->cpu_maxhz) { 324 cpufreq_set_clock(sc, sc->cpu_maxhz); 325 } 326} 327 328static void 329tempmon_goslow(struct imx6_anatop_softc *sc) 330{ 331 332 if (sc->cpu_curhz > sc->cpu_minhz) { 333 cpufreq_set_clock(sc, sc->cpu_minhz); 334 } 335} 336 337static int 338tempmon_intr(void *arg) 339{ 340 struct imx6_anatop_softc *sc = arg; 341 342 /* 343 * XXX Note that this code doesn't currently run (for some mysterious 344 * reason we just never get an interrupt), so the real monitoring is 345 * done by tempmon_throttle_check(). 346 */ 347 tempmon_goslow(sc); 348 /* XXX Schedule callout to speed back up eventually. */ 349 return (FILTER_HANDLED); 350} 351 352static void 353tempmon_throttle_check(void *arg) 354{ 355 struct imx6_anatop_softc *sc = arg; 356 357 /* Lower counts are higher temperatures. */ 358 if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt) 359 tempmon_goslow(sc); 360 else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt)) 361 tempmon_gofast(sc); 362 363 callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 364 0, tempmon_throttle_check, sc, 0); 365 366} 367 368static void 369initialize_tempmon(struct imx6_anatop_softc *sc) 370{ 371 uint32_t cal; 372 struct sysctl_ctx_list *ctx; 373 374 /* 375 * Fetch calibration data: a sensor count at room temperature (25C), 376 * a sensor count at a high temperature, and that temperature 377 */ 378 cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1); 379 sc->temp_room_cnt = (cal & 0xFFF00000) >> 20; 380 sc->temp_high_cnt = (cal & 0x000FFF00) >> 8; 381 sc->temp_high_val = (cal & 0x000000FF) * 10; 382 383 /* 384 * Throttle to a lower cpu freq at 10C below the "hot" temperature, and 385 * reset back to max cpu freq at 5C below the trigger. 386 */ 387 sc->temp_throttle_val = sc->temp_high_val - 100; 388 sc->temp_throttle_trigger_cnt = 389 temp_to_count(sc, sc->temp_throttle_val); 390 sc->temp_throttle_reset_cnt = 391 temp_to_count(sc, sc->temp_throttle_val - 50); 392 393 /* 394 * Set the sensor to sample automatically at 16Hz (32.768KHz/0x800), set 395 * the throttle count, and begin making measurements. 396 */ 397 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE1, 0x0800); 398 imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0, 399 (sc->temp_throttle_trigger_cnt << 400 IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) | 401 IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE); 402 403 /* 404 * XXX Note that the alarm-interrupt feature isn't working yet, so 405 * we'll use a callout handler to check at 10Hz. Make sure we have an 406 * initial temperature reading before starting up the callouts so we 407 * don't get a bogus reading of zero. 408 */ 409 while (sc->temp_last_cnt == 0) 410 temp_update_count(sc); 411 sc->temp_throttle_delay = 100 * SBT_1MS; 412 callout_init(&sc->temp_throttle_callout, 0); 413 callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 414 0, tempmon_throttle_check, sc, 0); 415 416 ctx = device_get_sysctl_ctx(sc->dev); 417 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 418 OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 419 temp_sysctl_handler, "IK", "Current die temperature"); 420 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 421 OID_AUTO, "throttle_temperature", CTLTYPE_INT | CTLFLAG_RW, sc, 422 0, temp_throttle_sysctl_handler, "IK", 423 "Throttle CPU when exceeding this temperature"); 424} 425 426static int 427imx6_anatop_detach(device_t dev) 428{ 429 430 return (EBUSY); 431} 432 433static int 434imx6_anatop_attach(device_t dev) 435{ 436 struct imx6_anatop_softc *sc; 437 int err; 438 439 sc = device_get_softc(dev); 440 sc->dev = dev; 441 442 /* Allocate bus_space resources. */ 443 if (bus_alloc_resources(dev, imx6_anatop_spec, sc->res)) { 444 device_printf(dev, "Cannot allocate resources\n"); 445 err = ENXIO; 446 goto out; 447 } 448 449 err = bus_setup_intr(dev, sc->res[IRQRES], INTR_TYPE_MISC | INTR_MPSAFE, 450 tempmon_intr, NULL, sc, &sc->temp_intrhand); 451 if (err != 0) 452 goto out; 453 454 imx6_anatop_sc = sc; 455 456 /* 457 * Other code seen on the net sets this SELFBIASOFF flag around the same 458 * time the temperature sensor is set up, although it's unclear how the 459 * two are related (if at all). 460 */ 461 imx6_anatop_write_4(IMX6_ANALOG_PMU_MISC0_SET, 462 IMX6_ANALOG_PMU_MISC0_SELFBIASOFF); 463 464 cpufreq_initialize(sc); 465 initialize_tempmon(sc); 466 467 err = 0; 468 469out: 470 471 if (err != 0) { 472 bus_release_resources(dev, imx6_anatop_spec, sc->res); 473 } 474 475 return (err); 476} 477 478static int 479imx6_anatop_probe(device_t dev) 480{ 481 482 if (!ofw_bus_status_okay(dev)) 483 return (ENXIO); 484 485 if (ofw_bus_is_compatible(dev, "fsl,imx6q-anatop") == 0) 486 return (ENXIO); 487 488 device_set_desc(dev, "Freescale i.MX6 Analog PLLs and Power"); 489 490 return (BUS_PROBE_DEFAULT); 491} 492 493uint32_t 494imx6_get_cpu_clock() 495{ 496 uint32_t div; 497 498 div = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & 499 IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; 500 return (cpufreq_hz_from_div(imx6_anatop_sc, div)); 501} 502 503static device_method_t imx6_anatop_methods[] = { 504 /* Device interface */ 505 DEVMETHOD(device_probe, imx6_anatop_probe), 506 DEVMETHOD(device_attach, imx6_anatop_attach), 507 DEVMETHOD(device_detach, imx6_anatop_detach), 508 509 DEVMETHOD_END 510}; 511 512static driver_t imx6_anatop_driver = { 513 "imx6_anatop", 514 imx6_anatop_methods, 515 sizeof(struct imx6_anatop_softc) 516}; 517 518static devclass_t imx6_anatop_devclass; 519 520DRIVER_MODULE(imx6_anatop, simplebus, imx6_anatop_driver, imx6_anatop_devclass, 0, 0); 521 522