mbox series

[v2,00/28] Add new Renesas RZ/G3S SoC and RZ/G3S SMARC EVK

Message ID 20230929053915.1530607-1-claudiu.beznea@bp.renesas.com
Headers show
Series Add new Renesas RZ/G3S SoC and RZ/G3S SMARC EVK | expand

Message

Claudiu Sept. 29, 2023, 5:38 a.m. UTC
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Hi,

This patch series adds initial support for The Renesas RZ/G3S (R9A08G045{S33})
SoC. The RZ/G3S device is a general-purpose microprocessor with a
single-core Arm® Cortex®-A55 (1.1GHz) and a dual-core Arm® Cortex®-M33 (250MHz),
perfect for an IOT gateway controller.

This includes:
- SoC identification;
- clocks (core clocks, pin controller clock, serial interface, SD ch0
  clock) and corresponding resets;
- minimal device tree for SoM and carrier boards.

With this series Linux can boot from eMMC or SD card. The eMMC and uSD
interface are multiplexed on the SoM; selection is made using a hardware
switch.

Patches are gouped as follows:
- 01    documents scif support;
- 02-05	contain fixes on clock drivers identified while adding RZ/G3S
	support
- 06	clock cleanups identifies while adding support for RZ/G3S
- 07-13	clock changes needed by RZ/G3S
- 14-21	pinctrl changes needed by RZ/G3S
- 22-28 device tree support for RZ/G3S

Changes in v2:
- addressed review comments
- collected tags
- removed from series patches that were already integrated
- added patches:
	- [PATCH v2 19/28] dt-bindings: pinctrl: renesas: set additionalProperties: false
	- [PATCH v2 23/28] dt-bindings: arm: renesas: document RZ/G3S SMARC SoM
	- [PATCH v2 26/28] dt-bindings: arm: renesas: document SMARC Carrier-II EVK
- please see individual patches for detailed changes

Claudiu Beznea (28):
  dt-bindings: serial: renesas,scif: document r9a08g045 support
  clk: renesas: rzg2l: wait for status bit of SD mux before continuing
  clk: renesas: rzg2l: lock around writes to mux register
  clk: renesas: rzg2l: trust value returned by hardware
  clk: renesas: rzg2l: fix computation formula
  clk: renesas: rzg2l: remove critical area
  clk: renesas: rzg2l: add support for RZ/G3S PLL
  clk: renesas: rzg2l: add struct clk_hw_data
  clk: renesas: rzg2l: remove CPG_SDHI_DSEL from generic header
  clk: renesas: rzg2l: refactor sd mux driver
  clk: renesas: rzg2l: add a divider clock for RZ/G3S
  dt-bindings: clock: renesas,rzg2l-cpg: document RZ/G3S SoC
  clk: renesas: add minimal boot support for RZ/G3S SoC
  pinctrl: renesas: rzg2l: index all registers based on port offset
  pinctrl: renesas: rzg2l: adapt for different SD/PWPR register offsets
  pinctrl: renesas: rzg2l: adapt function number for RZ/G3S
  pinctrl: renesas: rzg2l: move ds and oi to SoC specific configuration
  pinctrl: renesas: rzg2l: add support for different ds values on
    different groups
  dt-bindings: pinctrl: renesas: set additionalProperties: false
  dt-bindings: pinctrl: renesas: document RZ/G3S SoC
  pinctrl: renesas: rzg2l: add support for RZ/G3S SoC
  arm64: dts: renesas: add initial DTSI for RZ/G3S SoC
  dt-bindings: arm: renesas: document RZ/G3S SMARC SoM
  arm64: dts: renesas: rzg3l-smarc-som: add initial support for RZ/G3S
    SMARC SoM
  arm64: dts: renesas: rzg3s-smarc: add initial device tree for RZ SMARC
    Carrier-II Board
  dt-bindings: arm: renesas: document SMARC Carrier-II EVK
  arm64: dts: renesas: r9a08g045s33-smarc: add initial device tree for
    RZ/G3S SMARC EVK board
  arm64: defconfig: enable RZ/G3S (R9A08G045) SoC

 .../bindings/clock/renesas,rzg2l-cpg.yaml     |   1 +
 .../pinctrl/renesas,rzg2l-pinctrl.yaml        |  23 +-
 .../bindings/serial/renesas,scif.yaml         |   1 +
 .../bindings/soc/renesas/renesas.yaml         |  13 +
 arch/arm64/boot/dts/renesas/Makefile          |   2 +
 arch/arm64/boot/dts/renesas/r9a08g045.dtsi    | 139 ++++
 .../boot/dts/renesas/r9a08g045s33-smarc.dts   |  17 +
 arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi |  14 +
 .../boot/dts/renesas/rzg3s-smarc-som.dtsi     | 142 ++++
 arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi  |  28 +
 arch/arm64/configs/defconfig                  |   1 +
 drivers/clk/renesas/Kconfig                   |   7 +-
 drivers/clk/renesas/Makefile                  |   1 +
 drivers/clk/renesas/r9a07g043-cpg.c           |  19 +-
 drivers/clk/renesas/r9a07g044-cpg.c           |  19 +-
 drivers/clk/renesas/r9a08g045-cpg.c           | 213 ++++++
 drivers/clk/renesas/rzg2l-cpg.c               | 478 ++++++++++--
 drivers/clk/renesas/rzg2l-cpg.h               |  33 +-
 drivers/pinctrl/renesas/pinctrl-rzg2l.c       | 705 ++++++++++++++----
 include/dt-bindings/clock/r9a08g045-cpg.h     | 242 ++++++
 20 files changed, 1860 insertions(+), 238 deletions(-)
 create mode 100644 arch/arm64/boot/dts/renesas/r9a08g045.dtsi
 create mode 100644 arch/arm64/boot/dts/renesas/r9a08g045s33-smarc.dts
 create mode 100644 arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi
 create mode 100644 arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
 create mode 100644 arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
 create mode 100644 drivers/clk/renesas/r9a08g045-cpg.c
 create mode 100644 include/dt-bindings/clock/r9a08g045-cpg.h

Comments

Paul Barker Sept. 29, 2023, 9:24 a.m. UTC | #1
On 29/09/2023 06:39, Claudiu wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> RZ/G3S supports different drive strength values for different power sources
> and pin groups (A, B, C). On each group there could be up to 4 drive
> strength values per power source. Available power sources are 1v8, 2v5,
> 3v3. Drive strength values are fine tuned than what was previously

Should this be "are more fine tuned" or "are less fine tuned"?

