aboutsummaryrefslogtreecommitdiff
path: root/plat/marvell/a8k/common/plat_thermal.c
blob: 02fe82097d453effab0aeccc905a5542494035b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright (C) 2018 Marvell International Ltd.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 * https://spdx.org/licenses
 */

#include <debug.h>
#include <delay_timer.h>
#include <mmio.h>
#include <mvebu_def.h>
#include <thermal.h>

#define THERMAL_TIMEOUT					1200

#define THERMAL_SEN_CTRL_LSB_STRT_OFFSET		0
#define THERMAL_SEN_CTRL_LSB_STRT_MASK			\
				(0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET)
#define THERMAL_SEN_CTRL_LSB_RST_OFFSET			1
#define THERMAL_SEN_CTRL_LSB_RST_MASK			\
				(0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET)
#define THERMAL_SEN_CTRL_LSB_EN_OFFSET			2
#define THERMAL_SEN_CTRL_LSB_EN_MASK			\
				(0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET)

#define THERMAL_SEN_CTRL_STATS_VALID_OFFSET		16
#define THERMAL_SEN_CTRL_STATS_VALID_MASK		\
				(0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET)
#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET		0
#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK		\
			(0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET)

#define THERMAL_SEN_OUTPUT_MSB				512
#define THERMAL_SEN_OUTPUT_COMP				1024

struct tsen_regs {
	uint32_t ext_tsen_ctrl_lsb;
	uint32_t ext_tsen_ctrl_msb;
	uint32_t ext_tsen_status;
};

static int ext_tsen_probe(struct tsen_config *tsen_cfg)
{
	uint32_t reg, timeout = 0;
	struct tsen_regs *base;

	if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) {
		ERROR("initial thermal sensor configuration is missing\n");
		return -1;
	}
	base = (struct tsen_regs *)tsen_cfg->regs_base;

	INFO("initializing thermal sensor\n");

	/* initialize thermal sensor hardware reset once */
	reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb);
	reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */
	reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */
	reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */
	mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg);

	reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
	while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 &&
	       timeout < THERMAL_TIMEOUT) {
		udelay(100);
		reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
		timeout++;
	}

	if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) {
		ERROR("thermal sensor is not ready\n");
		return -1;
	}

	tsen_cfg->tsen_ready = 1;

	VERBOSE("thermal sensor was initialized\n");

	return 0;
}

static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp)
{
	uint32_t reg;
	struct tsen_regs *base;

	if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) {
		ERROR("thermal sensor was not initialized\n");
		return -1;
	}
	base = (struct tsen_regs *)tsen_cfg->regs_base;

	reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
	reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >>
		THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET);

	/*
	 * TSEN output format is signed as a 2s complement number
	 * ranging from-512 to +511. when MSB is set, need to
	 * calculate the complement number
	 */
	if (reg >= THERMAL_SEN_OUTPUT_MSB)
		reg -= THERMAL_SEN_OUTPUT_COMP;

	if (tsen_cfg->tsen_divisor == 0) {
		ERROR("thermal sensor divisor cannot be zero\n");
		return -1;
	}

	*temp = ((tsen_cfg->tsen_gain * ((int)reg)) +
		 tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor;

	return 0;
}

static struct tsen_config tsen_cfg = {
	.tsen_offset = 153400,
	.tsen_gain = 425,
	.tsen_divisor = 1000,
	.tsen_ready = 0,
	.regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE,
	.ptr_tsen_probe = ext_tsen_probe,
	.ptr_tsen_read = ext_tsen_read
};

struct tsen_config *marvell_thermal_config_get(void)
{
	return &tsen_cfg;
}