Path: blob/main/sys/arm/freescale/imx/imx6_anatop.c
39537 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2013 Ian Lepore <[email protected]>4* Copyright (c) 2014 Steven Lawrance <[email protected]>5* All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829#include <sys/cdefs.h>30/*31* Analog PLL and power regulator driver for Freescale i.MX6 family of SoCs.32* Also, temperature montoring and cpu frequency control. It was Freescale who33* kitchen-sinked this device, not us. :)34*35* We don't really do anything with analog PLLs, but the registers for36* controlling them belong to the same block as the power regulator registers.37* Since the newbus hierarchy makes it hard for anyone other than us to get at38* them, we just export a couple public functions to allow the imx6 CCM clock39* driver to read and write those registers.40*41* We also don't do anything about power regulation yet, but when the need42* arises, this would be the place for that code to live.43*44* I have no idea where the "anatop" name comes from. It's in the standard DTS45* source describing i.MX6 SoCs, and in the linux and u-boot code which comes46* from Freescale, but it's not in the SoC manual.47*48* Note that temperature values throughout this code are handled in two types of49* units. Items with '_cnt' in the name use the hardware temperature count50* units (higher counts are lower temperatures). Items with '_val' in the name51* are deci-Celsius, which are converted to/from deci-Kelvins in the sysctl52* handlers (dK is the standard unit for temperature in sysctl).53*/5455#include <sys/param.h>56#include <sys/systm.h>57#include <sys/callout.h>58#include <sys/kernel.h>59#include <sys/limits.h>60#include <sys/sysctl.h>61#include <sys/module.h>62#include <sys/bus.h>63#include <sys/rman.h>6465#include <dev/ofw/ofw_bus.h>66#include <dev/ofw/ofw_bus_subr.h>6768#include <machine/bus.h>6970#include <arm/arm/mpcore_timervar.h>71#include <arm/freescale/fsl_ocotpreg.h>72#include <arm/freescale/fsl_ocotpvar.h>73#include <arm/freescale/imx/imx_ccmvar.h>74#include <arm/freescale/imx/imx_machdep.h>75#include <arm/freescale/imx/imx6_anatopreg.h>76#include <arm/freescale/imx/imx6_anatopvar.h>7778static struct resource_spec imx6_anatop_spec[] = {79{ SYS_RES_MEMORY, 0, RF_ACTIVE },80{ -1, 0 }81};82#define MEMRES 083#define IRQRES 18485struct imx6_anatop_softc {86device_t dev;87struct resource *res[2];88struct intr_config_hook89intr_setup_hook;90uint32_t cpu_curmhz;91uint32_t cpu_curmv;92uint32_t cpu_minmhz;93uint32_t cpu_minmv;94uint32_t cpu_maxmhz;95uint32_t cpu_maxmv;96uint32_t cpu_maxmhz_hw;97boolean_t cpu_overclock_enable;98boolean_t cpu_init_done;99uint32_t refosc_mhz;100void *temp_intrhand;101uint32_t temp_high_val;102uint32_t temp_high_cnt;103uint32_t temp_last_cnt;104uint32_t temp_room_cnt;105struct callout temp_throttle_callout;106sbintime_t temp_throttle_delay;107uint32_t temp_throttle_reset_cnt;108uint32_t temp_throttle_trigger_cnt;109uint32_t temp_throttle_val;110};111112static struct imx6_anatop_softc *imx6_anatop_sc;113114/*115* Table of "operating points".116* These are combinations of frequency and voltage blessed by Freescale.117* While the datasheet says the ARM voltage can be as low as 925mV at118* 396MHz, it also says that the ARM and SOC voltages can't differ by119* more than 200mV, and the minimum SOC voltage is 1150mV, so that120* dictates the 950mV entry in this table.121*/122static struct oppt {123uint32_t mhz;124uint32_t mv;125} imx6_oppt_table[] = {126{ 396, 950},127{ 792, 1150},128{ 852, 1225},129{ 996, 1225},130{1200, 1275},131};132133/*134* Table of CPU max frequencies. This is used to translate the max frequency135* value (0-3) from the ocotp CFG3 register into a mhz value that can be looked136* up in the operating points table.137*/138static uint32_t imx6_ocotp_mhz_tab[] = {792, 852, 996, 1200};139140#define TZ_ZEROC 2731 /* deci-Kelvin <-> deci-Celsius offset. */141142uint32_t143imx6_anatop_read_4(bus_size_t offset)144{145146KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_read_4 sc NULL"));147148return (bus_read_4(imx6_anatop_sc->res[MEMRES], offset));149}150151void152imx6_anatop_write_4(bus_size_t offset, uint32_t value)153{154155KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_write_4 sc NULL"));156157bus_write_4(imx6_anatop_sc->res[MEMRES], offset, value);158}159160static void161vdd_set(struct imx6_anatop_softc *sc, int mv)162{163int newtarg, newtargSoc, oldtarg;164uint32_t delay, pmureg;165static boolean_t init_done = false;166167/*168* The datasheet says VDD_PU and VDD_SOC must be equal, and VDD_ARM169* can't be more than 50mV above or 200mV below them. We keep them the170* same except in the case of the lowest operating point, which is171* handled as a special case below.172*/173174pmureg = imx6_anatop_read_4(IMX6_ANALOG_PMU_REG_CORE);175oldtarg = pmureg & IMX6_ANALOG_PMU_REG0_TARG_MASK;176177/* Convert mV to target value. Clamp target to valid range. */178if (mv < 725)179newtarg = 0x00;180else if (mv > 1450)181newtarg = 0x1F;182else183newtarg = (mv - 700) / 25;184185/*186* The SOC voltage can't go below 1150mV, and thus because of the 200mV187* rule, the ARM voltage can't go below 950mV. The 950 is encoded in188* our oppt table, here we handle the SOC 1150 rule as a special case.189* (1150-700/25=18).190*/191newtargSoc = (newtarg < 18) ? 18 : newtarg;192193/*194* The first time through the 3 voltages might not be equal so use a195* long conservative delay. After that we need to delay 3uS for every196* 25mV step upward; we actually delay 6uS because empirically, it works197* and the 3uS per step recommended by the docs doesn't (3uS fails when198* going from 400->1200, but works for smaller changes).199*/200if (init_done) {201if (newtarg == oldtarg)202return;203else if (newtarg > oldtarg)204delay = (newtarg - oldtarg) * 6;205else206delay = 0;207} else {208delay = (700 / 25) * 6;209init_done = true;210}211212/*213* Make the change and wait for it to take effect.214*/215pmureg &= ~(IMX6_ANALOG_PMU_REG0_TARG_MASK |216IMX6_ANALOG_PMU_REG1_TARG_MASK |217IMX6_ANALOG_PMU_REG2_TARG_MASK);218219pmureg |= newtarg << IMX6_ANALOG_PMU_REG0_TARG_SHIFT;220pmureg |= newtarg << IMX6_ANALOG_PMU_REG1_TARG_SHIFT;221pmureg |= newtargSoc << IMX6_ANALOG_PMU_REG2_TARG_SHIFT;222223imx6_anatop_write_4(IMX6_ANALOG_PMU_REG_CORE, pmureg);224DELAY(delay);225sc->cpu_curmv = newtarg * 25 + 700;226}227228static inline uint32_t229cpufreq_mhz_from_div(struct imx6_anatop_softc *sc, uint32_t corediv,230uint32_t plldiv)231{232233return ((sc->refosc_mhz * (plldiv / 2)) / (corediv + 1));234}235236static inline void237cpufreq_mhz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_mhz,238uint32_t *corediv, uint32_t *plldiv)239{240241*corediv = (cpu_mhz < 650) ? 1 : 0;242*plldiv = ((*corediv + 1) * cpu_mhz) / (sc->refosc_mhz / 2);243}244245static inline uint32_t246cpufreq_actual_mhz(struct imx6_anatop_softc *sc, uint32_t cpu_mhz)247{248uint32_t corediv, plldiv;249250cpufreq_mhz_to_div(sc, cpu_mhz, &corediv, &plldiv);251return (cpufreq_mhz_from_div(sc, corediv, plldiv));252}253254static struct oppt *255cpufreq_nearest_oppt(struct imx6_anatop_softc *sc, uint32_t cpu_newmhz)256{257int d, diff, i, nearest;258259if (cpu_newmhz > sc->cpu_maxmhz_hw && !sc->cpu_overclock_enable)260cpu_newmhz = sc->cpu_maxmhz_hw;261262diff = INT_MAX;263nearest = 0;264for (i = 0; i < nitems(imx6_oppt_table); ++i) {265d = abs((int)cpu_newmhz - (int)imx6_oppt_table[i].mhz);266if (diff > d) {267diff = d;268nearest = i;269}270}271return (&imx6_oppt_table[nearest]);272}273274static void275cpufreq_set_clock(struct imx6_anatop_softc * sc, struct oppt *op)276{277uint32_t corediv, plldiv, timeout, wrk32;278279/* If increasing the frequency, we must first increase the voltage. */280if (op->mhz > sc->cpu_curmhz) {281vdd_set(sc, op->mv);282}283284/*285* I can't find a documented procedure for changing the ARM PLL divisor,286* but some trial and error came up with this:287* - Set the bypass clock source to REF_CLK_24M (source #0).288* - Set the PLL into bypass mode; cpu should now be running at 24mhz.289* - Change the divisor.290* - Wait for the LOCK bit to come on; it takes ~50 loop iterations.291* - Turn off bypass mode; cpu should now be running at the new speed.292*/293cpufreq_mhz_to_div(sc, op->mhz, &corediv, &plldiv);294imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR,295IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK);296imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_SET,297IMX6_ANALOG_CCM_PLL_ARM_BYPASS);298299wrk32 = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM);300wrk32 &= ~IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK;301wrk32 |= plldiv;302imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM, wrk32);303304timeout = 10000;305while ((imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) &306IMX6_ANALOG_CCM_PLL_ARM_LOCK) == 0)307if (--timeout == 0)308panic("imx6_set_cpu_clock(): PLL never locked");309310imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR,311IMX6_ANALOG_CCM_PLL_ARM_BYPASS);312imx_ccm_set_cacrr(corediv);313314/* If lowering the frequency, it is now safe to lower the voltage. */315if (op->mhz < sc->cpu_curmhz)316vdd_set(sc, op->mv);317sc->cpu_curmhz = op->mhz;318319/* Tell the mpcore timer that its frequency has changed. */320arm_tmr_change_frequency(321cpufreq_actual_mhz(sc, sc->cpu_curmhz) * 1000000 / 2);322}323324static int325cpufreq_sysctl_minmhz(SYSCTL_HANDLER_ARGS)326{327struct imx6_anatop_softc *sc;328struct oppt * op;329uint32_t temp;330int err;331332sc = arg1;333334temp = sc->cpu_minmhz;335err = sysctl_handle_int(oidp, &temp, 0, req);336if (err != 0 || req->newptr == NULL)337return (err);338339op = cpufreq_nearest_oppt(sc, temp);340if (op->mhz > sc->cpu_maxmhz)341return (ERANGE);342else if (op->mhz == sc->cpu_minmhz)343return (0);344345/*346* Value changed, update softc. If the new min is higher than the347* current speed, raise the current speed to match.348*/349sc->cpu_minmhz = op->mhz;350if (sc->cpu_minmhz > sc->cpu_curmhz) {351cpufreq_set_clock(sc, op);352}353return (err);354}355356static int357cpufreq_sysctl_maxmhz(SYSCTL_HANDLER_ARGS)358{359struct imx6_anatop_softc *sc;360struct oppt * op;361uint32_t temp;362int err;363364sc = arg1;365366temp = sc->cpu_maxmhz;367err = sysctl_handle_int(oidp, &temp, 0, req);368if (err != 0 || req->newptr == NULL)369return (err);370371op = cpufreq_nearest_oppt(sc, temp);372if (op->mhz < sc->cpu_minmhz)373return (ERANGE);374else if (op->mhz == sc->cpu_maxmhz)375return (0);376377/*378* Value changed, update softc and hardware. The hardware update is379* unconditional. We always try to run at max speed, so any change of380* the max means we need to change the current speed too, regardless of381* whether it is higher or lower than the old max.382*/383sc->cpu_maxmhz = op->mhz;384cpufreq_set_clock(sc, op);385386return (err);387}388389static void390cpufreq_initialize(struct imx6_anatop_softc *sc)391{392uint32_t cfg3speed;393struct oppt * op;394395SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),396OID_AUTO, "cpu_mhz", CTLFLAG_RD, &sc->cpu_curmhz, 0,397"CPU frequency");398399SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),400OID_AUTO, "cpu_minmhz",401CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_NEEDGIANT,402sc, 0, cpufreq_sysctl_minmhz, "IU", "Minimum CPU frequency");403404SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),405OID_AUTO, "cpu_maxmhz",406CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_NEEDGIANT,407sc, 0, cpufreq_sysctl_maxmhz, "IU", "Maximum CPU frequency");408409SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),410OID_AUTO, "cpu_maxmhz_hw", CTLFLAG_RD, &sc->cpu_maxmhz_hw, 0,411"Maximum CPU frequency allowed by hardware");412413SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),414OID_AUTO, "cpu_overclock_enable", CTLFLAG_RWTUN,415&sc->cpu_overclock_enable, 0,416"Allow setting CPU frequency higher than cpu_maxmhz_hw");417418/*419* XXX 24mhz shouldn't be hard-coded, should get this from imx6_ccm420* (even though in the real world it will always be 24mhz). Oh wait a421* sec, I never wrote imx6_ccm.422*/423sc->refosc_mhz = 24;424425/*426* Get the maximum speed this cpu can be set to. The values in the427* OCOTP CFG3 register are not documented in the reference manual.428* The following info was in an archived email found via web search:429* - 2b'11: 1200000000Hz;430* - 2b'10: 996000000Hz;431* - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.432* - 2b'00: 792000000Hz;433* The default hardware max speed can be overridden by a tunable.434*/435cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) &436FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT;437sc->cpu_maxmhz_hw = imx6_ocotp_mhz_tab[cfg3speed];438sc->cpu_maxmhz = sc->cpu_maxmhz_hw;439440TUNABLE_INT_FETCH("hw.imx6.cpu_minmhz", &sc->cpu_minmhz);441op = cpufreq_nearest_oppt(sc, sc->cpu_minmhz);442sc->cpu_minmhz = op->mhz;443sc->cpu_minmv = op->mv;444445TUNABLE_INT_FETCH("hw.imx6.cpu_maxmhz", &sc->cpu_maxmhz);446op = cpufreq_nearest_oppt(sc, sc->cpu_maxmhz);447sc->cpu_maxmhz = op->mhz;448sc->cpu_maxmv = op->mv;449450/*451* Set the CPU to maximum speed.452*453* We won't have thermal throttling until interrupts are enabled, but we454* want to run at full speed through all the device init stuff. This455* basically assumes that a single core can't overheat before interrupts456* are enabled; empirical testing shows that to be a safe assumption.457*/458cpufreq_set_clock(sc, op);459}460461static inline uint32_t462temp_from_count(struct imx6_anatop_softc *sc, uint32_t count)463{464465return (((sc->temp_high_val - (count - sc->temp_high_cnt) *466(sc->temp_high_val - 250) /467(sc->temp_room_cnt - sc->temp_high_cnt))));468}469470static inline uint32_t471temp_to_count(struct imx6_anatop_softc *sc, uint32_t temp)472{473474return ((sc->temp_room_cnt - sc->temp_high_cnt) *475(sc->temp_high_val - temp) / (sc->temp_high_val - 250) +476sc->temp_high_cnt);477}478479static void480temp_update_count(struct imx6_anatop_softc *sc)481{482uint32_t val;483484val = imx6_anatop_read_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0);485if (!(val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_VALID))486return;487sc->temp_last_cnt =488(val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >>489IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT;490}491492static int493temp_sysctl_handler(SYSCTL_HANDLER_ARGS)494{495struct imx6_anatop_softc *sc = arg1;496uint32_t t;497498temp_update_count(sc);499500t = temp_from_count(sc, sc->temp_last_cnt) + TZ_ZEROC;501502return (sysctl_handle_int(oidp, &t, 0, req));503}504505static int506temp_throttle_sysctl_handler(SYSCTL_HANDLER_ARGS)507{508struct imx6_anatop_softc *sc = arg1;509int err;510uint32_t temp;511512temp = sc->temp_throttle_val + TZ_ZEROC;513err = sysctl_handle_int(oidp, &temp, 0, req);514if (temp < TZ_ZEROC)515return (ERANGE);516temp -= TZ_ZEROC;517if (err != 0 || req->newptr == NULL || temp == sc->temp_throttle_val)518return (err);519520/* Value changed, update counts in softc and hardware. */521sc->temp_throttle_val = temp;522sc->temp_throttle_trigger_cnt = temp_to_count(sc, sc->temp_throttle_val);523sc->temp_throttle_reset_cnt = temp_to_count(sc, sc->temp_throttle_val - 100);524imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_CLR,525IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_MASK);526imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_SET,527(sc->temp_throttle_trigger_cnt <<528IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT));529return (err);530}531532static void533tempmon_gofast(struct imx6_anatop_softc *sc)534{535536if (sc->cpu_curmhz < sc->cpu_maxmhz) {537cpufreq_set_clock(sc, cpufreq_nearest_oppt(sc, sc->cpu_maxmhz));538}539}540541static void542tempmon_goslow(struct imx6_anatop_softc *sc)543{544545if (sc->cpu_curmhz > sc->cpu_minmhz) {546cpufreq_set_clock(sc, cpufreq_nearest_oppt(sc, sc->cpu_minmhz));547}548}549550static int551tempmon_intr(void *arg)552{553struct imx6_anatop_softc *sc = arg;554555/*556* XXX Note that this code doesn't currently run (for some mysterious557* reason we just never get an interrupt), so the real monitoring is558* done by tempmon_throttle_check().559*/560tempmon_goslow(sc);561/* XXX Schedule callout to speed back up eventually. */562return (FILTER_HANDLED);563}564565static void566tempmon_throttle_check(void *arg)567{568struct imx6_anatop_softc *sc = arg;569570/* Lower counts are higher temperatures. */571if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt)572tempmon_goslow(sc);573else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt))574tempmon_gofast(sc);575576callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay,5770, tempmon_throttle_check, sc, 0);578579}580581static void582initialize_tempmon(struct imx6_anatop_softc *sc)583{584uint32_t cal;585586/*587* Fetch calibration data: a sensor count at room temperature (25C),588* a sensor count at a high temperature, and that temperature589*/590cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1);591sc->temp_room_cnt = (cal & 0xFFF00000) >> 20;592sc->temp_high_cnt = (cal & 0x000FFF00) >> 8;593sc->temp_high_val = (cal & 0x000000FF) * 10;594595/*596* Throttle to a lower cpu freq at 10C below the "hot" temperature, and597* reset back to max cpu freq at 5C below the trigger.598*/599sc->temp_throttle_val = sc->temp_high_val - 100;600sc->temp_throttle_trigger_cnt =601temp_to_count(sc, sc->temp_throttle_val);602sc->temp_throttle_reset_cnt =603temp_to_count(sc, sc->temp_throttle_val - 50);604605/*606* Set the sensor to sample automatically at 16Hz (32.768KHz/0x800), set607* the throttle count, and begin making measurements.608*/609imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE1, 0x0800);610imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0,611(sc->temp_throttle_trigger_cnt <<612IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) |613IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE);614615/*616* XXX Note that the alarm-interrupt feature isn't working yet, so617* we'll use a callout handler to check at 10Hz. Make sure we have an618* initial temperature reading before starting up the callouts so we619* don't get a bogus reading of zero.620*/621while (sc->temp_last_cnt == 0)622temp_update_count(sc);623sc->temp_throttle_delay = 100 * SBT_1MS;624callout_init(&sc->temp_throttle_callout, 0);625callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay,6260, tempmon_throttle_check, sc, 0);627628SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),629OID_AUTO, "temperature",630CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,631temp_sysctl_handler, "IK", "Current die temperature");632SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx),633OID_AUTO, "throttle_temperature",634CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,6350, temp_throttle_sysctl_handler, "IK",636"Throttle CPU when exceeding this temperature");637}638639static void640intr_setup(void *arg)641{642int rid;643struct imx6_anatop_softc *sc;644645sc = arg;646rid = 0;647sc->res[IRQRES] = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid,648RF_ACTIVE);649if (sc->res[IRQRES] != NULL) {650bus_setup_intr(sc->dev, sc->res[IRQRES],651INTR_TYPE_MISC | INTR_MPSAFE, tempmon_intr, NULL, sc,652&sc->temp_intrhand);653} else {654device_printf(sc->dev, "Cannot allocate IRQ resource\n");655}656config_intrhook_disestablish(&sc->intr_setup_hook);657}658659static void660imx6_anatop_new_pass(device_t dev)661{662struct imx6_anatop_softc *sc;663const int cpu_init_pass = BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE;664665/*666* We attach during BUS_PASS_BUS (because some day we will be a667* simplebus that has regulator devices as children), but some of our668* init work cannot be done until BUS_PASS_CPU (we rely on other devices669* that attach on the CPU pass).670*/671sc = device_get_softc(dev);672if (!sc->cpu_init_done && bus_get_pass() >= cpu_init_pass) {673sc->cpu_init_done = true;674cpufreq_initialize(sc);675initialize_tempmon(sc);676if (bootverbose) {677device_printf(sc->dev, "CPU %uMHz @ %umV\n",678sc->cpu_curmhz, sc->cpu_curmv);679}680}681bus_generic_new_pass(dev);682}683684static int685imx6_anatop_detach(device_t dev)686{687688/* This device can never detach. */689return (EBUSY);690}691692static int693imx6_anatop_attach(device_t dev)694{695struct imx6_anatop_softc *sc;696int err;697698sc = device_get_softc(dev);699sc->dev = dev;700701/* Allocate bus_space resources. */702if (bus_alloc_resources(dev, imx6_anatop_spec, sc->res)) {703device_printf(dev, "Cannot allocate resources\n");704err = ENXIO;705goto out;706}707708sc->intr_setup_hook.ich_func = intr_setup;709sc->intr_setup_hook.ich_arg = sc;710config_intrhook_establish(&sc->intr_setup_hook);711712SYSCTL_ADD_UINT(device_get_sysctl_ctx(sc->dev),713SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),714OID_AUTO, "cpu_voltage", CTLFLAG_RD,715&sc->cpu_curmv, 0, "Current CPU voltage in millivolts");716717imx6_anatop_sc = sc;718719/*720* Other code seen on the net sets this SELFBIASOFF flag around the same721* time the temperature sensor is set up, although it's unclear how the722* two are related (if at all).723*/724imx6_anatop_write_4(IMX6_ANALOG_PMU_MISC0_SET,725IMX6_ANALOG_PMU_MISC0_SELFBIASOFF);726727/*728* Some day, when we're ready to deal with the actual anatop regulators729* that are described in fdt data as children of this "bus", this would730* be the place to invoke a simplebus helper routine to instantiate the731* children from the fdt data.732*/733734err = 0;735736out:737738if (err != 0) {739bus_release_resources(dev, imx6_anatop_spec, sc->res);740}741742return (err);743}744745uint32_t746pll4_configure_output(uint32_t mfi, uint32_t mfn, uint32_t mfd)747{748int reg;749750/*751* Audio PLL (PLL4).752* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM)753*/754755reg = (IMX6_ANALOG_CCM_PLL_AUDIO_ENABLE);756reg &= ~(IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_MASK << \757IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT);758reg |= (mfi << IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT);759imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO, reg);760imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_NUM, mfn);761imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_DENOM, mfd);762763return (0);764}765766static int767imx6_anatop_probe(device_t dev)768{769770if (!ofw_bus_status_okay(dev))771return (ENXIO);772773if (ofw_bus_is_compatible(dev, "fsl,imx6q-anatop") == 0)774return (ENXIO);775776device_set_desc(dev, "Freescale i.MX6 Analog PLLs and Power");777778return (BUS_PROBE_DEFAULT);779}780781uint32_t782imx6_get_cpu_clock(void)783{784uint32_t corediv, plldiv;785786corediv = imx_ccm_get_cacrr();787plldiv = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) &788IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK;789return (cpufreq_mhz_from_div(imx6_anatop_sc, corediv, plldiv));790}791792static device_method_t imx6_anatop_methods[] = {793/* Device interface */794DEVMETHOD(device_probe, imx6_anatop_probe),795DEVMETHOD(device_attach, imx6_anatop_attach),796DEVMETHOD(device_detach, imx6_anatop_detach),797798/* Bus interface */799DEVMETHOD(bus_new_pass, imx6_anatop_new_pass),800801DEVMETHOD_END802};803804static driver_t imx6_anatop_driver = {805"imx6_anatop",806imx6_anatop_methods,807sizeof(struct imx6_anatop_softc)808};809810EARLY_DRIVER_MODULE(imx6_anatop, simplebus, imx6_anatop_driver, 0, 0,811BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);812EARLY_DRIVER_MODULE(imx6_anatop, ofwbus, imx6_anatop_driver, 0, 0,813BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);814815816