[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