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