aboutsummaryrefslogtreecommitdiff
path: root/sys/arm/allwinner/aw_thermal.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm/allwinner/aw_thermal.c')
-rw-r--r--sys/arm/allwinner/aw_thermal.c233
1 files changed, 168 insertions, 65 deletions
diff --git a/sys/arm/allwinner/aw_thermal.c b/sys/arm/allwinner/aw_thermal.c
index 0082da1dff6a..89bf89559bcb 100644
--- a/sys/arm/allwinner/aw_thermal.c
+++ b/sys/arm/allwinner/aw_thermal.c
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#define SENSOR1_EN (1 << 1)
#define SENSOR0_EN (1 << 0)
#define THS_INTC 0x44
+#define THS_THERMAL_PER_SHIFT 12
#define THS_INTS 0x48
#define THS2_DATA_IRQ_STS (1 << 10)
#define THS1_DATA_IRQ_STS (1 << 9)
@@ -92,33 +93,49 @@ __FBSDID("$FreeBSD$");
#define THS_DATA2 0x88
#define DATA_MASK 0xfff
-#define A83T_ADC_ACQUIRE_TIME 0x17
-#define A83T_FILTER 0x4
-#define A83T_INTC 0x1000
+#define A83T_CLK_RATE 24000000
+#define A83T_ADC_ACQUIRE_TIME 23 /* 24Mhz/(23 + 1) = 1us */
+#define A83T_THERMAL_PER 1 /* 4096 * (1 + 1) / 24Mhz = 341 us */
+#define A83T_FILTER 0x5 /* Filter enabled, avg of 4 */
#define A83T_TEMP_BASE 2719000
#define A83T_TEMP_MUL 1000
#define A83T_TEMP_DIV 14186
-#define A83T_CLK_RATE 24000000
-#define A64_ADC_ACQUIRE_TIME 0x190
-#define A64_FILTER 0x6
-#define A64_INTC 0x18000
+#define A64_CLK_RATE 4000000
+#define A64_ADC_ACQUIRE_TIME 400 /* 4Mhz/(400 + 1) = 100 us */
+#define A64_THERMAL_PER 24 /* 4096 * (24 + 1) / 4Mhz = 25.6 ms */
+#define A64_FILTER 0x6 /* Filter enabled, avg of 8 */
#define A64_TEMP_BASE 2170000
#define A64_TEMP_MUL 1000
#define A64_TEMP_DIV 8560
-#define A64_CLK_RATE 4000000
+#define H3_CLK_RATE 4000000
#define H3_ADC_ACQUIRE_TIME 0x3f
-#define H3_FILTER 0x6
-#define H3_INTC 0x191000
+#define H3_THERMAL_PER 401
+#define H3_FILTER 0x6 /* Filter enabled, avg of 8 */
#define H3_TEMP_BASE 217
#define H3_TEMP_MUL 1000
#define H3_TEMP_DIV 8253
#define H3_TEMP_MINUS 1794000
-#define H3_CLK_RATE 4000000
#define H3_INIT_ALARM 90 /* degC */
#define H3_INIT_SHUT 105 /* degC */
+#define H5_CLK_RATE 24000000
+#define H5_ADC_ACQUIRE_TIME 479 /* 24Mhz/479 = 20us */
+#define H5_THERMAL_PER 58 /* 4096 * (58 + 1) / 24Mhz = 10ms */
+#define H5_FILTER 0x6 /* Filter enabled, avg of 8 */
+#define H5_TEMP_BASE 233832448
+#define H5_TEMP_MUL 124885
+#define H5_TEMP_DIV 20
+#define H5_TEMP_BASE_CPU 271581184
+#define H5_TEMP_MUL_CPU 152253
+#define H5_TEMP_BASE_GPU 289406976
+#define H5_TEMP_MUL_GPU 166724
+#define H5_INIT_CPU_ALARM 80 /* degC */
+#define H5_INIT_CPU_SHUT 96 /* degC */
+#define H5_INIT_GPU_ALARM 84 /* degC */
+#define H5_INIT_GPU_SHUT 100 /* degC */
+
#define TEMP_C_TO_K 273
#define SENSOR_ENABLE_ALL (SENSOR0_EN|SENSOR1_EN|SENSOR2_EN)
#define SHUT_INT_ALL (SHUT_INT0_STS|SHUT_INT1_STS|SHUT_INT2_STS)
@@ -147,9 +164,9 @@ struct aw_thermal_config {
uint32_t adc_acquire_time;
int adc_cali_en;
uint32_t filter;
- uint32_t intc;
- int (*to_temp)(uint32_t);
- uint32_t (*to_reg)(int);
+ uint32_t thermal_per;
+ int (*to_temp)(uint32_t, int);
+ uint32_t (*to_reg)(int, int);
int temp_base;
int temp_mul;
int temp_div;
@@ -158,7 +175,7 @@ struct aw_thermal_config {
};
static int
-a83t_to_temp(uint32_t val)
+a83t_to_temp(uint32_t val, int sensor)
{
return ((A83T_TEMP_BASE - (val * A83T_TEMP_MUL)) / A83T_TEMP_DIV);
}
@@ -183,14 +200,14 @@ static const struct aw_thermal_config a83t_config = {
.adc_acquire_time = A83T_ADC_ACQUIRE_TIME,
.adc_cali_en = 1,
.filter = A83T_FILTER,
- .intc = A83T_INTC,
+ .thermal_per = A83T_THERMAL_PER,
.to_temp = a83t_to_temp,
.calib0_mask = 0xffffffff,
- .calib1_mask = 0xffffffff,
+ .calib1_mask = 0xffff,
};
static int
-a64_to_temp(uint32_t val)
+a64_to_temp(uint32_t val, int sensor)
{
return ((A64_TEMP_BASE - (val * A64_TEMP_MUL)) / A64_TEMP_DIV);
}
@@ -213,19 +230,22 @@ static const struct aw_thermal_config a64_config = {
},
.clk_rate = A64_CLK_RATE,
.adc_acquire_time = A64_ADC_ACQUIRE_TIME,
+ .adc_cali_en = 1,
.filter = A64_FILTER,
- .intc = A64_INTC,
+ .thermal_per = A64_THERMAL_PER,
.to_temp = a64_to_temp,
+ .calib0_mask = 0xffffffff,
+ .calib1_mask = 0xffff,
};
static int
-h3_to_temp(uint32_t val)
+h3_to_temp(uint32_t val, int sensor)
{
return (H3_TEMP_BASE - ((val * H3_TEMP_MUL) / H3_TEMP_DIV));
}
static uint32_t
-h3_to_reg(int val)
+h3_to_reg(int val, int sensor)
{
return ((H3_TEMP_MINUS - (val * H3_TEMP_DIV)) / H3_TEMP_MUL);
}
@@ -242,17 +262,93 @@ static const struct aw_thermal_config h3_config = {
},
.clk_rate = H3_CLK_RATE,
.adc_acquire_time = H3_ADC_ACQUIRE_TIME,
+ .adc_cali_en = 1,
.filter = H3_FILTER,
- .intc = H3_INTC,
+ .thermal_per = H3_THERMAL_PER,
.to_temp = h3_to_temp,
.to_reg = h3_to_reg,
- .calib0_mask = 0xfff,
+ .calib0_mask = 0xffff,
+};
+
+static int
+h5_to_temp(uint32_t val, int sensor)
+{
+ int tmp;
+
+ /* Temp is lower than 70 degrees */
+ if (val > 0x500) {
+ tmp = H5_TEMP_BASE - (val * H5_TEMP_MUL);
+ tmp >>= H5_TEMP_DIV;
+ return (tmp);
+ }
+
+ if (sensor == 0)
+ tmp = H5_TEMP_BASE_CPU - (val * H5_TEMP_MUL_CPU);
+ else if (sensor == 1)
+ tmp = H5_TEMP_BASE_GPU - (val * H5_TEMP_MUL_GPU);
+ else {
+ printf("Unknown sensor %d\n", sensor);
+ return (val);
+ }
+
+ tmp >>= H5_TEMP_DIV;
+ return (tmp);
+}
+
+static uint32_t
+h5_to_reg(int val, int sensor)
+{
+ int tmp;
+
+ if (val < 70) {
+ tmp = H5_TEMP_BASE - (val << H5_TEMP_DIV);
+ tmp /= H5_TEMP_MUL;
+ } else {
+ if (sensor == 0) {
+ tmp = H5_TEMP_BASE_CPU - (val << H5_TEMP_DIV);
+ tmp /= H5_TEMP_MUL_CPU;
+ } else if (sensor == 1) {
+ tmp = H5_TEMP_BASE_GPU - (val << H5_TEMP_DIV);
+ tmp /= H5_TEMP_MUL_GPU;
+ } else {
+ printf("Unknown sensor %d\n", sensor);
+ return (val);
+ }
+ }
+
+ return ((uint32_t)tmp);
+}
+
+static const struct aw_thermal_config h5_config = {
+ .nsensors = 2,
+ .sensors = {
+ [0] = {
+ .name = "cpu",
+ .desc = "CPU temperature",
+ .init_alarm = H5_INIT_CPU_ALARM,
+ .init_shut = H5_INIT_CPU_SHUT,
+ },
+ [1] = {
+ .name = "gpu",
+ .desc = "GPU temperature",
+ .init_alarm = H5_INIT_GPU_ALARM,
+ .init_shut = H5_INIT_GPU_SHUT,
+ },
+ },
+ .clk_rate = H5_CLK_RATE,
+ .adc_acquire_time = H5_ADC_ACQUIRE_TIME,
+ .filter = H5_FILTER,
+ .thermal_per = H5_THERMAL_PER,
+ .to_temp = h5_to_temp,
+ .to_reg = h5_to_reg,
+ .calib0_mask = 0xffffffff,
};
static struct ofw_compat_data compat_data[] = {
- { "allwinner,sun8i-a83t-ts", (uintptr_t)&a83t_config },
- { "allwinner,sun8i-h3-ts", (uintptr_t)&h3_config },
- { "allwinner,sun50i-a64-ts", (uintptr_t)&a64_config },
+ { "allwinner,sun8i-a83t-ths", (uintptr_t)&a83t_config },
+ { "allwinner,sun8i-h3-ths", (uintptr_t)&h3_config },
+ { "allwinner,sun50i-a64-ths", (uintptr_t)&a64_config },
+ { "allwinner,sun50i-h5-ths", (uintptr_t)&h5_config },
{ NULL, (uintptr_t)NULL }
};
@@ -269,6 +365,9 @@ struct aw_thermal_softc {
int min_freq;
struct cf_level levels[MAX_CF_LEVELS];
eventhandler_tag cf_pre_tag;
+
+ clk_t clk_apb;
+ clk_t clk_ths;
};
static struct resource_spec aw_thermal_spec[] = {
@@ -288,39 +387,41 @@ aw_thermal_init(struct aw_thermal_softc *sc)
int error;
node = ofw_bus_get_node(sc->dev);
- if (sc->conf->calib0_mask != 0 || sc->conf->calib1_mask != 0) {
- error = nvmem_read_cell_by_name(node, "ths_calibration",
- (void *)calib, sizeof(calib));
- /* Read calibration settings from EFUSE */
- if (error != 0) {
- device_printf(sc->dev, "Cannot read THS efuse\n");
- return (error);
- }
-
- device_printf(sc->dev, "calib0: %x\n", calib[0]);
- device_printf(sc->dev, "calib1: %x\n", calib[1]);
+ if (nvmem_get_cell_len(node, "ths-calib") > sizeof(calib)) {
+ device_printf(sc->dev, "ths-calib nvmem cell is too large\n");
+ return (ENXIO);
+ }
+ error = nvmem_read_cell_by_name(node, "ths-calib",
+ (void *)&calib, nvmem_get_cell_len(node, "ths-calib"));
+ /* Read calibration settings from EFUSE */
+ if (error != 0) {
+ device_printf(sc->dev, "Cannot read THS efuse\n");
+ return (error);
+ }
- calib[0] &= sc->conf->calib0_mask;
- calib[1] &= sc->conf->calib1_mask;
+ calib[0] &= sc->conf->calib0_mask;
+ calib[1] &= sc->conf->calib1_mask;
- /* Write calibration settings to thermal controller */
- if (calib[0] != 0)
- WR4(sc, THS_CALIB0, calib[0]);
- if (calib[1] != 0)
- WR4(sc, THS_CALIB1, calib[1]);
- }
+ /* Write calibration settings to thermal controller */
+ if (calib[0] != 0)
+ WR4(sc, THS_CALIB0, calib[0]);
+ if (calib[1] != 0)
+ WR4(sc, THS_CALIB1, calib[1]);
/* Configure ADC acquire time (CLK_IN/(N+1)) and enable sensors */
WR4(sc, THS_CTRL1, ADC_CALI_EN);
WR4(sc, THS_CTRL0, sc->conf->adc_acquire_time);
WR4(sc, THS_CTRL2, sc->conf->adc_acquire_time << SENSOR_ACQ1_SHIFT);
+ /* Set thermal period */
+ WR4(sc, THS_INTC, sc->conf->thermal_per << THS_THERMAL_PER_SHIFT);
+
/* Enable average filter */
WR4(sc, THS_FILTER, sc->conf->filter);
/* Enable interrupts */
WR4(sc, THS_INTS, RD4(sc, THS_INTS));
- WR4(sc, THS_INTC, sc->conf->intc | SHUT_INT_ALL | ALARM_INT_ALL);
+ WR4(sc, THS_INTC, RD4(sc, THS_INTC) | SHUT_INT_ALL | ALARM_INT_ALL);
/* Enable sensors */
WR4(sc, THS_CTRL2, RD4(sc, THS_CTRL2) | SENSOR_ENABLE_ALL);
@@ -335,7 +436,7 @@ aw_thermal_gettemp(struct aw_thermal_softc *sc, int sensor)
val = RD4(sc, THS_DATA0 + (sensor * 4));
- return (sc->conf->to_temp(val));
+ return (sc->conf->to_temp(val, sensor));
}
static int
@@ -346,7 +447,7 @@ aw_thermal_getshut(struct aw_thermal_softc *sc, int sensor)
val = RD4(sc, THS_SHUTDOWN0_CTRL + (sensor * 4));
val = (val >> SHUT_T_HOT_SHIFT) & SHUT_T_HOT_MASK;
- return (sc->conf->to_temp(val));
+ return (sc->conf->to_temp(val, sensor));
}
static void
@@ -356,7 +457,7 @@ aw_thermal_setshut(struct aw_thermal_softc *sc, int sensor, int temp)
val = RD4(sc, THS_SHUTDOWN0_CTRL + (sensor * 4));
val &= ~(SHUT_T_HOT_MASK << SHUT_T_HOT_SHIFT);
- val |= (sc->conf->to_reg(temp) << SHUT_T_HOT_SHIFT);
+ val |= (sc->conf->to_reg(temp, sensor) << SHUT_T_HOT_SHIFT);
WR4(sc, THS_SHUTDOWN0_CTRL + (sensor * 4), val);
}
@@ -368,7 +469,7 @@ aw_thermal_gethyst(struct aw_thermal_softc *sc, int sensor)
val = RD4(sc, THS_ALARM0_CTRL + (sensor * 4));
val = (val >> ALARM_T_HYST_SHIFT) & ALARM_T_HYST_MASK;
- return (sc->conf->to_temp(val));
+ return (sc->conf->to_temp(val, sensor));
}
static int
@@ -379,7 +480,7 @@ aw_thermal_getalarm(struct aw_thermal_softc *sc, int sensor)
val = RD4(sc, THS_ALARM0_CTRL + (sensor * 4));
val = (val >> ALARM_T_HOT_SHIFT) & ALARM_T_HOT_MASK;
- return (sc->conf->to_temp(val));
+ return (sc->conf->to_temp(val, sensor));
}
static void
@@ -389,7 +490,7 @@ aw_thermal_setalarm(struct aw_thermal_softc *sc, int sensor, int temp)
val = RD4(sc, THS_ALARM0_CTRL + (sensor * 4));
val &= ~(ALARM_T_HOT_MASK << ALARM_T_HOT_SHIFT);
- val |= (sc->conf->to_reg(temp) << ALARM_T_HOT_SHIFT);
+ val |= (sc->conf->to_reg(temp, sensor) << ALARM_T_HOT_SHIFT);
WR4(sc, THS_ALARM0_CTRL + (sensor * 4), val);
}
@@ -506,13 +607,12 @@ static int
aw_thermal_attach(device_t dev)
{
struct aw_thermal_softc *sc;
- clk_t clk_ahb, clk_ths;
hwreset_t rst;
int i, error;
void *ih;
sc = device_get_softc(dev);
- clk_ahb = clk_ths = NULL;
+ sc->dev = dev;
rst = NULL;
ih = NULL;
@@ -524,25 +624,27 @@ aw_thermal_attach(device_t dev)
return (ENXIO);
}
- if (clk_get_by_ofw_name(dev, 0, "ahb", &clk_ahb) == 0) {
- error = clk_enable(clk_ahb);
+ if (clk_get_by_ofw_name(dev, 0, "apb", &sc->clk_apb) == 0) {
+ error = clk_enable(sc->clk_apb);
if (error != 0) {
- device_printf(dev, "cannot enable ahb clock\n");
+ device_printf(dev, "cannot enable apb clock\n");
goto fail;
}
}
- if (clk_get_by_ofw_name(dev, 0, "ths", &clk_ths) == 0) {
- error = clk_set_freq(clk_ths, sc->conf->clk_rate, 0);
+
+ if (clk_get_by_ofw_name(dev, 0, "ths", &sc->clk_ths) == 0) {
+ error = clk_set_freq(sc->clk_ths, sc->conf->clk_rate, 0);
if (error != 0) {
device_printf(dev, "cannot set ths clock rate\n");
goto fail;
}
- error = clk_enable(clk_ths);
+ error = clk_enable(sc->clk_ths);
if (error != 0) {
device_printf(dev, "cannot enable ths clock\n");
goto fail;
}
}
+
if (hwreset_get_by_ofw_idx(dev, 0, 0, &rst) == 0) {
error = hwreset_deassert(rst);
if (error != 0) {
@@ -581,7 +683,8 @@ aw_thermal_attach(device_t dev)
if (bootverbose)
for (i = 0; i < sc->conf->nsensors; i++) {
device_printf(dev,
- "#%d: alarm %dC hyst %dC shut %dC\n", i,
+ "%s: alarm %dC hyst %dC shut %dC\n",
+ sc->conf->sensors[i].name,
aw_thermal_getalarm(sc, i),
aw_thermal_gethyst(sc, i),
aw_thermal_getshut(sc, i));
@@ -597,10 +700,10 @@ fail:
bus_teardown_intr(dev, sc->res[1], ih);
if (rst != NULL)
hwreset_release(rst);
- if (clk_ahb != NULL)
- clk_release(clk_ahb);
- if (clk_ths != NULL)
- clk_release(clk_ths);
+ if (sc->clk_apb != NULL)
+ clk_release(sc->clk_apb);
+ if (sc->clk_ths != NULL)
+ clk_release(sc->clk_ths);
bus_release_resources(dev, aw_thermal_spec, sc->res);
return (ENXIO);