> available on the driver thus the necessity of having micro-amp support.
> As drive strength and power source values are linked together the
> hardware setup for these was moved at the end of
> rzg2l_pinctrl_pinconf_set() to ensure proper validation of the new
> values.
> 
> The drive strength values are expected to be initialized though SoC
> specific hardware configuration data structure.
> 
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Thanks,
Paul
Geert Uytterhoeven Oct. 3, 2023, 3:14 p.m. UTC | #2
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Hardware user manual of RZ/G2L (r01uh0914ej0130-rzg2l-rzg2lc.pdf,
> chapter 7.4.7 Procedure for Switching Clocks by the Dynamic Switching
> Frequency Selectors) specifies that we need to check CPG_PL2SDHI_DSEL for
> SD clock switching status.
>
> Fixes: eaff33646f4cb ("clk: renesas: rzg2l: Add SDHI clk mux support")
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - initialized msk

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 3, 2023, 3:18 p.m. UTC | #3
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> SD MUX output (SD0) is further divided by 4 in G2{L, UL}. The divided
> clock is SD0_DIV4. SD0_DIV4 is registered with CLK_SET_RATE_PARENT which
> means a rate request for it is propagated to the MUX and could reach
> rzg2l_cpg_sd_clk_mux_set_parent() concurrently with the users of SD0.
> Add proper locking to avoid concurrent access on SD MUX set rate
> registers.
>
> Fixes: eaff33646f4cb ("clk: renesas: rzg2l: Add SDHI clk mux support")
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - adapted delay_us to 10us
> - adapted CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US to 200us; tested
>   with this adjustements on RZ/G3S and RZ/G2L SoCs

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 3, 2023, 3:19 p.m. UTC | #4
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Initial value of CPG_PL2SDHI_DSEL bits 0..1 or 4..6 is 01b. Hardware user's
> manual (r01uh0914ej0130-rzg2l-rzg2lc.pdf) specifies that setting 0 is
> prohibited. The rzg2l_cpg_sd_clk_mux_get_parent() should just read
> CPG_PL2SDHI_DSEL, trust the value and return the proper clock parent index
> based on the read value. Do this.
>
> Fixes: eaff33646f4cb ("clk: renesas: rzg2l: Add SDHI clk mux support")
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - Used "return val ? val - 1 : 0;"

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 8:08 a.m. UTC | #5
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> According to hardware manual of RZ/G2L (r01uh0914ej0130-rzg2l-rzg2lc.pdf)
> the computation formula for PLL rate is as follows:
>
> Fout = ((m + k/65536) * Fin) / (p * 2^s)
>
> and k has values in range [-32768, 32767]. Dividing k by 65536 with
> integer variables leads all the time to zero. Thus we may have slight
> differences b/w what has been set vs. what is displayed. Thus,
> get rid of this and decompose the formula before dividing k by 65536.
>
> Fixes: ef3c613ccd68a ("clk: renesas: Add CPG core wrapper for RZ/G2L SoC")
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - used mul_u64_u32_shr()

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk-for-v6.7.

> --- a/drivers/clk/renesas/rzg2l-cpg.c
> +++ b/drivers/clk/renesas/rzg2l-cpg.c
> @@ -695,18 +695,18 @@ static unsigned long rzg2l_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
>         struct pll_clk *pll_clk = to_pll(hw);
>         struct rzg2l_cpg_priv *priv = pll_clk->priv;
>         unsigned int val1, val2;
> -       unsigned int mult = 1;
> -       unsigned int div = 1;
> +       u64 rate;
>
>         if (pll_clk->type != CLK_TYPE_SAM_PLL)
>                 return parent_rate;
>
>         val1 = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf));
>         val2 = readl(priv->base + GET_REG_SAMPLL_CLK2(pll_clk->conf));
> -       mult = MDIV(val1) + KDIV(val1) / 65536;
> -       div = PDIV(val1) << SDIV(val2);
>
> -       return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, div);
> +       rate = mul_u64_u32_shr(parent_rate, (MDIV(val1) << 16) + (s16)KDIV(val1),

As KDIV() is always a signed number, I will move the cast to s16 to
the definition of KDIV() while applying.

> +                              16 + SDIV(val2));
> +
> +       return DIV_ROUND_CLOSEST_ULL(rate, PDIV(val1));
>  }
>
>  static const struct clk_ops rzg2l_cpg_pll_ops = {

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 8:11 a.m. UTC | #6
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> spinlock in rzg2l_mod_clock_endisable() is intended to protect the accesses
> to hardware register. There is no need to protect the instructions that set
> temporary variable which will be then written to register. With this only
> one write to one clock register is executed thus locking/unlocking rmw_lock
> is removed.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - removed also the spinlock
> - s/reduce/remove in patch title

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 8:45 a.m. UTC | #7
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add support for reading the frequency of PLL1/4/6 available on RZ/G3S.
> The computation formula for PLL frequency is as follows:
> Fout = (nir + nfr / 4096) * Fin / (mr * pr)
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - added GENMASK() defines for DIV_P, DIV_M, DIV_NI, DIV_NF
> - used mul_u64_u32_shr() as suggested by Geert on v1
> - s/CLK_TYPE_G3S_SAM_PLL/CLK_TYPE_G3S_PLL/g

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 8:47 a.m. UTC | #8
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add clk_hw_data struct that keeps the core part of a clock data. The
> sd_hw_data embeds a member of type struct clk_hw_data along with other
> members (in the next commits). This commit prepares the field for
> refactoring the SD MUX clock driver.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - collected tags

Thanks, will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 8:50 a.m. UTC | #9
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Remove CPG_SDHI_DSEL and its bits from generic header as RZ/G3S has
> different offset register and bits for this, thus avoid mixing them.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - s/form/from in commit description
> - removed "G2UL_" prefix from macros' names
> - collected tags

Thanks, will queue in renesas-clk-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 11:30 a.m. UTC | #10
Hi Claudiu,

On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Refactor SD MUX driver to be able to reuse the same code on RZ/G3S.
> RZ/G2{L, UL} has a limitation with regards to switching the clock source
> for SD MUX (MUX clock source has to be switched to 266MHz before switching
> b/w 533MHz and 400MHz). This limitation has been introduced as a clock
> notifier that is registered on platform based initialization data thus the
> SD MUX code could be reused on RZ/G3S.
>
> As both RZ/G2{L, UL} and RZ/G3S has specific bits in specific registers
> to check if the clock switching has been done, this configuration (register
> offset, register bits and bits width) is now passed though
> struct cpg_core_clk::sconf (status configuration) from platform specific
> initialization code.
>
> Along with struct cpg_core_clk::sconf the mux table indices are also
> passed from platform specific initialization code.
>
> Also, mux flags are now passed to DEF_SD_MUX() as they will be later
> used by RZ/G3S.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - s/indexes/indices in commit description
> - mentioned in commit description that mux flags can now be passed to
>   driver though DEF_SD_MUX() macro
> - removed SoC specific names from macros' names
> - added spaces after { and before } when initializing arrays
> - preserved the order of .[gs]set_parent() API definitions for simpler
>   diff b/w versions
> - removed SD_MUX_NOTIF macro

Thanks for the update!

> --- a/drivers/clk/renesas/rzg2l-cpg.c
> +++ b/drivers/clk/renesas/rzg2l-cpg.c

> @@ -142,6 +146,77 @@ static void rzg2l_cpg_del_clk_provider(void *data)
>         of_clk_del_provider(data);
>  }
>
> +/* Must be called in atomic context. */
> +static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf)
> +{
> +       u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf);
> +       u32 off = GET_REG_OFFSET(conf);
> +       u32 val;
> +
> +       return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200);
> +}
> +
> +int rzg2l_cpg_sd_mux_clk_notifier(struct notifier_block *nb, unsigned long event,
> +                                 void *data)
> +{
> +       struct clk_notifier_data *cnd = data;
> +       struct clk_hw *hw = __clk_get_hw(cnd->clk);
> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
> +       u32 off = GET_REG_OFFSET(clk_hw_data->conf);
> +       u32 shift = GET_SHIFT(clk_hw_data->conf);
> +       const u32 clk_src_266 = 3;
> +       unsigned long flags;
> +       u32 bitmask;
> +       int ret;
> +
> +       if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266))
> +               return 0;

include/linux/clk.h:

 * PRE_RATE_CHANGE - called immediately before the clk rate is changed,
 *     to indicate that the rate change will proceed.  Drivers must
 *     immediately terminate any operations that will be affected by the
 *     rate change.  Callbacks may either return NOTIFY_DONE, NOTIFY_OK,
 *     NOTIFY_STOP or NOTIFY_BAD.

> +
> +       spin_lock_irqsave(&priv->rmw_lock, flags);
> +
> +       /*
> +        * As per the HW manual, we should not directly switch from 533 MHz to
> +        * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz)
> +        * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first,
> +        * and then switch to the target setting (2’b01 (533 MHz) or 2’b10
> +        * (400 MHz)).
> +        * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock
> +        * switching register is prohibited.
> +        * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and
> +        * the index to value mapping is done by adding 1 to the index.
> +        */
> +       bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16;
> +       writel(bitmask | (clk_src_266 << shift), priv->base + off);
> +
> +       /* Wait for the update done. */
> +       ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
> +
> +       spin_unlock_irqrestore(&priv->rmw_lock, flags);
> +
> +       if (ret)
> +               dev_err(priv->dev, "failed to switch to safe clk source\n");
> +
> +       return ret;

