Blame view

drivers/thermal/nxp_tmu.c 10 KB
8e09d0f0a   Ye Li   MLK-16238-1 therm...
1
  /*
1a66350d1   Ye Li   MLK-20784-1 TMU: ...
2
   * Copyright 2017-2019 NXP
8e09d0f0a   Ye Li   MLK-16238-1 therm...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *
   * SPDX-License-Identifier:	GPL-2.0+
   */
  
  #include <config.h>
  #include <common.h>
  #include <fuse.h>
  #include <asm/io.h>
  #include <asm/arch/clock.h>
  #include <asm/arch/sys_proto.h>
  #include <dm.h>
  #include <errno.h>
  #include <malloc.h>
  #include <thermal.h>
  #include <dm/device-internal.h>
  #include <dm/device.h>
  
  DECLARE_GLOBAL_DATA_PTR;
  
  #define SITES_MAX	16
f68b8d4e0   Ye Li   MLK-18341-1 therm...
23
  #define FLAGS_VER2 	0x1
8e09d0f0a   Ye Li   MLK-16238-1 therm...
24
25
26
27
28
29
  
  #define TMR_DISABLE	0x0
  #define TMR_ME		0x80000000
  #define TMR_ALPF	0x0c000000
  #define TMTMIR_DEFAULT	0x00000002
  #define TIER_DISABLE	0x0
f68b8d4e0   Ye Li   MLK-18341-1 therm...
30
31
  #define TER_EN			0x80000000
  #define TER_ALPF		0x3
8e09d0f0a   Ye Li   MLK-16238-1 therm...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  /*
   * NXP TMU Registers
   */
  struct nxp_tmu_site_regs {
  	u32 tritsr;		/* Immediate Temperature Site Register */
  	u32 tratsr;		/* Average Temperature Site Register */
  	u8 res0[0x8];
  };
  
  struct nxp_tmu_regs {
  	u32 tmr;		/* Mode Register */
  	u32 tsr;		/* Status Register */
  	u32 tmtmir;		/* Temperature measurement interval Register */
  	u8 res0[0x14];
  	u32 tier;		/* Interrupt Enable Register */
  	u32 tidr;		/* Interrupt Detect Register */
  	u32 tiscr;		/* Interrupt Site Capture Register */
  	u32 ticscr;		/* Interrupt Critical Site Capture Register */
  	u8 res1[0x10];
  	u32 tmhtcrh;		/* High Temperature Capture Register */
  	u32 tmhtcrl;		/* Low Temperature Capture Register */
  	u8 res2[0x8];
  	u32 tmhtitr;		/* High Temperature Immediate Threshold */
  	u32 tmhtatr;		/* High Temperature Average Threshold */
  	u32 tmhtactr;	/* High Temperature Average Crit Threshold */
  	u8 res3[0x24];
  	u32 ttcfgr;		/* Temperature Configuration Register */
  	u32 tscfgr;		/* Sensor Configuration Register */
  	u8 res4[0x78];
  	struct nxp_tmu_site_regs site[SITES_MAX];
  	u8 res5[0x9f8];
  	u32 ipbrr0;		/* IP Block Revision Register 0 */
  	u32 ipbrr1;		/* IP Block Revision Register 1 */
  	u8 res6[0x310];
  	u32 ttr0cr;		/* Temperature Range 0 Control Register */
  	u32 ttr1cr;		/* Temperature Range 1 Control Register */
  	u32 ttr2cr;		/* Temperature Range 2 Control Register */
  	u32 ttr3cr;		/* Temperature Range 3 Control Register */
  };
f68b8d4e0   Ye Li   MLK-18341-1 therm...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  struct nxp_tmu_regs_v2 {
  	u32 ter;		/* TMU enable Register */
  	u32 tsr;		/* Status Register */
  	u32 tier;		/* Interrupt enable register */
  	u32 tidr;		/* Interrupt detect  register */
  	u32 tmhtitr;		/* Monitor high temperature immediate threshold register */
  	u32 tmhtatr;		/* Monitor high temperature average threshold register */
  	u32 tmhtactr;	/* TMU monitor high temperature average critical  threshold register */
  	u32 tscr;		/* Sensor value capture register */
  	u32 tritsr;		/* Report immediate temperature site register 0 */
  	u32 tratsr;		/* Report average temperature site register 0 */
  	u32 tasr;			/* Amplifier setting register */
  	u32 ttmc;		/* Test MUX control */
  	u32 tcaliv;
  };
  
  union tmu_regs {
  	struct nxp_tmu_regs regs_v1;
  	struct nxp_tmu_regs_v2 regs_v2;
  };
