svn commit: r305352 - in head/sys: arm/allwinner arm/allwinner/clk arm64/conf conf

Jared McNeill jmcneill at FreeBSD.org
Sat Sep 3 15:26:02 UTC 2016


Author: jmcneill
Date: Sat Sep  3 15:26:00 2016
New Revision: 305352
URL: https://svnweb.freebsd.org/changeset/base/305352

Log:
  Add support for Allwinner A64 thermal sensors.

Added:
  head/sys/arm/allwinner/clk/aw_thsclk.c   (contents, props changed)
Modified:
  head/sys/arm/allwinner/aw_thermal.c
  head/sys/arm64/conf/GENERIC
  head/sys/conf/files.arm64

Modified: head/sys/arm/allwinner/aw_thermal.c
==============================================================================
--- head/sys/arm/allwinner/aw_thermal.c	Sat Sep  3 15:24:30 2016	(r305351)
+++ head/sys/arm/allwinner/aw_thermal.c	Sat Sep  3 15:26:00 2016	(r305352)
@@ -39,15 +39,21 @@ __FBSDID("$FreeBSD$");
 #include <sys/rman.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
+#include <sys/reboot.h>
 #include <sys/module.h>
 #include <machine/bus.h>
 
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+
 #include <arm/allwinner/aw_sid.h>
 
 #define	THS_CTRL0		0x00
+#define	THS_CTRL1		0x04
+#define	 ADC_CALI_EN		(1 << 17)
 #define	THS_CTRL2		0x40
 #define	 SENSOR_ACQ1_SHIFT	16
 #define	 SENSOR2_EN		(1 << 2)
@@ -55,8 +61,16 @@ __FBSDID("$FreeBSD$");
 #define	 SENSOR0_EN		(1 << 0)
 #define	THS_INTC		0x44
 #define	THS_INTS		0x48
+#define	 THS2_DATA_IRQ_STS	(1 << 10)
+#define	 THS1_DATA_IRQ_STS	(1 << 9)
+#define	 THS0_DATA_IRQ_STS	(1 << 8)
+#define	 SHUT_INT2_STS		(1 << 6)
+#define	 SHUT_INT1_STS		(1 << 5)
+#define	 SHUT_INT0_STS		(1 << 4)
+#define	 ALARM_INT2_STS		(1 << 2)
+#define	 ALARM_INT1_STS		(1 << 1)
+#define	 ALARM_INT0_STS		(1 << 0)
 #define	THS_FILTER		0x70
-#define	 FILTER_EN		(1 << 2)
 #define	THS_CALIB0		0x74
 #define	THS_CALIB1		0x78
 #define	THS_DATA0		0x80
@@ -64,38 +78,93 @@ __FBSDID("$FreeBSD$");
 #define	THS_DATA2		0x88
 #define	 DATA_MASK		0xfff
 
-#define	TEMP_BASE		2719
-#define	TEMP_MUL		1000
-#define	TEMP_DIV		14186
-#define	TEMP_TO_K		273
-#define	ADC_ACQUIRE_TIME	(24 - 1)
+#define	A83T_ADC_ACQUIRE_TIME	0x17
+#define	A83T_FILTER		0x4
+#define	A83T_INTC		0x1000
+#define	A83T_TEMP_BASE		2719000
+#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_TEMP_BASE		2170000
+#define	A64_TEMP_DIV		8560
+#define	A64_CLK_RATE		4000000
+
+#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)
 
-enum aw_thermal_sensor {
-	THS_SENSOR_CPU_CLUSTER0,
-	THS_SENSOR_CPU_CLUSTER1,
-	THS_SENSOR_GPU,
-	THS_SENSOR_END = -1
-};
+#define	MAX_SENSORS	3
 