Likewise.

> +}

>
>  static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = {
>         .determine_rate = __clk_mux_determine_rate_closest,
> -       .set_parent     = rzg2l_cpg_sd_clk_mux_set_parent,
> -       .get_parent     = rzg2l_cpg_sd_clk_mux_get_parent,
> +       .set_parent     = rzg2l_cpg_sd_mux_clk_set_parent,
> +       .get_parent     = rzg2l_cpg_sd_mux_clk_get_parent,

Please keep the old names, for consistency with
__clk_mux_determine_rate_closest() and drivers/clk/clk-mux.c, and to
reduce the diff.

Any existing inconsistent use of "clk_mux" vs. "mux_clk" can be resolved
later with a separate patch, if anyone cares.

> --- a/drivers/clk/renesas/rzg2l-cpg.h
> +++ b/drivers/clk/renesas/rzg2l-cpg.h

> @@ -272,4 +276,6 @@ extern const struct rzg2l_cpg_info r9a07g044_cpg_info;
>  extern const struct rzg2l_cpg_info r9a07g054_cpg_info;
>  extern const struct rzg2l_cpg_info r9a09g011_cpg_info;
>
> +int rzg2l_cpg_sd_mux_clk_notifier(struct notifier_block *nb, unsigned long event, void *data);

rzg2l_cpg_sd_clk_mux_notifier()?

> +
>  #endif

The rest LGTM.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

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
Geert Uytterhoeven Oct. 4, 2023, 12:30 p.m. UTC | #11
Hi Claudiu,

On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add a divider clock driver for RZ/G3S. This will be used in RZ/G3S
> by SDHI, SPI, OCTA, I, I2, I3, P0, P1, P2, P3 core clocks.
> The divider has some limitation for SDHI and OCTA clocks:
> - SD div cannot be 1 if parent rate is 800MHz
> - OCTA div cannot be 1 if parent rate is 400MHz
> For these clocks a notifier could be registered from platform specific
> clock driver and proper actions are taken before clock rate is changed,
> if needed.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - removed DIV_NOTIF macro

Thanks for the update!

> --- a/drivers/clk/renesas/rzg2l-cpg.c
> +++ b/drivers/clk/renesas/rzg2l-cpg.c
> @@ -91,6 +91,22 @@ struct sd_mux_hw_data {
>
>  #define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data)
>
> +/**
> + * struct div_hw_data - divider clock hardware data
> + * @hw_data: clock hw data
> + * @dtable: pointer to divider table
> + * @invalid_rate: invalid rate for divider
> + * @width: divider width
> + */
> +struct div_hw_data {
> +       struct clk_hw_data hw_data;
> +       const struct clk_div_table *dtable;
> +       unsigned long invalid_rate;
> +       u32 width;
> +};
> +
> +#define to_div_hw_data(_hw)    container_of(_hw, struct div_hw_data, hw_data)
> +
>  struct rzg2l_pll5_param {
>         u32 pl5_fracin;
>         u8 pl5_refdiv;
> @@ -200,6 +216,54 @@ int rzg2l_cpg_sd_mux_clk_notifier(struct notifier_block *nb, unsigned long event
>         return ret;
>  }
>
> +int rzg3s_cpg_div_clk_notifier(struct notifier_block *nb, unsigned long event,
> +                              void *data)
> +{
> +       struct clk_notifier_data *cnd = data;
> +       struct clk_hw *hw = __clk_get_hw(cnd->clk);
> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
> +       u32 off = GET_REG_OFFSET(clk_hw_data->conf);
> +       u32 shift = GET_SHIFT(clk_hw_data->conf);
> +       u32 bitmask = GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
> +       unsigned long flags;
> +       int ret = 0;
> +       u32 val;
> +
> +       if (event != PRE_RATE_CHANGE || !div_hw_data->invalid_rate ||
> +           div_hw_data->invalid_rate % cnd->new_rate)
> +               return 0;

NOTIFY_DONE for event != PRE_RATE_CHANGE
NOTIFY_OK for the other cases

> +
> +       spin_lock_irqsave(&priv->rmw_lock, flags);
> +
> +       val = readl(priv->base + off);
> +       val >>= shift;
> +       val &= bitmask;
> +
> +       /*
> +        * There are different constraints for the user of this notifiers as follows:
> +        * 1/ SD div cannot be 1 (val == 0) if parent rate is 800MHz
> +        * 2/ OCTA div cannot be 1 (val == 0) if parent rate is 400MHz
> +        * As SD can have only one parent having 800MHz and OCTA div can have
> +        * only one parent having 400MHz we took into account the parent rate
> +        * at the beginning of function (by checking invalid_rate % new_rate).
> +        * Now it is time to check the hardware divider and update it accordingly.
> +        */
> +       if (!val) {
> +               writel(((bitmask << shift) << 16) | BIT(shift), priv->base + off);

Haven't you exchanged the (single) write-enable bit and the (multi-bit)
division ratio setting?  According to the docs, the write-enable bit
is at 16 + shift, while the division ratio is at shift.

Also, using bitmask as the division ratio means the maximum value
that fits in the bitfield, which would be a prohibited setting in case
of DIV_OCTA.

Now, looking at rzg3s_div_clk_set_rate() below, perhaps you just wanted
to set the ratio to value to 1, but used the wrong size for bitmask?

> +               /* Wait for the update done. */
> +               ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
> +       }
> +
> +       spin_unlock_irqrestore(&priv->rmw_lock, flags);
> +
> +       if (ret)
> +               dev_err(priv->dev, "Failed to downgrade the div\n");

and return NOTIFY_BAD

> +
> +       return ret;

NOTIFY_OK

> +}
> +
>  static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core,
>                                    struct rzg2l_cpg_priv *priv)
>  {
> @@ -217,6 +281,146 @@ static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk
>         return clk_notifier_register(hw->clk, nb);
>  }
>
> +static unsigned long rzg3s_div_clk_recalc_rate(struct clk_hw *hw,
> +                                              unsigned long parent_rate)
> +{
> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
> +       u32 val;
> +
> +       val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf));
> +       val >>= GET_SHIFT(clk_hw_data->conf);
> +       val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
> +
> +       return divider_recalc_rate(hw, parent_rate, val, div_hw_data->dtable,
> +                                  CLK_DIVIDER_ROUND_CLOSEST, div_hw_data->width);
> +}
> +
> +static bool rzg3s_div_clk_is_rate_valid(const unsigned long invalid_rate, unsigned long rate)
> +{
> +       if (invalid_rate && rate >= invalid_rate)
> +               return false;
> +
> +       return true;
> +}
> +
> +static long rzg3s_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                    unsigned long *parent_rate)
> +{
> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
> +       long round_rate;
> +
> +       round_rate = divider_round_rate(hw, rate, parent_rate, div_hw_data->dtable,
> +                                       div_hw_data->width, CLK_DIVIDER_ROUND_CLOSEST);
> +
> +       if (!rzg3s_div_clk_is_rate_valid(div_hw_data->invalid_rate, round_rate))
> +               return -EINVAL;

Shouldn't this return the closest rate that is actually supported instead?

> +
> +       return round_rate;
> +}

But please implement .determine_rate() instead of .round_rate() in
new drivers.

