1
2
3
4
5
6
7#include <config.h>
8#include <common.h>
9#include <asm/io.h>
10#include <asm/arch/clock.h>
11#include <asm/arch/sys_proto.h>
12#include <dm.h>
13#include <dm/device-internal.h>
14#include <dm/device.h>
15#include <errno.h>
16#include <fuse.h>
17#include <linux/delay.h>
18#include <malloc.h>
19#include <thermal.h>
20
21DECLARE_GLOBAL_DATA_PTR;
22
23#define SITES_MAX 16
24#define FLAGS_VER2 0x1
25#define FLAGS_VER3 0x2
26
27#define TMR_DISABLE 0x0
28#define TMR_ME 0x80000000
29#define TMR_ALPF 0x0c000000
30#define TMTMIR_DEFAULT 0x00000002
31#define TIER_DISABLE 0x0
32
33#define TER_EN 0x80000000
34#define TER_ADC_PD 0x40000000
35#define TER_ALPF 0x3
36
37
38
39
40struct imx_tmu_site_regs {
41 u32 tritsr;
42 u32 tratsr;
43 u8 res0[0x8];
44};
45
46struct imx_tmu_regs {
47 u32 tmr;
48 u32 tsr;
49 u32 tmtmir;
50 u8 res0[0x14];
51 u32 tier;
52 u32 tidr;
53 u32 tiscr;
54 u32 ticscr;
55 u8 res1[0x10];
56 u32 tmhtcrh;
57 u32 tmhtcrl;
58 u8 res2[0x8];
59 u32 tmhtitr;
60 u32 tmhtatr;
61 u32 tmhtactr;
62 u8 res3[0x24];
63 u32 ttcfgr;
64 u32 tscfgr;
65 u8 res4[0x78];
66 struct imx_tmu_site_regs site[SITES_MAX];
67 u8 res5[0x9f8];
68 u32 ipbrr0;
69 u32 ipbrr1;
70 u8 res6[0x310];
71 u32 ttr0cr;
72 u32 ttr1cr;
73 u32 ttr2cr;
74 u32 ttr3cr;
75};
76
77struct imx_tmu_regs_v2 {
78 u32 ter;
79 u32 tsr;
80 u32 tier;
81 u32 tidr;
82 u32 tmhtitr;
83 u32 tmhtatr;
84 u32 tmhtactr;
85 u32 tscr;
86 u32 tritsr;
87 u32 tratsr;
88 u32 tasr;
89 u32 ttmc;
90 u32 tcaliv;
91};
92
93struct imx_tmu_regs_v3 {
94 u32 ter;
95 u32 tps;
96 u32 tier;
97 u32 tidr;
98 u32 tmhtitr;
99 u32 tmhtatr;
100 u32 tmhtactr;
101 u32 tscr;
102 u32 tritsr;
103 u32 tratsr;
104 u32 tasr;
105 u32 ttmc;
106 u32 tcaliv0;
107 u32 tcaliv1;
108 u32 tcaliv_m40;
109 u32 trim;
110};
111
112union tmu_regs {
113 struct imx_tmu_regs regs_v1;
114 struct imx_tmu_regs_v2 regs_v2;
115 struct imx_tmu_regs_v3 regs_v3;
116};
117
118struct imx_tmu_plat {
119 int critical;
120 int alert;
121 int polling_delay;
122 int id;
123 bool zone_node;
124 union tmu_regs *regs;
125};
126
127static int read_temperature(struct udevice *dev, int *temp)
128{
129 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
130 ulong drv_data = dev_get_driver_data(dev);
131 u32 val;
132 u32 retry = 10;
133 u32 valid = 0;
134
135 do {
136 mdelay(100);
137 retry--;
138
139 if (drv_data & FLAGS_VER3) {
140 val = readl(&pdata->regs->regs_v3.tritsr);
141 valid = val & (1 << (30 + pdata->id));
142 } else if (drv_data & FLAGS_VER2) {
143 val = readl(&pdata->regs->regs_v2.tritsr);
144
145
146
147
148 valid = ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1;
149 } else {
150 val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
151 valid = val & 0x80000000;
152 }
153 } while (!valid && retry > 0);
154
155 if (retry > 0) {
156 if (drv_data & FLAGS_VER3) {
157 val = (val >> (pdata->id * 16)) & 0xff;
158 if (val & 0x80)
159 val = (~(val & 0x7f) + 1);
160
161 *temp = val;
162 if (*temp < -40 || *temp > 125)
163 return -EINVAL;
164
165 *temp *= 1000;
166 } else {
167 *temp = (val & 0xff) * 1000;
168 }
169 } else {
170 return -EINVAL;
171 }
172
173 return 0;
174}
175
176int imx_tmu_get_temp(struct udevice *dev, int *temp)
177{
178 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
179 int cpu_tmp = 0;
180 int ret;
181
182 ret = read_temperature(dev, &cpu_tmp);
183 if (ret)
184 return ret;
185
186 while (cpu_tmp >= pdata->alert) {
187 printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)", cpu_tmp, pdata->alert, pdata->critical);
188 puts(" waiting...\n");
189 mdelay(pdata->polling_delay);
190 ret = read_temperature(dev, &cpu_tmp);
191 if (ret)
192 return ret;
193 }
194
195 *temp = cpu_tmp / 1000;
196
197 return 0;
198}
199
200static const struct dm_thermal_ops imx_tmu_ops = {
201 .get_temp = imx_tmu_get_temp,
202};
203
204static int imx_tmu_calibration(struct udevice *dev)
205{
206 int i, val, len, ret;
207 u32 range[4];
208 const fdt32_t *calibration;
209 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
210 ulong drv_data = dev_get_driver_data(dev);
211
212 debug("%s\n", __func__);
213
214 if (drv_data & (FLAGS_VER2 | FLAGS_VER3))
215 return 0;
216
217 ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4);
218 if (ret) {
219 printf("TMU: missing calibration range, ret = %d.\n", ret);
220 return ret;
221 }
222
223
224 writel(range[0], &pdata->regs->regs_v1.ttr0cr);
225 writel(range[1], &pdata->regs->regs_v1.ttr1cr);
226 writel(range[2], &pdata->regs->regs_v1.ttr2cr);
227 writel(range[3], &pdata->regs->regs_v1.ttr3cr);
228
229 calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
230 if (!calibration || len % 8) {
231 printf("TMU: invalid calibration data.\n");
232 return -ENODEV;
233 }
234
235 for (i = 0; i < len; i += 8, calibration += 2) {
236 val = fdt32_to_cpu(*calibration);
237 writel(val, &pdata->regs->regs_v1.ttcfgr);
238 val = fdt32_to_cpu(*(calibration + 1));
239 writel(val, &pdata->regs->regs_v1.tscfgr);
240 }
241
242 return 0;
243}
244
245void __weak imx_tmu_arch_init(void *reg_base)
246{
247}
248
249static void imx_tmu_init(struct udevice *dev)
250{
251 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
252 ulong drv_data = dev_get_driver_data(dev);
253
254 debug("%s\n", __func__);
255
256 if (drv_data & FLAGS_VER3) {
257
258 writel(0x0, &pdata->regs->regs_v3.ter);
259
260
261 writel(0x0, &pdata->regs->regs_v3.tier);
262
263 } else if (drv_data & FLAGS_VER2) {
264
265 writel(0x0, &pdata->regs->regs_v2.ter);
266
267
268 writel(0x0, &pdata->regs->regs_v2.tier);
269 } else {
270
271 writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
272
273
274 writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
275
276
277 writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
278 }
279
280 imx_tmu_arch_init((void *)pdata->regs);
281}
282
283static int imx_tmu_enable_msite(struct udevice *dev)
284{
285 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
286 ulong drv_data = dev_get_driver_data(dev);
287 u32 reg;
288
289 debug("%s\n", __func__);
290
291 if (!pdata->regs)
292 return -EIO;
293
294 if (drv_data & FLAGS_VER3) {
295 reg = readl(&pdata->regs->regs_v3.ter);
296 reg &= ~TER_EN;
297 writel(reg, &pdata->regs->regs_v3.ter);
298
299 writel(pdata->id << 30, &pdata->regs->regs_v3.tps);
300
301 reg &= ~TER_ALPF;
302 reg |= 0x1;
303 reg &= ~TER_ADC_PD;
304 writel(reg, &pdata->regs->regs_v3.ter);
305
306
307 reg |= TER_EN;
308 writel(reg, &pdata->regs->regs_v3.ter);
309 } else if (drv_data & FLAGS_VER2) {
310 reg = readl(&pdata->regs->regs_v2.ter);
311 reg &= ~TER_EN;
312 writel(reg, &pdata->regs->regs_v2.ter);
313
314 reg &= ~TER_ALPF;
315 reg |= 0x1;
316 writel(reg, &pdata->regs->regs_v2.ter);
317
318
319 reg |= TER_EN;
320 writel(reg, &pdata->regs->regs_v2.ter);
321 } else {
322
323 reg = readl(&pdata->regs->regs_v1.tmr);
324 reg &= ~TMR_ME;
325 writel(reg, &pdata->regs->regs_v1.tmr);
326
327 reg |= 1 << (15 - pdata->id);
328 reg |= TMR_ALPF;
329 writel(reg, &pdata->regs->regs_v1.tmr);
330
331
332 reg |= TMR_ME;
333 writel(reg, &pdata->regs->regs_v1.tmr);
334 }
335
336 return 0;
337}
338
339static int imx_tmu_bind(struct udevice *dev)
340{
341 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
342 int ret;
343 ofnode node, offset;
344 const char *name;
345 const void *prop;
346
347 debug("%s dev name %s\n", __func__, dev->name);
348
349 prop = dev_read_prop(dev, "compatible", NULL);
350 if (!prop)
351 return 0;
352
353 pdata->zone_node = 1;
354
355 node = ofnode_path("/thermal-zones");
356 ofnode_for_each_subnode(offset, node) {
357
358 name = ofnode_get_name(offset);
359
360 ret = device_bind_with_driver_data(dev, dev->driver, name,
361 dev->driver_data, offset,
362 NULL);
363 if (ret)
364 printf("Error binding driver '%s': %d\n",
365 dev->driver->name, ret);
366 }
367
368 return 0;
369}
370
371static int imx_tmu_parse_fdt(struct udevice *dev)
372{
373 struct imx_tmu_plat *pdata = dev_get_platdata(dev), *p_parent_data;
374 struct ofnode_phandle_args args;
375 ofnode trips_np;
376 int ret;
377
378 debug("%s dev name %s\n", __func__, dev->name);
379
380 if (pdata->zone_node) {
381 pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev);
382
383 if (!pdata->regs)
384 return -EINVAL;
385 return 0;
386 }
387
388 p_parent_data = dev_get_platdata(dev->parent);
389 if (p_parent_data->zone_node)
390 pdata->regs = p_parent_data->regs;
391
392 ret = dev_read_phandle_with_args(dev, "thermal-sensors",
393 "#thermal-sensor-cells",
394 0, 0, &args);
395 if (ret)
396 return ret;
397
398 if (!ofnode_equal(args.node, dev_ofnode(dev->parent)))
399 return -EFAULT;
400
401 if (args.args_count >= 1)
402 pdata->id = args.args[0];
403 else
404 pdata->id = 0;
405
406 debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
407
408 pdata->polling_delay = dev_read_u32_default(dev, "polling-delay", 1000);
409
410 trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
411 ofnode_for_each_subnode(trips_np, trips_np) {
412 const char *type;
413
414 type = ofnode_get_property(trips_np, "type", NULL);
415 if (!type)
416 continue;
417 if (!strcmp(type, "critical"))
418 pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
419 else if (strcmp(type, "passive") == 0)
420 pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
421 else
422 continue;
423 }
424
425 debug("id %d polling_delay %d, critical %d, alert %d\n",
426 pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
427
428 return 0;
429}
430
431static int imx_tmu_probe(struct udevice *dev)
432{
433 struct imx_tmu_plat *pdata = dev_get_platdata(dev);
434 int ret;
435
436 ret = imx_tmu_parse_fdt(dev);
437 if (ret) {
438 printf("Error in parsing TMU FDT %d\n", ret);
439 return ret;
440 }
441
442 if (pdata->zone_node) {
443 imx_tmu_init(dev);
444 imx_tmu_calibration(dev);
445 } else {
446 imx_tmu_enable_msite(dev);
447 }
448
449 return 0;
450}
451
452static const struct udevice_id imx_tmu_ids[] = {
453 { .compatible = "fsl,imx8mq-tmu", },
454 { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, },
455 { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, },
456 { }
457};
458
459U_BOOT_DRIVER(imx_tmu) = {
460 .name = "imx_tmu",
461 .id = UCLASS_THERMAL,
462 .ops = &imx_tmu_ops,
463 .of_match = imx_tmu_ids,
464 .bind = imx_tmu_bind,
465 .probe = imx_tmu_probe,
466 .platdata_auto_alloc_size = sizeof(struct imx_tmu_plat),
467 .flags = DM_FLAG_PRE_RELOC,
468};
469