Page MenuHomeFreeBSD

D9517.id25611.diff
No OneTemporary

D9517.id25611.diff

Index: sys/arm/allwinner/clkng/aw_ccung.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_ccung.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#ifndef __CCU_NG_H__
+#define __CCU_NG_H__
+
+struct aw_ccung_softc {
+ device_t dev;
+ struct resource *res;
+ struct clkdom *clkdom;
+ struct mtx mtx;
+ int type;
+ struct aw_ccung_reset *resets;
+ int nresets;
+ struct aw_ccung_gate *gates;
+ int ngates;
+ struct aw_clk_init *clk_init;
+ int n_clk_init;
+};
+
+struct aw_ccung_reset {
+ uint32_t offset;
+ uint32_t shift;
+};
+
+struct aw_ccung_gate {
+ const char *name;
+ const char *parent_name;
+ uint32_t id;
+ uint32_t offset;
+ uint32_t shift;
+};
+
+#endif /* __CCU_NG_H__ */
Index: sys/arm/allwinner/clkng/aw_ccung.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_ccung.c
@@ -0,0 +1,348 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Allwinner Clock Control Unit
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_gate.h>
+
+#include <dev/extres/hwreset/hwreset.h>
+
+#include <arm/allwinner/clkng/aw_ccung.h>
+#include <arm/allwinner/clkng/aw_clk.h>
+
+#if defined(SOC_ALLWINNER_H3)
+#include <arm/allwinner/clkng/ccu_h3.h>
+#endif
+
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+
+static struct resource_spec aw_ccung_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+#if defined(SOC_ALLWINNER_H3)
+#define H3_CCU 1
+#endif
+
+static struct ofw_compat_data compat_data[] = {
+#if defined(SOC_ALLWINNER_H3)
+ { "allwinner,sun8i-h3-ccu", H3_CCU },
+#endif
+ {NULL, 0 }
+};
+
+#define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg))
+#define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
+
+static int
+aw_ccung_write_4(device_t dev, bus_addr_t addr, uint32_t val)
+{
+ struct aw_ccung_softc *sc;
+
+ sc = device_get_softc(dev);
+ CCU_WRITE4(sc, addr, val);
+ return (0);
+}
+
+static int
+aw_ccung_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+{
+ struct aw_ccung_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ *val = CCU_READ4(sc, addr);
+ return (0);
+}
+
+static int
+aw_ccung_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
+{
+ struct aw_ccung_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ reg = CCU_READ4(sc, addr);
+ reg &= ~clr;
+ reg |= set;
+ CCU_WRITE4(sc, addr, reg);
+
+ return (0);
+}
+
+static int
+aw_ccung_reset_assert(device_t dev, intptr_t id, bool reset)
+{
+ struct aw_ccung_softc *sc;
+ uint32_t val;
+
+ sc = device_get_softc(dev);
+
+ if (id >= sc->nresets || sc->resets[id].offset == 0)
+ return (0);
+
+ mtx_lock(&sc->mtx);
+ val = CCU_READ4(sc, sc->resets[id].offset);
+ if (reset)
+ val &= ~(1 << sc->resets[id].shift);
+ else
+ val |= 1 << sc->resets[id].shift;
+ CCU_WRITE4(sc, sc->resets[id].offset, val);
+ mtx_unlock(&sc->mtx);
+
+ return (0);
+}
+
+static int
+aw_ccung_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
+{
+ struct aw_ccung_softc *sc;
+ uint32_t val;
+
+ sc = device_get_softc(dev);
+
+ if (id >= sc->nresets || sc->resets[id].offset == 0)
+ return (0);
+
+ mtx_lock(&sc->mtx);
+ val = CCU_READ4(sc, sc->resets[id].offset);
+ *reset = (val & (1 << sc->resets[id].shift)) != 0 ? false : true;
+ mtx_unlock(&sc->mtx);
+
+ return (0);
+}
+
+static void
+aw_ccung_device_lock(device_t dev)
+{
+ struct aw_ccung_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+aw_ccung_device_unlock(device_t dev)
+{
+ struct aw_ccung_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static int
+aw_ccung_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 Clock Control Unit NG");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+aw_ccung_register_gates(struct aw_ccung_softc *sc)
+{
+ struct clk_gate_def def;
+ int i;
+
+ for (i = 0; i < sc->ngates; i++) {
+ if (sc->gates[i].name == NULL)
+ continue;
+ memset(&def, 0, sizeof(def));
+ def.clkdef.id = i;
+ def.clkdef.name = sc->gates[i].name;
+ def.clkdef.parent_names = &sc->gates[i].parent_name;
+ def.clkdef.parent_cnt = 1;
+ def.offset = sc->gates[i].offset;
+ def.shift = sc->gates[i].shift;
+ def.mask = 1;
+ def.on_value = 1;
+ def.off_value = 0;
+ clknode_gate_register(sc->clkdom, &def);
+ }
+
+ return (0);
+}
+
+static void
+aw_ccung_init_clocks(struct aw_ccung_softc *sc)
+{
+ struct clknode *clknode;
+ int i, error;
+
+ for (i = 0; i < sc->n_clk_init; i++) {
+ clknode = clknode_find_by_name(sc->clk_init[i].name);
+ if (clknode == NULL) {
+ device_printf(sc->dev, "Cannot find clock %s\n",
+ sc->clk_init[i].name);
+ continue;
+ }
+
+ if (sc->clk_init[i].parent_name != NULL) {
+ if (bootverbose)
+ device_printf(sc->dev, "Setting %s as parent for %s\n",
+ sc->clk_init[i].parent_name,
+ sc->clk_init[i].name);
+ error = clknode_set_parent_by_name(clknode,
+ sc->clk_init[i].parent_name);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "Cannot set parent to %s for %s\n",
+ sc->clk_init[i].parent_name,
+ sc->clk_init[i].name);
+ continue;
+ }
+ }
+ if (sc->clk_init[i].default_freq != 0) {
+ error = clknode_set_freq(clknode,
+ sc->clk_init[i].default_freq, 0 , 0);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "Cannot set frequency for %s to %llu\n",
+ sc->clk_init[i].name,
+ sc->clk_init[i].default_freq);
+ continue;
+ }
+ }
+ if (sc->clk_init[i].enable) {
+ error = clknode_enable(clknode);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "Cannot enable %s\n",
+ sc->clk_init[i].name);
+ continue;
+ }
+ }
+ }
+}
+
+static int
+aw_ccung_attach(device_t dev)
+{
+ struct aw_ccung_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ if (bus_alloc_resources(dev, aw_ccung_spec, &sc->res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+ sc->clkdom = clkdom_create(dev);
+ if (sc->clkdom == NULL)
+ panic("Cannot create clkdom\n");
+
+ switch (sc->type) {
+#if defined(SOC_ALLWINNER_H3)
+ case H3_CCU:
+ ccu_h3_register_clocks(sc);
+ break;
+#endif
+ }
+
+ if (sc->gates)
+ aw_ccung_register_gates(sc);
+ if (clkdom_finit(sc->clkdom) != 0)
+ panic("cannot finalize clkdom initialization\n");
+
+ clkdom_xlock(sc->clkdom);
+ aw_ccung_init_clocks(sc);
+ clkdom_unlock(sc->clkdom);
+
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+
+ /* If we have resets, register our self as a reset provider */
+ if (sc->resets)
+ hwreset_register_ofw_provider(dev);
+
+ return (0);
+}
+
+static device_method_t aw_ccung_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, aw_ccung_probe),
+ DEVMETHOD(device_attach, aw_ccung_attach),
+
+ /* clkdev interface */
+ DEVMETHOD(clkdev_write_4, aw_ccung_write_4),
+ DEVMETHOD(clkdev_read_4, aw_ccung_read_4),
+ DEVMETHOD(clkdev_modify_4, aw_ccung_modify_4),
+ DEVMETHOD(clkdev_device_lock, aw_ccung_device_lock),
+ DEVMETHOD(clkdev_device_unlock, aw_ccung_device_unlock),
+
+ /* Reset interface */
+ DEVMETHOD(hwreset_assert, aw_ccung_reset_assert),
+ DEVMETHOD(hwreset_is_asserted, aw_ccung_reset_is_asserted),
+
+ DEVMETHOD_END
+};
+
+static driver_t aw_ccung_driver = {
+ "aw_ccung",
+ aw_ccung_methods,
+ sizeof(struct aw_ccung_softc),
+};
+
+static devclass_t aw_ccung_devclass;
+
+EARLY_DRIVER_MODULE(aw_ccung, simplebus, aw_ccung_driver, aw_ccung_devclass,
+ 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(aw_ccung, 1);
Index: sys/arm/allwinner/clkng/aw_clk.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk.h
@@ -0,0 +1,317 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#ifndef __AW_CLK_H__
+#define __AW_CLK_H__
+
+/*
+ Allwinner clocks formula :
+
+PLLs:
+
+(24MHz*N*K)/(M*P)
+(24MHz*N)/(M*P)
+(24MHz*N*2)/M
+(24MHz*N)/M
+(24MHz*N*K)/M
+(24MHz*N*K/2)
+(24MHz*N)/M
+(24MHz*N*K/2)
+(24MHz*N)/M
+
+Periph clocks:
+
+Clock Source/Divider N/Divider M
+Clock Source/Divider N/Divider M/2
+
+ */
+
+struct aw_clk_init {
+ const char *name;
+ const char *parent_name;
+ uint64_t default_freq;
+ bool enable;
+};
+
+#define AW_CLK_HAS_GATE 0x0001
+#define AW_CLK_HAS_LOCK 0x0002
+#define AW_CLK_HAS_MUX 0x0004
+#define AW_CLK_REPARENT 0x0008
+#define AW_CLK_SCALE_CHANGE 0x0010
+
+#define AW_CLK_FACTOR_POWER_OF_TWO 0x0001
+#define AW_CLK_FACTOR_ZERO_BASED 0x0002
+#define AW_CLK_FACTOR_HAS_COND 0x0004
+#define AW_CLK_FACTOR_FIXED 0x0008
+
+struct aw_clk_factor {
+ uint32_t shift; /* Shift bits for the factor */
+ uint32_t mask; /* Mask to get the factor, will be override by the clk methods */
+ uint32_t width; /* Number of bits for the factor */
+ uint32_t value; /* Fixed value, depends on AW_CLK_FACTOR_FIXED */
+
+ uint32_t cond_shift;
+ uint32_t cond_mask;
+ uint32_t cond_width;
+ uint32_t cond_value;
+
+ uint32_t flags; /* Flags */
+};
+
+static inline uint32_t
+aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor)
+{
+ uint32_t factor_val;
+ uint32_t cond;
+
+ if (factor->flags & AW_CLK_FACTOR_HAS_COND) {
+ cond = (val & factor->cond_mask) >> factor->cond_shift;
+ if (cond != factor->cond_value)
+ return (1);
+ }
+
+ if (factor->flags & AW_CLK_FACTOR_FIXED)
+ return (factor->value);
+
+ factor_val = (val & factor->mask) >> factor->shift;
+ if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED))
+ factor_val += 1;
+ else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
+ factor_val = 1 << factor_val;
+
+ return (factor_val);
+}
+
+static inline uint32_t
+aw_clk_factor_get_max(struct aw_clk_factor *factor)
+{
+ uint32_t max;
+
+ if (factor->flags & AW_CLK_FACTOR_FIXED)
+ max = factor->value;
+ else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
+ max = 1 << ((1 << factor->width) - 1);
+ else {
+ max = (1 << factor->width);
+ }
+
+ return (max);
+}
+
+static inline uint32_t
+aw_clk_factor_get_min(struct aw_clk_factor *factor)
+{
+ uint32_t min;
+
+ if (factor->flags & AW_CLK_FACTOR_FIXED)
+ min = factor->value;
+ else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
+ min = 0;
+ else
+ min = 1;
+
+ return (min);
+}
+
+static inline uint32_t
+aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw)
+{
+ uint32_t val;
+
+ if (factor->flags & AW_CLK_FACTOR_FIXED)
+ return (factor->value);
+
+ if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
+ val = raw;
+ else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) {
+ for (val = 0; raw != 1; val++)
+ raw >>= 1;
+ } else
+ val = raw - 1;
+
+ return (val);
+}
+
+#define CCU_RESET(idx, o, s) \
+ [idx] = { \
+ .offset = o, \
+ .shift = s, \
+ },
+
+#define CCU_GATE(idx, clkname, pname, o, s) \
+ [idx] = { \
+ .name = clkname, \
+ .parent_name = pname, \
+ .offset = o, \
+ .shift = s, \
+ },
+
+#define NKMP_CLK(_id, _name, _pnames, \
+ _offset, \
+ _n_shift, _n_width, _n_value, _n_flags, \
+ _k_shift, _k_width, _k_value, _k_flags, \
+ _m_shift, _m_width, _m_value, _m_flags, \
+ _p_shift, _p_width, _p_value, _p_flags, \
+ _gate, \
+ _lock, _lock_retries, \
+ _flags) \
+ { \
+ .clkdef = { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _pnames, \
+ .parent_cnt = nitems(_pnames), \
+ }, \
+ .offset = _offset, \
+ .n.shift = _n_shift, \
+ .n.width = _n_width, \
+ .n.value = _n_value, \
+ .n.flags = _n_flags, \
+ .k.shift = _k_shift, \
+ .k.width = _k_width, \
+ .k.value = _k_value, \
+ .k.flags = _k_flags, \
+ .m.shift = _m_shift, \
+ .m.width = _m_width, \
+ .m.value = _m_value, \
+ .m.flags = _m_flags, \
+ .p.shift = _p_shift, \
+ .p.width = _p_width, \
+ .p.value = _p_value, \
+ .p.flags = _p_flags, \
+ .gate_shift = _gate, \
+ .lock_shift = _lock, \
+ .lock_retries = _lock_retries, \
+ .flags = _flags, \
+ },
+
+#define NM_CLK(_id, _name, _pnames, \
+ _offset, \
+ _nshift, _nwidth, _nvalue, _nflags, \
+ _mshift, _mwidth, _mvalue, _mflags, \
+ _mux_shift, _mux_width, \
+ _gate_shift, \
+ _flags) \
+ { \
+ .clkdef = { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _pnames, \
+ .parent_cnt = nitems(_pnames), \
+ }, \
+ .offset = _offset, \
+ .n.shift = _nshift, \
+ .n.width = _nwidth, \
+ .n.value = _nvalue, \
+ .n.flags = _nflags, \
+ .mux_shift = _mux_shift, \
+ .m.shift = _mshift, \
+ .m.width = _mwidth, \
+ .m.value = _mvalue, \
+ .m.flags = _mflags, \
+ .mux_width = _mux_width, \
+ .flags = _flags, \
+ },
+
+#define PREDIV_CLK(_id, _name, _pnames, \
+ _offset, \
+ _mux_shift, _mux_width, \
+ _div_shift, _div_width, _div_value, _div_flags, \
+ _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \
+ _prediv_cond_shift, _prediv_cond_width, _prediv_cond_value) \
+ { \
+ .clkdef = { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _pnames, \
+ .parent_cnt = nitems(_pnames), \
+ }, \
+ .offset = _offset, \
+ .mux_shift = _mux_shift, \
+ .mux_width = _mux_width, \
+ .div.shift = _div_shift, \
+ .div.width = _div_width, \
+ .div.value = _div_value, \
+ .div.flags = _div_flags, \
+ .prediv.shift = _prediv_shift, \
+ .prediv.width = _prediv_width, \
+ .prediv.value = _prediv_value, \
+ .prediv.flags = _prediv_flags, \
+ .prediv.cond_shift = _prediv_cond_shift, \
+ .prediv.cond_width = _prediv_cond_width, \
+ .prediv.cond_value = _prediv_cond_value, \
+ },
+
+#define MUX_CLK(_id, _name, _pnames, \
+ _offset, _shift, _width) \
+ { \
+ .clkdef = { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _pnames, \
+ .parent_cnt = nitems(_pnames) \
+ }, \
+ .offset = _offset, \
+ .shift = _shift, \
+ .width = _width, \
+ },
+
+#define DIV_CLK(_id, _name, _pnames, \
+ _offset, \
+ _i_shift, _i_width, \
+ _div_flags, _div_table) \
+ { \
+ .clkdef = { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _pnames, \
+ .parent_cnt = nitems(_pnames) \
+ }, \
+ .offset = _offset, \
+ .i_shift = _i_shift, \
+ .i_width = _i_width, \
+ .div_flags = _div_flags, \
+ .div_table = _div_table, \
+ },
+
+#define FIXED_CLK(_id, _name, _pnames, \
+ _freq, _mult, _div, _flags) \
+ { \
+ .clkdef = { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _pnames, \
+ .parent_cnt = 1, \
+ }, \
+ .freq = _freq, \
+ .mult = _mult, \
+ .div = _div, \
+ .fixed_flags = _flags, \
+ },
+
+#endif /* __AW_CLK_H__ */
Index: sys/arm/allwinner/clkng/aw_clk_nkmp.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk_nkmp.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#ifndef __AW_CLK_NKMP_H__
+#define __AW_CLK_NKMP_H__
+
+#include <arm/allwinner/clkng/aw_clk.h>
+
+struct aw_clk_nkmp_def {
+ struct clknode_init_def clkdef;
+
+ uint32_t offset;
+
+ struct aw_clk_factor m;
+ struct aw_clk_factor k;
+ struct aw_clk_factor n;
+ struct aw_clk_factor p;
+
+ uint32_t gate_shift;
+ uint32_t lock_shift;
+ uint32_t lock_retries;
+
+ uint32_t flags;
+};
+
+int aw_clk_nkmp_register(struct clkdom *clkdom, struct aw_clk_nkmp_def *clkdef);
+
+#endif /* __AW_CLK_NKMP_H__ */
Index: sys/arm/allwinner/clkng/aw_clk_nkmp.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk_nkmp.c
@@ -0,0 +1,362 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm/allwinner/clkng/aw_clk.h>
+#include <arm/allwinner/clkng/aw_clk_nkmp.h>
+
+#include "clkdev_if.h"
+
+/*
+ * clknode for clocks matching the formula :
+ *
+ * clk = (clkin * n * k) / (m * p)
+ *
+ */
+
+struct aw_clk_nkmp_sc {
+ uint32_t offset;
+
+ struct aw_clk_factor n;
+ struct aw_clk_factor k;
+ struct aw_clk_factor m;
+ struct aw_clk_factor p;
+
+ uint32_t gate_shift;
+ uint32_t lock_shift;
+ uint32_t lock_retries;
+
+ uint32_t flags;
+};
+
+#define WRITE4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define READ4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define MODIFY4(_clk, off, clr, set ) \
+ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+static int
+aw_clk_nkmp_init(struct clknode *clk, device_t dev)
+{
+ clknode_init_parent_idx(clk, 0);
+ return (0);
+}
+
+static int
+aw_clk_nkmp_set_gate(struct clknode *clk, bool enable)
+{
+ struct aw_clk_nkmp_sc *sc;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+
+ if ((sc->flags & AW_CLK_HAS_GATE) == 0)
+ return (0);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ if (enable)
+ val |= (1 << sc->gate_shift);
+ else
+ val &= ~(1 << sc->gate_shift);
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static uint64_t
+aw_clk_nkmp_find_best(struct aw_clk_nkmp_sc *sc, uint64_t fparent, uint64_t *fout,
+ uint32_t *factor_n, uint32_t *factor_k, uint32_t *factor_m, uint32_t *factor_p)
+{
+ uint64_t cur, best;
+ uint32_t n, k, m, p;
+
+ best = 0;
+ *factor_n = 0;
+ *factor_k = 0;
+ *factor_m = 0;
+ *factor_p = 0;
+
+ for (n = aw_clk_factor_get_min(&sc->n); n <= aw_clk_factor_get_max(&sc->n); ) {
+ for (k = aw_clk_factor_get_min(&sc->k); k <= aw_clk_factor_get_max(&sc->k); ) {
+ for (m = aw_clk_factor_get_min(&sc->m); m <= aw_clk_factor_get_max(&sc->m); ) {
+ for (p = aw_clk_factor_get_min(&sc->p); p <= aw_clk_factor_get_max(&sc->p); ) {
+ cur = (fparent * n * k) / (m * p);
+ if ((*fout - cur) < (*fout - best)) {
+ best = cur;
+ *factor_n = n;
+ *factor_k = k;
+ *factor_m = m;
+ *factor_p = p;
+ }
+ if (best == *fout)
+ return (best);
+ if ((sc->p.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
+ p <<= 1;
+ else
+ p++;
+ }
+ if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
+ m <<= 1;
+ else
+ m++;
+ }
+ if ((sc->k.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
+ k <<= 1;
+ else
+ k++;
+ }
+ if ((sc->n.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
+ n <<= 1;
+ else
+ n++;
+ }
+
+ return best;
+}
+
+static void
+aw_clk_nkmp_set_freq_scale(struct clknode *clk, struct aw_clk_nkmp_sc *sc,
+ uint32_t factor_n, uint32_t factor_k, uint32_t factor_m, uint32_t factor_p)
+{
+ uint32_t val, n, k, m, p;
+ int retry;
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+
+ n = aw_clk_get_factor(val, &sc->n);
+ k = aw_clk_get_factor(val, &sc->k);
+ m = aw_clk_get_factor(val, &sc->m);
+ p = aw_clk_get_factor(val, &sc->p);
+
+ if (p < factor_p) {
+ val &= ~sc->p.mask;
+ val |= aw_clk_factor_get_value(&sc->p, factor_p) << sc->p.shift;
+ WRITE4(clk, sc->offset, val);
+ DELAY(2000);
+ }
+
+ if (m < factor_m) {
+ val &= ~sc->m.mask;
+ val |= aw_clk_factor_get_value(&sc->m, factor_m) << sc->m.shift;
+ WRITE4(clk, sc->offset, val);
+ DELAY(2000);
+ }
+
+ val &= ~sc->n.mask;
+ val &= ~sc->k.mask;
+ val |= aw_clk_factor_get_value(&sc->n, factor_n) << sc->n.shift;
+ val |= aw_clk_factor_get_value(&sc->k, factor_k) << sc->k.shift;
+ WRITE4(clk, sc->offset, val);
+ DELAY(2000);
+
+ if (m > factor_m) {
+ val &= ~sc->m.mask;
+ val |= aw_clk_factor_get_value(&sc->m, factor_m) << sc->m.shift;
+ WRITE4(clk, sc->offset, val);
+ DELAY(2000);
+ }
+
+ if (p > factor_p) {
+ val &= ~sc->p.mask;
+ val |= aw_clk_factor_get_value(&sc->p, factor_p) << sc->p.shift;
+ WRITE4(clk, sc->offset, val);
+ DELAY(2000);
+ }
+
+ if ((sc->flags & AW_CLK_HAS_LOCK) != 0) {
+ for (retry = 0; retry < sc->lock_retries; retry++) {
+ READ4(clk, sc->offset, &val);
+ if ((val & (1 << sc->lock_shift)) != 0)
+ break;
+ DELAY(1000);
+ }
+ }
+
+ DEVICE_UNLOCK(clk);
+}
+
+static int
+aw_clk_nkmp_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct aw_clk_nkmp_sc *sc;
+ uint64_t best;
+ uint32_t val, best_n, best_k, best_m, best_p;
+ int retry;
+
+ sc = clknode_get_softc(clk);
+
+ best = aw_clk_nkmp_find_best(sc, fparent, fout,
+ &best_n, &best_k, &best_m, &best_p);
+ if ((flags & CLK_SET_DRYRUN) != 0) {
+ *fout = best;
+ *stop = 1;
+ return (0);
+ }
+
+ if ((best < *fout) &&
+ ((flags & CLK_SET_ROUND_DOWN) != 0)) {
+ *stop = 1;
+ return (ERANGE);
+ }
+ if ((best > *fout) &&
+ ((flags & CLK_SET_ROUND_UP) != 0)) {
+ *stop = 1;
+ return (ERANGE);
+ }
+
+ if ((sc->flags & AW_CLK_SCALE_CHANGE) != 0)
+ aw_clk_nkmp_set_freq_scale(clk, sc,
+ best_n, best_k, best_m, best_p);
+ else {
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ val &= ~sc->n.mask;
+ val &= ~sc->k.mask;
+ val &= ~sc->m.mask;
+ val &= ~sc->p.mask;
+ val |= aw_clk_factor_get_value(&sc->n, best_n) << sc->n.shift;
+ val |= aw_clk_factor_get_value(&sc->k, best_k) << sc->k.shift;
+ val |= aw_clk_factor_get_value(&sc->m, best_m) << sc->m.shift;
+ val |= aw_clk_factor_get_value(&sc->p, best_p) << sc->p.shift;
+ WRITE4(clk, sc->offset, val);
+ DELAY(2000);
+
+ if ((sc->flags & AW_CLK_HAS_LOCK) != 0) {
+ for (retry = 0; retry < sc->lock_retries; retry++) {
+ READ4(clk, sc->offset, &val);
+ if ((val & (1 << sc->lock_shift)) != 0)
+ break;
+ DELAY(1000);
+ }
+ }
+ }
+
+ *fout = best;
+ *stop = 1;
+
+ return (0);
+}
+
+static int
+aw_clk_nkmp_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct aw_clk_nkmp_sc *sc;
+ uint32_t val, m, n, k, p;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ DEVICE_UNLOCK(clk);
+
+ n = aw_clk_get_factor(val, &sc->n);
+ k = aw_clk_get_factor(val, &sc->k);
+ m = aw_clk_get_factor(val, &sc->m);
+ p = aw_clk_get_factor(val, &sc->p);
+
+ *freq = (*freq * n * k) / (m * p);
+
+ return (0);
+}
+
+static clknode_method_t aw_nkmp_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, aw_clk_nkmp_init),
+ CLKNODEMETHOD(clknode_set_gate, aw_clk_nkmp_set_gate),
+ CLKNODEMETHOD(clknode_recalc_freq, aw_clk_nkmp_recalc),
+ CLKNODEMETHOD(clknode_set_freq, aw_clk_nkmp_set_freq),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(aw_nkmp_clknode, aw_nkmp_clknode_class, aw_nkmp_clknode_methods,
+ sizeof(struct aw_clk_nkmp_sc), clknode_class);
+
+int
+aw_clk_nkmp_register(struct clkdom *clkdom, struct aw_clk_nkmp_def *clkdef)
+{
+ struct clknode *clk;
+ struct aw_clk_nkmp_sc *sc;
+
+ clk = clknode_create(clkdom, &aw_nkmp_clknode_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->offset = clkdef->offset;
+
+ sc->n.shift = clkdef->n.shift;
+ sc->n.width = clkdef->n.width;
+ sc->n.mask = ((1 << clkdef->n.width) - 1) << sc->n.shift;
+ sc->n.value = clkdef->n.value;
+ sc->n.flags = clkdef->n.flags;
+
+ sc->k.shift = clkdef->k.shift;
+ sc->k.width = clkdef->k.width;
+ sc->k.mask = ((1 << clkdef->k.width) - 1) << sc->k.shift;
+ sc->k.value = clkdef->k.value;
+ sc->k.flags = clkdef->k.flags;
+
+ sc->m.shift = clkdef->m.shift;
+ sc->m.width = clkdef->m.width;
+ sc->m.mask = ((1 << clkdef->m.width) - 1) << sc->m.shift;
+ sc->m.value = clkdef->m.value;
+ sc->m.flags = clkdef->m.flags;
+
+ sc->p.shift = clkdef->p.shift;
+ sc->p.width = clkdef->p.width;
+ sc->p.mask = ((1 << clkdef->p.width) - 1) << sc->p.shift;
+ sc->p.value = clkdef->p.value;
+ sc->p.flags = clkdef->p.flags;
+
+ sc->gate_shift = clkdef->gate_shift;
+ sc->lock_shift = clkdef->lock_shift;
+ sc->lock_retries = clkdef->lock_retries;
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Index: sys/arm/allwinner/clkng/aw_clk_nm.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk_nm.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#ifndef __AW_CLK_NM_H__
+#define __AW_CLK_NM_H__
+
+#include <dev/extres/clk/clk.h>
+
+struct aw_clk_nm_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+
+ struct aw_clk_factor m;
+ struct aw_clk_factor n;
+
+ uint32_t mux_shift;
+ uint32_t mux_width;
+ uint32_t gate_shift;
+
+ uint32_t flags;
+};
+
+int aw_clk_nm_register(struct clkdom *clkdom, struct aw_clk_nm_def *clkdef);
+
+#endif /* __AW_CLK_NM_H__ */
Index: sys/arm/allwinner/clkng/aw_clk_nm.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk_nm.c
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm/allwinner/clkng/aw_clk.h>
+#include <arm/allwinner/clkng/aw_clk_nm.h>
+
+#include "clkdev_if.h"
+
+/*
+ * clknode for clocks matching the formula :
+ *
+ * clk = clkin / n / m
+ *
+ */
+
+struct aw_clk_nm_sc {
+ uint32_t offset;
+
+ struct aw_clk_factor m;
+ struct aw_clk_factor n;
+
+ uint32_t mux_shift;
+ uint32_t mux_mask;
+ uint32_t gate_shift;
+
+ uint32_t flags;
+};
+
+#define WRITE4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define READ4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+static int
+aw_clk_nm_init(struct clknode *clk, device_t dev)
+{
+ struct aw_clk_nm_sc *sc;
+ uint32_t val, idx;
+
+ sc = clknode_get_softc(clk);
+
+ idx = 0;
+ if ((sc->flags & AW_CLK_HAS_MUX) != 0) {
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ DEVICE_UNLOCK(clk);
+
+ idx = (val & sc->mux_mask) >> sc->mux_shift;
+ }
+
+ clknode_init_parent_idx(clk, idx);
+ return (0);
+}
+
+static int
+aw_clk_nm_set_gate(struct clknode *clk, bool enable)
+{
+ struct aw_clk_nm_sc *sc;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+
+ if ((sc->flags & AW_CLK_HAS_GATE) == 0)
+ return (0);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ if (enable)
+ val |= (1 << sc->gate_shift);
+ else
+ val &= ~(1 << sc->gate_shift);
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+aw_clk_nm_set_mux(struct clknode *clk, int index)
+{
+ struct aw_clk_nm_sc *sc;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+
+ if ((sc->flags & AW_CLK_HAS_MUX) != 0)
+ return (0);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ val &= ~(sc->mux_mask >> sc->mux_shift);
+ val |= index << sc->mux_shift;
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static uint64_t
+aw_clk_nm_find_best(struct aw_clk_nm_sc *sc, uint64_t fparent, uint64_t *fout,
+ uint32_t *factor_n, uint32_t *factor_m)
+{
+ uint64_t cur, best;
+ uint32_t m, n, max_m, max_n, min_m, min_n;
+
+ *factor_n = *factor_m = 0;
+
+ max_m = aw_clk_factor_get_max(&sc->m);
+ max_n = aw_clk_factor_get_max(&sc->n);
+ min_m = aw_clk_factor_get_min(&sc->m);
+ min_n = aw_clk_factor_get_min(&sc->n);
+
+ for (m = min_m; m <= max_m; ) {
+ for (n = min_m; n <= max_n; ) {
+ cur = fparent / n / m;
+ if ((*fout - cur) < (*fout - best)) {
+ best = cur;
+ *factor_n = n;
+ *factor_m = m;
+ }
+
+ if ((sc->n.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
+ n <<= 1;
+ else
+ n++;
+ }
+ if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
+ m <<= 1;
+ else
+ m++;
+ }
+
+ return (best);
+}
+
+static int
+aw_clk_nm_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct aw_clk_nm_sc *sc;
+ struct clknode *p_clk;
+ const char **p_names;
+ uint64_t cur, best;
+ uint32_t val, m, n, best_m, best_n;
+ int p_idx, best_parent;
+
+ sc = clknode_get_softc(clk);
+
+ best = cur = 0;
+ best_parent = 0;
+
+ if ((sc->flags & AW_CLK_REPARENT) != 0) {
+ p_names = clknode_get_parent_names(clk);
+ for (p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) {
+ p_clk = clknode_find_by_name(p_names[p_idx]);
+ clknode_get_freq(p_clk, &fparent);
+
+ cur = aw_clk_nm_find_best(sc, fparent, fout, &n, &m);
+ if ((*fout - cur) < (*fout - best)) {
+ best = cur;
+ best_parent = p_idx;
+ best_n = n;
+ best_m = m;
+ }
+ }
+
+ p_idx = clknode_get_parent_idx(clk);
+ p_clk = clknode_get_parent(clk);
+ clknode_get_freq(p_clk, &fparent);
+ } else
+ best = aw_clk_nm_find_best(sc, fparent, fout, &best_n, &best_m);
+
+ if ((flags & CLK_SET_DRYRUN) != 0) {
+ *fout = best;
+ *stop = 1;
+ return (0);
+ }
+
+ if ((best < *fout) &&
+ ((flags & CLK_SET_ROUND_DOWN) == 0)) {
+ *stop = 1;
+ return (ERANGE);
+ }
+ if ((best > *fout) &&
+ ((flags & CLK_SET_ROUND_UP) == 0)) {
+ *stop = 1;
+ return (ERANGE);
+ }
+
+ if (p_idx != best_parent)
+ clknode_set_parent_by_idx(clk, best_parent);
+
+ n = aw_clk_factor_get_value(&sc->n, best_n);
+ m = aw_clk_factor_get_value(&sc->m, best_m);
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ val &= ~sc->n.mask;
+ val &= ~sc->m.mask;
+ val |= n << sc->n.shift;
+ val |= m << sc->m.shift;
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ *fout = best;
+ *stop = 1;
+
+ return (0);
+}
+
+static int
+aw_clk_nm_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct aw_clk_nm_sc *sc;
+ uint32_t val, m, n;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ DEVICE_UNLOCK(clk);
+
+ m = aw_clk_get_factor(val, &sc->m);
+ n = aw_clk_get_factor(val, &sc->n);
+
+ *freq = *freq / n / m;
+
+ return (0);
+}
+
+static clknode_method_t aw_nm_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, aw_clk_nm_init),
+ CLKNODEMETHOD(clknode_set_gate, aw_clk_nm_set_gate),
+ CLKNODEMETHOD(clknode_set_mux, aw_clk_nm_set_mux),
+ CLKNODEMETHOD(clknode_recalc_freq, aw_clk_nm_recalc),
+ CLKNODEMETHOD(clknode_set_freq, aw_clk_nm_set_freq),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(aw_nm_clknode, aw_nm_clknode_class, aw_nm_clknode_methods,
+ sizeof(struct aw_clk_nm_sc), clknode_class);
+
+int
+aw_clk_nm_register(struct clkdom *clkdom, struct aw_clk_nm_def *clkdef)
+{
+ struct clknode *clk;
+ struct aw_clk_nm_sc *sc;
+
+ clk = clknode_create(clkdom, &aw_nm_clknode_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->offset = clkdef->offset;
+
+ sc->m.shift = clkdef->m.shift;
+ sc->m.width = clkdef->m.width;
+ sc->m.mask = ((1 << sc->m.width) - 1) << sc->m.shift;
+ sc->m.flags = clkdef->m.flags;
+
+ sc->n.shift = clkdef->n.shift;
+ sc->n.width = clkdef->n.width;
+ sc->n.mask = ((1 << sc->n.width) - 1) << sc->n.shift;
+ sc->n.flags = clkdef->n.flags;
+
+ sc->mux_shift = clkdef->mux_shift;
+ sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
+
+ sc->gate_shift = clkdef->gate_shift;
+
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Index: sys/arm/allwinner/clkng/aw_clk_prediv_mux.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk_prediv_mux.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#ifndef __AW_CLK_PREDIV_MUX_H__
+#define __AW_CLK_PREDIV_MUX_H__
+
+#include <arm/allwinner/clkng/aw_clk.h>
+
+struct aw_clk_prediv_mux_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+
+ uint32_t mux_shift;
+ uint32_t mux_width;
+
+ struct aw_clk_factor div;
+ struct aw_clk_factor prediv;
+
+ uint32_t flags;
+};
+
+int aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef);
+
+#endif /* __AW_CLK_PREDIV_MUX_H__ */
Index: sys/arm/allwinner/clkng/aw_clk_prediv_mux.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/aw_clk_prediv_mux.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm/allwinner/clkng/aw_clk.h>
+#include <arm/allwinner/clkng/aw_clk_prediv_mux.h>
+
+#include "clkdev_if.h"
+
+/*
+ * clknode for clocks matching the formula :
+ *
+ * clk = clkin / prediv / div
+ *
+ * and where prediv is conditional
+ *
+ */
+
+struct aw_clk_prediv_mux_sc {
+ uint32_t offset;
+
+ uint32_t mux_shift;
+ uint32_t mux_mask;
+
+ struct aw_clk_factor div;
+ struct aw_clk_factor prediv;
+
+ uint32_t flags;
+};
+
+#define WRITE4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define READ4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define MODIFY4(_clk, off, clr, set ) \
+ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+static int
+aw_clk_prediv_mux_init(struct clknode *clk, device_t dev)
+{
+ clknode_init_parent_idx(clk, 0);
+ return (0);
+}
+
+static int
+aw_clk_prediv_mux_set_mux(struct clknode *clk, int index)
+{
+ struct aw_clk_prediv_mux_sc *sc;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ val &= ~sc->mux_mask;
+ val |= index << sc->mux_shift;
+ WRITE4(clk, sc->offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+aw_clk_prediv_mux_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct aw_clk_prediv_mux_sc *sc;
+ uint32_t val, div, prediv;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->offset, &val);
+ DEVICE_UNLOCK(clk);
+
+ div = aw_clk_get_factor(val, &sc->div);
+ prediv = aw_clk_get_factor(val, &sc->prediv);
+
+ *freq = *freq / prediv / div;
+ return (0);
+}
+
+static clknode_method_t aw_prediv_mux_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, aw_clk_prediv_mux_init),
+ CLKNODEMETHOD(clknode_set_mux, aw_clk_prediv_mux_set_mux),
+ CLKNODEMETHOD(clknode_recalc_freq, aw_clk_prediv_mux_recalc),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(aw_prediv_mux_clknode, aw_prediv_mux_clknode_class,
+ aw_prediv_mux_clknode_methods, sizeof(struct aw_clk_prediv_mux_sc),
+ clknode_class);
+
+int
+aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef)
+{
+ struct clknode *clk;
+ struct aw_clk_prediv_mux_sc *sc;
+
+ clk = clknode_create(clkdom, &aw_prediv_mux_clknode_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->offset = clkdef->offset;
+
+ sc->mux_shift = clkdef->mux_shift;
+ sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
+
+ sc->div.shift = clkdef->div.shift;
+ sc->div.mask = ((1 << clkdef->div.width) - 1) << sc->div.shift;
+ sc->div.value = clkdef->div.value;
+ sc->div.cond_shift = clkdef->div.cond_shift;
+ sc->div.cond_mask = ((1 << clkdef->div.cond_width) - 1) << sc->div.shift;
+ sc->div.cond_value = clkdef->div.cond_value;
+ sc->div.flags = clkdef->div.flags;
+
+ sc->prediv.shift = clkdef->prediv.shift;
+ sc->prediv.mask = ((1 << clkdef->prediv.width) - 1) << sc->prediv.shift;
+ sc->prediv.value = clkdef->prediv.value;
+ sc->prediv.cond_shift = clkdef->prediv.cond_shift;
+ sc->prediv.cond_mask = ((1 << clkdef->prediv.cond_width) - 1) << sc->prediv.shift;
+ sc->prediv.cond_value = clkdef->prediv.cond_value;
+ sc->prediv.flags = clkdef->prediv.flags;
+
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Index: sys/arm/allwinner/clkng/ccu_h3.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/ccu_h3.h
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#ifndef __CCU_H3_H__
+#define __CCU_H3_H__
+
+#define H3_RST_USB_PHY0 0
+#define H3_RST_USB_PHY1 1
+#define H3_RST_USB_PHY2 2
+#define H3_RST_USB_PHY3 3
+#define H3_RST_MBUS 4
+#define H3_RST_BUS_CE 5
+#define H3_RST_BUS_DMA 6
+#define H3_RST_BUS_MMC0 7
+#define H3_RST_BUS_MMC1 8
+#define H3_RST_BUS_MMC2 9
+#define H3_RST_BUS_NAND 10
+#define H3_RST_BUS_DRAM 11
+#define H3_RST_BUS_EMAC 12
+#define H3_RST_BUS_TS 13
+#define H3_RST_BUS_HSTIMER 14
+#define H3_RST_BUS_SPI0 15
+#define H3_RST_BUS_SPI1 16
+#define H3_RST_BUS_OTG 17
+#define H3_RST_BUS_EHCI0 18
+#define H3_RST_BUS_EHCI1 19
+#define H3_RST_BUS_EHCI2 20
+#define H3_RST_BUS_EHCI3 21
+#define H3_RST_BUS_OHCI0 22
+#define H3_RST_BUS_OHCI1 23
+#define H3_RST_BUS_OHCI2 24
+#define H3_RST_BUS_OHCI3 25
+#define H3_RST_BUS_VE 26
+#define H3_RST_BUS_TCON0 27
+#define H3_RST_BUS_TCON1 28
+#define H3_RST_BUS_DEINTERLACE 29
+#define H3_RST_BUS_CSI 30
+#define H3_RST_BUS_TVE 31
+#define H3_RST_BUS_HDMI0 32
+#define H3_RST_BUS_HDMI1 33
+#define H3_RST_BUS_DE 34
+#define H3_RST_BUS_GPU 35
+#define H3_RST_BUS_MSGBOX 36
+#define H3_RST_BUS_SPINLOCK 37
+#define H3_RST_BUS_DBG 38
+#define H3_RST_BUS_EPHY 39
+#define H3_RST_BUS_CODEC 40
+#define H3_RST_BUS_SPDIF 41
+#define H3_RST_BUS_THS 42
+#define H3_RST_BUS_I2S0 43
+#define H3_RST_BUS_I2S1 44
+#define H3_RST_BUS_I2S2 45
+#define H3_RST_BUS_I2C0 46
+#define H3_RST_BUS_I2C1 47
+#define H3_RST_BUS_I2C2 48
+#define H3_RST_BUS_UART0 49
+#define H3_RST_BUS_UART1 50
+#define H3_RST_BUS_UART2 51
+#define H3_RST_BUS_UART3 52
+#define H3_RST_BUS_SCR 53
+
+#define H3_CLK_PLL_CPUX 0
+#define H3_CLK_PLL_AUDIO_BASE 1
+#define H3_CLK_PLL_AUDIO 2
+#define H3_CLK_PLL_AUDIO_2X 3
+#define H3_CLK_PLL_AUDIO_4X 4
+#define H3_CLK_PLL_AUDIO_8X 5
+#define H3_CLK_PLL_VIDEO 6
+#define H3_CLK_PLL_VE 7
+#define H3_CLK_PLL_DDR 8
+#define H3_CLK_PLL_PERIPH0 9
+#define H3_CLK_PLL_PERIPH0_2X 10
+#define H3_CLK_PLL_GPU 11
+#define H3_CLK_PLL_PERIPH1 12
+#define H3_CLK_PLL_DE 13
+
+#define H3_CLK_CPUX 14
+#define H3_CLK_AXI 15
+#define H3_CLK_AHB1 16
+#define H3_CLK_APB1 17
+#define H3_CLK_APB2 18
+#define H3_CLK_AHB2 19
+
+#define H3_CLK_BUS_CE 20
+#define H3_CLK_BUS_DMA 21
+#define H3_CLK_BUS_MMC0 22
+#define H3_CLK_BUS_MMC1 23
+#define H3_CLK_BUS_MMC2 24
+#define H3_CLK_BUS_NAND 25
+#define H3_CLK_BUS_DRAM 26
+#define H3_CLK_BUS_EMAC 27
+#define H3_CLK_BUS_TS 28
+#define H3_CLK_BUS_HSTIMER 29
+#define H3_CLK_BUS_SPI0 30
+#define H3_CLK_BUS_SPI1 31
+#define H3_CLK_BUS_OTG 32
+#define H3_CLK_BUS_EHCI0 33
+#define H3_CLK_BUS_EHCI1 34
+#define H3_CLK_BUS_EHCI2 35
+#define H3_CLK_BUS_EHCI3 36
+#define H3_CLK_BUS_OHCI0 37
+#define H3_CLK_BUS_OHCI1 38
+#define H3_CLK_BUS_OHCI2 39
+#define H3_CLK_BUS_OHCI3 40
+#define H3_CLK_BUS_VE 41
+#define H3_CLK_BUS_TCON0 42
+#define H3_CLK_BUS_TCON1 43
+#define H3_CLK_BUS_DEINTERLACE 44
+#define H3_CLK_BUS_CSI 45
+#define H3_CLK_BUS_TVE 46
+#define H3_CLK_BUS_HDMI 47
+#define H3_CLK_BUS_DE 48
+#define H3_CLK_BUS_GPU 49
+#define H3_CLK_BUS_MSGBOX 50
+#define H3_CLK_BUS_SPINLOCK 51
+#define H3_CLK_BUS_CODEC 52
+#define H3_CLK_BUS_SPDIF 53
+#define H3_CLK_BUS_PIO 54
+#define H3_CLK_BUS_THS 55
+#define H3_CLK_BUS_I2S0 56
+#define H3_CLK_BUS_I2S1 57
+#define H3_CLK_BUS_I2S2 58
+#define H3_CLK_BUS_I2C0 59
+#define H3_CLK_BUS_I2C1 60
+#define H3_CLK_BUS_I2C2 61
+#define H3_CLK_BUS_UART0 62
+#define H3_CLK_BUS_UART1 63
+#define H3_CLK_BUS_UART2 64
+#define H3_CLK_BUS_UART3 65
+#define H3_CLK_BUS_SCR 66
+#define H3_CLK_BUS_EPHY 67
+#define H3_CLK_BUS_DBG 68
+
+#define H3_CLK_THS 69
+#define H3_CLK_NAND 70
+#define H3_CLK_MMC0 71
+#define H3_CLK_MMC0_SAMPLE 72
+#define H3_CLK_MMC0_OUTPUT 73
+#define H3_CLK_MMC1 74
+#define H3_CLK_MMC1_SAMPLE 75
+#define H3_CLK_MMC1_OUTPUT 76
+#define H3_CLK_MMC2 77
+#define H3_CLK_MMC2_SAMPLE 78
+#define H3_CLK_MMC2_OUTPUT 79
+#define H3_CLK_TS 80
+#define H3_CLK_CE 81
+#define H3_CLK_SPI0 82
+#define H3_CLK_SPI1 83
+#define H3_CLK_I2S0 84
+#define H3_CLK_I2S1 85
+#define H3_CLK_I2S2 86
+#define H3_CLK_SPDIF 87
+#define H3_CLK_USBPHY0 88
+#define H3_CLK_USBPHY1 89
+#define H3_CLK_USBPHY2 90
+#define H3_CLK_USBPHY3 91
+#define H3_CLK_USBOHCI0 92
+#define H3_CLK_USBOHCI1 93
+#define H3_CLK_USBOHCI2 94
+#define H3_CLK_USBOHCI3 95
+
+void ccu_h3_register_clocks(struct aw_ccung_softc *sc);
+
+#endif /* __CCU_H3_H__ */
Index: sys/arm/allwinner/clkng/ccu_h3.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/clkng/ccu_h3.c
@@ -0,0 +1,475 @@
+/*-
+ * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <arm/allwinner/clkng/aw_ccung.h>
+#include <arm/allwinner/clkng/aw_clk.h>
+#include <arm/allwinner/clkng/aw_clk_nm.h>
+#include <arm/allwinner/clkng/aw_clk_nkmp.h>
+#include <arm/allwinner/clkng/aw_clk_prediv_mux.h>
+
+#include "ccu_h3.h"
+
+static struct aw_ccung_reset h3_ccu_resets[] = {
+ CCU_RESET(H3_RST_USB_PHY0, 0xcc, 0)
+ CCU_RESET(H3_RST_USB_PHY1, 0xcc, 1)
+ CCU_RESET(H3_RST_USB_PHY2, 0xcc, 2)
+ CCU_RESET(H3_RST_USB_PHY3, 0xcc, 3)
+
+ CCU_RESET(H3_RST_MBUS, 0xfc, 31)
+
+ CCU_RESET(H3_RST_BUS_CE, 0x2c0, 5)
+ CCU_RESET(H3_RST_BUS_DMA, 0x2c0, 6)
+ CCU_RESET(H3_RST_BUS_MMC0, 0x2c0, 8)
+ CCU_RESET(H3_RST_BUS_MMC1, 0x2c0, 9)
+ CCU_RESET(H3_RST_BUS_MMC2, 0x2c0, 10)
+ CCU_RESET(H3_RST_BUS_NAND, 0x2c0, 13)
+ CCU_RESET(H3_RST_BUS_DRAM, 0x2c0, 14)
+ CCU_RESET(H3_RST_BUS_EMAC, 0x2c0, 17)
+ CCU_RESET(H3_RST_BUS_TS, 0x2c0, 18)
+ CCU_RESET(H3_RST_BUS_HSTIMER, 0x2c0, 19)
+ CCU_RESET(H3_RST_BUS_SPI0, 0x2c0, 20)
+ CCU_RESET(H3_RST_BUS_SPI1, 0x2c0, 21)
+ CCU_RESET(H3_RST_BUS_OTG, 0x2c0, 23)
+ CCU_RESET(H3_RST_BUS_EHCI0, 0x2c0, 24)
+ CCU_RESET(H3_RST_BUS_EHCI1, 0x2c0, 25)
+ CCU_RESET(H3_RST_BUS_EHCI2, 0x2c0, 26)
+ CCU_RESET(H3_RST_BUS_EHCI3, 0x2c0, 27)
+ CCU_RESET(H3_RST_BUS_OHCI0, 0x2c0, 28)
+ CCU_RESET(H3_RST_BUS_OHCI1, 0x2c0, 29)
+ CCU_RESET(H3_RST_BUS_OHCI2, 0x2c0, 30)
+ CCU_RESET(H3_RST_BUS_OHCI3, 0x2c0, 31)
+
+ CCU_RESET(H3_RST_BUS_VE, 0x2c4, 0)
+ CCU_RESET(H3_RST_BUS_TCON0, 0x2c4, 3)
+ CCU_RESET(H3_RST_BUS_TCON1, 0x2c4, 4)
+ CCU_RESET(H3_RST_BUS_DEINTERLACE, 0x2c4, 5)
+ CCU_RESET(H3_RST_BUS_CSI, 0x2c4, 8)
+ CCU_RESET(H3_RST_BUS_TVE, 0x2c4, 9)
+ CCU_RESET(H3_RST_BUS_HDMI0, 0x2c4, 10)
+ CCU_RESET(H3_RST_BUS_HDMI1, 0x2c4, 11)
+ CCU_RESET(H3_RST_BUS_DE, 0x2c4, 12)
+ CCU_RESET(H3_RST_BUS_GPU, 0x2c4, 20)
+ CCU_RESET(H3_RST_BUS_MSGBOX, 0x2c4, 21)
+ CCU_RESET(H3_RST_BUS_SPINLOCK, 0x2c4, 22)
+ CCU_RESET(H3_RST_BUS_DBG, 0x2c4, 31)
+
+ CCU_RESET(H3_RST_BUS_EPHY, 0x2c8, 2)
+
+ CCU_RESET(H3_RST_BUS_CODEC, 0x2d0, 0)
+ CCU_RESET(H3_RST_BUS_SPDIF, 0x2d0, 1)
+ CCU_RESET(H3_RST_BUS_THS, 0x2d0, 8)
+ CCU_RESET(H3_RST_BUS_I2S0, 0x2d0, 12)
+ CCU_RESET(H3_RST_BUS_I2S1, 0x2d0, 13)
+ CCU_RESET(H3_RST_BUS_I2S2, 0x2d0, 14)
+
+ CCU_RESET(H3_RST_BUS_I2C0, 0x2d8, 0)
+ CCU_RESET(H3_RST_BUS_I2C1, 0x2d8, 1)
+ CCU_RESET(H3_RST_BUS_I2C2, 0x2d8, 2)
+ CCU_RESET(H3_RST_BUS_UART0, 0x2d8, 16)
+ CCU_RESET(H3_RST_BUS_UART1, 0x2d8, 17)
+ CCU_RESET(H3_RST_BUS_UART2, 0x2d8, 18)
+ CCU_RESET(H3_RST_BUS_UART3, 0x2d8, 19)
+ CCU_RESET(H3_RST_BUS_SCR, 0x2d8, 20)
+};
+
+static struct aw_ccung_gate h3_ccu_gates[] = {
+ CCU_GATE(H3_CLK_BUS_CE, "bus-ce", "ahb1", 0x60, 5)
+ CCU_GATE(H3_CLK_BUS_DMA, "bus-dma", "ahb1", 0x60, 6)
+ CCU_GATE(H3_CLK_BUS_MMC0, "bus-mmc0", "ahb1", 0x60, 8)
+ CCU_GATE(H3_CLK_BUS_MMC1, "bus-mmc1", "ahb1", 0x60, 9)
+ CCU_GATE(H3_CLK_BUS_MMC2, "bus-mmc2", "ahb1", 0x60, 10)
+ CCU_GATE(H3_CLK_BUS_NAND, "bus-nand", "ahb1", 0x60, 13)
+ CCU_GATE(H3_CLK_BUS_DRAM, "bus-dram", "ahb1", 0x60, 14)
+ CCU_GATE(H3_CLK_BUS_EMAC, "bus-emac", "ahb2", 0x60, 17)
+ CCU_GATE(H3_CLK_BUS_TS, "bus-ts", "ahb1", 0x60, 18)
+ CCU_GATE(H3_CLK_BUS_HSTIMER, "bus-hstimer", "ahb1", 0x60, 19)
+ CCU_GATE(H3_CLK_BUS_SPI0, "bus-spi0", "ahb1", 0x60, 20)
+ CCU_GATE(H3_CLK_BUS_SPI1, "bus-spi1", "ahb1", 0x60, 21)
+ CCU_GATE(H3_CLK_BUS_OTG, "bus-otg", "ahb1", 0x60, 23)
+ CCU_GATE(H3_CLK_BUS_EHCI0, "bus-ehci0", "ahb1", 0x60, 24)
+ CCU_GATE(H3_CLK_BUS_EHCI1, "bus-ehci1", "ahb2", 0x60, 25)
+ CCU_GATE(H3_CLK_BUS_EHCI2, "bus-ehci2", "ahb2", 0x60, 26)
+ CCU_GATE(H3_CLK_BUS_EHCI3, "bus-ehci3", "ahb2", 0x60, 27)
+ CCU_GATE(H3_CLK_BUS_OHCI0, "bus-ohci0", "ahb1", 0x60, 28)
+ CCU_GATE(H3_CLK_BUS_OHCI1, "bus-ohci1", "ahb2", 0x60, 29)
+ CCU_GATE(H3_CLK_BUS_OHCI2, "bus-ohci2", "ahb2", 0x60, 30)
+ CCU_GATE(H3_CLK_BUS_OHCI3, "bus-ohci3", "ahb2", 0x60, 31)
+
+ CCU_GATE(H3_CLK_BUS_VE, "bus-ve", "ahb1", 0x64, 0)
+ CCU_GATE(H3_CLK_BUS_TCON0, "bus-tcon0", "ahb1", 0x64, 3)
+ CCU_GATE(H3_CLK_BUS_TCON1, "bus-tcon1", "ahb1", 0x64, 4)
+ CCU_GATE(H3_CLK_BUS_DEINTERLACE, "bus-deinterlace", "ahb1", 0x64, 5)
+ CCU_GATE(H3_CLK_BUS_CSI, "bus-csi", "ahb1", 0x64, 8)
+ CCU_GATE(H3_CLK_BUS_TVE, "bus-tve", "ahb1", 0x64, 9)
+ CCU_GATE(H3_CLK_BUS_HDMI, "bus-hdmi", "ahb1", 0x64, 11)
+ CCU_GATE(H3_CLK_BUS_DE, "bus-de", "ahb1", 0x64, 12)
+ CCU_GATE(H3_CLK_BUS_GPU, "bus-gpu", "ahb1", 0x64, 20)
+ CCU_GATE(H3_CLK_BUS_MSGBOX, "bus-msgbox", "ahb1", 0x64, 21)
+ CCU_GATE(H3_CLK_BUS_SPINLOCK, "bus-spinlock", "ahb1", 0x64, 22)
+
+ CCU_GATE(H3_CLK_BUS_CODEC, "bus-codec", "apb1", 0x68, 0)
+ CCU_GATE(H3_CLK_BUS_SPDIF, "bus-spdif", "apb1", 0x68, 1)
+ CCU_GATE(H3_CLK_BUS_PIO, "bus-pio", "apb1", 0x68, 5)
+ CCU_GATE(H3_CLK_BUS_THS, "bus-ths", "apb1", 0x68, 8)
+ CCU_GATE(H3_CLK_BUS_I2S0, "bus-i2c0", "apb1", 0x68, 12)
+ CCU_GATE(H3_CLK_BUS_I2S1, "bus-i2c1", "apb1", 0x68, 13)
+ CCU_GATE(H3_CLK_BUS_I2S2, "bus-i2c2", "apb1", 0x68, 14)
+
+ CCU_GATE(H3_CLK_BUS_I2C0, "bus-i2c0", "apb2", 0x6c, 0)
+ CCU_GATE(H3_CLK_BUS_I2C1, "bus-i2c1", "apb2", 0x6c, 1)
+ CCU_GATE(H3_CLK_BUS_I2C2, "bus-i2c2", "apb2", 0x6c, 2)
+ CCU_GATE(H3_CLK_BUS_UART0, "bus-uart0", "apb2", 0x6c, 16)
+ CCU_GATE(H3_CLK_BUS_UART1, "bus-uart1", "apb2", 0x6c, 17)
+ CCU_GATE(H3_CLK_BUS_UART2, "bus-uart2", "apb2", 0x6c, 18)
+ CCU_GATE(H3_CLK_BUS_UART3, "bus-uart3", "apb2", 0x6c, 19)
+ CCU_GATE(H3_CLK_BUS_SCR, "bus-scr", "apb2", 0x6c, 20)
+
+ CCU_GATE(H3_CLK_BUS_EPHY, "bus-ephy", "ahb1", 0x70, 0)
+ CCU_GATE(H3_CLK_BUS_DBG, "bus-dbg", "ahb1", 0x70, 7)
+
+ CCU_GATE(H3_CLK_USBPHY0, "usb-phy0", "osc24M", 0xcc, 8)
+ CCU_GATE(H3_CLK_USBPHY1, "usb-phy1", "osc24M", 0xcc, 9)
+ CCU_GATE(H3_CLK_USBPHY2, "usb-phy2", "osc24M", 0xcc, 10)
+ CCU_GATE(H3_CLK_USBPHY3, "usb-phy3", "osc24M", 0xcc, 11)
+ CCU_GATE(H3_CLK_USBOHCI0, "usb-ohci0", "osc24M", 0xcc, 16)
+ CCU_GATE(H3_CLK_USBOHCI1, "usb-ohci1", "osc24M", 0xcc, 17)
+ CCU_GATE(H3_CLK_USBOHCI2, "usb-ohci2", "osc24M", 0xcc, 18)
+ CCU_GATE(H3_CLK_USBOHCI3, "usb-ohci3", "osc24M", 0xcc, 19)
+
+ CCU_GATE(H3_CLK_THS, "ths", "thsdiv", 0x74, 31)
+ CCU_GATE(H3_CLK_I2S0, "i2s0", "i2s0mux", 0xB0, 31)
+ CCU_GATE(H3_CLK_I2S1, "i2s1", "i2s1mux", 0xB4, 31)
+ CCU_GATE(H3_CLK_I2S2, "i2s2", "i2s2mux", 0xB8, 31)
+};
+
+static const char *pll_cpux_parents[] = {"osc24M"};
+static const char *pll_audio_parents[] = {"osc24M"};
+static const char *pll_audio_mult_parents[] = {"pll_audio"};
+/*
+ * Need fractional mode on nkmp or a NM fract
+static const char *pll_video_parents[] = {"osc24M"};
+ */
+/*
+ * Need fractional mode on nkmp or a NM fract
+static const char *pll_ve_parents[] = {"osc24M"};
+ */
+/*
+ * Needs a update bit on nkmp or special clk
+static const char *pll_ddr_parents[] = {"osc24M"};
+ */
+static const char *pll_periph0_parents[] = {"osc24M"};
+static const char *pll_periph0_2x_parents[] = {"pll_periph0"};
+/*
+ * Need fractional mode on nkmp or a NM fract
+static const char *pll_gpu_parents[] = {"osc24M"};
+ */
+static const char *pll_periph1_parents[] = {"osc24M"};
+/*
+ * Need fractional mode on nkmp or a NM fract
+static const char *pll_de_parents[] = {"osc24M"};
+ */
+
+static struct aw_clk_nkmp_def nkmp_clks[] = {
+ NKMP_CLK(H3_CLK_PLL_CPUX, /* id */
+ "pll_cpux", pll_cpux_parents, /* name, parents */
+ 0x00, /* offset */
+ 8, 5, 0, 0, /* n factor */
+ 4, 2, 0, 0, /* k factor */
+ 0, 2, 0, 0, /* m factor */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* p factor */
+ 31, /* gate */
+ 28, 1000, /* lock */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK | AW_CLK_SCALE_CHANGE) /* flags */
+ NKMP_CLK(H3_CLK_PLL_AUDIO, /* id */
+ "pll_audio", pll_audio_parents, /* name, parents */
+ 0x08, /* offset */
+ 8, 7, 0, 0, /* n factor */
+ 0, 0, 1, AW_CLK_FACTOR_FIXED, /* k factor (fake) */
+ 0, 5, 0, 0, /* m factor */
+ 16, 4, 0, 0, /* p factor */
+ 31, /* gate */
+ 28, 1000, /* lock */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK) /* flags */
+ NKMP_CLK(H3_CLK_PLL_PERIPH0, /* id */
+ "pll_periph0", pll_periph0_parents, /* name, parents */
+ 0x28, /* offset */
+ 8, 5, 0, 0, /* n factor */
+ 4, 2, 0, 0, /* k factor */
+ 0, 0, 2, AW_CLK_FACTOR_FIXED, /* m factor (fake) */
+ 0, 0, 1, AW_CLK_FACTOR_FIXED, /* p factor (fake) */
+ 31, /* gate */
+ 28, 1000, /* lock */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK) /* flags */
+ NKMP_CLK(H3_CLK_PLL_PERIPH1, /* id */
+ "pll_periph1", pll_periph1_parents, /* name, parents */
+ 0x44, /* offset */
+ 8, 5, 0, 0, /* n factor */
+ 4, 2, 0, 0, /* k factor */
+ 0, 0, 2, AW_CLK_FACTOR_FIXED, /* m factor (fake) */
+ 0, 0, 1, AW_CLK_FACTOR_FIXED, /* p factor (fake) */
+ 31, /* gate */
+ 28, 1000, /* lock */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK) /* flags */
+};
+
+static const char *ahb1_parents[] = {"osc32k", "osc24M", "axi", "pll_periph0"};
+static const char *ahb2_parents[] = {"ahb1", "pll_periph0"};
+
+static struct aw_clk_prediv_mux_def prediv_mux_clks[] = {
+ PREDIV_CLK(H3_CLK_AHB1, /* id */
+ "ahb1", ahb1_parents, /* name, parents */
+ 0x54, /* offset */
+ 12, 2, /* mux */
+ 4, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* div */
+ 6, 2, 0, AW_CLK_FACTOR_HAS_COND, /* prediv */
+ 12, 2, 3) /* prediv condition */
+ PREDIV_CLK(H3_CLK_AHB2, /* id */
+ "ahb2", ahb2_parents, /* name, parents */
+ 0x5c, /* offset */
+ 0, 2, /* mux */
+ 0, 0, 1, AW_CLK_FACTOR_FIXED, /* div */
+ 0, 0, 2, AW_CLK_FACTOR_HAS_COND | AW_CLK_FACTOR_FIXED, /* prediv */
+ 0, 2, 1) /* prediv condition */
+};
+
+static const char *apb2_parents[] = {"osc32k", "osc24M", "pll_periph0", "pll_periph0"};
+static const char *mod_parents[] = {"osc24M", "pll_periph0", "pll_periph1"};
+static const char *ts_parents[] = {"osc24M", "pll_periph0"};
+static const char *spdif_parents[] = {"pll_audio"};
+static const char *i2s_parents[] = {"pll_audio-8x", "pll_audio-4x", "pll_audio-2x", "pll_audio"};
+
+static struct aw_clk_nm_def nm_clks[] = {
+ NM_CLK(H3_CLK_APB2, /* id */
+ "apb2", apb2_parents, /* name, parents */
+ 0x58, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 5, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 0, /* gate */
+ AW_CLK_HAS_MUX)
+ NM_CLK(H3_CLK_NAND, "nand", mod_parents, /* id, name, parents */
+ 0x80, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX) /* flags */
+ NM_CLK(H3_CLK_MMC0, "mmc0", mod_parents, /* id, name, parents */
+ 0x88, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
+ AW_CLK_REPARENT) /* flags */
+ NM_CLK(H3_CLK_MMC1, "mmc1", mod_parents, /* id, name, parents */
+ 0x8c, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
+ AW_CLK_REPARENT) /* flags */
+ NM_CLK(H3_CLK_MMC2, "mmc2", mod_parents, /* id, name, parents */
+ 0x90, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
+ AW_CLK_REPARENT) /* flags */
+ NM_CLK(H3_CLK_TS, "ts", ts_parents, /* id, name, parents */
+ 0x98, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX) /* flags */
+ NM_CLK(H3_CLK_CE, "ce", mod_parents, /* id, name, parents */
+ 0x9C, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX) /* flags */
+ NM_CLK(H3_CLK_SPI0, "spi0", mod_parents, /* id, name, parents */
+ 0xA0, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
+ AW_CLK_REPARENT) /* flags */
+ NM_CLK(H3_CLK_SPI1, "spi1", mod_parents, /* id, name, parents */
+ 0xA4, /* offset */
+ 16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
+ 0, 4, 0, 0, /* m factor */
+ 24, 2, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
+ AW_CLK_REPARENT) /* flags */
+ NM_CLK(H3_CLK_SPDIF, "spdif", spdif_parents, /* id, name, parents */
+ 0xC0, /* offset */
+ 0, 0, 1, AW_CLK_FACTOR_FIXED, /* n factor (fake) */
+ 0, 4, 0, 0, /* m factor */
+ 0, 0, /* mux */
+ 31, /* gate */
+ AW_CLK_HAS_GATE) /* flags */
+
+};
+
+static const char *cpux_parents[] = {"osc32k", "osc24M", "pll_cpux", "pll_cpux"};
+
+static struct clk_mux_def mux_clks[] = {
+ MUX_CLK(H3_CLK_CPUX, /* id */
+ "cpux", cpux_parents, /* name, parents */
+ 0x50, 16, 2) /* offset, shift, width */
+ MUX_CLK(0,
+ "i2s0mux", i2s_parents,
+ 0xb0, 16, 2)
+ MUX_CLK(0,
+ "i2s1mux", i2s_parents,
+ 0xb4, 16, 2)
+ MUX_CLK(0,
+ "i2s2mux", i2s_parents,
+ 0xb8, 16, 2)
+};
+
+static struct clk_div_table apb1_div_table[] = {
+ { .value = 0, .divider = 2, },
+ { .value = 1, .divider = 2, },
+ { .value = 2, .divider = 4, },
+ { .value = 3, .divider = 8, },
+ { },
+};
+
+static struct clk_div_table ths_div_table[] = {
+ { .value = 0, .divider = 1, },
+ { .value = 1, .divider = 2, },
+ { .value = 2, .divider = 4, },
+ { .value = 3, .divider = 6, },
+ { },
+};
+
+static const char *ths_parents[] = {"osc24M"};
+static const char *axi_parents[] = {"cpux"};
+static const char *apb1_parents[] = {"ahb1"};
+
+static struct clk_div_def div_clks[] = {
+ DIV_CLK(H3_CLK_AXI, /* id */
+ "axi", axi_parents, /* name, parents */
+ 0x50, /* offset */
+ 0, 2, /* shift, width */
+ 0, NULL) /* flags, div table */
+ DIV_CLK(H3_CLK_APB1, /* id */
+ "apb1", apb1_parents, /* name, parents */
+ 0x54, /* offset */
+ 8, 2, /* shift, width */
+ CLK_DIV_WITH_TABLE, /* flags */
+ apb1_div_table) /* div table */
+ DIV_CLK(0, /* id */
+ "thsdiv", ths_parents, /* name, parents */
+ 0x74, /* offset */
+ 0, 2, /* shift, width */
+ CLK_DIV_WITH_TABLE, /* flags */
+ ths_div_table) /* div table */
+};
+
+static struct clk_fixed_def fixed_factor_clks[] = {
+ FIXED_CLK(H3_CLK_PLL_PERIPH0_2X, /* id */
+ "pll_periph0-2x", /* name */
+ pll_periph0_2x_parents, /* parent */
+ 0, /* freq */
+ 2, /* mult */
+ 1, /* div */
+ 0) /* flags */
+ FIXED_CLK(H3_CLK_PLL_AUDIO_2X, /* id */
+ "pll_audio-2x", /* name */
+ pll_audio_mult_parents, /* parent */
+ 0, /* freq */
+ 2, /* mult */
+ 1, /* div */
+ 0) /* flags */
+ FIXED_CLK(H3_CLK_PLL_AUDIO_4X, /* id */
+ "pll_audio-4x", /* name */
+ pll_audio_mult_parents, /* parent */
+ 0, /* freq */
+ 4, /* mult */
+ 1, /* div */
+ 0) /* flags */
+ FIXED_CLK(H3_CLK_PLL_AUDIO_8X, /* id */
+ "pll_audio-8x", /* name */
+ pll_audio_mult_parents, /* parent */
+ 0, /* freq */
+ 8, /* mult */
+ 1, /* div */
+ 0) /* flags */
+};
+
+static struct aw_clk_init init_clks[] = {
+ {"ahb1", "pll_periph0", 0, false},
+ {"ahb2", "pll_periph0", 0, false},
+};
+
+void
+ccu_h3_register_clocks(struct aw_ccung_softc *sc)
+{
+ int i;
+
+ sc->resets = h3_ccu_resets;
+ sc->nresets = nitems(h3_ccu_resets);
+ sc->gates = h3_ccu_gates;
+ sc->ngates = nitems(h3_ccu_gates);
+ sc->clk_init = init_clks;
+ sc->n_clk_init = nitems(init_clks);
+
+ for (i = 0; i < nitems(nkmp_clks); i++)
+ aw_clk_nkmp_register(sc->clkdom, &nkmp_clks[i]);
+ for (i = 0; i < nitems(nm_clks); i++)
+ aw_clk_nm_register(sc->clkdom, &nm_clks[i]);
+ for (i = 0; i < nitems(prediv_mux_clks); i++)
+ aw_clk_prediv_mux_register(sc->clkdom, &prediv_mux_clks[i]);
+
+ for (i = 0; i < nitems(mux_clks); i++)
+ clknode_mux_register(sc->clkdom, &mux_clks[i]);
+ for (i = 0; i < nitems(div_clks); i++)
+ clknode_div_register(sc->clkdom, &div_clks[i]);
+ for (i = 0; i < nitems(fixed_factor_clks); i++)
+ clknode_fixed_register(sc->clkdom, &fixed_factor_clks[i]);
+}
Index: sys/arm/allwinner/files.allwinner
===================================================================
--- sys/arm/allwinner/files.allwinner
+++ sys/arm/allwinner/files.allwinner
@@ -56,3 +56,8 @@
arm/allwinner/clk/aw_pll.c standard
arm/allwinner/clk/aw_thsclk.c standard
arm/allwinner/clk/aw_usbclk.c standard
+
+arm/allwinner/clkng/aw_ccung.c standard
+arm/allwinner/clkng/aw_clk_nkmp.c standard
+arm/allwinner/clkng/aw_clk_nm.c standard
+arm/allwinner/clkng/aw_clk_prediv_mux.c standard
Index: sys/arm/allwinner/h3/files.h3
===================================================================
--- sys/arm/allwinner/h3/files.h3
+++ sys/arm/allwinner/h3/files.h3
@@ -1,4 +1,5 @@
# $FreeBSD$
+arm/allwinner/clkng/ccu_h3.c standard
arm/allwinner/h3/h3_padconf.c standard
arm/allwinner/h3/h3_r_padconf.c standard

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 18, 4:48 AM (1 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25480543
Default Alt Text
D9517.id25611.diff (71 KB)

Event Timeline