131 lines
3.4 KiB
C
131 lines
3.4 KiB
C
/*
|
|
* Copyright (C) 2018 Marvell International Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
* https://spdx.org/licenses
|
|
*/
|
|
|
|
#include <common/debug.h>
|
|
#include <drivers/delay_timer.h>
|
|
#include <drivers/marvell/thermal.h>
|
|
#include <lib/mmio.h>
|
|
|
|
#include <mvebu_def.h>
|
|
|
|
#define THERMAL_TIMEOUT 1200
|
|
|
|
#define THERMAL_SEN_CTRL_LSB_STRT_OFFSET 0
|
|
#define THERMAL_SEN_CTRL_LSB_STRT_MASK \
|
|
(0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET)
|
|
#define THERMAL_SEN_CTRL_LSB_RST_OFFSET 1
|
|
#define THERMAL_SEN_CTRL_LSB_RST_MASK \
|
|
(0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET)
|
|
#define THERMAL_SEN_CTRL_LSB_EN_OFFSET 2
|
|
#define THERMAL_SEN_CTRL_LSB_EN_MASK \
|
|
(0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET)
|
|
|
|
#define THERMAL_SEN_CTRL_STATS_VALID_OFFSET 16
|
|
#define THERMAL_SEN_CTRL_STATS_VALID_MASK \
|
|
(0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET)
|
|
#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET 0
|
|
#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK \
|
|
(0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET)
|
|
|
|
#define THERMAL_SEN_OUTPUT_MSB 512
|
|
#define THERMAL_SEN_OUTPUT_COMP 1024
|
|
|
|
struct tsen_regs {
|
|
uint32_t ext_tsen_ctrl_lsb;
|
|
uint32_t ext_tsen_ctrl_msb;
|
|
uint32_t ext_tsen_status;
|
|
};
|
|
|
|
static int ext_tsen_probe(struct tsen_config *tsen_cfg)
|
|
{
|
|
uint32_t reg, timeout = 0;
|
|
struct tsen_regs *base;
|
|
|
|
if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) {
|
|
ERROR("initial thermal sensor configuration is missing\n");
|
|
return -1;
|
|
}
|
|
base = (struct tsen_regs *)tsen_cfg->regs_base;
|
|
|
|
INFO("initializing thermal sensor\n");
|
|
|
|
/* initialize thermal sensor hardware reset once */
|
|
reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb);
|
|
reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */
|
|
reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */
|
|
reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */
|
|
mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg);
|
|
|
|
reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
|
|
while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 &&
|
|
timeout < THERMAL_TIMEOUT) {
|
|
udelay(100);
|
|
reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
|
|
timeout++;
|
|
}
|
|
|
|
if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) {
|
|
ERROR("thermal sensor is not ready\n");
|
|
return -1;
|
|
}
|
|
|
|
tsen_cfg->tsen_ready = 1;
|
|
|
|
VERBOSE("thermal sensor was initialized\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp)
|
|
{
|
|
uint32_t reg;
|
|
struct tsen_regs *base;
|
|
|
|
if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) {
|
|
ERROR("thermal sensor was not initialized\n");
|
|
return -1;
|
|
}
|
|
base = (struct tsen_regs *)tsen_cfg->regs_base;
|
|
|
|
reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
|
|
reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >>
|
|
THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET);
|
|
|
|
/*
|
|
* TSEN output format is signed as a 2s complement number
|
|
* ranging from-512 to +511. when MSB is set, need to
|
|
* calculate the complement number
|
|
*/
|
|
if (reg >= THERMAL_SEN_OUTPUT_MSB)
|
|
reg -= THERMAL_SEN_OUTPUT_COMP;
|
|
|
|
if (tsen_cfg->tsen_divisor == 0) {
|
|
ERROR("thermal sensor divisor cannot be zero\n");
|
|
return -1;
|
|
}
|
|
|
|
*temp = ((tsen_cfg->tsen_gain * ((int)reg)) +
|
|
tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct tsen_config tsen_cfg = {
|
|
.tsen_offset = 153400,
|
|
.tsen_gain = 425,
|
|
.tsen_divisor = 1000,
|
|
.tsen_ready = 0,
|
|
.regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE,
|
|
.ptr_tsen_probe = ext_tsen_probe,
|
|
.ptr_tsen_read = ext_tsen_read
|
|
};
|
|
|
|
struct tsen_config *marvell_thermal_config_get(void)
|
|
{
|
|
return &tsen_cfg;
|
|
}
|