Messages in this thread | | | From | Stephen Boyd <> | Subject | Re: [RFC/RFT 07/14] clk: meson: g12a: add notifiers to handle cpu clock change | Date | Tue, 25 Jun 2019 13:31:51 -0700 |
| |
Quoting Neil Armstrong (2019-06-20 08:00:06) > In order to implement clock switching for the CLKID_CPU_CLK and > CLKID_CPUB_CLK, notifiers are added on specific points of the > clock tree : > > cpu_clk / cpub_clk > | \- cpu_clk_dyn > | | \- cpu_clk_premux0 > | | |- cpu_clk_postmux0 > | | | |- cpu_clk_dyn0_div > | | | \- xtal/fclk_div2/fclk_div3 > | | \- xtal/fclk_div2/fclk_div3 > | \- cpu_clk_premux1 > | |- cpu_clk_postmux1 > | | |- cpu_clk_dyn1_div > | | \- xtal/fclk_div2/fclk_div3 > | \- xtal/fclk_div2/fclk_div3 > \ sys_pll / sys1_pll > > This for each cluster, a single one for G12A, two for G12B. > > Each cpu_clk_premux1 tree is marked as read-only and CLK_SET_RATE_NO_REPARENT, > to be used as "parking" clock in a safe clock frequency. > > A notifier is added on each cpu_clk_premux0 to detech when CCF want to > change the frequency of the cpu_clk_dyn tree. > In this notifier, the cpu_clk_premux1 tree is configured to use the xtal > clock and then the cpu_clk_dyn is switch to cpu_clk_premux1 while CCF > updates the cpu_clk_premux0 tree. > > A notifier is added on each sys_pll/sys1_pll to detect when CCF wants to > change the PLL clock source of the cpu_clk. > In this notifier, the cpu_clk is switched to cpu_clk_dyn while CCF > updates the sys_pll/sys1_pll frequency. > > A third small notifier is added on each cpu_clk / cpub_clk and cpu_clk_dyn, > add a small delay at PRE_RATE_CHANGE/POST_RATE_CHANGE to let the other > notofiers change propagate before changing the cpu_clk_premux0 and sys_pll > clock trees. > > This notifier set permits switching the cpu_clk / cpub_clk without any > glitches and using a safe parking clock while switching between sub-GHz > clocks using the cpu_clk_dyn tree. > > This setup has been tested and validated on the Amlogic G12A and G12B > SoCs running the arm64 cpuburn at [1] and cycling between all the possible > cpufreq translations of each cluster and checking the final frequency using > the clock-measurer, script at [2]. > > [1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S > [2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f > > Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> [...] > @@ -418,6 +458,35 @@ static struct clk_regmap g12b_cpub_clk_premux0 = { > }, > }; > > +/* This divider uses bit 26 to take change in account */ > +static int g12b_cpub_clk_mux0_div_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + struct clk_regmap *clk = to_clk_regmap(hw); > + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); > + unsigned int val; > + int ret; > + > + ret = divider_get_val(rate, parent_rate, div->table, div->width, > + div->flags); > + if (ret < 0) > + return ret; > + > + val = (unsigned int)ret << div->shift; > + > + regmap_update_bits(clk->map, HHI_SYS_CPUB_CLK_CNTL, > + SYS_CPU_DYN_ENABLE, SYS_CPU_DYN_ENABLE); > + > + return regmap_update_bits(clk->map, div->offset, > + clk_div_mask(div->width) << div->shift | SYS_CPU_DYN_ENABLE, val); > +}; > + > +const struct clk_ops g12b_cpub_clk_mux0_div_ops = {
static?
> + .recalc_rate = clk_regmap_div_recalc_rate, > + .round_rate = clk_regmap_div_round_rate, > + .set_rate = g12b_cpub_clk_mux0_div_set_rate, > +}; > + > /* Datasheet names this field as "mux0_divn_tcnt" */ > static struct clk_regmap g12b_cpub_clk_mux0_div = { > .data = &(struct clk_regmap_div_data){ [...] > > +static int g12a_cpu_clk_mux_notifier_cb(struct notifier_block *nb, > + unsigned long event, void *data) > +{ > + switch (event) { > + case POST_RATE_CHANGE: > + case PRE_RATE_CHANGE: > + /* Wait for clock propagation before/after changing the mux */ > + udelay(100); > + return NOTIFY_OK; > + > + default: > + return NOTIFY_DONE; > + }
Maybe convert this into a if statement and then have a default return of NOTIFY_DONE otherwise?
> +} > + > +struct notifier_block g12a_cpu_clk_mux_nb = {
static?
> + .notifier_call = g12a_cpu_clk_mux_notifier_cb, > +}; > + > +struct g12a_cpu_clk_postmux_nb_data { > + struct notifier_block nb; > + struct clk_hw *xtal; > + struct clk_hw *cpu_clk_dyn; > + struct clk_hw *cpu_clk_postmux0; > + struct clk_hw *cpu_clk_postmux1; > + struct clk_hw *cpu_clk_premux1; > +}; > + > +static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, > + unsigned long event, void *data) > +{ > + struct g12a_cpu_clk_postmux_nb_data *nb_data = > + container_of(nb, struct g12a_cpu_clk_postmux_nb_data, nb); > + > + switch (event) { > + case PRE_RATE_CHANGE: > + /* > + * This notifier means cpu_clk_postmux0 clock will be changed > + * to feed cpu_clk, this the current path :
Maybe write "this is the current path"?
| |