blob: ea6c8329c0a6af384ad1447c779956d61140e831 [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
Ye Lib7662562023-04-28 12:08:07 +080028#define FLAGS_VER4 0x4
Peng Fan10de5792020-05-03 22:19:46 +080029
30#define TMR_DISABLE 0x0
31#define TMR_ME 0x80000000
32#define TMR_ALPF 0x0c000000
33#define TMTMIR_DEFAULT 0x00000002
34#define TIER_DISABLE 0x0
35
Peng Fanbef7d2a2020-05-03 22:19:47 +080036#define TER_EN 0x80000000
37#define TER_ADC_PD 0x40000000
Peng Fanfed211f2020-05-03 22:19:51 +080038#define TER_ALPF 0x3
39
Fabio Estevam83ba4072023-08-23 14:59:11 -030040#define IMX_TMU_POLLING_DELAY_MS 5000
Peng Fan10de5792020-05-03 22:19:46 +080041/*
42 * i.MX TMU Registers
43 */
44struct imx_tmu_site_regs {
45 u32 tritsr; /* Immediate Temperature Site Register */
46 u32 tratsr; /* Average Temperature Site Register */
47 u8 res0[0x8];
48};
49
50struct imx_tmu_regs {
51 u32 tmr; /* Mode Register */
52 u32 tsr; /* Status Register */
53 u32 tmtmir; /* Temperature measurement interval Register */
54 u8 res0[0x14];
55 u32 tier; /* Interrupt Enable Register */
56 u32 tidr; /* Interrupt Detect Register */
57 u32 tiscr; /* Interrupt Site Capture Register */
58 u32 ticscr; /* Interrupt Critical Site Capture Register */
59 u8 res1[0x10];
60 u32 tmhtcrh; /* High Temperature Capture Register */
61 u32 tmhtcrl; /* Low Temperature Capture Register */
62 u8 res2[0x8];
63 u32 tmhtitr; /* High Temperature Immediate Threshold */
64 u32 tmhtatr; /* High Temperature Average Threshold */
65 u32 tmhtactr; /* High Temperature Average Crit Threshold */
66 u8 res3[0x24];
67 u32 ttcfgr; /* Temperature Configuration Register */
68 u32 tscfgr; /* Sensor Configuration Register */
69 u8 res4[0x78];
70 struct imx_tmu_site_regs site[SITES_MAX];
71 u8 res5[0x9f8];
72 u32 ipbrr0; /* IP Block Revision Register 0 */
73 u32 ipbrr1; /* IP Block Revision Register 1 */
74 u8 res6[0x310];
75 u32 ttr0cr; /* Temperature Range 0 Control Register */
76 u32 ttr1cr; /* Temperature Range 1 Control Register */
77 u32 ttr2cr; /* Temperature Range 2 Control Register */
78 u32 ttr3cr; /* Temperature Range 3 Control Register */
79};
80
Ye Lib7662562023-04-28 12:08:07 +080081struct imx_tmu_regs_v4 {
82 u32 tmr; /* Mode Register */
83 u32 tsr; /* Status Register */
84 u32 tmsr; /* Monitor Site Register */
85 u32 tmtmir; /* Temperature measurement interval Register */
86 u8 res0[0x10];
87 u32 tier; /* Interrupt Enable Register */
88 u32 tidr; /* Interrupt Detect Register */
89 u8 res1[0x8];
90 u32 tiiscr; /* Interrupt Immediate Site Capture Register */
91 u32 tiascr; /* Interrupt Average Site Capture Register */
92 u32 ticscr; /* Interrupt Critical Site Capture Register */
93 u8 res2[0x4];
94 u32 tmhtcr; /* Monitor High Temperature Capture Register */
95 u32 tmltcr; /* MonitorLow Temperature Capture Register */
96 u32 tmrtrcr; /* Monitor Rising Temperature Rate Capture Register */
97 u32 tmftrcr; /* Monitor Falling Temperature Rate Capture Register */
98 u32 tmhtitr; /* Monitor High Temperature Immediate Threshold */
99 u32 tmhtatr; /* Monitor High Temperature Average Threshold */
100 u32 tmhtactr; /* Monitor High Temperature Average Crit Threshold */
101 u8 res3[0x4];
102 u32 tmltitr; /* Monitor Low Temperature Immediate Threshold */
103 u32 tmltatr; /* Monitor Low Temperature Average Threshold */
104 u32 tmltactr; /* Monitor Low Temperature Average Crit Threshold */
105 u8 res4[0x4];
106 u32 tmrtrctr; /* Monitor Rising Temperature Rate Critical Threshold Register */
107 u32 tmftrctr; /* Monitor Falling Temperature Rate Critical Threshold Register */
108 u8 res5[0x8];
109 u32 ttcfgr; /* Temperature Configuration Register */
110 u32 tscfgr; /* Sensor Configuration Register */
111 u8 res6[0x78];
112 u32 tritsr0; /* Immediate Temperature Site Register */
113 u32 tratsr0; /* Average Temperature Site Register */
114 u8 res7[0xdf8];
115 u32 tcmcfg; /* Central Module Configuration */
116 u8 res8[0xc];
117 u32 ttrcr[16]; /* Temperature Range Control Register */
118};
119
Peng Fanbef7d2a2020-05-03 22:19:47 +0800120struct imx_tmu_regs_v2 {
121 u32 ter; /* TMU enable Register */
122 u32 tsr; /* Status Register */
123 u32 tier; /* Interrupt enable register */
124 u32 tidr; /* Interrupt detect register */
125 u32 tmhtitr; /* Monitor high temperature immediate threshold register */
126 u32 tmhtatr; /* Monitor high temperature average threshold register */
127 u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */
128 u32 tscr; /* Sensor value capture register */
129 u32 tritsr; /* Report immediate temperature site register 0 */
130 u32 tratsr; /* Report average temperature site register 0 */
131 u32 tasr; /* Amplifier setting register */
132 u32 ttmc; /* Test MUX control */
133 u32 tcaliv;
134};
135
Peng Fanfed211f2020-05-03 22:19:51 +0800136struct imx_tmu_regs_v3 {
137 u32 ter; /* TMU enable Register */
138 u32 tps; /* Status Register */
139 u32 tier; /* Interrupt enable register */
140 u32 tidr; /* Interrupt detect register */
141 u32 tmhtitr; /* Monitor high temperature immediate threshold register */
142 u32 tmhtatr; /* Monitor high temperature average threshold register */
143 u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */
144 u32 tscr; /* Sensor value capture register */
145 u32 tritsr; /* Report immediate temperature site register 0 */
146 u32 tratsr; /* Report average temperature site register 0 */
147 u32 tasr; /* Amplifier setting register */
148 u32 ttmc; /* Test MUX control */
149 u32 tcaliv0;
150 u32 tcaliv1;
151 u32 tcaliv_m40;
152 u32 trim;
153};
154
Peng Fanbef7d2a2020-05-03 22:19:47 +0800155union tmu_regs {
156 struct imx_tmu_regs regs_v1;
157 struct imx_tmu_regs_v2 regs_v2;
Peng Fanfed211f2020-05-03 22:19:51 +0800158 struct imx_tmu_regs_v3 regs_v3;
Ye Lib7662562023-04-28 12:08:07 +0800159 struct imx_tmu_regs_v4 regs_v4;
Peng Fanbef7d2a2020-05-03 22:19:47 +0800160};
161
Peng Fan10de5792020-05-03 22:19:46 +0800162struct imx_tmu_plat {
163 int critical;
164 int alert;
165 int polling_delay;
166 int id;
167 bool zone_node;
Peng Fanbef7d2a2020-05-03 22:19:47 +0800168 union tmu_regs *regs;
Peng Fan10de5792020-05-03 22:19:46 +0800169};
170
171static int read_temperature(struct udevice *dev, int *temp)
172{
Simon Glassfa20e932020-12-03 16:55:20 -0700173 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800174 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800175 u32 val;
Peng Fancabe2312020-05-03 22:19:49 +0800176 u32 retry = 10;
Peng Fan6eff2872020-05-03 22:19:50 +0800177 u32 valid = 0;
Peng Fan10de5792020-05-03 22:19:46 +0800178
179 do {
Peng Fancabe2312020-05-03 22:19:49 +0800180 mdelay(100);
181 retry--;
182
Peng Fanfed211f2020-05-03 22:19:51 +0800183 if (drv_data & FLAGS_VER3) {
184 val = readl(&pdata->regs->regs_v3.tritsr);
185 valid = val & (1 << (30 + pdata->id));
186 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800187 val = readl(&pdata->regs->regs_v2.tritsr);
Peng Fan6eff2872020-05-03 22:19:50 +0800188 /*
189 * Check if TEMP is in valid range, the V bit in TRITSR
190 * only reflects the RAW uncalibrated data
191 */
192 valid = ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1;
Ye Lib7662562023-04-28 12:08:07 +0800193 } else if (drv_data & FLAGS_VER4) {
194 val = readl(&pdata->regs->regs_v4.tritsr0);
195 valid = val & 0x80000000;
Peng Fan6eff2872020-05-03 22:19:50 +0800196 } else {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800197 val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
Peng Fan6eff2872020-05-03 22:19:50 +0800198 valid = val & 0x80000000;
199 }
200 } while (!valid && retry > 0);
Peng Fan10de5792020-05-03 22:19:46 +0800201
Peng Fanfed211f2020-05-03 22:19:51 +0800202 if (retry > 0) {
203 if (drv_data & FLAGS_VER3) {
204 val = (val >> (pdata->id * 16)) & 0xff;
205 if (val & 0x80) /* Negative */
206 val = (~(val & 0x7f) + 1);
207
208 *temp = val;
209 if (*temp < -40 || *temp > 125) /* Check the range */
210 return -EINVAL;
211
212 *temp *= 1000;
Ye Lib7662562023-04-28 12:08:07 +0800213 } else if (drv_data & FLAGS_VER4) {
214 *temp = (val & 0x1ff) * 1000;
215 if (val & 0x200)
216 *temp += 500;
217
218 /* Convert Kelvin to Celsius */
219 *temp -= 273000;
Peng Fanfed211f2020-05-03 22:19:51 +0800220 } else {
221 *temp = (val & 0xff) * 1000;
222 }
223 } else {
Peng Fancabe2312020-05-03 22:19:49 +0800224 return -EINVAL;
Peng Fanfed211f2020-05-03 22:19:51 +0800225 }
Peng Fan10de5792020-05-03 22:19:46 +0800226
227 return 0;
228}
229
230int imx_tmu_get_temp(struct udevice *dev, int *temp)
231{
Simon Glassfa20e932020-12-03 16:55:20 -0700232 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800233 int cpu_tmp = 0;
234 int ret;
235
236 ret = read_temperature(dev, &cpu_tmp);
237 if (ret)
238 return ret;
239
240 while (cpu_tmp >= pdata->alert) {
Fabio Estevamc28c0752023-08-23 14:59:10 -0300241 dev_crit(dev, "CPU Temperature (%dC) is beyond alert (%dC), close to critical (%dC) waiting...\n",
242 cpu_tmp / 1000, pdata->alert / 1000, pdata->critical / 1000);
Peng Fan10de5792020-05-03 22:19:46 +0800243 mdelay(pdata->polling_delay);
244 ret = read_temperature(dev, &cpu_tmp);
245 if (ret)
246 return ret;
247 }
248
249 *temp = cpu_tmp / 1000;
250
251 return 0;
252}
253
254static const struct dm_thermal_ops imx_tmu_ops = {
255 .get_temp = imx_tmu_get_temp,
256};
257
258static int imx_tmu_calibration(struct udevice *dev)
259{
260 int i, val, len, ret;
Ye Lib7662562023-04-28 12:08:07 +0800261 int index;
Peng Fan10de5792020-05-03 22:19:46 +0800262 u32 range[4];
263 const fdt32_t *calibration;
Simon Glassfa20e932020-12-03 16:55:20 -0700264 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800265 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800266
Marek Vasut39779c62023-04-04 21:25:09 +0200267 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800268
Peng Fanfed211f2020-05-03 22:19:51 +0800269 if (drv_data & (FLAGS_VER2 | FLAGS_VER3))
Peng Fanbef7d2a2020-05-03 22:19:47 +0800270 return 0;
271
Ye Lib7662562023-04-28 12:08:07 +0800272 if (drv_data & FLAGS_VER4) {
273 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
274 if (!calibration || len % 8 || len > 128) {
275 printf("TMU: invalid calibration data.\n");
276 return -ENODEV;
277 }
278
279 for (i = 0; i < len; i += 8, calibration += 2) {
280 index = i / 8;
281 writel(index, &pdata->regs->regs_v4.ttcfgr);
282 val = fdt32_to_cpu(*calibration);
283 writel(val, &pdata->regs->regs_v4.tscfgr);
284 val = fdt32_to_cpu(*(calibration + 1));
285 writel((1 << 31) | val, &pdata->regs->regs_v4.ttrcr[index]);
286 }
287
288 return 0;
289 }
290
Peng Fan10de5792020-05-03 22:19:46 +0800291 ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4);
292 if (ret) {
Marek Vasut39779c62023-04-04 21:25:09 +0200293 dev_err(dev, "TMU: missing calibration range, ret = %d.\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800294 return ret;
295 }
296
297 /* Init temperature range registers */
Peng Fanbef7d2a2020-05-03 22:19:47 +0800298 writel(range[0], &pdata->regs->regs_v1.ttr0cr);
299 writel(range[1], &pdata->regs->regs_v1.ttr1cr);
300 writel(range[2], &pdata->regs->regs_v1.ttr2cr);
301 writel(range[3], &pdata->regs->regs_v1.ttr3cr);
Peng Fan10de5792020-05-03 22:19:46 +0800302
303 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
304 if (!calibration || len % 8) {
Marek Vasut39779c62023-04-04 21:25:09 +0200305 dev_err(dev, "TMU: invalid calibration data.\n");
Peng Fan10de5792020-05-03 22:19:46 +0800306 return -ENODEV;
307 }
308
309 for (i = 0; i < len; i += 8, calibration += 2) {
310 val = fdt32_to_cpu(*calibration);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800311 writel(val, &pdata->regs->regs_v1.ttcfgr);
Peng Fan10de5792020-05-03 22:19:46 +0800312 val = fdt32_to_cpu(*(calibration + 1));
Peng Fanbef7d2a2020-05-03 22:19:47 +0800313 writel(val, &pdata->regs->regs_v1.tscfgr);
Peng Fan10de5792020-05-03 22:19:46 +0800314 }
315
316 return 0;
317}
318
Marek Vasut7903bcf2023-04-04 21:25:10 +0200319#if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN)
320static void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev)
Peng Fan4f5026c2020-05-03 22:19:48 +0800321{
Marek Vasut7903bcf2023-04-04 21:25:10 +0200322 /* Load TCALIV and TASR from fuses */
323 struct ocotp_regs *ocotp =
324 (struct ocotp_regs *)OCOTP_BASE_ADDR;
325 struct fuse_bank *bank = &ocotp->bank[3];
326 struct fuse_bank3_regs *fuse =
327 (struct fuse_bank3_regs *)bank->fuse_regs;
328 struct imx_tmu_plat *pdata = dev_get_plat(dev);
329 void *reg_base = (void *)pdata->regs;
330
331 u32 tca_rt, tca_hr, tca_en;
332 u32 buf_vref, buf_slope;
333
334 tca_rt = fuse->ana0 & 0xFF;
335 tca_hr = (fuse->ana0 & 0xFF00) >> 8;
336 tca_en = (fuse->ana0 & 0x2000000) >> 25;
337
338 buf_vref = (fuse->ana0 & 0x1F00000) >> 20;
339 buf_slope = (fuse->ana0 & 0xF0000) >> 16;
340
341 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
342 writel((tca_en << 31) | (tca_hr << 16) | tca_rt,
343 (ulong)reg_base + 0x30);
344}
345#else
346static inline void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev) { }
347#endif
348
349#if defined(CONFIG_IMX8MP)
350static void imx_tmu_mx8mp_init(struct udevice *dev)
351{
352 /* Load TCALIV0/1/m40 and TRIM from fuses */
353 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
354 struct fuse_bank *bank = &ocotp->bank[38];
355 struct fuse_bank38_regs *fuse =
356 (struct fuse_bank38_regs *)bank->fuse_regs;
357 struct fuse_bank *bank2 = &ocotp->bank[39];
358 struct fuse_bank39_regs *fuse2 =
359 (struct fuse_bank39_regs *)bank2->fuse_regs;
360 struct imx_tmu_plat *pdata = dev_get_plat(dev);
361 void *reg_base = (void *)pdata->regs;
362 u32 buf_vref, buf_slope, bjt_cur, vlsb, bgr;
363 u32 reg;
364 u32 tca40[2], tca25[2], tca105[2];
365
366 /* For blank sample */
367 if (!fuse->ana_trim2 && !fuse->ana_trim3 &&
368 !fuse->ana_trim4 && !fuse2->ana_trim5) {
369 /* Use a default 25C binary codes */
370 tca25[0] = 1596;
371 tca25[1] = 1596;
372 writel(tca25[0], (ulong)reg_base + 0x30);
373 writel(tca25[1], (ulong)reg_base + 0x34);
374 return;
375 }
376
377 buf_vref = (fuse->ana_trim2 & 0xc0) >> 6;
378 buf_slope = (fuse->ana_trim2 & 0xF00) >> 8;
379 bjt_cur = (fuse->ana_trim2 & 0xF000) >> 12;
380 bgr = (fuse->ana_trim2 & 0xF0000) >> 16;
381 vlsb = (fuse->ana_trim2 & 0xF00000) >> 20;
382 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
383
384 reg = (bgr << 28) | (bjt_cur << 20) | (vlsb << 12) | (1 << 7);
385 writel(reg, (ulong)reg_base + 0x3c);
386
387 tca40[0] = (fuse->ana_trim3 & 0xFFF0000) >> 16;
388 tca25[0] = (fuse->ana_trim3 & 0xF0000000) >> 28;
389 tca25[0] |= ((fuse->ana_trim4 & 0xFF) << 4);
390 tca105[0] = (fuse->ana_trim4 & 0xFFF00) >> 8;
391 tca40[1] = (fuse->ana_trim4 & 0xFFF00000) >> 20;
392 tca25[1] = fuse2->ana_trim5 & 0xFFF;
393 tca105[1] = (fuse2->ana_trim5 & 0xFFF000) >> 12;
394
395 /* use 25c for 1p calibration */
396 writel(tca25[0] | (tca105[0] << 16), (ulong)reg_base + 0x30);
397 writel(tca25[1] | (tca105[1] << 16), (ulong)reg_base + 0x34);
398 writel(tca40[0] | (tca40[1] << 16), (ulong)reg_base + 0x38);
399}
400#else
401static inline void imx_tmu_mx8mp_init(struct udevice *dev) { }
402#endif
403
Ye Lib7662562023-04-28 12:08:07 +0800404static inline void imx_tmu_mx93_init(struct udevice *dev) { }
Ye Li3e2c22c2024-03-28 18:49:59 +0800405static inline void imx_tmu_mx8mq_init(struct udevice *dev) { }
Ye Lib7662562023-04-28 12:08:07 +0800406
Marek Vasut7903bcf2023-04-04 21:25:10 +0200407static void imx_tmu_arch_init(struct udevice *dev)
408{
409 if (is_imx8mm() || is_imx8mn())
410 imx_tmu_mx8mm_mx8mn_init(dev);
411 else if (is_imx8mp())
412 imx_tmu_mx8mp_init(dev);
Ye Lib7662562023-04-28 12:08:07 +0800413 else if (is_imx93())
414 imx_tmu_mx93_init(dev);
Ye Li3e2c22c2024-03-28 18:49:59 +0800415 else if (is_imx8mq())
416 imx_tmu_mx8mq_init(dev);
Marek Vasut7903bcf2023-04-04 21:25:10 +0200417 else
418 dev_err(dev, "Unsupported SoC, TMU calibration not loaded!\n");
Peng Fan4f5026c2020-05-03 22:19:48 +0800419}
420
Peng Fanbef7d2a2020-05-03 22:19:47 +0800421static void imx_tmu_init(struct udevice *dev)
Peng Fan10de5792020-05-03 22:19:46 +0800422{
Simon Glassfa20e932020-12-03 16:55:20 -0700423 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800424 ulong drv_data = dev_get_driver_data(dev);
425
Marek Vasut39779c62023-04-04 21:25:09 +0200426 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800427
Peng Fanfed211f2020-05-03 22:19:51 +0800428 if (drv_data & FLAGS_VER3) {
429 /* Disable monitoring */
430 writel(0x0, &pdata->regs->regs_v3.ter);
431
432 /* Disable interrupt, using polling instead */
433 writel(0x0, &pdata->regs->regs_v3.tier);
434
435 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800436 /* Disable monitoring */
437 writel(0x0, &pdata->regs->regs_v2.ter);
438
439 /* Disable interrupt, using polling instead */
440 writel(0x0, &pdata->regs->regs_v2.tier);
Ye Lib7662562023-04-28 12:08:07 +0800441 } else if (drv_data & FLAGS_VER4) {
442 /* Disable monitoring */
443 writel(TMR_DISABLE, &pdata->regs->regs_v4.tmr);
444
445 /* Disable interrupt, using polling instead */
446 writel(TIER_DISABLE, &pdata->regs->regs_v4.tier);
447
448 /* Set update_interval */
449 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v4.tmtmir);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800450 } else {
451 /* Disable monitoring */
452 writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
Peng Fan10de5792020-05-03 22:19:46 +0800453
Peng Fanbef7d2a2020-05-03 22:19:47 +0800454 /* Disable interrupt, using polling instead */
455 writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
Peng Fan10de5792020-05-03 22:19:46 +0800456
Peng Fanbef7d2a2020-05-03 22:19:47 +0800457 /* Set update_interval */
458 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
459 }
Peng Fan4f5026c2020-05-03 22:19:48 +0800460
Marek Vasut7903bcf2023-04-04 21:25:10 +0200461 imx_tmu_arch_init(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800462}
463
464static int imx_tmu_enable_msite(struct udevice *dev)
465{
Simon Glassfa20e932020-12-03 16:55:20 -0700466 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800467 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800468 u32 reg;
469
Marek Vasut39779c62023-04-04 21:25:09 +0200470 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800471
472 if (!pdata->regs)
473 return -EIO;
474
Peng Fanfed211f2020-05-03 22:19:51 +0800475 if (drv_data & FLAGS_VER3) {
476 reg = readl(&pdata->regs->regs_v3.ter);
477 reg &= ~TER_EN;
478 writel(reg, &pdata->regs->regs_v3.ter);
479
480 writel(pdata->id << 30, &pdata->regs->regs_v3.tps);
481
482 reg &= ~TER_ALPF;
483 reg |= 0x1;
484 reg &= ~TER_ADC_PD;
485 writel(reg, &pdata->regs->regs_v3.ter);
486
487 /* Enable monitor */
488 reg |= TER_EN;
489 writel(reg, &pdata->regs->regs_v3.ter);
490 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800491 reg = readl(&pdata->regs->regs_v2.ter);
492 reg &= ~TER_EN;
493 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan10de5792020-05-03 22:19:46 +0800494
Peng Fanbef7d2a2020-05-03 22:19:47 +0800495 reg &= ~TER_ALPF;
496 reg |= 0x1;
497 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan10de5792020-05-03 22:19:46 +0800498
Peng Fanbef7d2a2020-05-03 22:19:47 +0800499 /* Enable monitor */
500 reg |= TER_EN;
501 writel(reg, &pdata->regs->regs_v2.ter);
Ye Lib7662562023-04-28 12:08:07 +0800502 } else if (drv_data & FLAGS_VER4) {
503 reg = readl(&pdata->regs->regs_v4.tcmcfg);
504 reg |= (1 << 30) | (1 << 28);
505 reg &= ~0xF000; /* set SAR clk = IPG clk /16 */
506 writel(reg, &pdata->regs->regs_v4.tcmcfg);
507
508 /* Set ALPF*/
509 reg = readl(&pdata->regs->regs_v4.tmr);
510 reg |= TMR_ALPF;
511 writel(reg, &pdata->regs->regs_v4.tmr);
512
513 writel(1, &pdata->regs->regs_v4.tmsr);
514
515 /* Enable ME */
516 reg |= TMR_ME;
517 writel(reg, &pdata->regs->regs_v4.tmr);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800518 } else {
519 /* Clear the ME before setting MSITE and ALPF*/
520 reg = readl(&pdata->regs->regs_v1.tmr);
521 reg &= ~TMR_ME;
522 writel(reg, &pdata->regs->regs_v1.tmr);
523
524 reg |= 1 << (15 - pdata->id);
525 reg |= TMR_ALPF;
526 writel(reg, &pdata->regs->regs_v1.tmr);
527
528 /* Enable ME */
529 reg |= TMR_ME;
530 writel(reg, &pdata->regs->regs_v1.tmr);
531 }
Peng Fan10de5792020-05-03 22:19:46 +0800532
533 return 0;
534}
535
536static int imx_tmu_bind(struct udevice *dev)
537{
Simon Glassfa20e932020-12-03 16:55:20 -0700538 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800539 int ret;
540 ofnode node, offset;
541 const char *name;
542 const void *prop;
Tim Harvey83858252021-02-05 16:11:05 -0800543 int minc, maxc;
Peng Fan10de5792020-05-03 22:19:46 +0800544
Marek Vasut39779c62023-04-04 21:25:09 +0200545 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800546
547 prop = dev_read_prop(dev, "compatible", NULL);
548 if (!prop)
549 return 0;
550
551 pdata->zone_node = 1;
Tim Harvey83858252021-02-05 16:11:05 -0800552 /* default alert/crit temps based on temp grade */
553 get_cpu_temp_grade(&minc, &maxc);
554 pdata->critical = maxc * 1000;
555 pdata->alert = (maxc - 10) * 1000;
Peng Fan10de5792020-05-03 22:19:46 +0800556
557 node = ofnode_path("/thermal-zones");
558 ofnode_for_each_subnode(offset, node) {
559 /* Bind the subnode to this driver */
560 name = ofnode_get_name(offset);
561
562 ret = device_bind_with_driver_data(dev, dev->driver, name,
563 dev->driver_data, offset,
564 NULL);
565 if (ret)
Marek Vasut39779c62023-04-04 21:25:09 +0200566 dev_err(dev, "Error binding driver: %d\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800567 }
568
569 return 0;
570}
571
572static int imx_tmu_parse_fdt(struct udevice *dev)
573{
Simon Glassfa20e932020-12-03 16:55:20 -0700574 struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data;
Peng Fan10de5792020-05-03 22:19:46 +0800575 struct ofnode_phandle_args args;
Benjamin Hahn1c2382e2024-03-04 12:48:54 +0100576 ofnode trips_np, cpu_thermal_np;
Peng Fan10de5792020-05-03 22:19:46 +0800577 int ret;
578
Marek Vasut39779c62023-04-04 21:25:09 +0200579 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800580
Benjamin Hahn1c2382e2024-03-04 12:48:54 +0100581 cpu_thermal_np = ofnode_path("/thermal-zones/cpu-thermal");
582 pdata->polling_delay = ofnode_read_u32_default(cpu_thermal_np, "polling-delay",
583 IMX_TMU_POLLING_DELAY_MS);
Fabio Estevama0266752023-08-23 14:59:08 -0300584
Peng Fan10de5792020-05-03 22:19:46 +0800585 if (pdata->zone_node) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800586 pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800587
588 if (!pdata->regs)
589 return -EINVAL;
590 return 0;
591 }
592
Simon Glassfa20e932020-12-03 16:55:20 -0700593 p_parent_data = dev_get_plat(dev->parent);
Peng Fan10de5792020-05-03 22:19:46 +0800594 if (p_parent_data->zone_node)
595 pdata->regs = p_parent_data->regs;
596
597 ret = dev_read_phandle_with_args(dev, "thermal-sensors",
598 "#thermal-sensor-cells",
599 0, 0, &args);
600 if (ret)
601 return ret;
602
603 if (!ofnode_equal(args.node, dev_ofnode(dev->parent)))
604 return -EFAULT;
605
606 if (args.args_count >= 1)
607 pdata->id = args.args[0];
608 else
609 pdata->id = 0;
610
Marek Vasut39779c62023-04-04 21:25:09 +0200611 dev_dbg(dev, "args.args_count %d, id %d\n", args.args_count, pdata->id);
Peng Fan10de5792020-05-03 22:19:46 +0800612
Fabio Estevama0266752023-08-23 14:59:08 -0300613 pdata->polling_delay = dev_read_u32_default(dev, "polling-delay",
614 IMX_TMU_POLLING_DELAY_MS);
Peng Fan10de5792020-05-03 22:19:46 +0800615
616 trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
617 ofnode_for_each_subnode(trips_np, trips_np) {
618 const char *type;
619
620 type = ofnode_get_property(trips_np, "type", NULL);
621 if (!type)
622 continue;
623 if (!strcmp(type, "critical"))
624 pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
625 else if (strcmp(type, "passive") == 0)
626 pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
627 else
628 continue;
629 }
630
Marek Vasut39779c62023-04-04 21:25:09 +0200631 dev_dbg(dev, "id %d polling_delay %d, critical %d, alert %d\n",
632 pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
Peng Fan10de5792020-05-03 22:19:46 +0800633
634 return 0;
635}
636
637static int imx_tmu_probe(struct udevice *dev)
638{
Simon Glassfa20e932020-12-03 16:55:20 -0700639 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800640 int ret;
641
642 ret = imx_tmu_parse_fdt(dev);
643 if (ret) {
Marek Vasut39779c62023-04-04 21:25:09 +0200644 dev_err(dev, "Error in parsing TMU FDT %d\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800645 return ret;
646 }
647
648 if (pdata->zone_node) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800649 imx_tmu_init(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800650 imx_tmu_calibration(dev);
Tim Harvey83858252021-02-05 16:11:05 -0800651 imx_tmu_enable_msite(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800652 } else {
653 imx_tmu_enable_msite(dev);
654 }
655
656 return 0;
657}
658
659static const struct udevice_id imx_tmu_ids[] = {
660 { .compatible = "fsl,imx8mq-tmu", },
Peng Fanbef7d2a2020-05-03 22:19:47 +0800661 { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, },
Peng Fanfed211f2020-05-03 22:19:51 +0800662 { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, },
Ye Lib7662562023-04-28 12:08:07 +0800663 { .compatible = "fsl,imx93-tmu", .data = FLAGS_VER4, },
Peng Fan10de5792020-05-03 22:19:46 +0800664 { }
665};
666
667U_BOOT_DRIVER(imx_tmu) = {
668 .name = "imx_tmu",
669 .id = UCLASS_THERMAL,
670 .ops = &imx_tmu_ops,
671 .of_match = imx_tmu_ids,
672 .bind = imx_tmu_bind,
673 .probe = imx_tmu_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700674 .plat_auto = sizeof(struct imx_tmu_plat),
Peng Fan10de5792020-05-03 22:19:46 +0800675 .flags = DM_FLAG_PRE_RELOC,
676};