xref: /arm-trusted-firmware/plat/marvell/armada/a8k/common/plat_thermal.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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