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