Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/qoriq/qoriq_therm.c
39478 views
1
/*-
2
*
3
* SPDX-License-Identifier: BSD-2-Clause
4
*
5
* Copyright 2020 Michal Meloun <[email protected]>
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
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
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
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
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
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
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
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
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
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
bus_attach_children(dev);
468
return (0);
469
470
fail:
471
if (sc->irq_ih != NULL)
472
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
473
sysctl_ctx_free(&qoriq_therm_sysctl_ctx);
474
if (sc->clk != NULL)
475
clk_release(sc->clk);
476
if (sc->irq_res != NULL)
477
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
478
if (sc->mem_res != NULL)
479
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
480
481
return (ENXIO);
482
}
483
484
static int
485
qoriq_therm_detach(device_t dev)
486
{
487
struct qoriq_therm_softc *sc;
488
sc = device_get_softc(dev);
489
490
if (sc->irq_ih != NULL)
491
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
492
sysctl_ctx_free(&qoriq_therm_sysctl_ctx);
493
if (sc->clk != NULL)
494
clk_release(sc->clk);
495
if (sc->irq_res != NULL)
496
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
497
if (sc->mem_res != NULL)
498
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
499
500
return (0);
501
}
502
503
static device_method_t qoriq_qoriq_therm_methods[] = {
504
/* Device interface */
505
DEVMETHOD(device_probe, qoriq_therm_probe),
506
DEVMETHOD(device_attach, qoriq_therm_attach),
507
DEVMETHOD(device_detach, qoriq_therm_detach),
508
509
/* SOCTHERM interface */
510
DEVMETHOD(qoriq_therm_get_temperature, qoriq_therm_get_temp),
511
512
DEVMETHOD_END
513
};
514
515
static DEFINE_CLASS_0(soctherm, qoriq_qoriq_therm_driver, qoriq_qoriq_therm_methods,
516
sizeof(struct qoriq_therm_softc));
517
DRIVER_MODULE(qoriq_soctherm, simplebus, qoriq_qoriq_therm_driver, NULL, NULL);
518
519