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