[Midnightbsd-cvs] src [12400] trunk/sys/arm/allwinner/clk: sync with freebsd 11 stable

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Fri Mar 6 12:15:48 EST 2020


Revision: 12400
          http://svnweb.midnightbsd.org/src/?rev=12400
Author:   laffer1
Date:     2020-03-06 12:15:48 -0500 (Fri, 06 Mar 2020)
Log Message:
-----------
sync with freebsd 11 stable

Added Paths:
-----------
    trunk/sys/arm/allwinner/clk/
    trunk/sys/arm/allwinner/clk/aw_ahbclk.c
    trunk/sys/arm/allwinner/clk/aw_apbclk.c
    trunk/sys/arm/allwinner/clk/aw_axiclk.c
    trunk/sys/arm/allwinner/clk/aw_codecclk.c
    trunk/sys/arm/allwinner/clk/aw_cpuclk.c
    trunk/sys/arm/allwinner/clk/aw_cpusclk.c
    trunk/sys/arm/allwinner/clk/aw_debeclk.c
    trunk/sys/arm/allwinner/clk/aw_gate.c
    trunk/sys/arm/allwinner/clk/aw_gmacclk.c
    trunk/sys/arm/allwinner/clk/aw_hdmiclk.c
    trunk/sys/arm/allwinner/clk/aw_lcdclk.c
    trunk/sys/arm/allwinner/clk/aw_mmcclk.c
    trunk/sys/arm/allwinner/clk/aw_modclk.c
    trunk/sys/arm/allwinner/clk/aw_oscclk.c
    trunk/sys/arm/allwinner/clk/aw_pll.c
    trunk/sys/arm/allwinner/clk/aw_usbclk.c

