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