> +
> +static int rzg3s_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
> +                                 unsigned long parent_rate)
> +{
> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
> +       u32 off = GET_REG_OFFSET(clk_hw_data->conf);
> +       u32 shift = GET_SHIFT(clk_hw_data->conf);
> +       unsigned long flags;
> +       u32 bitmask, val;
> +       int ret;
> +
> +       /*
> +        * Some dividers cannot support some rates:
> +        * - SD div cannot support 800 MHz when parent is @800MHz and div = 1
> +        * - OCTA div cannot support 400 MHz when parent is @400MHz and div = 1
> +        * Check these scenarios.
> +        */
> +       if (!rzg3s_div_clk_is_rate_valid(div_hw_data->invalid_rate, rate))
> +               return -EINVAL;

Can this actually happen? Wouldn't the notifier have prevented us from
getting here?

> +
> +       val = divider_get_val(rate, parent_rate, div_hw_data->dtable, div_hw_data->width,
> +                             CLK_DIVIDER_ROUND_CLOSEST);
> +
> +       bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16;

Is bitmask the (single) write-enable bit?

If yes, that should be BIT(16 + shift), and the variable should be
renamed to reflect that.

I guess there should be a general "#define CPG_WEN BIT(16)", then you
can simply use

    writel((CPG_WEN | val) << shift, ...);

> +
> +       spin_lock_irqsave(&priv->rmw_lock, flags);
> +       writel(bitmask | (val << shift), priv->base + off);
> +       /* Wait for the update done. */
> +       ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
> +       spin_unlock_irqrestore(&priv->rmw_lock, flags);
> +
> +       return ret;
> +}
> +
> +static const struct clk_ops rzg3s_div_clk_ops = {
> +       .recalc_rate = rzg3s_div_clk_recalc_rate,
> +       .round_rate = rzg3s_div_clk_round_rate,
> +       .set_rate = rzg3s_div_clk_set_rate,
> +};
> +
> +static struct clk * __init
> +rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks,
> +                          void __iomem *base, struct rzg2l_cpg_priv *priv)
> +{
> +       struct div_hw_data *div_hw_data;
> +       struct clk_init_data init = {};
> +       const struct clk_div_table *clkt;
> +       struct clk_hw *clk_hw;
> +       const struct clk *parent;
> +       const char *parent_name;
> +       u32 max;
> +       int ret;
> +
> +       parent = clks[core->parent & 0xffff];
> +       if (IS_ERR(parent))
> +               return ERR_CAST(parent);
> +
> +       parent_name = __clk_get_name(parent);
> +
> +       div_hw_data = devm_kzalloc(priv->dev, sizeof(*div_hw_data), GFP_KERNEL);
> +       if (!div_hw_data)
> +               return ERR_PTR(-ENOMEM);
> +
> +       init.name = core->name;
> +       init.flags = core->flag;
> +       init.ops = &rzg3s_div_clk_ops;
> +       init.parent_names = &parent_name;
> +       init.num_parents = 1;
> +
> +       /* Get the maximum divider to retrieve div width. */
> +       for (clkt = core->dtable; clkt->div; clkt++) {
> +               if (max < clkt->div)

"max" is used uninitialized

> +                       max = clkt->div;
> +       }
> +
> +       div_hw_data->hw_data.priv = priv;
> +       div_hw_data->hw_data.conf = core->conf;
> +       div_hw_data->hw_data.sconf = core->sconf;
> +       div_hw_data->dtable = core->dtable;
> +       div_hw_data->invalid_rate = core->invalid_rate;
> +       div_hw_data->width = fls(max) - 1;

Isn't that
> +
> +       clk_hw = &div_hw_data->hw_data.hw;
> +       clk_hw->init = &init;
> +
> +       ret = devm_clk_hw_register(priv->dev, clk_hw);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       ret = rzg2l_register_notifier(clk_hw, core, priv);
> +       if (ret) {
> +               dev_err(priv->dev, "Failed to register notifier for %s\n",
> +                       core->name);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return clk_hw->clk;
> +}

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 12:41 p.m. UTC | #12
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add minimal clock and reset support for RZ/G3S SoC to be able to boot
> Linux from SD Card/eMMC. This includes necessary core clocks for booting
> and GIC, SCIF, GPIO, SD0 mod clocks and resets.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - used RZ/G3S specific definition for CPG_CLKDIVSTATUS register
> - removed CLK_PLL3_DIV2_2, CLK_SD0_DIV, CLK_S0_DIV2
> - added space after { and before } in array initializations
> - s/indexes/indices/g
> - s/.osc/OSC and moved it in core output clocks section
> - s/.osc2/OSC2 and moved it in core output clock section
> - s/SD0_DIV4/.sd0_div4

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 12:52 p.m. UTC | #13
Hi Claudiu,

On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> To get address that needs to be read/write for specific port
> functionalities the P(), PM(), PMC(), PFC(), PIN(), IOLH() IEN(), ISEL()
> macros are used. Some of these macros received as argument the hardware
> port identifier, some hardware port offset address (e.g. ISEL() received
> port identifier, IOLH() received port offset address). This makes hard to
> extend the current driver for SoCs were port identifiers are not continuous
> in memory map of pin controller. This is the case for RZ/G3S pin controller
> were ports are mapped as follows:
>
> port offset    port identifier
> -----------    ---------------
> 0x20           P0
> 0x21           P5
> 0x22           P6
> 0x23           P11
> 0x24           P12
> 0x25           P13
> 0x26           P14
> 0x27           P15
> 0x28           P16
> 0x29           P17
> 0x2a           P18
> 0x30           P1
> 0x31           P2
> 0x32           P3
> 0x33           P4
> 0x34           P7
> 0x35           P8
> 0x36           P8
> 0x37           P10
>
> To make this achievable change all the above macros used to get the address
> of a port register for specific port functionality based on port hardware
> address. Shortly, all the above macros will get as argument the port
> offset address listed in the above table.
>
> With this RZG2L_SINGLE_PIN_GET_PORT_OFFSET(), RZG2L_PIN_ID_TO_PORT_OFFSET()
> and RZG2L_GPIO_PORT_GET_INDEX() were replaced by
> RZG2L_PIN_CFG_TO_PORT_OFFSET(), RZG2L_SINGLE_PIN_GET_CFGS() and
> RZG2L_GPIO_PORT_GET_CFGS() were replaced by RZG2L_PIN_CFG_TO_CAPS().
>
> Also rzg2l_pinctrl_set_pfc_mode() don't need port argument anymore.
> Also rzg2l_gpio_direction_input() and rzg2l_gpio_direction_output() don't
> need to translate port and bit locally as this can be done by
> rzg2l_gpio_set_direction().
>
> To use the same naming for port, bit/pin and register offset the
> port_offset variable names in different places was replaced by variable
> named off and there is no need to initialize anymore cfg and bit in
> different code places.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
>
> Changes in v2:
> - mentioned in commit description about the replacement of
>   RZG2L_GPIO_PORT_GET_INDEX() with RZG2L_PIN_CFG_TO_PORT_OFFSET()
> - moved variable declaration inside for()
> - got rid of local variable and used directly RZG2L_PIN_ID_TO_PORT() in
>   debug message from rzg2l_pinctrl_set_mux() function
> - collected tags

Thanks for the update! Sill queue in renesas-pinctrl-for-v6.7.

> --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
> +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
> @@ -202,9 +202,11 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
>                                  unsigned int group_selector)
>  {
>         struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct pinctrl_pin_desc *pin_desc;
> +       unsigned int *psel_val, *pin_data;
>         struct function_desc *func;
> -       unsigned int i, *psel_val;
>         struct group_desc *group;
> +       u32 pin, off;
>         int *pins;
>
>         func = pinmux_generic_get_function(pctldev, func_selector);
> @@ -217,12 +219,17 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
>         psel_val = func->data;
>         pins = group->pins;
>
> -       for (i = 0; i < group->num_pins; i++) {
> -               dev_dbg(pctrl->dev, "port:%u pin: %u PSEL:%u\n",
> -                       RZG2L_PIN_ID_TO_PORT(pins[i]), RZG2L_PIN_ID_TO_PIN(pins[i]),
> -                       psel_val[i]);
> -               rzg2l_pinctrl_set_pfc_mode(pctrl, RZG2L_PIN_ID_TO_PORT(pins[i]),
> -                                          RZG2L_PIN_ID_TO_PIN(pins[i]), psel_val[i]);
> +       for (unsigned int i = 0; i < group->num_pins; i++) {
> +               pin_desc = &pctrl->desc.pins[pins[i]];
> +               pin_data = pin_desc->drv_data;
> +
> +               pin = RZG2L_PIN_ID_TO_PIN(pins[i]);
> +               off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);

In my comments on v1, I actually meant to combine these assignments
to variables with the variable declarations.  I will handle that while applying.

> +
> +               dev_dbg(pctrl->dev, "port:%u pin: %u off:%x PSEL:%u\n",
> +                       RZG2L_PIN_ID_TO_PORT(pins[i]), pin, off, psel_val[i]);
> +
> +               rzg2l_pinctrl_set_pfc_mode(pctrl, pin, off, psel_val[i]);
>         }
>
>         return 0;

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 12:57 p.m. UTC | #14
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> SD, PWPR power registers have different offsets b/w RZ/G2L and RZ/G3S.
> Commit adds a per SoC configuration data structure that is initialized with
> proper register offset for individual SoCs. The struct rzg2l_hwcfg will be
> further extended in next commits.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - collected tags

Thanks, will queue in renesas-pinctrl-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 12:58 p.m. UTC | #15
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> On RZ/G3S PFC register allow setting 8 functions for individual ports
> (function1 to function8). For function1 register need to be configured
> with 0, for function8 register need to be configured with 7.
> We cannot use zero based addressing when requesting functions from
> different code places as documentation (RZG3S_pinfunction_List_r1.0.xlsx)
> states explicitly that function0 is GPIO.
>
> For this add a new member to struct rzg2l_hwcfg that will keep the
> offset that need to be substracted before applying a value to PFC register.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - in commit description mentioned that function0 is GPIO
> - collected tags

Thanks, will queue in renesas-pinctrl-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:17 p.m. UTC | #16
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> RZ/G3S supports different drive strength values for different power sources
> and pin groups (A, B, C). On each group there could be up to 4 drive
> strength values per power source. Available power sources are 1v8, 2v5,
> 3v3. Drive strength values are fine tuned than what was previously
> available on the driver thus the necessity of having micro-amp support.
> As drive strength and power source values are linked together the
> hardware setup for these was moved at the end of
> rzg2l_pinctrl_pinconf_set() to ensure proper validation of the new
> values.
>
> The drive strength values are expected to be initialized though SoC
> specific hardware configuration data structure.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - s/strenght/strength, s/togheter/together in commit description
> - got rid of RZG2L_INVALID_IOLH_VAL macro and consider zero as invalid
>   value for entries in struct rzg2l_hwcfg::iolh_group[abc]_ua[] arrays
> - removed spinlock in rzg2l_[sg]et_power_source()
> - introduced caps_to_pwr_reg() and simplified the code in
>   rzg2l_[sg]et_power_source()
> - changed return type of rzg2l_iolh_ua_to_val() to int and return
>   -EINVAL on failure cases
> - s/rzg2l_ds_supported/rzg2l_ds_is_supported
> - inverted the logic in rzg2l_pinctrl_pinconf_set() when applying drive
>   strength and power source to hardware registers and thus simplified the
>   code
> - used devm_kcalloc() instead of devm_kzalloc()
> - adderessed the rest of the review comments

Thanks, will queue in renesas-pinctrl-for-v6.7, with Paul's comment
addresses.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:18 p.m. UTC | #17
On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Move drive strength and output impedance values to SoC specific
> configuration data structure (struct rzg2l_hwcfg). This allows extending
> the drive strength support for RZ/G3S. Along with this the DS values
> were converted to uA for simple integration with RZ/G3S support.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - s/indexes/indices in code documentation
> - s/micro amps/uA in code documentation
> - added RZG2L_IOLH_MAX_DS_ENTRIES for "+ 4" statements in code
> - changed struct rzg2l_hwcfg::iolh_groupb_oi[] size to 4 to avoid
>   oversize it in next commits when RZG2L_IOLH_IDX_MAX will be increased
>   and thus avoiding issues when executing
>   "if (index == ARRAY_SIZE(hwcfg->iolh_groupb_oi))" in
>   rzg2l_pinctrl_pinconf_set()
> - collected tags

Thanks, will queue in renesas-pinctrl-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:24 p.m. UTC | #18
On Fri, Sep 29, 2023 at 7:40 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add basic support for RZ/G3S to be able to boot from SD card, have a
> running console port and use GPIOs. RZ/G3S has 82 general-purpose IO
> ports. Support for the remaining pin functions (e.g. Ethernet, XSPI)
> will be added along with controller specific support.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - dropped [RZG2L_IOLH_IDX_2V5 ... RZG2L_IOLH_IDX_3V3 - 1] =
>   RZG2L_INVALID_IOLH_VAL initializations from v1 as these are not needed
>   anymore with the new code adjustements
> - added BUILD_BUG_ON() for r9a08g045_gpio_configs[] in
>   rzg2l_pinctrl_probe()

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-pinctrl-for-v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:29 p.m. UTC | #19
On Fri, Sep 29, 2023 at 7:40 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add initial DTSI for RZ/G3S SoC. Files in commit has the following
> meaning:
> r9a08g045.dtsi          RZ/G3S family SoC common parts
> r9a08g045s33.dtsi       RZ/G3S R0A08G045S33 SoC specific parts
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - collected tags

Thanks, will queue in renesas-devel for v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:30 p.m. UTC | #20
On Fri, Sep 29, 2023 at 7:40 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add initial support for RZ/G3S SMARC SoM. The following devices available
> on SoM were added to this initial device tree:
>
> - RZ/G3S SoC: Renesas R9A08G045S33GBG
> - Clock Generator (only 24MHz output): Renesas 5L35023B
> - 1GiB LPDDR4 SDRAM: Micron MT53D512M16D1DS-046
> - 64GB eMMC Flash (though SD ch0): Micron MTFC64GBCAQTC
>
> SD channel 0 of RZ/G3S is connected to an uSD card interface
> and an eMMC. The selection b/w them is done though a hardware switch.
> The DT will select b/w uSD and eMMC though SW_SD0_DEV_SEL build flag.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - s/Carrier-II SoM/SoM in patch title
> - listed in commit description only devices addressed by this initial dtsi
> - s/8G LPDDR4/1GiB LPDDR4 in commit description
> - removed sd0-pwr-en-hog node and use specific GPIO in vcc_sdhi0 regulator
> - added SoM compatible:
>   compatible = "renesas,rzg3s-smarcm", "renesas,r9a08g045s33", "renesas,r9a08g045";

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:31 p.m. UTC | #21
On Fri, Sep 29, 2023 at 7:40 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add initial device tree for RZ SMARC Carrier-II. At the moment it
> contains only serial interface.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - inversed the pin naming

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:33 p.m. UTC | #22
On Fri, Sep 29, 2023 at 7:40 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Add initial device tree for RZ/G3S SMARC EVK board.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - modified compatible
> - @Geert: I haven't added you Rb tag as I've added
>   "renesas,rzg3s-smarcm" to the compatible list

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v6.7.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 4, 2023, 1:34 p.m. UTC | #23
On Fri, Sep 29, 2023 at 7:40 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Enable config flag for Renesas RZ/G3S (R9A08G045) SoC.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> Changes in v2:
> - collected tags

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v6.7.

Gr{oetje,eeting}s,

                        Geert
Claudiu Oct. 5, 2023, 4:24 a.m. UTC | #24
Hi, Geert,

On 04.10.2023 14:30, Geert Uytterhoeven wrote:
> Hi Claudiu,
> 
> On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> Refactor SD MUX driver to be able to reuse the same code on RZ/G3S.
>> RZ/G2{L, UL} has a limitation with regards to switching the clock source
>> for SD MUX (MUX clock source has to be switched to 266MHz before switching
>> b/w 533MHz and 400MHz). This limitation has been introduced as a clock
>> notifier that is registered on platform based initialization data thus the
>> SD MUX code could be reused on RZ/G3S.
>>
>> As both RZ/G2{L, UL} and RZ/G3S has specific bits in specific registers
>> to check if the clock switching has been done, this configuration (register
>> offset, register bits and bits width) is now passed though
>> struct cpg_core_clk::sconf (status configuration) from platform specific
>> initialization code.
>>
>> Along with struct cpg_core_clk::sconf the mux table indices are also
>> passed from platform specific initialization code.
>>
>> Also, mux flags are now passed to DEF_SD_MUX() as they will be later
>> used by RZ/G3S.
>>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
>> Changes in v2:
>> - s/indexes/indices in commit description
>> - mentioned in commit description that mux flags can now be passed to
>>   driver though DEF_SD_MUX() macro
>> - removed SoC specific names from macros' names
>> - added spaces after { and before } when initializing arrays
>> - preserved the order of .[gs]set_parent() API definitions for simpler
>>   diff b/w versions
>> - removed SD_MUX_NOTIF macro
> 
> Thanks for the update!
> 
>> --- a/drivers/clk/renesas/rzg2l-cpg.c
>> +++ b/drivers/clk/renesas/rzg2l-cpg.c
> 
>> @@ -142,6 +146,77 @@ static void rzg2l_cpg_del_clk_provider(void *data)
>>         of_clk_del_provider(data);
>>  }
>>
>> +/* Must be called in atomic context. */
>> +static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf)
>> +{
>> +       u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf);
>> +       u32 off = GET_REG_OFFSET(conf);
>> +       u32 val;
>> +
>> +       return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200);
>> +}
>> +
>> +int rzg2l_cpg_sd_mux_clk_notifier(struct notifier_block *nb, unsigned long event,
>> +                                 void *data)
>> +{
>> +       struct clk_notifier_data *cnd = data;
>> +       struct clk_hw *hw = __clk_get_hw(cnd->clk);
>> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
>> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
>> +       u32 off = GET_REG_OFFSET(clk_hw_data->conf);
>> +       u32 shift = GET_SHIFT(clk_hw_data->conf);
>> +       const u32 clk_src_266 = 3;
>> +       unsigned long flags;
>> +       u32 bitmask;
>> +       int ret;
>> +
>> +       if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266))
>> +               return 0;
> 
> include/linux/clk.h:
> 
>  * PRE_RATE_CHANGE - called immediately before the clk rate is changed,
>  *     to indicate that the rate change will proceed.  Drivers must
>  *     immediately terminate any operations that will be affected by the
>  *     rate change.  Callbacks may either return NOTIFY_DONE, NOTIFY_OK,
>  *     NOTIFY_STOP or NOTIFY_BAD.

