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