Date: Mon, 26 Feb 2018 21:25:51 +0000 (UTC) From: Emmanuel Vadot <manu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r330036 - in head/sys: arm64/conf arm64/rockchip arm64/rockchip/clk conf Message-ID: <201802262125.w1QLPpc1089816@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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@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@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@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@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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802262125.w1QLPpc1089816>