Indeed I missed these.

> 
>> +
>> +       spin_lock_irqsave(&priv->rmw_lock, flags);
>> +
>> +       /*
>> +        * As per the HW manual, we should not directly switch from 533 MHz to
>> +        * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz)
>> +        * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first,
>> +        * and then switch to the target setting (2’b01 (533 MHz) or 2’b10
>> +        * (400 MHz)).
>> +        * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock
>> +        * switching register is prohibited.
>> +        * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and
>> +        * the index to value mapping is done by adding 1 to the index.
>> +        */
>> +       bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16;
>> +       writel(bitmask | (clk_src_266 << shift), priv->base + off);
>> +
>> +       /* Wait for the update done. */
>> +       ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
>> +
>> +       spin_unlock_irqrestore(&priv->rmw_lock, flags);
>> +
>> +       if (ret)
>> +               dev_err(priv->dev, "failed to switch to safe clk source\n");
>> +
>> +       return ret;
> 
> Likewise.
> 
>> +}
> 
>>
>>  static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = {
>>         .determine_rate = __clk_mux_determine_rate_closest,
>> -       .set_parent     = rzg2l_cpg_sd_clk_mux_set_parent,
>> -       .get_parent     = rzg2l_cpg_sd_clk_mux_get_parent,
>> +       .set_parent     = rzg2l_cpg_sd_mux_clk_set_parent,
>> +       .get_parent     = rzg2l_cpg_sd_mux_clk_get_parent,
> 
> Please keep the old names, for consistency with
> __clk_mux_determine_rate_closest() and drivers/clk/clk-mux.c, and to
> reduce the diff.
> 
> Any existing inconsistent use of "clk_mux" vs. "mux_clk" can be resolved
> later with a separate patch, if anyone cares.

ok

> 
>> --- a/drivers/clk/renesas/rzg2l-cpg.h
>> +++ b/drivers/clk/renesas/rzg2l-cpg.h
> 
>> @@ -272,4 +276,6 @@ extern const struct rzg2l_cpg_info r9a07g044_cpg_info;
>>  extern const struct rzg2l_cpg_info r9a07g054_cpg_info;
>>  extern const struct rzg2l_cpg_info r9a09g011_cpg_info;
>>
>> +int rzg2l_cpg_sd_mux_clk_notifier(struct notifier_block *nb, unsigned long event, void *data);
> 
> rzg2l_cpg_sd_clk_mux_notifier()?

ok

> 
>> +
>>  #endif
> 
> The rest LGTM.
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> 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
Claudiu Oct. 5, 2023, 5:04 a.m. UTC | #25
Hi, Geert,

On 04.10.2023 15:30, Geert Uytterhoeven wrote:
> Hi Claudiu,
> 
> On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> Add a divider clock driver for RZ/G3S. This will be used in RZ/G3S
>> by SDHI, SPI, OCTA, I, I2, I3, P0, P1, P2, P3 core clocks.
>> The divider has some limitation for SDHI and OCTA clocks:
>> - SD div cannot be 1 if parent rate is 800MHz
>> - OCTA div cannot be 1 if parent rate is 400MHz
>> For these clocks a notifier could be registered from platform specific
>> clock driver and proper actions are taken before clock rate is changed,
>> if needed.
>>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
>> Changes in v2:
>> - removed DIV_NOTIF macro
> 
> Thanks for the update!
> 
>> --- a/drivers/clk/renesas/rzg2l-cpg.c
>> +++ b/drivers/clk/renesas/rzg2l-cpg.c
>> @@ -91,6 +91,22 @@ struct sd_mux_hw_data {
>>
>>  #define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data)
>>
>> +/**
>> + * struct div_hw_data - divider clock hardware data
>> + * @hw_data: clock hw data
>> + * @dtable: pointer to divider table
>> + * @invalid_rate: invalid rate for divider
>> + * @width: divider width
>> + */
>> +struct div_hw_data {
>> +       struct clk_hw_data hw_data;
>> +       const struct clk_div_table *dtable;
>> +       unsigned long invalid_rate;
>> +       u32 width;
>> +};
>> +
>> +#define to_div_hw_data(_hw)    container_of(_hw, struct div_hw_data, hw_data)
>> +
>>  struct rzg2l_pll5_param {
>>         u32 pl5_fracin;
>>         u8 pl5_refdiv;
>> @@ -200,6 +216,54 @@ int rzg2l_cpg_sd_mux_clk_notifier(struct notifier_block *nb, unsigned long event
>>         return ret;
>>  }
>>
>> +int rzg3s_cpg_div_clk_notifier(struct notifier_block *nb, unsigned long event,
>> +                              void *data)
>> +{
>> +       struct clk_notifier_data *cnd = data;
>> +       struct clk_hw *hw = __clk_get_hw(cnd->clk);
>> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
>> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
>> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
>> +       u32 off = GET_REG_OFFSET(clk_hw_data->conf);
>> +       u32 shift = GET_SHIFT(clk_hw_data->conf);
>> +       u32 bitmask = GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
>> +       unsigned long flags;
>> +       int ret = 0;
>> +       u32 val;
>> +
>> +       if (event != PRE_RATE_CHANGE || !div_hw_data->invalid_rate ||
>> +           div_hw_data->invalid_rate % cnd->new_rate)
>> +               return 0;
> 
> NOTIFY_DONE for event != PRE_RATE_CHANGE
> NOTIFY_OK for the other cases

Sure!

> 
>> +
>> +       spin_lock_irqsave(&priv->rmw_lock, flags);
>> +
>> +       val = readl(priv->base + off);
>> +       val >>= shift;
>> +       val &= bitmask;
>> +
>> +       /*
>> +        * There are different constraints for the user of this notifiers as follows:
>> +        * 1/ SD div cannot be 1 (val == 0) if parent rate is 800MHz
>> +        * 2/ OCTA div cannot be 1 (val == 0) if parent rate is 400MHz
>> +        * As SD can have only one parent having 800MHz and OCTA div can have
>> +        * only one parent having 400MHz we took into account the parent rate
>> +        * at the beginning of function (by checking invalid_rate % new_rate).
>> +        * Now it is time to check the hardware divider and update it accordingly.
>> +        */
>> +       if (!val) {
>> +               writel(((bitmask << shift) << 16) | BIT(shift), priv->base + off);
> 
> Haven't you exchanged the (single) write-enable bit and the (multi-bit)
> division ratio setting?  According to the docs, the write-enable bit
> is at 16 + shift, while the division ratio is at shift.

Indeed, I messed this up. Though, I've tested quite some use cases and they
all worked... I'll review this anyway, thanks for pointing it up.

> 
> Also, using bitmask as the division ratio means the maximum value
> that fits in the bitfield, which would be a prohibited setting in case
> of DIV_OCTA.
> 
> Now, looking at rzg3s_div_clk_set_rate() below, perhaps you just wanted
> to set the ratio to value to 1, but used the wrong size for bitmask?

Yes, the idea was to set a safe divider.

> 
>> +               /* Wait for the update done. */
>> +               ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
>> +       }
>> +
>> +       spin_unlock_irqrestore(&priv->rmw_lock, flags);
>> +
>> +       if (ret)
>> +               dev_err(priv->dev, "Failed to downgrade the div\n");
> 
> and return NOTIFY_BAD

Sure!

> 
>> +
>> +       return ret;
> 
> NOTIFY_OK

Sure!

> 
>> +}
>> +
>>  static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core,
>>                                    struct rzg2l_cpg_priv *priv)
>>  {
>> @@ -217,6 +281,146 @@ static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk
>>         return clk_notifier_register(hw->clk, nb);
>>  }
>>
>> +static unsigned long rzg3s_div_clk_recalc_rate(struct clk_hw *hw,
>> +                                              unsigned long parent_rate)
>> +{
>> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
>> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
>> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
>> +       u32 val;
>> +
>> +       val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf));
>> +       val >>= GET_SHIFT(clk_hw_data->conf);
>> +       val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
>> +
>> +       return divider_recalc_rate(hw, parent_rate, val, div_hw_data->dtable,
>> +                                  CLK_DIVIDER_ROUND_CLOSEST, div_hw_data->width);
>> +}
>> +
>> +static bool rzg3s_div_clk_is_rate_valid(const unsigned long invalid_rate, unsigned long rate)
>> +{
>> +       if (invalid_rate && rate >= invalid_rate)
>> +               return false;
>> +
>> +       return true;
>> +}
>> +
>> +static long rzg3s_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
>> +                                    unsigned long *parent_rate)
>> +{
>> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
>> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
>> +       long round_rate;
>> +
>> +       round_rate = divider_round_rate(hw, rate, parent_rate, div_hw_data->dtable,
>> +                                       div_hw_data->width, CLK_DIVIDER_ROUND_CLOSEST);
>> +
>> +       if (!rzg3s_div_clk_is_rate_valid(div_hw_data->invalid_rate, round_rate))
>> +               return -EINVAL;
> 
> Shouldn't this return the closest rate that is actually supported instead?

The divider_round_rate() already choose it as the closest rate that it is
actually not supported, thus I chose to just return -EINVAL. I chose it
this way to use divider_round_rate(). Don't know if there is way around
this using divider_round_rate() I'll have a look.

> 
>> +
>> +       return round_rate;
>> +}
> 
> But please implement .determine_rate() instead of .round_rate() in
> new drivers.

