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;