-struct aw_thermal_sensor_config {
-	enum aw_thermal_sensor	sensor;
+struct aw_thermal_sensor {
 	const char		*name;
 	const char		*desc;
 };
 
-static const struct aw_thermal_sensor_config a83t_sensor_config[] = {
-	{ .sensor = THS_SENSOR_CPU_CLUSTER0,
-	  .name = "cluster0",	.desc = "CPU cluster 0 temperature" },
-	{ .sensor = THS_SENSOR_CPU_CLUSTER1,
-	  .name = "cluster1",	.desc = "CPU cluster 1 temperature" },
-	{ .sensor = THS_SENSOR_GPU,
-	  .name = "gpu",	.desc = "GPU temperature" },
-	{ .sensor = THS_SENSOR_END }
+struct aw_thermal_config {
+	struct aw_thermal_sensor	sensors[MAX_SENSORS];
+	int				nsensors;
+	uint64_t			clk_rate;
+	uint32_t			adc_acquire_time;
+	uint32_t			filter;
+	uint32_t			intc;
+	uint32_t			temp_base;
+	uint32_t			temp_div;
+};
+
+static const struct aw_thermal_config a83t_config = {
+	.nsensors = 3,
+	.sensors = {
+		[0] = {
+			.name = "cluster0",
+			.desc = "CPU cluster 0 temperature",
+		},
+		[1] = {
+			.name = "cluster1",
+			.desc = "CPU cluster 1 temperature",
+		},
+		[2] = {
+			.name = "gpu",
+			.desc = "GPU temperature",
+		},
+	},
+	.clk_rate = A83T_CLK_RATE,
+	.adc_acquire_time = A83T_ADC_ACQUIRE_TIME,
+	.filter = A83T_FILTER,
+	.intc = A83T_INTC,
+	.temp_base = A83T_TEMP_BASE,
+	.temp_div = A83T_TEMP_DIV,
+};
+
+static const struct aw_thermal_config a64_config = {
+	.nsensors = 3,
+	.sensors = {
+		[0] = {
+			.name = "cpu",
+			.desc = "CPU temperature",
+		},
+		[1] = {
+			.name = "gpu1",
+			.desc = "GPU temperature 1",
+		},
+		[2] = {
+			.name = "gpu2",
+			.desc = "GPU temperature 2",
+		},
+	},
+	.clk_rate = A64_CLK_RATE,
+	.adc_acquire_time = A64_ADC_ACQUIRE_TIME,
+	.filter = A64_FILTER,
+	.intc = A64_INTC,
+	.temp_base = A64_TEMP_BASE,
+	.temp_div = A64_TEMP_DIV,
 };
 
 static struct ofw_compat_data compat_data[] = {
-	{ "allwinner,sun8i-a83t-ts",	(uintptr_t)&a83t_sensor_config },
+	{ "allwinner,sun8i-a83t-ts",	(uintptr_t)&a83t_config },
+	{ "allwinner,sun50i-a64-ts",	(uintptr_t)&a64_config },
 	{ NULL,				(uintptr_t)NULL }
 };
 
@@ -103,17 +172,18 @@ static struct ofw_compat_data compat_dat
 	(void *)ofw_bus_search_compatible((d), compat_data)->ocd_data
 
 struct aw_thermal_softc {
-	struct resource			*res;
-	struct aw_thermal_sensor_config	*conf;
+	struct resource			*res[2];
+	struct aw_thermal_config	*conf;
 };
 
 static struct resource_spec aw_thermal_spec[] = {
 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
 	{ -1, 0 }
 };
 
-#define	RD4(sc, reg)		bus_read_4((sc)->res, (reg))
-#define	WR4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
+#define	RD4(sc, reg)		bus_read_4((sc)->res[0], (reg))
+#define	WR4(sc, reg, val)	bus_write_4((sc)->res[0], (reg), (val))
 
 static int
 aw_thermal_init(struct aw_thermal_softc *sc)
@@ -131,44 +201,73 @@ aw_thermal_init(struct aw_thermal_softc 
 	WR4(sc, THS_CALIB1, calib1);
 
 	/* Configure ADC acquire time (CLK_IN/(N+1)) and enable sensors */
-	WR4(sc, THS_CTRL0, ADC_ACQUIRE_TIME);
-	WR4(sc, THS_CTRL2, (ADC_ACQUIRE_TIME << SENSOR_ACQ1_SHIFT) |
-	    SENSOR_ENABLE_ALL);
+	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);
+
+	/* Enable average filter */
+	WR4(sc, THS_FILTER, sc->conf->filter);
 
-	/* Disable interrupts */
-	WR4(sc, THS_INTC, 0);
+	/* Enable interrupts */
 	WR4(sc, THS_INTS, RD4(sc, THS_INTS));
+	WR4(sc, THS_INTC, sc->conf->intc | SHUT_INT_ALL);
 
-	/* Enable average filter */
-	WR4(sc, THS_FILTER, RD4(sc, THS_FILTER) | FILTER_EN);
+	/* Enable sensors */
+	WR4(sc, THS_CTRL2, RD4(sc, THS_CTRL2) | SENSOR_ENABLE_ALL);
 
 	return (0);
 }
 
 static int
-aw_thermal_gettemp(uint32_t val)
+aw_thermal_reg_to_temp(struct aw_thermal_softc *sc, uint32_t val)
+{
+	return ((sc->conf->temp_base - val * 1000) / sc->conf->temp_div);
+}
+
+static int
+aw_thermal_gettemp(struct aw_thermal_softc *sc, int sensor)
 {
-	int raw;
+	uint32_t val;
+
+	val = RD4(sc, THS_DATA0 + (sensor * 4));
 
-	raw = val & DATA_MASK;
-	return (((TEMP_BASE - raw) * TEMP_MUL) / TEMP_DIV) + TEMP_TO_K;
+	return (aw_thermal_reg_to_temp(sc, val) + TEMP_C_TO_K);
 }
 
 static int
 aw_thermal_sysctl(SYSCTL_HANDLER_ARGS)
 {
 	struct aw_thermal_softc *sc;
-	enum aw_thermal_sensor sensor;
-	int val;
+	int sensor, val;
 
 	sc = arg1;
 	sensor = arg2;
 
-	val = aw_thermal_gettemp(RD4(sc, THS_DATA0 + (sensor * 4)));
+	val = aw_thermal_gettemp(sc, sensor);
 
 	return sysctl_handle_opaque(oidp, &val, sizeof(val), req);
 }
 
+static void
+aw_thermal_intr(void *arg)
+{
+	struct aw_thermal_softc *sc;
+	device_t dev;
+	uint32_t ints;
+
+	dev = arg;
+	sc = device_get_softc(dev);
+
+	ints = RD4(sc, THS_INTS);
+	WR4(sc, THS_INTS, ints);
+
+	if ((ints & SHUT_INT_ALL) != 0) {
+		device_printf(dev,
+		   "WARNING - current temperature exceeds safe limits\n");
+		shutdown_nice(RB_POWEROFF);
+	}
+}
+
 static int
 aw_thermal_probe(device_t dev)
 {
@@ -186,29 +285,82 @@ static int
 aw_thermal_attach(device_t dev)
 {
 	struct aw_thermal_softc *sc;
-	int i;
+	clk_t clk_ahb, clk_ths;
+	hwreset_t rst;
+	int i, error;
+	void *ih;
 
 	sc = device_get_softc(dev);
+	clk_ahb = clk_ths = NULL;
+	rst = NULL;
+	ih = NULL;
 
 	sc->conf = THS_CONF(dev);
 
-	if (bus_alloc_resources(dev, aw_thermal_spec, &sc->res) != 0) {
+	if (bus_alloc_resources(dev, aw_thermal_spec, sc->res) != 0) {
 		device_printf(dev, "cannot allocate resources for device\n");
 		return (ENXIO);
 	}
 
+	if (clk_get_by_ofw_name(dev, 0, "ahb", &clk_ahb) == 0) {
+		error = clk_enable(clk_ahb);
+		if (error != 0) {
+			device_printf(dev, "cannot enable ahb 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 (error != 0) {
+			device_printf(dev, "cannot set ths clock rate\n");
+			goto fail;
+		}
+		error = clk_enable(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) {
+			device_printf(dev, "cannot de-assert reset\n");
+			goto fail;
+		}
+	}
+
+	error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, aw_thermal_intr, dev, &ih);
+	if (error != 0) {
+		device_printf(dev, "cannot setup interrupt handler\n");
+		goto fail;
+	}
+
 	if (aw_thermal_init(sc) != 0)
-		return (ENXIO);
+		goto fail;
 
-	for (i = 0; sc->conf[i].sensor != THS_SENSOR_END; i++)
+	for (i = 0; i < sc->conf->nsensors; i++)
 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-		    OID_AUTO, sc->conf[i].name,
+		    OID_AUTO, sc->conf->sensors[i].name,
 		    CTLTYPE_INT | CTLFLAG_RD,
-		    sc, sc->conf[i].sensor, aw_thermal_sysctl, "IK0",
-		    sc->conf[i].desc);
+		    sc, i, aw_thermal_sysctl, "IK0",
+		    sc->conf->sensors[i].desc);
 
 	return (0);
+
+fail:
+	if (ih != NULL)
+		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);
+	bus_release_resources(dev, aw_thermal_spec, sc->res);
+
+	return (ENXIO);
 }
 
 static device_method_t aw_thermal_methods[] = {

Added: head/sys/arm/allwinner/clk/aw_thsclk.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/allwinner/clk/aw_thsclk.c	Sat Sep  3 15:26:00 2016	(r305352)
@@ -0,0 +1,320 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Allwinner THS clocks
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_subr.h>
+
+#include <dev/extres/clk/clk_mux.h>
+#include <dev/extres/clk/clk_gate.h>
+
+#include "clkdev_if.h"
+
+#define	SCLK_GATING		(1 << 31)
+#define	CLK_SRC_SEL		(0x3 << 24)
+#define	CLK_SRC_SEL_SHIFT	24
+#define	CLK_SRC_SEL_MAX		1
+#define	CLK_DIV_RATIO		(0x3 << 0)
+#define	CLK_DIV_RATIO_SHIFT	0
+#define	CLK_DIV_RATIO_MAX	3
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun50i-a64-ths-clk",	1 },
+	{ NULL, 0 }
+};
+
+struct aw_thsclk_sc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+};
+
+#define	THSCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	THSCLK_WRITE(sc, val)	CLKDEV_WRITE_4((sc)->clkdev, (sc)->reg, (val))
+#define	DEVICE_LOCK(sc)		CLKDEV_DEVICE_LOCK((sc)->clkdev)
+#define	DEVICE_UNLOCK(sc)	CLKDEV_DEVICE_UNLOCK((sc)->clkdev)
+
+static int
+aw_thsclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_thsclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	THSCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	index = (val & CLK_SRC_SEL) >> CLK_SRC_SEL_SHIFT;
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_thsclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_thsclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	if (index < 0 || index >= CLK_SRC_SEL_MAX)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	THSCLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	THSCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_thsclk_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_thsclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	THSCLK_READ(sc, &val);
+	if (enable)
+		val |= SCLK_GATING;
+	else
+		val &= ~SCLK_GATING;
+	THSCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_thsclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_thsclk_sc *sc;
+	uint32_t val, div;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	THSCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	switch (val & CLK_DIV_RATIO) {
+	case 3:
+		div = 6;
+		break;
+	default:
+		div = 1 << (val & CLK_DIV_RATIO);
+		break;
+	}
+
+	*freq = *freq / div;
+
+	return (0);
+}
+
+static int
+aw_thsclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_thsclk_sc *sc;
+	uint32_t val, div, n, best_div, best_n;
+	uint64_t cur_freq;
+	int64_t best_diff, cur_diff;
+
+	sc = clknode_get_softc(clk);
+	best_diff = (int64_t)*fout; 
+	best_n = 0;
+
+	for (div = 0; div <= CLK_DIV_RATIO_MAX; div++) {
+		n = (div == 3) ? 6 : (1 << div);
+		cur_freq = fin / n;
+		cur_diff = (int64_t)*fout - cur_freq;
+		if (cur_diff >= 0 && cur_diff < best_diff) {
+			best_diff = cur_diff;
+			best_div = div;
+			best_n = n;
+		}
+	}
+
+	if (best_diff == (int64_t)*fout || best_n == 0)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	THSCLK_READ(sc, &val);
+	val &= ~CLK_DIV_RATIO;
+	val |= (best_div << CLK_DIV_RATIO_SHIFT);
+	THSCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	*fout = fin / best_n;
+	*stop = 1;
+
+	return (0);
+}
+
+static clknode_method_t aw_thsclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_thsclk_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_thsclk_set_gate),
+	CLKNODEMETHOD(clknode_set_mux,		aw_thsclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_thsclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_freq,		aw_thsclk_set_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_thsclk_clknode, aw_thsclk_clknode_class,
+    aw_thsclk_clknode_methods, sizeof(struct aw_thsclk_sc), clknode_class);
+
+static int
+aw_thsclk_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner THS Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_thsclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_thsclk_sc *sc;
+	struct clkdom *clkdom;
+	struct clknode *clk;
+	clk_t clk_parent;
+	bus_addr_t paddr;
+	bus_size_t psize;
+	phandle_t node;
+	int error, ncells, i;
+
+	node = ofw_bus_get_node(dev);
+
+	if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
+		device_printf(dev, "cannot parse 'reg' property\n");
+		return (ENXIO);
+	}
+
+	error = ofw_bus_parse_xref_list_get_length(node, "clocks",
+	    "#clock-cells", &ncells);
+	if (error != 0) {
+		device_printf(dev, "cannot get clock count\n");
+		return (error);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	memset(&def, 0, sizeof(def));
+	error = clk_parse_ofw_clk_name(dev, node, &def.name);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock name\n");
+		error = ENXIO;
+		goto fail;
+	}
+	def.id = 1;
+	def.parent_names = malloc(sizeof(char *) * ncells, M_OFWPROP, M_WAITOK);
+	for (i = 0; i < ncells; i++) {
+		error = clk_get_by_ofw_index(dev, 0, i, &clk_parent);
+		if (error != 0) {
+			device_printf(dev, "cannot get clock %d\n", i);
+			goto fail;
+		}
+		def.parent_names[i] = clk_get_name(clk_parent);
+		clk_release(clk_parent);
+	}
+	def.parent_cnt = ncells;
+
+	clk = clknode_create(clkdom, &aw_thsclk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clknode\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	sc = clknode_get_softc(clk);
+	sc->reg = paddr;
+	sc->clkdev = device_get_parent(dev);
+
+	clknode_register(clkdom, clk);
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(dev, "cannot finalize clkdom initialization\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	return (0);
+
+fail:
+	return (error);
+}
+
+static device_method_t aw_thsclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_thsclk_probe),
+	DEVMETHOD(device_attach,	aw_thsclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_thsclk_driver = {
+	"aw_thsclk",
+	aw_thsclk_methods,
+	0
+};
+
+static devclass_t aw_thsclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_thsclk, simplebus, aw_thsclk_driver,
+    aw_thsclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);

Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC	Sat Sep  3 15:24:30 2016	(r305351)
+++ head/sys/arm64/conf/GENERIC	Sat Sep  3 15:26:00 2016	(r305352)
@@ -167,6 +167,12 @@ device		aw_wdog		# Allwinner Watchdog
 # Power management controllers
 device		axp81x		# X-Powers AXP81x PMIC
 
