static void initialize_tempmon(struct imx6_anatop_softc *sc) { uint32_t cal; struct sysctl_ctx_list *ctx; /* * Fetch calibration data: a sensor count at room temperature (25C), * a sensor count at a high temperature, and that temperature */ cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1); sc->temp_room_cnt = (cal & 0xFFF00000) >> 20; sc->temp_high_cnt = (cal & 0x000FFF00) >> 8; sc->temp_high_val = (cal & 0x000000FF) * 10; /* * Throttle to a lower cpu freq at 10C below the "hot" temperature, and * reset back to max cpu freq at 5C below the trigger. */ sc->temp_throttle_val = sc->temp_high_val - 100; sc->temp_throttle_trigger_cnt = temp_to_count(sc, sc->temp_throttle_val); sc->temp_throttle_reset_cnt = temp_to_count(sc, sc->temp_throttle_val - 50); /* * Set the sensor to sample automatically at 16Hz (32.768KHz/0x800), set * the throttle count, and begin making measurements. */ imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE1, 0x0800); imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0, (sc->temp_throttle_trigger_cnt << IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) | IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE); /* * XXX Note that the alarm-interrupt feature isn't working yet, so * we'll use a callout handler to check at 10Hz. Make sure we have an * initial temperature reading before starting up the callouts so we * don't get a bogus reading of zero. */ while (sc->temp_last_cnt == 0) temp_update_count(sc); sc->temp_throttle_delay = 100 * SBT_1MS; callout_init(&sc->temp_throttle_callout, 0); callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 0, tempmon_throttle_check, sc, 0); ctx = device_get_sysctl_ctx(sc->dev); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, temp_sysctl_handler, "IK", "Current die temperature"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "throttle_temperature", CTLTYPE_INT | CTLFLAG_RW, sc, 0, temp_throttle_sysctl_handler, "IK", "Throttle CPU when exceeding this temperature"); }
static void cpufreq_initialize(struct imx6_anatop_softc *sc) { uint32_t cfg3speed; struct oppt * op; SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx6), OID_AUTO, "cpu_mhz", CTLFLAG_RD, &sc->cpu_curmhz, 0, "CPU frequency"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx6), OID_AUTO, "cpu_minmhz", CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, cpufreq_sysctl_minmhz, "IU", "Minimum CPU frequency"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx6), OID_AUTO, "cpu_maxmhz", CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, cpufreq_sysctl_maxmhz, "IU", "Maximum CPU frequency"); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx6), OID_AUTO, "cpu_maxmhz_hw", CTLFLAG_RD, &sc->cpu_maxmhz_hw, 0, "Maximum CPU frequency allowed by hardware"); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx6), OID_AUTO, "cpu_overclock_enable", CTLFLAG_RWTUN, &sc->cpu_overclock_enable, 0, "Allow setting CPU frequency higher than cpu_maxmhz_hw"); /* * XXX 24mhz shouldn't be hard-coded, should get this from imx6_ccm * (even though in the real world it will always be 24mhz). Oh wait a * sec, I never wrote imx6_ccm. */ sc->refosc_mhz = 24; /* * Get the maximum speed this cpu can be set to. The values in the * OCOTP CFG3 register are not documented in the reference manual. * The following info was in an archived email found via web search: * - 2b'11: 1200000000Hz; * - 2b'10: 996000000Hz; * - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. * - 2b'00: 792000000Hz; * The default hardware max speed can be overridden by a tunable. */ cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT; sc->cpu_maxmhz_hw = imx6_ocotp_mhz_tab[cfg3speed]; sc->cpu_maxmhz = sc->cpu_maxmhz_hw; TUNABLE_INT_FETCH("hw.imx6.cpu_overclock_enable", &sc->cpu_overclock_enable); TUNABLE_INT_FETCH("hw.imx6.cpu_minmhz", &sc->cpu_minmhz); op = cpufreq_nearest_oppt(sc, sc->cpu_minmhz); sc->cpu_minmhz = op->mhz; sc->cpu_minmv = op->mv; TUNABLE_INT_FETCH("hw.imx6.cpu_maxmhz", &sc->cpu_maxmhz); op = cpufreq_nearest_oppt(sc, sc->cpu_maxmhz); sc->cpu_maxmhz = op->mhz; sc->cpu_maxmv = op->mv; /* * Set the CPU to maximum speed. * * We won't have thermal throttling until interrupts are enabled, but we * want to run at full speed through all the device init stuff. This * basically assumes that a single core can't overheat before interrupts * are enabled; empirical testing shows that to be a safe assumption. */ cpufreq_set_clock(sc, op); }