1*a2847172SGrzegorz Jaszczyk /* 2*a2847172SGrzegorz Jaszczyk * Copyright (C) 2018 Marvell International Ltd. 3*a2847172SGrzegorz Jaszczyk * 4*a2847172SGrzegorz Jaszczyk * SPDX-License-Identifier: BSD-3-Clause 5*a2847172SGrzegorz Jaszczyk * https://spdx.org/licenses 6*a2847172SGrzegorz Jaszczyk */ 7*a2847172SGrzegorz Jaszczyk 8*a2847172SGrzegorz Jaszczyk #include <common/debug.h> 9*a2847172SGrzegorz Jaszczyk #include <drivers/delay_timer.h> 10*a2847172SGrzegorz Jaszczyk #include <drivers/marvell/thermal.h> 11*a2847172SGrzegorz Jaszczyk #include <lib/mmio.h> 12*a2847172SGrzegorz Jaszczyk 13*a2847172SGrzegorz Jaszczyk #include <mvebu_def.h> 14*a2847172SGrzegorz Jaszczyk 15*a2847172SGrzegorz Jaszczyk #define THERMAL_TIMEOUT 1200 16*a2847172SGrzegorz Jaszczyk 17*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_LSB_STRT_OFFSET 0 18*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_LSB_STRT_MASK \ 19*a2847172SGrzegorz Jaszczyk (0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET) 20*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_LSB_RST_OFFSET 1 21*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_LSB_RST_MASK \ 22*a2847172SGrzegorz Jaszczyk (0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET) 23*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_LSB_EN_OFFSET 2 24*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_LSB_EN_MASK \ 25*a2847172SGrzegorz Jaszczyk (0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET) 26*a2847172SGrzegorz Jaszczyk 27*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_STATS_VALID_OFFSET 16 28*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_STATS_VALID_MASK \ 29*a2847172SGrzegorz Jaszczyk (0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET) 30*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET 0 31*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK \ 32*a2847172SGrzegorz Jaszczyk (0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET) 33*a2847172SGrzegorz Jaszczyk 34*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_OUTPUT_MSB 512 35*a2847172SGrzegorz Jaszczyk #define THERMAL_SEN_OUTPUT_COMP 1024 36*a2847172SGrzegorz Jaszczyk 37*a2847172SGrzegorz Jaszczyk struct tsen_regs { 38*a2847172SGrzegorz Jaszczyk uint32_t ext_tsen_ctrl_lsb; 39*a2847172SGrzegorz Jaszczyk uint32_t ext_tsen_ctrl_msb; 40*a2847172SGrzegorz Jaszczyk uint32_t ext_tsen_status; 41*a2847172SGrzegorz Jaszczyk }; 42*a2847172SGrzegorz Jaszczyk 43*a2847172SGrzegorz Jaszczyk static int ext_tsen_probe(struct tsen_config *tsen_cfg) 44*a2847172SGrzegorz Jaszczyk { 45*a2847172SGrzegorz Jaszczyk uint32_t reg, timeout = 0; 46*a2847172SGrzegorz Jaszczyk struct tsen_regs *base; 47*a2847172SGrzegorz Jaszczyk 48*a2847172SGrzegorz Jaszczyk if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) { 49*a2847172SGrzegorz Jaszczyk ERROR("initial thermal sensor configuration is missing\n"); 50*a2847172SGrzegorz Jaszczyk return -1; 51*a2847172SGrzegorz Jaszczyk } 52*a2847172SGrzegorz Jaszczyk base = (struct tsen_regs *)tsen_cfg->regs_base; 53*a2847172SGrzegorz Jaszczyk 54*a2847172SGrzegorz Jaszczyk INFO("initializing thermal sensor\n"); 55*a2847172SGrzegorz Jaszczyk 56*a2847172SGrzegorz Jaszczyk /* initialize thermal sensor hardware reset once */ 57*a2847172SGrzegorz Jaszczyk reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb); 58*a2847172SGrzegorz Jaszczyk reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */ 59*a2847172SGrzegorz Jaszczyk reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */ 60*a2847172SGrzegorz Jaszczyk reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */ 61*a2847172SGrzegorz Jaszczyk mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg); 62*a2847172SGrzegorz Jaszczyk 63*a2847172SGrzegorz Jaszczyk reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); 64*a2847172SGrzegorz Jaszczyk while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 && 65*a2847172SGrzegorz Jaszczyk timeout < THERMAL_TIMEOUT) { 66*a2847172SGrzegorz Jaszczyk udelay(100); 67*a2847172SGrzegorz Jaszczyk reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); 68*a2847172SGrzegorz Jaszczyk timeout++; 69*a2847172SGrzegorz Jaszczyk } 70*a2847172SGrzegorz Jaszczyk 71*a2847172SGrzegorz Jaszczyk if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) { 72*a2847172SGrzegorz Jaszczyk ERROR("thermal sensor is not ready\n"); 73*a2847172SGrzegorz Jaszczyk return -1; 74*a2847172SGrzegorz Jaszczyk } 75*a2847172SGrzegorz Jaszczyk 76*a2847172SGrzegorz Jaszczyk tsen_cfg->tsen_ready = 1; 77*a2847172SGrzegorz Jaszczyk 78*a2847172SGrzegorz Jaszczyk VERBOSE("thermal sensor was initialized\n"); 79*a2847172SGrzegorz Jaszczyk 80*a2847172SGrzegorz Jaszczyk return 0; 81*a2847172SGrzegorz Jaszczyk } 82*a2847172SGrzegorz Jaszczyk 83*a2847172SGrzegorz Jaszczyk static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp) 84*a2847172SGrzegorz Jaszczyk { 85*a2847172SGrzegorz Jaszczyk uint32_t reg; 86*a2847172SGrzegorz Jaszczyk struct tsen_regs *base; 87*a2847172SGrzegorz Jaszczyk 88*a2847172SGrzegorz Jaszczyk if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) { 89*a2847172SGrzegorz Jaszczyk ERROR("thermal sensor was not initialized\n"); 90*a2847172SGrzegorz Jaszczyk return -1; 91*a2847172SGrzegorz Jaszczyk } 92*a2847172SGrzegorz Jaszczyk base = (struct tsen_regs *)tsen_cfg->regs_base; 93*a2847172SGrzegorz Jaszczyk 94*a2847172SGrzegorz Jaszczyk reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); 95*a2847172SGrzegorz Jaszczyk reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >> 96*a2847172SGrzegorz Jaszczyk THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET); 97*a2847172SGrzegorz Jaszczyk 98*a2847172SGrzegorz Jaszczyk /* 99*a2847172SGrzegorz Jaszczyk * TSEN output format is signed as a 2s complement number 100*a2847172SGrzegorz Jaszczyk * ranging from-512 to +511. when MSB is set, need to 101*a2847172SGrzegorz Jaszczyk * calculate the complement number 102*a2847172SGrzegorz Jaszczyk */ 103*a2847172SGrzegorz Jaszczyk if (reg >= THERMAL_SEN_OUTPUT_MSB) 104*a2847172SGrzegorz Jaszczyk reg -= THERMAL_SEN_OUTPUT_COMP; 105*a2847172SGrzegorz Jaszczyk 106*a2847172SGrzegorz Jaszczyk if (tsen_cfg->tsen_divisor == 0) { 107*a2847172SGrzegorz Jaszczyk ERROR("thermal sensor divisor cannot be zero\n"); 108*a2847172SGrzegorz Jaszczyk return -1; 109*a2847172SGrzegorz Jaszczyk } 110*a2847172SGrzegorz Jaszczyk 111*a2847172SGrzegorz Jaszczyk *temp = ((tsen_cfg->tsen_gain * ((int)reg)) + 112*a2847172SGrzegorz Jaszczyk tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor; 113*a2847172SGrzegorz Jaszczyk 114*a2847172SGrzegorz Jaszczyk return 0; 115*a2847172SGrzegorz Jaszczyk } 116*a2847172SGrzegorz Jaszczyk 117*a2847172SGrzegorz Jaszczyk static struct tsen_config tsen_cfg = { 118*a2847172SGrzegorz Jaszczyk .tsen_offset = 153400, 119*a2847172SGrzegorz Jaszczyk .tsen_gain = 425, 120*a2847172SGrzegorz Jaszczyk .tsen_divisor = 1000, 121*a2847172SGrzegorz Jaszczyk .tsen_ready = 0, 122*a2847172SGrzegorz Jaszczyk .regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE, 123*a2847172SGrzegorz Jaszczyk .ptr_tsen_probe = ext_tsen_probe, 124*a2847172SGrzegorz Jaszczyk .ptr_tsen_read = ext_tsen_read 125*a2847172SGrzegorz Jaszczyk }; 126*a2847172SGrzegorz Jaszczyk 127*a2847172SGrzegorz Jaszczyk struct tsen_config *marvell_thermal_config_get(void) 128*a2847172SGrzegorz Jaszczyk { 129*a2847172SGrzegorz Jaszczyk return &tsen_cfg; 130*a2847172SGrzegorz Jaszczyk } 131