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