From f0a5e81af4361abfc09ccaefbc375ece35ff79cc Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Thu, 6 May 2021 14:25:52 +0000 Subject: [PATCH] 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 --- sys/arm64/rockchip/clk/rk3399_cru.c | 2 +- sys/arm64/rockchip/rk805.c | 122 +++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/sys/arm64/rockchip/clk/rk3399_cru.c b/sys/arm64/rockchip/clk/rk3399_cru.c index 595085862e13..585f6d4c33b9 100644 --- a/sys/arm64/rockchip/clk/rk3399_cru.c +++ b/sys/arm64/rockchip/clk/rk3399_cru.c @@ -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), diff --git a/sys/arm64/rockchip/rk805.c b/sys/arm64/rockchip/rk805.c index d3e04081aeb2..2d5635fee72a 100644 --- a/sys/arm64/rockchip/rk805.c +++ b/sys/arm64/rockchip/rk805.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -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;