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.
This commit is contained in:
parent
1f13c23f3d
commit
2a3d5e3364
@ -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
|
||||
|
476
sys/arm64/rockchip/clk/rk3328_cru.c
Normal file
476
sys/arm64/rockchip/clk/rk3328_cru.c
Normal file
@ -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);
|
255
sys/arm64/rockchip/clk/rk_clk_composite.c
Normal file
255
sys/arm64/rockchip/clk/rk_clk_composite.c
Normal file
@ -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);
|
||||
}
|
61
sys/arm64/rockchip/clk/rk_clk_composite.h
Normal file
61
sys/arm64/rockchip/clk/rk_clk_composite.h
Normal file
@ -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_ */
|
135
sys/arm64/rockchip/clk/rk_clk_gate.c
Normal file
135
sys/arm64/rockchip/clk/rk_clk_gate.c
Normal file
@ -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);
|
||||
}
|
50
sys/arm64/rockchip/clk/rk_clk_gate.h
Normal file
50
sys/arm64/rockchip/clk/rk_clk_gate.h
Normal file
@ -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);
|
||||
|
||||
#endif /* _RK_CLK_GATE_H_ */
|
139
sys/arm64/rockchip/clk/rk_clk_mux.c
Normal file
139
sys/arm64/rockchip/clk/rk_clk_mux.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*-
|
||||
* 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/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
#include <arm64/rockchip/clk/rk_cru.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_mux.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_mux_init(struct clknode *clk, device_t dev);
|
||||
static int rk_clk_mux_set_mux(struct clknode *clk, int idx);
|
||||
|
||||
struct rk_clk_mux_sc {
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
uint32_t mask;
|
||||
int mux_flags;
|
||||
};
|
||||
|
||||
static clknode_method_t rk_clk_mux_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, rk_clk_mux_init),
|
||||
CLKNODEMETHOD(clknode_set_mux, rk_clk_mux_set_mux),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
DEFINE_CLASS_1(rk_clk_mux, rk_clk_mux_class, rk_clk_mux_methods,
|
||||
sizeof(struct rk_clk_mux_sc), clknode_class);
|
||||
|
||||
|
||||
static int
|
||||
rk_clk_mux_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
uint32_t reg;
|
||||
struct rk_clk_mux_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;
|
||||
clknode_init_parent_idx(clk, reg);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_clk_mux_set_mux(struct clknode *clk, int idx)
|
||||
{
|
||||
uint32_t reg;
|
||||
struct rk_clk_mux_sc *sc;
|
||||
int rv;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
rv = MD4(clk, sc->offset, sc->mask << sc->shift,
|
||||
((idx & sc->mask) << sc->shift) | RK_CLK_MUX_MASK);
|
||||
if (rv != 0) {
|
||||
DEVICE_UNLOCK(clk);
|
||||
return (rv);
|
||||
}
|
||||
RD4(clk, sc->offset, ®);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
rk_clk_mux_register(struct clkdom *clkdom, struct rk_clk_mux_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct rk_clk_mux_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &rk_clk_mux_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
sc->offset = clkdef->offset;
|
||||
sc->shift = clkdef->shift;
|
||||
sc->mask = (1 << clkdef->width) - 1;
|
||||
sc->mux_flags = clkdef->mux_flags;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
return (0);
|
||||
}
|
47
sys/arm64/rockchip/clk/rk_clk_mux.h
Normal file
47
sys/arm64/rockchip/clk/rk_clk_mux.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*-
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef _RK_CLK_MUX_H_
|
||||
#define _RK_CLK_MUX_H_
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
struct rk_clk_mux_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
uint32_t width;
|
||||
int mux_flags;
|
||||
};
|
||||
|
||||
#define RK_CLK_MUX_MASK 0xFFFF0000
|
||||
|
||||
int rk_clk_mux_register(struct clkdom *clkdom, struct rk_clk_mux_def *clkdef);
|
||||
|
||||
#endif /* _RK_CLK_MUX_H_ */
|
203
sys/arm64/rockchip/clk/rk_clk_pll.c
Normal file
203
sys/arm64/rockchip/clk/rk_clk_pll.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*-
|
||||
* 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_pll.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
struct rk_clk_pll_sc {
|
||||
uint32_t base_offset;
|
||||
|
||||
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_CLK_PLL_DSMPD_OFFSET 4
|
||||
#define RK_CLK_PLL_DSMPD_SHIFT 12
|
||||
#define RK_CLK_PLL_DSMPD_MASK 0x1000
|
||||
|
||||
#define RK_CLK_PLL_REFDIV_OFFSET 4
|
||||
#define RK_CLK_PLL_REFDIV_SHIFT 0
|
||||
#define RK_CLK_PLL_REFDIV_MASK 0x3F
|
||||
|
||||
#define RK_CLK_PLL_FBDIV_OFFSET 0
|
||||
#define RK_CLK_PLL_FBDIV_SHIFT 0
|
||||
#define RK_CLK_PLL_FBDIV_MASK 0xFFF
|
||||
|
||||
#define RK_CLK_PLL_POSTDIV1_OFFSET 0
|
||||
#define RK_CLK_PLL_POSTDIV1_SHIFT 12
|
||||
#define RK_CLK_PLL_POSTDIV1_MASK 0x7000
|
||||
|
||||
#define RK_CLK_PLL_POSTDIV2_OFFSET 4
|
||||
#define RK_CLK_PLL_POSTDIV2_SHIFT 6
|
||||
#define RK_CLK_PLL_POSTDIV2_MASK 0x1C0
|
||||
|
||||
#define RK_CLK_PLL_FRAC_OFFSET 8
|
||||
#define RK_CLK_PLL_FRAC_SHIFT 0
|
||||
#define RK_CLK_PLL_FRAC_MASK 0xFFFFFF
|
||||
|
||||
static int
|
||||
rk_clk_pll_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
struct rk_clk_pll_sc *sc;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
clknode_init_parent_idx(clk, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_clk_pll_set_gate(struct clknode *clk, bool enable)
|
||||
{
|
||||
struct rk_clk_pll_sc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
if ((sc->flags & RK_CLK_PLL_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_PLL_MASK);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct rk_clk_pll_sc *sc;
|
||||
uint64_t foutvco;
|
||||
uint32_t dsmpd, refdiv, fbdiv;
|
||||
uint32_t postdiv1, postdiv2, frac;
|
||||
uint32_t raw1, raw2;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
READ4(clk, sc->base_offset, &raw1);
|
||||
READ4(clk, sc->base_offset + 4, &raw2);
|
||||
|
||||
READ4(clk, sc->base_offset + RK_CLK_PLL_DSMPD_OFFSET, &dsmpd);
|
||||
dsmpd = (dsmpd & RK_CLK_PLL_DSMPD_MASK) >> RK_CLK_PLL_DSMPD_SHIFT;
|
||||
|
||||
READ4(clk, sc->base_offset + RK_CLK_PLL_REFDIV_OFFSET, &refdiv);
|
||||
refdiv = (refdiv & RK_CLK_PLL_REFDIV_MASK) >> RK_CLK_PLL_REFDIV_SHIFT;
|
||||
|
||||
READ4(clk, sc->base_offset + RK_CLK_PLL_FBDIV_OFFSET, &fbdiv);
|
||||
fbdiv = (fbdiv & RK_CLK_PLL_FBDIV_MASK) >> RK_CLK_PLL_FBDIV_SHIFT;
|
||||
|
||||
READ4(clk, sc->base_offset + RK_CLK_PLL_POSTDIV1_OFFSET, &postdiv1);
|
||||
postdiv1 = (postdiv1 & RK_CLK_PLL_POSTDIV1_MASK) >> RK_CLK_PLL_POSTDIV1_SHIFT;
|
||||
|
||||
READ4(clk, sc->base_offset + RK_CLK_PLL_POSTDIV2_OFFSET, &postdiv2);
|
||||
postdiv2 = (postdiv2 & RK_CLK_PLL_POSTDIV2_MASK) >> RK_CLK_PLL_POSTDIV2_SHIFT;
|
||||
|
||||
READ4(clk, sc->base_offset + RK_CLK_PLL_FRAC_OFFSET, &frac);
|
||||
frac = (frac & RK_CLK_PLL_FRAC_MASK) >> RK_CLK_PLL_FRAC_SHIFT;
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
if (dsmpd == 0) {
|
||||
/* Fractional mode */
|
||||
foutvco = *freq / refdiv * (fbdiv + frac / 224);
|
||||
} else {
|
||||
/* Integer mode */
|
||||
|
||||
foutvco = *freq / refdiv * fbdiv;
|
||||
}
|
||||
|
||||
*freq = foutvco / postdiv1 / postdiv2;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t rk_clk_pll_clknode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, rk_clk_pll_init),
|
||||
CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, rk_clk_pll_recalc),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(rk_clk_pll_clknode, rk_clk_pll_clknode_class,
|
||||
rk_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
|
||||
|
||||
int
|
||||
rk_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct rk_clk_pll_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &rk_clk_pll_clknode_class,
|
||||
&clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
sc->base_offset = clkdef->base_offset;
|
||||
sc->gate_offset = clkdef->gate_offset;
|
||||
sc->gate_shift = clkdef->gate_shift;
|
||||
sc->flags = clkdef->flags;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
52
sys/arm64/rockchip/clk/rk_clk_pll.h
Normal file
52
sys/arm64/rockchip/clk/rk_clk_pll.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*-
|
||||
* 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_PLL_H_
|
||||
#define _RK_CLK_PLL_H_
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
struct rk_clk_pll_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t base_offset;
|
||||
|
||||
uint32_t gate_offset;
|
||||
uint32_t gate_shift;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
#define RK_CLK_PLL_HAVE_GATE 0x1
|
||||
|
||||
#define RK_CLK_PLL_MASK 0xFFFF0000
|
||||
|
||||
int rk_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef);
|
||||
|
||||
#endif /* _RK_CLK_PLL_H_ */
|
267
sys/arm64/rockchip/clk/rk_cru.c
Normal file
267
sys/arm64/rockchip/clk/rk_cru.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*-
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/*
|
||||
* RockChip Clock and Reset Unit
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/fdt/simplebus.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
#include <dev/extres/clk/clk_gate.h>
|
||||
#include <dev/extres/hwreset/hwreset.h>
|
||||
|
||||
#include <arm64/rockchip/clk/rk_clk_composite.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_gate.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_mux.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_pll.h>
|
||||
#include <arm64/rockchip/clk/rk_cru.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
#include "hwreset_if.h"
|
||||
|
||||
static struct resource_spec rk_cru_spec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
#define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg))
|
||||
#define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
|
||||
|
||||
void rk3328_cru_register_clocks(struct rk_cru_softc *sc);
|
||||
|
||||
static int
|
||||
rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
CCU_WRITE4(sc, addr, val);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
*val = CCU_READ4(sc, addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
uint32_t reg;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
reg = CCU_READ4(sc, addr);
|
||||
reg &= ~clr;
|
||||
reg |= set;
|
||||
CCU_WRITE4(sc, addr, reg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_cru_reset_assert(device_t dev, intptr_t id, bool reset)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (id >= sc->nresets || sc->resets[id].offset == 0)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->mtx);
|
||||
val = CCU_READ4(sc, sc->resets[id].offset);
|
||||
if (reset)
|
||||
val &= ~(1 << sc->resets[id].shift);
|
||||
else
|
||||
val |= 1 << sc->resets[id].shift;
|
||||
CCU_WRITE4(sc, sc->resets[id].offset, val);
|
||||
mtx_unlock(&sc->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (id >= sc->nresets || sc->resets[id].offset == 0)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->mtx);
|
||||
val = CCU_READ4(sc, sc->resets[id].offset);
|
||||
*reset = (val & (1 << sc->resets[id].shift)) != 0 ? false : true;
|
||||
mtx_unlock(&sc->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
rk_cru_device_lock(device_t dev)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_lock(&sc->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
rk_cru_device_unlock(device_t dev)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_unlock(&sc->mtx);
|
||||
}
|
||||
|
||||
static int
|
||||
rk_cru_register_gates(struct rk_cru_softc *sc)
|
||||
{
|
||||
struct rk_clk_gate_def def;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sc->ngates; i++) {
|
||||
if (sc->gates[i].name == NULL)
|
||||
continue;
|
||||
memset(&def, 0, sizeof(def));
|
||||
def.clkdef.id = sc->gates[i].id;
|
||||
def.clkdef.name = sc->gates[i].name;
|
||||
def.clkdef.parent_names = &sc->gates[i].parent_name;
|
||||
def.clkdef.parent_cnt = 1;
|
||||
def.offset = sc->gates[i].offset;
|
||||
def.shift = sc->gates[i].shift;
|
||||
def.mask = 1;
|
||||
def.on_value = 0;
|
||||
def.off_value = 1;
|
||||
rk_clk_gate_register(sc->clkdom, &def);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rk_cru_attach(device_t dev)
|
||||
{
|
||||
struct rk_cru_softc *sc;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
|
||||
device_printf(dev, "cannot allocate resources for device\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
|
||||
|
||||
sc->clkdom = clkdom_create(dev);
|
||||
if (sc->clkdom == NULL)
|
||||
panic("Cannot create clkdom\n");
|
||||
|
||||
for (i = 0; i < sc->nclks; i++) {
|
||||
switch (sc->clks[i].type) {
|
||||
case RK_CLK_UNDEFINED:
|
||||
break;
|
||||
case RK_CLK_PLL:
|
||||
rk_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll);
|
||||
break;
|
||||
case RK_CLK_COMPOSITE:
|
||||
rk_clk_composite_register(sc->clkdom,
|
||||
sc->clks[i].clk.composite);
|
||||
break;
|
||||
case RK_CLK_MUX:
|
||||
rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
|
||||
default:
|
||||
device_printf(dev, "Unknown clock type\n");
|
||||
return (ENXIO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sc->gates)
|
||||
rk_cru_register_gates(sc);
|
||||
|
||||
if (clkdom_finit(sc->clkdom) != 0)
|
||||
panic("cannot finalize clkdom initialization\n");
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(sc->clkdom);
|
||||
|
||||
/* If we have resets, register our self as a reset provider */
|
||||
if (sc->resets)
|
||||
hwreset_register_ofw_provider(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t rk_cru_methods[] = {
|
||||
/* clkdev interface */
|
||||
DEVMETHOD(clkdev_write_4, rk_cru_write_4),
|
||||
DEVMETHOD(clkdev_read_4, rk_cru_read_4),
|
||||
DEVMETHOD(clkdev_modify_4, rk_cru_modify_4),
|
||||
DEVMETHOD(clkdev_device_lock, rk_cru_device_lock),
|
||||
DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock),
|
||||
|
||||
/* Reset interface */
|
||||
DEVMETHOD(hwreset_assert, rk_cru_reset_assert),
|
||||
DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods,
|
||||
sizeof(struct rk_cru_softc));
|
95
sys/arm64/rockchip/clk/rk_cru.h
Normal file
95
sys/arm64/rockchip/clk/rk_cru.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*-
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __RK_CRU_H__
|
||||
#define __RK_CRU_H__
|
||||
|
||||
#include <arm64/rockchip/clk/rk_clk_composite.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_gate.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_mux.h>
|
||||
#include <arm64/rockchip/clk/rk_clk_pll.h>
|
||||
|
||||
struct rk_cru_reset {
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
};
|
||||
|
||||
struct rk_cru_gate {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
};
|
||||
|
||||
#define CRU_GATE(idx, clkname, pname, o, s) \
|
||||
{ \
|
||||
.id = idx, \
|
||||
.name = clkname, \
|
||||
.parent_name = pname, \
|
||||
.offset = o, \
|
||||
.shift = s, \
|
||||
},
|
||||
|
||||
enum rk_clk_type {
|
||||
RK_CLK_UNDEFINED = 0,
|
||||
RK_CLK_PLL,
|
||||
RK_CLK_COMPOSITE,
|
||||
RK_CLK_MUX,
|
||||
};
|
||||
|
||||
struct rk_clk {
|
||||
enum rk_clk_type type;
|
||||
union {
|
||||
struct rk_clk_pll_def *pll;
|
||||
struct rk_clk_composite_def *composite;
|
||||
struct rk_clk_mux_def *mux;
|
||||
} clk;
|
||||
};
|
||||
|
||||
struct rk_cru_softc {
|
||||
device_t dev;
|
||||
struct resource *res;
|
||||
struct clkdom *clkdom;
|
||||
struct mtx mtx;
|
||||
int type;
|
||||
struct rk_cru_reset *resets;
|
||||
int nresets;
|
||||
struct rk_cru_gate *gates;
|
||||
int ngates;
|
||||
struct rk_clk *clks;
|
||||
int nclks;
|
||||
};
|
||||
|
||||
DECLARE_CLASS(rk_cru_driver);
|
||||
|
||||
int rk_cru_attach(device_t dev);
|
||||
|
||||
#endif /* __RK_CRU_H__ */
|
@ -228,3 +228,10 @@ cddl/contrib/opensolaris/common/atomic/aarch64/opensolaris_atomic.S optional zfs
|
||||
cddl/dev/dtrace/aarch64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}"
|
||||
cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}"
|
||||
cddl/dev/fbt/aarch64/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}"
|
||||
|
||||
arm64/rockchip/clk/rk_cru.c optional fdt soc_rockchip_rk3328
|
||||
arm64/rockchip/clk/rk_clk_composite.c optional fdt soc_rockchip_rk3328
|
||||
arm64/rockchip/clk/rk_clk_gate.c optional fdt soc_rockchip_rk3328
|
||||
arm64/rockchip/clk/rk_clk_mux.c optional fdt soc_rockchip_rk3328
|
||||
arm64/rockchip/clk/rk_clk_pll.c optional fdt soc_rockchip_rk3328
|
||||
arm64/rockchip/clk/rk3328_cru.c optional fdt soc_rockchip_rk3328
|
||||
|
@ -22,3 +22,4 @@ SOC_ALLWINNER_H5 opt_soc.h
|
||||
SOC_BRCM_BCM2837 opt_soc.h
|
||||
SOC_CAVM_THUNDERX opt_soc.h
|
||||
SOC_HISI_HI6220 opt_soc.h
|
||||
SOC_ROCKCHIP_RK3328 opt_soc.h
|
||||
|
Loading…
x
Reference in New Issue
Block a user