1/*-
2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/cpu.h>
34#include <sys/kernel.h>
35#include <sys/lock.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38
39#include <machine/bus.h>
40#include <machine/cpu.h>
41
42#include <dev/extres/clk/clk.h>
43#include <dev/extres/regulator/regulator.h>
44#include <dev/ofw/ofw_bus_subr.h>
45
46#include <arm/nvidia/tegra_efuse.h>
47
48#include "cpufreq_if.h"
49
50#define	XXX
51
52/* CPU voltage table entry */
53struct speedo_entry {
54	uint64_t		freq; 	/* Frequency point */
55	int			c0; 	/* Coeeficient values for */
56	int			c1;	/* quadratic equation: */
57	int 			c2;	/* c2 * speedo^2 + c1 * speedo + c0 */
58};
59
60struct cpu_volt_def {
61	int			min_uvolt;	/* Min allowed CPU voltage */
62	int			max_uvolt;	/* Max allowed CPU voltage */
63	int 			step_uvolt; 	/* Step of CPU voltage */
64	int			speedo_scale;	/* Scaling factor for cvt */
65	int			speedo_nitems;	/* Size of speedo table */
66	struct speedo_entry	*speedo_tbl;	/* CPU voltage table */
67};
68
69struct cpu_speed_point {
70	uint64_t		freq;		/* Frequecy */
71	int			uvolt;		/* Requested voltage */
72};
73
74static struct speedo_entry tegra124_speedo_dpll_tbl[] =
75{
76	{ 204000000ULL,	1112619, -29295, 402},
77	{ 306000000ULL,	1150460, -30585, 402},
78	{ 408000000ULL,	1190122, -31865, 402},
79	{ 510000000ULL,	1231606, -33155, 402},
80	{ 612000000ULL,	1274912, -34435, 402},
81	{ 714000000ULL,	1320040, -35725, 402},
82	{ 816000000ULL,	1366990, -37005, 402},
83	{ 918000000ULL,	1415762, -38295, 402},
84	{1020000000ULL,	1466355, -39575, 402},
85	{1122000000ULL,	1518771, -40865, 402},
86	{1224000000ULL,	1573009, -42145, 402},
87	{1326000000ULL,	1629068, -43435, 402},
88	{1428000000ULL,	1686950, -44715, 402},
89	{1530000000ULL,	1746653, -46005, 402},
90	{1632000000ULL,	1808179, -47285, 402},
91	{1734000000ULL,	1871526, -48575, 402},
92	{1836000000ULL,	1936696, -49855, 402},
93	{1938000000ULL,	2003687, -51145, 402},
94	{2014500000ULL,	2054787, -52095, 402},
95	{2116500000ULL,	2124957, -53385, 402},
96	{2218500000ULL,	2196950, -54665, 402},
97	{2320500000ULL,	2270765, -55955, 402},
98	{2320500000ULL,	2270765, -55955, 402},
99	{2422500000ULL,	2346401, -57235, 402},
100	{2524500000ULL,	2437299, -58535, 402},
101};
102
103static struct cpu_volt_def tegra124_cpu_volt_dpll_def =
104{
105	.min_uvolt =  900000,		/* 0.9 V */
106	.max_uvolt = 1260000,		/* 1.26 */
107	.step_uvolt =  10000,		/* 10 mV */
108	.speedo_scale = 100,
109	.speedo_nitems = nitems(tegra124_speedo_dpll_tbl),
110	.speedo_tbl = tegra124_speedo_dpll_tbl,
111};
112
113static struct speedo_entry tegra124_speedo_pllx_tbl[] =
114{
115	{ 204000000ULL,	 800000, 0, 0},
116	{ 306000000ULL,	 800000, 0, 0},
117	{ 408000000ULL,	 800000, 0, 0},
118	{ 510000000ULL,	 800000, 0, 0},
119	{ 612000000ULL,	 800000, 0, 0},
120	{ 714000000ULL,	 800000, 0, 0},
121	{ 816000000ULL,	 820000, 0, 0},
122	{ 918000000ULL,	 840000, 0, 0},
123	{1020000000ULL,	 880000, 0, 0},
124	{1122000000ULL,	 900000, 0, 0},
125	{1224000000ULL,	 930000, 0, 0},
126	{1326000000ULL,	 960000, 0, 0},
127	{1428000000ULL,	 990000, 0, 0},
128	{1530000000ULL,	1020000, 0, 0},
129	{1632000000ULL,	1070000, 0, 0},
130	{1734000000ULL,	1100000, 0, 0},
131	{1836000000ULL,	1140000, 0, 0},
132	{1938000000ULL,	1180000, 0, 0},
133	{2014500000ULL,	1220000, 0, 0},
134	{2116500000ULL,	1260000, 0, 0},
135	{2218500000ULL,	1310000, 0, 0},
136	{2320500000ULL,	1360000, 0, 0},
137	{2397000000ULL,	1400000, 0, 0},
138	{2499000000ULL,	1400000, 0, 0},
139};
140
141
142static struct cpu_volt_def tegra124_cpu_volt_pllx_def =
143{
144	.min_uvolt = 1000000,		/* XXX 0.9 V doesn't work on all boards */
145	.max_uvolt = 1260000,		/* 1.26 */
146	.step_uvolt =  10000,		/* 10 mV */
147	.speedo_scale = 100,
148	.speedo_nitems = nitems(tegra124_speedo_pllx_tbl),
149	.speedo_tbl = tegra124_speedo_pllx_tbl,
150};
151
152static uint64_t cpu_freq_tbl[] = {
153	 204000000ULL,
154	 306000000ULL,
155	 408000000ULL,
156	 510000000ULL,
157	 612000000ULL,
158	 714000000ULL,
159	 816000000ULL,
160	 918000000ULL,
161	1020000000ULL,
162	1122000000ULL,
163	1224000000ULL,
164	1326000000ULL,
165	1428000000ULL,
166	1530000000ULL,
167	1632000000ULL,
168	1734000000ULL,
169	1836000000ULL,
170	1938000000ULL,
171	2014000000ULL,
172	2116000000ULL,
173	2218000000ULL,
174	2320000000ULL,
175	2422000000ULL,
176	2524000000ULL,
177};
178
179static uint64_t cpu_max_freq[] = {
180	2014500000ULL,
181	2320500000ULL,
182	2116500000ULL,
183	2524500000ULL,
184};
185
186struct tegra124_cpufreq_softc {
187	device_t		dev;
188	phandle_t		node;
189
190	regulator_t		supply_vdd_cpu;
191	clk_t			clk_cpu_g;
192	clk_t			clk_cpu_lp;
193	clk_t			clk_pll_x;
194	clk_t			clk_pll_p;
195	clk_t			clk_dfll;
196
197	int 			process_id;
198	int 			speedo_id;
199	int 			speedo_value;
200
201	uint64_t		cpu_max_freq;
202	struct cpu_volt_def	*cpu_def;
203	struct cpu_speed_point	*speed_points;
204	int			nspeed_points;
205
206	struct cpu_speed_point	*act_speed_point;
207
208	int			latency;
209};
210
211static int cpufreq_lowest_freq = 1;
212TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq);
213
214#define	DIV_ROUND_CLOSEST(val, div)	(((val) + ((div) / 2)) / (div))
215
216#define	ROUND_UP(val, div)	roundup(val, div)
217#define	ROUND_DOWN(val, div)	rounddown(val, div)
218
219/*
220 * Compute requesetd voltage for given frequency and SoC process variations,
221 * - compute base voltage from speedo value using speedo table
222 * - round up voltage to next regulator step
223 * - clamp it to regulator limits
224 */
225static int
226freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq)
227{
228	int uv, scale, min_uvolt, max_uvolt, step_uvolt;
229	struct speedo_entry *ent;
230	int i;
231
232	/* Get speedo entry with higher frequency */
233	ent = NULL;
234	for (i = 0; i < sc->cpu_def->speedo_nitems; i++) {
235		if (sc->cpu_def->speedo_tbl[i].freq >= freq) {
236			ent = &sc->cpu_def->speedo_tbl[i];
237			break;
238		}
239	}
240	if (ent == NULL)
241		ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
242	scale = sc->cpu_def->speedo_scale;
243
244
245	/* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */
246	uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale);
247	uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) +
248	    ent->c0;
249	step_uvolt = sc->cpu_def->step_uvolt;
250	/* Round up it to next regulator step */
251	uv = ROUND_UP(uv, step_uvolt);
252
253	/* Clamp result */
254	min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
255	max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
256	if (uv < min_uvolt)
257		uv =  min_uvolt;
258	if (uv > max_uvolt)
259		uv =  max_uvolt;
260	return (uv);
261
262}
263
264static void
265build_speed_points(struct tegra124_cpufreq_softc *sc) {
266	int i;
267
268	sc->nspeed_points = nitems(cpu_freq_tbl);
269	sc->speed_points = malloc(sizeof(struct cpu_speed_point) *
270	    sc->nspeed_points, M_DEVBUF, M_NOWAIT);
271	for (i = 0; i < sc->nspeed_points; i++) {
272		sc->speed_points[i].freq = cpu_freq_tbl[i];
273		sc->speed_points[i].uvolt = freq_to_voltage(sc,
274		    cpu_freq_tbl[i]);
275	}
276}
277
278static struct cpu_speed_point *
279get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq)
280{
281	int i;
282
283	if (sc->speed_points[0].freq >= freq)
284		return (sc->speed_points + 0);
285
286	for (i = 0; i < sc->nspeed_points - 1; i++) {
287		if (sc->speed_points[i + 1].freq > freq)
288			return (sc->speed_points + i);
289	}
290
291	return (sc->speed_points + sc->nspeed_points - 1);
292}
293
294static int
295tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
296{
297	struct tegra124_cpufreq_softc *sc;
298	int i, j, max_cnt;
299
300	if (sets == NULL || count == NULL)
301		return (EINVAL);
302
303	sc = device_get_softc(dev);
304	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
305
306	max_cnt = min(sc->nspeed_points, *count);
307	for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
308		if (sc->cpu_max_freq < sc->speed_points[j].freq)
309			continue;
310		sets[i].freq = sc->speed_points[j].freq / 1000000;
311		sets[i].volts = sc->speed_points[j].uvolt / 1000;
312		sets[i].lat = sc->latency;
313		sets[i].dev = dev;
314		i++;
315	}
316	*count = i;
317
318	return (0);
319}
320
321static int
322set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
323{
324	struct cpu_speed_point *point;
325	int rv;
326
327	point = get_speed_point(sc, freq);
328
329	if (sc->act_speed_point->uvolt < point->uvolt) {
330		/* set cpu voltage */
331		rv = regulator_set_voltage(sc->supply_vdd_cpu,
332		    point->uvolt, point->uvolt);
333		DELAY(10000);
334		if (rv != 0)
335			return (rv);
336	}
337
338	/* Switch supermux to PLLP first */
339	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
340	if (rv != 0) {
341		device_printf(sc->dev, "Can't set parent to PLLP\n");
342		return (rv);
343	}
344
345	/* Set PLLX frequency */
346	rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
347	if (rv != 0) {
348		device_printf(sc->dev, "Can't set CPU clock frequency\n");
349		return (rv);
350	}
351
352	rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
353	if (rv != 0) {
354		device_printf(sc->dev, "Can't set parent to PLLX\n");
355		return (rv);
356	}
357
358	if (sc->act_speed_point->uvolt > point->uvolt) {
359		/* set cpu voltage */
360		rv = regulator_set_voltage(sc->supply_vdd_cpu,
361		    point->uvolt, point->uvolt);
362		if (rv != 0)
363			return (rv);
364	}
365
366	sc->act_speed_point = point;
367
368	return (0);
369}
370
371static int
372tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
373{
374	struct tegra124_cpufreq_softc *sc;
375	uint64_t freq;
376	int rv;
377
378	if (cf == NULL || cf->freq < 0)
379		return (EINVAL);
380
381	sc = device_get_softc(dev);
382
383	freq = cf->freq;
384	if (freq < cpufreq_lowest_freq)
385		freq = cpufreq_lowest_freq;
386	freq *= 1000000;
387	if (freq >= sc->cpu_max_freq)
388		freq = sc->cpu_max_freq;
389	rv = set_cpu_freq(sc, freq);
390
391	return (rv);
392}
393
394static int
395tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
396{
397	struct tegra124_cpufreq_softc *sc;
398
399	if (cf == NULL)
400		return (EINVAL);
401
402	sc = device_get_softc(dev);
403	memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
404	cf->dev = NULL;
405	cf->freq = sc->act_speed_point->freq / 1000000;
406	cf->volts = sc->act_speed_point->uvolt / 1000;
407	/* Transition latency in us. */
408	cf->lat = sc->latency;
409	/* Driver providing this setting. */
410	cf->dev = dev;
411
412	return (0);
413}
414
415
416static int
417tegra124_cpufreq_type(device_t dev, int *type)
418{
419
420	if (type == NULL)
421		return (EINVAL);
422	*type = CPUFREQ_TYPE_ABSOLUTE;
423
424	return (0);
425}
426
427static int
428get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
429{
430	int rv;
431	device_t parent_dev;
432
433	parent_dev =  device_get_parent(sc->dev);
434	rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply",
435	    &sc->supply_vdd_cpu);
436	if (rv != 0) {
437		device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
438		return (rv);
439	}
440
441	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
442	if (rv != 0) {
443		device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
444		return (ENXIO);
445	}
446
447	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp);
448	if (rv != 0) {
449		device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
450		return (ENXIO);
451	}
452
453	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
454	if (rv != 0) {
455		device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
456		return (ENXIO);
457	}
458	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
459	if (rv != 0) {
460		device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
461		return (ENXIO);
462	}
463	rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
464	if (rv != 0) {
465		/* XXX DPLL is not implemented yet */
466/*
467		device_printf(sc->dev, "Cannot get 'dfll' clock\n");
468		return (ENXIO);
469*/
470	}
471	return (0);
472}
473
474static void
475tegra124_cpufreq_identify(driver_t *driver, device_t parent)
476{
477	phandle_t root;
478
479	root = OF_finddevice("/");
480	if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124"))
481		return;
482
483	if (device_get_unit(parent) != 0)
484		return;
485	if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
486		return;
487	if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
488		device_printf(parent, "add child failed\n");
489}
490
491static int
492tegra124_cpufreq_probe(device_t dev)
493{
494
495	device_set_desc(dev, "CPU Frequency Control");
496
497	return (0);
498}
499
500static int
501tegra124_cpufreq_attach(device_t dev)
502{
503	struct tegra124_cpufreq_softc *sc;
504	uint64_t freq;
505	int rv;
506
507	sc = device_get_softc(dev);
508	sc->dev = dev;
509	sc->node = ofw_bus_get_node(device_get_parent(dev));
510
511	sc->process_id = tegra_sku_info.cpu_process_id;
512	sc->speedo_id = tegra_sku_info.cpu_speedo_id;
513	sc->speedo_value = tegra_sku_info.cpu_speedo_value;
514
515	/* Tegra 124 */
516	/* XXX DPLL is not implemented yet */
517	if (1)
518		sc->cpu_def = &tegra124_cpu_volt_pllx_def;
519	else
520		sc->cpu_def = &tegra124_cpu_volt_dpll_def;
521
522
523	rv = get_fdt_resources(sc, sc->node);
524	if (rv !=  0) {
525		return (rv);
526	}
527
528	build_speed_points(sc);
529
530	rv = clk_get_freq(sc->clk_cpu_g, &freq);
531	if (rv != 0) {
532		device_printf(dev, "Can't get CPU clock frequency\n");
533		return (rv);
534	}
535	if (sc->speedo_id < nitems(cpu_max_freq))
536		sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
537	else
538		sc->cpu_max_freq = cpu_max_freq[0];
539	sc->act_speed_point = get_speed_point(sc, freq);
540
541	/* Set safe startup CPU frequency. */
542	rv = set_cpu_freq(sc, 1632000000);
543	if (rv != 0) {
544		device_printf(dev, "Can't set initial CPU clock frequency\n");
545		return (rv);
546	}
547
548	/* This device is controlled by cpufreq(4). */
549	cpufreq_register(dev);
550
551	return (0);
552}
553
554static int
555tegra124_cpufreq_detach(device_t dev)
556{
557	struct tegra124_cpufreq_softc *sc;
558
559	sc = device_get_softc(dev);
560	cpufreq_unregister(dev);
561
562	if (sc->supply_vdd_cpu != NULL)
563		regulator_release(sc->supply_vdd_cpu);
564
565	if (sc->clk_cpu_g != NULL)
566		clk_release(sc->clk_cpu_g);
567	if (sc->clk_cpu_lp != NULL)
568		clk_release(sc->clk_cpu_lp);
569	if (sc->clk_pll_x != NULL)
570		clk_release(sc->clk_pll_x);
571	if (sc->clk_pll_p != NULL)
572		clk_release(sc->clk_pll_p);
573	if (sc->clk_dfll != NULL)
574		clk_release(sc->clk_dfll);
575	return (0);
576}
577
578static device_method_t tegra124_cpufreq_methods[] = {
579	/* Device interface */
580	DEVMETHOD(device_identify,	tegra124_cpufreq_identify),
581	DEVMETHOD(device_probe,		tegra124_cpufreq_probe),
582	DEVMETHOD(device_attach,	tegra124_cpufreq_attach),
583	DEVMETHOD(device_detach,	tegra124_cpufreq_detach),
584
585	/* cpufreq interface */
586	DEVMETHOD(cpufreq_drv_set,	tegra124_cpufreq_set),
587	DEVMETHOD(cpufreq_drv_get,	tegra124_cpufreq_get),
588	DEVMETHOD(cpufreq_drv_settings,	tegra124_cpufreq_settings),
589	DEVMETHOD(cpufreq_drv_type,	tegra124_cpufreq_type),
590
591	DEVMETHOD_END
592};
593
594static devclass_t tegra124_cpufreq_devclass;
595static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
596    tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
597DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver,
598    tegra124_cpufreq_devclass, NULL, NULL);
599