+# EFUSE
+device		aw_sid		# Allwinner Secure ID EFUSE
+
+# Thermal sensors
+device		aw_thermal	# Allwinner Thermal Sensor Controller
+
 # Pseudo devices.
 device		loop		# Network loopback
 device		random		# Entropy device

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64	Sat Sep  3 15:24:30 2016	(r305351)
+++ head/sys/conf/files.arm64	Sat Sep  3 15:26:00 2016	(r305352)
@@ -22,6 +22,8 @@ arm/allwinner/aw_nmi.c		optional	aw_nmi 
 arm/allwinner/aw_reset.c	optional	aw_ccu
 arm/allwinner/aw_rsb.c		optional	aw_rsb
 arm/allwinner/aw_rtc.c		optional	aw_rtc
+arm/allwinner/aw_sid.c		optional	aw_sid
+arm/allwinner/aw_thermal.c	optional	aw_thermal
 arm/allwinner/aw_usbphy.c	optional	ehci aw_usbphy
 arm/allwinner/aw_wdog.c		optional	aw_wdog
 arm/allwinner/axp81x.c		optional	axp81x
@@ -33,6 +35,7 @@ arm/allwinner/clk/aw_gate.c	optional	aw_
 arm/allwinner/clk/aw_modclk.c	optional	aw_ccu
 arm/allwinner/clk/aw_pll.c	optional	aw_ccu \
 	compile-with "${NORMAL_C} -I$S/gnu/dts/include"
+arm/allwinner/clk/aw_thsclk.c	optional	aw_ccu
 arm/allwinner/clk/aw_usbclk.c	optional	aw_ccu
 arm/allwinner/if_awg.c		optional	awg
 arm/arm/generic_timer.c		standard


More information about the svn-src-head mailing list