From 8ca1ca8f6039f19673fb61552f276b848539dbd6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 22 Dec 2015 22:27:59 +0100 Subject: [PATCH 1/5] clk: rockchip: handle mux dependency of fractional dividers The fractional dividers of Rockchip SoCs contain an "auto-gating-feature" that requires the downstream mux to actually point to the fractional divider and the fractional divider gate to be enabled, for it to really accept changes to the divider ratio. The downstream muxes themselfs are not generic enough to include them directly into the fractional divider, as they have varying sources of parent clocks including not only clocks related to the fractional dividers but other clocks as well. To solve this, allow our clock branches to specify direct child clock- branches in the new child property, let the fractional divider register its downstream mux through this and add a clock notifier that temporarily switches the mux setting when it notices rate changes to the fractional divider. Signed-off-by: Heiko Stuebner Tested-by: Sjoerd Simons Reviewed-by: Sjoerd Simons Signed-off-by: Michael Turquette --- drivers/clk/rockchip/clk.c | 137 +++++++++++++++++++++++++++++++++---- drivers/clk/rockchip/clk.h | 19 +++++ 2 files changed, 142 insertions(+), 14 deletions(-) diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index be6c7fd8315d..f6d147b15c2b 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -102,22 +102,82 @@ static struct clk *rockchip_clk_register_branch(const char *name, return clk; } +struct rockchip_clk_frac { + struct notifier_block clk_nb; + struct clk_fractional_divider div; + struct clk_gate gate; + + struct clk_mux mux; + const struct clk_ops *mux_ops; + int mux_frac_idx; + + bool rate_change_remuxed; + int rate_change_idx; +}; + +#define to_rockchip_clk_frac_nb(nb) \ + container_of(nb, struct rockchip_clk_frac, clk_nb) + +static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct clk_notifier_data *ndata = data; + struct rockchip_clk_frac *frac = to_rockchip_clk_frac_nb(nb); + struct clk_mux *frac_mux = &frac->mux; + int ret = 0; + + pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n", + __func__, event, ndata->old_rate, ndata->new_rate); + if (event == PRE_RATE_CHANGE) { + frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw); + if (frac->rate_change_idx != frac->mux_frac_idx) { + frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx); + frac->rate_change_remuxed = 1; + } + } else if (event == POST_RATE_CHANGE) { + /* + * The POST_RATE_CHANGE notifier runs directly after the + * divider clock is set in clk_change_rate, so we'll have + * remuxed back to the original parent before clk_change_rate + * reaches the mux itself. + */ + if (frac->rate_change_remuxed) { + frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx); + frac->rate_change_remuxed = 0; + } + } + + return notifier_from_errno(ret); +} + static struct clk *rockchip_clk_register_frac_branch(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *base, int muxdiv_offset, u8 div_flags, int gate_offset, u8 gate_shift, u8 gate_flags, - unsigned long flags, spinlock_t *lock) + unsigned long flags, struct rockchip_clk_branch *child, + spinlock_t *lock) { + struct rockchip_clk_frac *frac; struct clk *clk; struct clk_gate *gate = NULL; struct clk_fractional_divider *div = NULL; const struct clk_ops *div_ops = NULL, *gate_ops = NULL; - if (gate_offset >= 0) { - gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) - return ERR_PTR(-ENOMEM); + if (muxdiv_offset < 0) + return ERR_PTR(-EINVAL); + if (child && child->branch_type != branch_mux) { + pr_err("%s: fractional child clock for %s can only be a mux\n", + __func__, name); + return ERR_PTR(-EINVAL); + } + + frac = kzalloc(sizeof(*frac), GFP_KERNEL); + if (!frac) + return ERR_PTR(-ENOMEM); + + if (gate_offset >= 0) { + gate = &frac->gate; gate->flags = gate_flags; gate->reg = base + gate_offset; gate->bit_idx = gate_shift; @@ -125,13 +185,7 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name, gate_ops = &clk_gate_ops; } - if (muxdiv_offset < 0) - return ERR_PTR(-EINVAL); - - div = kzalloc(sizeof(*div), GFP_KERNEL); - if (!div) - return ERR_PTR(-ENOMEM); - + div = &frac->div; div->flags = div_flags; div->reg = base + muxdiv_offset; div->mshift = 16; @@ -147,7 +201,61 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name, NULL, NULL, &div->hw, div_ops, gate ? &gate->hw : NULL, gate_ops, - flags); + flags | CLK_SET_RATE_UNGATE); + if (IS_ERR(clk)) { + kfree(frac); + return clk; + } + + if (child) { + struct clk_mux *frac_mux = &frac->mux; + struct clk_init_data init; + struct clk *mux_clk; + int i, ret; + + frac->mux_frac_idx = -1; + for (i = 0; i < child->num_parents; i++) { + if (!strcmp(name, child->parent_names[i])) { + pr_debug("%s: found fractional parent in mux at pos %d\n", + __func__, i); + frac->mux_frac_idx = i; + break; + } + } + + frac->mux_ops = &clk_mux_ops; + frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb; + + frac_mux->reg = base + child->muxdiv_offset; + frac_mux->shift = child->mux_shift; + frac_mux->mask = BIT(child->mux_width) - 1; + frac_mux->flags = child->mux_flags; + frac_mux->lock = lock; + frac_mux->hw.init = &init; + + init.name = child->name; + init.flags = child->flags | CLK_SET_RATE_PARENT; + init.ops = frac->mux_ops; + init.parent_names = child->parent_names; + init.num_parents = child->num_parents; + + mux_clk = clk_register(NULL, &frac_mux->hw); + if (IS_ERR(mux_clk)) + return clk; + + rockchip_clk_add_lookup(mux_clk, child->id); + + /* notifier on the fraction divider to catch rate changes */ + if (frac->mux_frac_idx >= 0) { + ret = clk_notifier_register(clk, &frac->clk_nb); + if (ret) + pr_err("%s: failed to register clock notifier for %s\n", + __func__, name); + } else { + pr_warn("%s: could not find %s as parent of %s, rate changes may not work\n", + __func__, name, child->name); + } + } return clk; } @@ -251,7 +359,8 @@ void __init rockchip_clk_register_branches( list->parent_names, list->num_parents, reg_base, list->muxdiv_offset, list->div_flags, list->gate_offset, list->gate_shift, - list->gate_flags, flags, &clk_lock); + list->gate_flags, flags, list->child, + &clk_lock); break; case branch_gate: flags |= CLK_SET_RATE_PARENT; diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 8d8f942ae7fc..176a3eb52ef4 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -265,6 +265,7 @@ struct rockchip_clk_branch { int gate_offset; u8 gate_shift; u8 gate_flags; + struct rockchip_clk_branch *child; }; #define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ @@ -399,6 +400,24 @@ struct rockchip_clk_branch { .gate_flags = gf, \ } +#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \ + { \ + .id = _id, \ + .branch_type = branch_fraction_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = mo, \ + .div_shift = 16, \ + .div_width = 16, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + .child = &(struct rockchip_clk_branch)ch, \ + } + #define MUX(_id, cname, pnames, f, o, s, w, mf) \ { \ .id = _id, \ From 66746420898984a273ea08fa5926bd1640eaed3e Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 22 Dec 2015 22:28:00 +0100 Subject: [PATCH 2/5] clk: rockchip: include downstream muxes into fractional dividers Use the newly introduced possibility to combine the fractional dividers with their downstream muxes for all fractional dividers on currently supported Rockchip SoCs. Signed-off-by: Heiko Stuebner Tested-by: Sjoerd Simons Reviewed-by: Sjoerd Simons Signed-off-by: Michael Turquette --- drivers/clk/rockchip/clk-rk3188.c | 80 +++++++++++++++---------------- drivers/clk/rockchip/clk-rk3288.c | 66 ++++++++++++------------- 2 files changed, 74 insertions(+), 72 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index abb47608713b..c2c5c69d1230 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -335,11 +335,11 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0, RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS, RK2928_CLKGATE_CON(2), 6, GFLAGS), - COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0, + COMPOSITE_FRACMUX(0, "hsadc_frac", "hsadc_src", 0, RK2928_CLKSEL_CON(23), 0, - RK2928_CLKGATE_CON(2), 7, GFLAGS), - MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0, - RK2928_CLKSEL_CON(22), 4, 2, MFLAGS), + RK2928_CLKGATE_CON(2), 7, GFLAGS, + MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0, + RK2928_CLKSEL_CON(22), 4, 2, MFLAGS)), INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out", RK2928_CLKSEL_CON(22), 7, IFLAGS), @@ -350,11 +350,11 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0, RK2928_CLKSEL_CON(5), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 13, GFLAGS), - COMPOSITE_FRAC(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_pll", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(9), 0, - RK2928_CLKGATE_CON(0), 14, GFLAGS), - MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(0), 14, GFLAGS, + MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(5), 8, 2, MFLAGS)), /* * Clock-Architecture Diagram 4 @@ -385,35 +385,35 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0, RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 8, GFLAGS), - COMPOSITE_FRAC(0, "uart0_frac", "uart0_pre", 0, + COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0, RK2928_CLKSEL_CON(17), 0, - RK2928_CLKGATE_CON(1), 9, GFLAGS), - MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0, - RK2928_CLKSEL_CON(13), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(1), 9, GFLAGS, + MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0, + RK2928_CLKSEL_CON(13), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0, RK2928_CLKSEL_CON(14), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 10, GFLAGS), - COMPOSITE_FRAC(0, "uart1_frac", "uart1_pre", 0, + COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0, RK2928_CLKSEL_CON(18), 0, - RK2928_CLKGATE_CON(1), 11, GFLAGS), - MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0, - RK2928_CLKSEL_CON(14), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(1), 11, GFLAGS, + MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0, + RK2928_CLKSEL_CON(14), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0, RK2928_CLKSEL_CON(15), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 12, GFLAGS), - COMPOSITE_FRAC(0, "uart2_frac", "uart2_pre", 0, + COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0, RK2928_CLKSEL_CON(19), 0, - RK2928_CLKGATE_CON(1), 13, GFLAGS), - MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0, - RK2928_CLKSEL_CON(15), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(1), 13, GFLAGS, + MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0, + RK2928_CLKSEL_CON(15), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0, RK2928_CLKSEL_CON(16), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 14, GFLAGS), - COMPOSITE_FRAC(0, "uart3_frac", "uart3_pre", 0, + COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0, RK2928_CLKSEL_CON(20), 0, - RK2928_CLKGATE_CON(1), 15, GFLAGS), - MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0, - RK2928_CLKSEL_CON(16), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(1), 15, GFLAGS, + MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0, + RK2928_CLKSEL_CON(16), 8, 2, MFLAGS)), GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS), @@ -584,27 +584,27 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0, RK2928_CLKSEL_CON(2), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 7, GFLAGS), - COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0, + COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0, RK2928_CLKSEL_CON(6), 0, - RK2928_CLKGATE_CON(0), 8, GFLAGS), - MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, - RK2928_CLKSEL_CON(2), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(0), 8, GFLAGS, + MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, + RK2928_CLKSEL_CON(2), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0, RK2928_CLKSEL_CON(3), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 9, GFLAGS), - COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_pre", 0, + COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0, RK2928_CLKSEL_CON(7), 0, - RK2928_CLKGATE_CON(0), 10, GFLAGS), - MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0, - RK2928_CLKSEL_CON(3), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(0), 10, GFLAGS, + MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0, + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0, RK2928_CLKSEL_CON(4), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 11, GFLAGS), - COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_pre", 0, + COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0, RK2928_CLKSEL_CON(8), 0, - RK2928_CLKGATE_CON(0), 12, GFLAGS), - MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0, - RK2928_CLKSEL_CON(4), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(0), 12, GFLAGS, + MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0, + RK2928_CLKSEL_CON(4), 8, 2, MFLAGS)), GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), @@ -691,11 +691,11 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0, RK2928_CLKSEL_CON(3), 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 9, GFLAGS), - COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0, + COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0, RK2928_CLKSEL_CON(7), 0, - RK2928_CLKGATE_CON(0), 10, GFLAGS), - MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, - RK2928_CLKSEL_CON(3), 8, 2, MFLAGS), + RK2928_CLKGATE_CON(0), 10, GFLAGS, + MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS)), GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS), diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index d613ad96ef70..3d1a6efdbe99 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -304,11 +304,11 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 1, GFLAGS), - COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(8), 0, - RK3288_CLKGATE_CON(4), 2, GFLAGS), - MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, - RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), + RK3288_CLKGATE_CON(4), 2, GFLAGS, + MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(4), 8, 2, MFLAGS)), COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0, RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, RK3288_CLKGATE_CON(4), 0, GFLAGS), @@ -320,20 +320,22 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", 0, RK3288_CLKSEL_CON(5), 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 4, GFLAGS), - COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0, + COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0, RK3288_CLKSEL_CON(9), 0, - RK3288_CLKGATE_CON(4), 5, GFLAGS), - COMPOSITE_NODIV(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0, - RK3288_CLKSEL_CON(5), 8, 2, MFLAGS, + RK3288_CLKGATE_CON(4), 5, GFLAGS, + MUX(0, "spdif_mux", mux_spdif_p, 0, + RK3288_CLKSEL_CON(5), 8, 2, MFLAGS)), + GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", 0, RK3288_CLKGATE_CON(4), 6, GFLAGS), COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0, RK3288_CLKSEL_CON(40), 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 7, GFLAGS), - COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_pre", 0, + COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", 0, RK3288_CLKSEL_CON(41), 0, - RK3288_CLKGATE_CON(4), 8, GFLAGS), - COMPOSITE_NODIV(SCLK_SPDIF8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0, - RK3288_CLKSEL_CON(40), 8, 2, MFLAGS, + RK3288_CLKGATE_CON(4), 8, GFLAGS, + MUX(0, "spdif_8ch_mux", mux_spdif_8ch_p, 0, + RK3288_CLKSEL_CON(40), 8, 2, MFLAGS)), + GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", 0, RK3288_CLKGATE_CON(4), 9, GFLAGS), GATE(0, "sclk_acc_efuse", "xin24m", 0, @@ -536,45 +538,45 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0, RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS, RK3288_CLKGATE_CON(1), 8, GFLAGS), - COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(17), 0, - RK3288_CLKGATE_CON(1), 9, GFLAGS), - MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, - RK3288_CLKSEL_CON(13), 8, 2, MFLAGS), + RK3288_CLKGATE_CON(1), 9, GFLAGS, + MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(13), 8, 2, MFLAGS)), MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(13), 15, 1, MFLAGS), COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0, RK3288_CLKSEL_CON(14), 0, 7, DFLAGS, RK3288_CLKGATE_CON(1), 10, GFLAGS), - COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(18), 0, - RK3288_CLKGATE_CON(1), 11, GFLAGS), - MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, - RK3288_CLKSEL_CON(14), 8, 2, MFLAGS), + RK3288_CLKGATE_CON(1), 11, GFLAGS, + MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(14), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0, RK3288_CLKSEL_CON(15), 0, 7, DFLAGS, RK3288_CLKGATE_CON(1), 12, GFLAGS), - COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(19), 0, - RK3288_CLKGATE_CON(1), 13, GFLAGS), - MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, - RK3288_CLKSEL_CON(15), 8, 2, MFLAGS), + RK3288_CLKGATE_CON(1), 13, GFLAGS, + MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(15), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0, RK3288_CLKSEL_CON(16), 0, 7, DFLAGS, RK3288_CLKGATE_CON(1), 14, GFLAGS), - COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(20), 0, - RK3288_CLKGATE_CON(1), 15, GFLAGS), - MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT, - RK3288_CLKSEL_CON(16), 8, 2, MFLAGS), + RK3288_CLKGATE_CON(1), 15, GFLAGS, + MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(16), 8, 2, MFLAGS)), COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0, RK3288_CLKSEL_CON(3), 0, 7, DFLAGS, RK3288_CLKGATE_CON(2), 12, GFLAGS), - COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(7), 0, - RK3288_CLKGATE_CON(2), 13, GFLAGS), - MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT, - RK3288_CLKSEL_CON(3), 8, 2, MFLAGS), + RK3288_CLKGATE_CON(2), 13, GFLAGS, + MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(3), 8, 2, MFLAGS)), COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0, RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS, From 84a8c541664b037a4d1fdc3151466b4ec45c37a5 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Tue, 22 Dec 2015 22:28:02 +0100 Subject: [PATCH 3/5] clk: rockchip: Allow the RK3288 SPDIF clocks to change their parent The clock branches leading to sclk_spdif and sclk_spdif_8ch on RK3288 SoCs only feed those clocks, allow those clocks to change their parents all the way up the hierarchy. Signed-off-by: Sjoerd Simons Signed-off-by: Heiko Stuebner Signed-off-by: Michael Turquette --- drivers/clk/rockchip/clk-rk3288.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 3d1a6efdbe99..074550c0cb90 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -317,25 +317,25 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(5), 15, 1, MFLAGS), - COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", 0, + COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(5), 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 4, GFLAGS), - COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0, + COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(9), 0, RK3288_CLKGATE_CON(4), 5, GFLAGS, - MUX(0, "spdif_mux", mux_spdif_p, 0, + MUX(0, "spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(5), 8, 2, MFLAGS)), - GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", 0, + GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", CLK_SET_RATE_PARENT, RK3288_CLKGATE_CON(4), 6, GFLAGS), - COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0, + COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(40), 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 7, GFLAGS), - COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", 0, + COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(41), 0, RK3288_CLKGATE_CON(4), 8, GFLAGS, - MUX(0, "spdif_8ch_mux", mux_spdif_8ch_p, 0, + MUX(0, "spdif_8ch_mux", mux_spdif_8ch_p, CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(40), 8, 2, MFLAGS)), - GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", 0, + GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", CLK_SET_RATE_PARENT, RK3288_CLKGATE_CON(4), 9, GFLAGS), GATE(0, "sclk_acc_efuse", "xin24m", 0, From 2eb8c7104c648ad4bfae1f5333f98c09522149b5 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 22 Dec 2015 22:27:58 +0100 Subject: [PATCH 4/5] clk: add flag for clocks that need to be enabled on rate changes Some clocks need to be enabled to accept rate changes. This patch adds a new flag CLK_SET_RATE_UNGATE that lets clk_change_rate enable the clock before trying to change the rate and disable it again afterwards. This of course doesn't effect clocks that are already running at that point, as their refcount will only temporarily increase. Signed-off-by: Heiko Stuebner Tested-by: Sjoerd Simons Reviewed-by: Sjoerd Simons Signed-off-by: Michael Turquette --- drivers/clk/clk.c | 18 ++++++++++++++++++ include/linux/clk-provider.h | 1 + 2 files changed, 19 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f13c3f4228d4..bd64a9414de2 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1443,6 +1443,15 @@ static void clk_change_rate(struct clk_core *core) else if (core->parent) best_parent_rate = core->parent->rate; + if (core->flags & CLK_SET_RATE_UNGATE) { + unsigned long flags; + + clk_core_prepare(core); + flags = clk_enable_lock(); + clk_core_enable(core); + clk_enable_unlock(flags); + } + if (core->new_parent && core->new_parent != core->parent) { old_parent = __clk_set_parent_before(core, core->new_parent); trace_clk_set_parent(core, core->new_parent); @@ -1469,6 +1478,15 @@ static void clk_change_rate(struct clk_core *core) core->rate = clk_recalc(core, best_parent_rate); + if (core->flags & CLK_SET_RATE_UNGATE) { + unsigned long flags; + + flags = clk_enable_lock(); + clk_core_disable(core); + clk_enable_unlock(flags); + clk_core_unprepare(core); + } + if (core->notifier_count && old_rate != core->rate) __clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index c56988ac63f7..a971ce462565 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -31,6 +31,7 @@ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ #define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */ +#define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */ struct clk; struct clk_hw; From b0158bb27c7b6e9843f541c17b24dbd964b76db6 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Tue, 22 Dec 2015 22:28:01 +0100 Subject: [PATCH 5/5] clk: rockchip: rk3036: include downstream muxes into fractional dividers Use the newly introduced possibility to combine the fractional dividers with their downstream muxes for all fractional dividers on currently supported RK3036 SoCs. Signed-off-by: Xing Zheng Signed-off-by: Caesar Wang Signed-off-by: Heiko Stuebner Signed-off-by: Michael Turquette --- drivers/clk/rockchip/clk-rk3036.c | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c index 75553af3dc39..42c2003e5eb4 100644 --- a/drivers/clk/rockchip/clk-rk3036.c +++ b/drivers/clk/rockchip/clk-rk3036.c @@ -227,21 +227,21 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0, RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 8, GFLAGS), - COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(17), 0, - RK2928_CLKGATE_CON(1), 9, GFLAGS), - COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(18), 0, - RK2928_CLKGATE_CON(1), 11, GFLAGS), - COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(19), 0, - RK2928_CLKGATE_CON(1), 13, GFLAGS), + RK2928_CLKGATE_CON(1), 9, GFLAGS, MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(13), 8, 2, MFLAGS), + RK2928_CLKSEL_CON(13), 8, 2, MFLAGS)), + COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(18), 0, + RK2928_CLKGATE_CON(1), 11, GFLAGS, MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(14), 8, 2, MFLAGS), + RK2928_CLKSEL_CON(14), 8, 2, MFLAGS)), + COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(19), 0, + RK2928_CLKGATE_CON(1), 13, GFLAGS, MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(15), 8, 2, MFLAGS), + RK2928_CLKSEL_CON(15), 8, 2, MFLAGS)), COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0, RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, @@ -289,11 +289,11 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0, RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS, RK2928_CLKGATE_CON(0), 9, GFLAGS), - COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(7), 0, - RK2928_CLKGATE_CON(0), 10, GFLAGS), + RK2928_CLKGATE_CON(0), 10, GFLAGS, MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, - RK2928_CLKSEL_CON(3), 8, 2, MFLAGS), + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS)), COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0, RK2928_CLKSEL_CON(3), 12, 1, MFLAGS, RK2928_CLKGATE_CON(0), 13, GFLAGS), @@ -303,11 +303,11 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0, RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS, RK2928_CLKGATE_CON(2), 10, GFLAGS), - COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0, + COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0, RK2928_CLKSEL_CON(9), 0, - RK2928_CLKGATE_CON(2), 12, GFLAGS), + RK2928_CLKGATE_CON(2), 12, GFLAGS, MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0, - RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), + RK2928_CLKSEL_CON(5), 8, 2, MFLAGS)), GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(1), 5, GFLAGS),