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, &reg);
+
+	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, &reg);
+	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, &reg);
+	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-head mailing list