Re: [PATCH v3 3/4] clk: renesas: rzg2l: Add support to handle coupled clocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Biju,

On Sun, Aug 15, 2021 at 12:30 PM Biju Das <biju.das.jz@xxxxxxxxxxxxxx> wrote:
> The AXI and CHI clocks use the same register bit for controlling clock
> output. Add a new clock type for coupled clocks, which sets the
> CPG_CLKON_ETH.CLK[01]_ON bit when at least one clock is enabled, and
> clears the bit only when both clocks are disabled.
>
> Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>
> Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
> ---
> v2->v3:
>  * Reworked as per Geert's suggestion
>  * Added enabled flag to track the status of clock, if it is coupled
>    with another clock
>  * Introduced siblings pointer which points to the other coupled
>    clock
>  * coupled clock linking is done during module clk register.
>  * rzg2l_mod_clock_is_enabled function returns soft state of the
>    module clocks, if it is coupled with another clock
>  * Updated the commit header

Thanks for the update!

> --- a/drivers/clk/renesas/rzg2l-cpg.c
> +++ b/drivers/clk/renesas/rzg2l-cpg.c
> @@ -392,11 +396,35 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable)
>
>  static int rzg2l_mod_clock_enable(struct clk_hw *hw)
>  {
> +       struct mstp_clock *clock = to_mod_clock(hw);
> +       struct mstp_clock *siblings = clock->siblings;
> +
> +       if (siblings) {
> +               if (siblings->enabled) {
> +                       clock->enabled = true;
> +                       return 0;
> +               }
> +
> +               clock->enabled = true;

clock->enabled is set to true regardless of the if condition.
This also needs locking, in case both clocks are changed concurrently:

    spin_lock_irqsave(&priv->rmw_lock, flags);
    enabled = siblings->enabled;
    clock->enabled = true;
    spin_unlock_irqrestore(&priv->rmw_lock, flags);
    if (enabled)
            return 0;

> +       }
> +
>         return rzg2l_mod_clock_endisable(hw, true);
>  }
>
>  static void rzg2l_mod_clock_disable(struct clk_hw *hw)
>  {
> +       struct mstp_clock *clock = to_mod_clock(hw);
> +       struct mstp_clock *siblings = clock->siblings;
> +
> +       if (siblings) {
> +               if (siblings->enabled) {
> +                       clock->enabled = false;
> +                       return;
> +               }
> +
> +               clock->enabled = false;

Likewise.

> +       }
> +
>         rzg2l_mod_clock_endisable(hw, false);
>  }
>
> @@ -412,6 +440,9 @@ static int rzg2l_mod_clock_is_enabled(struct clk_hw *hw)
>                 return 1;
>         }
>
> +       if (clock->siblings)
> +               return clock->enabled;
> +
>         value = readl(priv->base + CLK_MON_R(clock->off));
>
>         return !(value & bitmask);
> @@ -423,11 +454,33 @@ static const struct clk_ops rzg2l_mod_clock_ops = {
>         .is_enabled = rzg2l_mod_clock_is_enabled,
>  };
>
> +static struct mstp_clock
> +*rzg2l_cpg_get_sibling_clk(struct mstp_clock *clock,
> +                          struct rzg2l_cpg_priv *priv)
> +{
> +       struct mstp_clock *sibl_clk = NULL;

clk?
It's only a sibling when the condition inside the loop is true.

> +       struct clk_hw *hw;
> +       unsigned int i;
> +
> +       for (i = 0; i < priv->num_mod_clks; i++) {
> +               if (priv->clks[priv->num_core_clks + i] == ERR_PTR(-ENOENT))
> +                       continue;
> +
> +               hw = __clk_get_hw(priv->clks[priv->num_core_clks + i]);
> +               sibl_clk = to_mod_clock(hw);
> +               if (clock->off == sibl_clk->off && clock->bit == sibl_clk->bit)
> +                       break;
> +       }
> +
> +       return sibl_clk;
> +}
> +
>  static void __init
>  rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod,
>                            const struct rzg2l_cpg_info *info,
>                            struct rzg2l_cpg_priv *priv)
>  {
> +       struct mstp_clock *sibling_clock = NULL;
>         struct mstp_clock *clock = NULL;
>         struct device *dev = priv->dev;
>         unsigned int id = mod->id;
> @@ -484,6 +537,15 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod,
>
>         dev_dbg(dev, "Module clock %pC at %lu Hz\n", clk, clk_get_rate(clk));
>         priv->clks[id] = clk;
> +
> +       if (mod->is_coupled) {
> +               sibling_clock = rzg2l_cpg_get_sibling_clk(clock, priv);
> +               if (sibling_clock) {
> +                       clock->siblings = sibling_clock;
> +                       sibling_clock->siblings = clock;
> +               }

You forgot to initialize mstp_clock.enabled to match the current
hardware state.

> +       }
> +
>         return;
>
>  fail:

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds



[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux