xref: /rk3399_ARM-atf/plat/marvell/armada/a8k/common/plat_thermal.c (revision 9935047b2086faa3bf3ccf0b95a76510eb5a160b)
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 
ext_tsen_probe(struct tsen_config * tsen_cfg)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 
ext_tsen_read(struct tsen_config * tsen_cfg,int * temp)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 
marvell_thermal_config_get(void)127*a2847172SGrzegorz Jaszczyk struct tsen_config *marvell_thermal_config_get(void)
128*a2847172SGrzegorz Jaszczyk {
129*a2847172SGrzegorz Jaszczyk 	return &tsen_cfg;
130*a2847172SGrzegorz Jaszczyk }
131