aboutsummaryrefslogtreecommitdiff
path: root/plat/marvell/a8k/common/plat_thermal.c
blob: a2fc0d0ab57ef728db0ac2b03629f9abb56d4753 (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
130
/*
 * Copyright (C) 2018 Marvell International Ltd.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 * https://spdx.org/licenses
 */

#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/marvell/thermal.h>
#include <lib/mmio.h>

#include <mvebu_def.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;
}