clk: renesas: Pass sub struct of cpg_mssr_priv to cpg_clk_register

[ Upstream commit 3d37ca1482c36975255f29911a529f84f1bc34a9 ]

In a subsequent patch, the registration callback will need more parameters
from cpg_mssr_priv (like another base address with clock controllers
with double register block, and also, notifiers and rmw_lock).
Instead of adding more parameters, move the needed parameters to a public
sub-struct.
Instead moving clks to this structure, which would have implied to add
an allocation (and cleanup) for it, keep the way the allocation is done
and just have a copy of the pointer in the public structure.

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Thierry Bultel <thierry.bultel.yh@bp.renesas.com>
Link: https://lore.kernel.org/20250515141828.43444-5-thierry.bultel.yh@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Stable-dep-of: b91401af6c00 ("clk: renesas: cpg-mssr: Read back reset registers to assure values latched")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Thierry Bultel
2025-05-15 16:18:19 +02:00
committed by Greg Kroah-Hartman
parent 224a0d7c84
commit e8c7304992
10 changed files with 88 additions and 71 deletions

View File

@@ -159,12 +159,13 @@ static void __init r7s9210_update_clk_table(struct clk *extal_clk,
static struct clk * __init rza2_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
struct cpg_mssr_pub *pub)
{
struct clk *parent;
void __iomem *base = pub->base0;
struct clk **clks = pub->clks;
unsigned int mult = 1;
unsigned int div = 1;
struct clk *parent;
parent = clks[core->parent];
if (IS_ERR(parent))

View File

@@ -222,10 +222,11 @@ static int __init r8a77970_cpg_mssr_init(struct device *dev)
static struct clk * __init r8a77970_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
struct cpg_mssr_pub *pub)
{
const struct clk_div_table *table;
void __iomem *base = pub->base0;
struct clk **clks = pub->clks;
const struct clk *parent;
unsigned int shift;
@@ -239,8 +240,7 @@ static struct clk * __init r8a77970_cpg_clk_register(struct device *dev,
shift = 4;
break;
default:
return rcar_gen3_cpg_clk_register(dev, core, info, clks, base,
notifiers);
return rcar_gen3_cpg_clk_register(dev, core, info, pub);
}
parent = clks[core->parent];

View File

@@ -274,10 +274,11 @@ static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
struct clk * __init rcar_gen2_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
struct cpg_mssr_pub *pub)
{
const struct clk_div_table *table = NULL;
void __iomem *base = pub->base0;
struct clk **clks = pub->clks;
const struct clk *parent;
const char *parent_name;
unsigned int mult = 1;

View File

@@ -32,8 +32,7 @@ struct rcar_gen2_cpg_pll_config {
struct clk *rcar_gen2_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers);
struct cpg_mssr_pub *pub);
int rcar_gen2_cpg_init(const struct rcar_gen2_cpg_pll_config *config,
unsigned int pll0_div, u32 mode);

View File

@@ -346,9 +346,11 @@ static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
struct cpg_mssr_pub *pub)
{
struct raw_notifier_head *notifiers = &pub->notifiers;
void __iomem *base = pub->base0;
struct clk **clks = pub->clks;
const struct clk *parent;
unsigned int mult = 1;
unsigned int div = 1;

View File

@@ -81,8 +81,7 @@ struct rcar_gen3_cpg_pll_config {
struct clk *rcar_gen3_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers);
struct cpg_mssr_pub *pub);
int rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config,
unsigned int clk_extalr, u32 mode);

View File

@@ -330,9 +330,11 @@ static const struct clk_div_table cpg_rpcsrc_div_table[] = {
struct clk * __init rcar_gen4_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
struct cpg_mssr_pub *pub)
{
struct raw_notifier_head *notifiers = &pub->notifiers;
void __iomem *base = pub->base0;
struct clk **clks = pub->clks;
const struct clk *parent;
unsigned int mult = 1;
unsigned int div = 1;

View File

@@ -72,8 +72,7 @@ struct rcar_gen4_cpg_pll_config {
struct clk *rcar_gen4_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers);
struct cpg_mssr_pub *pub);
int rcar_gen4_cpg_init(const struct rcar_gen4_cpg_pll_config *config,
unsigned int clk_extalr, u32 mode);

View File