8e09d0f0a   Ye Li   MLK-16238-1 therm...
91
92
93
94
95
96
  struct nxp_tmu_plat {
  	int critical;
  	int alert;
  	int polling_delay;
  	int id;
  	bool zone_node;
f68b8d4e0   Ye Li   MLK-18341-1 therm...
97
  	union tmu_regs *regs;
8e09d0f0a   Ye Li   MLK-16238-1 therm...
98
99
100
101
102
  };
  
  static int read_temperature(struct udevice *dev, int *temp)
  {
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
f68b8d4e0   Ye Li   MLK-18341-1 therm...
103
  	ulong drv_data = dev_get_driver_data(dev);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
104
  	u32 val;
e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
105
  	u32 retry = 10;
c466dbc65   Ye Li   MLK-21019 TMU: Ch...
106
  	u32 valid = 0;
8e09d0f0a   Ye Li   MLK-16238-1 therm...
107
108
  
  	do {
e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
109
110
  		mdelay(100);
  		retry--;
c466dbc65   Ye Li   MLK-21019 TMU: Ch...
111
  		if (drv_data & FLAGS_VER2) {
f68b8d4e0   Ye Li   MLK-18341-1 therm...
112
  			val = readl(&pdata->regs->regs_v2.tritsr);
c466dbc65   Ye Li   MLK-21019 TMU: Ch...
113
114
115
116
117
118
  
  			/* Check if TEMP is in valid range, the V bit in TRITSR
  			 * only reflects the RAW uncalibrated data
  			 */
  			valid =  ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1;
  		} else {
f68b8d4e0   Ye Li   MLK-18341-1 therm...
119
  			val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
c466dbc65   Ye Li   MLK-21019 TMU: Ch...
120
121
122
  			valid = val & 0x80000000;
  		}
  	} while (!valid && retry > 0);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
123

e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
124
125
126
127
128
129
  	if (retry > 0) {
  		*temp = (val & 0xff) * 1000;
  		return 0;
  	} else {
  		return -EINVAL;
  	}
8e09d0f0a   Ye Li   MLK-16238-1 therm...
130
131
132
133
134
135
136
137
138
  }
  
  int nxp_tmu_get_temp(struct udevice *dev, int *temp)
  {
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
  	int cpu_tmp = 0;
  	int ret;
  
  	ret = read_temperature(dev, &cpu_tmp);
e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
139
140
141
  	if (ret) {
  		printf("invalid data
  ");
8e09d0f0a   Ye Li   MLK-16238-1 therm...
142
  		return ret;
e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
143
  	}
8e09d0f0a   Ye Li   MLK-16238-1 therm...
144
145
146
147
148
149
150
151
  
  	while (cpu_tmp >= pdata->alert) {
  		printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)",
  		       cpu_tmp, pdata->alert, pdata->critical);
  		puts(" waiting...
  ");
  		mdelay(pdata->polling_delay);
  		ret = read_temperature(dev, &cpu_tmp);
e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
152
153
154
  		if (ret) {
  			printf("invalid data
  ");
c466dbc65   Ye Li   MLK-21019 TMU: Ch...
155
  			return ret;
e4ab28d1b   Ye Li   MLK-20966 TMU: Fi...
156
  		}
8e09d0f0a   Ye Li   MLK-16238-1 therm...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  	}
  
  	*temp = cpu_tmp / 1000;
  
  	return 0;
  }
  
  static const struct dm_thermal_ops nxp_tmu_ops = {
  	.get_temp	= nxp_tmu_get_temp,
  };
  
  static int nxp_tmu_calibration(struct udevice *dev)
  {
  	int i, val, len, ret;
  	u32 range[4];
  	const fdt32_t *calibration;
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
f68b8d4e0   Ye Li   MLK-18341-1 therm...
174
  	ulong drv_data = dev_get_driver_data(dev);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
175
176
177
  
  	debug("%s
  ", __func__);
f68b8d4e0   Ye Li   MLK-18341-1 therm...
178
179
  	if (drv_data & FLAGS_VER2)
  		return 0;
8e09d0f0a   Ye Li   MLK-16238-1 therm...
180
181
182
183
184
185
186
187
188
  	ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
  		"fsl,tmu-range", range, 4);
  	if (ret) {
  		printf("TMU: missing calibration range, ret = %d.
  ", ret);
  		return ret;
  	}
  
  	/* Init temperature range registers */
f68b8d4e0   Ye Li   MLK-18341-1 therm...
189
190
191
192
  	writel(range[0], &pdata->regs->regs_v1.ttr0cr);
  	writel(range[1], &pdata->regs->regs_v1.ttr1cr);
  	writel(range[2], &pdata->regs->regs_v1.ttr2cr);
  	writel(range[3], &pdata->regs->regs_v1.ttr3cr);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
193
194
195
196
197
198
199
200
201
202
203
  
  	calibration = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
  		"fsl,tmu-calibration", &len);
  	if (calibration == NULL || len % 8) {
  		printf("TMU: invalid calibration data.
  ");
  		return -ENODEV;
  	}
  
  	for (i = 0; i < len; i += 8, calibration += 2) {
  		val = fdt32_to_cpu(*calibration);
f68b8d4e0   Ye Li   MLK-18341-1 therm...
204
  		writel(val, &pdata->regs->regs_v1.ttcfgr);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
205
  		val = fdt32_to_cpu(*(calibration + 1));
f68b8d4e0   Ye Li   MLK-18341-1 therm...
206
  		writel(val, &pdata->regs->regs_v1.tscfgr);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
207
208
209
210
  	}
  
  	return 0;
  }
1a66350d1   Ye Li   MLK-20784-1 TMU: ...
211
212
213
214
  void __weak nxp_tmu_arch_init(void *reg_base)
  {
  	return;
  }
f68b8d4e0   Ye Li   MLK-18341-1 therm...
215
  static void nxp_tmu_init(struct udevice *dev)
8e09d0f0a   Ye Li   MLK-16238-1 therm...
216
  {
f68b8d4e0   Ye Li   MLK-18341-1 therm...
217
218
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
  	ulong drv_data = dev_get_driver_data(dev);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
219
220
  	debug("%s
  ", __func__);
f68b8d4e0   Ye Li   MLK-18341-1 therm...
221
222
223
224
225
226
227
228
229
  	if (drv_data & FLAGS_VER2) {
  		/* Disable monitoring */
  		writel(0x0, &pdata->regs->regs_v2.ter);
  
  		/* Disable interrupt, using polling instead */
  		writel(0x0, &pdata->regs->regs_v2.tier);
  	} else {
  		/* Disable monitoring */
  		writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
230

f68b8d4e0   Ye Li   MLK-18341-1 therm...
231
232
  		/* Disable interrupt, using polling instead */
  		writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
233

f68b8d4e0   Ye Li   MLK-18341-1 therm...
234
235
236
  		/* Set update_interval */
  		writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
  	}
1a66350d1   Ye Li   MLK-20784-1 TMU: ...
237
238
  
  	nxp_tmu_arch_init((void *)pdata->regs);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
239
240
241
242
243
  }
  
  static int nxp_tmu_enable_msite(struct udevice *dev)
  {
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
f68b8d4e0   Ye Li   MLK-18341-1 therm...
244
  	ulong drv_data = dev_get_driver_data(dev);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
245
246
247
248
249
250
251
  	u32 reg;
  
  	debug("%s
  ", __func__);
  
  	if (!pdata->regs)
  		return -EIO;
f68b8d4e0   Ye Li   MLK-18341-1 therm...
252
253
254
255
  	if (drv_data & FLAGS_VER2) {
  		reg = readl(&pdata->regs->regs_v2.ter);
  		reg &= ~TER_EN;
  		writel(reg, &pdata->regs->regs_v2.ter);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
256

f68b8d4e0   Ye Li   MLK-18341-1 therm...
257
258
259
  		reg &= ~TER_ALPF;
  		reg |= 0x1;
  		writel(reg, &pdata->regs->regs_v2.ter);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
260

f68b8d4e0   Ye Li   MLK-18341-1 therm...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  		/* Enable monitor */
  		reg |= TER_EN;
  		writel(reg, &pdata->regs->regs_v2.ter);
  	} else {
  		/* Clear the ME before setting MSITE and ALPF*/
  		reg = readl(&pdata->regs->regs_v1.tmr);
  		reg &= ~TMR_ME;
  		writel(reg, &pdata->regs->regs_v1.tmr);
  
  		reg |= 1 << (15 - pdata->id);
  		reg |= TMR_ALPF;
  		writel(reg, &pdata->regs->regs_v1.tmr);
  
  		/* Enable ME */
  		reg |= TMR_ME;
  		writel(reg, &pdata->regs->regs_v1.tmr);
  	}
8e09d0f0a   Ye Li   MLK-16238-1 therm...
278
279
280
281
282
283
284
285
286
287
288
289
  
  	return 0;
  }
  
  static int nxp_tmu_probe(struct udevice *dev)
  {
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
  
  	debug("%s dev name %s
  ", __func__, dev->name);
  
  	if (pdata->zone_node) {
f68b8d4e0   Ye Li   MLK-18341-1 therm...
290
  		nxp_tmu_init(dev);
8e09d0f0a   Ye Li   MLK-16238-1 therm...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  		nxp_tmu_calibration(dev);
  	} else {
  		nxp_tmu_enable_msite(dev);
  	}
  
  	return 0;
  }
  
  static int nxp_tmu_bind(struct udevice *dev)
  {
  	int ret;
  	int offset;
  	const char *name;
  	const void *prop;
  
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
  
  	debug("%s dev name %s
  ", __func__, dev->name);
  
  	prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible", NULL);
  	if (!prop)
  		return 0;
  	else
  		pdata->zone_node = 1;
  
  	offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
  	fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
  		/* Bind the subnode to this driver */
  		name = fdt_get_name(gd->fdt_blob, offset, NULL);
  
  		ret = device_bind_with_driver_data(dev, dev->driver, name,
  						   dev->driver_data, offset_to_ofnode(offset), NULL);
  		if (ret)
  			printf("Error binding driver '%s': %d
  ", dev->driver->name,
  				ret);
  	}
  	return 0;
  }
  
  static int nxp_tmu_ofdata_to_platdata(struct udevice *dev)
  {
  	int ret;
  	int trips_np;
  
  	struct nxp_tmu_plat *pdata = dev_get_platdata(dev);
  	struct fdtdec_phandle_args args;
  
  	debug("%s dev name %s
  ", __func__, dev->name);
  
  	if (pdata->zone_node) {
f68b8d4e0   Ye Li   MLK-18341-1 therm...
344
  		pdata->regs = (union tmu_regs *)fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg");
8e09d0f0a   Ye Li   MLK-16238-1 therm...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  
  		if ((fdt_addr_t)pdata->regs == FDT_ADDR_T_NONE)
  			return -EINVAL;
  		return 0;
  	} else {
  		struct nxp_tmu_plat *p_parent_data = dev_get_platdata(dev->parent);
  		if (p_parent_data->zone_node)
  			pdata->regs = p_parent_data->regs;
  	}
  
  	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), "thermal-sensors",
  					 "#thermal-sensor-cells",
  					 0, 0, &args);
  	if (ret)
  		return ret;
  
  	if (args.node != dev_of_offset(dev->parent))
  		return -EFAULT;
  
  	if (args.args_count >= 1)
  		pdata->id = args.args[0];
  	else
  		pdata->id = 0;
  
  	debug("args.args_count %d, id %d
  ", args.args_count, pdata->id);
  
  	pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "polling-delay", 1000);
  
  	trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev), "trips");
  	fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
  		const char *type;
  		type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
  		if (type) {
  			if (strcmp(type, "critical") == 0)
  				pdata->critical = fdtdec_get_int(gd->fdt_blob, trips_np, "temperature", 85);
  			else if (strcmp(type, "passive") == 0)
  				pdata->alert = fdtdec_get_int(gd->fdt_blob, trips_np, "temperature", 80);
  		}
  	}
  
  	debug("id %d polling_delay %d, critical %d, alert %d
  ",
  		pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
  
  	return 0;
  }
  
  static const struct udevice_id nxp_tmu_ids[] = {
  	{ .compatible = "fsl,imx8mq-tmu", },
f68b8d4e0   Ye Li   MLK-18341-1 therm...
395
  	{ .compatible = "fsl,imx8mm-tmu", .data=FLAGS_VER2, },
8e09d0f0a   Ye Li   MLK-16238-1 therm...
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  	{ }
  };
  
  U_BOOT_DRIVER(nxp_tmu) = {
  	.name	= "nxp_tmu",
  	.id	= UCLASS_THERMAL,
  	.ops	= &nxp_tmu_ops,
  	.of_match = nxp_tmu_ids,
  	.bind = nxp_tmu_bind,
  	.probe	= nxp_tmu_probe,
  	.ofdata_to_platdata = nxp_tmu_ofdata_to_platdata,
  	.platdata_auto_alloc_size = sizeof(struct nxp_tmu_plat),
  	.flags  = DM_FLAG_PRE_RELOC,
  };