]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/nvidia/tegra124/tegra124_cpufreq.c
Merge from upstream at 4189ef5d from https://github.com/onetrueawk/awk.git
[FreeBSD/FreeBSD.git] / sys / arm / nvidia / tegra124 / tegra124_cpufreq.c
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 */
53 struct 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
60 struct 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
69 struct cpu_speed_point {
70         uint64_t                freq;           /* Frequecy */
71         int                     uvolt;          /* Requested voltage */
72 };
73
74 static 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
103 static 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
113 static 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
142 static 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
152 static 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
179 static uint64_t cpu_max_freq[] = {
180         2014500000ULL,
181         2320500000ULL,
182         2116500000ULL,
183         2524500000ULL,
184 };
185
186 struct 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
211 static int cpufreq_lowest_freq = 1;
212 TUNABLE_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  */
225 static int
226 freq_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
264 static void
265 build_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
278 static struct cpu_speed_point *
279 get_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
294 static int
295 tegra124_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
321 static int
322 set_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
371 static int
372 tegra124_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
394 static int
395 tegra124_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
416 static int
417 tegra124_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
427 static int
428 get_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
474 static void
475 tegra124_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
491 static int
492 tegra124_cpufreq_probe(device_t dev)
493 {
494
495         device_set_desc(dev, "CPU Frequency Control");
496
497         return (0);
498 }
499
500 static int
501 tegra124_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
554 static int
555 tegra124_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
578 static 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
594 static devclass_t tegra124_cpufreq_devclass;
595 static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver,
596     tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc));
597 DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver,
598     tegra124_cpufreq_devclass, NULL, NULL);