@@ -127,16 +127,14 @@ static const u16 srstclr_for_gen4[] = {
* struct cpg_mssr_priv - Clock Pulse Generator / Module Standby
* and Software Reset Private Data
*
* @pub: Data passed to clock registration callback
* @rcdev: Optional reset controller entity
* @dev: CPG/MSSR device
* @base: CPG/MSSR register block base address
* @reg_layout: CPG/MSSR register layout
* @rmw_lock: protects RMW register accesses
* @np: Device node in DT for this CPG/MSSR module
* @num_core_clks: Number of Core Clocks in clks[]
* @num_mod_clks: Number of Module Clocks in clks[]
* @last_dt_core_clk: ID of the last Core Clock exported to DT
* @notifiers: Notifier chain to save/restore clock state for system resume
* @status_regs: Pointer to status registers array
* @control_regs: Pointer to control registers array
* @reset_regs: Pointer to reset registers array
@@ -146,20 +144,18 @@ static const u16 srstclr_for_gen4[] = {
* @clks: Array containing all Core and Module Clocks
*/
struct cpg_mssr_priv {
struct cpg_mssr_pub pub;
#ifdef CONFIG_RESET_CONTROLLER
struct reset_controller_dev rcdev;
#endif
struct device *dev;
void __iomem *base;
enum clk_reg_layout reg_layout;
spinlock_t rmw_lock;
struct device_node *np;
unsigned int num_core_clks;
unsigned int num_mod_clks;
unsigned int last_dt_core_clk;
struct raw_notifier_head notifiers;
const u16 *status_regs;
const u16 *control_regs;
const u16 *reset_regs;
@@ -202,38 +198,39 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
str_on_off(enable));
spin_lock_irqsave(&priv->rmw_lock, flags);
spin_lock_irqsave(&priv->pub.rmw_lock, flags);
if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
value = readb(priv->base + priv->control_regs[reg]);
value = readb(priv->pub.base0 + priv->control_regs[reg]);
if (enable)
value &= ~bitmask;
else
value |= bitmask;
writeb(value, priv->base + priv->control_regs[reg]);
writeb(value, priv->pub.base0 + priv->control_regs[reg]);
/* dummy read to ensure write has completed */
readb(priv->base + priv->control_regs[reg]);
barrier_data(priv->base + priv->control_regs[reg]);
readb(priv->pub.base0 + priv->control_regs[reg]);
barrier_data(priv->pub.base0 + priv->control_regs[reg]);
} else {
value = readl(priv->base + priv->control_regs[reg]);
value = readl(priv->pub.base0 + priv->control_regs[reg]);
if (enable)
value &= ~bitmask;
else
value |= bitmask;
writel(value, priv->base + priv->control_regs[reg]);
writel(value, priv->pub.base0 + priv->control_regs[reg]);
}
spin_unlock_irqrestore(&priv->rmw_lock, flags);
spin_unlock_irqrestore(&priv->pub.rmw_lock, flags);
if (!enable || priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
return 0;
error = readl_poll_timeout_atomic(priv->base + priv->status_regs[reg],
error = readl_poll_timeout_atomic(priv->pub.base0 + 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);
priv->pub.base0 + priv->control_regs[reg], bit);
return error;
}
@@ -252,12 +249,13 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
{
struct mstp_clock *clock = to_mstp_clock(hw);
struct cpg_mssr_priv *priv = clock->priv;
unsigned int reg = clock->index / 32;
u32 value;
if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
value = readb(priv->base + priv->control_regs[clock->index / 32]);
value = readb(priv->pub.base0 + priv->control_regs[reg]);
else
value = readl(priv->base + priv->status_regs[clock->index / 32]);
value = readl(priv->pub.base0 + priv->status_regs[reg]);
return !(value & BIT(clock->index % 32));
}
@@ -349,7 +347,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
case CLK_TYPE_DIV6P1:
case CLK_TYPE_DIV6_RO:
WARN_DEBUG(core->parent >= priv->num_core_clks);
parent = priv->clks[core->parent];
parent = priv->pub.clks[core->parent];
if (IS_ERR(parent)) {
clk = parent;
goto fail;
@@ -359,12 +357,12 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
if (core->type == CLK_TYPE_DIV6_RO)
/* Multiply with the DIV6 register value */
div *= (readl(priv->base + core->offset) & 0x3f) + 1;
div *= (readl(priv->pub.base0 + core->offset) & 0x3f) + 1;
if (core->type == CLK_TYPE_DIV6P1) {
clk = cpg_div6_register(core->name, 1, &parent_name,
priv->base + core->offset,
&priv->notifiers);
priv->pub.base0 + core->offset,
&priv->pub.notifiers);
} else {
clk = clk_register_fixed_factor(NULL, core->name,
parent_name, 0,
@@ -380,8 +378,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
default:
if (info->cpg_clk_register)
clk = info->cpg_clk_register(dev, core, info,
priv->clks, priv->base,
&priv->notifiers);
&priv->pub);
else
dev_err(dev, "%s has unsupported core clock type %u\n",
core->name, core->type);
@@ -392,7 +389,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
goto fail;
dev_dbg(dev, "Core clock %pC at %lu Hz\n", clk, clk_get_rate(clk));
priv->clks[id] = clk;
priv->pub.clks[id] = clk;
return;
fail:
@@ -415,14 +412,14 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
WARN_DEBUG(id < priv->num_core_clks);
WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
WARN_DEBUG(PTR_ERR(priv->pub.clks[id]) != -ENOENT);
if (!mod->name) {
/* Skip NULLified clock */
return;
}
parent = priv->clks[mod->parent];
parent = priv->pub.clks[mod->parent];
if (IS_ERR(parent)) {
clk = parent;
goto fail;
@@ -611,7 +608,7 @@ static int cpg_mssr_reset(struct reset_controller_dev *rcdev,
dev_dbg(priv->dev, "reset %u%02u\n", reg, bit);
/* Reset module */
writel(bitmask, priv->base + priv->reset_regs[reg]);
writel(bitmask, priv->pub.base0 + priv->reset_regs[reg]);
/*
* On R-Car Gen4, delay after SRCR has been written is 1ms.
@@ -624,7 +621,7 @@ static int cpg_mssr_reset(struct reset_controller_dev *rcdev,
usleep_range(35, 1000);
/* Release module from reset state */
writel(bitmask, priv->base + priv->reset_clear_regs[reg]);
writel(bitmask, priv->pub.base0 + priv->reset_clear_regs[reg]);
return 0;
}
@@ -638,7 +635,7 @@ static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id)
dev_dbg(priv->dev, "assert %u%02u\n", reg, bit);
writel(bitmask, priv->base + priv->reset_regs[reg]);
writel(bitmask, priv->pub.base0 + priv->reset_regs[reg]);
return 0;
}
@@ -652,7 +649,7 @@ static int cpg_mssr_deassert(struct reset_controller_dev *rcdev,
dev_dbg(priv->dev, "deassert %u%02u\n", reg, bit);
writel(bitmask, priv->base + priv->reset_clear_regs[reg]);
writel(bitmask, priv->pub.base0 + priv->reset_clear_regs[reg]);
return 0;
}
@@ -664,7 +661,7 @@ static int cpg_mssr_status(struct reset_controller_dev *rcdev,
unsigned int bit = id % 32;
u32 bitmask = BIT(bit);
return !!(readl(priv->base + priv->reset_regs[reg]) & bitmask);
return !!(readl(priv->pub.base0 + priv->reset_regs[reg]) & bitmask);
}
static const struct reset_control_ops cpg_mssr_reset_ops = {
@@ -885,12 +882,12 @@ static int cpg_mssr_suspend_noirq(struct device *dev)
if (priv->smstpcr_saved[reg].mask)
priv->smstpcr_saved[reg].val =
priv->reg_layout == CLK_REG_LAYOUT_RZ_A ?
readb(priv->base + priv->control_regs[reg]) :
readl(priv->base + priv->control_regs[reg]);
readb(priv->pub.base0 + priv->control_regs[reg]) :
readl(priv->pub.base0 + priv->control_regs[reg]);
}
/* Save core clocks */
raw_notifier_call_chain(&priv->notifiers, PM_EVENT_SUSPEND, NULL);
raw_notifier_call_chain(&priv->pub.notifiers, PM_EVENT_SUSPEND, NULL);
return 0;
}
@@ -907,7 +904,7 @@ static int cpg_mssr_resume_noirq(struct device *dev)
return 0;
/* Restore core clocks */
raw_notifier_call_chain(&priv->notifiers, PM_EVENT_RESUME, NULL);
raw_notifier_call_chain(&priv->pub.notifiers, PM_EVENT_RESUME, NULL);
/* Restore module clocks */
for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
@@ -916,29 +913,29 @@ static int cpg_mssr_resume_noirq(struct device *dev)
continue;
if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
oldval = readb(priv->base + priv->control_regs[reg]);
oldval = readb(priv->pub.base0 + priv->control_regs[reg]);
else
oldval = readl(priv->base + priv->control_regs[reg]);
oldval = readl(priv->pub.base0 + priv->control_regs[reg]);
newval = oldval & ~mask;
newval |= priv->smstpcr_saved[reg].val & mask;
if (newval == oldval)
continue;
if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
writeb(newval, priv->base + priv->control_regs[reg]);
writeb(newval, priv->pub.base0 + priv->control_regs[reg]);
/* dummy read to ensure write has completed */
readb(priv->base + priv->control_regs[reg]);
barrier_data(priv->base + priv->control_regs[reg]);
readb(priv->pub.base0 + priv->control_regs[reg]);
barrier_data(priv->pub.base0 + priv->control_regs[reg]);
continue;
} else
writel(newval, priv->base + priv->control_regs[reg]);
writel(newval, priv->pub.base0 + priv->control_regs[reg]);
/* Wait until enabled clocks are really enabled */
mask &= ~priv->smstpcr_saved[reg].val;
if (!mask)
continue;
error = readl_poll_timeout_atomic(priv->base + priv->status_regs[reg],
error = readl_poll_timeout_atomic(priv->pub.base0 + priv->status_regs[reg],
oldval, !(oldval & mask), 0, 10);
if (error)
dev_warn(dev, "Failed to enable SMSTP%u[0x%x]\n", reg,
@@ -976,12 +973,13 @@ static int __init cpg_mssr_common_init(struct device *dev,
if (!priv)
return -ENOMEM;
priv->pub.clks = priv->clks;
priv->np = np;
priv->dev = dev;
spin_lock_init(&priv->rmw_lock);
spin_lock_init(&priv->pub.rmw_lock);
priv->base = of_iomap(np, 0);
if (!priv->base) {
priv->pub.base0 = of_iomap(np, 0);
if (!priv->pub.base0) {
error = -ENOMEM;
goto out_err;
}
@@ -989,7 +987,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
priv->num_core_clks = info->num_total_core_clks;
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
RAW_INIT_NOTIFIER_HEAD(&priv->notifiers);
RAW_INIT_NOTIFIER_HEAD(&priv->pub.notifiers);
priv->reg_layout = info->reg_layout;
if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) {
priv->status_regs = mstpsr;
@@ -1009,7 +1007,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
}
for (i = 0; i < nclks; i++)
priv->clks[i] = ERR_PTR(-ENOENT);
priv->pub.clks[i] = ERR_PTR(-ENOENT);
error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
if (error)
@@ -1020,8 +1018,8 @@ static int __init cpg_mssr_common_init(struct device *dev,
return 0;
out_err:
if (priv->base)
iounmap(priv->base);
if (priv->pub.base0)
iounmap(priv->pub.base0);
kfree(priv);
return error;

View File

@@ -8,6 +8,8 @@
#ifndef __CLK_RENESAS_CPG_MSSR_H__
#define __CLK_RENESAS_CPG_MSSR_H__
#include <linux/notifier.h>
/*
* Definitions of CPG Core Clocks
*
@@ -29,6 +31,21 @@ struct cpg_core_clk {
unsigned int offset;
};
/**
* struct cpg_mssr_pub - data shared with device-specific clk registration code
*
* @base0: CPG/MSSR register block base0 address
* @notifiers: Notifier chain to save/restore clock state for system resume
* @rmw_lock: protects RMW register accesses
* @clks: pointer to clocks
*/
struct cpg_mssr_pub {
void __iomem *base0;
struct raw_notifier_head notifiers;
spinlock_t rmw_lock;
struct clk **clks;
};
enum clk_types {
/* Generic */
CLK_TYPE_IN, /* External Clock Input */
@@ -153,8 +170,7 @@ struct cpg_mssr_info {
struct clk *(*cpg_clk_register)(struct device *dev,
const struct cpg_core_clk *core,
const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers);
struct cpg_mssr_pub *pub);
};
extern const struct cpg_mssr_info r7s9210_cpg_mssr_info;