blob: 9a088244dd1efdc50d002b297db6e282e44ce1a5 [file] [log] [blame]
Tero Kristo9d233b42019-10-24 15:00:46 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Texas Instruments' K3 Clas 0 Adaptive Voltage Scaling driver
4 *
5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Tero Kristo <t-kristo@ti.com>
7 *
8 */
9
10#include <common.h>
11#include <dm.h>
12#include <errno.h>
13#include <asm/io.h>
14#include <i2c.h>
15#include <k3-avs.h>
Simon Glass336d4612020-02-03 07:36:16 -070016#include <dm/device_compat.h>
Simon Glasscd93d622020-05-10 11:40:13 -060017#include <linux/bitops.h>
Udit Kumarb2549752023-10-19 12:57:53 +053018#include <linux/delay.h>
Tero Kristo9d233b42019-10-24 15:00:46 +053019#include <power/regulator.h>
20
21#define AM6_VTM_DEVINFO(i) (priv->base + 0x100 + 0x20 * (i))
22#define AM6_VTM_OPPVID_VD(i) (priv->base + 0x104 + 0x20 * (i))
23
24#define AM6_VTM_AVS0_SUPPORTED BIT(12)
25
26#define AM6_VTM_OPP_SHIFT(opp) (8 * (opp))
27#define AM6_VTM_OPP_MASK 0xff
28
Udit Kumarb2549752023-10-19 12:57:53 +053029#define K3_VTM_DEVINFO_PWR0_OFFSET 0x4
30#define K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK 0xf0
31#define K3_VTM_TMPSENS0_CTRL_OFFSET 0x300
32#define K3_VTM_TMPSENS_STAT_OFFSET 0x8
33#define K3_VTM_ANYMAXT_OUTRG_ALERT_EN 0x1
34#define K3_VTM_LOW_TEMP_OFFSET 0x10
35#define K3_VTM_MISC_CTRL2_OFFSET 0x10
36#define K3_VTM_MISC_CTRL1_OFFSET 0xc
37#define K3_VTM_TMPSENS_CTRL1_SOC BIT(5)
38#define K3_VTM_TMPSENS_CTRL_CLRZ BIT(6)
39#define K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN BIT(11)
40#define K3_VTM_ADC_COUNT_FOR_123C 0x2f8
41#define K3_VTM_ADC_COUNT_FOR_105C 0x288
42#define K3_VTM_ADC_WA_VALUE 0x2c
43#define K3_VTM_FUSE_MASK 0xc0000000
44
Tero Kristo9d233b42019-10-24 15:00:46 +053045#define VD_FLAG_INIT_DONE BIT(0)
46
47struct k3_avs_privdata {
48 void *base;
49 struct vd_config *vd_config;
Udit Kumarb2549752023-10-19 12:57:53 +053050 struct udevice *dev;
Tero Kristo9d233b42019-10-24 15:00:46 +053051};
52
53struct opp {
54 u32 freq;
55 u32 volt;
56};
57
58struct vd_data {
59 int id;
60 u8 opp;
61 u8 flags;
62 int dev_id;
63 int clk_id;
64 struct opp opps[NUM_OPPS];
65 struct udevice *supply;
66};
67
68struct vd_config {
69 struct vd_data *vds;
70 u32 (*efuse_xlate)(struct k3_avs_privdata *priv, int idx, int opp);
71};
72
73static struct k3_avs_privdata *k3_avs_priv;
74
75/**
76 * am6_efuse_voltage: read efuse voltage from VTM
77 * @priv: driver private data
78 * @idx: VD to read efuse for
79 * @opp: opp id to read
80 *
81 * Reads efuse value for the specified OPP, and converts the register
82 * value to a voltage. Returns the voltage in uV, or 0 if nominal voltage
83 * should be used.
84 *
85 * Efuse val to volt conversion logic:
86 *
87 * val > 171 volt increments in 20mV steps with base 171 => 1.66V
88 * val between 115 to 11 increments in 10mV steps with base 115 => 1.1V
89 * val between 15 to 115 increments in 5mV steps with base 15 => .6V
90 * val between 1 to 15 increments in 20mv steps with base 0 => .3V
91 * val 0 is invalid
92 */
93static u32 am6_efuse_xlate(struct k3_avs_privdata *priv, int idx, int opp)
94{
95 u32 val = readl(AM6_VTM_OPPVID_VD(idx));
96
97 val >>= AM6_VTM_OPP_SHIFT(opp);
98 val &= AM6_VTM_OPP_MASK;
99
100 if (!val)
101 return 0;
102
103 if (val > 171)
104 return 1660000 + 20000 * (val - 171);
105
106 if (val > 115)
107 return 1100000 + 10000 * (val - 115);
108
109 if (val > 15)
110 return 600000 + 5000 * (val - 15);
111
112 return 300000 + 20000 * val;
113}
114
115static int k3_avs_program_voltage(struct k3_avs_privdata *priv,
116 struct vd_data *vd,
117 int opp_id)
118{
119 u32 volt = vd->opps[opp_id].volt;
120 struct vd_data *vd2;
121
122 if (!vd->supply)
123 return -ENODEV;
124
125 vd->opp = opp_id;
126 vd->flags |= VD_FLAG_INIT_DONE;
127
128 /* Take care of ganged rails and pick the Max amongst them*/
129 for (vd2 = priv->vd_config->vds; vd2->id >= 0; vd2++) {
130 if (vd == vd2)
131 continue;
132
133 if (vd2->supply != vd->supply)
134 continue;
135
136 if (vd2->opps[vd2->opp].volt > volt)
137 volt = vd2->opps[vd2->opp].volt;
138
139 vd2->flags |= VD_FLAG_INIT_DONE;
140 }
141
142 return regulator_set_value(vd->supply, volt);
143}
144
145static struct vd_data *get_vd(struct k3_avs_privdata *priv, int idx)
146{
147 struct vd_data *vd;
148
149 for (vd = priv->vd_config->vds; vd->id >= 0 && vd->id != idx; vd++)
150 ;
151
152 if (vd->id < 0)
153 return NULL;
154
155 return vd;
156}
157
158/**
159 * k3_avs_set_opp: Sets the voltage for an arbitrary VD rail
160 * @dev: AVS device
161 * @vdd_id: voltage domain ID
162 * @opp_id: OPP ID
163 *
164 * Programs the desired OPP value for the defined voltage rail. This
165 * should be called from board files if reconfiguration is desired.
166 * Returns 0 on success, negative error value on failure.
167 */
168int k3_avs_set_opp(struct udevice *dev, int vdd_id, int opp_id)
169{
170 struct k3_avs_privdata *priv = dev_get_priv(dev);
171 struct vd_data *vd;
172
173 vd = get_vd(priv, vdd_id);
174 if (!vd)
175 return -EINVAL;
176
177 return k3_avs_program_voltage(priv, vd, opp_id);
178}
179
180static int match_opp(struct vd_data *vd, u32 freq)
181{
182 struct opp *opp;
183 int opp_id;
184
185 for (opp_id = 0; opp_id < NUM_OPPS; opp_id++) {
186 opp = &vd->opps[opp_id];
187 if (opp->freq == freq)
188 return opp_id;
189 }
190
191 printf("No matching OPP found for freq %d.\n", freq);
192
193 return -EINVAL;
194}
195
196/**
197 * k3_avs_notify_freq: Notify clock rate change towards AVS subsystem
198 * @dev_id: Device ID for the clock to be changed
199 * @clk_id: Clock ID for the clock to be changed
200 * @freq: New frequency for clock
201 *
202 * Checks if the provided clock is the MPU clock or not, if not, return
203 * immediately. If MPU clock is provided, maps the provided MPU frequency
204 * towards an MPU OPP, and programs the voltage to the regulator. Return 0
205 * on success, negative error value on failure.
206 */
207int k3_avs_notify_freq(int dev_id, int clk_id, u32 freq)
208{
209 int opp_id;
210 struct k3_avs_privdata *priv = k3_avs_priv;
211 struct vd_data *vd;
212
Vignesh Raghavendra7a8d03f2020-02-14 17:52:17 +0530213 /* Driver may not be probed yet */
214 if (!priv)
215 return -EINVAL;
216
Tero Kristo9d233b42019-10-24 15:00:46 +0530217 for (vd = priv->vd_config->vds; vd->id >= 0; vd++) {
218 if (vd->dev_id != dev_id || vd->clk_id != clk_id)
219 continue;
220
221 opp_id = match_opp(vd, freq);
222 if (opp_id < 0)
223 return opp_id;
224
225 vd->opp = opp_id;
226 return k3_avs_program_voltage(priv, vd, opp_id);
227 }
228
229 return -EINVAL;
230}
231
232static int k3_avs_configure(struct udevice *dev, struct k3_avs_privdata *priv)
233{
234 struct vd_config *conf;
235 int ret;
236 char pname[20];
237 struct vd_data *vd;
238
239 conf = (void *)dev_get_driver_data(dev);
240
241 priv->vd_config = conf;
242
243 for (vd = conf->vds; vd->id >= 0; vd++) {
244 sprintf(pname, "vdd-supply-%d", vd->id);
245 ret = device_get_supply_regulator(dev, pname, &vd->supply);
246 if (ret)
247 dev_warn(dev, "supply not found for VD%d.\n", vd->id);
248
249 sprintf(pname, "ti,default-opp-%d", vd->id);
250 ret = dev_read_u32_default(dev, pname, -1);
251 if (ret != -1)
252 vd->opp = ret;
253 }
254
255 return 0;
256}
257
Udit Kumarb2549752023-10-19 12:57:53 +0530258/* k3_avs_program_tshut : Program thermal shutdown value for SOC
259 * set the values corresponding to thresholds to ~123C and 105C
260 * This is optional feature, Few times OS driver takes care of
261 * tshut programing.
262 */
263
264static void k3_avs_program_tshut(struct k3_avs_privdata *priv)
265{
266 int cnt, id, val;
267 int workaround_needed = 0;
268 u32 ctrl_offset;
269 void __iomem *cfg2_base;
270 void __iomem *fuse_base;
271
272 cfg2_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 1);
273 if (IS_ERR(cfg2_base)) {
274 dev_err(priv->dev, "cfg base is not defined\n");
275 return;
276 }
277
278 /*
279 * Some of TI's J721E SoCs require a software trimming procedure
280 * for the temperature monitors to function properly. To determine
281 * if this particular SoC is NOT affected, both bits in the
282 * WKUP_SPARE_FUSE0[31:30] will be set (0xC0000000) indicating
283 * when software trimming should NOT be applied.
284 *
285 * https://www.ti.com/lit/er/sprz455c/sprz455c.pdf
286 * This routine checks if workaround_needed to be applied or not
287 * based upon workaround_needed, adjust fixed value of tshut high and low
288 */
289
290 if (device_is_compatible(priv->dev, "ti,j721e-vtm")) {
291 fuse_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 2);
292 if (IS_ERR(fuse_base)) {
293 dev_err(priv->dev, "fuse-base is not defined for J721E Soc\n");
294 return;
295 }
296
297 if (!((readl(fuse_base) & K3_VTM_FUSE_MASK) == K3_VTM_FUSE_MASK))
298 workaround_needed = 1;
299 }
300
301 dev_dbg(priv->dev, "Work around %sneeded\n", workaround_needed ? "" : "not ");
302
303 /* Get the sensor count in the VTM */
304 val = readl(priv->base + K3_VTM_DEVINFO_PWR0_OFFSET);
305 cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
306 cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
307
308 /* Program the thermal sensors */
309 for (id = 0; id < cnt; id++) {
310 ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20;
311
312 val = readl(cfg2_base + ctrl_offset);
313 val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN |
314 K3_VTM_TMPSENS_CTRL1_SOC |
315 K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4));
316 writel(val, cfg2_base + ctrl_offset);
317 }
318
319 /*
320 * Program TSHUT thresholds
321 * Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2
322 * Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit
323 * This is already taken care as per of init
324 * Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit
325 */
326
327 /* Low thresholds for tshut*/
328 val = (K3_VTM_ADC_COUNT_FOR_105C - workaround_needed * K3_VTM_ADC_WA_VALUE)
329 << K3_VTM_LOW_TEMP_OFFSET;
330 /* high thresholds */
331 val |= K3_VTM_ADC_COUNT_FOR_123C - workaround_needed * K3_VTM_ADC_WA_VALUE;
332
333 writel(val, cfg2_base + K3_VTM_MISC_CTRL2_OFFSET);
334 /* ramp-up delay from Linux code */
335 mdelay(100);
336 val = readl(cfg2_base + K3_VTM_MISC_CTRL1_OFFSET) | K3_VTM_ANYMAXT_OUTRG_ALERT_EN;
337 writel(val, cfg2_base + K3_VTM_MISC_CTRL1_OFFSET);
338}
339
Tero Kristo9d233b42019-10-24 15:00:46 +0530340/**
341 * k3_avs_probe: parses VD info from VTM, and re-configures the OPP data
342 *
343 * Parses all VDs on a device calculating the AVS class-0 voltages for them,
344 * and updates the vd_data based on this. The vd_data itself shall be used
345 * to program the required OPPs later on. Returns 0 on success, negative
346 * error value on failure.
347 */
348static int k3_avs_probe(struct udevice *dev)
349{
350 int opp_id;
351 u32 volt;
352 struct opp *opp;
353 struct k3_avs_privdata *priv;
354 struct vd_data *vd;
355 int ret;
356
357 priv = dev_get_priv(dev);
Udit Kumarb2549752023-10-19 12:57:53 +0530358 priv->dev = dev;
Tero Kristo9d233b42019-10-24 15:00:46 +0530359
360 k3_avs_priv = priv;
361
362 ret = k3_avs_configure(dev, priv);
363 if (ret)
364 return ret;
365
366 priv->base = dev_read_addr_ptr(dev);
367 if (!priv->base)
368 return -ENODEV;
369
370 for (vd = priv->vd_config->vds; vd->id >= 0; vd++) {
371 if (!(readl(AM6_VTM_DEVINFO(vd->id)) &
372 AM6_VTM_AVS0_SUPPORTED)) {
373 dev_warn(dev, "AVS-class 0 not supported for VD%d\n",
374 vd->id);
375 continue;
376 }
377
378 for (opp_id = 0; opp_id < NUM_OPPS; opp_id++) {
379 opp = &vd->opps[opp_id];
380
381 if (!opp->freq)
382 continue;
383
384 volt = priv->vd_config->efuse_xlate(priv, vd->id,
385 opp_id);
386 if (volt)
387 opp->volt = volt;
388 }
389 }
390
391 for (vd = priv->vd_config->vds; vd->id >= 0; vd++) {
392 if (vd->flags & VD_FLAG_INIT_DONE)
393 continue;
394
395 k3_avs_program_voltage(priv, vd, vd->opp);
396 }
397
Udit Kumarb2549752023-10-19 12:57:53 +0530398 if (!device_is_compatible(priv->dev, "ti,am654-avs"))
399 k3_avs_program_tshut(priv);
400
Tero Kristo9d233b42019-10-24 15:00:46 +0530401 return 0;
402}
403
404static struct vd_data am654_vd_data[] = {
405 {
406 .id = AM6_VDD_CORE,
407 .dev_id = 82, /* AM6_DEV_CBASS0 */
408 .clk_id = 0, /* main sysclk0 */
409 .opp = AM6_OPP_NOM,
410 .opps = {
411 [AM6_OPP_NOM] = {
412 .volt = 1000000,
413 .freq = 250000000, /* CBASS0 */
414 },
415 },
416 },
417 {
418 .id = AM6_VDD_MPU0,
419 .dev_id = 202, /* AM6_DEV_COMPUTE_CLUSTER_A53_0 */
420 .clk_id = 0, /* ARM clock */
421 .opp = AM6_OPP_NOM,
422 .opps = {
423 [AM6_OPP_NOM] = {
Tero Kristo3e7b0aa2020-02-14 09:05:10 +0200424 .volt = 1100000,
Tero Kristo9d233b42019-10-24 15:00:46 +0530425 .freq = 800000000,
426 },
427 [AM6_OPP_OD] = {
Tero Kristo3e7b0aa2020-02-14 09:05:10 +0200428 .volt = 1200000,
Tero Kristo9d233b42019-10-24 15:00:46 +0530429 .freq = 1000000000,
430 },
431 [AM6_OPP_TURBO] = {
Tero Kristo3e7b0aa2020-02-14 09:05:10 +0200432 .volt = 1240000,
Tero Kristo9d233b42019-10-24 15:00:46 +0530433 .freq = 1100000000,
434 },
435 },
436 },
437 {
438 .id = AM6_VDD_MPU1,
439 .opp = AM6_OPP_NOM,
440 .dev_id = 204, /* AM6_DEV_COMPUTE_CLUSTER_A53_2 */
441 .clk_id = 0, /* ARM clock */
442 .opps = {
443 [AM6_OPP_NOM] = {
Tero Kristo3e7b0aa2020-02-14 09:05:10 +0200444 .volt = 1100000,
Tero Kristo9d233b42019-10-24 15:00:46 +0530445 .freq = 800000000,
446 },
447 [AM6_OPP_OD] = {
Tero Kristo3e7b0aa2020-02-14 09:05:10 +0200448 .volt = 1200000,
Tero Kristo9d233b42019-10-24 15:00:46 +0530449 .freq = 1000000000,
450 },
451 [AM6_OPP_TURBO] = {
Tero Kristo3e7b0aa2020-02-14 09:05:10 +0200452 .volt = 1240000,
Tero Kristo9d233b42019-10-24 15:00:46 +0530453 .freq = 1100000000,
454 },
455 },
456 },
457 { .id = -1 },
458};
459
Keerthy9a03e502019-10-24 15:00:49 +0530460static struct vd_data j721e_vd_data[] = {
461 {
462 .id = J721E_VDD_MPU,
463 .opp = AM6_OPP_NOM,
464 .dev_id = 202, /* J721E_DEV_A72SS0_CORE0 */
465 .clk_id = 2, /* ARM clock */
466 .opps = {
467 [AM6_OPP_NOM] = {
468 .volt = 880000, /* TBD in DM */
469 .freq = 2000000000,
470 },
471 },
472 },
473 { .id = -1 },
474};
475
476static struct vd_config j721e_vd_config = {
477 .efuse_xlate = am6_efuse_xlate,
478 .vds = j721e_vd_data,
479};
480
Tero Kristo9d233b42019-10-24 15:00:46 +0530481static struct vd_config am654_vd_config = {
482 .efuse_xlate = am6_efuse_xlate,
483 .vds = am654_vd_data,
484};
485
486static const struct udevice_id k3_avs_ids[] = {
487 { .compatible = "ti,am654-avs", .data = (ulong)&am654_vd_config },
Keerthy9a03e502019-10-24 15:00:49 +0530488 { .compatible = "ti,j721e-avs", .data = (ulong)&j721e_vd_config },
Reid Tonking77269ba2023-09-07 13:06:35 -0500489 { .compatible = "ti,j721e-vtm", .data = (ulong)&j721e_vd_config },
490 { .compatible = "ti,j7200-vtm", .data = (ulong)&j721e_vd_config },
Tero Kristo9d233b42019-10-24 15:00:46 +0530491 {}
492};
493
494U_BOOT_DRIVER(k3_avs) = {
495 .name = "k3_avs",
496 .of_match = k3_avs_ids,
497 .id = UCLASS_MISC,
498 .probe = k3_avs_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700499 .priv_auto = sizeof(struct k3_avs_privdata),
Tero Kristo9d233b42019-10-24 15:00:46 +0530500};