]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/nvidia/tegra_soctherm.c
Copy libevent sources to contrib
[FreeBSD/FreeBSD.git] / sys / arm / nvidia / tegra_soctherm.c
1 /*-
2  * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31  * Thermometer and thermal zones driver for Tegra SoCs.
32  * Calibration data and algo are taken from Linux, because this part of SoC
33  * is undocumented in TRM.
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/gpio.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/malloc.h>
43 #include <sys/rman.h>
44 #include <sys/sysctl.h>
45
46 #include <machine/bus.h>
47
48 #include <dev/extres/clk/clk.h>
49 #include <dev/extres/hwreset/hwreset.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52
53 #include <arm/nvidia/tegra_efuse.h>
54 #include <gnu/dts/include/dt-bindings/thermal/tegra124-soctherm.h>
55 #include "tegra_soctherm_if.h"
56
57 /* Per sensors registers - base is 0x0c0*/
58 #define TSENSOR_CONFIG0                         0x000
59 #define  TSENSOR_CONFIG0_TALL(x)                        (((x) & 0xFFFFF) << 8)
60 #define  TSENSOR_CONFIG0_STATUS_CLR                     (1 << 5)
61 #define  TSENSOR_CONFIG0_TCALC_OVERFLOW                 (1 << 4)
62 #define  TSENSOR_CONFIG0_OVERFLOW                       (1 << 3)
63 #define  TSENSOR_CONFIG0_CPTR_OVERFLOW                  (1 << 2)
64 #define  TSENSOR_CONFIG0_RO_SEL                         (1 << 1)
65 #define  TSENSOR_CONFIG0_STOP                           (1 << 0)
66
67 #define TSENSOR_CONFIG1                         0x004
68 #define  TSENSOR_CONFIG1_TEMP_ENABLE                    (1U << 31)
69 #define  TSENSOR_CONFIG1_TEN_COUNT(x)                   (((x) & 0x3F) << 24)
70 #define  TSENSOR_CONFIG1_TIDDQ_EN(x)                    (((x) & 0x3F) << 15)
71 #define  TSENSOR_CONFIG1_TSAMPLE(x)                     (((x) & 0x3FF) << 0)
72
73 #define TSENSOR_CONFIG2                         0x008
74 #define TSENSOR_CONFIG2_THERMA(x)                       (((x) & 0xFFFF) << 16)
75 #define TSENSOR_CONFIG2_THERMB(x)                       (((x) & 0xFFFF) << 0)
76
77 #define TSENSOR_STATUS0                         0x00c
78 #define  TSENSOR_STATUS0_CAPTURE_VALID                  (1U << 31)
79 #define  TSENSOR_STATUS0_CAPTURE(x)                     (((x) >> 0) & 0xffff)
80
81 #define TSENSOR_STATUS1                         0x010
82 #define  TSENSOR_STATUS1_TEMP_VALID                     (1U << 31)
83 #define  TSENSOR_STATUS1_TEMP(x)                        (((x) >> 0) & 0xffff)
84
85 #define TSENSOR_STATUS2                         0x014
86 #define  TSENSOR_STATUS2_TEMP_MAX(x)                    (((x) >> 16) & 0xffff)
87 #define  TSENSOR_STATUS2_TEMP_MIN(x)                    (((x) >>  0) & 0xffff)
88
89 /* Global registers */
90 #define TSENSOR_PDIV                            0x1c0
91 #define  TSENSOR_PDIV_T124                              0x8888
92 #define TSENSOR_HOTSPOT_OFF                     0x1c4
93 #define  TSENSOR_HOTSPOT_OFF_T124                       0x00060600
94 #define TSENSOR_TEMP1                           0x1c8
95 #define TSENSOR_TEMP2                           0x1cc
96
97 /* Readbacks */
98 #define READBACK_VALUE_MASK                             0xff00
99 #define READBACK_VALUE_SHIFT                            8
100 #define READBACK_ADD_HALF                               (1 << 7)
101 #define READBACK_NEGATE                                 (1 << 0)
102
103
104 /* Fuses */
105 #define  FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT            0
106 #define  FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS             13
107 #define  FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT            13
108 #define  FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS             13
109
110 #define FUSE_TSENSOR8_CALIB                     0x180
111 #define  FUSE_TSENSOR8_CALIB_CP_TS_BASE(x)              (((x) >>  0) & 0x3ff)
112 #define  FUSE_TSENSOR8_CALIB_FT_TS_BASE(x)              (((x) >> 10) & 0x7ff)
113
114 #define FUSE_SPARE_REALIGNMENT_REG              0x1fc
115 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT      0
116 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS       6
117 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT      21
118 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS       5
119 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP(x)         (((x) >>  0) & 0x3f)
120 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT(x)         (((x) >> 21) & 0x1f)
121
122
123 #define NOMINAL_CALIB_FT_T124   105
124 #define NOMINAL_CALIB_CP_T124   25
125
126 #define WR4(_sc, _r, _v)        bus_write_4((_sc)->mem_res, (_r), (_v))
127 #define RD4(_sc, _r)            bus_read_4((_sc)->mem_res, (_r))
128
129 static struct sysctl_ctx_list soctherm_sysctl_ctx;
130
131 struct soctherm_shared_cal {
132         uint32_t                base_cp;
133         uint32_t                base_ft;
134         int32_t                 actual_temp_cp;
135         int32_t                 actual_temp_ft;
136 };
137 struct tsensor_cfg {
138         uint32_t                tall;
139         uint32_t                tsample;
140         uint32_t                tiddq_en;
141         uint32_t                ten_count;
142         uint32_t                pdiv;
143         uint32_t                tsample_ate;
144         uint32_t                pdiv_ate;
145 };
146
147 struct tsensor {
148         char                    *name;
149         int                     id;
150         struct tsensor_cfg      *cfg;
151         bus_addr_t              sensor_base;
152         bus_addr_t              calib_fuse;
153         int                     fuse_corr_alpha;
154         int                     fuse_corr_beta;
155
156         int16_t                 therm_a;
157         int16_t                 therm_b;
158 };
159
160 struct soctherm_softc {
161         device_t                dev;
162         struct resource         *mem_res;
163         struct resource         *irq_res;
164         void                    *irq_ih;
165
166         clk_t                   tsensor_clk;
167         clk_t                   soctherm_clk;
168         hwreset_t                       reset;
169
170         int                     ntsensors;
171         struct tsensor          *tsensors;
172 };
173
174 static struct ofw_compat_data compat_data[] = {
175         {"nvidia,tegra124-soctherm",    1},
176         {NULL,                          0},
177 };
178
179 static struct tsensor_cfg t124_tsensor_config = {
180         .tall = 16300,
181         .tsample = 120,
182         .tiddq_en = 1,
183         .ten_count = 1,
184         .pdiv = 8,
185         .tsample_ate = 480,
186         .pdiv_ate = 8
187 };
188
189
190 static struct tsensor t124_tsensors[] = {
191         {
192                 .name = "cpu0",
193                 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
194                 .cfg = &t124_tsensor_config,
195                 .sensor_base = 0x0c0,
196                 .calib_fuse = 0x098,
197                 .fuse_corr_alpha = 1135400,
198                 .fuse_corr_beta = -6266900,
199         },
200         {
201                 .name = "cpu1",
202                 .id = -1,
203                 .cfg = &t124_tsensor_config,
204                 .sensor_base = 0x0e0,
205                 .calib_fuse = 0x084,
206                 .fuse_corr_alpha = 1122220,
207                 .fuse_corr_beta = -5700700,
208         },
209         {
210                 .name = "cpu2",
211                 .id = -1,
212                 .cfg = &t124_tsensor_config,
213                 .sensor_base = 0x100,
214                 .calib_fuse = 0x088,
215                 .fuse_corr_alpha = 1127000,
216                 .fuse_corr_beta = -6768200,
217         },
218         {
219                 .name = "cpu3",
220                 .id = -1,
221                 .cfg = &t124_tsensor_config,
222                 .sensor_base = 0x120,
223                 .calib_fuse = 0x12c,
224                 .fuse_corr_alpha = 1110900,
225                 .fuse_corr_beta = -6232000,
226         },
227         {
228                 .name = "mem0",
229                 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
230                 .cfg = &t124_tsensor_config,
231                 .sensor_base = 0x140,
232                 .calib_fuse = 0x158,
233                 .fuse_corr_alpha = 1122300,
234                 .fuse_corr_beta = -5936400,
235         },
236         {
237                 .name = "mem1",
238                 .id = -1,
239                 .cfg = &t124_tsensor_config,
240                 .sensor_base = 0x160,
241                 .calib_fuse = 0x15c,
242                 .fuse_corr_alpha = 1145700,
243                 .fuse_corr_beta = -7124600,
244         },
245         {
246                 .name = "gpu",
247                 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
248                 .cfg = &t124_tsensor_config,
249                 .sensor_base = 0x180,
250                 .calib_fuse = 0x154,
251                 .fuse_corr_alpha = 1120100,
252                 .fuse_corr_beta = -6000500,
253         },
254         {
255                 .name = "pllX",
256                 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
257                 .cfg = &t124_tsensor_config,
258                 .sensor_base = 0x1a0,
259                 .calib_fuse = 0x160,
260                 .fuse_corr_alpha = 1106500,
261                 .fuse_corr_beta = -6729300,
262         },
263 };
264
265 /* Extract signed integer bitfield from register */
266 static int
267 extract_signed(uint32_t reg, int shift, int bits)
268 {
269         int32_t val;
270         uint32_t mask;
271
272         mask = (1 << bits) - 1;
273         val = ((reg >> shift) & mask) << (32 - bits);
274         val >>= 32 - bits;
275         return ((int32_t)val);
276 }
277
278 static inline int64_t div64_s64_precise(int64_t a, int64_t b)
279 {
280         int64_t r, al;
281
282         al = a << 16;
283         r = (al * 2 + 1) / (2 * b);
284         return r >> 16;
285 }
286
287 static void
288 get_shared_cal(struct soctherm_softc *sc, struct soctherm_shared_cal *cal)
289 {
290         uint32_t val;
291         int calib_cp, calib_ft;
292
293         val = tegra_fuse_read_4(FUSE_TSENSOR8_CALIB);
294         cal->base_cp = FUSE_TSENSOR8_CALIB_CP_TS_BASE(val);
295         cal->base_ft = FUSE_TSENSOR8_CALIB_FT_TS_BASE(val);
296
297         val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
298         calib_ft = extract_signed(val,
299             FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT,
300             FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS);
301         calib_cp = extract_signed(val,
302             FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
303             FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
304
305         cal->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + calib_cp;
306         cal->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + calib_ft;
307 #ifdef DEBUG
308         printf("%s: base_cp: %u, base_ft: %d,"
309             " actual_temp_cp: %d, actual_temp_ft: %d\n",
310             __func__, cal->base_cp, cal->base_ft,
311             cal->actual_temp_cp, cal->actual_temp_ft);
312 #endif
313 }
314
315
316 static void
317 tsensor_calibration(struct tsensor *sensor, struct soctherm_shared_cal *shared)
318 {
319         uint32_t val;
320         int mult, div, calib_cp, calib_ft;
321         int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
322         int temp_a, temp_b;
323         int64_t tmp;
324
325         val =  tegra_fuse_read_4(sensor->calib_fuse);
326         calib_cp = extract_signed(val,
327             FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
328             FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
329         actual_tsensor_cp = shared->base_cp * 64 + calib_cp;
330
331         calib_ft = extract_signed(val,
332             FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
333             FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
334         actual_tsensor_ft = shared->base_ft * 32 + calib_ft;
335
336         delta_sens = actual_tsensor_ft - actual_tsensor_cp;
337         delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
338         mult = sensor->cfg->pdiv * sensor->cfg->tsample_ate;
339         div = sensor->cfg->tsample * sensor->cfg->pdiv_ate;
340
341
342         temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
343                                    (int64_t) delta_sens * div);
344
345         tmp = (int64_t)actual_tsensor_ft * shared->actual_temp_cp -
346               (int64_t)actual_tsensor_cp * shared->actual_temp_ft;
347         temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
348
349         temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
350                                    1000000);
351         temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
352                                    sensor->fuse_corr_beta, 1000000);
353         sensor->therm_a = (int16_t)temp_a;
354         sensor->therm_b = (int16_t)temp_b;
355 #ifdef DEBUG
356         printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
357             " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
358             __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
359             calib_cp, calib_cp, calib_ft, calib_ft);
360         printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
361             (uint16_t)sensor->therm_a, temp_a,
362             (uint16_t)sensor->therm_b, sensor->therm_b);
363 #endif
364 }
365
366 static void
367 soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor,
368     struct soctherm_shared_cal *shared_cal)
369 {
370         uint32_t val;
371
372         tsensor_calibration(sensor, shared_cal);
373
374         val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
375         val |= TSENSOR_CONFIG0_STOP;
376         val |= TSENSOR_CONFIG0_STATUS_CLR;
377         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
378
379         val = TSENSOR_CONFIG0_TALL(sensor->cfg->tall);
380         val |= TSENSOR_CONFIG0_STOP;
381         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
382
383         val = TSENSOR_CONFIG1_TSAMPLE(sensor->cfg->tsample - 1);
384         val |= TSENSOR_CONFIG1_TIDDQ_EN(sensor->cfg->tiddq_en);
385         val |= TSENSOR_CONFIG1_TEN_COUNT(sensor->cfg->ten_count);
386         val |= TSENSOR_CONFIG1_TEMP_ENABLE;
387         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
388
389         val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
390              TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
391         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
392
393         val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
394         val &= ~TSENSOR_CONFIG0_STOP;
395         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
396 #ifdef DEBUG
397         printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
398             " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
399             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
400             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
401             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
402             RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
403             RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
404             RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
405             );
406 #endif
407 }
408
409 static int
410 soctherm_convert_raw(uint32_t val)
411 {
412         int32_t t;
413
414         t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
415         if (val & READBACK_ADD_HALF)
416                 t += 500;
417         if (val & READBACK_NEGATE)
418                 t *= -1;
419
420         return t;
421 }
422
423 static int
424 soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
425 {
426         int timeout;
427         uint32_t val;
428
429
430         /* wait for valid sample */
431         for (timeout = 1000; timeout > 0; timeout--) {
432                 val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
433                 if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
434                         break;
435                 DELAY(100);
436         }
437         if (timeout <= 0)
438                 device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
439         *temp = soctherm_convert_raw(val);
440 #ifdef DEBUG
441         printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
442         printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
443             " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
444             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
445             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
446             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
447             RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
448             RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
449             RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
450             );
451 #endif
452         return 0;
453 }
454
455 static int
456 soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
457 {
458         struct soctherm_softc *sc;
459         int i;
460
461         sc = device_get_softc(dev);
462         /* The direct sensor map starts at 0x100 */
463         if (id >= 0x100) {
464                 id -= 0x100;
465                 if (id >= sc->ntsensors)
466                         return (ERANGE);
467                 return(soctherm_read_temp(sc, sc->tsensors + id, val));
468         }
469         /* Linux (DT) compatible thermal zones */
470         for (i = 0; i < sc->ntsensors; i++) {
471                 if (sc->tsensors->id == id)
472                         return(soctherm_read_temp(sc, sc->tsensors + id, val));
473         }
474         return (ERANGE);
475 }
476
477 static int
478 soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
479 {
480         struct soctherm_softc *sc;
481         int val;
482         int rv;
483         int id;
484
485         /* Write request */
486         if (req->newptr != NULL)
487                 return (EINVAL);
488
489         sc = arg1;
490         id = arg2;
491
492         if (id >= sc->ntsensors)
493                 return (ERANGE);
494         rv =  soctherm_read_temp(sc, sc->tsensors + id, &val);
495         if (rv != 0)
496                 return (rv);
497
498         val = val / 100;
499         val +=  2731;
500         rv = sysctl_handle_int(oidp, &val, 0, req);
501         return (rv);
502 }
503
504 static int
505 soctherm_init_sysctl(struct soctherm_softc *sc)
506 {
507         int i;
508         struct sysctl_oid *oid, *tmp;
509
510         sysctl_ctx_init(&soctherm_sysctl_ctx);
511         /* create node for hw.temp */
512         oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
513             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
514             CTLFLAG_RD, NULL, "");
515         if (oid == NULL)
516                 return (ENXIO);
517
518         /* Add sensors */
519         for (i = sc->ntsensors  - 1; i >= 0; i--) {
520                 tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
521                     SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
522                     CTLTYPE_INT | CTLFLAG_RD, sc, i,
523                     soctherm_sysctl_temperature, "IK", "SoC Temperature");
524                 if (tmp == NULL)
525                         return (ENXIO);
526         }
527
528         return (0);
529 }
530
531 static int
532 soctherm_probe(device_t dev)
533 {
534
535         if (!ofw_bus_status_okay(dev))
536                 return (ENXIO);
537
538         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
539                 return (ENXIO);
540
541         device_set_desc(dev, "Tegra temperature sensors");
542         return (BUS_PROBE_DEFAULT);
543 }
544
545 static int
546 soctherm_attach(device_t dev)
547 {
548         struct soctherm_softc *sc;
549         phandle_t node;
550         int i, rid, rv;
551         struct soctherm_shared_cal shared_calib;
552
553         sc = device_get_softc(dev);
554         sc->dev = dev;
555         node = ofw_bus_get_node(sc->dev);
556
557         rid = 0;
558         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
559             RF_ACTIVE);
560         if (sc->mem_res == NULL) {
561                 device_printf(dev, "Cannot allocate memory resources\n");
562                 goto fail;
563         }
564
565         rid = 0;
566         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
567         if (sc->irq_res == NULL) {
568                 device_printf(dev, "Cannot allocate IRQ resources\n");
569                 goto fail;
570         }
571
572 /*
573         if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
574             soctherm_intr, NULL, sc, &sc->irq_ih))) {
575                 device_printf(dev,
576                     "WARNING: unable to register interrupt handler\n");
577                 goto fail;
578         }
579 */
580
581         /* OWF resources */
582         rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
583         if (rv != 0) {
584                 device_printf(dev, "Cannot get fuse reset\n");
585                 goto fail;
586         }
587         rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
588         if (rv != 0) {
589                 device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
590                 goto fail;
591         }
592         rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
593         if (rv != 0) {
594                 device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
595                 goto fail;
596         }
597
598         rv = hwreset_assert(sc->reset);
599         if (rv != 0) {
600                 device_printf(dev, "Cannot assert reset\n");
601                 goto fail;
602         }
603         rv = clk_enable(sc->tsensor_clk);
604         if (rv != 0) {
605                 device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
606                 goto fail;
607         }
608         rv = clk_enable(sc->soctherm_clk);
609         if (rv != 0) {
610                 device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
611                 goto fail;
612         }
613         rv = hwreset_deassert(sc->reset);
614         if (rv != 0) {
615                 device_printf(dev, "Cannot clear reset\n");
616                 goto fail;
617         }
618
619         /* Tegra 124 */
620         sc->tsensors = t124_tsensors;
621         sc->ntsensors = nitems(t124_tsensors);
622         get_shared_cal(sc, &shared_calib);
623
624         WR4(sc, TSENSOR_PDIV, TSENSOR_PDIV_T124);
625         WR4(sc, TSENSOR_HOTSPOT_OFF, TSENSOR_HOTSPOT_OFF_T124);
626
627         for (i = 0; i < sc->ntsensors; i++)
628                 soctherm_init_tsensor(sc, sc->tsensors + i, &shared_calib);
629
630         rv = soctherm_init_sysctl(sc);
631         if (rv != 0) {
632                 device_printf(sc->dev, "Cannot initialize sysctls\n");
633                 goto fail;
634         }
635
636         OF_device_register_xref(OF_xref_from_node(node), dev);
637         return (bus_generic_attach(dev));
638
639 fail:
640         if (sc->irq_ih != NULL)
641                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
642         sysctl_ctx_free(&soctherm_sysctl_ctx);
643         if (sc->tsensor_clk != NULL)
644                 clk_release(sc->tsensor_clk);
645         if (sc->soctherm_clk != NULL)
646                 clk_release(sc->soctherm_clk);
647         if (sc->reset != NULL)
648                 hwreset_release(sc->reset);
649         if (sc->irq_res != NULL)
650                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
651         if (sc->mem_res != NULL)
652                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
653
654         return (ENXIO);
655 }
656
657 static int
658 soctherm_detach(device_t dev)
659 {
660         struct soctherm_softc *sc;
661         sc = device_get_softc(dev);
662
663         if (sc->irq_ih != NULL)
664                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
665         sysctl_ctx_free(&soctherm_sysctl_ctx);
666         if (sc->tsensor_clk != NULL)
667                 clk_release(sc->tsensor_clk);
668         if (sc->soctherm_clk != NULL)
669                 clk_release(sc->soctherm_clk);
670         if (sc->reset != NULL)
671                 hwreset_release(sc->reset);
672         if (sc->irq_res != NULL)
673                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
674         if (sc->mem_res != NULL)
675                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
676
677         return (ENXIO);
678 }
679
680 static device_method_t tegra_soctherm_methods[] = {
681         /* Device interface */
682         DEVMETHOD(device_probe,                 soctherm_probe),
683         DEVMETHOD(device_attach,                soctherm_attach),
684         DEVMETHOD(device_detach,                soctherm_detach),
685
686         /* SOCTHERM interface */
687         DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
688
689         DEVMETHOD_END
690 };
691
692 static devclass_t tegra_soctherm_devclass;
693 static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
694     sizeof(struct soctherm_softc));
695 EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
696     tegra_soctherm_devclass, NULL, NULL, 79);