diff options
Diffstat (limited to 'drivers/clk/renesas/renesas-cpg-mssr.c')
-rw-r--r-- | drivers/clk/renesas/renesas-cpg-mssr.c | 193 |
1 files changed, 141 insertions, 52 deletions
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 71431970d6e6..5ff6ee1f7d4b 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -81,6 +81,37 @@ static const u16 mstpcr_for_gen4[] = { }; /* + * Module Stop Control Register (RZ/T2H) + * RZ/T2H has 2 registers blocks, + * Bit 12 is used to differentiate them + */ + +#define RZT2H_MSTPCR_BLOCK_SHIFT 12 +#define RZT2H_MSTPCR_OFFSET_MASK GENMASK(11, 0) +#define RZT2H_MSTPCR(block, offset) (((block) << RZT2H_MSTPCR_BLOCK_SHIFT) | \ + ((offset) & RZT2H_MSTPCR_OFFSET_MASK)) + +#define RZT2H_MSTPCR_BLOCK(x) ((x) >> RZT2H_MSTPCR_BLOCK_SHIFT) +#define RZT2H_MSTPCR_OFFSET(x) ((x) & RZT2H_MSTPCR_OFFSET_MASK) + +static const u16 mstpcr_for_rzt2h[] = { + RZT2H_MSTPCR(0, 0x300), /* MSTPCRA */ + RZT2H_MSTPCR(0, 0x304), /* MSTPCRB */ + RZT2H_MSTPCR(0, 0x308), /* MSTPCRC */ + RZT2H_MSTPCR(0, 0x30c), /* MSTPCRD */ + RZT2H_MSTPCR(0, 0x310), /* MSTPCRE */ + 0, + RZT2H_MSTPCR(1, 0x318), /* MSTPCRG */ + 0, + RZT2H_MSTPCR(1, 0x320), /* MSTPCRI */ + RZT2H_MSTPCR(0, 0x324), /* MSTPCRJ */ + RZT2H_MSTPCR(0, 0x328), /* MSTPCRK */ + RZT2H_MSTPCR(0, 0x32c), /* MSTPCRL */ + RZT2H_MSTPCR(0, 0x330), /* MSTPCRM */ + RZT2H_MSTPCR(1, 0x334), /* MSTPCRN */ +}; + +/* * Standby Control Register offsets (RZ/A) * Base address is FRQCR register */ @@ -126,16 +157,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 @@ -147,20 +176,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; @@ -192,6 +219,26 @@ struct mstp_clock { #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) +static u32 cpg_rzt2h_mstp_read(struct clk_hw *hw, u16 offset) +{ + struct mstp_clock *clock = to_mstp_clock(hw); + struct cpg_mssr_priv *priv = clock->priv; + void __iomem *base = + RZT2H_MSTPCR_BLOCK(offset) ? priv->pub.base1 : priv->pub.base0; + + return readl(base + RZT2H_MSTPCR_OFFSET(offset)); +} + +static void cpg_rzt2h_mstp_write(struct clk_hw *hw, u16 offset, u32 value) +{ + struct mstp_clock *clock = to_mstp_clock(hw); + struct cpg_mssr_priv *priv = clock->priv; + void __iomem *base = + RZT2H_MSTPCR_BLOCK(offset) ? priv->pub.base1 : priv->pub.base0; + + writel(value, base + RZT2H_MSTPCR_OFFSET(offset)); +} + static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) { struct mstp_clock *clock = to_mstp_clock(hw); @@ -206,38 +253,52 @@ 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 if (priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) { + value = cpg_rzt2h_mstp_read(hw, + priv->control_regs[reg]); + + if (enable) + value &= ~bitmask; + else + value |= bitmask; + + cpg_rzt2h_mstp_write(hw, + priv->control_regs[reg], + value); } 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) + if (!enable || priv->reg_layout == CLK_REG_LAYOUT_RZ_A || + priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) 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; } @@ -256,12 +317,16 @@ 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 if (priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) + value = cpg_rzt2h_mstp_read(hw, + 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)); } @@ -348,7 +413,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; @@ -358,12 +423,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, @@ -379,8 +444,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); @@ -391,7 +455,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: @@ -414,14 +478,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; @@ -623,13 +687,13 @@ 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]); /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ udelay(35); /* 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; } @@ -643,7 +707,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; } @@ -657,7 +721,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; } @@ -669,7 +733,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 = { @@ -872,6 +936,18 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a779h0_cpg_mssr_info, }, #endif +#ifdef CONFIG_CLK_R9A09G077 + { + .compatible = "renesas,r9a09g077-cpg-mssr", + .data = &r9a09g077_cpg_mssr_info, + }, +#endif +#ifdef CONFIG_CLK_R9A09G087 + { + .compatible = "renesas,r9a09g087-cpg-mssr", + .data = &r9a09g077_cpg_mssr_info, + }, +#endif { /* sentinel */ } }; @@ -895,12 +971,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; } @@ -917,7 +993,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++) { @@ -926,29 +1002,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, @@ -1058,20 +1134,28 @@ 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; } + if (info->reg_layout == CLK_REG_LAYOUT_RZ_T2H) { + priv->pub.base1 = of_iomap(np, 1); + if (!priv->pub.base1) { + error = -ENOMEM; + goto out_err; + } + } 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; @@ -1080,6 +1164,8 @@ static int __init cpg_mssr_common_init(struct device *dev, priv->reset_clear_regs = srstclr; } else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) { priv->control_regs = stbcr; + } else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) { + priv->control_regs = mstpcr_for_rzt2h; } else if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_GEN4) { priv->status_regs = mstpsr_for_gen4; priv->control_regs = mstpcr_for_gen4; @@ -1091,7 +1177,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 = cpg_mssr_reserved_init(priv, info); if (error) @@ -1108,8 +1194,10 @@ static int __init cpg_mssr_common_init(struct device *dev, reserve_err: cpg_mssr_reserved_exit(priv); out_err: - if (priv->base) - iounmap(priv->base); + if (priv->pub.base0) + iounmap(priv->pub.base0); + if (priv->pub.base1) + iounmap(priv->pub.base1); kfree(priv); return error; @@ -1174,7 +1262,8 @@ static int __init cpg_mssr_probe(struct platform_device *pdev) goto reserve_exit; /* Reset Controller not supported for Standby Control SoCs */ - if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A || + priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) goto reserve_exit; error = cpg_mssr_reset_controller_register(priv); |