svn commit: r337372 - head/sys/arm/allwinner

Emmanuel Vadot manu at FreeBSD.org
Mon Aug 6 05:36:01 UTC 2018


Author: manu
Date: Mon Aug  6 05:36:00 2018
New Revision: 337372
URL: https://svnweb.freebsd.org/changeset/base/337372

Log:
  aw_thermal: Add nvmem and H5 support
  
  Now that aw_sid expose nvmem interface, use that to read the calibration
  data.
  Add support for H5 SoC.
  Fix the bindings, we used to have non-upstreamed bindings. Switch to the
  one that have been sent upstream. They are not stable yet, so we switch
  from custom, wrong, bindings to correct, proposed bindings

Modified:
  head/sys/arm/allwinner/aw_thermal.c

Modified: head/sys/arm/allwinner/aw_thermal.c
==============================================================================
--- head/sys/arm/allwinner/aw_thermal.c	Mon Aug  6 05:35:24 2018	(r337371)
+++ head/sys/arm/allwinner/aw_thermal.c	Mon Aug  6 05:36:00 2018	(r337372)
@@ -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);
-		}
+	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);
+	}
 
-		device_printf(sc->dev, "calib0: %x\n", calib[0]);
-		device_printf(sc->dev, "calib1: %x\n", calib[1]);
+	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 se
 
 	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 se
 	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 se
 
 	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 se
 	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 s
 	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 s
 
 	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);


More information about the svn-src-head mailing list