This is a note to let you know that I've just added the patch titled clk: renesas: rzg2l: Check reset monitor registers to the 6.7-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: clk-renesas-rzg2l-check-reset-monitor-registers.patch and it can be found in the queue-6.7 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. commit 8bc94d9d151e0ddf2ea30f7447ae15d4c4021c26 Author: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> Date: Thu Dec 7 09:06:50 2023 +0200 clk: renesas: rzg2l: Check reset monitor registers [ Upstream commit da235d2fac212d0add570e755feb1167a830bc99 ] The hardware manual of both RZ/G2L and RZ/G3S specifies that the reset monitor registers need to be interrogated when the reset signals are toggled (chapters "Procedures for Supplying and Stopping Reset Signals" and "Procedure for Activating Modules"). Without this, there is a chance that different modules (e.g. Ethernet) are not ready after their reset signal is toggled, leading to failures (on probe or resume from deep sleep states). The same indications are available for RZ/V2M for TYPE-B reset controls. Fixes: ef3c613ccd68 ("clk: renesas: Add CPG core wrapper for RZ/G2L SoC") Fixes: 8090bea32484 ("clk: renesas: rzg2l: Add support for RZ/V2M reset monitor reg") Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> Reviewed-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx> Link: https://lore.kernel.org/r/20231207070700.4156557-2-claudiu.beznea.uj@xxxxxxxxxxxxxx Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 3189c3167ba8..3d2daa4ba2a4 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1416,12 +1416,27 @@ static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; unsigned int reg = info->resets[id].off; - u32 value = BIT(info->resets[id].bit) << 16; + u32 mask = BIT(info->resets[id].bit); + s8 monbit = info->resets[id].monbit; + u32 value = mask << 16; dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); writel(value, priv->base + CLK_RST_R(reg)); - return 0; + + if (info->has_clk_mon_regs) { + reg = CLK_MRST_R(reg); + } else if (monbit >= 0) { + reg = CPG_RST_MON; + mask = BIT(monbit); + } else { + /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ + udelay(35); + return 0; + } + + return readl_poll_timeout_atomic(priv->base + reg, value, + value & mask, 10, 200); } static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, @@ -1430,14 +1445,28 @@ static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; unsigned int reg = info->resets[id].off; - u32 dis = BIT(info->resets[id].bit); - u32 value = (dis << 16) | dis; + u32 mask = BIT(info->resets[id].bit); + s8 monbit = info->resets[id].monbit; + u32 value = (mask << 16) | mask; dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); writel(value, priv->base + CLK_RST_R(reg)); - return 0; + + if (info->has_clk_mon_regs) { + reg = CLK_MRST_R(reg); + } else if (monbit >= 0) { + reg = CPG_RST_MON; + mask = BIT(monbit); + } else { + /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ + udelay(35); + return 0; + } + + return readl_poll_timeout_atomic(priv->base + reg, value, + !(value & mask), 10, 200); } static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, @@ -1449,9 +1478,6 @@ static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, if (ret) return ret; - /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ - udelay(35); - return rzg2l_cpg_deassert(rcdev, id); } @@ -1460,18 +1486,21 @@ static int rzg2l_cpg_status(struct reset_controller_dev *rcdev, { struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; - unsigned int reg = info->resets[id].off; - u32 bitmask = BIT(info->resets[id].bit); s8 monbit = info->resets[id].monbit; + unsigned int reg; + u32 bitmask; if (info->has_clk_mon_regs) { - return !!(readl(priv->base + CLK_MRST_R(reg)) & bitmask); + reg = CLK_MRST_R(info->resets[id].off); + bitmask = BIT(info->resets[id].bit); } else if (monbit >= 0) { - u32 monbitmask = BIT(monbit); - - return !!(readl(priv->base + CPG_RST_MON) & monbitmask); + reg = CPG_RST_MON; + bitmask = BIT(monbit); + } else { + return -ENOTSUPP; } - return -ENOTSUPP; + + return !!(readl(priv->base + reg) & bitmask); } static const struct reset_control_ops rzg2l_cpg_reset_ops = {