arm64: rockchip, implement the two rk805/808 clocks
While the xin32k clk was implemented in rk3399_cru as a fixed rate clock, migrate it to rk805 as we will also need the 2nd clock 'rtc_clko_wifi' for SDIO and BT. Both clocks remain fixed rate, and while the 1st one is always on (though that is not expressed in the clk framework), the 2nd one we can toggle on/off. Reviewed-by: manu Tested-by: manu MFC-after: 2 weeks Differential Revision: https://reviews.freebsd.org/D26870
This commit is contained in:
parent
7de0aa0135
commit
f0a5e81af4
@ -775,7 +775,7 @@ PLIST(uart3_p)= {"clk_uart3_div", "clk_uart3_frac", "xin24m"};
|
||||
static struct rk_clk rk3399_clks[] = {
|
||||
/* External clocks */
|
||||
LINK("xin24m"),
|
||||
FRATE(0, "xin32k", 32768),
|
||||
LINK("xin32k"),
|
||||
FFACT(0, "xin12m", "xin24m", 1, 2),
|
||||
FRATE(0, "clkin_i2s", 0),
|
||||
FRATE(0, "pclkin_cif", 0),
|
||||
|
@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
#include <dev/extres/regulator/regulator.h>
|
||||
|
||||
#include <arm64/rockchip/rk805reg.h>
|
||||
@ -584,6 +585,118 @@ rk805_reg_attach(device_t dev, phandle_t node,
|
||||
return (reg_sc);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Clock class and method */
|
||||
struct rk805_clk_sc {
|
||||
device_t base_dev;
|
||||
};
|
||||
|
||||
#define CLK32OUT_REG 0x20
|
||||
#define CLK32OUT_CLKOUT2_EN 1
|
||||
|
||||
static int
|
||||
rk805_clk_set_gate_1(struct clknode *clk, bool enable)
|
||||
{
|
||||
struct rk805_clk_sc *sc;
|
||||
uint8_t val;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
rk805_read(sc->base_dev, CLK32OUT_REG, &val, sizeof(val));
|
||||
if (enable)
|
||||
val |= CLK32OUT_CLKOUT2_EN;
|
||||
else
|
||||
val &= ~CLK32OUT_CLKOUT2_EN;
|
||||
rk805_write(sc->base_dev, CLK32OUT_REG, &val, 1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rk805_clk_recalc(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
|
||||
*freq = 32768;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t rk805_clk_clknode_methods_0[] = {
|
||||
CLKNODEMETHOD(clknode_recalc_freq, rk805_clk_recalc),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(rk805_clk_clknode_0, rk805_clk_clknode_class_0,
|
||||
rk805_clk_clknode_methods_0, sizeof(struct rk805_clk_sc),
|
||||
clknode_class);
|
||||
|
||||
static clknode_method_t rk805_clk_clknode_methods_1[] = {
|
||||
CLKNODEMETHOD(clknode_set_gate, rk805_clk_set_gate_1),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(rk805_clk_clknode_1, rk805_clk_clknode_class_1,
|
||||
rk805_clk_clknode_methods_1, sizeof(struct rk805_clk_sc),
|
||||
rk805_clk_clknode_class_0);
|
||||
|
||||
static int
|
||||
rk805_export_clocks(device_t dev)
|
||||
{
|
||||
struct clkdom *clkdom;
|
||||
struct clknode_init_def clkidef;
|
||||
struct clknode *clk;
|
||||
struct rk805_clk_sc *clksc;
|
||||
const char **clknames;
|
||||
phandle_t node;
|
||||
int nclks, rv;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
|
||||
/* clock-output-names are optional. Could use them for clkidef.name. */
|
||||
nclks = ofw_bus_string_list_to_array(node, "clock-output-names",
|
||||
&clknames);
|
||||
|
||||
clkdom = clkdom_create(dev);
|
||||
|
||||
memset(&clkidef, 0, sizeof(clkidef));
|
||||
clkidef.id = 0;
|
||||
clkidef.name = (nclks = 2) ? clknames[0] : "clk32kout1";
|
||||
clk = clknode_create(clkdom, &rk805_clk_clknode_class_0, &clkidef);
|
||||
if (clk == NULL) {
|
||||
device_printf(dev, "Cannot create '%s'.\n", clkidef.name);
|
||||
return (ENXIO);
|
||||
}
|
||||
clksc = clknode_get_softc(clk);
|
||||
clksc->base_dev = dev;
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
memset(&clkidef, 0, sizeof(clkidef));
|
||||
clkidef.id = 1;
|
||||
clkidef.name = (nclks = 2) ? clknames[1] : "clk32kout2";
|
||||
clk = clknode_create(clkdom, &rk805_clk_clknode_class_1, &clkidef);
|
||||
if (clk == NULL) {
|
||||
device_printf(dev, "Cannot create '%s'.\n", clkidef.name);
|
||||
return (ENXIO);
|
||||
}
|
||||
clksc = clknode_get_softc(clk);
|
||||
clksc->base_dev = dev;
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
rv = clkdom_finit(clkdom);
|
||||
if (rv != 0) {
|
||||
device_printf(dev, "Cannot finalize clkdom initialization: "
|
||||
"%d\n", rv);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(clkdom);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
rk805_probe(device_t dev)
|
||||
{
|
||||
@ -745,17 +858,20 @@ rk805_attach(device_t dev)
|
||||
struct rk805_regdef *regdefs;
|
||||
struct reg_list *regp;
|
||||
phandle_t rnode, child;
|
||||
int i;
|
||||
int error, i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||
error = rk805_export_clocks(dev);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
sc->intr_hook.ich_func = rk805_start;
|
||||
sc->intr_hook.ich_arg = dev;
|
||||
|
||||
if (config_intrhook_establish(&sc->intr_hook) != 0)
|
||||
return (ENOMEM);
|
||||
|
||||
sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||
switch (sc->type) {
|
||||
case RK805:
|
||||
regdefs = rk805_regdefs;
|
||||
|
Loading…
Reference in New Issue
Block a user