xref: /freebsd/sys/arm64/qoriq/qoriq_therm.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
1 /*-
2  *
3  * SPDX-License-Identifier: BSD-2-Clause
4  *
5  * Copyright  2020 Michal Meloun <mmel@FreeBSD.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 /*
31  * Thermometer driver for QorIQ  SoCs.
32  */
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/malloc.h>
40 #include <sys/rman.h>
41 #include <sys/sysctl.h>
42 
43 #include <machine/bus.h>
44 
45 #include <dev/clk/clk.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48 
49 #include "qoriq_therm_if.h"
50 
51 #define	TMU_TMR		0x00
52 #define	TMU_TSR		0x04
53 #define TMUV1_TMTMIR	0x08
54 #define TMUV2_TMSR	0x08
55 #define TMUV2_TMTMIR	0x0C
56 #define	TMU_TIER	0x20
57 #define	TMU_TTCFGR	0x80
58 #define	TMU_TSCFGR	0x84
59 #define	TMU_TRITSR(x)	(0x100 + (16 * (x)))
60 #define	 TMU_TRITSR_VALID	(1U << 31)
61 #define	TMUV2_TMSAR(x)	(0x304 + (16 * (x)))
62 #define	TMU_VERSION	0xBF8			/* not in TRM */
63 #define	TMUV2_TEUMR(x)	(0xF00 + (4 * (x)))
64 #define	TMU_TTRCR(x)	(0xF10 + (4 * (x)))
65 
66 
67 struct tsensor {
68 	int			site_id;
69 	char 			*name;
70 	int			id;
71 };
72 
73 struct qoriq_therm_softc {
74 	device_t		dev;
75 	struct resource		*mem_res;
76 	struct resource		*irq_res;
77 	void			*irq_ih;
78 	int			ntsensors;
79 	struct tsensor		*tsensors;
80 	bool			little_endian;
81 	clk_t			clk;
82 	int			ver;
83 };
84 
85 static struct sysctl_ctx_list qoriq_therm_sysctl_ctx;
86 
87 struct tsensor default_sensors[] =
88 {
89 	{ 0,	"site0",		0 },
90 	{ 1,	"site1",		1 },
91 	{ 2,	"site2",		2 },
92 	{ 3,	"site3",		3 },
93 	{ 4,	"site4",		4 },
94 	{ 5,	"site5",		5 },
95 	{ 6,	"site6",		6 },
96 	{ 7,	"site7",		7 },
97 	{ 8,	"site8",		8 },
98 	{ 9,	"site9",		9 },
99 	{ 10,	"site10",		10 },
100 	{ 11,	"site11",		11 },
101 	{ 12,	"site12",		12 },
102 	{ 13,	"site13",		13 },
103 	{ 14,	"site14",		14 },
104 	{ 15,	"site15",		15 },
105 };
106 
107 static struct tsensor imx8mq_sensors[] =
108 {
109 	{ 0,	"cpu",			0 },
110 	{ 1,	"gpu",			1 },
111 	{ 2,	"vpu",			2 },
112 };
113 
114 static struct tsensor ls1012_sensors[] =
115 {
116 	{ 0,	"cpu-thermal",		0 },
117 };
118 
119 static struct tsensor ls1028_sensors[] =
120 {
121 	{ 0,	"ddr-controller",	0 },
122 	{ 1,	"core-cluster",		1 },
123 };
124 
125 static struct tsensor ls1043_sensors[] =
126 {
127 	{ 0,	"ddr-controller",	0 },
128 	{ 1,	"serdes",		1 },
129 	{ 2,	"fman",			2 },
130 	{ 3,	"core-cluster",		3 },
131 };
132 
133 static struct tsensor ls1046_sensors[] =
134 {
135 	{ 0,	"ddr-controller",	0 },
136 	{ 1,	"serdes",		1 },
137 	{ 2,	"fman",			2 },
138 	{ 3,	"core-cluster",		3 },
139 	{ 4,	"sec",			4 },
140 };
141 
142 static struct tsensor ls1088_sensors[] =
143 {
144 	{ 0,	"core-cluster",		0 },
145 	{ 1,	"soc",			1 },
146 };
147 
148 /* Note: tmu[1..7] not [0..6]. */
149 static struct tsensor lx2080_sensors[] =
150 {
151 	{ 1,	"ddr-controller1",	0 },
152 	{ 2,	"ddr-controller2",	1 },
153 	{ 3,	"ddr-controller3",	2 },
154 	{ 4,	"core-cluster1",	3 },
155 	{ 5,	"core-cluster2",	4 },
156 	{ 6,	"core-cluster3",	5 },
157 	{ 7,	"core-cluster4",	6 },
158 };
159 
160 static struct tsensor lx2160_sensors[] =
161 {
162 	{ 0,	"cluster6-7",		0 },
163 	{ 1,	"ddr-cluster5",		1 },
164 	{ 2,	"wriop",		2 },
165 	{ 3,	"dce-qbman-hsio2",	3 },
166 	{ 4,	"ccn-dpaa-tbu",		4 },
167 	{ 5,	"cluster4-hsio3",	5 },
168 	{ 6,	"cluster2-3",		6 },
169 };
170 
171 struct qoriq_therm_socs {
172 	const char		*name;
173 	struct tsensor		*tsensors;
174 	int			ntsensors;
175 } qoriq_therm_socs[] = {
176 #define	_SOC(_n, _a)	{ _n, _a, nitems(_a) }
177 	_SOC("fsl,imx8mq",	imx8mq_sensors),
178 	_SOC("fsl,ls1012a",	ls1012_sensors),
179 	_SOC("fsl,ls1028a",	ls1028_sensors),
180 	_SOC("fsl,ls1043a",	ls1043_sensors),
181 	_SOC("fsl,ls1046a",	ls1046_sensors),
182 	_SOC("fsl,ls1088a",	ls1088_sensors),
183 	_SOC("fsl,ls2080a",	lx2080_sensors),
184 	_SOC("fsl,lx2160a",	lx2160_sensors),
185 	{ NULL,	NULL, 0 }
186 #undef _SOC
187 };
188 
189 static struct ofw_compat_data compat_data[] = {
190 	{"fsl,qoriq-tmu",	1},
191 	{"fsl,imx8mq-tmu",	1},
192 	{NULL,			0},
193 };
194 
195 static inline void
WR4(struct qoriq_therm_softc * sc,bus_size_t addr,uint32_t val)196 WR4(struct qoriq_therm_softc *sc, bus_size_t addr, uint32_t val)
197 {
198 
199 	val = sc->little_endian ? htole32(val): htobe32(val);
200 	bus_write_4(sc->mem_res, addr, val);
201 }
202 
203 static inline uint32_t
RD4(struct qoriq_therm_softc * sc,bus_size_t addr)204 RD4(struct qoriq_therm_softc *sc, bus_size_t addr)
205 {
206 	uint32_t val;
207 
208 	val = bus_read_4(sc->mem_res, addr);
209 	return (sc->little_endian ? le32toh(val): be32toh(val));
210 }
211 
212 static int
qoriq_therm_read_temp(struct qoriq_therm_softc * sc,struct tsensor * sensor,int * temp)213 qoriq_therm_read_temp(struct qoriq_therm_softc *sc, struct tsensor *sensor,
214     int *temp)
215 {
216 	int timeout;
217 	uint32_t val;
218 
219 	/* wait for valid sample */
220 	for (timeout = 1000; timeout > 0; timeout--) {
221 		val = RD4(sc, TMU_TRITSR(sensor->site_id));
222 		if (val & TMU_TRITSR_VALID)
223 			break;
224 		DELAY(100);
225 	}
226 	if (timeout <= 0)
227 		device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
228 
229 	*temp = (int)(val & 0x1FF) * 1000;
230 	if (sc->ver == 1)
231 		*temp = (int)(val & 0xFF) * 1000;
232 	else
233 		*temp = (int)(val & 0x1FF) * 1000 - 273100;
234 
235 	return (0);
236 }
237 
238 static int
qoriq_therm_get_temp(device_t dev,device_t cdev,uintptr_t id,int * val)239 qoriq_therm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
240 {
241 	struct qoriq_therm_softc *sc;
242 
243 	sc = device_get_softc(dev);
244 	if (id >= sc->ntsensors)
245 		return (ERANGE);
246 	return(qoriq_therm_read_temp(sc, sc->tsensors + id, val));
247 }
248 
249 static int
qoriq_therm_sysctl_temperature(SYSCTL_HANDLER_ARGS)250 qoriq_therm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
251 {
252 	struct qoriq_therm_softc *sc;
253 	int val;
254 	int rv;
255 	int id;
256 
257 	/* Write request */
258 	if (req->newptr != NULL)
259 		return (EINVAL);
260 
261 	sc = arg1;
262 	id = arg2;
263 
264 	if (id >= sc->ntsensors)
265 		return (ERANGE);
266 	rv =  qoriq_therm_read_temp(sc, sc->tsensors + id, &val);
267 	if (rv != 0)
268 		return (rv);
269 
270 	val = val / 100;
271 	val +=  2731;
272 	rv = sysctl_handle_int(oidp, &val, 0, req);
273 	return (rv);
274 }
275 
276 static int
qoriq_therm_init_sysctl(struct qoriq_therm_softc * sc)277 qoriq_therm_init_sysctl(struct qoriq_therm_softc *sc)
278 {
279 	int i;
280 	struct sysctl_oid *oid, *tmp;
281 
282 	/* create node for hw.temp */
283 	oid = SYSCTL_ADD_NODE(&qoriq_therm_sysctl_ctx,
284 	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
285 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
286 	if (oid == NULL)
287 		return (ENXIO);
288 
289 	/* add sensors */
290 	for (i = sc->ntsensors  - 1; i >= 0; i--) {
291 		tmp = SYSCTL_ADD_PROC(&qoriq_therm_sysctl_ctx,
292 		    SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
293 		    CTLTYPE_INT | CTLFLAG_RD , sc, i,
294 		    qoriq_therm_sysctl_temperature, "IK", "SoC Temperature");
295 		if (tmp == NULL)
296 			return (ENXIO);
297 	}
298 	return (0);
299 }
300 
301 static int
qoriq_therm_fdt_calib(struct qoriq_therm_softc * sc,phandle_t node)302 qoriq_therm_fdt_calib(struct qoriq_therm_softc *sc, phandle_t node)
303 {
304 	int 	nranges, ncalibs, i;
305 	int	*ranges, *calibs;
306 
307 	/* initialize temperature range control registes */
308 	nranges = OF_getencprop_alloc_multi(node, "fsl,tmu-range",
309 	    sizeof(*ranges), (void **)&ranges);
310 	if (nranges < 2 || nranges > 4) {
311 		device_printf(sc->dev, "Invalid 'tmu-range' property\n");
312 		return (ERANGE);
313 	}
314 	for (i = 0; i < nranges; i++) {
315 		WR4(sc, TMU_TTRCR(i), ranges[i]);
316 	}
317 
318 	/* initialize calibration data for above ranges */
319 	ncalibs = OF_getencprop_alloc_multi(node, "fsl,tmu-calibration",
320 	    sizeof(*calibs),(void **)&calibs);
321 	if (ncalibs <= 0 || (ncalibs % 2) != 0) {
322 		device_printf(sc->dev, "Invalid 'tmu-calibration' property\n");
323 		return (ERANGE);
324 	}
325 	for (i = 0; i < ncalibs; i +=2) {
326 		WR4(sc, TMU_TTCFGR, calibs[i]);
327 		WR4(sc, TMU_TSCFGR, calibs[i + 1]);
328 	}
329 
330 	return (0);
331 }
332 
333 static int
qoriq_therm_probe(device_t dev)334 qoriq_therm_probe(device_t dev)
335 {
336 
337 	if (!ofw_bus_status_okay(dev))
338 		return (ENXIO);
339 
340 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
341 		return (ENXIO);
342 
343 	device_set_desc(dev, "QorIQ temperature sensors");
344 	return (BUS_PROBE_DEFAULT);
345 }
346 
347 static int
qoriq_therm_attach(device_t dev)348 qoriq_therm_attach(device_t dev)
349 {
350 	struct qoriq_therm_softc *sc;
351 	struct qoriq_therm_socs *soc;
352 	phandle_t node, root;
353 	uint32_t sites;
354 	int rid, rv;
355 
356 	sc = device_get_softc(dev);
357 	sc->dev = dev;
358 	node = ofw_bus_get_node(sc->dev);
359 	sc->little_endian = OF_hasprop(node, "little-endian");
360 
361 	sysctl_ctx_init(&qoriq_therm_sysctl_ctx);
362 
363 	rid = 0;
364 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
365 	    RF_ACTIVE);
366 	if (sc->mem_res == NULL) {
367 		device_printf(dev, "Cannot allocate memory resources\n");
368 		goto fail;
369 	}
370 
371 	rid = 0;
372 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
373 	if (sc->irq_res == NULL) {
374 		device_printf(dev, "Cannot allocate IRQ resources\n");
375 		goto fail;
376 	}
377 
378 /*
379 	if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
380 	    qoriq_therm_intr, NULL, sc, &sc->irq_ih))) {
381 		device_printf(dev,
382 		    "WARNING: unable to register interrupt handler\n");
383 		goto fail;
384 	}
385 */
386 	rv = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
387 	if (rv != 0 && rv != ENOENT) {
388 		device_printf(dev, "Cannot get clock: %d %d\n", rv, ENOENT);
389 		goto fail;
390 	}
391 	if (sc->clk != NULL) {
392 		rv = clk_enable(sc->clk);
393 		if (rv != 0) {
394 			device_printf(dev, "Cannot enable clock: %d\n", rv);
395 			goto fail;
396 		}
397 	}
398 
399 	sc->ver = (RD4(sc, TMU_VERSION) >> 8) & 0xFF;
400 
401 	/* Select per SoC configuration. */
402 	root = OF_finddevice("/");
403 	if (root < 0) {
404 		device_printf(dev, "Cannot get root node: %d\n", root);
405 		goto fail;
406 	}
407 	soc = qoriq_therm_socs;
408 	while (soc != NULL && soc->name != NULL) {
409 		if (ofw_bus_node_is_compatible(root, soc->name))
410 			break;
411 		soc++;
412 	}
413 	if (soc == NULL) {
414 		device_printf(dev, "Unsupported SoC, using default sites.\n");
415 		sc->tsensors = default_sensors;
416 		sc->ntsensors = nitems(default_sensors);
417 	} else {
418 		sc->tsensors = soc->tsensors;
419 		sc->ntsensors = soc->ntsensors;
420 	}
421 
422 	/* stop monitoring */
423 	WR4(sc, TMU_TMR, 0);
424 	RD4(sc, TMU_TMR);
425 
426 	/* disable all interrupts */
427 	WR4(sc, TMU_TIER, 0);
428 
429 	/* setup measurement interval */
430 	if (sc->ver == 1) {
431 		WR4(sc, TMUV1_TMTMIR, 0x0F);
432 	} else {
433 		WR4(sc, TMUV2_TMTMIR, 0x0F);	/* disable */
434 		/* these registers are not of settings is not in TRM */
435 		WR4(sc, TMUV2_TEUMR(0), 0x51009c00);
436 		for (int i = 0; i < sc->ntsensors; i++)
437 			WR4(sc, TMUV2_TMSAR(sc->tsensors[i].site_id), 0xE);
438 	}
439 
440 	/* prepare calibration tables */
441 	rv = qoriq_therm_fdt_calib(sc, node);
442 	if (rv != 0) {
443 		device_printf(sc->dev,
444 		    "Cannot initialize calibration tables\n");
445 		goto fail;
446 	}
447 	/* start monitoring */
448 	sites = 0;
449 	if (sc->ver == 1) {
450 		for (int i = 0; i < sc->ntsensors; i++)
451 			sites |= 1 << (15 - sc->tsensors[i].site_id);
452 		WR4(sc, TMU_TMR, 0x8C000000 | sites);
453 	} else {
454 		for (int i = 0; i < sc->ntsensors; i++)
455 			sites |= 1 << sc->tsensors[i].site_id;
456 		WR4(sc, TMUV2_TMSR, sites);
457 		WR4(sc, TMU_TMR, 0x83000000);
458 	}
459 
460 	rv = qoriq_therm_init_sysctl(sc);
461 	if (rv != 0) {
462 		device_printf(sc->dev, "Cannot initialize sysctls\n");
463 		goto fail;
464 	}
465 
466 	OF_device_register_xref(OF_xref_from_node(node), dev);
467 	return (bus_generic_attach(dev));
468 
469 fail:
470 	if (sc->irq_ih != NULL)
471 		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
472 	sysctl_ctx_free(&qoriq_therm_sysctl_ctx);
473 	if (sc->clk != NULL)
474 		clk_release(sc->clk);
475 	if (sc->irq_res != NULL)
476 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
477 	if (sc->mem_res != NULL)
478 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
479 
480 	return (ENXIO);
481 }
482 
483 static int
qoriq_therm_detach(device_t dev)484 qoriq_therm_detach(device_t dev)
485 {
486 	struct qoriq_therm_softc *sc;
487 	sc = device_get_softc(dev);
488 
489 	if (sc->irq_ih != NULL)
490 		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
491 	sysctl_ctx_free(&qoriq_therm_sysctl_ctx);
492 	if (sc->clk != NULL)
493 		clk_release(sc->clk);
494 	if (sc->irq_res != NULL)
495 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
496 	if (sc->mem_res != NULL)
497 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
498 
499 	return (0);
500 }
501 
502 static device_method_t qoriq_qoriq_therm_methods[] = {
503 	/* Device interface */
504 	DEVMETHOD(device_probe,			qoriq_therm_probe),
505 	DEVMETHOD(device_attach,		qoriq_therm_attach),
506 	DEVMETHOD(device_detach,		qoriq_therm_detach),
507 
508 	/* SOCTHERM interface */
509 	DEVMETHOD(qoriq_therm_get_temperature,	qoriq_therm_get_temp),
510 
511 	DEVMETHOD_END
512 };
513 
514 static DEFINE_CLASS_0(soctherm, qoriq_qoriq_therm_driver, qoriq_qoriq_therm_methods,
515     sizeof(struct qoriq_therm_softc));
516 DRIVER_MODULE(qoriq_soctherm, simplebus, qoriq_qoriq_therm_driver, NULL, NULL);
517