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