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 <m...@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 <m...@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 <m...@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 <m...@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 <m...@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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to