blob: 70d002aee25ba94271d687c45bd1cc8833ebc31d [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>
Simon Glass3ba929a2020-10-30 21:38:53 -06008#include <asm/global_data.h>
Peng Fan10de5792020-05-03 22:19:46 +08009#include <asm/io.h>
10#include <asm/arch/clock.h>
11#include <asm/arch/sys_proto.h>
12#include <dm.h>
Marek Vasut39779c62023-04-04 21:25:09 +020013#include <dm/device_compat.h>
Peng Fan10de5792020-05-03 22:19:46 +080014#include <dm/device-internal.h>
15#include <dm/device.h>
16#include <errno.h>
17#include <fuse.h>
Tim Harveya77d3092020-10-12 12:21:54 -070018#include <linux/delay.h>
Peng Fan10de5792020-05-03 22:19:46 +080019#include <malloc.h>
20#include <thermal.h>
21
22DECLARE_GLOBAL_DATA_PTR;
23
24#define SITES_MAX 16
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020025#define FLAGS_VER2 0x1
26#define FLAGS_VER3 0x2
Ye Lib7662562023-04-28 12:08:07 +080027#define FLAGS_VER4 0x4
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
Fabio Estevam83ba4072023-08-23 14:59:11 -030039#define IMX_TMU_POLLING_DELAY_MS 5000
Peng Fan10de5792020-05-03 22:19:46 +080040/*
41 * i.MX TMU Registers
42 */
43struct imx_tmu_site_regs {
44 u32 tritsr; /* Immediate Temperature Site Register */
45 u32 tratsr; /* Average Temperature Site Register */
46 u8 res0[0x8];
47};
48
49struct imx_tmu_regs {
50 u32 tmr; /* Mode Register */
51 u32 tsr; /* Status Register */
52 u32 tmtmir; /* Temperature measurement interval Register */
53 u8 res0[0x14];
54 u32 tier; /* Interrupt Enable Register */
55 u32 tidr; /* Interrupt Detect Register */
56 u32 tiscr; /* Interrupt Site Capture Register */
57 u32 ticscr; /* Interrupt Critical Site Capture Register */
58 u8 res1[0x10];
59 u32 tmhtcrh; /* High Temperature Capture Register */
60 u32 tmhtcrl; /* Low Temperature Capture Register */
61 u8 res2[0x8];
62 u32 tmhtitr; /* High Temperature Immediate Threshold */
63 u32 tmhtatr; /* High Temperature Average Threshold */
64 u32 tmhtactr; /* High Temperature Average Crit Threshold */
65 u8 res3[0x24];
66 u32 ttcfgr; /* Temperature Configuration Register */
67 u32 tscfgr; /* Sensor Configuration Register */
68 u8 res4[0x78];
69 struct imx_tmu_site_regs site[SITES_MAX];
70 u8 res5[0x9f8];
71 u32 ipbrr0; /* IP Block Revision Register 0 */
72 u32 ipbrr1; /* IP Block Revision Register 1 */
73 u8 res6[0x310];
74 u32 ttr0cr; /* Temperature Range 0 Control Register */
75 u32 ttr1cr; /* Temperature Range 1 Control Register */
76 u32 ttr2cr; /* Temperature Range 2 Control Register */
77 u32 ttr3cr; /* Temperature Range 3 Control Register */
78};
79
Ye Lib7662562023-04-28 12:08:07 +080080struct imx_tmu_regs_v4 {
81 u32 tmr; /* Mode Register */
82 u32 tsr; /* Status Register */
83 u32 tmsr; /* Monitor Site Register */
84 u32 tmtmir; /* Temperature measurement interval Register */
85 u8 res0[0x10];
86 u32 tier; /* Interrupt Enable Register */
87 u32 tidr; /* Interrupt Detect Register */
88 u8 res1[0x8];
89 u32 tiiscr; /* Interrupt Immediate Site Capture Register */
90 u32 tiascr; /* Interrupt Average Site Capture Register */
91 u32 ticscr; /* Interrupt Critical Site Capture Register */
92 u8 res2[0x4];
93 u32 tmhtcr; /* Monitor High Temperature Capture Register */
94 u32 tmltcr; /* MonitorLow Temperature Capture Register */
95 u32 tmrtrcr; /* Monitor Rising Temperature Rate Capture Register */
96 u32 tmftrcr; /* Monitor Falling Temperature Rate Capture Register */
97 u32 tmhtitr; /* Monitor High Temperature Immediate Threshold */
98 u32 tmhtatr; /* Monitor High Temperature Average Threshold */
99 u32 tmhtactr; /* Monitor High Temperature Average Crit Threshold */
100 u8 res3[0x4];
101 u32 tmltitr; /* Monitor Low Temperature Immediate Threshold */
102 u32 tmltatr; /* Monitor Low Temperature Average Threshold */
103 u32 tmltactr; /* Monitor Low Temperature Average Crit Threshold */
104 u8 res4[0x4];
105 u32 tmrtrctr; /* Monitor Rising Temperature Rate Critical Threshold Register */
106 u32 tmftrctr; /* Monitor Falling Temperature Rate Critical Threshold Register */
107 u8 res5[0x8];
108 u32 ttcfgr; /* Temperature Configuration Register */
109 u32 tscfgr; /* Sensor Configuration Register */
110 u8 res6[0x78];
111 u32 tritsr0; /* Immediate Temperature Site Register */
112 u32 tratsr0; /* Average Temperature Site Register */
113 u8 res7[0xdf8];
114 u32 tcmcfg; /* Central Module Configuration */
115 u8 res8[0xc];
116 u32 ttrcr[16]; /* Temperature Range Control Register */
117};
118
Peng Fanbef7d2a2020-05-03 22:19:47 +0800119struct imx_tmu_regs_v2 {
120 u32 ter; /* TMU enable Register */
121 u32 tsr; /* Status Register */
122 u32 tier; /* Interrupt enable register */
123 u32 tidr; /* Interrupt detect register */
124 u32 tmhtitr; /* Monitor high temperature immediate threshold register */
125 u32 tmhtatr; /* Monitor high temperature average threshold register */
126 u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */
127 u32 tscr; /* Sensor value capture register */
128 u32 tritsr; /* Report immediate temperature site register 0 */
129 u32 tratsr; /* Report average temperature site register 0 */
130 u32 tasr; /* Amplifier setting register */
131 u32 ttmc; /* Test MUX control */
132 u32 tcaliv;
133};
134
Peng Fanfed211f2020-05-03 22:19:51 +0800135struct imx_tmu_regs_v3 {
136 u32 ter; /* TMU enable Register */
137 u32 tps; /* Status Register */
138 u32 tier; /* Interrupt enable register */
139 u32 tidr; /* Interrupt detect register */
140 u32 tmhtitr; /* Monitor high temperature immediate threshold register */
141 u32 tmhtatr; /* Monitor high temperature average threshold register */
142 u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */
143 u32 tscr; /* Sensor value capture register */
144 u32 tritsr; /* Report immediate temperature site register 0 */
145 u32 tratsr; /* Report average temperature site register 0 */
146 u32 tasr; /* Amplifier setting register */
147 u32 ttmc; /* Test MUX control */
148 u32 tcaliv0;
149 u32 tcaliv1;
150 u32 tcaliv_m40;
151 u32 trim;
152};
153
Peng Fanbef7d2a2020-05-03 22:19:47 +0800154union tmu_regs {
155 struct imx_tmu_regs regs_v1;
156 struct imx_tmu_regs_v2 regs_v2;
Peng Fanfed211f2020-05-03 22:19:51 +0800157 struct imx_tmu_regs_v3 regs_v3;
Ye Lib7662562023-04-28 12:08:07 +0800158 struct imx_tmu_regs_v4 regs_v4;
Peng Fanbef7d2a2020-05-03 22:19:47 +0800159};
160
Peng Fan10de5792020-05-03 22:19:46 +0800161struct imx_tmu_plat {
162 int critical;
163 int alert;
164 int polling_delay;
165 int id;
166 bool zone_node;
Peng Fanbef7d2a2020-05-03 22:19:47 +0800167 union tmu_regs *regs;
Peng Fan10de5792020-05-03 22:19:46 +0800168};
169
170static int read_temperature(struct udevice *dev, int *temp)
171{
Simon Glassfa20e932020-12-03 16:55:20 -0700172 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800173 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800174 u32 val;
Peng Fancabe2312020-05-03 22:19:49 +0800175 u32 retry = 10;
Peng Fan6eff2872020-05-03 22:19:50 +0800176 u32 valid = 0;
Peng Fan10de5792020-05-03 22:19:46 +0800177
178 do {
Peng Fancabe2312020-05-03 22:19:49 +0800179 mdelay(100);
180 retry--;
181
Peng Fanfed211f2020-05-03 22:19:51 +0800182 if (drv_data & FLAGS_VER3) {
183 val = readl(&pdata->regs->regs_v3.tritsr);
184 valid = val & (1 << (30 + pdata->id));
185 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800186 val = readl(&pdata->regs->regs_v2.tritsr);
Peng Fan6eff2872020-05-03 22:19:50 +0800187 /*
188 * Check if TEMP is in valid range, the V bit in TRITSR
189 * only reflects the RAW uncalibrated data
190 */
191 valid = ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1;
Ye Lib7662562023-04-28 12:08:07 +0800192 } else if (drv_data & FLAGS_VER4) {
193 val = readl(&pdata->regs->regs_v4.tritsr0);
194 valid = val & 0x80000000;
Peng Fan6eff2872020-05-03 22:19:50 +0800195 } else {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800196 val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
Peng Fan6eff2872020-05-03 22:19:50 +0800197 valid = val & 0x80000000;
198 }
199 } while (!valid && retry > 0);
Peng Fan10de5792020-05-03 22:19:46 +0800200
Peng Fanfed211f2020-05-03 22:19:51 +0800201 if (retry > 0) {
202 if (drv_data & FLAGS_VER3) {
203 val = (val >> (pdata->id * 16)) & 0xff;
204 if (val & 0x80) /* Negative */
205 val = (~(val & 0x7f) + 1);
206
207 *temp = val;
208 if (*temp < -40 || *temp > 125) /* Check the range */
209 return -EINVAL;
210
211 *temp *= 1000;
Ye Lib7662562023-04-28 12:08:07 +0800212 } else if (drv_data & FLAGS_VER4) {
213 *temp = (val & 0x1ff) * 1000;
214 if (val & 0x200)
215 *temp += 500;
216
217 /* Convert Kelvin to Celsius */
218 *temp -= 273000;
Peng Fanfed211f2020-05-03 22:19:51 +0800219 } else {
220 *temp = (val & 0xff) * 1000;
221 }
222 } else {
Peng Fancabe2312020-05-03 22:19:49 +0800223 return -EINVAL;
Peng Fanfed211f2020-05-03 22:19:51 +0800224 }
Peng Fan10de5792020-05-03 22:19:46 +0800225
226 return 0;
227}
228
229int imx_tmu_get_temp(struct udevice *dev, int *temp)
230{
Simon Glassfa20e932020-12-03 16:55:20 -0700231 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800232 int cpu_tmp = 0;
233 int ret;
234
235 ret = read_temperature(dev, &cpu_tmp);
236 if (ret)
237 return ret;
238
239 while (cpu_tmp >= pdata->alert) {
Fabio Estevamc28c0752023-08-23 14:59:10 -0300240 dev_crit(dev, "CPU Temperature (%dC) is beyond alert (%dC), close to critical (%dC) waiting...\n",
241 cpu_tmp / 1000, pdata->alert / 1000, pdata->critical / 1000);
Peng Fan10de5792020-05-03 22:19:46 +0800242 mdelay(pdata->polling_delay);
243 ret = read_temperature(dev, &cpu_tmp);
244 if (ret)
245 return ret;
246 }
247
248 *temp = cpu_tmp / 1000;
249
250 return 0;
251}
252
253static const struct dm_thermal_ops imx_tmu_ops = {
254 .get_temp = imx_tmu_get_temp,
255};
256
257static int imx_tmu_calibration(struct udevice *dev)
258{
259 int i, val, len, ret;
Ye Lib7662562023-04-28 12:08:07 +0800260 int index;
Peng Fan10de5792020-05-03 22:19:46 +0800261 u32 range[4];
262 const fdt32_t *calibration;
Simon Glassfa20e932020-12-03 16:55:20 -0700263 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800264 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800265
Marek Vasut39779c62023-04-04 21:25:09 +0200266 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800267
Peng Fanfed211f2020-05-03 22:19:51 +0800268 if (drv_data & (FLAGS_VER2 | FLAGS_VER3))
Peng Fanbef7d2a2020-05-03 22:19:47 +0800269 return 0;
270
Ye Lib7662562023-04-28 12:08:07 +0800271 if (drv_data & FLAGS_VER4) {
272 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
273 if (!calibration || len % 8 || len > 128) {
274 printf("TMU: invalid calibration data.\n");
275 return -ENODEV;
276 }
277
278 for (i = 0; i < len; i += 8, calibration += 2) {
279 index = i / 8;
280 writel(index, &pdata->regs->regs_v4.ttcfgr);
281 val = fdt32_to_cpu(*calibration);
282 writel(val, &pdata->regs->regs_v4.tscfgr);
283 val = fdt32_to_cpu(*(calibration + 1));
284 writel((1 << 31) | val, &pdata->regs->regs_v4.ttrcr[index]);
285 }
286
287 return 0;
288 }
289
Peng Fan10de5792020-05-03 22:19:46 +0800290 ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4);
291 if (ret) {
Marek Vasut39779c62023-04-04 21:25:09 +0200292 dev_err(dev, "TMU: missing calibration range, ret = %d.\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800293 return ret;
294 }
295
296 /* Init temperature range registers */
Peng Fanbef7d2a2020-05-03 22:19:47 +0800297 writel(range[0], &pdata->regs->regs_v1.ttr0cr);
298 writel(range[1], &pdata->regs->regs_v1.ttr1cr);
299 writel(range[2], &pdata->regs->regs_v1.ttr2cr);
300 writel(range[3], &pdata->regs->regs_v1.ttr3cr);
Peng Fan10de5792020-05-03 22:19:46 +0800301
302 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
303 if (!calibration || len % 8) {
Marek Vasut39779c62023-04-04 21:25:09 +0200304 dev_err(dev, "TMU: invalid calibration data.\n");
Peng Fan10de5792020-05-03 22:19:46 +0800305 return -ENODEV;
306 }
307
308 for (i = 0; i < len; i += 8, calibration += 2) {
309 val = fdt32_to_cpu(*calibration);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800310 writel(val, &pdata->regs->regs_v1.ttcfgr);
Peng Fan10de5792020-05-03 22:19:46 +0800311 val = fdt32_to_cpu(*(calibration + 1));
Peng Fanbef7d2a2020-05-03 22:19:47 +0800312 writel(val, &pdata->regs->regs_v1.tscfgr);
Peng Fan10de5792020-05-03 22:19:46 +0800313 }
314
315 return 0;
316}
317
Marek Vasut7903bcf2023-04-04 21:25:10 +0200318#if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN)
319static void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev)
Peng Fan4f5026c2020-05-03 22:19:48 +0800320{
Marek Vasut7903bcf2023-04-04 21:25:10 +0200321 /* Load TCALIV and TASR from fuses */
322 struct ocotp_regs *ocotp =
323 (struct ocotp_regs *)OCOTP_BASE_ADDR;
324 struct fuse_bank *bank = &ocotp->bank[3];
325 struct fuse_bank3_regs *fuse =
326 (struct fuse_bank3_regs *)bank->fuse_regs;
327 struct imx_tmu_plat *pdata = dev_get_plat(dev);
328 void *reg_base = (void *)pdata->regs;
329
330 u32 tca_rt, tca_hr, tca_en;
331 u32 buf_vref, buf_slope;
332
333 tca_rt = fuse->ana0 & 0xFF;
334 tca_hr = (fuse->ana0 & 0xFF00) >> 8;
335 tca_en = (fuse->ana0 & 0x2000000) >> 25;
336
337 buf_vref = (fuse->ana0 & 0x1F00000) >> 20;
338 buf_slope = (fuse->ana0 & 0xF0000) >> 16;
339
340 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
341 writel((tca_en << 31) | (tca_hr << 16) | tca_rt,
342 (ulong)reg_base + 0x30);
343}
344#else
345static inline void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev) { }
346#endif
347
348#if defined(CONFIG_IMX8MP)
349static void imx_tmu_mx8mp_init(struct udevice *dev)
350{
351 /* Load TCALIV0/1/m40 and TRIM from fuses */
352 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
353 struct fuse_bank *bank = &ocotp->bank[38];
354 struct fuse_bank38_regs *fuse =
355 (struct fuse_bank38_regs *)bank->fuse_regs;
356 struct fuse_bank *bank2 = &ocotp->bank[39];
357 struct fuse_bank39_regs *fuse2 =
358 (struct fuse_bank39_regs *)bank2->fuse_regs;
359 struct imx_tmu_plat *pdata = dev_get_plat(dev);
360 void *reg_base = (void *)pdata->regs;
361 u32 buf_vref, buf_slope, bjt_cur, vlsb, bgr;
362 u32 reg;
363 u32 tca40[2], tca25[2], tca105[2];
364
365 /* For blank sample */
366 if (!fuse->ana_trim2 && !fuse->ana_trim3 &&
367 !fuse->ana_trim4 && !fuse2->ana_trim5) {
368 /* Use a default 25C binary codes */
369 tca25[0] = 1596;
370 tca25[1] = 1596;
371 writel(tca25[0], (ulong)reg_base + 0x30);
372 writel(tca25[1], (ulong)reg_base + 0x34);
373 return;
374 }
375
376 buf_vref = (fuse->ana_trim2 & 0xc0) >> 6;
377 buf_slope = (fuse->ana_trim2 & 0xF00) >> 8;
378 bjt_cur = (fuse->ana_trim2 & 0xF000) >> 12;
379 bgr = (fuse->ana_trim2 & 0xF0000) >> 16;
380 vlsb = (fuse->ana_trim2 & 0xF00000) >> 20;
381 writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28);
382
383 reg = (bgr << 28) | (bjt_cur << 20) | (vlsb << 12) | (1 << 7);
384 writel(reg, (ulong)reg_base + 0x3c);
385
386 tca40[0] = (fuse->ana_trim3 & 0xFFF0000) >> 16;
387 tca25[0] = (fuse->ana_trim3 & 0xF0000000) >> 28;
388 tca25[0] |= ((fuse->ana_trim4 & 0xFF) << 4);
389 tca105[0] = (fuse->ana_trim4 & 0xFFF00) >> 8;
390 tca40[1] = (fuse->ana_trim4 & 0xFFF00000) >> 20;
391 tca25[1] = fuse2->ana_trim5 & 0xFFF;
392 tca105[1] = (fuse2->ana_trim5 & 0xFFF000) >> 12;
393
394 /* use 25c for 1p calibration */
395 writel(tca25[0] | (tca105[0] << 16), (ulong)reg_base + 0x30);
396 writel(tca25[1] | (tca105[1] << 16), (ulong)reg_base + 0x34);
397 writel(tca40[0] | (tca40[1] << 16), (ulong)reg_base + 0x38);
398}
399#else
400static inline void imx_tmu_mx8mp_init(struct udevice *dev) { }
401#endif
402
Ye Lib7662562023-04-28 12:08:07 +0800403static inline void imx_tmu_mx93_init(struct udevice *dev) { }
Ye Li3e2c22c2024-03-28 18:49:59 +0800404static inline void imx_tmu_mx8mq_init(struct udevice *dev) { }
Ye Lib7662562023-04-28 12:08:07 +0800405
Marek Vasut7903bcf2023-04-04 21:25:10 +0200406static void imx_tmu_arch_init(struct udevice *dev)
407{
408 if (is_imx8mm() || is_imx8mn())
409 imx_tmu_mx8mm_mx8mn_init(dev);
410 else if (is_imx8mp())
411 imx_tmu_mx8mp_init(dev);
Ye Lib7662562023-04-28 12:08:07 +0800412 else if (is_imx93())
413 imx_tmu_mx93_init(dev);
Ye Li3e2c22c2024-03-28 18:49:59 +0800414 else if (is_imx8mq())
415 imx_tmu_mx8mq_init(dev);
Marek Vasut7903bcf2023-04-04 21:25:10 +0200416 else
417 dev_err(dev, "Unsupported SoC, TMU calibration not loaded!\n");
Peng Fan4f5026c2020-05-03 22:19:48 +0800418}
419
Peng Fanbef7d2a2020-05-03 22:19:47 +0800420static void imx_tmu_init(struct udevice *dev)
Peng Fan10de5792020-05-03 22:19:46 +0800421{
Simon Glassfa20e932020-12-03 16:55:20 -0700422 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800423 ulong drv_data = dev_get_driver_data(dev);
424
Marek Vasut39779c62023-04-04 21:25:09 +0200425 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800426
Peng Fanfed211f2020-05-03 22:19:51 +0800427 if (drv_data & FLAGS_VER3) {
428 /* Disable monitoring */
429 writel(0x0, &pdata->regs->regs_v3.ter);
430
431 /* Disable interrupt, using polling instead */
432 writel(0x0, &pdata->regs->regs_v3.tier);
433
434 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800435 /* Disable monitoring */
436 writel(0x0, &pdata->regs->regs_v2.ter);
437
438 /* Disable interrupt, using polling instead */
439 writel(0x0, &pdata->regs->regs_v2.tier);
Ye Lib7662562023-04-28 12:08:07 +0800440 } else if (drv_data & FLAGS_VER4) {
441 /* Disable monitoring */
442 writel(TMR_DISABLE, &pdata->regs->regs_v4.tmr);
443
444 /* Disable interrupt, using polling instead */
445 writel(TIER_DISABLE, &pdata->regs->regs_v4.tier);
446
447 /* Set update_interval */
448 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v4.tmtmir);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800449 } else {
450 /* Disable monitoring */
451 writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
Peng Fan10de5792020-05-03 22:19:46 +0800452
Peng Fanbef7d2a2020-05-03 22:19:47 +0800453 /* Disable interrupt, using polling instead */
454 writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
Peng Fan10de5792020-05-03 22:19:46 +0800455
Peng Fanbef7d2a2020-05-03 22:19:47 +0800456 /* Set update_interval */
457 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
458 }
Peng Fan4f5026c2020-05-03 22:19:48 +0800459
Marek Vasut7903bcf2023-04-04 21:25:10 +0200460 imx_tmu_arch_init(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800461}
462
463static int imx_tmu_enable_msite(struct udevice *dev)
464{
Simon Glassfa20e932020-12-03 16:55:20 -0700465 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800466 ulong drv_data = dev_get_driver_data(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800467 u32 reg;
468
Marek Vasut39779c62023-04-04 21:25:09 +0200469 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800470
471 if (!pdata->regs)
472 return -EIO;
473
Peng Fanfed211f2020-05-03 22:19:51 +0800474 if (drv_data & FLAGS_VER3) {
475 reg = readl(&pdata->regs->regs_v3.ter);
476 reg &= ~TER_EN;
477 writel(reg, &pdata->regs->regs_v3.ter);
478
479 writel(pdata->id << 30, &pdata->regs->regs_v3.tps);
480
481 reg &= ~TER_ALPF;
482 reg |= 0x1;
483 reg &= ~TER_ADC_PD;
484 writel(reg, &pdata->regs->regs_v3.ter);
485
486 /* Enable monitor */
487 reg |= TER_EN;
488 writel(reg, &pdata->regs->regs_v3.ter);
489 } else if (drv_data & FLAGS_VER2) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800490 reg = readl(&pdata->regs->regs_v2.ter);
491 reg &= ~TER_EN;
492 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan10de5792020-05-03 22:19:46 +0800493
Peng Fanbef7d2a2020-05-03 22:19:47 +0800494 reg &= ~TER_ALPF;
495 reg |= 0x1;
496 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan10de5792020-05-03 22:19:46 +0800497
Peng Fanbef7d2a2020-05-03 22:19:47 +0800498 /* Enable monitor */
499 reg |= TER_EN;
500 writel(reg, &pdata->regs->regs_v2.ter);
Ye Lib7662562023-04-28 12:08:07 +0800501 } else if (drv_data & FLAGS_VER4) {
502 reg = readl(&pdata->regs->regs_v4.tcmcfg);
503 reg |= (1 << 30) | (1 << 28);
504 reg &= ~0xF000; /* set SAR clk = IPG clk /16 */
505 writel(reg, &pdata->regs->regs_v4.tcmcfg);
506
507 /* Set ALPF*/
508 reg = readl(&pdata->regs->regs_v4.tmr);
509 reg |= TMR_ALPF;
510 writel(reg, &pdata->regs->regs_v4.tmr);
511
512 writel(1, &pdata->regs->regs_v4.tmsr);
513
514 /* Enable ME */
515 reg |= TMR_ME;
516 writel(reg, &pdata->regs->regs_v4.tmr);
Peng Fanbef7d2a2020-05-03 22:19:47 +0800517 } else {
518 /* Clear the ME before setting MSITE and ALPF*/
519 reg = readl(&pdata->regs->regs_v1.tmr);
520 reg &= ~TMR_ME;
521 writel(reg, &pdata->regs->regs_v1.tmr);
522
523 reg |= 1 << (15 - pdata->id);
524 reg |= TMR_ALPF;
525 writel(reg, &pdata->regs->regs_v1.tmr);
526
527 /* Enable ME */
528 reg |= TMR_ME;
529 writel(reg, &pdata->regs->regs_v1.tmr);
530 }
Peng Fan10de5792020-05-03 22:19:46 +0800531
532 return 0;
533}
534
535static int imx_tmu_bind(struct udevice *dev)
536{
Simon Glassfa20e932020-12-03 16:55:20 -0700537 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800538 int ret;
539 ofnode node, offset;
540 const char *name;
541 const void *prop;
Tim Harvey83858252021-02-05 16:11:05 -0800542 int minc, maxc;
Peng Fan10de5792020-05-03 22:19:46 +0800543
Marek Vasut39779c62023-04-04 21:25:09 +0200544 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800545
546 prop = dev_read_prop(dev, "compatible", NULL);
547 if (!prop)
548 return 0;
549
550 pdata->zone_node = 1;
Tim Harvey83858252021-02-05 16:11:05 -0800551 /* default alert/crit temps based on temp grade */
552 get_cpu_temp_grade(&minc, &maxc);
553 pdata->critical = maxc * 1000;
554 pdata->alert = (maxc - 10) * 1000;
Peng Fan10de5792020-05-03 22:19:46 +0800555
556 node = ofnode_path("/thermal-zones");
557 ofnode_for_each_subnode(offset, node) {
558 /* Bind the subnode to this driver */
559 name = ofnode_get_name(offset);
560
561 ret = device_bind_with_driver_data(dev, dev->driver, name,
562 dev->driver_data, offset,
563 NULL);
564 if (ret)
Marek Vasut39779c62023-04-04 21:25:09 +0200565 dev_err(dev, "Error binding driver: %d\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800566 }
567
568 return 0;
569}
570
571static int imx_tmu_parse_fdt(struct udevice *dev)
572{
Simon Glassfa20e932020-12-03 16:55:20 -0700573 struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data;
Peng Fan10de5792020-05-03 22:19:46 +0800574 struct ofnode_phandle_args args;
Benjamin Hahn1c2382e2024-03-04 12:48:54 +0100575 ofnode trips_np, cpu_thermal_np;
Peng Fan10de5792020-05-03 22:19:46 +0800576 int ret;
577
Marek Vasut39779c62023-04-04 21:25:09 +0200578 dev_dbg(dev, "%s\n", __func__);
Peng Fan10de5792020-05-03 22:19:46 +0800579
Benjamin Hahn1c2382e2024-03-04 12:48:54 +0100580 cpu_thermal_np = ofnode_path("/thermal-zones/cpu-thermal");
581 pdata->polling_delay = ofnode_read_u32_default(cpu_thermal_np, "polling-delay",
582 IMX_TMU_POLLING_DELAY_MS);
Fabio Estevama0266752023-08-23 14:59:08 -0300583
Peng Fan10de5792020-05-03 22:19:46 +0800584 if (pdata->zone_node) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800585 pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800586
587 if (!pdata->regs)
588 return -EINVAL;
589 return 0;
590 }
591
Simon Glassfa20e932020-12-03 16:55:20 -0700592 p_parent_data = dev_get_plat(dev->parent);
Peng Fan10de5792020-05-03 22:19:46 +0800593 if (p_parent_data->zone_node)
594 pdata->regs = p_parent_data->regs;
595
596 ret = dev_read_phandle_with_args(dev, "thermal-sensors",
597 "#thermal-sensor-cells",
598 0, 0, &args);
599 if (ret)
600 return ret;
601
602 if (!ofnode_equal(args.node, dev_ofnode(dev->parent)))
603 return -EFAULT;
604
605 if (args.args_count >= 1)
606 pdata->id = args.args[0];
607 else
608 pdata->id = 0;
609
Marek Vasut39779c62023-04-04 21:25:09 +0200610 dev_dbg(dev, "args.args_count %d, id %d\n", args.args_count, pdata->id);
Peng Fan10de5792020-05-03 22:19:46 +0800611
Fabio Estevama0266752023-08-23 14:59:08 -0300612 pdata->polling_delay = dev_read_u32_default(dev, "polling-delay",
613 IMX_TMU_POLLING_DELAY_MS);
Peng Fan10de5792020-05-03 22:19:46 +0800614
615 trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
616 ofnode_for_each_subnode(trips_np, trips_np) {
617 const char *type;
618
619 type = ofnode_get_property(trips_np, "type", NULL);
620 if (!type)
621 continue;
622 if (!strcmp(type, "critical"))
623 pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
624 else if (strcmp(type, "passive") == 0)
625 pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
626 else
627 continue;
628 }
629
Marek Vasut39779c62023-04-04 21:25:09 +0200630 dev_dbg(dev, "id %d polling_delay %d, critical %d, alert %d\n",
631 pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
Peng Fan10de5792020-05-03 22:19:46 +0800632
633 return 0;
634}
635
636static int imx_tmu_probe(struct udevice *dev)
637{
Simon Glassfa20e932020-12-03 16:55:20 -0700638 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800639 int ret;
640
641 ret = imx_tmu_parse_fdt(dev);
642 if (ret) {
Marek Vasut39779c62023-04-04 21:25:09 +0200643 dev_err(dev, "Error in parsing TMU FDT %d\n", ret);
Peng Fan10de5792020-05-03 22:19:46 +0800644 return ret;
645 }
646
647 if (pdata->zone_node) {
Peng Fanbef7d2a2020-05-03 22:19:47 +0800648 imx_tmu_init(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800649 imx_tmu_calibration(dev);
Tim Harvey83858252021-02-05 16:11:05 -0800650 imx_tmu_enable_msite(dev);
Peng Fan10de5792020-05-03 22:19:46 +0800651 } else {
652 imx_tmu_enable_msite(dev);
653 }
654
655 return 0;
656}
657
658static const struct udevice_id imx_tmu_ids[] = {
659 { .compatible = "fsl,imx8mq-tmu", },
Peng Fanbef7d2a2020-05-03 22:19:47 +0800660 { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, },
Peng Fanfed211f2020-05-03 22:19:51 +0800661 { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, },
Ye Lib7662562023-04-28 12:08:07 +0800662 { .compatible = "fsl,imx93-tmu", .data = FLAGS_VER4, },
Peng Fan10de5792020-05-03 22:19:46 +0800663 { }
664};
665
666U_BOOT_DRIVER(imx_tmu) = {
667 .name = "imx_tmu",
668 .id = UCLASS_THERMAL,
669 .ops = &imx_tmu_ops,
670 .of_match = imx_tmu_ids,
671 .bind = imx_tmu_bind,
672 .probe = imx_tmu_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700673 .plat_auto = sizeof(struct imx_tmu_plat),
Peng Fan10de5792020-05-03 22:19:46 +0800674 .flags = DM_FLAG_PRE_RELOC,
675};