Indeed, I missed this one.

> 
>> +
>> +static int rzg3s_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
>> +                                 unsigned long parent_rate)
>> +{
>> +       struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
>> +       struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
>> +       struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
>> +       u32 off = GET_REG_OFFSET(clk_hw_data->conf);
>> +       u32 shift = GET_SHIFT(clk_hw_data->conf);
>> +       unsigned long flags;
>> +       u32 bitmask, val;
>> +       int ret;
>> +
>> +       /*
>> +        * Some dividers cannot support some rates:
>> +        * - SD div cannot support 800 MHz when parent is @800MHz and div = 1
>> +        * - OCTA div cannot support 400 MHz when parent is @400MHz and div = 1
>> +        * Check these scenarios.
>> +        */
>> +       if (!rzg3s_div_clk_is_rate_valid(div_hw_data->invalid_rate, rate))
>> +               return -EINVAL;
> 
> Can this actually happen? Wouldn't the notifier have prevented us from
> getting here?

I remember I added it here as a result of testing. I'll double check it.

> 
>> +
>> +       val = divider_get_val(rate, parent_rate, div_hw_data->dtable, div_hw_data->width,
>> +                             CLK_DIVIDER_ROUND_CLOSEST);
>> +
>> +       bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16;
> 
> Is bitmask the (single) write-enable bit?
> 
> If yes, that should be BIT(16 + shift), and the variable should be
> renamed to reflect that.
> 
> I guess there should be a general "#define CPG_WEN BIT(16)", then you
> can simply use
> 
>     writel((CPG_WEN | val) << shift, ...);

OK.

> 
>> +
>> +       spin_lock_irqsave(&priv->rmw_lock, flags);
>> +       writel(bitmask | (val << shift), priv->base + off);
>> +       /* Wait for the update done. */
>> +       ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
>> +       spin_unlock_irqrestore(&priv->rmw_lock, flags);
>> +
>> +       return ret;
>> +}
>> +
>> +static const struct clk_ops rzg3s_div_clk_ops = {
>> +       .recalc_rate = rzg3s_div_clk_recalc_rate,
>> +       .round_rate = rzg3s_div_clk_round_rate,
>> +       .set_rate = rzg3s_div_clk_set_rate,
>> +};
>> +
>> +static struct clk * __init
>> +rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks,
>> +                          void __iomem *base, struct rzg2l_cpg_priv *priv)
>> +{
>> +       struct div_hw_data *div_hw_data;
>> +       struct clk_init_data init = {};
>> +       const struct clk_div_table *clkt;
>> +       struct clk_hw *clk_hw;
>> +       const struct clk *parent;
>> +       const char *parent_name;
>> +       u32 max;
>> +       int ret;
>> +
>> +       parent = clks[core->parent & 0xffff];
>> +       if (IS_ERR(parent))
>> +               return ERR_CAST(parent);
>> +
>> +       parent_name = __clk_get_name(parent);
>> +
>> +       div_hw_data = devm_kzalloc(priv->dev, sizeof(*div_hw_data), GFP_KERNEL);
>> +       if (!div_hw_data)
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       init.name = core->name;
>> +       init.flags = core->flag;
>> +       init.ops = &rzg3s_div_clk_ops;
>> +       init.parent_names = &parent_name;
>> +       init.num_parents = 1;
>> +
>> +       /* Get the maximum divider to retrieve div width. */
>> +       for (clkt = core->dtable; clkt->div; clkt++) {
>> +               if (max < clkt->div)
> 
> "max" is used uninitialized

Yes, you're right.

Thank you for your review,
Claudiu Beznea

> 
>> +                       max = clkt->div;
>> +       }
>> +
>> +       div_hw_data->hw_data.priv = priv;
>> +       div_hw_data->hw_data.conf = core->conf;
>> +       div_hw_data->hw_data.sconf = core->sconf;
>> +       div_hw_data->dtable = core->dtable;
>> +       div_hw_data->invalid_rate = core->invalid_rate;
>> +       div_hw_data->width = fls(max) - 1;
> 
> Isn't that
>> +
>> +       clk_hw = &div_hw_data->hw_data.hw;
>> +       clk_hw->init = &init;
>> +
>> +       ret = devm_clk_hw_register(priv->dev, clk_hw);
>> +       if (ret)
>> +               return ERR_PTR(ret);
>> +
>> +       ret = rzg2l_register_notifier(clk_hw, core, priv);
>> +       if (ret) {
>> +               dev_err(priv->dev, "Failed to register notifier for %s\n",
>> +                       core->name);
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       return clk_hw->clk;
>> +}
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
>
Claudiu Oct. 5, 2023, 5:05 a.m. UTC | #26
On 04.10.2023 16:17, Geert Uytterhoeven wrote:
> On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> RZ/G3S supports different drive strength values for different power sources
>> and pin groups (A, B, C). On each group there could be up to 4 drive
>> strength values per power source. Available power sources are 1v8, 2v5,
>> 3v3. Drive strength values are fine tuned than what was previously
>> available on the driver thus the necessity of having micro-amp support.
>> As drive strength and power source values are linked together the
>> hardware setup for these was moved at the end of
>> rzg2l_pinctrl_pinconf_set() to ensure proper validation of the new
>> values.
>>
>> The drive strength values are expected to be initialized though SoC
>> specific hardware configuration data structure.
>>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
>> Changes in v2:
>> - s/strenght/strength, s/togheter/together in commit description
>> - got rid of RZG2L_INVALID_IOLH_VAL macro and consider zero as invalid
>>   value for entries in struct rzg2l_hwcfg::iolh_group[abc]_ua[] arrays
>> - removed spinlock in rzg2l_[sg]et_power_source()
>> - introduced caps_to_pwr_reg() and simplified the code in
>>   rzg2l_[sg]et_power_source()
>> - changed return type of rzg2l_iolh_ua_to_val() to int and return
>>   -EINVAL on failure cases
>> - s/rzg2l_ds_supported/rzg2l_ds_is_supported
>> - inverted the logic in rzg2l_pinctrl_pinconf_set() when applying drive
>>   strength and power source to hardware registers and thus simplified the
>>   code
>> - used devm_kcalloc() instead of devm_kzalloc()
>> - adderessed the rest of the review comments
> 
> Thanks, will queue in renesas-pinctrl-for-v6.7, with Paul's comment
> addresses.

Thank you Geert and Paul!

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
>
Geert Uytterhoeven Oct. 5, 2023, 10:04 a.m. UTC | #27
On Wed, Oct 4, 2023 at 3:17 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> > From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >
> > RZ/G3S supports different drive strength values for different power sources
> > and pin groups (A, B, C). On each group there could be up to 4 drive
> > strength values per power source. Available power sources are 1v8, 2v5,
> > 3v3. Drive strength values are fine tuned than what was previously
> > available on the driver thus the necessity of having micro-amp support.
> > As drive strength and power source values are linked together the
> > hardware setup for these was moved at the end of
> > rzg2l_pinctrl_pinconf_set() to ensure proper validation of the new
> > values.
> >
> > The drive strength values are expected to be initialized though SoC
> > specific hardware configuration data structure.
> >
> > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > ---
> >
> > Changes in v2:
> > - s/strenght/strength, s/togheter/together in commit description
> > - got rid of RZG2L_INVALID_IOLH_VAL macro and consider zero as invalid
> >   value for entries in struct rzg2l_hwcfg::iolh_group[abc]_ua[] arrays
> > - removed spinlock in rzg2l_[sg]et_power_source()
> > - introduced caps_to_pwr_reg() and simplified the code in
> >   rzg2l_[sg]et_power_source()
> > - changed return type of rzg2l_iolh_ua_to_val() to int and return
> >   -EINVAL on failure cases
> > - s/rzg2l_ds_supported/rzg2l_ds_is_supported
> > - inverted the logic in rzg2l_pinctrl_pinconf_set() when applying drive
> >   strength and power source to hardware registers and thus simplified the
> >   code
> > - used devm_kcalloc() instead of devm_kzalloc()
> > - adderessed the rest of the review comments

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

> Thanks, will queue in renesas-pinctrl-for-v6.7, with Paul's comment
> addresses.

Gr{oetje,eeting}s,

                        Geert
Geert Uytterhoeven Oct. 9, 2023, 11:57 a.m. UTC | #28
Hi Claudiu,

On Wed, Oct 4, 2023 at 2:30 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Fri, Sep 29, 2023 at 7:39 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> > From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >
> > Add a divider clock driver for RZ/G3S. This will be used in RZ/G3S
> > by SDHI, SPI, OCTA, I, I2, I3, P0, P1, P2, P3 core clocks.
> > The divider has some limitation for SDHI and OCTA clocks:
> > - SD div cannot be 1 if parent rate is 800MHz
> > - OCTA div cannot be 1 if parent rate is 400MHz
> > For these clocks a notifier could be registered from platform specific
> > clock driver and proper actions are taken before clock rate is changed,
> > if needed.
> >
> > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > ---
> >
> > Changes in v2:
> > - removed DIV_NOTIF macro

> > --- a/drivers/clk/renesas/rzg2l-cpg.c
> > +++ b/drivers/clk/renesas/rzg2l-cpg.c

> > +static struct clk * __init
> > +rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks,
> > +                          void __iomem *base, struct rzg2l_cpg_priv *priv)
> > +{
> > +       struct div_hw_data *div_hw_data;
> > +       struct clk_init_data init = {};
> > +       const struct clk_div_table *clkt;
> > +       struct clk_hw *clk_hw;
> > +       const struct clk *parent;
> > +       const char *parent_name;
> > +       u32 max;
> > +       int ret;
> > +
> > +       parent = clks[core->parent & 0xffff];
> > +       if (IS_ERR(parent))
> > +               return ERR_CAST(parent);
> > +
> > +       parent_name = __clk_get_name(parent);
> > +
> > +       div_hw_data = devm_kzalloc(priv->dev, sizeof(*div_hw_data), GFP_KERNEL);
> > +       if (!div_hw_data)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       init.name = core->name;
> > +       init.flags = core->flag;
> > +       init.ops = &rzg3s_div_clk_ops;
> > +       init.parent_names = &parent_name;
> > +       init.num_parents = 1;
> > +
> > +       /* Get the maximum divider to retrieve div width. */
> > +       for (clkt = core->dtable; clkt->div; clkt++) {
> > +               if (max < clkt->div)
>
> "max" is used uninitialized
>
> > +                       max = clkt->div;
> > +       }
> > +
> > +       div_hw_data->hw_data.priv = priv;
> > +       div_hw_data->hw_data.conf = core->conf;
> > +       div_hw_data->hw_data.sconf = core->sconf;
> > +       div_hw_data->dtable = core->dtable;
> > +       div_hw_data->invalid_rate = core->invalid_rate;
> > +       div_hw_data->width = fls(max) - 1;
>
> Isn't that

My apologies for not finishing my sentence; I wanted to write "Isn't
that identical to __fls(max)?".  But as the latter generates slightly
worse code, it's not worth making that change.

Gr{oetje,eeting}s,

                        Geert