Added: trunk/sys/arm/allwinner/clk/aw_ahbclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_ahbclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_ahbclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,386 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_ahbclk.c 309771 2016-12-09 21:17:40Z manu $
+ */
+
+/*
+ * Allwinner AHB clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_ahbclk.c 309771 2016-12-09 21:17:40Z manu $");
+
+#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.h>
+
+#include "clkdev_if.h"
+
+#define	A10_AHB_CLK_DIV_RATIO		(0x3 << 4)
+#define	A10_AHB_CLK_DIV_RATIO_SHIFT	4
+
+#define	A13_AHB_CLK_SRC_SEL		(0x3 << 6)
+#define	A13_AHB_CLK_SRC_SEL_MAX		3
+#define	A13_AHB_CLK_SRC_SEL_SHIFT	6
+
+#define	A31_AHB1_PRE_DIV		(0x3 << 6)
+#define	A31_AHB1_PRE_DIV_SHIFT		6
+#define	A31_AHB1_CLK_SRC_SEL		(0x3 << 12)
+#define	A31_AHB1_CLK_SRC_SEL_PLL6	3
+#define	A31_AHB1_CLK_SRC_SEL_MAX	3
+#define	A31_AHB1_CLK_SRC_SEL_SHIFT	12
+
+#define	A83T_AHB1_CLK_SRC_SEL		(0x3 << 12)
+#define	A83T_AHB1_CLK_SRC_SEL_ISPLL(x)	((x) & 0x2)
+#define	A83T_AHB1_CLK_SRC_SEL_MAX	3
+#define	A83T_AHB1_CLK_SRC_SEL_SHIFT	12
+#define	A83T_AHB1_PRE_DIV		(0x3 << 6)
+#define	A83T_AHB1_PRE_DIV_SHIFT		6
+#define	A83T_AHB1_CLK_DIV_RATIO		(0x3 << 4)
+#define	A83T_AHB1_CLK_DIV_RATIO_SHIFT	4
+
+#define	H3_AHB2_CLK_CFG			(0x3 << 0)
+#define	H3_AHB2_CLK_CFG_SHIFT		0
+#define	H3_AHB2_CLK_CFG_AHB1		0
+#define	H3_AHB2_CLK_CFG_PLL_PERIPH_DIV2	1
+#define	H3_AHB2_CLK_CFG_MAX		1
+
+enum aw_ahbclk_type {
+	AW_A10_AHB = 1,
+	AW_A13_AHB,
+	AW_A31_AHB1,
+	AW_A83T_AHB1,
+	AW_H3_AHB2,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-ahb-clk",	AW_A10_AHB },
+	{ "allwinner,sun5i-a13-ahb-clk",	AW_A13_AHB },
+	{ "allwinner,sun6i-a31-ahb1-clk",	AW_A31_AHB1 },
+	{ "allwinner,sun8i-a83t-ahb1-clk",	AW_A83T_AHB1 },
+	{ "allwinner,sun8i-h3-ahb2-clk",	AW_H3_AHB2 },
+	{ NULL, 0 }
+};
+
+struct aw_ahbclk_sc {
+	device_t		clkdev;
+	bus_addr_t		reg;
+	enum aw_ahbclk_type	type;
+};
+
+#define	AHBCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	AHBCLK_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_ahbclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_ahbclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_A10_AHB:
+		index = 0;
+		break;
+	case AW_A13_AHB:
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		DEVICE_UNLOCK(sc);
+		index = (val & A13_AHB_CLK_SRC_SEL) >>
+		    A13_AHB_CLK_SRC_SEL_SHIFT;
+		break;
+	case AW_A31_AHB1:
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		DEVICE_UNLOCK(sc);
+		index = (val & A31_AHB1_CLK_SRC_SEL) >>
+		    A31_AHB1_CLK_SRC_SEL_SHIFT;
+		break;
+	case AW_A83T_AHB1:
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		DEVICE_UNLOCK(sc);
+		index = (val & A83T_AHB1_CLK_SRC_SEL) >>
+		    A83T_AHB1_CLK_SRC_SEL_SHIFT;
+		break;
+	case AW_H3_AHB2:
+		/* Set source to PLL_PERIPH/2 */
+		index = H3_AHB2_CLK_CFG_PLL_PERIPH_DIV2;
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		val &= ~H3_AHB2_CLK_CFG;
+		val |= (index << H3_AHB2_CLK_CFG_SHIFT);
+		AHBCLK_WRITE(sc, val);
+		DEVICE_UNLOCK(sc);
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_ahbclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_ahbclk_sc *sc;
+	uint32_t val, src_sel, div, pre_div;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	AHBCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	switch (sc->type) {
+	case AW_A31_AHB1:
+		div = 1 << ((val & A10_AHB_CLK_DIV_RATIO) >>
+		    A10_AHB_CLK_DIV_RATIO_SHIFT);
+		src_sel = (val & A31_AHB1_CLK_SRC_SEL) >>
+		    A31_AHB1_CLK_SRC_SEL_SHIFT;
+		if (src_sel == A31_AHB1_CLK_SRC_SEL_PLL6)
+			pre_div = ((val & A31_AHB1_PRE_DIV) >>
+			    A31_AHB1_PRE_DIV_SHIFT) + 1;
+		else
+			pre_div = 1;
+		break;
+	case AW_A83T_AHB1:
+		div = 1 << ((val & A83T_AHB1_CLK_DIV_RATIO) >>
+		    A83T_AHB1_CLK_DIV_RATIO_SHIFT);
+		src_sel = (val & A83T_AHB1_CLK_SRC_SEL) >>
+		    A83T_AHB1_CLK_SRC_SEL_SHIFT;
+		if (A83T_AHB1_CLK_SRC_SEL_ISPLL(src_sel))
+			pre_div = ((val & A83T_AHB1_PRE_DIV) >>
+			    A83T_AHB1_PRE_DIV_SHIFT) + 1;
+		else
+			pre_div = 1;
+		break;
+	case AW_H3_AHB2:
+		div = pre_div = 1;
+		break;
+	default:
+		div = 1 << ((val & A10_AHB_CLK_DIV_RATIO) >>
+		    A10_AHB_CLK_DIV_RATIO_SHIFT);
+		pre_div = 1;
+		break;
+	}
+
+	*freq = *freq / pre_div / div;
+
+	return (0);
+}
+
+static int
+aw_ahbclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_ahbclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_A10_AHB:
+		if (index != 0)
+			return (ERANGE);
+		break;
+	case AW_A13_AHB:
+		if (index < 0 || index > A13_AHB_CLK_SRC_SEL_MAX)
+			return (ERANGE);
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		val &= ~A13_AHB_CLK_SRC_SEL;
+		val |= (index << A13_AHB_CLK_SRC_SEL_SHIFT);
+		AHBCLK_WRITE(sc, val);
+		DEVICE_UNLOCK(sc);
+		break;
+	case AW_A83T_AHB1:
+		if (index < 0 || index > A83T_AHB1_CLK_SRC_SEL_MAX)
+			return (ERANGE);
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		val &= ~A83T_AHB1_CLK_SRC_SEL;
+		val |= (index << A83T_AHB1_CLK_SRC_SEL_SHIFT);
+		AHBCLK_WRITE(sc, val);
+		DEVICE_UNLOCK(sc);
+		break;
+	case AW_H3_AHB2:
+		if (index < 0 || index > H3_AHB2_CLK_CFG)
+			return (ERANGE);
+		DEVICE_LOCK(sc);
+		AHBCLK_READ(sc, &val);
+		val &= ~H3_AHB2_CLK_CFG;
+		val |= (index << H3_AHB2_CLK_CFG_SHIFT);
+		AHBCLK_WRITE(sc, val);
+		DEVICE_UNLOCK(sc);
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static clknode_method_t aw_ahbclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_ahbclk_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_ahbclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_mux,		aw_ahbclk_set_mux),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_ahbclk_clknode, aw_ahbclk_clknode_class,
+    aw_ahbclk_clknode_methods, sizeof(struct aw_ahbclk_sc), clknode_class);
+
+static int
+aw_ahbclk_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 AHB Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_ahbclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_ahbclk_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));
+	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;
+
+	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;
+	}
+
+	clk = clknode_create(clkdom, &aw_ahbclk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clknode\n");
+		error = ENXIO;
+		goto fail;
+	}
+	sc = clknode_get_softc(clk);
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	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;
+	}
+
+	error = clk_set_assigned(dev, node);
+	if (error != 0 && error != ENOENT) {
+		device_printf(dev, "cannot set assigned parents: %d\n", error);
+		goto fail;
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	return (0);
+
+fail:
+	return (error);
+}
+
+static device_method_t aw_ahbclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_ahbclk_probe),
+	DEVMETHOD(device_attach,	aw_ahbclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_ahbclk_driver = {
+	"aw_ahbclk",
+	aw_ahbclk_methods,
+	0
+};
+
+static devclass_t aw_ahbclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_ahbclk, simplebus, aw_ahbclk_driver,
+    aw_ahbclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_ahbclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_apbclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_apbclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_apbclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,308 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_apbclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner APB clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_apbclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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.h>
+
+#include "clkdev_if.h"
+
+#define	A10_APB0_CLK_RATIO		(0x3 << 8)
+#define	A10_APB0_CLK_RATIO_SHIFT	8
+#define	A10_APB1_CLK_SRC_SEL		(0x3 << 24)
+#define	A10_APB1_CLK_SRC_SEL_SHIFT	24
+#define	A10_APB1_CLK_SRC_SEL_MAX	0x3
+#define	A10_APB1_CLK_RAT_N		(0x3 << 16)
+#define	A10_APB1_CLK_RAT_N_SHIFT	16
+#define	A10_APB1_CLK_RAT_M		(0x1f << 0)
+#define	A10_APB1_CLK_RAT_M_SHIFT	0
+#define	A23_APB0_CLK_RATIO		(0x3 << 0)
+#define	A23_APB0_CLK_RATIO_SHIFT	0
+#define	A83T_APB1_CLK_RATIO		(0x3 << 8)
+#define	A83T_APB1_CLK_RATIO_SHIFT	8
+
+enum aw_apbclk_type {
+	AW_A10_APB0 = 1,
+	AW_A10_APB1,
+	AW_A23_APB0,
+	AW_A83T_APB1,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-apb0-clk",	AW_A10_APB0 },
+	{ "allwinner,sun4i-a10-apb1-clk",	AW_A10_APB1 },
+	{ "allwinner,sun8i-a23-apb0-clk",	AW_A23_APB0 },
+	{ "allwinner,sun8i-a83t-apb1-clk",	AW_A83T_APB1 },
+	{ NULL, 0 }
+};
+
+struct aw_apbclk_sc {
+	device_t		clkdev;
+	bus_addr_t		reg;
+	enum aw_apbclk_type	type;
+};
+
+#define	APBCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	APBCLK_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_apbclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_apbclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_A10_APB0:
+	case AW_A23_APB0:
+	case AW_A83T_APB1:
+		index = 0;
+		break;
+	case AW_A10_APB1:
+		DEVICE_LOCK(sc);
+		APBCLK_READ(sc, &val);
+		DEVICE_UNLOCK(sc);
+		index = (val & A10_APB1_CLK_SRC_SEL) >>
+		    A10_APB1_CLK_SRC_SEL_SHIFT;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_apbclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_apbclk_sc *sc;
+	uint32_t val, div, m, n;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	APBCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	switch (sc->type) {
+	case AW_A10_APB0:
+		div = 1 << ((val & A10_APB0_CLK_RATIO) >>
+		    A10_APB0_CLK_RATIO_SHIFT);
+		if (div == 1)
+			div = 2;
+		*freq = *freq / div;
+		break;
+	case AW_A10_APB1:
+		n = 1 << ((val & A10_APB1_CLK_RAT_N) >>
+		    A10_APB1_CLK_RAT_N_SHIFT);
+		m = ((val & A10_APB1_CLK_RAT_N) >>
+		    A10_APB1_CLK_RAT_M_SHIFT) + 1;
+		*freq = *freq / n / m;
+		break;
+	case AW_A23_APB0:
+		div = 1 << ((val & A23_APB0_CLK_RATIO) >>
+		    A23_APB0_CLK_RATIO_SHIFT);
+		*freq = *freq / div;
+		break;
+	case AW_A83T_APB1:
+		div = ((val & A83T_APB1_CLK_RATIO) >>
+		    A83T_APB1_CLK_RATIO_SHIFT) + 1;
+		*freq = *freq / div;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+aw_apbclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_apbclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	if (sc->type != AW_A10_APB1)
+		return (ENXIO);
+
+	if (index < 0 || index > A10_APB1_CLK_SRC_SEL_MAX)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	APBCLK_READ(sc, &val);
+	val &= ~A10_APB1_CLK_SRC_SEL;
+	val |= (index << A10_APB1_CLK_SRC_SEL_SHIFT);
+	APBCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static clknode_method_t aw_apbclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_apbclk_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_apbclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_mux,		aw_apbclk_set_mux),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_apbclk_clknode, aw_apbclk_clknode_class,
+    aw_apbclk_clknode_methods, sizeof(struct aw_apbclk_sc), clknode_class);
+
+static int
+aw_apbclk_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 APB Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_apbclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_apbclk_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_apbclk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clknode\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	sc = clknode_get_softc(clk);
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	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_apbclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_apbclk_probe),
+	DEVMETHOD(device_attach,	aw_apbclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_apbclk_driver = {
+	"aw_apbclk",
+	aw_apbclk_methods,
+	0
+};
+
+static devclass_t aw_apbclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_apbclk, simplebus, aw_apbclk_driver,
+    aw_apbclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_apbclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_axiclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_axiclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_axiclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,202 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_axiclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner AXI clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_axiclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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	AXI_CLK_DIV_RATIO	(0x3 << 0)
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-axi-clk",	1 },
+	{ NULL, 0 }
+};
+
+struct aw_axiclk_sc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+};
+
+#define	AXICLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	AXICLK_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_axiclk_init(struct clknode *clk, device_t dev)
+{
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+aw_axiclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_axiclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	AXICLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	*freq = *freq / ((val & AXI_CLK_DIV_RATIO) + 1);
+
+	return (0);
+}
+
+static clknode_method_t aw_axiclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_axiclk_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_axiclk_recalc_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_axiclk_clknode, aw_axiclk_clknode_class,
+    aw_axiclk_clknode_methods, sizeof(struct aw_axiclk_sc), clknode_class);
+
+static int
+aw_axiclk_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 AXI Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_axiclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_axiclk_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;
+
+	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);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	error = clk_get_by_ofw_index(dev, 0, 0, &clk_parent);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock parent\n");
+		return (ENXIO);
+	}
+
+	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 *), M_OFWPROP, M_WAITOK);
+	def.parent_names[0] = clk_get_name(clk_parent);
+	def.parent_cnt = 1;
+
+	clk = clknode_create(clkdom, &aw_axiclk_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_axiclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_axiclk_probe),
+	DEVMETHOD(device_attach,	aw_axiclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_axiclk_driver = {
+	"aw_axiclk",
+	aw_axiclk_methods,
+	0
+};
+
+static devclass_t aw_axiclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_axiclk, simplebus, aw_axiclk_driver,
+    aw_axiclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_axiclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_codecclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_codecclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_codecclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,165 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_codecclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner CODEC clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_codecclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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_gate.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "clkdev_if.h"
+
+#define	SCLK_GATING_SHIFT	31
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-codec-clk",	1 },
+	{ NULL, 0 }
+};
+
+static int
+aw_codecclk_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom,
+    const char *pclkname, const char *clkname, int index)
+{
+	const char *parent_names[1] = { pclkname };
+	struct clk_gate_def def;
+
+	memset(&def, 0, sizeof(def));
+	def.clkdef.id = index;
+	def.clkdef.name = clkname;
+	def.clkdef.parent_names = parent_names;
+	def.clkdef.parent_cnt = 1;
+	def.offset = paddr;
+	def.shift = SCLK_GATING_SHIFT;
+	def.mask = 1;
+	def.on_value = 1;
+	def.off_value = 0;
+
+	return (clknode_gate_register(clkdom, &def));
+}
+
+static int
+aw_codecclk_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 CODEC Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_codecclk_attach(device_t dev)
+{
+	struct clkdom *clkdom;
+	const char **names;
+	int nout, error;
+	uint32_t *indices;
+	clk_t clk_parent;
+	bus_addr_t paddr;
+	bus_size_t psize;
+	phandle_t node;
+
+	node = ofw_bus_get_node(dev);
+	indices = NULL;
+
+	if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
+		device_printf(dev, "cannot parse 'reg' property\n");
+		return (ENXIO);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
+	if (nout != 1) {
+		device_printf(dev, "must have exactly one output clock\n");
+		error = ENOENT;
+		goto fail;
+	}
+
+	error = clk_get_by_ofw_index(dev, 0, 0, &clk_parent);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock parent\n");
+		return (ENXIO);
+	}
+
+	error = aw_codecclk_create(dev, paddr, clkdom,
+	    clk_get_name(clk_parent), names[0], 1);
+
+	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_codecclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_codecclk_probe),
+	DEVMETHOD(device_attach,	aw_codecclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_codecclk_driver = {
+	"aw_codecclk",
+	aw_codecclk_methods,
+	0
+};
+
+static devclass_t aw_codecclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_codecclk, simplebus, aw_codecclk_driver,
+    aw_codecclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_codecclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_cpuclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_cpuclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_cpuclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,162 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_cpuclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner CPU clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_cpuclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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>
+
+#define	CPU_CLK_SRC_SEL_WIDTH	2
+#define	CPU_CLK_SRC_SEL_SHIFT	16
+
+static int
+aw_cpuclk_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-cpu-clk"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner CPU Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_cpuclk_attach(device_t dev)
+{
+	struct clk_mux_def def;
+	struct clkdom *clkdom;
+	bus_addr_t paddr;
+	bus_size_t psize;
+	phandle_t node;
+	int error, ncells, i;
+	clk_t clk;
+
+	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));
+	def.clkdef.id = 1;
+	def.clkdef.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);
+		if (error != 0) {
+			device_printf(dev, "cannot get clock %d\n", i);
+			goto fail;
+		}
+		def.clkdef.parent_names[i] = clk_get_name(clk);
+		clk_release(clk);
+	}
+	def.clkdef.parent_cnt = ncells;
+	def.offset = paddr;
+	def.shift = CPU_CLK_SRC_SEL_SHIFT;
+	def.width = CPU_CLK_SRC_SEL_WIDTH;
+
+	error = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock name\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	error = clknode_mux_register(clkdom, &def);
+	if (error != 0) {
+		device_printf(dev, "cannot register mux clock\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(dev, "cannot finalize clkdom initialization\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	OF_prop_free(__DECONST(char *, def.clkdef.parent_names));
+	OF_prop_free(__DECONST(char *, def.clkdef.name));
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	return (0);
+
+fail:
+	OF_prop_free(__DECONST(char *, def.clkdef.name));
+	return (error);
+}
+
+static device_method_t aw_cpuclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_cpuclk_probe),
+	DEVMETHOD(device_attach,	aw_cpuclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_cpuclk_driver = {
+	"aw_cpuclk",
+	aw_cpuclk_methods,
+	0
+};
+
+static devclass_t aw_cpuclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_cpuclk, simplebus, aw_cpuclk_driver,
+    aw_cpuclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_cpuclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_cpusclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_cpusclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_cpusclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,321 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_cpusclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner CPUS clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_cpusclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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.h>
+
+#include "clkdev_if.h"
+
+#define	A80_CPUS_CLK_SRC_SEL			(0x3 << 16)
+#define	A80_CPUS_CLK_SRC_SEL_SHIFT		16
+#define	A80_CPUS_CLK_SRC_SEL_X32KI		0
+#define	A80_CPUS_CLK_SRC_SEL_OSC24M		1
+#define	A80_CPUS_CLK_SRC_SEL_PLL_PERIPH		2
+#define	A80_CPUS_CLK_SRC_SEL_PLL_AUDIO		3
+#define	A80_CPUS_POST_DIV			(0x1f << 8)
+#define	A80_CPUS_POST_DIV_SHIFT			8
+#define	A80_CPUS_CLK_RATIO			(0x3 << 4)
+#define	A80_CPUS_CLK_RATIO_SHIFT		4
+
+#define	A83T_CPUS_CLK_SRC_SEL			(0x3 << 16)
+#define	A83T_CPUS_CLK_SRC_SEL_SHIFT		16
+#define	A83T_CPUS_CLK_SRC_SEL_X32KI		0
+#define	A83T_CPUS_CLK_SRC_SEL_OSC24M		1
+#define	A83T_CPUS_CLK_SRC_SEL_PLL_PERIPH	2
+#define	A83T_CPUS_CLK_SRC_SEL_INTERNAL_OSC	3
+#define	A83T_CPUS_POST_DIV			(0x1f << 8)
+#define	A83T_CPUS_POST_DIV_SHIFT		8
+#define	A83T_CPUS_CLK_RATIO			(0x3 << 4)
+#define	A83T_CPUS_CLK_RATIO_SHIFT		4
+
+enum aw_cpusclk_type {
+	AW_A80_CPUS = 1,
+	AW_A83T_CPUS,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun9i-a80-cpus-clk",	AW_A80_CPUS },
+	{ "allwinner,sun8i-a83t-cpus-clk",	AW_A83T_CPUS },
+	{ NULL, 0 }
+};
+
+struct aw_cpusclk_sc {
+	device_t		clkdev;
+	bus_addr_t		reg;
+	enum aw_cpusclk_type	type;
+};
+
+#define	CPUSCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	CPUSCLK_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_cpusclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_cpusclk_sc *sc;
+	uint32_t val, mask, shift, index;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_A80_CPUS:
+		mask = A80_CPUS_CLK_SRC_SEL;
+		shift = A80_CPUS_CLK_SRC_SEL_SHIFT;
+		break;
+	case AW_A83T_CPUS:
+		mask = A83T_CPUS_CLK_SRC_SEL;
+		shift = A83T_CPUS_CLK_SRC_SEL_SHIFT;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	DEVICE_LOCK(sc);
+	CPUSCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+	index = (val & mask) >> shift;
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_cpusclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_cpusclk_sc *sc;
+	uint32_t val, src_sel, post_div, clk_ratio;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	CPUSCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	switch (sc->type) {
+	case AW_A80_CPUS:
+		src_sel = (val & A80_CPUS_CLK_SRC_SEL) >>
+		    A80_CPUS_CLK_SRC_SEL_SHIFT;
+		post_div = ((val & A80_CPUS_POST_DIV) >>
+		    A80_CPUS_POST_DIV_SHIFT) + 1;
+		clk_ratio = ((val & A80_CPUS_CLK_RATIO) >>
+		    A80_CPUS_CLK_RATIO_SHIFT) + 1;
+		if (src_sel == A80_CPUS_CLK_SRC_SEL_PLL_PERIPH)
+			*freq = *freq / post_div / clk_ratio;
+		else
+			*freq = *freq / clk_ratio;
+		break;
+	case AW_A83T_CPUS:
+		src_sel = (val & A83T_CPUS_CLK_SRC_SEL) >>
+		    A83T_CPUS_CLK_SRC_SEL_SHIFT;
+		post_div = ((val & A83T_CPUS_POST_DIV) >>
+		    A83T_CPUS_POST_DIV_SHIFT) + 1;
+		clk_ratio = 1 << ((val & A83T_CPUS_CLK_RATIO) >>
+		    A83T_CPUS_CLK_RATIO_SHIFT);
+		if (src_sel == A83T_CPUS_CLK_SRC_SEL_PLL_PERIPH)
+			*freq = *freq / post_div / clk_ratio;
+		else
+			*freq = *freq / clk_ratio;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+aw_cpusclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_cpusclk_sc *sc;
+	uint32_t mask, shift, val;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_A80_CPUS:
+		mask = A80_CPUS_CLK_SRC_SEL;
+		shift = A80_CPUS_CLK_SRC_SEL_SHIFT;
+		break;
+	case AW_A83T_CPUS:
+		mask = A83T_CPUS_CLK_SRC_SEL;
+		shift = A83T_CPUS_CLK_SRC_SEL_SHIFT;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	DEVICE_LOCK(sc);
+	CPUSCLK_READ(sc, &val);
+	val &= ~mask;
+	val |= (index << shift);
+	CPUSCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static clknode_method_t aw_cpusclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_cpusclk_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_cpusclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_mux,		aw_cpusclk_set_mux),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_cpusclk_clknode, aw_cpusclk_clknode_class,
+    aw_cpusclk_clknode_methods, sizeof(struct aw_cpusclk_sc), clknode_class);
+
+static int
+aw_cpusclk_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 CPUS Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_cpusclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_cpusclk_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));
+	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;
+
+	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;
+	}
+
+	clk = clknode_create(clkdom, &aw_cpusclk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clknode\n");
+		error = ENXIO;
+		goto fail;
+	}
+	sc = clknode_get_softc(clk);
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	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_cpusclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_cpusclk_probe),
+	DEVMETHOD(device_attach,	aw_cpusclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_cpusclk_driver = {
+	"aw_cpusclk",
+	aw_cpusclk_methods,
+	0
+};
+
+static devclass_t aw_cpusclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_cpusclk, simplebus, aw_cpusclk_driver,
+    aw_cpusclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_cpusclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_debeclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_debeclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_debeclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,352 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_debeclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner display backend clocks
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_debeclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+
+#define	SCLK_GATING		(1 << 31)
+#define	BE_RST			(1 << 30)
+#define	CLK_SRC_SEL		(0x3 << 24)
+#define	CLK_SRC_SEL_SHIFT	24
+#define	CLK_SRC_SEL_MAX		2
+#define	CLK_SRC_SEL_PLL3	0
+#define	CLK_SRC_SEL_PLL7	1
+#define	CLK_SRC_SEL_PLL5	2
+#define	CLK_RATIO_M		(0xf << 0)
+#define	CLK_RATIO_M_SHIFT	0
+#define	CLK_RATIO_M_MAX		0xf
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-de-be-clk",	1 },
+	{ NULL, 0 }
+};
+
+struct aw_debeclk_softc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+};
+
+#define	DEBECLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	DEBECLK_WRITE(sc, val)	CLKDEV_WRITE_4((sc)->clkdev, (sc)->reg, (val))
+#define	DEBECLK_MODIFY(sc, clr, set)	\
+	CLKDEV_MODIFY_4((sc)->clkdev, (sc)->reg, (clr), (set))
+#define	DEVICE_LOCK(sc)		CLKDEV_DEVICE_LOCK((sc)->clkdev)
+#define	DEVICE_UNLOCK(sc)	CLKDEV_DEVICE_UNLOCK((sc)->clkdev)
+
+static int
+aw_debeclk_hwreset_assert(device_t dev, intptr_t id, bool value)
+{
+	struct aw_debeclk_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	DEVICE_LOCK(sc);
+	error = DEBECLK_MODIFY(sc, BE_RST, value ? 0 : BE_RST);
+	DEVICE_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+aw_debeclk_hwreset_is_asserted(device_t dev, intptr_t id, bool *value)
+{
+	struct aw_debeclk_softc *sc;
+	uint32_t val;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	DEVICE_LOCK(sc);
+	error = DEBECLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	if (error)
+		return (error);
+
+	*value = (val & BE_RST) != 0 ? false : true;
+
+	return (0);
+}
+
+static int
+aw_debeclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_debeclk_softc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	/* Set BE source to PLL5 (DDR external peripheral clock) */
+	index = CLK_SRC_SEL_PLL5;
+
+	DEVICE_LOCK(sc);
+	DEBECLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	DEBECLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_debeclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_debeclk_softc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	if (index < 0 || index > CLK_SRC_SEL_MAX)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	DEBECLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	DEBECLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_debeclk_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_debeclk_softc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	DEBECLK_READ(sc, &val);
+	if (enable)
+		val |= SCLK_GATING;
+	else
+		val &= ~SCLK_GATING;
+	DEBECLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_debeclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_debeclk_softc *sc;
+	uint32_t val, m;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	DEBECLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	m = ((val & CLK_RATIO_M) >> CLK_RATIO_M_SHIFT) + 1;
+
+	*freq = *freq / m;
+
+	return (0);
+}
+
+static int
+aw_debeclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_debeclk_softc *sc;
+	uint32_t val, m;
+
+	sc = clknode_get_softc(clk);
+
+	m = howmany(fin, *fout) - 1;
+
+	DEVICE_LOCK(sc);
+	DEBECLK_READ(sc, &val);
+	val &= ~CLK_RATIO_M;
+	val |= (m << CLK_RATIO_M_SHIFT);
+	DEBECLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	*fout = fin / (m + 1);
+	*stop = 1;
+
+	return (0);
+}
+
+static clknode_method_t aw_debeclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_debeclk_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_debeclk_set_gate),
+	CLKNODEMETHOD(clknode_set_mux,		aw_debeclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_debeclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_freq,		aw_debeclk_set_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_debeclk_clknode, aw_debeclk_clknode_class,
+    aw_debeclk_clknode_methods, sizeof(struct aw_debeclk_softc), clknode_class);
+
+static int
+aw_debeclk_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 Display Engine Backend Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_debeclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_debeclk_softc *sc, *clk_sc;
+	struct clkdom *clkdom;
+	struct clknode *clk;
+	clk_t clk_parent;
+	bus_size_t psize;
+	phandle_t node;
+	int error, ncells, i;
+
+	sc = device_get_softc(dev);
+	sc->clkdev = device_get_parent(dev);
+	node = ofw_bus_get_node(dev);
+
+	if (ofw_reg_to_paddr(node, 0, &sc->reg, &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_debeclk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clknode\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	clk_sc = clknode_get_softc(clk);
+	clk_sc->reg = sc->reg;
+	clk_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);
+
+	hwreset_register_ofw_provider(dev);
+
+	return (0);
+
+fail:
+	return (error);
+}
+
+static device_method_t aw_debeclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_debeclk_probe),
+	DEVMETHOD(device_attach,	aw_debeclk_attach),
+
+	/* Reset interface */
+	DEVMETHOD(hwreset_assert,	aw_debeclk_hwreset_assert),
+	DEVMETHOD(hwreset_is_asserted,	aw_debeclk_hwreset_is_asserted),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_debeclk_driver = {
+	"aw_debeclk",
+	aw_debeclk_methods,
+	sizeof(struct aw_debeclk_softc)
+};
+
+static devclass_t aw_debeclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_debeclk, simplebus, aw_debeclk_driver,
+    aw_debeclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_debeclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_gate.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_gate.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_gate.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,232 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_gate.c 309762 2016-12-09 20:35:01Z manu $
+ */
+
+/*
+ * Allwinner clock gates
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_gate.c 309762 2016-12-09 20:35:01Z manu $");
+
+#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/fdt/fdt_common.h>
+
+#include <dev/extres/clk/clk_gate.h>
+
+#define	GATE_OFFSET(index)	((index / 32) * 4)
+#define	GATE_SHIFT(index)	(index % 32)
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-dram-gates-clk",
+	  (uintptr_t)"Allwinner DRAM Clock Gates" },
+	{ "allwinner,sun4i-a10-ahb-gates-clk",
+	  (uintptr_t)"Allwinner AHB Clock Gates" },
+	{ "allwinner,sun4i-a10-apb0-gates-clk",
+	  (uintptr_t)"Allwinner APB0 Clock Gates" },
+	{ "allwinner,sun4i-a10-apb1-gates-clk",
+	  (uintptr_t)"Allwinner APB1 Clock Gates" },
+
+	{ "allwinner,sun5i-a13-ahb-gates-clk",
+	  (uintptr_t)"Allwinner AHB Clock Gates" },
+	{ "allwinner,sun5i-a13-apb0-gates-clk",
+	  (uintptr_t)"Allwinner APB0 Clock Gates" },
+	{ "allwinner,sun5i-a13-apb1-gates-clk",
+	  (uintptr_t)"Allwinner APB1 Clock Gates" },
+
+	{ "allwinner,sun7i-a20-ahb-gates-clk",
+	  (uintptr_t)"Allwinner AHB Clock Gates" },
+	{ "allwinner,sun7i-a20-apb0-gates-clk",
+	  (uintptr_t)"Allwinner APB0 Clock Gates" },
+	{ "allwinner,sun7i-a20-apb1-gates-clk",
+	  (uintptr_t)"Allwinner APB1 Clock Gates" },
+
+	{ "allwinner,sun6i-a31-ahb1-gates-clk",
+	  (uintptr_t)"Allwinner AHB1 Clock Gates" },
+	{ "allwinner,sun6i-a31-apb0-gates-clk",
+	  (uintptr_t)"Allwinner APB0 Clock Gates" },
+	{ "allwinner,sun6i-a31-apb1-gates-clk",
+	  (uintptr_t)"Allwinner APB1 Clock Gates" },
+	{ "allwinner,sun6i-a31-apb2-gates-clk",
+	  (uintptr_t)"Allwinner APB2 Clock Gates" },
+
+	{ "allwinner,sun8i-a83t-bus-gates-clk",
+	  (uintptr_t)"Allwinner Bus Clock Gates" },
+	{ "allwinner,sun8i-a83t-apb0-gates-clk",
+	  (uintptr_t)"Allwinner APB0 Clock Gates" },
+
+	{ "allwinner,sun8i-h3-bus-gates-clk",
+	  (uintptr_t)"Allwinner Bus Clock Gates" },
+	{ "allwinner,sun8i-h3-apb0-gates-clk",
+	  (uintptr_t)"Allwinner APB0 Clock Gates" },
+
+	{ "allwinner,sun9i-a80-apbs-gates-clk",
+	  (uintptr_t)"Allwinner APBS Clock Gates" },
+
+	{ "allwinner,sunxi-multi-bus-gates-clk",
+	  (uintptr_t)"Allwinner Multi Bus Clock Gates" },
+
+	{ NULL, 0 }
+};
+
+static int
+aw_gate_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom,
+    const char *pclkname, const char *clkname, int index)
+{
+	const char *parent_names[1] = { pclkname };
+	struct clk_gate_def def;
+
+	memset(&def, 0, sizeof(def));
+	def.clkdef.id = index;
+	def.clkdef.name = clkname;
+	def.clkdef.parent_names = parent_names;
+	def.clkdef.parent_cnt = 1;
+	def.offset = paddr + GATE_OFFSET(index);
+	def.shift = GATE_SHIFT(index);
+	def.mask = 1;
+	def.on_value = 1;
+	def.off_value = 0;
+
+	return (clknode_gate_register(clkdom, &def));
+}
+
+static int
+aw_gate_add(device_t dev, struct clkdom *clkdom, phandle_t node,
+    bus_addr_t paddr)
+{
+	const char **names;
+	uint32_t *indices;
+	clk_t clk_parent;
+	int index, nout, error;
+
+	indices = NULL;
+
+	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
+	if (nout == 0) {
+		device_printf(dev, "no clock outputs found\n");
+		return (ENOENT);
+	}
+	if (indices == NULL) {
+		device_printf(dev, "no clock-indices property\n");
+		return (ENXIO);
+	}
+
+	error = clk_get_by_ofw_index(dev, node, 0, &clk_parent);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock parent\n");
+		return (ENXIO);
+	}
+
+	for (index = 0; index < nout; index++) {
+		error = aw_gate_create(dev, paddr, clkdom,
+		    clk_get_name(clk_parent), names[index], indices[index]);
+		if (error)
+			return (error);
+	}
+
+	return (0);
+}
+
+static int
+aw_gate_probe(device_t dev)
+{
+	const char *d;
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	d = (const char *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	if (d == NULL)
+		return (ENXIO);
+
+	device_set_desc(dev, d);
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_gate_attach(device_t dev)
+{
+	struct clkdom *clkdom;
+	bus_addr_t paddr;
+	bus_size_t psize;
+	phandle_t node, child;
+
+	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);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	if (ofw_bus_is_compatible(dev, "allwinner,sunxi-multi-bus-gates-clk")) {
+		for (child = OF_child(node); child > 0; child = OF_peer(child))
+			aw_gate_add(dev, clkdom, child, paddr);
+	} else
+		aw_gate_add(dev, clkdom, node, paddr);
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(dev, "cannot finalize clkdom initialization\n");
+		return (ENXIO);
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	return (0);
+}
+
+static device_method_t aw_gate_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_gate_probe),
+	DEVMETHOD(device_attach,	aw_gate_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_gate_driver = {
+	"aw_gate",
+	aw_gate_methods,
+	0
+};
+
+static devclass_t aw_gate_devclass;
+
+EARLY_DRIVER_MODULE(aw_gate, simplebus, aw_gate_driver,
+    aw_gate_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_gate.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_gmacclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_gmacclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_gmacclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,303 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_gmacclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner GMAC clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_gmacclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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	GMAC_CLK_PIT		(0x1 << 2)
+#define	GMAC_CLK_PIT_SHIFT	2
+#define	GMAC_CLK_PIT_MII	0
+#define	GMAC_CLK_PIT_RGMII	1
+#define	GMAC_CLK_SRC		(0x3 << 0)
+#define	GMAC_CLK_SRC_SHIFT	0
+#define	GMAC_CLK_SRC_MII	0
+#define	GMAC_CLK_SRC_EXT_RGMII	1
+#define	GMAC_CLK_SRC_RGMII	2
+
+#define	EMAC_TXC_DIV_CFG	(1 << 15)
+#define	EMAC_TXC_DIV_CFG_SHIFT	15
+#define	EMAC_TXC_DIV_CFG_125MHZ	0
+#define	EMAC_TXC_DIV_CFG_25MHZ	1
+#define	EMAC_PHY_SELECT		(1 << 16)
+#define	EMAC_PHY_SELECT_SHIFT	16
+#define	EMAC_PHY_SELECT_INT	0
+#define	EMAC_PHY_SELECT_EXT	1
+#define	EMAC_ETXDC		(0x7 << 10)
+#define	EMAC_ETXDC_SHIFT	10
+#define	EMAC_ERXDC		(0x1f << 5)
+#define	EMAC_ERXDC_SHIFT	5
+
+#define	CLK_IDX_MII		0
+#define	CLK_IDX_RGMII		1
+#define	CLK_IDX_COUNT		2
+
+enum aw_gmacclk_type {
+	GMACCLK_A20 = 1,
+	GMACCLK_A83T,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun7i-a20-gmac-clk",	GMACCLK_A20 },
+	{ "allwinner,sun8i-a83t-emac-clk",	GMACCLK_A83T },
+	{ NULL, 0 }
+};
+
+struct aw_gmacclk_sc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+	enum aw_gmacclk_type type;
+
+	int		rx_delay;
+	int		tx_delay;
+};
+
+#define	GMACCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	GMACCLK_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_gmacclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_gmacclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	GMACCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	switch ((val & GMAC_CLK_SRC) >> GMAC_CLK_SRC_SHIFT) {
+	case GMAC_CLK_SRC_MII:
+		index = CLK_IDX_MII;
+		break;
+	case GMAC_CLK_SRC_RGMII:
+		index = CLK_IDX_RGMII;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_gmacclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_gmacclk_sc *sc;
+	uint32_t val, clk_src, pit, txc_div;
+	int error;
+
+	sc = clknode_get_softc(clk);
+	error = 0;
+
+	switch (index) {
+	case CLK_IDX_MII:
+		clk_src = GMAC_CLK_SRC_MII;
+		pit = GMAC_CLK_PIT_MII;
+		txc_div = EMAC_TXC_DIV_CFG_25MHZ;
+		break;
+	case CLK_IDX_RGMII:
+		clk_src = GMAC_CLK_SRC_RGMII;
+		pit = GMAC_CLK_PIT_RGMII;
+		txc_div = EMAC_TXC_DIV_CFG_125MHZ;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	DEVICE_LOCK(sc);
+	GMACCLK_READ(sc, &val);
+	val &= ~(GMAC_CLK_SRC | GMAC_CLK_PIT);
+	val |= (clk_src << GMAC_CLK_SRC_SHIFT);
+	val |= (pit << GMAC_CLK_PIT_SHIFT);
+	if (sc->type == GMACCLK_A83T) {
+		val &= ~EMAC_TXC_DIV_CFG;
+		val |= (txc_div << EMAC_TXC_DIV_CFG_SHIFT);
+		val &= ~EMAC_PHY_SELECT;
+		val |= (EMAC_PHY_SELECT_EXT << EMAC_PHY_SELECT_SHIFT);
+		if (sc->tx_delay >= 0) {
+			val &= ~EMAC_ETXDC;
+			val |= (sc->tx_delay << EMAC_ETXDC_SHIFT);
+		}
+		if (sc->rx_delay >= 0) {
+			val &= ~EMAC_ERXDC;
+			val |= (sc->rx_delay << EMAC_ERXDC_SHIFT);
+		}
+	}
+	GMACCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static clknode_method_t aw_gmacclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_gmacclk_init),
+	CLKNODEMETHOD(clknode_set_mux,		aw_gmacclk_set_mux),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_gmacclk_clknode, aw_gmacclk_clknode_class,
+    aw_gmacclk_clknode_methods, sizeof(struct aw_gmacclk_sc), clknode_class);
+
+static int
+aw_gmacclk_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 GMAC Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_gmacclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_gmacclk_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 || ncells != CLK_IDX_COUNT) {
+		device_printf(dev, "couldn't find parent clocks\n");
+		return (ENXIO);
+	}
+
+	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", error);
+			goto fail;
+		}
+		def.parent_names[i] = clk_get_name(clk_parent);
+		clk_release(clk_parent);
+	}
+	def.parent_cnt = ncells;
+
+	clk = clknode_create(clkdom, &aw_gmacclk_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);
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	sc->tx_delay = sc->rx_delay = -1;
+	OF_getencprop(node, "tx-delay", &sc->tx_delay, sizeof(sc->tx_delay));
+	OF_getencprop(node, "rx-delay", &sc->rx_delay, sizeof(sc->rx_delay));
+
+	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_gmacclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_gmacclk_probe),
+	DEVMETHOD(device_attach,	aw_gmacclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_gmacclk_driver = {
+	"aw_gmacclk",
+	aw_gmacclk_methods,
+	0
+};
+
+static devclass_t aw_gmacclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_gmacclk, simplebus, aw_gmacclk_driver,
+    aw_gmacclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_gmacclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_hdmiclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_hdmiclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_hdmiclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,316 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_hdmiclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner HDMI clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_hdmiclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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		0x3
+#define	CLK_RATIO_N		(0x3 << 16)
+#define	CLK_RATIO_N_SHIFT	16
+#define	CLK_RATIO_N_MAX		0x3
+#define	CLK_RATIO_M		(0x1f << 0)
+#define	CLK_RATIO_M_SHIFT	0
+#define	CLK_RATIO_M_MAX		0x1f
+
+#define	CLK_IDX_PLL3_1X		0
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-hdmi-clk",	1 },
+	{ NULL, 0 }
+};
+
+struct aw_hdmiclk_sc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+};
+
+#define	HDMICLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	HDMICLK_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_hdmiclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_hdmiclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	/* Select PLL3(1X) clock source */
+	index = CLK_IDX_PLL3_1X;
+
+	DEVICE_LOCK(sc);
+	HDMICLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	HDMICLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_hdmiclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_hdmiclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	if (index < 0 || index > CLK_SRC_SEL_MAX)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	HDMICLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	HDMICLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_hdmiclk_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_hdmiclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	HDMICLK_READ(sc, &val);
+	if (enable)
+		val |= SCLK_GATING;
+	else
+		val &= ~SCLK_GATING;
+	HDMICLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_hdmiclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_hdmiclk_sc *sc;
+	uint32_t val, m, n;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	HDMICLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	n = 1 << ((val & CLK_RATIO_N) >> CLK_RATIO_N_SHIFT);
+	m = ((val & CLK_RATIO_M) >> CLK_RATIO_M_SHIFT) + 1;
+
+	*freq = *freq / n / m;
+
+	return (0);
+}
+
+static int
+aw_hdmiclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_hdmiclk_sc *sc;
+	uint32_t val, m, n, best_m, best_n;
+	uint64_t cur_freq;
+	int64_t best_diff, cur_diff;
+
+	sc = clknode_get_softc(clk);
+	best_n = best_m = 0;
+	best_diff = (int64_t)*fout; 
+
+	for (n = 0; n <= CLK_RATIO_N_MAX; n++)
+		for (m = 0; m <= CLK_RATIO_M_MAX; m++) {
+			cur_freq = fin / (1 << n) / (m + 1);
+			cur_diff = (int64_t)*fout - cur_freq;
+			if (cur_diff >= 0 && cur_diff < best_diff) {
+				best_diff = cur_diff;
+				best_m = m;
+				best_n = n;
+			}
+		}
+
+	if (best_diff == (int64_t)*fout)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	HDMICLK_READ(sc, &val);
+	val &= ~(CLK_RATIO_N | CLK_RATIO_M);
+	val |= (best_n << CLK_RATIO_N_SHIFT);
+	val |= (best_m << CLK_RATIO_M_SHIFT);
+	HDMICLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	*fout = fin / (1 << best_n) / (best_m + 1);
+	*stop = 1;
+
+	return (0);
+}
+
+static clknode_method_t aw_hdmiclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_hdmiclk_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_hdmiclk_set_gate),
+	CLKNODEMETHOD(clknode_set_mux,		aw_hdmiclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_hdmiclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_freq,		aw_hdmiclk_set_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_hdmiclk_clknode, aw_hdmiclk_clknode_class,
+    aw_hdmiclk_clknode_methods, sizeof(struct aw_hdmiclk_sc), clknode_class);
+
+static int
+aw_hdmiclk_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 HDMI Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_hdmiclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_hdmiclk_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;
+
+	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);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	error = clk_get_by_ofw_index(dev, 0, 0, &clk_parent);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock parent\n");
+		return (ENXIO);
+	}
+
+	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 *), M_OFWPROP, M_WAITOK);
+	def.parent_names[0] = clk_get_name(clk_parent);
+	def.parent_cnt = 1;
+
+	clk = clknode_create(clkdom, &aw_hdmiclk_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_hdmiclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_hdmiclk_probe),
+	DEVMETHOD(device_attach,	aw_hdmiclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_hdmiclk_driver = {
+	"aw_hdmiclk",
+	aw_hdmiclk_methods,
+	0
+};
+
+static devclass_t aw_hdmiclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_hdmiclk, simplebus, aw_hdmiclk_driver,
+    aw_hdmiclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_hdmiclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_lcdclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_lcdclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_lcdclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,562 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_lcdclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner LCD clocks
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_lcdclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+
+/* CH0 */
+#define	CH0_SCLK_GATING			(1 << 31)
+#define	CH0_LCD_RST			(1 << 30)
+#define	CH0_CLK_SRC_SEL			(0x3 << 24)
+#define	CH0_CLK_SRC_SEL_SHIFT		24
+#define	CH0_CLK_SRC_SEL_PLL3_1X		0
+#define	CH0_CLK_SRC_SEL_PLL7_1X		1
+#define	CH0_CLK_SRC_SEL_PLL3_2X		2
+#define	CH0_CLK_SRC_SEL_PLL6		3
+
+/* CH1 */
+#define	CH1_SCLK2_GATING		(1 << 31)
+#define	CH1_SCLK2_SEL			(0x3 << 24)
+#define	CH1_SCLK2_SEL_SHIFT		24
+#define	CH1_SCLK2_SEL_PLL3_1X		0
+#define	CH1_SCLK2_SEL_PLL7_1X		1
+#define	CH1_SCLK2_SEL_PLL3_2X		2
+#define	CH1_SCLK2_SEL_PLL7_2X		3
+#define	CH1_SCLK1_GATING		(1 << 15)
+#define	CH1_SCLK1_SEL			(0x1 << 11)
+#define	CH1_SCLK1_SEL_SHIFT		11
+#define	CH1_SCLK1_SEL_SCLK2		0
+#define	CH1_SCLK1_SEL_SCLK2_DIV2	1
+#define	CH1_CLK_DIV_RATIO_M		(0x1f << 0)
+#define	CH1_CLK_DIV_RATIO_M_SHIFT	0
+
+#define	TCON_PLLREF			3000000ULL
+#define	TCON_PLL_M_MIN			1
+#define	TCON_PLL_M_MAX			15
+#define	TCON_PLL_N_MIN			9
+#define	TCON_PLL_N_MAX			127
+
+#define	CLK_IDX_CH1_SCLK1		0
+#define	CLK_IDX_CH1_SCLK2		1
+
+#define	CLK_IDX_
+
+enum aw_lcdclk_type {
+	AW_LCD_CH0 = 1,
+	AW_LCD_CH1,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-lcd-ch0-clk",	AW_LCD_CH0 },
+	{ "allwinner,sun4i-a10-lcd-ch1-clk",	AW_LCD_CH1 },
+	{ NULL, 0 }
+};
+
+struct aw_lcdclk_softc {
+	enum aw_lcdclk_type	type;
+	device_t		clkdev;
+	bus_addr_t		reg;
+	int			id;
+};
+
+#define	LCDCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	LCDCLK_WRITE(sc, val)	CLKDEV_WRITE_4((sc)->clkdev, (sc)->reg, (val))
+#define	LCDCLK_MODIFY(sc, clr, set)	\
+	CLKDEV_MODIFY_4((sc)->clkdev, (sc)->reg, (clr), (set))
+#define	DEVICE_LOCK(sc)		CLKDEV_DEVICE_LOCK((sc)->clkdev)
+#define	DEVICE_UNLOCK(sc)	CLKDEV_DEVICE_UNLOCK((sc)->clkdev)
+
+static int
+aw_lcdclk_hwreset_assert(device_t dev, intptr_t id, bool value)
+{
+	struct aw_lcdclk_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (sc->type != AW_LCD_CH0)
+		return (ENXIO);
+
+	DEVICE_LOCK(sc);
+	error = LCDCLK_MODIFY(sc, CH0_LCD_RST, value ? 0 : CH0_LCD_RST);
+	DEVICE_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+aw_lcdclk_hwreset_is_asserted(device_t dev, intptr_t id, bool *value)
+{
+	struct aw_lcdclk_softc *sc;
+	uint32_t val;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (sc->type != AW_LCD_CH0)
+		return (ENXIO);
+
+	DEVICE_LOCK(sc);
+	error = LCDCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	if (error)
+		return (error);
+
+	*value = (val & CH0_LCD_RST) != 0 ? false : true;
+
+	return (0);
+}
+
+static int
+aw_lcdclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_lcdclk_softc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	LCDCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	switch (sc->type) {
+	case AW_LCD_CH0:
+		index = (val & CH0_CLK_SRC_SEL) >> CH0_CLK_SRC_SEL_SHIFT;
+		break;
+	case AW_LCD_CH1:
+		switch (sc->id) {
+		case CLK_IDX_CH1_SCLK1:
+			index = 0;
+			break;
+		case CLK_IDX_CH1_SCLK2:
+			index = (val & CH1_SCLK2_SEL_SHIFT) >>
+			    CH1_SCLK2_SEL_SHIFT;
+			break;
+		default:
+			return (ENXIO);
+		}
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	clknode_init_parent_idx(clk, index);
+	return (0);
+}
+
+static int
+aw_lcdclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_lcdclk_softc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_LCD_CH0:
+		DEVICE_LOCK(sc);
+		LCDCLK_READ(sc, &val);
+		val &= ~CH0_CLK_SRC_SEL;
+		val |= (index << CH0_CLK_SRC_SEL_SHIFT);
+		LCDCLK_WRITE(sc, val);
+		DEVICE_UNLOCK(sc);
+		break;
+	case AW_LCD_CH1:
+		switch (sc->id) {
+		case CLK_IDX_CH1_SCLK2:
+			DEVICE_LOCK(sc);
+			LCDCLK_READ(sc, &val);
+			val &= ~CH1_SCLK2_SEL;
+			val |= (index << CH1_SCLK2_SEL_SHIFT);
+			LCDCLK_WRITE(sc, val);
+			DEVICE_UNLOCK(sc);
+			break;
+		default:
+			return (ENXIO);
+		}
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+aw_lcdclk_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_lcdclk_softc *sc;
+	uint32_t val, mask;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_LCD_CH0:
+		mask = CH0_SCLK_GATING;
+		break;
+	case AW_LCD_CH1:
+		mask = (sc->id == CLK_IDX_CH1_SCLK1) ? CH1_SCLK1_GATING :
+		    CH1_SCLK2_GATING;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	DEVICE_LOCK(sc);
+	LCDCLK_READ(sc, &val);
+	if (enable)
+		val |= mask;
+	else
+		val &= ~mask;
+	LCDCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_lcdclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_lcdclk_softc *sc;
+	uint32_t val, m, src_sel;
+
+	sc = clknode_get_softc(clk);
+
+	if (sc->type != AW_LCD_CH1)
+		return (0);
+
+	DEVICE_LOCK(sc);
+	LCDCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	m = ((val & CH1_CLK_DIV_RATIO_M) >> CH1_CLK_DIV_RATIO_M_SHIFT) + 1;
+	*freq = *freq / m;
+
+	if (sc->id == CLK_IDX_CH1_SCLK1) {
+		src_sel = (val & CH1_SCLK1_SEL) >> CH1_SCLK1_SEL_SHIFT;
+		if (src_sel == CH1_SCLK1_SEL_SCLK2_DIV2)
+			*freq /= 2;
+	}
+
+	return (0);
+}
+
+static void
+calc_tcon_pll(uint64_t fin, uint64_t fout, uint32_t *pm, uint32_t *pn)
+{
+	int64_t diff, fcur, best;
+	int m, n;
+
+	best = fout;
+	for (m = TCON_PLL_M_MIN; m <= TCON_PLL_M_MAX; m++) {
+		for (n = TCON_PLL_N_MIN; n <= TCON_PLL_N_MAX; n++) {
+			fcur = (n * fin) / m;
+			diff = (int64_t)fout - fcur;
+			if (diff > 0 && diff < best) {
+				best = diff;
+				*pm = m;
+				*pn = n;
+			}
+		}
+	}
+}
+
+static int
+aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_lcdclk_softc *sc;
+	uint32_t val, m, m2, n, n2, src_sel;
+	uint64_t fsingle, fdouble;
+	int error;
+	bool dbl;
+
+	sc = clknode_get_softc(clk);
+
+	switch (sc->type) {
+	case AW_LCD_CH0:
+		*stop = 0;
+		break;
+	case AW_LCD_CH1:
+		if (sc->id != CLK_IDX_CH1_SCLK2)
+			return (ENXIO);
+
+		m = n = m2 = n2 = 0;
+		dbl = false;
+
+		/* Find the frequency closes to the target dot clock, using
+		 * both 1X and 2X PLL inputs as possible candidates.
+		 */
+		calc_tcon_pll(TCON_PLLREF, *fout, &m, &n);
+		calc_tcon_pll(TCON_PLLREF * 2, *fout, &m2, &n2);
+
+		fsingle = m ? (n * TCON_PLLREF) / m : 0;
+		fdouble = m2 ? (n2 * TCON_PLLREF * 2) / m2 : 0;
+
+		if (fdouble > fsingle) {
+			dbl = true;
+			m = m2;
+			n = n2;
+		}
+
+		src_sel = dbl ? CH0_CLK_SRC_SEL_PLL3_2X :
+		    CH0_CLK_SRC_SEL_PLL3_1X;
+
+		/* Switch parent clock if necessary */
+		if (src_sel != clknode_get_parent_idx(clk)) {
+			error = clknode_set_parent_by_idx(clk, src_sel);
+			if (error != 0)
+				return (error);
+		}
+
+		/* Set desired parent frequency */
+		fin = n * TCON_PLLREF;
+
+		error = clknode_set_freq(clknode_get_parent(clk), fin, 0, 0);
+		if (error != 0)
+			return (error);
+
+		error = clknode_enable(clknode_get_parent(clk));
+		if (error != 0)
+			return (error);
+
+		/* Fetch new input frequency */
+		error = clknode_get_freq(clknode_get_parent(clk), &fin);
+		if (error != 0)
+			return (error);
+
+		/* Set LCD divisor */
+		DEVICE_LOCK(sc);
+		LCDCLK_READ(sc, &val);
+		val &= ~CH1_CLK_DIV_RATIO_M;
+		val |= ((m - 1) << CH1_CLK_DIV_RATIO_M_SHIFT);
+		LCDCLK_WRITE(sc, val);
+		DEVICE_UNLOCK(sc);
+
+		*fout = fin / m;
+		*stop = 1;
+
+		break;
+	}
+
+	return (0);
+}
+
+static clknode_method_t aw_lcdclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_lcdclk_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_lcdclk_set_gate),
+	CLKNODEMETHOD(clknode_set_mux,		aw_lcdclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_lcdclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_freq,		aw_lcdclk_set_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_lcdclk_clknode, aw_lcdclk_clknode_class,
+    aw_lcdclk_clknode_methods, sizeof(struct aw_lcdclk_softc), clknode_class);
+
+static int
+aw_lcdclk_create(device_t dev, struct clkdom *clkdom,
+    const char **parent_names, int parent_cnt, const char *name, int index)
+{
+	struct aw_lcdclk_softc *sc, *clk_sc;
+	struct clknode_init_def def;
+	struct clknode *clk;
+	phandle_t node;
+
+	sc = device_get_softc(dev);
+	node = ofw_bus_get_node(dev);
+
+	memset(&def, 0, sizeof(def));
+	def.id = index;
+	def.name = name;
+	def.parent_names = parent_names;
+	def.parent_cnt = parent_cnt;
+
+	clk = clknode_create(clkdom, &aw_lcdclk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clknode\n");
+		return (ENXIO);
+	}
+
+	clk_sc = clknode_get_softc(clk);
+	clk_sc->type = sc->type;
+	clk_sc->reg = sc->reg;
+	clk_sc->clkdev = sc->clkdev;
+	clk_sc->id = index;
+
+	clknode_register(clkdom, clk);
+
+	return (0);
+}
+
+static int
+aw_lcdclk_probe(device_t dev)
+{
+	enum aw_lcdclk_type type;
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	switch (type) {
+	case AW_LCD_CH0:
+		device_set_desc(dev, "Allwinner LCD CH0 Clock");
+		break;
+	case AW_LCD_CH1:
+		device_set_desc(dev, "Allwinner LCD CH1 Clock");
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_lcdclk_attach(device_t dev)
+{
+	struct aw_lcdclk_softc *sc;
+	struct clkdom *clkdom;
+	clk_t clk_parent;
+	bus_size_t psize;
+	phandle_t node;
+	uint32_t *indices;
+	const char **parent_names;
+	const char **names;
+	int error, ncells, nout, i;
+
+	sc = device_get_softc(dev);
+	sc->clkdev = device_get_parent(dev);
+	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+	node = ofw_bus_get_node(dev);
+
+	if (ofw_reg_to_paddr(node, 0, &sc->reg, &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);
+	}
+
+	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;
+		}
+		parent_names[i] = clk_get_name(clk_parent);
+		clk_release(clk_parent);
+	}
+
+	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
+	if (nout == 0) {
+		device_printf(dev, "no clock outputs found\n");
+		return (error);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	for (i = 0; i < nout; i++) {
+		error = aw_lcdclk_create(dev, clkdom, parent_names, ncells,
+		    names[i], nout == 1 ? 1 : i);
+		if (error)
+			goto fail;
+	}
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(dev, "cannot finalize clkdom initialization\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	if (sc->type == AW_LCD_CH0)
+		hwreset_register_ofw_provider(dev);
+
+	OF_prop_free(parent_names);
+	return (0);
+
+fail:
+	OF_prop_free(parent_names);
+	return (error);
+}
+
+static device_method_t aw_lcdclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_lcdclk_probe),
+	DEVMETHOD(device_attach,	aw_lcdclk_attach),
+
+	/* Reset interface */
+	DEVMETHOD(hwreset_assert,	aw_lcdclk_hwreset_assert),
+	DEVMETHOD(hwreset_is_asserted,	aw_lcdclk_hwreset_is_asserted),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_lcdclk_driver = {
+	"aw_lcdclk",
+	aw_lcdclk_methods,
+	sizeof(struct aw_lcdclk_softc)
+};
+
+static devclass_t aw_lcdclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_lcdclk, simplebus, aw_lcdclk_driver,
+    aw_lcdclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_lcdclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_mmcclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_mmcclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_mmcclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,352 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_mmcclk.c 309756 2016-12-09 20:07:01Z manu $
+ */
+
+/*
+ * Allwinner MMC clocks
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_mmcclk.c 309756 2016-12-09 20:07:01Z manu $");
+
+#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			0x3
+#define	CLK_SRC_SEL_OSC24M		0
+#define	CLK_SRC_SEL_PLL6		1
+#define	CLK_PHASE_CTR			(0x7 << 20)
+#define	CLK_PHASE_CTR_SHIFT		20
+#define	CLK_RATIO_N			(0x3 << 16)
+#define	CLK_RATIO_N_SHIFT		16
+#define	CLK_RATIO_N_MAX			0x3
+#define	OUTPUT_CLK_PHASE_CTR		(0x7 << 8)
+#define	OUTPUT_CLK_PHASE_CTR_SHIFT	8
+#define	CLK_RATIO_M			(0xf << 0)
+#define	CLK_RATIO_M_SHIFT		0
+#define	CLK_RATIO_M_MAX			0xf
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-mmc-clk",	1 },
+	{ NULL, 0 }
+};
+
+struct aw_mmcclk_sc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+};
+
+#define	MODCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	MODCLK_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_mmcclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_mmcclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	MODCLK_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_mmcclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_mmcclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	if (index < 0 || index > CLK_SRC_SEL_MAX)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	MODCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_mmcclk_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_mmcclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	if (enable)
+		val |= SCLK_GATING;
+	else
+		val &= ~SCLK_GATING;
+	MODCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_mmcclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_mmcclk_sc *sc;
+	uint32_t val, m, n;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	n = 1 << ((val & CLK_RATIO_N) >> CLK_RATIO_N_SHIFT);
+	m = ((val & CLK_RATIO_M) >> CLK_RATIO_M_SHIFT) + 1;
+
+	*freq = *freq / n / m;
+
+	return (0);
+}
+
+static int
+aw_mmcclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_mmcclk_sc *sc;
+	uint32_t val, m, n, phase, ophase;
+	int parent_idx, error;
+
+	sc = clknode_get_softc(clk);
+
+	/* XXX
+	 * The ophase/phase values should be set by the MMC driver, but
+	 * there is currently no way to do this with the clk API
+	 */
+	if (*fout <= 400000) {
+		parent_idx = CLK_SRC_SEL_OSC24M;
+		ophase = 0;
+		phase = 0;
+		n = 2;
+	} else if (*fout <= 25000000) {
+		parent_idx = CLK_SRC_SEL_PLL6;
+		ophase = 0;
+		phase = 5;
+		n = 2;
+	} else if (*fout <= 52000000) {
+		parent_idx = CLK_SRC_SEL_PLL6;
+		ophase = 3;
+		phase = 5;
+		n = 0;
+	} else
+		return (ERANGE);
+
+	/* Switch parent clock, if necessary */
+	if (parent_idx != clknode_get_parent_idx(clk)) {
+		error = clknode_set_parent_by_idx(clk, parent_idx);
+		if (error != 0)
+			return (error);
+
+		/* Fetch new input frequency */
+		error = clknode_get_freq(clknode_get_parent(clk), &fin);
+		if (error != 0)
+			return (error);
+	}
+
+	m = ((fin / (1 << n)) / *fout) - 1;
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	val &= ~(CLK_RATIO_N | CLK_RATIO_M | CLK_PHASE_CTR |
+	    OUTPUT_CLK_PHASE_CTR);
+	val |= (n << CLK_RATIO_N_SHIFT);
+	val |= (m << CLK_RATIO_M_SHIFT);
+	val |= (phase << CLK_PHASE_CTR_SHIFT);
+	val |= (ophase << OUTPUT_CLK_PHASE_CTR_SHIFT);
+	MODCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	*fout = fin / (1 << n) / (m + 1);
+	*stop = 1;
+
+	return (0);
+}
+
+static clknode_method_t aw_mmcclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_mmcclk_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_mmcclk_set_gate),
+	CLKNODEMETHOD(clknode_set_mux,		aw_mmcclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_mmcclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_freq,		aw_mmcclk_set_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_mmcclk_clknode, aw_mmcclk_clknode_class,
+    aw_mmcclk_clknode_methods, sizeof(struct aw_mmcclk_sc), clknode_class);
+
+static int
+aw_mmcclk_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 MMC Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_mmcclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_mmcclk_sc *sc;
+	struct clkdom *clkdom;
+	struct clknode *clk;
+	const char **names;
+	uint32_t *indices;
+	clk_t clk_parent;
+	bus_addr_t paddr;
+	bus_size_t psize;
+	phandle_t node;
+	int error, nout, 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 || ncells == 0) {
+		device_printf(dev, "couldn't find parent clocks\n");
+		return (ENXIO);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
+	if (nout == 0) {
+		device_printf(dev, "no output clocks found\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	memset(&def, 0, sizeof(def));
+	def.name = names[0];
+	def.id = 0;
+	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;
+	def.flags = CLK_NODE_GLITCH_FREE;
+
+	clk = clknode_create(clkdom, &aw_mmcclk_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_mmcclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_mmcclk_probe),
+	DEVMETHOD(device_attach,	aw_mmcclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_mmcclk_driver = {
+	"aw_mmcclk",
+	aw_mmcclk_methods,
+	0
+};
+
+static devclass_t aw_mmcclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_mmcclk, simplebus, aw_mmcclk_driver,
+    aw_mmcclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_mmcclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_modclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_modclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_modclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,339 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_modclk.c 309767 2016-12-09 20:52:48Z manu $
+ */
+
+/*
+ * Allwinner module clocks
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_modclk.c 309767 2016-12-09 20:52:48Z manu $");
+
+#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_RATIO_N		(0x3 << 16)
+#define	CLK_RATIO_N_SHIFT	16
+#define	CLK_RATIO_N_MAX		0x3
+#define	CLK_RATIO_M		(0x1f << 0)
+#define	CLK_RATIO_M_SHIFT	0
+#define	CLK_RATIO_M_MAX		0x1f
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-mod0-clk",	1 },
+	{ NULL, 0 }
+};
+
+struct aw_modclk_sc {
+	device_t	clkdev;
+	bus_addr_t	reg;
+	u_int		parent_cnt;
+};
+
+#define	MODCLK_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	MODCLK_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_modclk_init(struct clknode *clk, device_t dev)
+{
+	struct aw_modclk_sc *sc;
+	uint32_t val, index;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	MODCLK_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_modclk_set_mux(struct clknode *clk, int index)
+{
+	struct aw_modclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	if (index < 0 || index >= sc->parent_cnt)
+		return (ERANGE);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	val &= ~CLK_SRC_SEL;
+	val |= (index << CLK_SRC_SEL_SHIFT);
+	MODCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_modclk_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_modclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	if (enable)
+		val |= SCLK_GATING;
+	else
+		val &= ~SCLK_GATING;
+	MODCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_modclk_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_modclk_sc *sc;
+	uint32_t val, m, n;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	n = 1 << ((val & CLK_RATIO_N) >> CLK_RATIO_N_SHIFT);
+	m = ((val & CLK_RATIO_M) >> CLK_RATIO_M_SHIFT) + 1;
+
+	*freq = *freq / n / m;
+
+	return (0);
+}
+
+static int
+aw_modclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_modclk_sc *sc;
+	uint32_t val, m, n, src, best_m, best_n, best_src;
+	uint64_t cur_freq;
+	int64_t best_diff, cur_diff;
+	int error;
+
+	sc = clknode_get_softc(clk);
+	best_n = best_m = 0;
+	best_diff = (int64_t)*fout; 
+	best_src = 0;
+
+	for (src = 0; src < sc->parent_cnt; src++) {
+		error = clknode_set_parent_by_idx(clk, src);
+		if (error != 0)
+			continue;
+		error = clknode_get_freq(clknode_get_parent(clk), &fin);
+		if (error != 0)
+			continue;
+
+		for (n = 0; n <= CLK_RATIO_N_MAX; n++)
+			for (m = 0; m <= CLK_RATIO_M_MAX; m++) {
+				cur_freq = fin / (1 << n) / (m + 1);
+				cur_diff = (int64_t)*fout - cur_freq;
+				if (cur_diff >= 0 && cur_diff < best_diff) {
+					best_src = src;
+					best_diff = cur_diff;
+					best_m = m;
+					best_n = n;
+				}
+			}
+	}
+
+	if (best_diff == (int64_t)*fout)
+		return (ERANGE);
+
+	error = clknode_set_parent_by_idx(clk, best_src);
+	if (error != 0)
+		return (error);
+	error = clknode_get_freq(clknode_get_parent(clk), &fin);
+	if (error != 0)
+		return (error);
+
+	DEVICE_LOCK(sc);
+	MODCLK_READ(sc, &val);
+	val &= ~(CLK_RATIO_N | CLK_RATIO_M);
+	val |= (best_n << CLK_RATIO_N_SHIFT);
+	val |= (best_m << CLK_RATIO_M_SHIFT);
+	MODCLK_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	*fout = fin / (1 << best_n) / (best_m + 1);
+	*stop = 1;
+
+	return (0);
+}
+
+static clknode_method_t aw_modclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_modclk_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_modclk_set_gate),
+	CLKNODEMETHOD(clknode_set_mux,		aw_modclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_modclk_recalc_freq),
+	CLKNODEMETHOD(clknode_set_freq,		aw_modclk_set_freq),
+	CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(aw_modclk_clknode, aw_modclk_clknode_class,
+    aw_modclk_clknode_methods, sizeof(struct aw_modclk_sc), clknode_class);
+
+static int
+aw_modclk_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 Module Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_modclk_attach(device_t dev)
+{
+	struct clknode_init_def def;
+	struct aw_modclk_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_modclk_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);
+	sc->parent_cnt = def.parent_cnt;
+
+	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_modclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_modclk_probe),
+	DEVMETHOD(device_attach,	aw_modclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_modclk_driver = {
+	"aw_modclk",
+	aw_modclk_methods,
+	0
+};
+
+static devclass_t aw_modclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_modclk, simplebus, aw_modclk_driver,
+    aw_modclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_modclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_oscclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_oscclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_oscclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,133 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_oscclk.c 299703 2016-05-13 22:28:02Z gonzo $
+ */
+
+/*
+ * Allwinner oscillator clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_oscclk.c 299703 2016-05-13 22:28:02Z gonzo $");
+
+#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 <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk_fixed.h>
+
+static int
+aw_oscclk_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-osc-clk"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner Oscillator Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_oscclk_attach(device_t dev)
+{
+	struct clk_fixed_def def;
+	struct clkdom *clkdom;
+	phandle_t node;
+	uint32_t freq;
+	int error;
+
+	node = ofw_bus_get_node(dev);
+
+	if (OF_getencprop(node, "clock-frequency", &freq,  sizeof(freq)) <= 0) {
+		device_printf(dev, "missing clock-frequency property\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	clkdom = clkdom_create(dev);
+
+	memset(&def, 0, sizeof(def));
+	def.clkdef.id = 1;
+	def.freq = freq;
+	error = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock name\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	error = clknode_fixed_register(clkdom, &def);
+	if (error != 0) {
+		device_printf(dev, "cannot register fixed clock\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(dev, "cannot finalize clkdom initialization\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	OF_prop_free(__DECONST(char *, def.clkdef.name));
+
+	return (0);
+
+fail:
+	OF_prop_free(__DECONST(char *, def.clkdef.name));
+	return (error);
+}
+
+static device_method_t aw_oscclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_oscclk_probe),
+	DEVMETHOD(device_attach,	aw_oscclk_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_oscclk_driver = {
+	"aw_oscclk",
+	aw_oscclk_methods,
+	0,
+};
+
+static devclass_t aw_oscclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_oscclk, simplebus, aw_oscclk_driver,
+    aw_oscclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_oscclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_pll.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_pll.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_pll.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,903 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_pll.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner PLL clock
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_pll.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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.h>
+
+#include <dt-bindings/clock/sun4i-a10-pll2.h>
+
+#include <arm/allwinner/aw_machdep.h>
+
+#include "clkdev_if.h"
+
+#define	AW_PLL_ENABLE			(1 << 31)
+
+#define	A10_PLL1_OUT_EXT_DIVP		(0x3 << 16)
+#define	A10_PLL1_OUT_EXT_DIVP_SHIFT	16
+#define	A10_PLL1_FACTOR_N		(0x1f << 8)
+#define	A10_PLL1_FACTOR_N_SHIFT		8
+#define	A10_PLL1_FACTOR_K		(0x3 << 4)
+#define	A10_PLL1_FACTOR_K_SHIFT		4
+#define	A10_PLL1_FACTOR_M		(0x3 << 0)
+#define	A10_PLL1_FACTOR_M_SHIFT		0
+
+#define	A10_PLL2_POST_DIV		(0xf << 26)
+#define	A10_PLL2_POST_DIV_SHIFT		26
+#define	A10_PLL2_FACTOR_N		(0x7f << 8)
+#define	A10_PLL2_FACTOR_N_SHIFT		8
+#define	A10_PLL2_PRE_DIV		(0x1f << 0)
+#define	A10_PLL2_PRE_DIV_SHIFT		0
+
+#define	A10_PLL3_MODE_SEL		(0x1 << 15)
+#define	A10_PLL3_MODE_SEL_FRACT		(0 << 15)
+#define	A10_PLL3_MODE_SEL_INT		(1 << 15)
+#define	A10_PLL3_FUNC_SET		(0x1 << 14)
+#define	A10_PLL3_FUNC_SET_270MHZ	(0 << 14)
+#define	A10_PLL3_FUNC_SET_297MHZ	(1 << 14)
+#define	A10_PLL3_FACTOR_M		(0x7f << 0)
+#define	A10_PLL3_FACTOR_M_SHIFT		0
+#define	A10_PLL3_REF_FREQ		3000000
+
+#define	A10_PLL5_OUT_EXT_DIVP		(0x3 << 16)
+#define	A10_PLL5_OUT_EXT_DIVP_SHIFT	16
+#define	A10_PLL5_FACTOR_N		(0x1f << 8)
+#define	A10_PLL5_FACTOR_N_SHIFT		8
+#define	A10_PLL5_FACTOR_K		(0x3 << 4)
+#define	A10_PLL5_FACTOR_K_SHIFT		4
+#define	A10_PLL5_FACTOR_M1		(0x3 << 2)
+#define	A10_PLL5_FACTOR_M1_SHIFT	2
+#define	A10_PLL5_FACTOR_M		(0x3 << 0)
+#define	A10_PLL5_FACTOR_M_SHIFT		0
+
+#define	A10_PLL6_BYPASS_EN		(1 << 30)
+#define	A10_PLL6_SATA_CLK_EN		(1 << 14)
+#define	A10_PLL6_FACTOR_N		(0x1f << 8)
+#define	A10_PLL6_FACTOR_N_SHIFT		8
+#define	A10_PLL6_FACTOR_K		(0x3 << 4)
+#define	A10_PLL6_FACTOR_K_SHIFT		4
+#define	A10_PLL6_FACTOR_M		(0x3 << 0)
+#define	A10_PLL6_FACTOR_M_SHIFT		0
+
+#define	A10_PLL2_POST_DIV		(0xf << 26)
+
+#define	A13_PLL2_POST_DIV		(0xf << 26)
+#define	A13_PLL2_POST_DIV_SHIFT		26
+#define	A13_PLL2_FACTOR_N		(0x7f << 8)
+#define	A13_PLL2_FACTOR_N_SHIFT		8
+#define	A13_PLL2_PRE_DIV		(0x1f << 0)
+#define	A13_PLL2_PRE_DIV_SHIFT		0
+
+#define	A23_PLL1_FACTOR_N		(0x1f << 8)
+#define	A23_PLL1_FACTOR_N_SHIFT		8
+#define	A23_PLL1_FACTOR_K		(0x3 << 4)
+#define	A23_PLL1_FACTOR_K_SHIFT		4
+#define	A23_PLL1_FACTOR_M		(0x3 << 0)
+#define	A23_PLL1_FACTOR_M_SHIFT		0
+#define	A23_PLL1_FACTOR_P		(0x3 << 16)
+#define	A23_PLL1_FACTOR_P_SHIFT		16
+
+#define	A31_PLL1_LOCK			(1 << 28)
+#define	A31_PLL1_CPU_SIGMA_DELTA_EN	(1 << 24)
+#define	A31_PLL1_FACTOR_N		(0x1f << 8)
+#define	A31_PLL1_FACTOR_N_SHIFT		8
+#define	A31_PLL1_FACTOR_K		(0x3 << 4)
+#define	A31_PLL1_FACTOR_K_SHIFT		4
+#define	A31_PLL1_FACTOR_M		(0x3 << 0)
+#define	A31_PLL1_FACTOR_M_SHIFT		0
+
+#define	A31_PLL6_LOCK			(1 << 28)
+#define	A31_PLL6_BYPASS_EN		(1 << 25)
+#define	A31_PLL6_CLK_OUT_EN		(1 << 24)
+#define	A31_PLL6_24M_OUT_EN		(1 << 18)
+#define	A31_PLL6_24M_POST_DIV		(0x3 << 16)
+#define	A31_PLL6_24M_POST_DIV_SHIFT	16
+#define	A31_PLL6_FACTOR_N		(0x1f << 8)
+#define	A31_PLL6_FACTOR_N_SHIFT		8
+#define	A31_PLL6_FACTOR_K		(0x3 << 4)
+#define	A31_PLL6_FACTOR_K_SHIFT		4
+#define	A31_PLL6_DEFAULT_N		0x18
+#define	A31_PLL6_DEFAULT_K		0x1
+#define	A31_PLL6_TIMEOUT		10
+
+#define	A80_PLL4_CLK_OUT_EN		(1 << 20)
+#define	A80_PLL4_PLL_DIV2		(1 << 18)
+#define	A80_PLL4_PLL_DIV1		(1 << 16)
+#define	A80_PLL4_FACTOR_N		(0xff << 8)
+#define	A80_PLL4_FACTOR_N_SHIFT		8
+
+#define	CLKID_A10_PLL3_1X		0
+#define	CLKID_A10_PLL3_2X		1
+
+#define	CLKID_A10_PLL5_DDR		0
+#define	CLKID_A10_PLL5_OTHER		1
+
+#define	CLKID_A10_PLL6_SATA		0
+#define	CLKID_A10_PLL6_OTHER		1
+#define	CLKID_A10_PLL6			2
+#define	CLKID_A10_PLL6_DIV_4		3
+
+#define	CLKID_A31_PLL6			0
+#define	CLKID_A31_PLL6_X2		1
+
+enum aw_pll_type {
+	AWPLL_A10_PLL1 = 1,
+	AWPLL_A10_PLL2,
+	AWPLL_A10_PLL3,
+	AWPLL_A10_PLL5,
+	AWPLL_A10_PLL6,
+	AWPLL_A13_PLL2,
+	AWPLL_A23_PLL1,
+	AWPLL_A31_PLL1,
+	AWPLL_A31_PLL6,
+	AWPLL_A80_PLL4,
+};
+
+struct aw_pll_sc {
+	enum aw_pll_type	type;
+	device_t		clkdev;
+	bus_addr_t		reg;
+	int			id;
+};
+
+struct aw_pll_funcs {
+	int	(*recalc)(struct aw_pll_sc *, uint64_t *);
+	int	(*set_freq)(struct aw_pll_sc *, uint64_t, uint64_t *, int);
+	int	(*init)(device_t, bus_addr_t, struct clknode_init_def *);
+};
+
+#define	PLL_READ(sc, val)	CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
+#define	PLL_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
+a10_pll1_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, m, n, k, p;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	p = 1 << ((val & A10_PLL1_OUT_EXT_DIVP) >> A10_PLL1_OUT_EXT_DIVP_SHIFT);
+	m = ((val & A10_PLL1_FACTOR_M) >> A10_PLL1_FACTOR_M_SHIFT) + 1;
+	k = ((val & A10_PLL1_FACTOR_K) >> A10_PLL1_FACTOR_K_SHIFT) + 1;
+	n = (val & A10_PLL1_FACTOR_N) >> A10_PLL1_FACTOR_N_SHIFT;
+	if (n == 0)
+		n = 1;
+
+	*freq = (*freq * n * k) / (m * p);
+
+	return (0);
+}
+
+static int
+a10_pll2_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, post_div, n, pre_div;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	post_div = (val & A10_PLL2_POST_DIV) >> A10_PLL2_POST_DIV_SHIFT;
+	if (post_div == 0)
+		post_div = 1;
+	n = (val & A10_PLL2_FACTOR_N) >> A10_PLL2_FACTOR_N_SHIFT;
+	if (n == 0)
+		n = 1;
+	pre_div = (val & A10_PLL2_PRE_DIV) >> A10_PLL2_PRE_DIV_SHIFT;
+	if (pre_div == 0)
+		pre_div = 1;
+
+	switch (sc->id) {
+	case SUN4I_A10_PLL2_1X:
+		*freq = (*freq * 2 * n) / pre_div / post_div / 2;
+		break;
+	case SUN4I_A10_PLL2_2X:
+		*freq = (*freq * 2 * n) / pre_div / 4;
+		break;
+	case SUN4I_A10_PLL2_4X:
+		*freq = (*freq * 2 * n) / pre_div / 2;
+		break;
+	case SUN4I_A10_PLL2_8X:
+		*freq = (*freq * 2 * n) / pre_div;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+a10_pll2_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
+    int flags)
+{
+	uint32_t val, post_div, n, pre_div;
+
+	if (sc->id != SUN4I_A10_PLL2_1X)
+		return (ENXIO);
+
+	/*
+	 * Audio Codec needs PLL2-1X to be either 24576000 or 22579200.
+	 *
+	 * PLL2-1X output frequency is (48MHz * n) / pre_div / post_div / 2.
+	 * To get as close as possible to the desired rate, we use a
+	 * pre-divider of 21 and a post-divider of 4. With these values,
+	 * a multiplier of 86 or 79 gets us close to the target rates.
+	 */
+	if (*fout != 24576000 && *fout != 22579200)
+		return (EINVAL);
+
+	pre_div = 21;
+	post_div = 4;
+	n = (*fout * pre_div * post_div * 2) / (2 * fin);
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	val &= ~(A10_PLL2_POST_DIV | A10_PLL2_FACTOR_N | A10_PLL2_PRE_DIV);
+	val |= (post_div << A10_PLL2_POST_DIV_SHIFT);
+	val |= (n << A10_PLL2_FACTOR_N_SHIFT);
+	val |= (pre_div << A10_PLL2_PRE_DIV_SHIFT);
+	PLL_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+a10_pll3_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, m;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	if ((val & A10_PLL3_MODE_SEL) == A10_PLL3_MODE_SEL_INT) {
+		/* In integer mode, output is 3MHz * m */
+		m = (val & A10_PLL3_FACTOR_M) >> A10_PLL3_FACTOR_M_SHIFT;
+		*freq = A10_PLL3_REF_FREQ * m;
+	} else {
+		/* In fractional mode, output is either 270MHz or 297MHz */
+		if ((val & A10_PLL3_FUNC_SET) == A10_PLL3_FUNC_SET_270MHZ)
+			*freq = 270000000;
+		else
+			*freq = 297000000;
+	}
+
+	if (sc->id == CLKID_A10_PLL3_2X)
+		*freq *= 2;
+
+	return (0);
+}
+
+static int
+a10_pll3_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
+    int flags)
+{
+	uint32_t val, m, mode, func;
+
+	m = *fout / A10_PLL3_REF_FREQ;
+	if (sc->id == CLKID_A10_PLL3_2X)
+		m /= 2;
+
+	mode = A10_PLL3_MODE_SEL_INT;
+	func = 0;
+	*fout = m * A10_PLL3_REF_FREQ;
+	if (sc->id == CLKID_A10_PLL3_2X)
+		*fout *= 2;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	val &= ~(A10_PLL3_MODE_SEL | A10_PLL3_FUNC_SET | A10_PLL3_FACTOR_M);
+	val |= mode;
+	val |= func;
+	val |= (m << A10_PLL3_FACTOR_M_SHIFT);
+	PLL_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+a10_pll3_init(device_t dev, bus_addr_t reg, struct clknode_init_def *def)
+{
+	uint32_t val;
+
+	/* Allow changing PLL frequency while enabled */
+	def->flags = CLK_NODE_GLITCH_FREE;
+
+	/* Set PLL to 297MHz */
+	CLKDEV_DEVICE_LOCK(dev);
+	CLKDEV_READ_4(dev, reg, &val);
+	val &= ~(A10_PLL3_MODE_SEL | A10_PLL3_FUNC_SET | A10_PLL3_FACTOR_M);
+	val |= A10_PLL3_MODE_SEL_FRACT;
+	val |= A10_PLL3_FUNC_SET_297MHZ;
+	CLKDEV_WRITE_4(dev, reg, val);
+	CLKDEV_DEVICE_UNLOCK(dev);
+
+	return (0);
+}
+
+static int
+a10_pll5_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, m, n, k, p;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	p = 1 << ((val & A10_PLL5_OUT_EXT_DIVP) >> A10_PLL5_OUT_EXT_DIVP_SHIFT);
+	m = ((val & A10_PLL5_FACTOR_M) >> A10_PLL5_FACTOR_M_SHIFT) + 1;
+	k = ((val & A10_PLL5_FACTOR_K) >> A10_PLL5_FACTOR_K_SHIFT) + 1;
+	n = (val & A10_PLL5_FACTOR_N) >> A10_PLL5_FACTOR_N_SHIFT;
+	if (n == 0)
+		return (ENXIO);
+
+	switch (sc->id) {
+	case CLKID_A10_PLL5_DDR:
+		*freq = (*freq * n * k) / m;
+		break;
+	case CLKID_A10_PLL5_OTHER:
+		*freq = (*freq * n * k) / p;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+a10_pll6_init(device_t dev, bus_addr_t reg, struct clknode_init_def *def)
+{
+	uint32_t val, m, n, k;
+
+	/*
+	 * SATA needs PLL6 to be a 100MHz clock.
+	 *
+	 * The SATA output frequency is (24MHz * n * k) / m / 6.
+	 * To get to 100MHz, k & m must be equal and n must be 25.
+	 */
+	m = k = 0;
+	n = 25;
+
+	CLKDEV_DEVICE_LOCK(dev);
+	CLKDEV_READ_4(dev, reg, &val);
+	val &= ~(A10_PLL6_FACTOR_N | A10_PLL6_FACTOR_K | A10_PLL6_FACTOR_M);
+	val &= ~A10_PLL6_BYPASS_EN;
+	val |= A10_PLL6_SATA_CLK_EN;
+	val |= (n << A10_PLL6_FACTOR_N_SHIFT);
+	val |= (k << A10_PLL6_FACTOR_K_SHIFT);
+	val |= (m << A10_PLL6_FACTOR_M_SHIFT);
+	CLKDEV_WRITE_4(dev, reg, val);
+	CLKDEV_DEVICE_UNLOCK(dev);
+
+	return (0);
+}
+
+static int
+a10_pll6_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, m, k, n;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	m = ((val & A10_PLL6_FACTOR_M) >> A10_PLL6_FACTOR_M_SHIFT) + 1;
+	k = ((val & A10_PLL6_FACTOR_K) >> A10_PLL6_FACTOR_K_SHIFT) + 1;
+	n = (val & A10_PLL6_FACTOR_N) >> A10_PLL6_FACTOR_N_SHIFT;
+	if (n == 0)
+		return (ENXIO);
+
+	switch (sc->id) {
+	case CLKID_A10_PLL6_SATA:
+		*freq = (*freq * n * k) / m / 6;
+		break;
+	case CLKID_A10_PLL6_OTHER:
+		*freq = (*freq * n * k) / 2;
+		break;
+	case CLKID_A10_PLL6:
+		*freq = (*freq * n * k);
+		break;
+	case CLKID_A10_PLL6_DIV_4:
+		*freq = (*freq * n * k) / 4;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+a10_pll6_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
+    int flags)
+{
+	if (sc->id != CLKID_A10_PLL6_SATA)
+		return (ENXIO);
+
+	/* PLL6 SATA output has been set to 100MHz in a10_pll6_init */
+	if (*fout != 100000000)
+		return (ERANGE);
+
+	return (0);
+}
+
+static int
+a13_pll2_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, post_div, n, pre_div;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	post_div = ((val & A13_PLL2_POST_DIV) >> A13_PLL2_POST_DIV_SHIFT) + 1;
+	if (post_div == 0)
+		post_div = 1;
+	n = (val & A13_PLL2_FACTOR_N) >> A13_PLL2_FACTOR_N_SHIFT;
+	if (n == 0)
+		n = 1;
+	pre_div = ((val & A13_PLL2_PRE_DIV) >> A13_PLL2_PRE_DIV_SHIFT) + 1;
+	if (pre_div == 0)
+		pre_div = 1;
+
+	switch (sc->id) {
+	case SUN4I_A10_PLL2_1X:
+		*freq = (*freq * 2 * n) / pre_div / post_div / 2;
+		break;
+	case SUN4I_A10_PLL2_2X:
+		*freq = (*freq * 2 * n) / pre_div / 4;
+		break;
+	case SUN4I_A10_PLL2_4X:
+		*freq = (*freq * 2 * n) / pre_div / 2;
+		break;
+	case SUN4I_A10_PLL2_8X:
+		*freq = (*freq * 2 * n) / pre_div;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+a13_pll2_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
+    int flags)
+{
+	uint32_t val, post_div, n, pre_div;
+
+	if (sc->id != SUN4I_A10_PLL2_1X)
+		return (ENXIO);
+
+	/*
+	 * Audio Codec needs PLL2-1X to be either 24576000 or 22579200.
+	 *
+	 * PLL2-1X output frequency is (48MHz * n) / pre_div / post_div / 2.
+	 * To get as close as possible to the desired rate, we use a
+	 * pre-divider of 21 and a post-divider of 4. With these values,
+	 * a multiplier of 86 or 79 gets us close to the target rates.
+	 */
+	if (*fout != 24576000 && *fout != 22579200)
+		return (EINVAL);
+
+	pre_div = 21;
+	post_div = 4;
+	n = (*fout * pre_div * post_div * 2) / (2 * fin);
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	val &= ~(A13_PLL2_POST_DIV | A13_PLL2_FACTOR_N | A13_PLL2_PRE_DIV);
+	val |= ((post_div - 1) << A13_PLL2_POST_DIV_SHIFT);
+	val |= (n << A13_PLL2_FACTOR_N_SHIFT);
+	val |= ((pre_div - 1) << A13_PLL2_PRE_DIV_SHIFT);
+	PLL_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+a23_pll1_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, m, n, k, p;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	m = ((val & A23_PLL1_FACTOR_M) >> A23_PLL1_FACTOR_M_SHIFT) + 1;
+	k = ((val & A23_PLL1_FACTOR_K) >> A23_PLL1_FACTOR_K_SHIFT) + 1;
+	n = ((val & A23_PLL1_FACTOR_N) >> A23_PLL1_FACTOR_N_SHIFT) + 1;
+	p = ((val & A23_PLL1_FACTOR_P) >> A23_PLL1_FACTOR_P_SHIFT) + 1;
+
+	*freq = (*freq * n * k) / (m * p);
+
+	return (0);
+}
+
+static int
+a31_pll1_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, m, n, k;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	m = ((val & A31_PLL1_FACTOR_M) >> A31_PLL1_FACTOR_M_SHIFT) + 1;
+	k = ((val & A31_PLL1_FACTOR_K) >> A31_PLL1_FACTOR_K_SHIFT) + 1;
+	n = ((val & A31_PLL1_FACTOR_N) >> A31_PLL1_FACTOR_N_SHIFT) + 1;
+
+	*freq = (*freq * n * k) / m;
+
+	return (0);
+}
+
+static int
+a31_pll6_init(device_t dev, bus_addr_t reg, struct clknode_init_def *def)
+{
+	uint32_t val;
+	int retry;
+
+	if (def->id != CLKID_A31_PLL6)
+		return (0);
+
+	/*
+	 * The datasheet recommends that PLL6 output should be fixed to
+	 * 600MHz.
+	 */
+	CLKDEV_DEVICE_LOCK(dev);
+	CLKDEV_READ_4(dev, reg, &val);
+	val &= ~(A31_PLL6_FACTOR_N | A31_PLL6_FACTOR_K | A31_PLL6_BYPASS_EN);
+	val |= (A31_PLL6_DEFAULT_N << A31_PLL6_FACTOR_N_SHIFT);
+	val |= (A31_PLL6_DEFAULT_K << A31_PLL6_FACTOR_K_SHIFT);
+	CLKDEV_WRITE_4(dev, reg, val);
+
+	/* Wait for PLL to become stable */
+	for (retry = A31_PLL6_TIMEOUT; retry > 0; retry--) {
+		CLKDEV_READ_4(dev, reg, &val);
+		if ((val & A31_PLL6_LOCK) == A31_PLL6_LOCK)
+			break;
+		DELAY(1);
+	}
+
+	CLKDEV_DEVICE_UNLOCK(dev);
+
+	if (retry == 0)
+		return (ETIMEDOUT);
+
+	return (0);
+}
+
+static int
+a31_pll6_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, k, n;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	k = ((val & A10_PLL6_FACTOR_K) >> A10_PLL6_FACTOR_K_SHIFT) + 1;
+	n = ((val & A10_PLL6_FACTOR_N) >> A10_PLL6_FACTOR_N_SHIFT) + 1;
+
+	switch (sc->id) {
+	case CLKID_A31_PLL6:
+		*freq = (*freq * n * k) / 2;
+		break;
+	case CLKID_A31_PLL6_X2:
+		*freq = *freq * n * k;
+		break;
+	default:
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+a80_pll4_recalc(struct aw_pll_sc *sc, uint64_t *freq)
+{
+	uint32_t val, n, div1, div2;
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	DEVICE_UNLOCK(sc);
+
+	n = (val & A80_PLL4_FACTOR_N) >> A80_PLL4_FACTOR_N_SHIFT;
+	div1 = (val & A80_PLL4_PLL_DIV1) == 0 ? 1 : 2;
+	div2 = (val & A80_PLL4_PLL_DIV2) == 0 ? 1 : 2;
+
+	*freq = (*freq * n) / div1 / div2;
+
+	return (0);
+}
+
+#define	PLL(_type, _recalc, _set_freq, _init)	\
+	[(_type)] = {				\
+		.recalc = (_recalc),		\
+		.set_freq = (_set_freq),	\
+		.init = (_init)			\
+	}
+
+static struct aw_pll_funcs aw_pll_func[] = {
+	PLL(AWPLL_A10_PLL1, a10_pll1_recalc, NULL, NULL),
+	PLL(AWPLL_A10_PLL2, a10_pll2_recalc, a10_pll2_set_freq, NULL),
+	PLL(AWPLL_A10_PLL3, a10_pll3_recalc, a10_pll3_set_freq, a10_pll3_init),
+	PLL(AWPLL_A10_PLL5, a10_pll5_recalc, NULL, NULL),
+	PLL(AWPLL_A10_PLL6, a10_pll6_recalc, a10_pll6_set_freq, a10_pll6_init),
+	PLL(AWPLL_A13_PLL2, a13_pll2_recalc, a13_pll2_set_freq, NULL),
+	PLL(AWPLL_A23_PLL1, a23_pll1_recalc, NULL, NULL),
+	PLL(AWPLL_A31_PLL1, a31_pll1_recalc, NULL, NULL),
+	PLL(AWPLL_A31_PLL6, a31_pll6_recalc, NULL, a31_pll6_init),
+	PLL(AWPLL_A80_PLL4, a80_pll4_recalc, NULL, NULL),
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-pll1-clk",	AWPLL_A10_PLL1 },
+	{ "allwinner,sun4i-a10-pll2-clk",	AWPLL_A10_PLL2 },
+	{ "allwinner,sun4i-a10-pll3-clk",	AWPLL_A10_PLL3 },
+	{ "allwinner,sun4i-a10-pll5-clk",	AWPLL_A10_PLL5 },
+	{ "allwinner,sun4i-a10-pll6-clk",	AWPLL_A10_PLL6 },
+	{ "allwinner,sun5i-a13-pll2-clk",	AWPLL_A13_PLL2 },
+	{ "allwinner,sun6i-a31-pll1-clk",	AWPLL_A31_PLL1 },
+	{ "allwinner,sun6i-a31-pll6-clk",	AWPLL_A31_PLL6 },
+	{ "allwinner,sun8i-a23-pll1-clk",	AWPLL_A23_PLL1 },
+	{ "allwinner,sun9i-a80-pll4-clk",	AWPLL_A80_PLL4 },
+	{ NULL, 0 }
+};
+
+static int
+aw_pll_init(struct clknode *clk, device_t dev)
+{
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+aw_pll_set_gate(struct clknode *clk, bool enable)
+{
+	struct aw_pll_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(sc);
+	PLL_READ(sc, &val);
+	if (enable)
+		val |= AW_PLL_ENABLE;
+	else
+		val &= ~AW_PLL_ENABLE;
+	PLL_WRITE(sc, val);
+	DEVICE_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+aw_pll_recalc(struct clknode *clk, uint64_t *freq)
+{
+	struct aw_pll_sc *sc;
+
+	sc = clknode_get_softc(clk);
+
+	if (aw_pll_func[sc->type].recalc == NULL)
+		return (ENXIO);
+
+	return (aw_pll_func[sc->type].recalc(sc, freq));
+}
+
+static int
+aw_pll_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct aw_pll_sc *sc;
+
+	sc = clknode_get_softc(clk);
+
+	*stop = 1;
+
+	if (aw_pll_func[sc->type].set_freq == NULL)
+		return (ENXIO);
+
+	return (aw_pll_func[sc->type].set_freq(sc, fin, fout, flags));
+}
+
+static clknode_method_t aw_pll_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		aw_pll_init),
+	CLKNODEMETHOD(clknode_set_gate,		aw_pll_set_gate),
+	CLKNODEMETHOD(clknode_recalc_freq,	aw_pll_recalc),
+	CLKNODEMETHOD(clknode_set_freq,		aw_pll_set_freq),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(aw_pll_clknode, aw_pll_clknode_class, aw_pll_clknode_methods,
+    sizeof(struct aw_pll_sc), clknode_class);
+
+static int
+aw_pll_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom,
+    const char *pclkname, const char *clkname, int index)
+{
+	enum aw_pll_type type;
+	struct clknode_init_def clkdef;
+	struct aw_pll_sc *sc;
+	struct clknode *clk;
+	int error;
+
+	type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+	memset(&clkdef, 0, sizeof(clkdef));
+	clkdef.id = index;
+	clkdef.name = clkname;
+	if (pclkname != NULL) {
+		clkdef.parent_names = malloc(sizeof(char *), M_OFWPROP,
+		    M_WAITOK);
+		clkdef.parent_names[0] = pclkname;
+		clkdef.parent_cnt = 1;
+	} else
+		clkdef.parent_cnt = 0;
+
+	if (aw_pll_func[type].init != NULL) {
+		error = aw_pll_func[type].init(device_get_parent(dev),
+		    paddr, &clkdef);
+		if (error != 0) {
+			device_printf(dev, "clock %s init failed\n", clkname);
+			return (error);
+		}
+	}
+
+	clk = clknode_create(clkdom, &aw_pll_clknode_class, &clkdef);
+	if (clk == NULL) {
+		device_printf(dev, "cannot create clock node\n");
+		return (ENXIO);
+	}
+	sc = clknode_get_softc(clk);
+	sc->clkdev = device_get_parent(dev);
+	sc->reg = paddr;
+	sc->type = type;
+	sc->id = clkdef.id;
+
+	clknode_register(clkdom, clk);
+
+	OF_prop_free(__DECONST(char *, clkdef.parent_names));
+
+	return (0);
+}
+
+static int
+aw_pll_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 PLL Clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_pll_attach(device_t dev)
+{
+	struct clkdom *clkdom;
+	const char **names;
+	int index, nout, error;
+	clk_t clk_parent;
+	uint32_t *indices;
+	bus_addr_t paddr;
+	bus_size_t psize;
+	phandle_t node;
+
+	node = ofw_bus_get_node(dev);
+
+	if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
+		device_printf(dev, "couldn't parse 'reg' property\n");
+		return (ENXIO);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
+	if (nout == 0) {
+		device_printf(dev, "no clock outputs found\n");
+		error = ENOENT;
+		goto fail;
+	}
+
+	if (clk_get_by_ofw_index(dev, 0, 0, &clk_parent) != 0)
+		clk_parent = NULL;
+
+	for (index = 0; index < nout; index++) {
+		error = aw_pll_create(dev, paddr, clkdom,
+		    clk_parent ? clk_get_name(clk_parent) : NULL,
+		    names[index], nout == 1 ? 1 : index);
+		if (error)
+			goto fail;
+	}
+
+	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_pll_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_pll_probe),
+	DEVMETHOD(device_attach,	aw_pll_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_pll_driver = {
+	"aw_pll",
+	aw_pll_methods,
+	0,
+};
+
+static devclass_t aw_pll_devclass;
+
+EARLY_DRIVER_MODULE(aw_pll, simplebus, aw_pll_driver,
+    aw_pll_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_pll.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/arm/allwinner/clk/aw_usbclk.c
===================================================================
--- trunk/sys/arm/allwinner/clk/aw_usbclk.c	                        (rev 0)
+++ trunk/sys/arm/allwinner/clk/aw_usbclk.c	2020-03-06 17:15:48 UTC (rev 12400)
@@ -0,0 +1,268 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/11/sys/arm/allwinner/clk/aw_usbclk.c 308324 2016-11-05 04:17:32Z mmel $
+ */
+
+/*
+ * Allwinner USB clocks
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_usbclk.c 308324 2016-11-05 04:17:32Z mmel $");
+
+#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_gate.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+
+#define	A10_SCLK_GATING_USBPHY	(1 << 8)
+#define	A10_SCLK_GATING_OHCI1	(1 << 7)
+#define	A10_SCLK_GATING_OHCI0	(1 << 6)
+
+#define	USBPHY2_RST		(1 << 2)
+#define	USBPHY1_RST		(1 << 1)
+#define	USBPHY0_RST		(1 << 0)
+
+enum aw_usbclk_type {
+	AW_A10_USBCLK = 1,
+	AW_A13_USBCLK,
+	AW_A31_USBCLK,
+	AW_A83T_USBCLK,
+	AW_H3_USBCLK,
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-usb-clk",	AW_A10_USBCLK },
+	{ "allwinner,sun5i-a13-usb-clk",	AW_A13_USBCLK },
+	{ "allwinner,sun6i-a31-usb-clk",	AW_A31_USBCLK },
+	{ "allwinner,sun8i-a83t-usb-clk",	AW_A83T_USBCLK },
+	{ "allwinner,sun8i-h3-usb-clk",		AW_H3_USBCLK },
+	{ NULL, 0 }
+};
+
+/* Clock indices for A10, as there is no clock-indices property in the DT */
+static uint32_t aw_usbclk_indices_a10[] = { 6, 7, 8 };
+/* Clock indices for H3, as there is no clock-indices property in the DT */
+static uint32_t aw_usbclk_indices_h3[] = { 8, 9, 10, 11, 16, 17, 18, 19 };
+
+struct aw_usbclk_softc {
+	bus_addr_t	reg;
+};
+
+static int
+aw_usbclk_hwreset_assert(device_t dev, intptr_t id, bool value)
+{
+	struct aw_usbclk_softc *sc;
+	uint32_t mask;
+	device_t pdev;
+	int error;
+
+	sc = device_get_softc(dev);
+	pdev = device_get_parent(dev);
+
+	mask = USBPHY0_RST << id;
+
+	CLKDEV_DEVICE_LOCK(pdev);
+	error = CLKDEV_MODIFY_4(pdev, sc->reg, mask, value ? 0 : mask);
+	CLKDEV_DEVICE_UNLOCK(pdev);
+
+	return (error);
+}
+
+static int
+aw_usbclk_hwreset_is_asserted(device_t dev, intptr_t id, bool *value)
+{
+	struct aw_usbclk_softc *sc;
+	uint32_t mask, val;
+	device_t pdev;
+	int error;
+
+	sc = device_get_softc(dev);
+	pdev = device_get_parent(dev);
+
+	mask = USBPHY0_RST << id;
+
+	CLKDEV_DEVICE_LOCK(pdev);
+	error = CLKDEV_READ_4(pdev, sc->reg, &val);
+	CLKDEV_DEVICE_UNLOCK(pdev);
+
+	if (error)
+		return (error);
+
+	*value = (val & mask) != 0 ? false : true;
+
+	return (0);
+}
+
+static int
+aw_usbclk_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom,
+    const char *pclkname, const char *clkname, int index)
+{
+	const char *parent_names[1] = { pclkname };
+	struct clk_gate_def def;
+
+	memset(&def, 0, sizeof(def));
+	def.clkdef.id = index;
+	def.clkdef.name = clkname;
+	def.clkdef.parent_names = parent_names;
+	def.clkdef.parent_cnt = 1;
+	def.offset = paddr;
+	def.shift = index;
+	def.mask = 1;
+	def.on_value = 1;
+	def.off_value = 0;
+
+	return (clknode_gate_register(clkdom, &def));
+}
+
+static int
+aw_usbclk_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 USB Clocks");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_usbclk_attach(device_t dev)
+{
+	struct aw_usbclk_softc *sc;
+	struct clkdom *clkdom;
+	const char **names;
+	const char *pname;
+	int index, nout, error;
+	enum aw_usbclk_type type;
+	uint32_t *indices;
+	clk_t clk_parent, clk_parent_pll;
+	bus_size_t psize;
+	phandle_t node;
+
+	sc = device_get_softc(dev);
+	node = ofw_bus_get_node(dev);
+	indices = NULL;
+	type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+	if (ofw_reg_to_paddr(node, 0, &sc->reg, &psize, NULL) != 0) {
+		device_printf(dev, "cannot parse 'reg' property\n");
+		return (ENXIO);
+	}
+
+	clkdom = clkdom_create(dev);
+
+	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
+	if (nout == 0) {
+		device_printf(dev, "no clock outputs found\n");
+		error = ENOENT;
+		goto fail;
+	}
+
+	if (indices == NULL && type == AW_A10_USBCLK)
+		indices = aw_usbclk_indices_a10;
+	else if (indices == NULL && type == AW_H3_USBCLK)
+		indices = aw_usbclk_indices_h3;
+
+	error = clk_get_by_ofw_index(dev, 0, 0, &clk_parent);
+	if (error != 0) {
+		device_printf(dev, "cannot parse clock parent\n");
+		return (ENXIO);
+	}
+	if (type == AW_A83T_USBCLK) {
+		error = clk_get_by_ofw_index(dev, 0, 1, &clk_parent_pll);
+		if (error != 0) {
+			device_printf(dev, "cannot parse pll clock parent\n");
+			return (ENXIO);
+		}
+	}
+
+	for (index = 0; index < nout; index++) {
+		if (strcmp(names[index], "usb_hsic_pll") == 0)
+			pname = clk_get_name(clk_parent_pll);
+		else
+			pname = clk_get_name(clk_parent);
+		error = aw_usbclk_create(dev, sc->reg, clkdom, pname,
+		    names[index], indices != NULL ? indices[index] : index);
+		if (error)
+			goto fail;
+	}
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(dev, "cannot finalize clkdom initialization\n");
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	hwreset_register_ofw_provider(dev);
+
+	return (0);
+
+fail:
+	return (error);
+}
+
+static device_method_t aw_usbclk_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		aw_usbclk_probe),
+	DEVMETHOD(device_attach,	aw_usbclk_attach),
+
+	/* Reset interface */
+	DEVMETHOD(hwreset_assert,	aw_usbclk_hwreset_assert),
+	DEVMETHOD(hwreset_is_asserted,	aw_usbclk_hwreset_is_asserted),
+
+	DEVMETHOD_END
+};
+
+static driver_t aw_usbclk_driver = {
+	"aw_usbclk",
+	aw_usbclk_methods,
+	sizeof(struct aw_usbclk_softc)
+};
+
+static devclass_t aw_usbclk_devclass;
+
+EARLY_DRIVER_MODULE(aw_usbclk, simplebus, aw_usbclk_driver,
+    aw_usbclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);


Property changes on: trunk/sys/arm/allwinner/clk/aw_usbclk.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list