svn commit: r330036 - in head/sys: arm64/conf arm64/rockchip arm64/rockchip/clk conf
Emmanuel Vadot
manu at FreeBSD.org
Mon Feb 26 21:25:52 UTC 2018
Author: manu
Date: Mon Feb 26 21:25:50 2018
New Revision: 330036
URL: https://svnweb.freebsd.org/changeset/base/330036
Log:
rk3328: Add support for this SoC
* rk_cru is a cru driver that needs to be subclassed by
the real CRU driver
* rk_clk_pll handle the pll type clock on RockChip SoC, it's only read
only for now.
* rk_clk_composite handle the different composite clock types (with gate,
with mux etc ...)
* rk_clk_gate handle the RockChip gates
* rk_clk_mux handle the RockChip muxes (unused for now)
* Only clocks for supported devices are supported for now, the rest will be
added when driver support comes
* The assigned-clock* property are not handled for now so we rely a lot on the
bootloader to setup some initial values for some clocks.
Added:
head/sys/arm64/rockchip/
head/sys/arm64/rockchip/clk/
head/sys/arm64/rockchip/clk/rk3328_cru.c (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_composite.c (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_composite.h (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_gate.c (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_gate.h (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_mux.c (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_mux.h (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_pll.c (contents, props changed)
head/sys/arm64/rockchip/clk/rk_clk_pll.h (contents, props changed)
head/sys/arm64/rockchip/clk/rk_cru.c (contents, props changed)
head/sys/arm64/rockchip/clk/rk_cru.h (contents, props changed)
Modified:
head/sys/arm64/conf/GENERIC
head/sys/conf/files.arm64
head/sys/conf/options.arm64
Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC Mon Feb 26 20:31:16 2018 (r330035)
+++ head/sys/arm64/conf/GENERIC Mon Feb 26 21:25:50 2018 (r330036)
@@ -97,6 +97,7 @@ options SOC_ALLWINNER_H5
options SOC_CAVM_THUNDERX
options SOC_HISI_HI6220
options SOC_BRCM_BCM2837
+options SOC_ROCKCHIP_RK3328
# Annapurna Alpine drivers
device al_ccu # Alpine Cache Coherency Unit
Added: head/sys/arm64/rockchip/clk/rk3328_cru.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk3328_cru.c Mon Feb 26 21:25:50 2018 (r330036)
@@ -0,0 +1,476 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Emmanuel Vadot <manu at 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 <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_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <arm64/rockchip/clk/rk_cru.h>
+
+/* GATES */
+
+#define ACLK_PERI 153
+#define HCLK_SDMMC 317
+#define HCLK_SDIO 318
+#define HCLK_EMMC 319
+#define HCLK_SDMMC_EXT 320
+
+static struct rk_cru_gate rk3328_gates[] = {
+ /* CRU_CLKGATE_CON0 */
+ CRU_GATE(0, "apll_core", "apll", 0x200, 0)
+ CRU_GATE(0, "dpll_core", "dpll", 0x200, 1)
+ CRU_GATE(0, "gpll_core", "gpll", 0x200, 2)
+ CRU_GATE(0, "npll_core", "npll", 0x200, 12)
+
+ /* CRU_CLKGATE_CON4 */
+ CRU_GATE(0, "gpll_peri", "gpll", 0x210, 0)
+ CRU_GATE(0, "cpll_peri", "cpll", 0x210, 1)
+
+ /* CRU_CLKGATE_CON8 */
+ CRU_GATE(0, "pclk_bus", "pclk_bus_pre", 0x220, 3)
+ CRU_GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0x220, 4)
+
+ /* CRU_CLKGATE_CON10 */
+ CRU_GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre", 0x228, 0)
+
+ /* CRU_CLKGATE_CON19 */
+ CRU_GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0x24C, 0)
+ CRU_GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0x24C, 1)
+ CRU_GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0x24C, 2)
+ CRU_GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0x24C, 15)
+};
+
+/*
+ * PLLs
+ */
+
+#define PLL_APLL 1
+#define PLL_DPLL 2
+#define PLL_CPLL 3
+#define PLL_GPLL 4
+#define PLL_NPLL 5
+
+static const char *pll_parents[] = {"xin24m"};
+static struct rk_clk_pll_def apll = {
+ .clkdef = {
+ .id = PLL_APLL,
+ .name = "apll",
+ .parent_names = pll_parents,
+ .parent_cnt = nitems(pll_parents),
+ },
+ .base_offset = 0x00,
+ .gate_offset = 0x200,
+ .gate_shift = 0,
+ .flags = RK_CLK_PLL_HAVE_GATE,
+};
+
+static struct rk_clk_pll_def dpll = {
+ .clkdef = {
+ .id = PLL_DPLL,
+ .name = "dpll",
+ .parent_names = pll_parents,
+ .parent_cnt = nitems(pll_parents),
+ },
+ .base_offset = 0x20,
+ .gate_offset = 0x200,
+ .gate_shift = 1,
+ .flags = RK_CLK_PLL_HAVE_GATE,
+};
+
+static struct rk_clk_pll_def cpll = {
+ .clkdef = {
+ .id = PLL_CPLL,
+ .name = "cpll",
+ .parent_names = pll_parents,
+ .parent_cnt = nitems(pll_parents),
+ },
+ .base_offset = 0x40,
+};
+
+static struct rk_clk_pll_def gpll = {
+ .clkdef = {
+ .id = PLL_GPLL,
+ .name = "gpll",
+ .parent_names = pll_parents,
+ .parent_cnt = nitems(pll_parents),
+ },
+ .base_offset = 0x60,
+ .gate_offset = 0x200,
+ .gate_shift = 2,
+ .flags = RK_CLK_PLL_HAVE_GATE,
+};
+
+static struct rk_clk_pll_def npll = {
+ .clkdef = {
+ .id = PLL_NPLL,
+ .name = "npll",
+ .parent_names = pll_parents,
+ .parent_cnt = nitems(pll_parents),
+ },
+ .base_offset = 0xa0,
+ .gate_offset = 0x200,
+ .gate_shift = 12,
+ .flags = RK_CLK_PLL_HAVE_GATE,
+};
+
+/* CRU_CLKSEL_CON0 */
+#define ACLK_BUS_PRE 136
+
+/* Needs hdmiphy as parent too*/
+static const char *aclk_bus_pre_parents[] = {"cpll", "gpll"};
+static struct rk_clk_composite_def aclk_bus_pre = {
+ .clkdef = {
+ .id = ACLK_BUS_PRE,
+ .name = "aclk_bus_pre",
+ .parent_names = aclk_bus_pre_parents,
+ .parent_cnt = nitems(aclk_bus_pre_parents),
+ },
+ .muxdiv_offset = 0x100,
+ .mux_shift = 13,
+ .mux_width = 2,
+
+ .div_shift = 8,
+ .div_width = 5,
+
+ .gate_offset = 0x232,
+ .gate_shift = 0,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+/* CRU_CLKSEL_CON1 */
+
+#define PCLK_BUS_PRE 216
+#define HCLK_BUS_PRE 328
+
+static const char *hclk_bus_pre_parents[] = {"aclk_bus_pre"};
+static struct rk_clk_composite_def hclk_bus_pre = {
+ .clkdef = {
+ .id = HCLK_BUS_PRE,
+ .name = "hclk_bus_pre",
+ .parent_names = hclk_bus_pre_parents,
+ .parent_cnt = nitems(hclk_bus_pre_parents),
+ },
+ .muxdiv_offset = 0x104,
+
+ .div_shift = 8,
+ .div_width = 2,
+
+ .gate_offset = 0x232,
+ .gate_shift = 1,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+static const char *pclk_bus_pre_parents[] = {"aclk_bus_pre"};
+static struct rk_clk_composite_def pclk_bus_pre = {
+ .clkdef = {
+ .id = PCLK_BUS_PRE,
+ .name = "pclk_bus_pre",
+ .parent_names = pclk_bus_pre_parents,
+ .parent_cnt = nitems(pclk_bus_pre_parents),
+ },
+ .muxdiv_offset = 0x104,
+
+ .div_shift = 12,
+ .div_width = 3,
+
+ .gate_offset = 0x232,
+ .gate_shift = 2,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+/* CRU_CLKSEL_CON28 */
+
+#define ACLK_PERI_PRE 137
+
+static const char *aclk_peri_pre_parents[] = {"cpll", "gpll"/* , "hdmiphy" */};
+static struct rk_clk_composite_def aclk_peri_pre = {
+ .clkdef = {
+ .id = ACLK_PERI_PRE,
+ .name = "aclk_peri_pre",
+ .parent_names = aclk_peri_pre_parents,
+ .parent_cnt = nitems(aclk_peri_pre_parents),
+ },
+ .muxdiv_offset = 0x170,
+
+ .mux_shift = 6,
+ .mux_width = 2,
+
+ .div_shift = 0,
+ .div_width = 5,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_MUX,
+};
+
+/* CRU_CLKSEL_CON29 */
+
+#define PCLK_PERI 230
+#define HCLK_PERI 308
+
+static const char *phclk_peri_parents[] = {"aclk_peri_pre"};
+static struct rk_clk_composite_def pclk_peri = {
+ .clkdef = {
+ .id = PCLK_PERI,
+ .name = "pclk_peri",
+ .parent_names = phclk_peri_parents,
+ .parent_cnt = nitems(phclk_peri_parents),
+ },
+
+ .div_shift = 0,
+ .div_width = 2,
+
+ /* CRU_CLKGATE_CON10 */
+ .gate_offset = 0x228,
+ .gate_shift = 2,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+static struct rk_clk_composite_def hclk_peri = {
+ .clkdef = {
+ .id = HCLK_PERI,
+ .name = "hclk_peri",
+ .parent_names = phclk_peri_parents,
+ .parent_cnt = nitems(phclk_peri_parents),
+ },
+
+ .div_shift = 4,
+ .div_width = 3,
+
+ /* CRU_CLKGATE_CON10 */
+ .gate_offset = 0x228,
+ .gate_shift = 1,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+/* CRU_CLKSEL_CON30 */
+
+#define SCLK_SDMMC 33
+
+static const char *mmc_parents[] = {"cpll", "gpll", "xin24m"/* , "usb480m" */};
+static struct rk_clk_composite_def sdmmc = {
+ .clkdef = {
+ .id = SCLK_SDMMC,
+ .name = "clk_sdmmc",
+ .parent_names = mmc_parents,
+ .parent_cnt = nitems(mmc_parents),
+ },
+ .muxdiv_offset = 0x178,
+
+ .mux_shift = 8,
+ .mux_width = 2,
+
+ .div_shift = 0,
+ .div_width = 8,
+
+ /* CRU_CLKGATE_CON4 */
+ .gate_offset = 0x210,
+ .gate_shift = 3,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+/* CRU_CLKSEL_CON31 */
+#define SCLK_SDIO 34
+
+static struct rk_clk_composite_def sdio = {
+ .clkdef = {
+ .id = SCLK_SDIO,
+ .name = "clk_sdio",
+ .parent_names = mmc_parents,
+ .parent_cnt = nitems(mmc_parents),
+ },
+ .muxdiv_offset = 0x17C,
+
+ .mux_shift = 8,
+ .mux_width = 2,
+
+ .div_shift = 0,
+ .div_width = 8,
+
+ /* CRU_CLKGATE_CON4 */
+ .gate_offset = 0x210,
+ .gate_shift = 4,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+/* CRU_CLKSEL_CON32 */
+#define SCLK_EMMC 35
+
+static struct rk_clk_composite_def emmc = {
+ .clkdef = {
+ .id = SCLK_EMMC,
+ .name = "clk_emmc",
+ .parent_names = mmc_parents,
+ .parent_cnt = nitems(mmc_parents),
+ },
+ .muxdiv_offset = 0x180,
+
+ .mux_shift = 8,
+ .mux_width = 2,
+
+ .div_shift = 0,
+ .div_width = 8,
+
+ /* CRU_CLKGATE_CON4 */
+ .gate_offset = 0x210,
+ .gate_shift = 5,
+
+ .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
+};
+
+static struct rk_clk rk3328_clks[] = {
+ [PLL_APLL] = {
+ .type = RK_CLK_PLL,
+ .clk.pll = &apll
+ },
+ [PLL_DPLL] = {
+ .type = RK_CLK_PLL,
+ .clk.pll = &dpll
+ },
+ [PLL_CPLL] = {
+ .type = RK_CLK_PLL,
+ .clk.pll = &cpll
+ },
+ [PLL_GPLL] = {
+ .type = RK_CLK_PLL,
+ .clk.pll = &gpll
+ },
+ [PLL_NPLL] = {
+ .type = RK_CLK_PLL,
+ .clk.pll = &npll
+ },
+
+ [ACLK_BUS_PRE] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &aclk_bus_pre
+ },
+ [HCLK_BUS_PRE] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &hclk_bus_pre
+ },
+ [PCLK_BUS_PRE] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &pclk_bus_pre
+ },
+
+ [ACLK_PERI_PRE] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &aclk_peri_pre,
+ },
+ [PCLK_PERI] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &pclk_peri,
+ },
+ [HCLK_PERI] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &hclk_peri,
+ },
+ [SCLK_SDMMC] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &sdmmc
+ },
+ [SCLK_SDIO] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &sdio
+ },
+ [SCLK_EMMC] = {
+ .type = RK_CLK_COMPOSITE,
+ .clk.composite = &emmc
+ },
+};
+
+static int
+rk3328_cru_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_is_compatible(dev, "rockchip,rk3328-cru")) {
+ device_set_desc(dev, "Rockchip RK3328 Clock and Reset Unit");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+rk3328_cru_attach(device_t dev)
+{
+ struct rk_cru_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ sc->gates = rk3328_gates;
+ sc->ngates = nitems(rk3328_gates);
+
+ sc->clks = rk3328_clks;
+ sc->nclks = nitems(rk3328_clks);
+
+ return (rk_cru_attach(dev));
+}
+
+static device_method_t rk3328_cru_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rk3328_cru_probe),
+ DEVMETHOD(device_attach, rk3328_cru_attach),
+
+ DEVMETHOD_END
+};
+
+static devclass_t rk3328_cru_devclass;
+
+DEFINE_CLASS_1(rk3328_cru, rk3328_cru_driver, rk3328_cru_methods,
+ sizeof(struct rk_cru_softc), rk_cru_driver);
+
+EARLY_DRIVER_MODULE(rk3328_cru, simplebus, rk3328_cru_driver,
+ rk3328_cru_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
Added: head/sys/arm64/rockchip/clk/rk_clk_composite.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk_clk_composite.c Mon Feb 26 21:25:50 2018 (r330036)
@@ -0,0 +1,255 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Emmanuel Vadot <manu at 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 <arm64/rockchip/clk/rk_clk_composite.h>
+
+#include "clkdev_if.h"
+
+struct rk_clk_composite_sc {
+ uint32_t muxdiv_offset;
+ uint32_t mux_shift;
+ uint32_t mux_width;
+ uint32_t mux_mask;
+
+ uint32_t div_shift;
+ uint32_t div_width;
+ uint32_t div_mask;
+
+ uint32_t gate_offset;
+ 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))
+
+#define RK_COMPOSITE_WRITE_MASK 0xFFFF0000
+
+static int
+rk_clk_composite_init(struct clknode *clk, device_t dev)
+{
+ struct rk_clk_composite_sc *sc;
+ uint32_t val, idx;
+
+ sc = clknode_get_softc(clk);
+
+ idx = 0;
+ if ((sc->flags & RK_CLK_COMPOSITE_HAVE_MUX) != 0) {
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->muxdiv_offset, &val);
+ DEVICE_UNLOCK(clk);
+
+ idx = (val & sc->mux_mask) >> sc->mux_shift;
+ }
+
+ clknode_init_parent_idx(clk, idx);
+
+ return (0);
+}
+
+static int
+rk_clk_composite_set_gate(struct clknode *clk, bool enable)
+{
+ struct rk_clk_composite_sc *sc;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+
+ if ((sc->flags & RK_CLK_COMPOSITE_HAVE_GATE) == 0)
+ return (0);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->gate_offset, &val);
+ if (enable)
+ val &= ~(1 << sc->gate_shift);
+ else
+ val |= 1 << sc->gate_shift;
+ WRITE4(clk, sc->gate_offset, val | RK_CLK_COMPOSITE_MASK);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+rk_clk_composite_set_mux(struct clknode *clk, int index)
+{
+ struct rk_clk_composite_sc *sc;
+ uint32_t val;
+
+ sc = clknode_get_softc(clk);
+
+ if ((sc->flags & RK_CLK_COMPOSITE_HAVE_MUX) == 0)
+ return (0);
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->muxdiv_offset, &val);
+ val &= ~(sc->mux_mask >> sc->mux_shift);
+ val |= index << sc->mux_shift;
+ WRITE4(clk, sc->muxdiv_offset, val);
+ DEVICE_UNLOCK(clk);
+
+ return (0);
+}
+
+static int
+rk_clk_composite_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct rk_clk_composite_sc *sc;
+ uint32_t reg, div;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(clk);
+
+ READ4(clk, sc->muxdiv_offset, ®);
+
+ DEVICE_UNLOCK(clk);
+
+ div = ((reg & sc->div_mask) >> sc->div_shift) + 1;
+
+ *freq = *freq / div;
+
+ return (0);
+}
+
+static int
+rk_clk_composite_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct rk_clk_composite_sc *sc;
+ uint64_t best, cur;
+ uint32_t div, best_div, val;
+
+ sc = clknode_get_softc(clk);
+
+ for (best = 0, best_div = 0, div = 0; div <= sc->div_mask; div++) {
+ cur = fparent / div;
+ if ((*fout - cur) < (*fout - best)) {
+ best = cur;
+ best_div = div;
+ break;
+ }
+ }
+
+ if (best_div == 0)
+ 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 ((flags & CLK_SET_DRYRUN) != 0) {
+ *fout = best;
+ *stop = 1;
+ return (0);
+ }
+
+ DEVICE_LOCK(clk);
+ READ4(clk, sc->muxdiv_offset, &val);
+ val &= ~sc->div_mask;
+ val |= (best_div - 1) << sc->div_shift;
+ WRITE4(clk, sc->muxdiv_offset, val | RK_CLK_COMPOSITE_MASK);
+ DEVICE_UNLOCK(clk);
+
+ *fout = best;
+ *stop = 1;
+
+ return (0);
+}
+
+static clknode_method_t rk_clk_composite_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, rk_clk_composite_init),
+ CLKNODEMETHOD(clknode_set_gate, rk_clk_composite_set_gate),
+ CLKNODEMETHOD(clknode_set_mux, rk_clk_composite_set_mux),
+ CLKNODEMETHOD(clknode_recalc_freq, rk_clk_composite_recalc),
+ CLKNODEMETHOD(clknode_set_freq, rk_clk_composite_set_freq),
+ CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(rk_clk_composite_clknode, rk_clk_composite_clknode_class,
+ rk_clk_composite_clknode_methods, sizeof(struct rk_clk_composite_sc),
+ clknode_class);
+
+int
+rk_clk_composite_register(struct clkdom *clkdom, struct rk_clk_composite_def *clkdef)
+{
+ struct clknode *clk;
+ struct rk_clk_composite_sc *sc;
+
+ clk = clknode_create(clkdom, &rk_clk_composite_clknode_class,
+ &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+
+ sc->muxdiv_offset = clkdef->muxdiv_offset;
+
+ sc->mux_shift = clkdef->mux_shift;
+ sc->mux_width = clkdef->mux_width;
+ sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
+
+ sc->div_shift = clkdef->div_shift;
+ sc->div_width = clkdef->div_width;
+ sc->div_mask = ((1 << clkdef->div_width) - 1) << sc->div_shift;
+
+ sc->gate_offset = clkdef->gate_offset;
+ sc->gate_shift = clkdef->gate_shift;
+
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+
+ return (0);
+}
Added: head/sys/arm64/rockchip/clk/rk_clk_composite.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk_clk_composite.h Mon Feb 26 21:25:50 2018 (r330036)
@@ -0,0 +1,61 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2018 Emmanuel Vadot <manu at 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 _RK_CLK_COMPOSITE_H_
+#define _RK_CLK_COMPOSITE_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct rk_clk_composite_def {
+ struct clknode_init_def clkdef;
+
+ uint32_t muxdiv_offset;
+
+ uint32_t mux_shift;
+ uint32_t mux_width;
+
+ uint32_t div_shift;
+ uint32_t div_width;
+
+ uint32_t gate_offset;
+ uint32_t gate_shift;
+
+ uint32_t flags;
+};
+
+#define RK_CLK_COMPOSITE_HAVE_MUX 0x0001
+#define RK_CLK_COMPOSITE_HAVE_GATE 0x0002
+
+#define RK_CLK_COMPOSITE_MASK 0xFFFF0000
+
+int rk_clk_composite_register(struct clkdom *clkdom,
+ struct rk_clk_composite_def *clkdef);
+
+#endif /* _RK_CLK_COMPOSITE_H_ */
Added: head/sys/arm64/rockchip/clk/rk_clk_gate.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk_clk_gate.c Mon Feb 26 21:25:50 2018 (r330036)
@@ -0,0 +1,135 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2016 Michal Meloun <mmel at 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#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 <arm64/rockchip/clk/rk_clk_gate.h>
+
+#include "clkdev_if.h"
+
+#define WR4(_clk, off, val) \
+ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define RD4(_clk, off, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define MD4(_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 rk_clk_gate_init(struct clknode *clk, device_t dev);
+static int rk_clk_gate_set_gate(struct clknode *clk, bool enable);
+struct rk_clk_gate_sc {
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t mask;
+ uint32_t on_value;
+ uint32_t off_value;
+ int gate_flags;
+ bool ungated;
+};
+
+static clknode_method_t rk_clk_gate_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, rk_clk_gate_init),
+ CLKNODEMETHOD(clknode_set_gate, rk_clk_gate_set_gate),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(rk_clk_gate, rk_clk_gate_class, rk_clk_gate_methods,
+ sizeof(struct rk_clk_gate_sc), clknode_class);
+
+static int
+rk_clk_gate_init(struct clknode *clk, device_t dev)
+{
+ uint32_t reg;
+ struct rk_clk_gate_sc *sc;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
+ rv = RD4(clk, sc->offset, ®);
+ DEVICE_UNLOCK(clk);
+ if (rv != 0)
+ return (rv);
+ reg = (reg >> sc->shift) & sc->mask;
+ sc->ungated = reg == sc->on_value ? 1 : 0;
+ clknode_init_parent_idx(clk, 0);
+ return(0);
+}
+
+static int
+rk_clk_gate_set_gate(struct clknode *clk, bool enable)
+{
+ uint32_t reg;
+ struct rk_clk_gate_sc *sc;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+ sc->ungated = enable;
+ DEVICE_LOCK(clk);
+ rv = MD4(clk, sc->offset, sc->mask << sc->shift,
+ ((sc->ungated ? sc->on_value : sc->off_value) << sc->shift) |
+ RK_CLK_GATE_MASK);
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
+ return (rv);
+ }
+ RD4(clk, sc->offset, ®);
+ DEVICE_UNLOCK(clk);
+ return(0);
+}
+
+int
+rk_clk_gate_register(struct clkdom *clkdom, struct rk_clk_gate_def *clkdef)
+{
+ struct clknode *clk;
+ struct rk_clk_gate_sc *sc;
+
+ clk = clknode_create(clkdom, &rk_clk_gate_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->offset = clkdef->offset;
+ sc->shift = clkdef->shift;
+ sc->mask = clkdef->mask;
+ sc->on_value = clkdef->on_value;
+ sc->off_value = clkdef->off_value;
+ sc->gate_flags = clkdef->gate_flags;
+
+ clknode_register(clkdom, clk);
+ return (0);
+}
Added: head/sys/arm64/rockchip/clk/rk_clk_gate.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk_clk_gate.h Mon Feb 26 21:25:50 2018 (r330036)
@@ -0,0 +1,50 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2018 Emmanuel Vadot <manu at 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 _RK_CLK_GATE_H_
+#define _RK_CLK_GATE_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct rk_clk_gate_def {
+ struct clknode_init_def clkdef;
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t mask;
+ uint32_t on_value;
+ uint32_t off_value;
+ int gate_flags;
+};
+
+#define RK_CLK_GATE_MASK 0xFFFF0000
+
+int rk_clk_gate_register(struct clkdom *clkdom, struct rk_clk_gate_def *clkdef);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list