blob: eb5605590fdb69daf8f08fee8d4a10878a3d7d22 [file] [log] [blame]
Peng Fan10de5792020-05-03 22:19:46 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2017~2020 NXP
4 *
5 */
6
7#include <config.h>
8#include <common.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Peng Fan10de5792020-05-03 22:19:46 +080010#include <asm/io.h>
11#include <asm/arch/clock.h>
12#include <asm/arch/sys_proto.h>
13#include <dm.h>
Marek Vasut39779c62023-04-04 21:25:09 +020014#include <dm/device_compat.h>
Peng Fan10de5792020-05-03 22:19:46 +080015#include <dm/device-internal.h>
16#include <dm/device.h>
17#include <errno.h>
18#include <fuse.h>
Tim Harveya77d3092020-10-12 12:21:54 -070019#include <linux/delay.h>
Peng Fan10de5792020-05-03 22:19:46 +080020#include <malloc.h>
21#include <thermal.h>
22
23DECLARE_GLOBAL_DATA_PTR;
24
25#define SITES_MAX 16
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020026#define FLAGS_VER2 0x1
27#define FLAGS_VER3 0x2
Peng Fan10de5792020-05-03 22:19:46 +080028
29#define TMR_DISABLE 0x0
30#define TMR_ME 0x80000000
31#define TMR_ALPF 0x0c000000
32#define TMTMIR_DEFAULT 0x00000002
33#define TIER_DISABLE 0x0
34
Peng Fanbef7d2a2020-05-03 22:19:47 +080035#define TER_EN 0x80000000
36#define TER_ADC_PD 0x40000000
Peng Fanfed211f2020-05-03 22:19:51 +080037#define TER_ALPF 0x3
38
Peng Fan10de5792020-05-03 22:19:46 +080039/*
40 * i.MX TMU Registers
41 */
42struct imx_tmu_site_regs {
43 u32 tritsr; /* Immediate Temperature Site Register */
44 u32 tratsr; /* Average Temperature Site Register */
45 u8 res0[0x8];
46};
47
48struct imx_tmu_regs {
49 u32 tmr; /* Mode Register */
50 u32 tsr; /* Status Register */
51 u32 tmtmir; /* Temperature measurement interval Register */
52 u8 res0[0x14];
53 u32 tier; /* Interrupt Enable Register */
54 u32 tidr; /* Interrupt Detect Register */
55 u32 tiscr; /* Interrupt Site Capture Register */
56 u32 ticscr; /* Interrupt Critical Site Capture Register */
57 u8 res1[0x10];
58 u32 tmhtcrh; /* High Temperature Capture Register */
59 u32 tmhtcrl; /* Low Temperature Capture Register */
60 u8 res2[0x8];
61 u32 tmhtitr; /* High Temperature Immediate Threshold */
62 u32 tmhtatr; /* High Temperature Average Threshold */
63 u32 tmhtactr; /* High Temperature Average Crit Threshold */
64 u8 res3[0x24];
65 u32 ttcfgr; /* Temperature Configuration Register */
66 u32 tscfgr; /* Sensor Configuration Register */
67 u8 res4[0x78];
68 struct imx_tmu_site_regs site[SITES_MAX];
69 u8 res5[0x9f8];
70 u32 ipbrr0; /* IP Block Revision Register 0 */
71 u32 ipbrr1; /* IP Block Revision Register 1 */
72 u8 res6[0x310];
73 u32 ttr0cr; /* Temperature Range 0 Control Register */
74 u32 ttr1cr; /* Temperature Range 1 Control Register */
75 u32 ttr2cr; /* Temperature Range 2 Control Register */
76 u32 ttr3cr; /* Temperature Range 3 Control Register */
77};
78
Peng Fanbef7d2a2020-05-03 22:19:47 +080079struct imx_tmu_regs_v2 {
80 u32 ter; /* TMU enable Register */
81 u32 tsr; /* Status Register */
82 u32 tier; /* Interrupt enable register */
83 u32 tidr; /* Interrupt detect register */
84 u32 tmhtitr; /* Monitor high temperature immediate threshold register */
85 u32 tmhtatr; /* Monitor high temperature average threshold register */
86 u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */
87 u32 tscr; /* Sensor value capture register */
88 u32 tritsr; /* Report immediate temperature site register 0 */
89 u32 tratsr; /* Report average temperature site register 0 */
90 u32 tasr; /* Amplifier setting register */
91 u32 ttmc; /* Test MUX control */
92 u32 tcaliv;
93};
94
Peng Fanfed211f2020-05-03 22:19:51 +080095struct imx_tmu_regs_v3 {
96 u32 ter; /* TMU enable Register */
97 u32 tps; /* Status Register */
98 u32 tier; /* Interrupt enable register */
99 u32 tidr; /* Interrupt detect register */
100 u32 tmhtitr; /* Monitor high temperature immediate threshold register */
101 u32 tmhtatr; /* Monitor high temperature average threshold register */
102 u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */
103 u32 tscr; /* Sensor value capture register */
104 u32 tritsr; /* Report immediate temperature site register 0 */
105 u32 tratsr; /* Report average temperature site register 0 */
106 u32 tasr; /* Amplifier setting register */
107 u32 ttmc; /* Test MUX control */
108 u32 tcaliv0;
109 u32 tcaliv1;
110 u32 tcaliv_m40;
111 u32 trim;
112};
113
Peng Fanbef7d2a2020-05-03 22:19:47 +0800114union tmu_regs {
115 struct imx_tmu_regs regs_v1;
116 struct imx_tmu_regs_v2 regs_v2;
Peng Fanfed211f2020-05-03 22:19:51 +0800117 struct imx_tmu_regs_v3 regs_v3;
Peng Fanbef7d2a2020-05-03 22:19:47 +0800118};
119
Peng Fan10de5792020-05-03 22:19:46 +0800120struct imx_tmu_plat {
121 int critical;
122 int alert;
123 int polling_delay;
124 int id;
125 bool zone_node;
Peng Fanbef7d2a2020-05-03 22:19:47 +0800126 union tmu_regs *regs;
Peng Fan10de5792020-05-03 22:19:46 +0800127};
128
129static int read_temperature(struct udevice *dev, int *temp)
130{
Simon Glassfa20e932020-12-03 16:55:20 -0700131 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800132 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800133 u32 val;
Peng Fancabe2312020-05-03 22:19:49 +0800134 u32 retry = 10;
Peng Fan6eff2872020-05-03 22:19:50 +0800135 u32 valid = 0;
Peng Fan10de5792020-05-03 22:19:46 +0800136
137 do {
Peng Fancabe2312020-05-03 22:19:49 +0800138 mdelay(100);
139 retry--;
140
Peng Fanfed211f2020-05-03 22:19:51 +0800141 if (drv_data & FLAGS_VER3) {
142 val = readl(&pdata->regs->regs_v3.tritsr);
143 valid = val & (1 << (30 + pdata->id));
144 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800145 val = readl(&pdata->regs->regs_v2.tritsr);
Peng Fan6eff2872020-05-03 22:19:50 +0800146 /*
147 * Check if TEMP is in valid range, the V bit in TRITSR
148 * only reflects the RAW uncalibrated data
149 */
150 valid = ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1;
151 } else {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800152 val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
Peng Fan6eff2872020-05-03 22:19:50 +0800153 valid = val & 0x80000000;
154 }
155 } while (!valid && retry > 0);
Peng Fan10de5792020-05-03 22:19:46 +0800156
Peng Fanfed211f2020-05-03 22:19:51 +0800157 if (retry > 0) {
158 if (drv_data & FLAGS_VER3) {
159 val = (val >> (pdata->id * 16)) & 0xff;
160 if (val & 0x80) /* Negative */
161 val = (~(val & 0x7f) + 1);
162
163 *temp = val;
164 if (*temp < -40 || *temp > 125) /* Check the range */
165 return -EINVAL;
166
167 *temp *= 1000;
168 } else {
169 *temp = (val & 0xff) * 1000;
170 }
171 } else {
Peng Fancabe2312020-05-03 22:19:49 +0800172 return -EINVAL;
Peng Fanfed211f2020-05-03 22:19:51 +0800173 }
Peng Fan10de5792020-05-03 22:19:46 +0800174
175 return 0;
176}
177
178int imx_tmu_get_temp(struct udevice *dev, int *temp)
179{
Simon Glassfa20e932020-12-03 16:55:20 -0700180 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800181 int cpu_tmp = 0;
182 int ret;
183
184 ret = read_temperature(dev, &cpu_tmp);
185 if (ret)
186 return ret;
187
188 while (cpu_tmp >= pdata->alert) {
Marek Vasut39779c62023-04-04 21:25:09 +0200189 dev_info(dev, "CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC) waiting...\n",
190 cpu_tmp, pdata->alert, pdata->critical);
Peng Fan10de5792020-05-03 22:19:46 +0800191 mdelay(pdata->polling_delay);
192 ret = read_temperature(dev, &cpu_tmp);
193 if (ret)
194 return ret;
195 }
196
197 *temp = cpu_tmp / 1000;
198
199 return 0;
200}
201
202static const struct dm_thermal_ops imx_tmu_ops = {
203 .get_temp = imx_tmu_get_temp,
204};
205
206static int imx_tmu_calibration(struct udevice *dev)
207{
208 int i, val, len, ret;
209 u32 range[4];
210 const fdt32_t *calibration;
Simon Glassfa20e932020-12-03 16:55:20 -0700211 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800212 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800213
Marek Vasut39779c62023-04-04 21:25:09 +0200214 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800215
Peng Fanfed211f2020-05-03 22:19:51 +0800216 if (drv_data & (FLAGS_VER2 | FLAGS_VER3))
Peng Fanbef7d2a2020-05-03 22:19:47 +0800217 return 0;
218
Peng Fan10de5792020-05-03 22:19:46 +0800219 ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4);
220 if (ret) {
Marek Vasut39779c62023-04-04 21:25:09 +0200221 dev_err(dev, "TMU: missing calibration range, ret = %d.\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800222 return ret;
223 }
224
225 /* Init temperature range registers */
Peng Fanbef7d2a2020-05-03 22:19:47 +0800226 writel(range[0], &pdata->regs->regs_v1.ttr0cr);
227 writel(range[1], &pdata->regs->regs_v1.ttr1cr);
228 writel(range[2], &pdata->regs->regs_v1.ttr2cr);
229 writel(range[3], &pdata->regs->regs_v1.ttr3cr);
Peng Fan10de5792020-05-03 22:19:46 +0800230
231 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
232 if (!calibration || len % 8) {
Marek Vasut39779c62023-04-04 21:25:09 +0200233 dev_err(dev, "TMU: invalid calibration data.\n");
Peng Fan10de5792020-05-03 22:19:46 +0800234 return -ENODEV;
235 }
236
237 for (i = 0; i < len; i += 8, calibration += 2) {
238 val = fdt32_to_cpu(*calibration);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800239 writel(val, &pdata->regs->regs_v1.ttcfgr);
Peng Fan10de5792020-05-03 22:19:46 +0800240 val = fdt32_to_cpu(*(calibration + 1));
Peng Fanbef7d2a2020-05-03 22:19:47 +0800241 writel(val, &pdata->regs->regs_v1.tscfgr);
Peng Fan10de5792020-05-03 22:19:46 +0800242 }
243
244 return 0;
245}
246
Marek Vasut7903bcf2023-04-04 21:25:10 +0200247#if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN)
248static void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev)
Peng Fan4f5026c2020-05-03 22:19:48 +0800249{
Marek Vasut7903bcf2023-04-04 21:25:10 +0200250 /* Load TCALIV and TASR from fuses */
251 struct ocotp_regs *ocotp =
252 (struct ocotp_regs *)OCOTP_BASE_ADDR;
253 struct fuse_bank *bank = &ocotp->bank[3];
254 struct fuse_bank3_regs *fuse =
255 (struct fuse_bank3_regs *)bank->fuse_regs;
256 struct imx_tmu_plat *pdata = dev_get_plat(dev);
257 void *reg_base = (void *)pdata->regs;
258
259 u32 tca_rt, tca_hr, tca_en;
260 u32 buf_vref, buf_slope;
261
262 tca_rt = fuse->ana0 & 0xFF;
263 tca_hr = (fuse->ana0 & 0xFF00) >> 8;
264 tca_en = (fuse->ana0 & 0x2000000) >> 25;
265
266 buf_vref = (fuse->ana0 & 0x1F00000) >> 20;
267 buf_slope = (fuse->ana0 & 0xF0000) >> 16;
268
269 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
270 writel((tca_en << 31) | (tca_hr << 16) | tca_rt,
271 (ulong)reg_base + 0x30);
272}
273#else
274static inline void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev) { }
275#endif
276
277#if defined(CONFIG_IMX8MP)
278static void imx_tmu_mx8mp_init(struct udevice *dev)
279{
280 /* Load TCALIV0/1/m40 and TRIM from fuses */
281 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
282 struct fuse_bank *bank = &ocotp->bank[38];
283 struct fuse_bank38_regs *fuse =
284 (struct fuse_bank38_regs *)bank->fuse_regs;
285 struct fuse_bank *bank2 = &ocotp->bank[39];
286 struct fuse_bank39_regs *fuse2 =
287 (struct fuse_bank39_regs *)bank2->fuse_regs;
288 struct imx_tmu_plat *pdata = dev_get_plat(dev);
289 void *reg_base = (void *)pdata->regs;
290 u32 buf_vref, buf_slope, bjt_cur, vlsb, bgr;
291 u32 reg;
292 u32 tca40[2], tca25[2], tca105[2];
293
294 /* For blank sample */
295 if (!fuse->ana_trim2 && !fuse->ana_trim3 &&
296 !fuse->ana_trim4 && !fuse2->ana_trim5) {
297 /* Use a default 25C binary codes */
298 tca25[0] = 1596;
299 tca25[1] = 1596;
300 writel(tca25[0], (ulong)reg_base + 0x30);
301 writel(tca25[1], (ulong)reg_base + 0x34);
302 return;
303 }
304
305 buf_vref = (fuse->ana_trim2 & 0xc0) >> 6;
306 buf_slope = (fuse->ana_trim2 & 0xF00) >> 8;
307 bjt_cur = (fuse->ana_trim2 & 0xF000) >> 12;
308 bgr = (fuse->ana_trim2 & 0xF0000) >> 16;
309 vlsb = (fuse->ana_trim2 & 0xF00000) >> 20;
310 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
311
312 reg = (bgr << 28) | (bjt_cur << 20) | (vlsb << 12) | (1 << 7);
313 writel(reg, (ulong)reg_base + 0x3c);
314
315 tca40[0] = (fuse->ana_trim3 & 0xFFF0000) >> 16;
316 tca25[0] = (fuse->ana_trim3 & 0xF0000000) >> 28;
317 tca25[0] |= ((fuse->ana_trim4 & 0xFF) << 4);
318 tca105[0] = (fuse->ana_trim4 & 0xFFF00) >> 8;
319 tca40[1] = (fuse->ana_trim4 & 0xFFF00000) >> 20;
320 tca25[1] = fuse2->ana_trim5 & 0xFFF;
321 tca105[1] = (fuse2->ana_trim5 & 0xFFF000) >> 12;
322
323 /* use 25c for 1p calibration */
324 writel(tca25[0] | (tca105[0] << 16), (ulong)reg_base + 0x30);
325 writel(tca25[1] | (tca105[1] << 16), (ulong)reg_base + 0x34);
326 writel(tca40[0] | (tca40[1] << 16), (ulong)reg_base + 0x38);
327}
328#else
329static inline void imx_tmu_mx8mp_init(struct udevice *dev) { }
330#endif
331
332static void imx_tmu_arch_init(struct udevice *dev)
333{
334 if (is_imx8mm() || is_imx8mn())
335 imx_tmu_mx8mm_mx8mn_init(dev);
336 else if (is_imx8mp())
337 imx_tmu_mx8mp_init(dev);
338 else
339 dev_err(dev, "Unsupported SoC, TMU calibration not loaded!\n");
Peng Fan4f5026c2020-05-03 22:19:48 +0800340}
341
Peng Fanbef7d2a2020-05-03 22:19:47 +0800342static void imx_tmu_init(struct udevice *dev)
Peng Fan10de5792020-05-03 22:19:46 +0800343{
Simon Glassfa20e932020-12-03 16:55:20 -0700344 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800345 ulong drv_data = dev_get_driver_data(dev);
346
Marek Vasut39779c62023-04-04 21:25:09 +0200347 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800348
Peng Fanfed211f2020-05-03 22:19:51 +0800349 if (drv_data & FLAGS_VER3) {
350 /* Disable monitoring */
351 writel(0x0, &pdata->regs->regs_v3.ter);
352
353 /* Disable interrupt, using polling instead */
354 writel(0x0, &pdata->regs->regs_v3.tier);
355
356 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800357 /* Disable monitoring */
358 writel(0x0, &pdata->regs->regs_v2.ter);
359
360 /* Disable interrupt, using polling instead */
361 writel(0x0, &pdata->regs->regs_v2.tier);
362 } else {
363 /* Disable monitoring */
364 writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
Peng Fan10de5792020-05-03 22:19:46 +0800365
Peng Fanbef7d2a2020-05-03 22:19:47 +0800366 /* Disable interrupt, using polling instead */
367 writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
Peng Fan10de5792020-05-03 22:19:46 +0800368
Peng Fanbef7d2a2020-05-03 22:19:47 +0800369 /* Set update_interval */
370 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
371 }
Peng Fan4f5026c2020-05-03 22:19:48 +0800372
Marek Vasut7903bcf2023-04-04 21:25:10 +0200373 imx_tmu_arch_init(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800374}
375
376static int imx_tmu_enable_msite(struct udevice *dev)
377{
Simon Glassfa20e932020-12-03 16:55:20 -0700378 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800379 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800380 u32 reg;
381
Marek Vasut39779c62023-04-04 21:25:09 +0200382 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800383
384 if (!pdata->regs)
385 return -EIO;
386
Peng Fanfed211f2020-05-03 22:19:51 +0800387 if (drv_data & FLAGS_VER3) {
388 reg = readl(&pdata->regs->regs_v3.ter);
389 reg &= ~TER_EN;
390 writel(reg, &pdata->regs->regs_v3.ter);
391
392 writel(pdata->id << 30, &pdata->regs->regs_v3.tps);
393
394 reg &= ~TER_ALPF;
395 reg |= 0x1;
396 reg &= ~TER_ADC_PD;
397 writel(reg, &pdata->regs->regs_v3.ter);
398
399 /* Enable monitor */
400 reg |= TER_EN;
401 writel(reg, &pdata->regs->regs_v3.ter);
402 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800403 reg = readl(&pdata->regs->regs_v2.ter);
404 reg &= ~TER_EN;
405 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan10de5792020-05-03 22:19:46 +0800406
Peng Fanbef7d2a2020-05-03 22:19:47 +0800407 reg &= ~TER_ALPF;
408 reg |= 0x1;
409 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan10de5792020-05-03 22:19:46 +0800410
Peng Fanbef7d2a2020-05-03 22:19:47 +0800411 /* Enable monitor */
412 reg |= TER_EN;
413 writel(reg, &pdata->regs->regs_v2.ter);
414 } else {
415 /* Clear the ME before setting MSITE and ALPF*/
416 reg = readl(&pdata->regs->regs_v1.tmr);
417 reg &= ~TMR_ME;
418 writel(reg, &pdata->regs->regs_v1.tmr);
419
420 reg |= 1 << (15 - pdata->id);
421 reg |= TMR_ALPF;
422 writel(reg, &pdata->regs->regs_v1.tmr);
423
424 /* Enable ME */
425 reg |= TMR_ME;
426 writel(reg, &pdata->regs->regs_v1.tmr);
427 }
Peng Fan10de5792020-05-03 22:19:46 +0800428
429 return 0;
430}
431
432static int imx_tmu_bind(struct udevice *dev)
433{
Simon Glassfa20e932020-12-03 16:55:20 -0700434 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800435 int ret;
436 ofnode node, offset;
437 const char *name;
438 const void *prop;
Tim Harvey83858252021-02-05 16:11:05 -0800439 int minc, maxc;
Peng Fan10de5792020-05-03 22:19:46 +0800440
Marek Vasut39779c62023-04-04 21:25:09 +0200441 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800442
443 prop = dev_read_prop(dev, "compatible", NULL);
444 if (!prop)
445 return 0;
446
447 pdata->zone_node = 1;
Tim Harvey83858252021-02-05 16:11:05 -0800448 /* default alert/crit temps based on temp grade */
449 get_cpu_temp_grade(&minc, &maxc);
450 pdata->critical = maxc * 1000;
451 pdata->alert = (maxc - 10) * 1000;
Peng Fan10de5792020-05-03 22:19:46 +0800452
453 node = ofnode_path("/thermal-zones");
454 ofnode_for_each_subnode(offset, node) {
455 /* Bind the subnode to this driver */
456 name = ofnode_get_name(offset);
457
458 ret = device_bind_with_driver_data(dev, dev->driver, name,
459 dev->driver_data, offset,
460 NULL);
461 if (ret)
Marek Vasut39779c62023-04-04 21:25:09 +0200462 dev_err(dev, "Error binding driver: %d\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800463 }
464
465 return 0;
466}
467
468static int imx_tmu_parse_fdt(struct udevice *dev)
469{
Simon Glassfa20e932020-12-03 16:55:20 -0700470 struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data;
Peng Fan10de5792020-05-03 22:19:46 +0800471 struct ofnode_phandle_args args;
472 ofnode trips_np;
473 int ret;
474
Marek Vasut39779c62023-04-04 21:25:09 +0200475 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800476
477 if (pdata->zone_node) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800478 pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800479
480 if (!pdata->regs)
481 return -EINVAL;
482 return 0;
483 }
484
Simon Glassfa20e932020-12-03 16:55:20 -0700485 p_parent_data = dev_get_plat(dev->parent);
Peng Fan10de5792020-05-03 22:19:46 +0800486 if (p_parent_data->zone_node)
487 pdata->regs = p_parent_data->regs;
488
489 ret = dev_read_phandle_with_args(dev, "thermal-sensors",
490 "#thermal-sensor-cells",
491 0, 0, &args);
492 if (ret)
493 return ret;
494
495 if (!ofnode_equal(args.node, dev_ofnode(dev->parent)))
496 return -EFAULT;
497
498 if (args.args_count >= 1)
499 pdata->id = args.args[0];
500 else
501 pdata->id = 0;
502
Marek Vasut39779c62023-04-04 21:25:09 +0200503 dev_dbg(dev, "args.args_count %d, id %d\n", args.args_count, pdata->id);
Peng Fan10de5792020-05-03 22:19:46 +0800504
505 pdata->polling_delay = dev_read_u32_default(dev, "polling-delay", 1000);
506
507 trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
508 ofnode_for_each_subnode(trips_np, trips_np) {
509 const char *type;
510
511 type = ofnode_get_property(trips_np, "type", NULL);
512 if (!type)
513 continue;
514 if (!strcmp(type, "critical"))
515 pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
516 else if (strcmp(type, "passive") == 0)
517 pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
518 else
519 continue;
520 }
521
Marek Vasut39779c62023-04-04 21:25:09 +0200522 dev_dbg(dev, "id %d polling_delay %d, critical %d, alert %d\n",
523 pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
Peng Fan10de5792020-05-03 22:19:46 +0800524
525 return 0;
526}
527
528static int imx_tmu_probe(struct udevice *dev)
529{
Simon Glassfa20e932020-12-03 16:55:20 -0700530 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800531 int ret;
532
533 ret = imx_tmu_parse_fdt(dev);
534 if (ret) {
Marek Vasut39779c62023-04-04 21:25:09 +0200535 dev_err(dev, "Error in parsing TMU FDT %d\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800536 return ret;
537 }
538
539 if (pdata->zone_node) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800540 imx_tmu_init(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800541 imx_tmu_calibration(dev);
Tim Harvey83858252021-02-05 16:11:05 -0800542 imx_tmu_enable_msite(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800543 } else {
544 imx_tmu_enable_msite(dev);
545 }
546
547 return 0;
548}
549
550static const struct udevice_id imx_tmu_ids[] = {
551 { .compatible = "fsl,imx8mq-tmu", },
Peng Fanbef7d2a2020-05-03 22:19:47 +0800552 { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, },
Peng Fanfed211f2020-05-03 22:19:51 +0800553 { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, },
Peng Fan10de5792020-05-03 22:19:46 +0800554 { }
555};
556
557U_BOOT_DRIVER(imx_tmu) = {
558 .name = "imx_tmu",
559 .id = UCLASS_THERMAL,
560 .ops = &imx_tmu_ops,
561 .of_match = imx_tmu_ids,
562 .bind = imx_tmu_bind,
563 .probe = imx_tmu_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700564 .plat_auto = sizeof(struct imx_tmu_plat),
Peng Fan10de5792020-05-03 22:19:46 +0800565 .flags = DM_FLAG_PRE_RELOC,
566};