blob: 4721cfbc021813108ba9a559d0ea9b471a52c269 [file] [log] [blame]
Peng Fan2cd7f472020-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 Glass401d1c42020-10-30 21:38:53 -06009#include <asm/global_data.h>
Peng Fan2cd7f472020-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 Vasut114eb252023-04-04 21:25:09 +020014#include <dm/device_compat.h>
Peng Fan2cd7f472020-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 Harvey85abf042020-10-12 12:21:54 -070019#include <linux/delay.h>
Peng Fan2cd7f472020-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 Denk0cf207e2021-09-27 17:42:39 +020026#define FLAGS_VER2 0x1
27#define FLAGS_VER3 0x2
Ye Lib08a0a42023-04-28 12:08:07 +080028#define FLAGS_VER4 0x4
Peng Fan2cd7f472020-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 Fanfc8657b2020-05-03 22:19:47 +080036#define TER_EN 0x80000000
37#define TER_ADC_PD 0x40000000
Peng Fan634fe732020-05-03 22:19:51 +080038#define TER_ALPF 0x3
39
Fabio Estevama79fca72023-08-23 14:59:11 -030040#define IMX_TMU_POLLING_DELAY_MS 5000
Peng Fan2cd7f472020-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 Lib08a0a42023-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 Fanfc8657b2020-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 Fan634fe732020-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 Fanfc8657b2020-05-03 22:19:47 +0800155union tmu_regs {
156 struct imx_tmu_regs regs_v1;
157 struct imx_tmu_regs_v2 regs_v2;
Peng Fan634fe732020-05-03 22:19:51 +0800158 struct imx_tmu_regs_v3 regs_v3;
Ye Lib08a0a42023-04-28 12:08:07 +0800159 struct imx_tmu_regs_v4 regs_v4;
Peng Fanfc8657b2020-05-03 22:19:47 +0800160};
161
Peng Fan2cd7f472020-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 Fanfc8657b2020-05-03 22:19:47 +0800168 union tmu_regs *regs;
Peng Fan2cd7f472020-05-03 22:19:46 +0800169};
170
171static int read_temperature(struct udevice *dev, int *temp)
172{
Simon Glassc69cda22020-12-03 16:55:20 -0700173 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanfc8657b2020-05-03 22:19:47 +0800174 ulong drv_data = dev_get_driver_data(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800175 u32 val;
Peng Fanb5447b92020-05-03 22:19:49 +0800176 u32 retry = 10;
Peng Fan951bf192020-05-03 22:19:50 +0800177 u32 valid = 0;
Peng Fan2cd7f472020-05-03 22:19:46 +0800178
179 do {
Peng Fanb5447b92020-05-03 22:19:49 +0800180 mdelay(100);
181 retry--;
182
Peng Fan634fe732020-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 Fanfc8657b2020-05-03 22:19:47 +0800187 val = readl(&pdata->regs->regs_v2.tritsr);
Peng Fan951bf192020-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 Lib08a0a42023-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 Fan951bf192020-05-03 22:19:50 +0800196 } else {
Peng Fanfc8657b2020-05-03 22:19:47 +0800197 val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
Peng Fan951bf192020-05-03 22:19:50 +0800198 valid = val & 0x80000000;
199 }
200 } while (!valid && retry > 0);
Peng Fan2cd7f472020-05-03 22:19:46 +0800201
Peng Fan634fe732020-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 Lib08a0a42023-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 Fan634fe732020-05-03 22:19:51 +0800220 } else {
221 *temp = (val & 0xff) * 1000;
222 }
223 } else {
Peng Fanb5447b92020-05-03 22:19:49 +0800224 return -EINVAL;
Peng Fan634fe732020-05-03 22:19:51 +0800225 }
Peng Fan2cd7f472020-05-03 22:19:46 +0800226
227 return 0;
228}
229
230int imx_tmu_get_temp(struct udevice *dev, int *temp)
231{
Simon Glassc69cda22020-12-03 16:55:20 -0700232 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan2cd7f472020-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 Estevamf4898e42023-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 Fan2cd7f472020-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 Lib08a0a42023-04-28 12:08:07 +0800261 int index;
Peng Fan2cd7f472020-05-03 22:19:46 +0800262 u32 range[4];
263 const fdt32_t *calibration;
Simon Glassc69cda22020-12-03 16:55:20 -0700264 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanfc8657b2020-05-03 22:19:47 +0800265 ulong drv_data = dev_get_driver_data(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800266
Marek Vasut114eb252023-04-04 21:25:09 +0200267 dev_dbg(dev, "%s\n", __func__);
Peng Fan2cd7f472020-05-03 22:19:46 +0800268
Peng Fan634fe732020-05-03 22:19:51 +0800269 if (drv_data & (FLAGS_VER2 | FLAGS_VER3))
Peng Fanfc8657b2020-05-03 22:19:47 +0800270 return 0;
271
Ye Lib08a0a42023-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 Fan2cd7f472020-05-03 22:19:46 +0800291 ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4);
292 if (ret) {
Marek Vasut114eb252023-04-04 21:25:09 +0200293 dev_err(dev, "TMU: missing calibration range, ret = %d.\n", ret);
Peng Fan2cd7f472020-05-03 22:19:46 +0800294 return ret;
295 }
296
297 /* Init temperature range registers */
Peng Fanfc8657b2020-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 Fan2cd7f472020-05-03 22:19:46 +0800302
303 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
304 if (!calibration || len % 8) {
Marek Vasut114eb252023-04-04 21:25:09 +0200305 dev_err(dev, "TMU: invalid calibration data.\n");
Peng Fan2cd7f472020-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 Fanfc8657b2020-05-03 22:19:47 +0800311 writel(val, &pdata->regs->regs_v1.ttcfgr);
Peng Fan2cd7f472020-05-03 22:19:46 +0800312 val = fdt32_to_cpu(*(calibration + 1));
Peng Fanfc8657b2020-05-03 22:19:47 +0800313 writel(val, &pdata->regs->regs_v1.tscfgr);
Peng Fan2cd7f472020-05-03 22:19:46 +0800314 }
315
316 return 0;
317}
318
Marek Vasuteb1e3702023-04-04 21:25:10 +0200319#if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN)
320static void imx_tmu_mx8mm_mx8mn_init(struct udevice *dev)
Peng Fan84897402020-05-03 22:19:48 +0800321{
Marek Vasuteb1e3702023-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 Lib08a0a42023-04-28 12:08:07 +0800404static inline void imx_tmu_mx93_init(struct udevice *dev) { }
405
Marek Vasuteb1e3702023-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 Lib08a0a42023-04-28 12:08:07 +0800412 else if (is_imx93())
413 imx_tmu_mx93_init(dev);
Marek Vasuteb1e3702023-04-04 21:25:10 +0200414 else
415 dev_err(dev, "Unsupported SoC, TMU calibration not loaded!\n");
Peng Fan84897402020-05-03 22:19:48 +0800416}
417
Peng Fanfc8657b2020-05-03 22:19:47 +0800418static void imx_tmu_init(struct udevice *dev)
Peng Fan2cd7f472020-05-03 22:19:46 +0800419{
Simon Glassc69cda22020-12-03 16:55:20 -0700420 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanfc8657b2020-05-03 22:19:47 +0800421 ulong drv_data = dev_get_driver_data(dev);
422
Marek Vasut114eb252023-04-04 21:25:09 +0200423 dev_dbg(dev, "%s\n", __func__);
Peng Fan2cd7f472020-05-03 22:19:46 +0800424
Peng Fan634fe732020-05-03 22:19:51 +0800425 if (drv_data & FLAGS_VER3) {
426 /* Disable monitoring */
427 writel(0x0, &pdata->regs->regs_v3.ter);
428
429 /* Disable interrupt, using polling instead */
430 writel(0x0, &pdata->regs->regs_v3.tier);
431
432 } else if (drv_data & FLAGS_VER2) {
Peng Fanfc8657b2020-05-03 22:19:47 +0800433 /* Disable monitoring */
434 writel(0x0, &pdata->regs->regs_v2.ter);
Peng Fan2cd7f472020-05-03 22:19:46 +0800435
Peng Fanfc8657b2020-05-03 22:19:47 +0800436 /* Disable interrupt, using polling instead */
437 writel(0x0, &pdata->regs->regs_v2.tier);
Ye Lib08a0a42023-04-28 12:08:07 +0800438 } else if (drv_data & FLAGS_VER4) {
439 /* Disable monitoring */
440 writel(TMR_DISABLE, &pdata->regs->regs_v4.tmr);
441
442 /* Disable interrupt, using polling instead */
443 writel(TIER_DISABLE, &pdata->regs->regs_v4.tier);
444
445 /* Set update_interval */
446 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v4.tmtmir);
Peng Fanfc8657b2020-05-03 22:19:47 +0800447 } else {
448 /* Disable monitoring */
449 writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
Peng Fan2cd7f472020-05-03 22:19:46 +0800450
Peng Fanfc8657b2020-05-03 22:19:47 +0800451 /* Disable interrupt, using polling instead */
452 writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
453
454 /* Set update_interval */
455 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
456 }
Peng Fan84897402020-05-03 22:19:48 +0800457
Marek Vasuteb1e3702023-04-04 21:25:10 +0200458 imx_tmu_arch_init(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800459}
460
461static int imx_tmu_enable_msite(struct udevice *dev)
462{
Simon Glassc69cda22020-12-03 16:55:20 -0700463 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fanfc8657b2020-05-03 22:19:47 +0800464 ulong drv_data = dev_get_driver_data(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800465 u32 reg;
466
Marek Vasut114eb252023-04-04 21:25:09 +0200467 dev_dbg(dev, "%s\n", __func__);
Peng Fan2cd7f472020-05-03 22:19:46 +0800468
469 if (!pdata->regs)
470 return -EIO;
471
Peng Fan634fe732020-05-03 22:19:51 +0800472 if (drv_data & FLAGS_VER3) {
473 reg = readl(&pdata->regs->regs_v3.ter);
474 reg &= ~TER_EN;
475 writel(reg, &pdata->regs->regs_v3.ter);
476
477 writel(pdata->id << 30, &pdata->regs->regs_v3.tps);
478
479 reg &= ~TER_ALPF;
480 reg |= 0x1;
481 reg &= ~TER_ADC_PD;
482 writel(reg, &pdata->regs->regs_v3.ter);
483
484 /* Enable monitor */
485 reg |= TER_EN;
486 writel(reg, &pdata->regs->regs_v3.ter);
487 } else if (drv_data & FLAGS_VER2) {
Peng Fanfc8657b2020-05-03 22:19:47 +0800488 reg = readl(&pdata->regs->regs_v2.ter);
489 reg &= ~TER_EN;
490 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan2cd7f472020-05-03 22:19:46 +0800491
Peng Fanfc8657b2020-05-03 22:19:47 +0800492 reg &= ~TER_ALPF;
493 reg |= 0x1;
494 writel(reg, &pdata->regs->regs_v2.ter);
Peng Fan2cd7f472020-05-03 22:19:46 +0800495
Peng Fanfc8657b2020-05-03 22:19:47 +0800496 /* Enable monitor */
497 reg |= TER_EN;
498 writel(reg, &pdata->regs->regs_v2.ter);
Ye Lib08a0a42023-04-28 12:08:07 +0800499 } else if (drv_data & FLAGS_VER4) {
500 reg = readl(&pdata->regs->regs_v4.tcmcfg);
501 reg |= (1 << 30) | (1 << 28);
502 reg &= ~0xF000; /* set SAR clk = IPG clk /16 */
503 writel(reg, &pdata->regs->regs_v4.tcmcfg);
504
505 /* Set ALPF*/
506 reg = readl(&pdata->regs->regs_v4.tmr);
507 reg |= TMR_ALPF;
508 writel(reg, &pdata->regs->regs_v4.tmr);
509
510 writel(1, &pdata->regs->regs_v4.tmsr);
511
512 /* Enable ME */
513 reg |= TMR_ME;
514 writel(reg, &pdata->regs->regs_v4.tmr);
Peng Fanfc8657b2020-05-03 22:19:47 +0800515 } else {
516 /* Clear the ME before setting MSITE and ALPF*/
517 reg = readl(&pdata->regs->regs_v1.tmr);
518 reg &= ~TMR_ME;
519 writel(reg, &pdata->regs->regs_v1.tmr);
520
521 reg |= 1 << (15 - pdata->id);
522 reg |= TMR_ALPF;
523 writel(reg, &pdata->regs->regs_v1.tmr);
524
525 /* Enable ME */
526 reg |= TMR_ME;
527 writel(reg, &pdata->regs->regs_v1.tmr);
528 }
Peng Fan2cd7f472020-05-03 22:19:46 +0800529
530 return 0;
531}
532
533static int imx_tmu_bind(struct udevice *dev)
534{
Simon Glassc69cda22020-12-03 16:55:20 -0700535 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800536 int ret;
537 ofnode node, offset;
538 const char *name;
539 const void *prop;
Tim Harveydeb78ff2021-02-05 16:11:05 -0800540 int minc, maxc;
Peng Fan2cd7f472020-05-03 22:19:46 +0800541
Marek Vasut114eb252023-04-04 21:25:09 +0200542 dev_dbg(dev, "%s\n", __func__);
Peng Fan2cd7f472020-05-03 22:19:46 +0800543
544 prop = dev_read_prop(dev, "compatible", NULL);
545 if (!prop)
546 return 0;
547
548 pdata->zone_node = 1;
Tim Harveydeb78ff2021-02-05 16:11:05 -0800549 /* default alert/crit temps based on temp grade */
550 get_cpu_temp_grade(&minc, &maxc);
551 pdata->critical = maxc * 1000;
552 pdata->alert = (maxc - 10) * 1000;
Peng Fan2cd7f472020-05-03 22:19:46 +0800553
554 node = ofnode_path("/thermal-zones");
555 ofnode_for_each_subnode(offset, node) {
556 /* Bind the subnode to this driver */
557 name = ofnode_get_name(offset);
558
559 ret = device_bind_with_driver_data(dev, dev->driver, name,
560 dev->driver_data, offset,
561 NULL);
562 if (ret)
Marek Vasut114eb252023-04-04 21:25:09 +0200563 dev_err(dev, "Error binding driver: %d\n", ret);
Peng Fan2cd7f472020-05-03 22:19:46 +0800564 }
565
566 return 0;
567}
568
569static int imx_tmu_parse_fdt(struct udevice *dev)
570{
Simon Glassc69cda22020-12-03 16:55:20 -0700571 struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data;
Peng Fan2cd7f472020-05-03 22:19:46 +0800572 struct ofnode_phandle_args args;
573 ofnode trips_np;
574 int ret;
575
Marek Vasut114eb252023-04-04 21:25:09 +0200576 dev_dbg(dev, "%s\n", __func__);
Peng Fan2cd7f472020-05-03 22:19:46 +0800577
Fabio Estevam402b8102023-08-23 14:59:08 -0300578 pdata->polling_delay = IMX_TMU_POLLING_DELAY_MS;
579
Peng Fan2cd7f472020-05-03 22:19:46 +0800580 if (pdata->zone_node) {
Peng Fanfc8657b2020-05-03 22:19:47 +0800581 pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800582
583 if (!pdata->regs)
584 return -EINVAL;
585 return 0;
586 }
587
Simon Glassc69cda22020-12-03 16:55:20 -0700588 p_parent_data = dev_get_plat(dev->parent);
Peng Fan2cd7f472020-05-03 22:19:46 +0800589 if (p_parent_data->zone_node)
590 pdata->regs = p_parent_data->regs;
591
592 ret = dev_read_phandle_with_args(dev, "thermal-sensors",
593 "#thermal-sensor-cells",
594 0, 0, &args);
595 if (ret)
596 return ret;
597
598 if (!ofnode_equal(args.node, dev_ofnode(dev->parent)))
599 return -EFAULT;
600
601 if (args.args_count >= 1)
602 pdata->id = args.args[0];
603 else
604 pdata->id = 0;
605
Marek Vasut114eb252023-04-04 21:25:09 +0200606 dev_dbg(dev, "args.args_count %d, id %d\n", args.args_count, pdata->id);
Peng Fan2cd7f472020-05-03 22:19:46 +0800607
Fabio Estevam402b8102023-08-23 14:59:08 -0300608 pdata->polling_delay = dev_read_u32_default(dev, "polling-delay",
609 IMX_TMU_POLLING_DELAY_MS);
Peng Fan2cd7f472020-05-03 22:19:46 +0800610
611 trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
612 ofnode_for_each_subnode(trips_np, trips_np) {
613 const char *type;
614
615 type = ofnode_get_property(trips_np, "type", NULL);
616 if (!type)
617 continue;
618 if (!strcmp(type, "critical"))
619 pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
620 else if (strcmp(type, "passive") == 0)
621 pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
622 else
623 continue;
624 }
625
Marek Vasut114eb252023-04-04 21:25:09 +0200626 dev_dbg(dev, "id %d polling_delay %d, critical %d, alert %d\n",
627 pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
Peng Fan2cd7f472020-05-03 22:19:46 +0800628
629 return 0;
630}
631
632static int imx_tmu_probe(struct udevice *dev)
633{
Simon Glassc69cda22020-12-03 16:55:20 -0700634 struct imx_tmu_plat *pdata = dev_get_plat(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800635 int ret;
636
637 ret = imx_tmu_parse_fdt(dev);
638 if (ret) {
Marek Vasut114eb252023-04-04 21:25:09 +0200639 dev_err(dev, "Error in parsing TMU FDT %d\n", ret);
Peng Fan2cd7f472020-05-03 22:19:46 +0800640 return ret;
641 }
642
643 if (pdata->zone_node) {
Peng Fanfc8657b2020-05-03 22:19:47 +0800644 imx_tmu_init(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800645 imx_tmu_calibration(dev);
Tim Harveydeb78ff2021-02-05 16:11:05 -0800646 imx_tmu_enable_msite(dev);
Peng Fan2cd7f472020-05-03 22:19:46 +0800647 } else {
648 imx_tmu_enable_msite(dev);
649 }
650
651 return 0;
652}
653
654static const struct udevice_id imx_tmu_ids[] = {
655 { .compatible = "fsl,imx8mq-tmu", },
Peng Fanfc8657b2020-05-03 22:19:47 +0800656 { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, },
Peng Fan634fe732020-05-03 22:19:51 +0800657 { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, },
Ye Lib08a0a42023-04-28 12:08:07 +0800658 { .compatible = "fsl,imx93-tmu", .data = FLAGS_VER4, },
Peng Fan2cd7f472020-05-03 22:19:46 +0800659 { }
660};
661
662U_BOOT_DRIVER(imx_tmu) = {
663 .name = "imx_tmu",
664 .id = UCLASS_THERMAL,
665 .ops = &imx_tmu_ops,
666 .of_match = imx_tmu_ids,
667 .bind = imx_tmu_bind,
668 .probe = imx_tmu_probe,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700669 .plat_auto = sizeof(struct imx_tmu_plat),
Peng Fan2cd7f472020-05-03 22:19:46 +0800670 .flags = DM_FLAG_PRE_RELOC,
671};