1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/bus.h>
31#include <sys/cpu.h>
32#include <sys/kernel.h>
33#include <sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/module.h>
36
37#include <machine/bus.h>
38#include <machine/cpu.h>
39
40#include <dev/clk/clk.h>
41#include <dev/regulator/regulator.h>
42#include <dev/ofw/ofw_bus_subr.h>
43
44#include <arm/nvidia/tegra_efuse.h>
45
46#include "cpufreq_if.h"
47
48/* CPU voltage table entry */
49struct speedo_entry {
50	uint64_t		freq; 	/* Frequency point */
51	int			c0; 	/* Coeeficient values for */
52	int			c1;	/* quadratic equation: */
53	int 			c2;	/* c2 * speedo^2 + c1 * speedo + c0 */
54};
55
56struct cpu_volt_def {
57	int			min_uvolt;	/* Min allowed CPU voltage */
58	int			max_uvolt;	/* Max allowed CPU voltage */
59	int 			step_uvolt; 	/* Step of CPU voltage */
60	int			speedo_scale;	/* Scaling factor for cvt */
61	int			speedo_nitems;	/* Size of speedo table */
62	struct speedo_entry	*speedo_tbl;	/* CPU voltage table */
63};
64
65struct cpu_speed_point {
66	uint64_t		freq;		/* Frequecy */
67	int			uvolt;		/* Requested voltage */
68};
69
70static struct speedo_entry tegra210_speedo_tbl[] =
71{
72	{204000000UL,	1007452, -23865, 370},
73	{306000000UL,	1052709, -24875, 370},
74	{408000000UL,	1099069, -25895, 370},
75	{510000000UL,	1146534, -26905, 370},
76	{612000000UL,	1195102, -27915, 370},
77	{714000000UL,	1244773, -28925, 370},
78	{816000000UL,	1295549, -29935, 370},
79	{918000000UL,	1347428, -30955, 370},
80	{1020000000UL,	1400411, -31965, 370},
81	{1122000000UL,	1454497, -32975, 370},
82	{1224000000UL,	1509687, -33985, 370},
83	{1326000000UL,	1565981, -35005, 370},
84	{1428000000UL,	1623379, -36015, 370},
85	{1530000000UL,	1681880, -37025, 370},
86	{1632000000UL,	1741485, -38035, 370},
87	{1734000000UL,	1802194, -39055, 370},
88	{1836000000UL,	1864006, -40065, 370},
89	{1912500000UL,	1910780, -40815, 370},
90	{2014500000UL,	1227000,      0,   0},
91	{2218500000UL,	1227000,      0,   0},
92};
93
94static struct cpu_volt_def tegra210_cpu_volt_def =
95{
96	.min_uvolt = 900000,		/* 0.9 V */
97	.max_uvolt = 1227000,		/* 1.227 */
98	.step_uvolt =  10000,		/* 10 mV */
99	.speedo_scale = 100,
100	.speedo_nitems = nitems(tegra210_speedo_tbl),
101	.speedo_tbl = tegra210_speedo_tbl,
102};
103
104static uint64_t cpu_max_freq[] = {
105	1912500000UL,
106	1912500000UL,
107	2218500000UL,
108	1785000000UL,
109	1632000000UL,
110	1912500000UL,
111	2014500000UL,
112	1734000000UL,
113	1683000000UL,
114	1555500000UL,
115	1504500000UL,
116};
117
118static uint64_t cpu_freq_tbl[] = {
119	 204000000UL,
120	 306000000UL,
121	 408000000UL,
122	 510000000UL,
123	 612000000UL,
124	 714000000UL,
125	 816000000UL,
126	 918000000UL,
127	1020000000UL,
128	1122000000UL,
129	1224000000UL,
130	1326000000UL,
131	1428000000UL,
132	1530000000UL,
133	1632000000UL,
134	1734000000UL,
135	1836000000UL,
136	1912500000UL,
137	2014500000UL,
138	2218500000UL,
139};
140
141struct tegra210_cpufreq_softc {
142	device_t		dev;
143	phandle_t		node;
144
145	clk_t			clk_cpu_g;
146	clk_t			clk_pll_x;
147	clk_t			clk_pll_p;
148	clk_t			clk_dfll;
149
150	int 			process_id;
151	int 			speedo_id;
152	int 			speedo_value;
153
154	uint64_t		cpu_max_freq;
155	struct cpu_volt_def	*cpu_def;
156	struct cpu_speed_point	*speed_points;
157	int			nspeed_points;
158
159	struct cpu_speed_point	*act_speed_point;
160
161	int			latency;
162};
163
164static int cpufreq_lowest_freq = 1;
165TUNABLE_INT("hw.tegra210.cpufreq.lowest_freq", &cpufreq_lowest_freq);
166
167#define	DIV_ROUND_CLOSEST(val, div)	(((val) + ((div) / 2)) / (div))
168
169#define	ROUND_UP(val, div)	roundup(val, div)
170#define	ROUND_DOWN(val, div)	rounddown(val, div)
171
172/*
173 * Compute requesetd voltage for given frequency and SoC process variations,
174 * - compute base voltage from speedo value using speedo table
175 * - round up voltage to next regulator step
176 * - clamp it to regulator limits
177 */
178static int
179freq_to_voltage(struct tegra210_cpufreq_softc *sc, uint64_t freq)
180{
181	int uv, scale, min_uvolt, max_uvolt, step_uvolt;
182	struct speedo_entry *ent;
183	int i;
184
185	/* Get speedo entry with higher frequency */
186	ent = NULL;
187	for (i = 0; i < sc->cpu_def->speedo_nitems; i++) {
188		if (sc->cpu_def->speedo_tbl[i].freq >= freq) {
189			ent = &sc->cpu_def->speedo_tbl[i];
190			break;
191		}
192	}
193	if (ent == NULL)
194		ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
195	scale = sc->cpu_def->speedo_scale;
196
197
198	/* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */
199	uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale);
200	uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) +
201	    ent->c0;
202	step_uvolt = sc->cpu_def->step_uvolt;
203	/* Round up it to next regulator step */
204	uv = ROUND_UP(uv, step_uvolt);
205
206	/* Clamp result */
207	min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
208	max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
209	if (uv < min_uvolt)
210		uv =  min_uvolt;
211	if (uv > max_uvolt)
212		uv =  max_uvolt;
213	return (uv);
214
215}
216
217static void
218build_speed_points(struct tegra210_cpufreq_softc *sc) {
219	int i;
220
221	sc->nspeed_points = nitems(cpu_freq_tbl);
222	sc->speed_points = malloc(sizeof(struct cpu_speed_point) *
223	    sc->nspeed_points, M_DEVBUF, M_NOWAIT);
224	for (i = 0; i < sc->nspeed_points; i++) {
225		sc->speed_points[i].freq = cpu_freq_tbl[i];
226		sc->speed_points[i].uvolt = freq_to_voltage(sc,
227		    cpu_freq_tbl[i]);
228	}
229}
230
231static struct cpu_speed_point *
232get_speed_point(struct tegra210_cpufreq_softc *sc, uint64_t freq)
233{
234	int i;
235
236	if (sc->speed_points[0].freq >= freq)
237		return (sc->speed_points + 0);
238
239	for (i = 0; i < sc->nspeed_points - 1; i++) {
240		if (sc->speed_points[i + 1].freq > freq)
241			return (sc->speed_points + i);
242	}
243
244	return (sc->speed_points + sc->nspeed_points - 1);
245}
246
247static int
248tegra210_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
249{
250	struct tegra210_cpufreq_softc *sc;
251	int i, j;
252
253	if (sets == NULL || count == NULL)
254		return (EINVAL);
255
256	sc = device_get_softc(dev);
257	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
258
259	for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
260		if (sc->cpu_max_freq < sc->speed_points[j].freq)
261			continue;
262		sets[i].freq = sc->speed_points[j].freq / 1000000;
263		sets[i].volts = sc->speed_points[j].uvolt / 1000;
264		sets[i].lat = sc->latency;
265		sets[i].dev = dev;
266		i++;
267	}
268	*count = i;
269
270	return (0);
271}
272
273static int
274set_cpu_freq(struct tegra210_cpufreq_softc *sc, uint64_t freq)
275{
276	struct cpu_speed_point *point;
277	int rv;
278
279	point = get_speed_point(sc, freq);
280
281	/* Set PLLX frequency */
282	rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
283	if (rv != 0) {
284		device_printf(sc->dev, "Can't set CPU clock frequency\n");
285		return (rv);
286	}
287
288	sc->act_speed_point = point;
289
290	return (0);
291}
292
293static int
294tegra210_cpufreq_set(device_t dev, const struct cf_setting *cf)
295{
296	struct tegra210_cpufreq_softc *sc;
297	uint64_t freq;
298	int rv;
299
300	if (cf == NULL || cf->freq < 0)
301		return (EINVAL);
302
303	sc = device_get_softc(dev);
304
305	freq = cf->freq;
306	if (freq < cpufreq_lowest_freq)
307		freq = cpufreq_lowest_freq;
308	freq *= 1000000;
309	if (freq >= sc->cpu_max_freq)
310		freq = sc->cpu_max_freq;
311	rv = set_cpu_freq(sc, freq);
312
313	return (rv);
314}
315
316static int
317tegra210_cpufreq_get(device_t dev, struct cf_setting *cf)
318{
319	struct tegra210_cpufreq_softc *sc;
320
321	if (cf == NULL)
322		return (EINVAL);
323
324	sc = device_get_softc(dev);
325	memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
326	cf->dev = NULL;
327	cf->freq = sc->act_speed_point->freq / 1000000;
328	cf->volts = sc->act_speed_point->uvolt / 1000;
329	/* Transition latency in us. */
330	cf->lat = sc->latency;
331	/* Driver providing this setting. */
332	cf->dev = dev;
333
334	return (0);
335}
336
337
338static int
339tegra210_cpufreq_type(device_t dev, int *type)
340{
341
342	if (type == NULL)
343		return (EINVAL);
344	*type = CPUFREQ_TYPE_ABSOLUTE;
345
346	return (0);
347}
348
349static int
350get_fdt_resources(struct tegra210_cpufreq_softc *sc, phandle_t node)
351{
352	int rv;
353	device_t parent_dev;
354
355	parent_dev =  device_get_parent(sc->dev);
356
357	rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g);
358	if (rv != 0) {
359		device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
360		return (ENXIO);
361	}
362
363	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x);
364	if (rv != 0) {
365		device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
366		return (ENXIO);
367	}
368	rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p);
369	if (rv != 0) {
370		device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
371		return (ENXIO);
372	}
373	rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll);
374
375	/* XXX DPLL is not implemented yet */
376#if 0
377	if (rv != 0) {
378		device_printf(sc->dev, "Cannot get 'dfll' clock\n");
379		return (ENXIO);
380	}
381#endif
382	return (0);
383}
384
385static void
386tegra210_cpufreq_identify(driver_t *driver, device_t parent)
387{
388	phandle_t root;
389
390	root = OF_finddevice("/");
391	if (!ofw_bus_node_is_compatible(root, "nvidia,tegra210"))
392		return;
393
394	if (device_get_unit(parent) != 0)
395		return;
396	if (device_find_child(parent, "tegra210_cpufreq", -1) != NULL)
397		return;
398	if (BUS_ADD_CHILD(parent, 0, "tegra210_cpufreq", -1) == NULL)
399		device_printf(parent, "add child failed\n");
400}
401
402static int
403tegra210_cpufreq_probe(device_t dev)
404{
405
406	device_set_desc(dev, "CPU Frequency Control");
407
408	return (0);
409}
410
411static int
412tegra210_cpufreq_attach(device_t dev)
413{
414	struct tegra210_cpufreq_softc *sc;
415	uint64_t freq;
416	int rv;
417
418	sc = device_get_softc(dev);
419	sc->dev = dev;
420	sc->node = ofw_bus_get_node(device_get_parent(dev));
421
422	sc->process_id = tegra_sku_info.cpu_process_id;
423	sc->speedo_id = tegra_sku_info.cpu_speedo_id;
424	sc->speedo_value = tegra_sku_info.cpu_speedo_value;
425
426	sc->cpu_def = &tegra210_cpu_volt_def;
427
428	rv = get_fdt_resources(sc, sc->node);
429	if (rv !=  0) {
430		return (rv);
431	}
432
433	build_speed_points(sc);
434
435	rv = clk_get_freq(sc->clk_cpu_g, &freq);
436	if (rv != 0) {
437		device_printf(dev, "Can't get CPU clock frequency\n");
438		return (rv);
439	}
440	if (sc->speedo_id < nitems(cpu_max_freq))
441		sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
442	else
443		sc->cpu_max_freq = cpu_max_freq[0];
444	sc->act_speed_point = get_speed_point(sc, freq);
445
446	/* Set safe startup CPU frequency. */
447	rv = set_cpu_freq(sc, 1632000000);
448	if (rv != 0) {
449		device_printf(dev, "Can't set initial CPU clock frequency\n");
450		return (rv);
451	}
452
453	/* This device is controlled by cpufreq(4). */
454	cpufreq_register(dev);
455
456	return (0);
457}
458
459static int
460tegra210_cpufreq_detach(device_t dev)
461{
462	struct tegra210_cpufreq_softc *sc;
463
464	sc = device_get_softc(dev);
465	cpufreq_unregister(dev);
466
467	if (sc->clk_cpu_g != NULL)
468		clk_release(sc->clk_cpu_g);
469	if (sc->clk_pll_x != NULL)
470		clk_release(sc->clk_pll_x);
471	if (sc->clk_pll_p != NULL)
472		clk_release(sc->clk_pll_p);
473	if (sc->clk_dfll != NULL)
474		clk_release(sc->clk_dfll);
475	return (0);
476}
477
478static device_method_t tegra210_cpufreq_methods[] = {
479	/* Device interface */
480	DEVMETHOD(device_identify,	tegra210_cpufreq_identify),
481	DEVMETHOD(device_probe,		tegra210_cpufreq_probe),
482	DEVMETHOD(device_attach,	tegra210_cpufreq_attach),
483	DEVMETHOD(device_detach,	tegra210_cpufreq_detach),
484
485	/* cpufreq interface */
486	DEVMETHOD(cpufreq_drv_set,	tegra210_cpufreq_set),
487	DEVMETHOD(cpufreq_drv_get,	tegra210_cpufreq_get),
488	DEVMETHOD(cpufreq_drv_settings,	tegra210_cpufreq_settings),
489	DEVMETHOD(cpufreq_drv_type,	tegra210_cpufreq_type),
490
491	DEVMETHOD_END
492};
493
494static DEFINE_CLASS_0(tegra210_cpufreq, tegra210_cpufreq_driver,
495    tegra210_cpufreq_methods, sizeof(struct tegra210_cpufreq_softc));
496DRIVER_MODULE(tegra210_cpufreq, cpu, tegra210_cpufreq_driver, NULL, NULL);
497