1257453Sian/*- 2257453Sian * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> 3266201Sian * Copyright (c) 2014 Steven Lawrance <stl@koffein.net> 4257453Sian * All rights reserved. 5257453Sian * 6257453Sian * Redistribution and use in source and binary forms, with or without 7257453Sian * modification, are permitted provided that the following conditions 8257453Sian * are met: 9257453Sian * 1. Redistributions of source code must retain the above copyright 10257453Sian * notice, this list of conditions and the following disclaimer. 11257453Sian * 2. Redistributions in binary form must reproduce the above copyright 12257453Sian * notice, this list of conditions and the following disclaimer in the 13257453Sian * documentation and/or other materials provided with the distribution. 14257453Sian * 15257453Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16257453Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17257453Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18257453Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19257453Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20257453Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21257453Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22257453Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23257453Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24257453Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25257453Sian * SUCH DAMAGE. 26257453Sian */ 27257453Sian 28257453Sian#include <sys/cdefs.h> 29257453Sian__FBSDID("$FreeBSD$"); 30257453Sian 31257453Sian/* 32257453Sian * Analog PLL and power regulator driver for Freescale i.MX6 family of SoCs. 33266201Sian * Also, temperature montoring and cpu frequency control. It was Freescale who 34266201Sian * kitchen-sinked this device, not us. :) 35257453Sian * 36257453Sian * We don't really do anything with analog PLLs, but the registers for 37257453Sian * controlling them belong to the same block as the power regulator registers. 38257453Sian * Since the newbus hierarchy makes it hard for anyone other than us to get at 39257453Sian * them, we just export a couple public functions to allow the imx6 CCM clock 40257453Sian * driver to read and write those registers. 41257453Sian * 42257453Sian * We also don't do anything about power regulation yet, but when the need 43257453Sian * arises, this would be the place for that code to live. 44257453Sian * 45257453Sian * I have no idea where the "anatop" name comes from. It's in the standard DTS 46257453Sian * source describing i.MX6 SoCs, and in the linux and u-boot code which comes 47257453Sian * from Freescale, but it's not in the SoC manual. 48266201Sian * 49266201Sian * Note that temperature values throughout this code are handled in two types of 50266201Sian * units. Items with '_cnt' in the name use the hardware temperature count 51266201Sian * units (higher counts are lower temperatures). Items with '_val' in the name 52266201Sian * are deci-Celcius, which are converted to/from deci-Kelvins in the sysctl 53266201Sian * handlers (dK is the standard unit for temperature in sysctl). 54257453Sian */ 55257453Sian 56257453Sian#include <sys/param.h> 57257453Sian#include <sys/systm.h> 58266201Sian#include <sys/callout.h> 59257453Sian#include <sys/kernel.h> 60266352Sian#include <sys/limits.h> 61266201Sian#include <sys/sysctl.h> 62257453Sian#include <sys/module.h> 63257453Sian#include <sys/bus.h> 64257453Sian#include <sys/rman.h> 65257453Sian 66257453Sian#include <dev/ofw/ofw_bus.h> 67257453Sian#include <dev/ofw/ofw_bus_subr.h> 68257453Sian 69257453Sian#include <machine/bus.h> 70266207Sian#include <machine/fdt.h> 71257453Sian 72266348Sian#include <arm/arm/mpcore_timervar.h> 73266201Sian#include <arm/freescale/fsl_ocotpreg.h> 74266201Sian#include <arm/freescale/fsl_ocotpvar.h> 75283501Sian#include <arm/freescale/imx/imx_ccmvar.h> 76294678Sian#include <arm/freescale/imx/imx_machdep.h> 77257453Sian#include <arm/freescale/imx/imx6_anatopreg.h> 78257453Sian#include <arm/freescale/imx/imx6_anatopvar.h> 79257453Sian 80266201Sianstatic struct resource_spec imx6_anatop_spec[] = { 81266201Sian { SYS_RES_MEMORY, 0, RF_ACTIVE }, 82266201Sian { SYS_RES_IRQ, 0, RF_ACTIVE }, 83266201Sian { -1, 0 } 84266201Sian}; 85266201Sian#define MEMRES 0 86266201Sian#define IRQRES 1 87266201Sian 88257453Sianstruct imx6_anatop_softc { 89257453Sian device_t dev; 90266201Sian struct resource *res[2]; 91273656Sian struct intr_config_hook 92273656Sian intr_setup_hook; 93266201Sian uint32_t cpu_curmhz; 94266207Sian uint32_t cpu_curmv; 95266352Sian uint32_t cpu_minmhz; 96266207Sian uint32_t cpu_minmv; 97266352Sian uint32_t cpu_maxmhz; 98266207Sian uint32_t cpu_maxmv; 99266352Sian uint32_t cpu_maxmhz_hw; 100266352Sian boolean_t cpu_overclock_enable; 101273679Sian boolean_t cpu_init_done; 102266352Sian uint32_t refosc_mhz; 103266201Sian void *temp_intrhand; 104266201Sian uint32_t temp_high_val; 105266201Sian uint32_t temp_high_cnt; 106266201Sian uint32_t temp_last_cnt; 107266201Sian uint32_t temp_room_cnt; 108266201Sian struct callout temp_throttle_callout; 109266201Sian sbintime_t temp_throttle_delay; 110266201Sian uint32_t temp_throttle_reset_cnt; 111266201Sian uint32_t temp_throttle_trigger_cnt; 112266201Sian uint32_t temp_throttle_val; 113257453Sian}; 114257453Sian 115257453Sianstatic struct imx6_anatop_softc *imx6_anatop_sc; 116257453Sian 117266201Sian/* 118266352Sian * Table of "operating points". 119266352Sian * These are combinations of frequency and voltage blessed by Freescale. 120283501Sian * While the datasheet says the ARM voltage can be as low as 925mV at 121283501Sian * 396MHz, it also says that the ARM and SOC voltages can't differ by 122283501Sian * more than 200mV, and the minimum SOC voltage is 1150mV, so that 123283501Sian * dictates the 950mV entry in this table. 124266201Sian */ 125266352Sianstatic struct oppt { 126266352Sian uint32_t mhz; 127266352Sian uint32_t mv; 128266352Sian} imx6_oppt_table[] = { 129283501Sian { 396, 950}, 130266352Sian { 792, 1150}, 131266352Sian { 852, 1225}, 132266352Sian { 996, 1225}, 133266352Sian {1200, 1275}, 134266201Sian}; 135266201Sian 136266352Sian/* 137266352Sian * Table of CPU max frequencies. This is used to translate the max frequency 138266352Sian * value (0-3) from the ocotp CFG3 register into a mhz value that can be looked 139266352Sian * up in the operating points table. 140266352Sian */ 141266352Sianstatic uint32_t imx6_ocotp_mhz_tab[] = {792, 852, 996, 1200}; 142266352Sian 143266201Sian#define TZ_ZEROC 2732 /* deci-Kelvin <-> deci-Celcius offset. */ 144266201Sian 145257453Sianuint32_t 146257453Sianimx6_anatop_read_4(bus_size_t offset) 147257453Sian{ 148257453Sian 149266201Sian KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_read_4 sc NULL")); 150266201Sian 151266201Sian return (bus_read_4(imx6_anatop_sc->res[MEMRES], offset)); 152257453Sian} 153257453Sian 154257453Sianvoid 155257453Sianimx6_anatop_write_4(bus_size_t offset, uint32_t value) 156257453Sian{ 157257453Sian 158266201Sian KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_write_4 sc NULL")); 159266201Sian 160266201Sian bus_write_4(imx6_anatop_sc->res[MEMRES], offset, value); 161257453Sian} 162257453Sian 163266207Sianstatic void 164266207Sianvdd_set(struct imx6_anatop_softc *sc, int mv) 165266207Sian{ 166283501Sian int newtarg, newtargSoc, oldtarg; 167266207Sian uint32_t delay, pmureg; 168266207Sian static boolean_t init_done = false; 169266207Sian 170266207Sian /* 171266207Sian * The datasheet says VDD_PU and VDD_SOC must be equal, and VDD_ARM 172283501Sian * can't be more than 50mV above or 200mV below them. We keep them the 173283501Sian * same except in the case of the lowest operating point, which is 174283501Sian * handled as a special case below. 175266207Sian */ 176266207Sian 177266207Sian pmureg = imx6_anatop_read_4(IMX6_ANALOG_PMU_REG_CORE); 178266207Sian oldtarg = pmureg & IMX6_ANALOG_PMU_REG0_TARG_MASK; 179266207Sian 180266207Sian /* Convert mV to target value. Clamp target to valid range. */ 181266207Sian if (mv < 725) 182266207Sian newtarg = 0x00; 183266207Sian else if (mv > 1450) 184266207Sian newtarg = 0x1F; 185266207Sian else 186266207Sian newtarg = (mv - 700) / 25; 187266207Sian 188266207Sian /* 189283501Sian * The SOC voltage can't go below 1150mV, and thus because of the 200mV 190283501Sian * rule, the ARM voltage can't go below 950mV. The 950 is encoded in 191283501Sian * our oppt table, here we handle the SOC 1150 rule as a special case. 192283501Sian * (1150-700/25=18). 193283501Sian */ 194283501Sian newtargSoc = (newtarg < 18) ? 18 : newtarg; 195283501Sian 196283501Sian /* 197266207Sian * The first time through the 3 voltages might not be equal so use a 198266207Sian * long conservative delay. After that we need to delay 3uS for every 199283501Sian * 25mV step upward; we actually delay 6uS because empirically, it works 200283501Sian * and the 3uS per step recommended by the docs doesn't (3uS fails when 201283501Sian * going from 400->1200, but works for smaller changes). 202266207Sian */ 203266207Sian if (init_done) { 204266207Sian if (newtarg == oldtarg) 205266207Sian return; 206266207Sian else if (newtarg > oldtarg) 207283501Sian delay = (newtarg - oldtarg) * 6; 208266207Sian else 209266207Sian delay = 0; 210266207Sian } else { 211283501Sian delay = (700 / 25) * 6; 212266207Sian init_done = true; 213266207Sian } 214266207Sian 215266207Sian /* 216266207Sian * Make the change and wait for it to take effect. 217266207Sian */ 218266207Sian pmureg &= ~(IMX6_ANALOG_PMU_REG0_TARG_MASK | 219266207Sian IMX6_ANALOG_PMU_REG1_TARG_MASK | 220266207Sian IMX6_ANALOG_PMU_REG2_TARG_MASK); 221266207Sian 222266207Sian pmureg |= newtarg << IMX6_ANALOG_PMU_REG0_TARG_SHIFT; 223266207Sian pmureg |= newtarg << IMX6_ANALOG_PMU_REG1_TARG_SHIFT; 224283501Sian pmureg |= newtargSoc << IMX6_ANALOG_PMU_REG2_TARG_SHIFT; 225266207Sian 226266207Sian imx6_anatop_write_4(IMX6_ANALOG_PMU_REG_CORE, pmureg); 227266207Sian DELAY(delay); 228266207Sian sc->cpu_curmv = newtarg * 25 + 700; 229266207Sian} 230266207Sian 231266201Sianstatic inline uint32_t 232283501Siancpufreq_mhz_from_div(struct imx6_anatop_softc *sc, uint32_t corediv, 233283501Sian uint32_t plldiv) 234266201Sian{ 235266201Sian 236283501Sian return ((sc->refosc_mhz * (plldiv / 2)) / (corediv + 1)); 237266201Sian} 238266201Sian 239283501Sianstatic inline void 240283501Siancpufreq_mhz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_mhz, 241283501Sian uint32_t *corediv, uint32_t *plldiv) 242266201Sian{ 243266201Sian 244283501Sian *corediv = (cpu_mhz < 650) ? 1 : 0; 245283501Sian *plldiv = ((*corediv + 1) * cpu_mhz) / (sc->refosc_mhz / 2); 246266201Sian} 247266201Sian 248266201Sianstatic inline uint32_t 249266352Siancpufreq_actual_mhz(struct imx6_anatop_softc *sc, uint32_t cpu_mhz) 250266201Sian{ 251283501Sian uint32_t corediv, plldiv; 252266201Sian 253283501Sian cpufreq_mhz_to_div(sc, cpu_mhz, &corediv, &plldiv); 254283501Sian return (cpufreq_mhz_from_div(sc, corediv, plldiv)); 255266201Sian} 256266201Sian 257266352Sianstatic struct oppt * 258266352Siancpufreq_nearest_oppt(struct imx6_anatop_softc *sc, uint32_t cpu_newmhz) 259266352Sian{ 260266352Sian int d, diff, i, nearest; 261266352Sian 262266352Sian if (cpu_newmhz > sc->cpu_maxmhz_hw && !sc->cpu_overclock_enable) 263266352Sian cpu_newmhz = sc->cpu_maxmhz_hw; 264266352Sian 265266352Sian diff = INT_MAX; 266266352Sian nearest = 0; 267266352Sian for (i = 0; i < nitems(imx6_oppt_table); ++i) { 268266352Sian d = abs((int)cpu_newmhz - (int)imx6_oppt_table[i].mhz); 269266352Sian if (diff > d) { 270266352Sian diff = d; 271266352Sian nearest = i; 272266352Sian } 273266352Sian } 274266352Sian return (&imx6_oppt_table[nearest]); 275266352Sian} 276266352Sian 277266201Sianstatic void 278266352Siancpufreq_set_clock(struct imx6_anatop_softc * sc, struct oppt *op) 279266201Sian{ 280283501Sian uint32_t corediv, plldiv, timeout, wrk32; 281266201Sian 282266352Sian /* If increasing the frequency, we must first increase the voltage. */ 283266352Sian if (op->mhz > sc->cpu_curmhz) { 284266352Sian vdd_set(sc, op->mv); 285266352Sian } 286266201Sian 287266201Sian /* 288266201Sian * I can't find a documented procedure for changing the ARM PLL divisor, 289266201Sian * but some trial and error came up with this: 290266201Sian * - Set the bypass clock source to REF_CLK_24M (source #0). 291266201Sian * - Set the PLL into bypass mode; cpu should now be running at 24mhz. 292266201Sian * - Change the divisor. 293266201Sian * - Wait for the LOCK bit to come on; it takes ~50 loop iterations. 294266352Sian * - Turn off bypass mode; cpu should now be running at the new speed. 295266201Sian */ 296283501Sian cpufreq_mhz_to_div(sc, op->mhz, &corediv, &plldiv); 297266201Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 298266201Sian IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK); 299266201Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_SET, 300266201Sian IMX6_ANALOG_CCM_PLL_ARM_BYPASS); 301266201Sian 302266201Sian wrk32 = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM); 303266201Sian wrk32 &= ~IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; 304283501Sian wrk32 |= plldiv; 305266201Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM, wrk32); 306266201Sian 307266201Sian timeout = 10000; 308266201Sian while ((imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & 309266201Sian IMX6_ANALOG_CCM_PLL_ARM_LOCK) == 0) 310266201Sian if (--timeout == 0) 311266201Sian panic("imx6_set_cpu_clock(): PLL never locked"); 312266201Sian 313266201Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 314266201Sian IMX6_ANALOG_CCM_PLL_ARM_BYPASS); 315283501Sian imx_ccm_set_cacrr(corediv); 316266348Sian 317266352Sian /* If lowering the frequency, it is now safe to lower the voltage. */ 318266352Sian if (op->mhz < sc->cpu_curmhz) 319266352Sian vdd_set(sc, op->mv); 320266352Sian sc->cpu_curmhz = op->mhz; 321266352Sian 322266352Sian /* Tell the mpcore timer that its frequency has changed. */ 323283501Sian arm_tmr_change_frequency( 324266352Sian cpufreq_actual_mhz(sc, sc->cpu_curmhz) * 1000000 / 2); 325266201Sian} 326266201Sian 327266352Sianstatic int 328266352Siancpufreq_sysctl_minmhz(SYSCTL_HANDLER_ARGS) 329266352Sian{ 330266352Sian struct imx6_anatop_softc *sc; 331266352Sian struct oppt * op; 332266352Sian uint32_t temp; 333266352Sian int err; 334266352Sian 335266352Sian sc = arg1; 336266352Sian 337266352Sian temp = sc->cpu_minmhz; 338266352Sian err = sysctl_handle_int(oidp, &temp, 0, req); 339266352Sian if (err != 0 || req->newptr == NULL) 340266352Sian return (err); 341266352Sian 342266352Sian op = cpufreq_nearest_oppt(sc, temp); 343266352Sian if (op->mhz > sc->cpu_maxmhz) 344266352Sian return (ERANGE); 345266352Sian else if (op->mhz == sc->cpu_minmhz) 346266352Sian return (0); 347266352Sian 348266352Sian /* 349266352Sian * Value changed, update softc. If the new min is higher than the 350266352Sian * current speed, raise the current speed to match. 351266352Sian */ 352266352Sian sc->cpu_minmhz = op->mhz; 353266352Sian if (sc->cpu_minmhz > sc->cpu_curmhz) { 354266352Sian cpufreq_set_clock(sc, op); 355266352Sian } 356266352Sian return (err); 357266352Sian} 358266352Sian 359266352Sianstatic int 360266352Siancpufreq_sysctl_maxmhz(SYSCTL_HANDLER_ARGS) 361266352Sian{ 362266352Sian struct imx6_anatop_softc *sc; 363266352Sian struct oppt * op; 364266352Sian uint32_t temp; 365266352Sian int err; 366266352Sian 367266352Sian sc = arg1; 368266352Sian 369266352Sian temp = sc->cpu_maxmhz; 370266352Sian err = sysctl_handle_int(oidp, &temp, 0, req); 371266352Sian if (err != 0 || req->newptr == NULL) 372266352Sian return (err); 373266352Sian 374266352Sian op = cpufreq_nearest_oppt(sc, temp); 375266352Sian if (op->mhz < sc->cpu_minmhz) 376266352Sian return (ERANGE); 377266352Sian else if (op->mhz == sc->cpu_maxmhz) 378266352Sian return (0); 379266352Sian 380266352Sian /* 381266352Sian * Value changed, update softc and hardware. The hardware update is 382266352Sian * unconditional. We always try to run at max speed, so any change of 383266352Sian * the max means we need to change the current speed too, regardless of 384266352Sian * whether it is higher or lower than the old max. 385266352Sian */ 386266352Sian sc->cpu_maxmhz = op->mhz; 387266352Sian cpufreq_set_clock(sc, op); 388266352Sian 389266352Sian return (err); 390266352Sian} 391266352Sian 392266201Sianstatic void 393266201Siancpufreq_initialize(struct imx6_anatop_softc *sc) 394266201Sian{ 395266201Sian uint32_t cfg3speed; 396266352Sian struct oppt * op; 397266201Sian 398294678Sian SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 399266201Sian OID_AUTO, "cpu_mhz", CTLFLAG_RD, &sc->cpu_curmhz, 0, 400266352Sian "CPU frequency"); 401266201Sian 402294678Sian SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 403266352Sian OID_AUTO, "cpu_minmhz", CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, 404266352Sian cpufreq_sysctl_minmhz, "IU", "Minimum CPU frequency"); 405266352Sian 406294678Sian SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 407266352Sian OID_AUTO, "cpu_maxmhz", CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, 408266352Sian cpufreq_sysctl_maxmhz, "IU", "Maximum CPU frequency"); 409266352Sian 410294678Sian SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 411266352Sian OID_AUTO, "cpu_maxmhz_hw", CTLFLAG_RD, &sc->cpu_maxmhz_hw, 0, 412266352Sian "Maximum CPU frequency allowed by hardware"); 413266352Sian 414294678Sian SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 415266352Sian OID_AUTO, "cpu_overclock_enable", CTLFLAG_RWTUN, 416266352Sian &sc->cpu_overclock_enable, 0, 417266352Sian "Allow setting CPU frequency higher than cpu_maxmhz_hw"); 418266352Sian 419266201Sian /* 420266201Sian * XXX 24mhz shouldn't be hard-coded, should get this from imx6_ccm 421266201Sian * (even though in the real world it will always be 24mhz). Oh wait a 422266201Sian * sec, I never wrote imx6_ccm. 423266201Sian */ 424266352Sian sc->refosc_mhz = 24; 425266201Sian 426266201Sian /* 427266201Sian * Get the maximum speed this cpu can be set to. The values in the 428266201Sian * OCOTP CFG3 register are not documented in the reference manual. 429266201Sian * The following info was in an archived email found via web search: 430266201Sian * - 2b'11: 1200000000Hz; 431266201Sian * - 2b'10: 996000000Hz; 432266201Sian * - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. 433266201Sian * - 2b'00: 792000000Hz; 434266352Sian * The default hardware max speed can be overridden by a tunable. 435266201Sian */ 436266201Sian cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & 437266201Sian FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT; 438266352Sian sc->cpu_maxmhz_hw = imx6_ocotp_mhz_tab[cfg3speed]; 439266352Sian sc->cpu_maxmhz = sc->cpu_maxmhz_hw; 440266201Sian 441266352Sian TUNABLE_INT_FETCH("hw.imx6.cpu_overclock_enable", 442266352Sian &sc->cpu_overclock_enable); 443266201Sian 444266352Sian TUNABLE_INT_FETCH("hw.imx6.cpu_minmhz", &sc->cpu_minmhz); 445266352Sian op = cpufreq_nearest_oppt(sc, sc->cpu_minmhz); 446266352Sian sc->cpu_minmhz = op->mhz; 447266352Sian sc->cpu_minmv = op->mv; 448266352Sian 449266352Sian TUNABLE_INT_FETCH("hw.imx6.cpu_maxmhz", &sc->cpu_maxmhz); 450266352Sian op = cpufreq_nearest_oppt(sc, sc->cpu_maxmhz); 451266352Sian sc->cpu_maxmhz = op->mhz; 452266352Sian sc->cpu_maxmv = op->mv; 453266352Sian 454266201Sian /* 455266201Sian * Set the CPU to maximum speed. 456266201Sian * 457266201Sian * We won't have thermal throttling until interrupts are enabled, but we 458266201Sian * want to run at full speed through all the device init stuff. This 459266201Sian * basically assumes that a single core can't overheat before interrupts 460266201Sian * are enabled; empirical testing shows that to be a safe assumption. 461266201Sian */ 462266352Sian cpufreq_set_clock(sc, op); 463266201Sian} 464266201Sian 465266201Sianstatic inline uint32_t 466266201Siantemp_from_count(struct imx6_anatop_softc *sc, uint32_t count) 467266201Sian{ 468266201Sian 469266201Sian return (((sc->temp_high_val - (count - sc->temp_high_cnt) * 470266201Sian (sc->temp_high_val - 250) / 471266201Sian (sc->temp_room_cnt - sc->temp_high_cnt)))); 472266201Sian} 473266201Sian 474266201Sianstatic inline uint32_t 475266201Siantemp_to_count(struct imx6_anatop_softc *sc, uint32_t temp) 476266201Sian{ 477266201Sian 478266201Sian return ((sc->temp_room_cnt - sc->temp_high_cnt) * 479266201Sian (sc->temp_high_val - temp) / (sc->temp_high_val - 250) + 480266201Sian sc->temp_high_cnt); 481266201Sian} 482266201Sian 483266201Sianstatic void 484266201Siantemp_update_count(struct imx6_anatop_softc *sc) 485266201Sian{ 486266201Sian uint32_t val; 487266201Sian 488266201Sian val = imx6_anatop_read_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0); 489266201Sian if (!(val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_VALID)) 490266201Sian return; 491266201Sian sc->temp_last_cnt = 492266201Sian (val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >> 493266201Sian IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT; 494266201Sian} 495266201Sian 496257453Sianstatic int 497266201Siantemp_sysctl_handler(SYSCTL_HANDLER_ARGS) 498257453Sian{ 499266201Sian struct imx6_anatop_softc *sc = arg1; 500266201Sian uint32_t t; 501257453Sian 502266201Sian temp_update_count(sc); 503257453Sian 504266201Sian t = temp_from_count(sc, sc->temp_last_cnt) + TZ_ZEROC; 505257453Sian 506266201Sian return (sysctl_handle_int(oidp, &t, 0, req)); 507257453Sian} 508257453Sian 509257453Sianstatic int 510266201Siantemp_throttle_sysctl_handler(SYSCTL_HANDLER_ARGS) 511266201Sian{ 512266201Sian struct imx6_anatop_softc *sc = arg1; 513266201Sian int err; 514266201Sian uint32_t temp; 515266201Sian 516266201Sian temp = sc->temp_throttle_val + TZ_ZEROC; 517266201Sian err = sysctl_handle_int(oidp, &temp, 0, req); 518266201Sian if (temp < TZ_ZEROC) 519266201Sian return (ERANGE); 520266201Sian temp -= TZ_ZEROC; 521266201Sian if (err != 0 || req->newptr == NULL || temp == sc->temp_throttle_val) 522266201Sian return (err); 523266201Sian 524266201Sian /* Value changed, update counts in softc and hardware. */ 525266201Sian sc->temp_throttle_val = temp; 526266201Sian sc->temp_throttle_trigger_cnt = temp_to_count(sc, sc->temp_throttle_val); 527266201Sian sc->temp_throttle_reset_cnt = temp_to_count(sc, sc->temp_throttle_val - 100); 528266201Sian imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_CLR, 529266201Sian IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_MASK); 530266201Sian imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_SET, 531266201Sian (sc->temp_throttle_trigger_cnt << 532266201Sian IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT)); 533266201Sian return (err); 534266201Sian} 535266201Sian 536266201Sianstatic void 537266201Siantempmon_gofast(struct imx6_anatop_softc *sc) 538266201Sian{ 539266201Sian 540266352Sian if (sc->cpu_curmhz < sc->cpu_maxmhz) { 541266352Sian cpufreq_set_clock(sc, cpufreq_nearest_oppt(sc, sc->cpu_maxmhz)); 542266201Sian } 543266201Sian} 544266201Sian 545266201Sianstatic void 546266201Siantempmon_goslow(struct imx6_anatop_softc *sc) 547266201Sian{ 548266201Sian 549266352Sian if (sc->cpu_curmhz > sc->cpu_minmhz) { 550266352Sian cpufreq_set_clock(sc, cpufreq_nearest_oppt(sc, sc->cpu_minmhz)); 551266201Sian } 552266201Sian} 553266201Sian 554266201Sianstatic int 555266201Siantempmon_intr(void *arg) 556266201Sian{ 557266201Sian struct imx6_anatop_softc *sc = arg; 558266201Sian 559266201Sian /* 560266201Sian * XXX Note that this code doesn't currently run (for some mysterious 561266201Sian * reason we just never get an interrupt), so the real monitoring is 562266201Sian * done by tempmon_throttle_check(). 563266201Sian */ 564266201Sian tempmon_goslow(sc); 565266201Sian /* XXX Schedule callout to speed back up eventually. */ 566266201Sian return (FILTER_HANDLED); 567266201Sian} 568266201Sian 569266201Sianstatic void 570266201Siantempmon_throttle_check(void *arg) 571266201Sian{ 572266201Sian struct imx6_anatop_softc *sc = arg; 573266201Sian 574266201Sian /* Lower counts are higher temperatures. */ 575266201Sian if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt) 576266201Sian tempmon_goslow(sc); 577266201Sian else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt)) 578266201Sian tempmon_gofast(sc); 579266201Sian 580266201Sian callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 581266201Sian 0, tempmon_throttle_check, sc, 0); 582266201Sian 583266201Sian} 584266201Sian 585266201Sianstatic void 586266201Sianinitialize_tempmon(struct imx6_anatop_softc *sc) 587266201Sian{ 588266201Sian uint32_t cal; 589266201Sian 590266201Sian /* 591266201Sian * Fetch calibration data: a sensor count at room temperature (25C), 592266201Sian * a sensor count at a high temperature, and that temperature 593266201Sian */ 594266201Sian cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1); 595266201Sian sc->temp_room_cnt = (cal & 0xFFF00000) >> 20; 596266201Sian sc->temp_high_cnt = (cal & 0x000FFF00) >> 8; 597266201Sian sc->temp_high_val = (cal & 0x000000FF) * 10; 598266201Sian 599266201Sian /* 600266201Sian * Throttle to a lower cpu freq at 10C below the "hot" temperature, and 601266201Sian * reset back to max cpu freq at 5C below the trigger. 602266201Sian */ 603266201Sian sc->temp_throttle_val = sc->temp_high_val - 100; 604266201Sian sc->temp_throttle_trigger_cnt = 605266201Sian temp_to_count(sc, sc->temp_throttle_val); 606266201Sian sc->temp_throttle_reset_cnt = 607266201Sian temp_to_count(sc, sc->temp_throttle_val - 50); 608266201Sian 609266201Sian /* 610266201Sian * Set the sensor to sample automatically at 16Hz (32.768KHz/0x800), set 611266201Sian * the throttle count, and begin making measurements. 612266201Sian */ 613266201Sian imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE1, 0x0800); 614266201Sian imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0, 615266201Sian (sc->temp_throttle_trigger_cnt << 616266201Sian IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) | 617266201Sian IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE); 618266201Sian 619266201Sian /* 620266201Sian * XXX Note that the alarm-interrupt feature isn't working yet, so 621266201Sian * we'll use a callout handler to check at 10Hz. Make sure we have an 622266201Sian * initial temperature reading before starting up the callouts so we 623266201Sian * don't get a bogus reading of zero. 624266201Sian */ 625266201Sian while (sc->temp_last_cnt == 0) 626266201Sian temp_update_count(sc); 627266201Sian sc->temp_throttle_delay = 100 * SBT_1MS; 628266201Sian callout_init(&sc->temp_throttle_callout, 0); 629266201Sian callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 630266201Sian 0, tempmon_throttle_check, sc, 0); 631266201Sian 632294678Sian SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 633266201Sian OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 634266201Sian temp_sysctl_handler, "IK", "Current die temperature"); 635294678Sian SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), 636266201Sian OID_AUTO, "throttle_temperature", CTLTYPE_INT | CTLFLAG_RW, sc, 637266201Sian 0, temp_throttle_sysctl_handler, "IK", 638266201Sian "Throttle CPU when exceeding this temperature"); 639266201Sian} 640266201Sian 641273656Sianstatic void 642273656Sianintr_setup(void *arg) 643273656Sian{ 644273656Sian struct imx6_anatop_softc *sc; 645273656Sian 646273656Sian sc = arg; 647273656Sian bus_setup_intr(sc->dev, sc->res[IRQRES], INTR_TYPE_MISC | INTR_MPSAFE, 648273656Sian tempmon_intr, NULL, sc, &sc->temp_intrhand); 649273656Sian config_intrhook_disestablish(&sc->intr_setup_hook); 650273656Sian} 651273656Sian 652273679Sianstatic void 653273679Sianimx6_anatop_new_pass(device_t dev) 654273679Sian{ 655273679Sian struct imx6_anatop_softc *sc; 656273679Sian const int cpu_init_pass = BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE; 657273679Sian 658273679Sian /* 659273679Sian * We attach during BUS_PASS_BUS (because some day we will be a 660273679Sian * simplebus that has regulator devices as children), but some of our 661273679Sian * init work cannot be done until BUS_PASS_CPU (we rely on other devices 662273679Sian * that attach on the CPU pass). 663273679Sian */ 664273679Sian sc = device_get_softc(dev); 665273679Sian if (!sc->cpu_init_done && bus_current_pass >= cpu_init_pass) { 666273679Sian sc->cpu_init_done = true; 667273679Sian cpufreq_initialize(sc); 668273679Sian initialize_tempmon(sc); 669273679Sian if (bootverbose) { 670273679Sian device_printf(sc->dev, "CPU %uMHz @ %umV\n", 671273679Sian sc->cpu_curmhz, sc->cpu_curmv); 672273679Sian } 673273679Sian } 674273679Sian bus_generic_new_pass(dev); 675273679Sian} 676273679Sian 677266201Sianstatic int 678266201Sianimx6_anatop_detach(device_t dev) 679266201Sian{ 680266201Sian 681273656Sian /* This device can never detach. */ 682266201Sian return (EBUSY); 683266201Sian} 684266201Sian 685266201Sianstatic int 686257453Sianimx6_anatop_attach(device_t dev) 687257453Sian{ 688257453Sian struct imx6_anatop_softc *sc; 689266201Sian int err; 690257453Sian 691257453Sian sc = device_get_softc(dev); 692266201Sian sc->dev = dev; 693257453Sian 694257453Sian /* Allocate bus_space resources. */ 695266201Sian if (bus_alloc_resources(dev, imx6_anatop_spec, sc->res)) { 696266201Sian device_printf(dev, "Cannot allocate resources\n"); 697257453Sian err = ENXIO; 698257453Sian goto out; 699257453Sian } 700257453Sian 701273656Sian sc->intr_setup_hook.ich_func = intr_setup; 702273656Sian sc->intr_setup_hook.ich_arg = sc; 703273656Sian config_intrhook_establish(&sc->intr_setup_hook); 704266201Sian 705266207Sian SYSCTL_ADD_UINT(device_get_sysctl_ctx(sc->dev), 706266207Sian SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 707266207Sian OID_AUTO, "cpu_voltage", CTLFLAG_RD, 708266207Sian &sc->cpu_curmv, 0, "Current CPU voltage in millivolts"); 709266207Sian 710257453Sian imx6_anatop_sc = sc; 711266201Sian 712266201Sian /* 713266201Sian * Other code seen on the net sets this SELFBIASOFF flag around the same 714266201Sian * time the temperature sensor is set up, although it's unclear how the 715266201Sian * two are related (if at all). 716266201Sian */ 717266201Sian imx6_anatop_write_4(IMX6_ANALOG_PMU_MISC0_SET, 718266201Sian IMX6_ANALOG_PMU_MISC0_SELFBIASOFF); 719266201Sian 720273679Sian /* 721273679Sian * Some day, when we're ready to deal with the actual anatop regulators 722273679Sian * that are described in fdt data as children of this "bus", this would 723273679Sian * be the place to invoke a simplebus helper routine to instantiate the 724273679Sian * children from the fdt data. 725273679Sian */ 726266201Sian 727257453Sian err = 0; 728257453Sian 729257453Sianout: 730257453Sian 731266201Sian if (err != 0) { 732266201Sian bus_release_resources(dev, imx6_anatop_spec, sc->res); 733266201Sian } 734257453Sian 735257453Sian return (err); 736257453Sian} 737257453Sian 738283500Sianuint32_t 739283500Sianpll4_configure_output(uint32_t mfi, uint32_t mfn, uint32_t mfd) 740283500Sian{ 741283500Sian int reg; 742283500Sian 743283500Sian /* 744283500Sian * Audio PLL (PLL4). 745283500Sian * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) 746283500Sian */ 747283500Sian 748283500Sian reg = (IMX6_ANALOG_CCM_PLL_AUDIO_ENABLE); 749283500Sian reg &= ~(IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_MASK << \ 750283500Sian IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT); 751283500Sian reg |= (mfi << IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT); 752283500Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO, reg); 753283500Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_NUM, mfn); 754283500Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_DENOM, mfd); 755283500Sian 756283500Sian return (0); 757283500Sian} 758283500Sian 759257453Sianstatic int 760257453Sianimx6_anatop_probe(device_t dev) 761257453Sian{ 762257453Sian 763266152Sian if (!ofw_bus_status_okay(dev)) 764266152Sian return (ENXIO); 765266152Sian 766266201Sian if (ofw_bus_is_compatible(dev, "fsl,imx6q-anatop") == 0) 767257453Sian return (ENXIO); 768257453Sian 769257453Sian device_set_desc(dev, "Freescale i.MX6 Analog PLLs and Power"); 770257453Sian 771257453Sian return (BUS_PROBE_DEFAULT); 772257453Sian} 773257453Sian 774266201Sianuint32_t 775266201Sianimx6_get_cpu_clock() 776266201Sian{ 777283501Sian uint32_t corediv, plldiv; 778266201Sian 779283501Sian corediv = imx_ccm_get_cacrr(); 780283501Sian plldiv = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & 781266201Sian IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; 782283501Sian return (cpufreq_mhz_from_div(imx6_anatop_sc, corediv, plldiv)); 783266201Sian} 784266201Sian 785257453Sianstatic device_method_t imx6_anatop_methods[] = { 786257453Sian /* Device interface */ 787257453Sian DEVMETHOD(device_probe, imx6_anatop_probe), 788257453Sian DEVMETHOD(device_attach, imx6_anatop_attach), 789257453Sian DEVMETHOD(device_detach, imx6_anatop_detach), 790257453Sian 791273679Sian /* Bus interface */ 792273679Sian DEVMETHOD(bus_new_pass, imx6_anatop_new_pass), 793273679Sian 794257453Sian DEVMETHOD_END 795257453Sian}; 796257453Sian 797257453Sianstatic driver_t imx6_anatop_driver = { 798257453Sian "imx6_anatop", 799257453Sian imx6_anatop_methods, 800257453Sian sizeof(struct imx6_anatop_softc) 801257453Sian}; 802257453Sian 803257453Sianstatic devclass_t imx6_anatop_devclass; 804257453Sian 805273656SianEARLY_DRIVER_MODULE(imx6_anatop, simplebus, imx6_anatop_driver, 806273679Sian imx6_anatop_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 807273679SianEARLY_DRIVER_MODULE(imx6_anatop, ofwbus, imx6_anatop_driver, 808273679Sian imx6_anatop_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 809257453Sian 810