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