aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Boyd <[email protected]>2023-06-09 14:59:14 -0700
committerStephen Boyd <[email protected]>2023-06-09 14:59:14 -0700
commite90f15be2447d95d6b56068ad03c5ec73730103d (patch)
treef35a17cdb584cefe1e5d9615ff9ec67a87bc2d0e
parentf73b836edfef23054c227712bbdb9d4c23e00440 (diff)
parent7df8eea64a417f1db6777cddc1d7eda3634b7175 (diff)
Merge tag 'renesas-clk-for-v6.5-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into clk-renesas
Pull more Renesas clk driver updates from Geert Uytterhoeven: - Convert the Renesas clock drivers to readl_poll_timeout_atomic() * tag 'renesas-clk-for-v6.5-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers: clk: renesas: rzg2l: Convert to readl_poll_timeout_atomic() clk: renesas: mstp: Convert to readl_poll_timeout_atomic() clk: renesas: cpg-mssr: Convert to readl_poll_timeout_atomic() iopoll: Do not use timekeeping in read_poll_timeout_atomic() iopoll: Call cpu_relax() in busy loops
-rw-r--r--drivers/clk/renesas/clk-mstp.c18
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c31
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.c16
-rw-r--r--include/linux/iopoll.h24
4 files changed, 42 insertions, 47 deletions
diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c
index 90804ac06fa5..6280f4dfed71 100644
--- a/drivers/clk/renesas/clk-mstp.c
+++ b/drivers/clk/renesas/clk-mstp.c
@@ -14,6 +14,7 @@
#include <linux/clk/renesas.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_clock.h>
@@ -78,8 +79,8 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
struct mstp_clock_group *group = clock->group;
u32 bitmask = BIT(clock->bit_index);
unsigned long flags;
- unsigned int i;
u32 value;
+ int ret;
spin_lock_irqsave(&group->lock, flags);
@@ -101,19 +102,14 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
if (!enable || !group->mstpsr)
return 0;
- for (i = 1000; i > 0; --i) {
- if (!(cpg_mstp_read(group, group->mstpsr) & bitmask))
- break;
- cpu_relax();
- }
-
- if (!i) {
+ /* group->width_8bit is always false if group->mstpsr is present */
+ ret = readl_poll_timeout_atomic(group->mstpsr, value,
+ !(value & bitmask), 0, 10);
+ if (ret)
pr_err("%s: failed to enable %p[%d]\n", __func__,
group->smstpcr, clock->bit_index);
- return -ETIMEDOUT;
- }
- return 0;
+ return ret;
}
static int cpg_mstp_clock_enable(struct clk_hw *hw)
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index e9c0e341380e..2772499d2016 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -17,6 +17,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_address.h>
@@ -196,8 +197,8 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
struct device *dev = priv->dev;
u32 bitmask = BIT(bit);
unsigned long flags;
- unsigned int i;
u32 value;
+ int error;
dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
enable ? "ON" : "OFF");
@@ -228,19 +229,13 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
if (!enable || priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
return 0;
- for (i = 1000; i > 0; --i) {
- if (!(readl(priv->base + priv->status_regs[reg]) & bitmask))
- break;
- cpu_relax();
- }
-
- if (!i) {
+ error = readl_poll_timeout_atomic(priv->base + priv->status_regs[reg],
+ value, !(value & bitmask), 0, 10);
+ if (error)
dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
priv->base + priv->control_regs[reg], bit);
- return -ETIMEDOUT;
- }
- return 0;
+ return error;
}
static int cpg_mstp_clock_enable(struct clk_hw *hw)
@@ -896,8 +891,9 @@ static int cpg_mssr_suspend_noirq(struct device *dev)
static int cpg_mssr_resume_noirq(struct device *dev)
{
struct cpg_mssr_priv *priv = dev_get_drvdata(dev);
- unsigned int reg, i;
+ unsigned int reg;
u32 mask, oldval, newval;
+ int error;
/* This is the best we can do to check for the presence of PSCI */
if (!psci_ops.cpu_suspend)
@@ -935,14 +931,9 @@ static int cpg_mssr_resume_noirq(struct device *dev)
if (!mask)
continue;
- for (i = 1000; i > 0; --i) {
- oldval = readl(priv->base + priv->status_regs[reg]);
- if (!(oldval & mask))
- break;
- cpu_relax();
- }
-
- if (!i)
+ error = readl_poll_timeout_atomic(priv->base + priv->status_regs[reg],
+ oldval, !(oldval & mask), 0, 10);
+ if (error)
dev_warn(dev, "Failed to enable SMSTP%u[0x%x]\n", reg,
oldval & mask);
}
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
index ca8b921c7762..bc623515ad84 100644
--- a/drivers/clk/renesas/rzg2l-cpg.c
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -903,9 +903,9 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable)
unsigned int reg = clock->off;
struct device *dev = priv->dev;
unsigned long flags;
- unsigned int i;
u32 bitmask = BIT(clock->bit);
u32 value;
+ int error;
if (!clock->off) {
dev_dbg(dev, "%pC does not support ON/OFF\n", hw->clk);
@@ -930,19 +930,13 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable)
if (!priv->info->has_clk_mon_regs)
return 0;
- for (i = 1000; i > 0; --i) {
- if (((readl(priv->base + CLK_MON_R(reg))) & bitmask))
- break;
- cpu_relax();
- }
-
- if (!i) {
+ error = readl_poll_timeout_atomic(priv->base + CLK_MON_R(reg), value,
+ value & bitmask, 0, 10);
+ if (error)
dev_err(dev, "Failed to enable CLK_ON %p\n",
priv->base + CLK_ON_R(reg));
- return -ETIMEDOUT;
- }
- return 0;
+ return error;
}
static int rzg2l_mod_clock_enable(struct clk_hw *hw)
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index 2c8860e406bd..19a7b00baff4 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -53,6 +53,7 @@
} \
if (__sleep_us) \
usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
+ cpu_relax(); \
} \
(cond) ? 0 : -ETIMEDOUT; \
})
@@ -73,6 +74,10 @@
* Returns 0 on success and -ETIMEDOUT upon a timeout. In either
* case, the last read value at @args is stored in @val.
*
+ * This macro does not rely on timekeeping. Hence it is safe to call even when
+ * timekeeping is suspended, at the expense of an underestimation of wall clock
+ * time, which is rather minimal with a non-zero delay_us.
+ *
* When available, you'll probably want to use one of the specialized
* macros defined below rather than this macro directly.
*/
@@ -80,21 +85,30 @@
delay_before_read, args...) \
({ \
u64 __timeout_us = (timeout_us); \
+ s64 __left_ns = __timeout_us * NSEC_PER_USEC; \
unsigned long __delay_us = (delay_us); \
- ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
- if (delay_before_read && __delay_us) \
+ u64 __delay_ns = __delay_us * NSEC_PER_USEC; \
+ if (delay_before_read && __delay_us) { \
udelay(__delay_us); \
+ if (__timeout_us) \
+ __left_ns -= __delay_ns; \
+ } \
for (;;) { \
(val) = op(args); \
if (cond) \
break; \
- if (__timeout_us && \
- ktime_compare(ktime_get(), __timeout) > 0) { \
+ if (__timeout_us && __left_ns < 0) { \
(val) = op(args); \
break; \
} \
- if (__delay_us) \
+ if (__delay_us) { \
udelay(__delay_us); \
+ if (__timeout_us) \
+ __left_ns -= __delay_ns; \
+ } \
+ cpu_relax(); \
+ if (__timeout_us) \
+ __left_ns--; \
} \
(cond) ? 0 : -ETIMEDOUT; \
})