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: releng/10.3/sys/arm/freescale/imx/imx6_anatop.c 294678 2016-01-24 19:34:05Z ian $");
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