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:
Emmanuel Vadot 2018-02-26 21:25:50 +00:00
parent 1f13c23f3d
commit 2a3d5e3364
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=330036
14 changed files with 1789 additions and 0 deletions

View File

@ -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

View 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);

View 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, &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);
}

View 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_ */

View 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, &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);
}

View 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_ */

View 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, &reg);
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, &reg);
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);
}

View 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_ */

View 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);
}

View 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_ */

View 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));

View 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__ */

View File

@ -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

View File

@ -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