diff options
| -rw-r--r-- | drivers/clk/renesas/clk-vbattb.c | 4 | ||||
| -rw-r--r-- | drivers/clk/renesas/r9a09g056-cpg.c | 10 | ||||
| -rw-r--r-- | drivers/clk/renesas/r9a09g057-cpg.c | 10 | ||||
| -rw-r--r-- | drivers/clk/renesas/r9a09g077-cpg.c | 13 | ||||
| -rw-r--r-- | drivers/clk/renesas/renesas-cpg-mssr.c | 54 | ||||
| -rw-r--r-- | drivers/clk/renesas/rzg2l-cpg.c | 189 | ||||
| -rw-r--r-- | drivers/clk/renesas/rzv2h-cpg.c | 15 | ||||
| -rw-r--r-- | include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h | 1 | ||||
| -rw-r--r-- | include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h | 1 | ||||
| -rw-r--r-- | include/linux/clk/renesas.h | 11 |
10 files changed, 237 insertions, 71 deletions
diff --git a/drivers/clk/renesas/clk-vbattb.c b/drivers/clk/renesas/clk-vbattb.c index ff9d1ead455c..2a961775b1d8 100644 --- a/drivers/clk/renesas/clk-vbattb.c +++ b/drivers/clk/renesas/clk-vbattb.c @@ -69,11 +69,11 @@ static void vbattb_clk_action(void *data) ret = reset_control_assert(rstc); if (ret) - dev_err(dev, "Failed to de-assert reset!"); + dev_err(dev, "Failed to de-assert reset!\n"); ret = pm_runtime_put_sync(dev); if (ret < 0) - dev_err(dev, "Failed to runtime suspend!"); + dev_err(dev, "Failed to runtime suspend!\n"); of_clk_del_provider(dev->of_node); } diff --git a/drivers/clk/renesas/r9a09g056-cpg.c b/drivers/clk/renesas/r9a09g056-cpg.c index d831246ff55d..fead173cae8b 100644 --- a/drivers/clk/renesas/r9a09g056-cpg.c +++ b/drivers/clk/renesas/r9a09g056-cpg.c @@ -46,6 +46,7 @@ enum clk_ids { CLK_PLLCLN_DIV2, CLK_PLLCLN_DIV8, CLK_PLLCLN_DIV16, + CLK_PLLCLN_DIV20, CLK_PLLCLN_DIV64, CLK_PLLCLN_DIV256, CLK_PLLCLN_DIV1024, @@ -183,6 +184,7 @@ static const struct cpg_core_clk r9a09g056_core_clks[] __initconst = { DEF_FIXED(".pllcln_div2", CLK_PLLCLN_DIV2, CLK_PLLCLN, 1, 2), DEF_FIXED(".pllcln_div8", CLK_PLLCLN_DIV8, CLK_PLLCLN, 1, 8), DEF_FIXED(".pllcln_div16", CLK_PLLCLN_DIV16, CLK_PLLCLN, 1, 16), + DEF_FIXED(".pllcln_div20", CLK_PLLCLN_DIV20, CLK_PLLCLN, 1, 20), DEF_FIXED(".pllcln_div64", CLK_PLLCLN_DIV64, CLK_PLLCLN, 1, 64), DEF_FIXED(".pllcln_div256", CLK_PLLCLN_DIV256, CLK_PLLCLN, 1, 256), DEF_FIXED(".pllcln_div1024", CLK_PLLCLN_DIV1024, CLK_PLLCLN, 1, 1024), @@ -431,6 +433,12 @@ static const struct rzv2h_mod_clk r9a09g056_mod_clks[] __initconst = { BUS_MSTOP(1, BIT(7))), DEF_MOD("riic_7_ckm", CLK_PLLCLN_DIV16, 9, 11, 4, 27, BUS_MSTOP(1, BIT(8))), + DEF_MOD("canfd_0_pclk", CLK_PLLCLN_DIV16, 9, 12, 4, 28, + BUS_MSTOP(10, BIT(14))), + DEF_MOD("canfd_0_clk_ram", CLK_PLLCLN_DIV8, 9, 13, 4, 29, + BUS_MSTOP(10, BIT(14))), + DEF_MOD("canfd_0_clkc", CLK_PLLCLN_DIV20, 9, 14, 4, 30, + BUS_MSTOP(10, BIT(14))), DEF_MOD("spi_hclk", CLK_PLLCM33_GEAR, 9, 15, 4, 31, BUS_MSTOP(4, BIT(5))), DEF_MOD("spi_aclk", CLK_PLLCM33_GEAR, 10, 0, 5, 0, @@ -603,6 +611,8 @@ static const struct rzv2h_reset r9a09g056_resets[] __initconst = { DEF_RST(9, 14, 4, 15), /* RIIC_6_MRST */ DEF_RST(9, 15, 4, 16), /* RIIC_7_MRST */ DEF_RST(10, 0, 4, 17), /* RIIC_8_MRST */ + DEF_RST(10, 1, 4, 18), /* CANFD_0_RSTP_N */ + DEF_RST(10, 2, 4, 19), /* CANFD_0_RSTC_N */ DEF_RST(10, 3, 4, 20), /* SPI_HRESETN */ DEF_RST(10, 4, 4, 21), /* SPI_ARESETN */ DEF_RST(10, 7, 4, 24), /* SDHI_0_IXRST */ diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c index 991f9a2ec12e..6943cad318b5 100644 --- a/drivers/clk/renesas/r9a09g057-cpg.c +++ b/drivers/clk/renesas/r9a09g057-cpg.c @@ -46,6 +46,7 @@ enum clk_ids { CLK_PLLCLN_DIV2, CLK_PLLCLN_DIV8, CLK_PLLCLN_DIV16, + CLK_PLLCLN_DIV20, CLK_PLLCLN_DIV64, CLK_PLLCLN_DIV256, CLK_PLLCLN_DIV1024, @@ -185,6 +186,7 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = { DEF_FIXED(".pllcln_div2", CLK_PLLCLN_DIV2, CLK_PLLCLN, 1, 2), DEF_FIXED(".pllcln_div8", CLK_PLLCLN_DIV8, CLK_PLLCLN, 1, 8), DEF_FIXED(".pllcln_div16", CLK_PLLCLN_DIV16, CLK_PLLCLN, 1, 16), + DEF_FIXED(".pllcln_div20", CLK_PLLCLN_DIV20, CLK_PLLCLN, 1, 20), DEF_FIXED(".pllcln_div64", CLK_PLLCLN_DIV64, CLK_PLLCLN, 1, 64), DEF_FIXED(".pllcln_div256", CLK_PLLCLN_DIV256, CLK_PLLCLN, 1, 256), DEF_FIXED(".pllcln_div1024", CLK_PLLCLN_DIV1024, CLK_PLLCLN, 1, 1024), @@ -440,6 +442,12 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { BUS_MSTOP(1, BIT(7))), DEF_MOD("riic_7_ckm", CLK_PLLCLN_DIV16, 9, 11, 4, 27, BUS_MSTOP(1, BIT(8))), + DEF_MOD("canfd_0_pclk", CLK_PLLCLN_DIV16, 9, 12, 4, 28, + BUS_MSTOP(10, BIT(14))), + DEF_MOD("canfd_0_clk_ram", CLK_PLLCLN_DIV8, 9, 13, 4, 29, + BUS_MSTOP(10, BIT(14))), + DEF_MOD("canfd_0_clkc", CLK_PLLCLN_DIV20, 9, 14, 4, 30, + BUS_MSTOP(10, BIT(14))), DEF_MOD("spi_hclk", CLK_PLLCM33_GEAR, 9, 15, 4, 31, BUS_MSTOP(4, BIT(5))), DEF_MOD("spi_aclk", CLK_PLLCM33_GEAR, 10, 0, 5, 0, @@ -634,6 +642,8 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = { DEF_RST(9, 14, 4, 15), /* RIIC_6_MRST */ DEF_RST(9, 15, 4, 16), /* RIIC_7_MRST */ DEF_RST(10, 0, 4, 17), /* RIIC_8_MRST */ + DEF_RST(10, 1, 4, 18), /* CANFD_0_RSTP_N */ + DEF_RST(10, 2, 4, 19), /* CANFD_0_RSTC_N */ DEF_RST(10, 3, 4, 20), /* SPI_HRESETN */ DEF_RST(10, 4, 4, 21), /* SPI_ARESETN */ DEF_RST(10, 7, 4, 24), /* SDHI_0_IXRST */ diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c index dee25cdadf1d..93b15e06a19b 100644 --- a/drivers/clk/renesas/r9a09g077-cpg.c +++ b/drivers/clk/renesas/r9a09g077-cpg.c @@ -47,6 +47,7 @@ #define FSELXSPI1 CONF_PACK(SCKCR, 8, 3) #define DIVSEL_XSPI0 CONF_PACK(SCKCR, 6, 1) #define DIVSEL_XSPI1 CONF_PACK(SCKCR, 14, 1) +#define FSELCANFD CONF_PACK(SCKCR, 20, 1) #define SEL_PLL CONF_PACK(SCKCR, 22, 1) #define DIVCA55C0 CONF_PACK(SCKCR2, 8, 1) @@ -85,7 +86,7 @@ enum rzt2h_clk_types { enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R9A09G077_XSPI_CLK1, + LAST_DT_CORE_CLK = R9A09G077_PCLKCAN, /* External Input Clocks */ CLK_EXTAL, @@ -103,6 +104,9 @@ enum clk_ids { CLK_PLL4D1, CLK_PLL4D1_DIV3, CLK_PLL4D1_DIV4, + CLK_PLL4D3, + CLK_PLL4D3_DIV10, + CLK_PLL4D3_DIV20, CLK_SCI0ASYNC, CLK_SCI1ASYNC, CLK_SCI2ASYNC, @@ -150,6 +154,7 @@ static const char * const sel_clk_pll1[] = { ".loco", ".pll1" }; static const char * const sel_clk_pll2[] = { ".loco", ".pll2" }; static const char * const sel_clk_pll4[] = { ".loco", ".pll4" }; static const char * const sel_clk_pll4d1_div3_div4[] = { ".pll4d1_div3", ".pll4d1_div4" }; +static const char * const sel_clk_pll4d3_div10_div20[] = { ".pll4d3_div10", ".pll4d3_div20" }; static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { /* External Clock Inputs */ @@ -174,6 +179,9 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1), DEF_FIXED(".pll4d1_div3", CLK_PLL4D1_DIV3, CLK_PLL4D1, 3, 1), DEF_FIXED(".pll4d1_div4", CLK_PLL4D1_DIV4, CLK_PLL4D1, 4, 1), + DEF_FIXED(".pll4d3", CLK_PLL4D3, CLK_SEL_CLK_PLL4, 3, 1), + DEF_FIXED(".pll4d3_div10", CLK_PLL4D3_DIV10, CLK_PLL4D3, 10, 1), + DEF_FIXED(".pll4d3_div20", CLK_PLL4D3_DIV20, CLK_PLL4D3, 20, 1), DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC, dtable_24_25_30_32), @@ -232,6 +240,8 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { FSELXSPI0, dtable_6_8_16_32_64), DEF_DIV_FSELXSPI("XSPI_CLK1", R9A09G077_XSPI_CLK1, CLK_DIVSELXSPI1_SCKCR, FSELXSPI1, dtable_6_8_16_32_64), + DEF_MUX("PCLKCAN", R9A09G077_PCLKCAN, FSELCANFD, + sel_clk_pll4d3_div10_div20, ARRAY_SIZE(sel_clk_pll4d3_div10_div20), 0), }; static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { @@ -251,6 +261,7 @@ static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { DEF_MOD("adc1", 207, R9A09G077_CLK_PCLKH), DEF_MOD("adc2", 225, R9A09G077_CLK_PCLKM), DEF_MOD("tsu", 307, R9A09G077_CLK_PCLKL), + DEF_MOD("canfd", 310, R9A09G077_CLK_PCLKM), DEF_MOD("gmac0", 400, R9A09G077_CLK_PCLKM), DEF_MOD("ethsw", 401, R9A09G077_CLK_PCLKM), DEF_MOD("ethss", 403, R9A09G077_CLK_PCLKM), diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 7f9b7aa39790..4824607d56c0 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -237,20 +237,16 @@ 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) +static u32 cpg_rzt2h_mstp_read(struct cpg_mssr_priv *priv, 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) +static void cpg_rzt2h_mstp_write(struct cpg_mssr_priv *priv, 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; @@ -286,17 +282,14 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) 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]); + value = cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]); if (enable) value &= ~bitmask; else value |= bitmask; - cpg_rzt2h_mstp_write(hw, - priv->control_regs[reg], - value); + cpg_rzt2h_mstp_write(priv, priv->control_regs[reg], value); } else { value = readl(priv->pub.base0 + priv->control_regs[reg]); if (enable) @@ -318,7 +311,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) * the IP at least seven times. Instead of memory-mapping the IP * register, we simply add a delay after the read operation. */ - cpg_rzt2h_mstp_read(hw, priv->control_regs[reg]); + cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]); udelay(10); return 0; } @@ -352,8 +345,7 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) 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]); + value = cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]); else value = readl(priv->pub.base0 + priv->status_regs[reg]); @@ -412,7 +404,7 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec, } if (IS_ERR(clk)) - dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, + dev_err(dev, "Cannot get %s clock %u: %ld\n", type, clkidx, PTR_ERR(clk)); else dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", @@ -802,14 +794,14 @@ static int cpg_mrcr_set_reset_state(struct reset_controller_dev *rcdev, /* Verify the operation */ val = readl(reg_addr); + + spin_unlock_irqrestore(&priv->pub.rmw_lock, flags); + if (set == !(bitmask & val)) { dev_err(priv->dev, "Reset register %u%02u operation failed\n", reg, bit); - spin_unlock_irqrestore(&priv->pub.rmw_lock, flags); return -EIO; } - spin_unlock_irqrestore(&priv->pub.rmw_lock, flags); - return 0; } @@ -1085,11 +1077,19 @@ static int cpg_mssr_suspend_noirq(struct device *dev) /* Save module registers with bits under our control */ for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) { - if (priv->smstpcr_saved[reg].mask) - priv->smstpcr_saved[reg].val = - priv->reg_layout == CLK_REG_LAYOUT_RZ_A ? - readb(priv->pub.base0 + priv->control_regs[reg]) : - readl(priv->pub.base0 + priv->control_regs[reg]); + u32 val; + + if (!priv->smstpcr_saved[reg].mask) + continue; + + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) + val = readb(priv->pub.base0 + priv->control_regs[reg]); + else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) + val = cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]); + else + val = readl(priv->pub.base0 + priv->control_regs[reg]); + + priv->smstpcr_saved[reg].val = val; } /* Save core clocks */ @@ -1120,6 +1120,8 @@ static int cpg_mssr_resume_noirq(struct device *dev) if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) oldval = readb(priv->pub.base0 + priv->control_regs[reg]); + else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) + oldval = cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]); else oldval = readl(priv->pub.base0 + priv->control_regs[reg]); newval = oldval & ~mask; @@ -1133,6 +1135,12 @@ static int cpg_mssr_resume_noirq(struct device *dev) readb(priv->pub.base0 + priv->control_regs[reg]); barrier_data(priv->pub.base0 + priv->control_regs[reg]); continue; + } else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_T2H) { + cpg_rzt2h_mstp_write(priv, priv->control_regs[reg], newval); + /* See cpg_mstp_clock_endisable() on why this is necessary. */ + cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]); + udelay(10); + continue; } else writel(newval, priv->pub.base0 + priv->control_regs[reg]); diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 0bcf64b152e0..c0584bab58a3 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -22,6 +22,7 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/iopoll.h> +#include <linux/math64.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of.h> @@ -74,6 +75,17 @@ #define MSTOP_OFF(conf) FIELD_GET(GENMASK(31, 16), (conf)) #define MSTOP_MASK(conf) FIELD_GET(GENMASK(15, 0), (conf)) +#define PLL5_FOUTVCO_MIN 800000000 +#define PLL5_FOUTVCO_MAX 3000000000 +#define PLL5_POSTDIV_MIN 1 +#define PLL5_POSTDIV_MAX 7 +#define PLL5_REFDIV_MIN 1 +#define PLL5_REFDIV_MAX 2 +#define PLL5_INTIN_MIN 20 +#define PLL5_INTIN_MAX 320 +#define PLL5_HSCLK_MIN 10000000 +#define PLL5_HSCLK_MAX 187500000 + /** * struct clk_hw_data - clock hardware data * @hw: clock hw @@ -129,6 +141,12 @@ struct rzg2l_pll5_param { u8 pl5_spread; }; +/* PLL5 output will be used for DPI or MIPI-DSI */ +static int dsi_div_target = PLL5_TARGET_DPI; + +/* Required division ratio for MIPI D-PHY clock depending on number of lanes and bpp. */ +static u8 dsi_div_ab_desired; + struct rzg2l_pll5_mux_dsi_div_param { u8 clksrc; u8 dsi_div_a; @@ -170,6 +188,11 @@ struct rzg2l_cpg_priv { struct rzg2l_pll5_mux_dsi_div_param mux_dsi_div_params; }; +static inline u8 rzg2l_cpg_div_ab(u8 a, u8 b) +{ + return (b + 1) << a; +} + static void rzg2l_cpg_del_clk_provider(void *data) { of_clk_del_provider(data); @@ -556,24 +579,121 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, return clk_hw->clk; } +/* + * VCO-->[POSTDIV1,2]--FOUTPOSTDIV--------------->| + * | |-->[1/(DSI DIV A * B)]--> MIPI_DSI_VCLK + * |-->[1/2]--FOUT1PH0-->| + * | + * |------->[1/16]--------------------------------> hsclk (MIPI-PHY) + */ static unsigned long -rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params, +rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_cpg_priv *priv, + struct rzg2l_pll5_param *params, unsigned long rate) { - unsigned long foutpostdiv_rate, foutvco_rate; + const u32 extal_hz = EXTAL_FREQ_IN_MEGA_HZ * MEGA; + unsigned long foutpostdiv_rate; + unsigned int a, b, odd; + unsigned long hsclk; + u8 dsi_div_ab_calc; + u64 foutvco_rate; + + if (dsi_div_target == PLL5_TARGET_DSI) { + /* Check hsclk */ + hsclk = rate * dsi_div_ab_desired / 16; + if (hsclk < PLL5_HSCLK_MIN || hsclk > PLL5_HSCLK_MAX) { + dev_err(priv->dev, "hsclk out of range\n"); + return 0; + } + + /* Determine the correct clock source based on even/odd of the divider */ + odd = dsi_div_ab_desired & 1; + if (odd) { + priv->mux_dsi_div_params.clksrc = 0; /* FOUTPOSTDIV */ + dsi_div_ab_calc = dsi_div_ab_desired; + } else { + priv->mux_dsi_div_params.clksrc = 1; /* FOUT1PH0 */ + dsi_div_ab_calc = dsi_div_ab_desired / 2; + } + + /* Calculate the DIV_DSI_A and DIV_DSI_B based on the desired divider */ + for (a = 0; a < 4; a++) { + /* FOUT1PH0: Max output of DIV_DSI_A is 750MHz so at least 1/2 to be safe */ + if (!odd && a == 0) + continue; + + /* FOUTPOSTDIV: DIV_DSI_A must always be 1/1 */ + if (odd && a != 0) + break; + + for (b = 0; b < 16; b++) { + /* FOUTPOSTDIV: DIV_DSI_B must always be odd divider 1/(b+1) */ + if (odd && b & 1) + continue; + + if (rzg2l_cpg_div_ab(a, b) == dsi_div_ab_calc) { + priv->mux_dsi_div_params.dsi_div_a = a; + priv->mux_dsi_div_params.dsi_div_b = b; + goto calc_pll_clk; + } + } + } + + dev_err(priv->dev, "Failed to calculate DIV_DSI_A,B\n"); + + return 0; + } else if (dsi_div_target == PLL5_TARGET_DPI) { + /* Fixed settings for DPI */ + priv->mux_dsi_div_params.clksrc = 0; + priv->mux_dsi_div_params.dsi_div_a = 3; /* Divided by 8 */ + priv->mux_dsi_div_params.dsi_div_b = 0; /* Divided by 1 */ + dsi_div_ab_desired = rzg2l_cpg_div_ab(priv->mux_dsi_div_params.dsi_div_a, + priv->mux_dsi_div_params.dsi_div_b); + } - params->pl5_intin = rate / MEGA; - params->pl5_fracin = div_u64(((u64)rate % MEGA) << 24, MEGA); - params->pl5_refdiv = 2; - params->pl5_postdiv1 = 1; - params->pl5_postdiv2 = 1; +calc_pll_clk: + /* PLL5 (MIPI_DSI_PLLCLK) = VCO / POSTDIV1 / POSTDIV2 */ + for (params->pl5_postdiv1 = PLL5_POSTDIV_MIN; + params->pl5_postdiv1 <= PLL5_POSTDIV_MAX; + params->pl5_postdiv1++) { + for (params->pl5_postdiv2 = PLL5_POSTDIV_MIN; + params->pl5_postdiv2 <= PLL5_POSTDIV_MAX; + params->pl5_postdiv2++) { + foutvco_rate = rate * params->pl5_postdiv1 * params->pl5_postdiv2 * + dsi_div_ab_desired; + if (foutvco_rate <= PLL5_FOUTVCO_MIN || foutvco_rate >= PLL5_FOUTVCO_MAX) + continue; + + for (params->pl5_refdiv = PLL5_REFDIV_MIN; + params->pl5_refdiv <= PLL5_REFDIV_MAX; + params->pl5_refdiv++) { + u32 rem; + + params->pl5_intin = div_u64_rem(foutvco_rate * params->pl5_refdiv, + extal_hz, &rem); + + if (params->pl5_intin < PLL5_INTIN_MIN || + params->pl5_intin > PLL5_INTIN_MAX) + continue; + + params->pl5_fracin = div_u64((u64)rem << 24, extal_hz); + + goto clk_valid; + } + } + } + + dev_err(priv->dev, "Failed to calculate PLL5 settings\n"); + return 0; + +clk_valid: params->pl5_spread = 0x16; foutvco_rate = div_u64(mul_u32_u32(EXTAL_FREQ_IN_MEGA_HZ * MEGA, (params->pl5_intin << 24) + params->pl5_fracin), params->pl5_refdiv) >> 24; - foutpostdiv_rate = DIV_ROUND_CLOSEST(foutvco_rate, - params->pl5_postdiv1 * params->pl5_postdiv2); + foutpostdiv_rate = DIV_U64_ROUND_CLOSEST(foutvco_rate, + params->pl5_postdiv1 * params->pl5_postdiv2); return foutpostdiv_rate; } @@ -607,7 +727,7 @@ static unsigned long rzg2l_cpg_get_vclk_parent_rate(struct clk_hw *hw, struct rzg2l_pll5_param params; unsigned long parent_rate; - parent_rate = rzg2l_cpg_get_foutpostdiv_rate(¶ms, rate); + parent_rate = rzg2l_cpg_get_foutpostdiv_rate(priv, ¶ms, rate); if (priv->mux_dsi_div_params.clksrc) parent_rate /= 2; @@ -623,9 +743,19 @@ static int rzg2l_cpg_dsi_div_determine_rate(struct clk_hw *hw, req->best_parent_rate = rzg2l_cpg_get_vclk_parent_rate(hw, req->rate); + if (!req->best_parent_rate) + return -EINVAL; + return 0; } +void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) +{ + dsi_div_ab_desired = divider; + dsi_div_target = target; +} +EXPORT_SYMBOL_GPL(rzg2l_cpg_dsi_div_set_divider); + static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -796,22 +926,6 @@ struct sipll5 { #define to_sipll5(_hw) container_of(_hw, struct sipll5, hw) -static unsigned long rzg2l_cpg_get_vclk_rate(struct clk_hw *hw, - unsigned long rate) -{ - struct sipll5 *sipll5 = to_sipll5(hw); - struct rzg2l_cpg_priv *priv = sipll5->priv; - unsigned long vclk; - - vclk = rate / ((1 << priv->mux_dsi_div_params.dsi_div_a) * - (priv->mux_dsi_div_params.dsi_div_b + 1)); - - if (priv->mux_dsi_div_params.clksrc) - vclk /= 2; - - return vclk; -} - static unsigned long rzg2l_cpg_sipll5_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -856,16 +970,16 @@ static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw, if (!rate) return -EINVAL; - vclk_rate = rzg2l_cpg_get_vclk_rate(hw, rate); + vclk_rate = rate / dsi_div_ab_desired; sipll5->foutpostdiv_rate = - rzg2l_cpg_get_foutpostdiv_rate(¶ms, vclk_rate); + rzg2l_cpg_get_foutpostdiv_rate(priv, ¶ms, vclk_rate); /* Put PLL5 into standby mode */ writel(CPG_SIPLL5_STBY_RESETB_WEN, priv->base + CPG_SIPLL5_STBY); ret = readl_poll_timeout(priv->base + CPG_SIPLL5_MON, val, !(val & CPG_SIPLL5_MON_PLL5_LOCK), 100, 250000); if (ret) { - dev_err(priv->dev, "failed to release pll5 lock"); + dev_err(priv->dev, "failed to release pll5 lock\n"); return ret; } @@ -892,7 +1006,7 @@ static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw, ret = readl_poll_timeout(priv->base + CPG_SIPLL5_MON, val, (val & CPG_SIPLL5_MON_PLL5_LOCK), 100, 250000); if (ret) { - dev_err(priv->dev, "failed to lock pll5"); + dev_err(priv->dev, "failed to lock pll5\n"); return ret; } @@ -945,9 +1059,7 @@ rzg2l_cpg_sipll5_register(const struct cpg_core_clk *core, if (ret) return ERR_PTR(ret); - priv->mux_dsi_div_params.clksrc = 1; /* Use clk src 1 for DSI */ - priv->mux_dsi_div_params.dsi_div_a = 1; /* Divided by 2 */ - priv->mux_dsi_div_params.dsi_div_b = 2; /* Divided by 3 */ + rzg2l_cpg_dsi_div_set_divider(8, PLL5_TARGET_DPI); return clk_hw->clk; } @@ -1102,7 +1214,7 @@ static struct clk } if (IS_ERR(clk)) - dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, + dev_err(dev, "Cannot get %s clock %u: %ld\n", type, clkidx, PTR_ERR(clk)); else dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", @@ -1647,6 +1759,7 @@ static int __rzg2l_cpg_assert(struct reset_controller_dev *rcdev, u32 mask = BIT(info->resets[id].bit); s8 monbit = info->resets[id].monbit; u32 value = mask << 16; + u32 mon; int ret; dev_dbg(rcdev->dev, "%s id:%ld offset:0x%x\n", @@ -1667,10 +1780,10 @@ static int __rzg2l_cpg_assert(struct reset_controller_dev *rcdev, return 0; } - ret = readl_poll_timeout_atomic(priv->base + reg, value, - assert == !!(value & mask), 10, 200); - if (ret && !assert) { - value = mask << 16; + ret = readl_poll_timeout_atomic(priv->base + reg, mon, + assert == !!(mon & mask), 10, 200); + if (ret) { + value ^= mask; writel(value, priv->base + CLK_RST_R(info->resets[id].off)); } diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 3f6299b9fec0..f6c47fb89bca 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -602,7 +602,7 @@ static int rzv2h_cpg_pll_set_rate(struct pll_clk *pll_clk, val, !(val & CPG_PLL_MON_LOCK), 100, 2000); if (ret) { - dev_err(priv->dev, "Failed to put PLLDSI into standby mode"); + dev_err(priv->dev, "Failed to put PLLDSI into standby mode\n"); return ret; } @@ -630,7 +630,7 @@ static int rzv2h_cpg_pll_set_rate(struct pll_clk *pll_clk, val, (val & CPG_PLL_MON_LOCK), 100, 2000); if (ret) { - dev_err(priv->dev, "Failed to put PLLDSI into normal mode"); + dev_err(priv->dev, "Failed to put PLLDSI into normal mode\n"); return ret; } @@ -1013,7 +1013,7 @@ static struct clk } if (IS_ERR(clk)) - dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, + dev_err(dev, "Cannot get %s clock %u: %ld\n", type, clkidx, PTR_ERR(clk)); else dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", @@ -1352,6 +1352,7 @@ static int __rzv2h_cpg_assert(struct reset_controller_dev *rcdev, u32 mask = BIT(priv->resets[id].reset_bit); u8 monbit = priv->resets[id].mon_bit; u32 value = mask << 16; + u32 mon; int ret; dev_dbg(rcdev->dev, "%s id:%ld offset:0x%x\n", @@ -1364,10 +1365,10 @@ static int __rzv2h_cpg_assert(struct reset_controller_dev *rcdev, reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); mask = BIT(monbit); - ret = readl_poll_timeout_atomic(priv->base + reg, value, - assert == !!(value & mask), 10, 200); - if (ret && !assert) { - value = mask << 16; + ret = readl_poll_timeout_atomic(priv->base + reg, mon, + assert == !!(mon & mask), 10, 200); + if (ret) { + value ^= mask; writel(value, priv->base + GET_RST_OFFSET(priv->resets[id].reset_index)); } diff --git a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h index 9eaedca6a616..c4863e444458 100644 --- a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h +++ b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h @@ -33,5 +33,6 @@ #define R9A09G077_ETCLKE 21 #define R9A09G077_XSPI_CLK0 22 #define R9A09G077_XSPI_CLK1 23 +#define R9A09G077_PCLKCAN 24 #endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G077_CPG_H__ */ diff --git a/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h b/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h index 606468ac49a4..0d53f1e65077 100644 --- a/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h +++ b/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h @@ -33,5 +33,6 @@ #define R9A09G087_ETCLKE 21 #define R9A09G087_XSPI_CLK0 22 #define R9A09G087_XSPI_CLK1 23 +#define R9A09G087_PCLKCAN 24 #endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G087_CPG_H__ */ diff --git a/include/linux/clk/renesas.h b/include/linux/clk/renesas.h index 69d8159deee3..c360df9fa735 100644 --- a/include/linux/clk/renesas.h +++ b/include/linux/clk/renesas.h @@ -35,6 +35,17 @@ void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev); #define cpg_mssr_detach_dev NULL #endif +enum { + PLL5_TARGET_DPI, + PLL5_TARGET_DSI +}; + +#ifdef CONFIG_CLK_RZG2L +void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target); +#else +static inline void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) { } +#endif + /** * struct rzv2h_pll_limits - PLL parameter constraints * |
