clk: renesas: Update R-Car Gen3 driver Gen4 support

Update R-Car Gen4 support in Gen3 clock driver. This patch renames the
V3U clock parts to Gen4 and extends them by new PLL2, PLL3, PLL4, PLL6
as well as SDSRC clock which use undocumented bits so far, and RPCSRC
clock which uses its own more capable divider table. The Gen4 module
standby and reset tables are also updated.

This patch makes use of union to alias Gen3 and more extensive Gen4
PLL tables, as the driver cannot ever be instantiated on hardware
that would identify itself as both Gen3 and Gen4.

The V3U clock driver is updated to match Gen4 clock driver behavior,
it is augmented with a more extensive PLL table and a valid MODEMR
register offset.

This supersedes "clk: renesas: Introduce R-Car Gen4 CPG driver"
from Hai Pham as the R-Car Gen3 and Gen4 clock core drivers are
extremely similar. That implementation was in turn based on Linux
commit 470e3f0d0b15 ("clk: renesas: rcar-gen4: Introduce R-Car Gen4 CPG driver")
by Yoshihiro Shimoda .

Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
This commit is contained in:
Marek Vasut 2023-02-28 22:34:38 +01:00
parent 2fa93af66a
commit 3e01ed8e0f
6 changed files with 138 additions and 55 deletions

View file

@ -45,13 +45,13 @@ config CLK_R8A7794
Enable this to support the clocks on Renesas R8A7794 SoC.
config CLK_RCAR_GEN3
bool "Renesas RCar Gen3 clock driver"
def_bool y if RCAR_GEN3
bool "Renesas RCar Gen3 and Gen4 clock driver"
def_bool y if RCAR_64
depends on CLK_RENESAS
select CLK_RCAR_CPG_LIB
select DM_RESET
help
Enable this to support the clocks on Renesas RCar Gen3 SoC.
Enable this to support the clocks on Renesas RCar Gen3 and Gen4 SoCs.
config CLK_R8A774A1
bool "Renesas R8A774A1 clock driver"

View file

@ -35,10 +35,16 @@
#define CPG_PLL2CR 0x002c
#define CPG_PLL4CR 0x01f4
static const struct clk_div_table cpg_rpcsrc_div_table[] = {
#define SD0CKCR1 0x08a4
static const struct clk_div_table gen3_cpg_rpcsrc_div_table[] = {
{ 2, 5 }, { 3, 6 }, { 0, 0 },
};
static const struct clk_div_table gen4_cpg_rpcsrc_div_table[] = {
{ 0, 4 }, { 1, 6 }, { 2, 5 }, { 3, 6 }, { 0, 0 },
};
static const struct clk_div_table r8a77970_cpg_sd0h_div_table[] = {
{ 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 },
{ 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 },
@ -181,8 +187,10 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
struct cpg_mssr_info *info = priv->info;
struct clk parent;
const struct cpg_core_clk *core;
const struct rcar_gen3_cpg_pll_config *pll_config =
priv->cpg_pll_config;
const struct rcar_gen3_cpg_pll_config *gen3_pll_config =
priv->gen3_cpg_pll_config;
const struct rcar_gen4_cpg_pll_config *gen4_pll_config =
priv->gen4_cpg_pll_config;
u32 value, div;
u64 rate = 0;
u8 shift;
@ -227,7 +235,7 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
case CLK_TYPE_GEN3_MAIN:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, 1, pll_config->extal_div,
0, 1, gen3_pll_config->extal_div,
"MAIN");
case CLK_TYPE_GEN3_PLL0:
@ -236,8 +244,9 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
case CLK_TYPE_GEN3_PLL1:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, pll_config->pll1_mult,
pll_config->pll1_div, "PLL1");
0, gen3_pll_config->pll1_mult,
gen3_pll_config->pll1_div,
"PLL1");
case CLK_TYPE_GEN3_PLL2:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
@ -245,8 +254,9 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
case CLK_TYPE_GEN3_PLL3:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, pll_config->pll3_mult,
pll_config->pll3_div, "PLL3");
0, gen3_pll_config->pll3_mult,
gen3_pll_config->pll3_div,
"PLL3");
case CLK_TYPE_GEN3_PLL4:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
@ -254,25 +264,48 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
case CLK_TYPE_GEN4_MAIN:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, 1, pll_config->extal_div,
"V3U_MAIN");
0, 1, gen4_pll_config->extal_div,
"MAIN");
case CLK_TYPE_GEN4_PLL1:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, pll_config->pll1_mult,
pll_config->pll1_div,
"V3U_PLL1");
0, gen4_pll_config->pll1_mult,
gen4_pll_config->pll1_div,
"PLL1");
case CLK_TYPE_GEN4_PLL2:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, gen4_pll_config->pll2_mult,
gen4_pll_config->pll2_div,
"PLL2");
case CLK_TYPE_GEN4_PLL2X_3X:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
core->offset, 0, 0,
"V3U_PLL2X_3X");
core->offset, 0, 0, "PLL2X_3X");
case CLK_TYPE_GEN4_PLL3:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, gen4_pll_config->pll3_mult,
gen4_pll_config->pll3_div,
"PLL3");
case CLK_TYPE_GEN4_PLL4:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, gen4_pll_config->pll4_mult,
gen4_pll_config->pll4_div,
"PLL4");
case CLK_TYPE_GEN4_PLL5:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, pll_config->pll5_mult,
pll_config->pll5_div,
"V3U_PLL5");
0, gen4_pll_config->pll5_mult,
gen4_pll_config->pll5_div,
"PLL5");
case CLK_TYPE_GEN4_PLL6:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
0, gen4_pll_config->pll6_mult,
gen4_pll_config->pll6_div,
"PLL6");
case CLK_TYPE_FF:
return gen3_clk_get_rate64_pll_mul_reg(priv, &parent,
@ -288,6 +321,13 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
div, rate);
return rate;
case CLK_TYPE_GEN4_SDSRC:
div = ((readl(priv->base + SD0CKCR1) >> 29) & 0x03) + 4;
rate = gen3_clk_get_rate64(&parent) / div;
debug("%s[%i] SDSRC clk: parent=%i div=%u => rate=%llu\n",
__func__, __LINE__, core->parent, div, rate);
return rate;
case CLK_TYPE_GEN3_SDH: /* Fixed factor 1:1 */
fallthrough;
case CLK_TYPE_GEN4_SDH: /* Fixed factor 1:1 */
@ -321,7 +361,16 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
gen3_clk_get_rate64(&parent),
priv->base + CPG_RPCCKCR,
CPG_RPCCKCR_DIV_POST_MASK,
cpg_rpcsrc_div_table, "RPCSRC");
gen3_cpg_rpcsrc_div_table,
"RPCSRC");
case CLK_TYPE_GEN4_RPCSRC:
return rcar_clk_get_rate64_div_table(core->parent,
gen3_clk_get_rate64(&parent),
priv->base + CPG_RPCCKCR,
CPG_RPCCKCR_DIV_POST_MASK,
gen4_cpg_rpcsrc_div_table,
"RPCSRC");
case CLK_TYPE_GEN3_D3_RPCSRC:
case CLK_TYPE_GEN3_E3_RPCSRC:
@ -409,6 +458,7 @@ static int gen3_clk_probe(struct udevice *dev)
struct gen3_clk_priv *priv = dev_get_priv(dev);
struct cpg_mssr_info *info =
(struct cpg_mssr_info *)dev_get_driver_data(dev);
const void *pll_config;
fdt_addr_t rst_base;
int ret;
@ -427,21 +477,24 @@ static int gen3_clk_probe(struct udevice *dev)
priv->cpg_mode = readl(rst_base + info->reset_modemr_offset);
priv->cpg_pll_config =
(struct rcar_gen3_cpg_pll_config *)info->get_pll_config(priv->cpg_mode);
if (!priv->cpg_pll_config->extal_div)
return -EINVAL;
pll_config = info->get_pll_config(priv->cpg_mode);
if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) {
priv->info->status_regs = mstpsr;
priv->info->control_regs = smstpcr;
priv->info->reset_regs = srcr;
priv->info->reset_clear_regs = srstclr;
} else if (info->reg_layout == CLK_REG_LAYOUT_RCAR_V3U) {
priv->info->status_regs = mstpsr_for_v3u;
priv->info->control_regs = mstpcr_for_v3u;
priv->info->reset_regs = srcr_for_v3u;
priv->info->reset_clear_regs = srstclr_for_v3u;
priv->gen3_cpg_pll_config = pll_config;
if (!priv->gen3_cpg_pll_config->extal_div)
return -EINVAL;
} else if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN4) {
priv->info->status_regs = mstpsr_for_gen4;
priv->info->control_regs = mstpcr_for_gen4;
priv->info->reset_regs = srcr_for_gen4;
priv->info->reset_clear_regs = srstclr_for_gen4;
priv->gen4_cpg_pll_config = pll_config;
if (!priv->gen4_cpg_pll_config->extal_div)
return -EINVAL;
} else {
return -EINVAL;
}

View file

@ -232,11 +232,10 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] = {
/*
* CPG Clock Data
*/
/*
* MD EXTAL PLL1 PLL20 PLL30 PLL4 PLL5 OSC
* 14 13 (MHz) 21 31
* --------------------------------------------------------
* ----------------------------------------------------------------
* 0 0 16.66 x 1 x128 x216 x128 x144 x192 /16
* 0 1 20 x 1 x106 x180 x106 x120 x160 /19
* 1 0 Prohibited setting
@ -244,13 +243,12 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] = {
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \
(((md) & BIT(13)) >> 13))
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[4] = {
/* EXTAL div PLL1 mult/div Not used OSC prediv PLL5 mult/div */
{ 1, 128, 1, 128, 1, 16, 192, 1, },
{ 1, 106, 1, 106, 1, 19, 160, 1, },
{ 0, 0, 0, 0, 0, 0, 0, 0, },
{ 2, 128, 1, 128, 1, 32, 192, 1, },
static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = {
/* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL4 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */
{ 1, 128, 1, 0, 0, 0, 0, 144, 1, 192, 1, 0, 0, 16, },
{ 1, 106, 1, 0, 0, 0, 0, 120, 1, 160, 1, 0, 0, 19, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 2, 128, 1, 0, 0, 0, 0, 144, 1, 192, 1, 0, 0, 32, },
};
/*
@ -292,13 +290,13 @@ static const struct cpg_mssr_info r8a779a0_cpg_mssr_info = {
.mstp_table = r8a779a0_mstp_table,
.mstp_table_size = ARRAY_SIZE(r8a779a0_mstp_table),
.reset_node = "renesas,r8a779a0-rst",
.reset_modemr_offset = 0x00,
.reset_modemr_offset = CPG_RST_MODEMR0,
.extalr_node = "extalr",
.mod_clk_base = MOD_CLK_BASE,
.clk_extal_id = CLK_EXTAL,
.clk_extalr_id = CLK_EXTALR,
.get_pll_config = r8a779a0_get_pll_config,
.reg_layout = CLK_REG_LAYOUT_RCAR_V3U,
.reg_layout = CLK_REG_LAYOUT_RCAR_GEN4,
};
static const struct udevice_id r8a779a0_cpg_ids[] = {

View file

@ -34,8 +34,13 @@ enum rcar_gen3_clk_types {
CLK_TYPE_GEN4_MAIN,
CLK_TYPE_GEN4_PLL1,
CLK_TYPE_GEN4_PLL2X_3X, /* PLL[23][01] */
CLK_TYPE_GEN4_PLL2,
CLK_TYPE_GEN4_PLL2X_3X, /* R8A779A0 only */
CLK_TYPE_GEN4_PLL3,
CLK_TYPE_GEN4_PLL5,
CLK_TYPE_GEN4_PLL4,
CLK_TYPE_GEN4_PLL6,
CLK_TYPE_GEN4_SDSRC,
CLK_TYPE_GEN4_SDH,
CLK_TYPE_GEN4_SD,
CLK_TYPE_GEN4_MDSEL, /* Select parent/divider using mode pin */
@ -107,11 +112,27 @@ struct rcar_gen3_cpg_pll_config {
u8 pll3_mult;
u8 pll3_div;
u8 osc_prediv;
};
struct rcar_gen4_cpg_pll_config {
u8 extal_div;
u8 pll1_mult;
u8 pll1_div;
u8 pll2_mult;
u8 pll2_div;
u8 pll3_mult;
u8 pll3_div;
u8 pll4_mult;
u8 pll4_div;
u8 pll5_mult;
u8 pll5_div;
u8 pll6_mult;
u8 pll6_div;
u8 osc_prediv;
};
#define CPG_RST_MODEMR 0x060
#define CPG_RST_MODEMR0 0x000
#define CPG_SDCKCR_STPnHCK BIT(9)
#define CPG_SDCKCR_STPnCK BIT(8)
@ -133,7 +154,10 @@ struct gen3_clk_priv {
struct clk clk_extal;
struct clk clk_extalr;
u32 cpg_mode;
const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
union {
const struct rcar_gen3_cpg_pll_config *gen3_cpg_pll_config;
const struct rcar_gen4_cpg_pll_config *gen4_cpg_pll_config;
};
};
int gen3_cpg_bind(struct udevice *parent);

View file

@ -128,7 +128,7 @@ int renesas_clk_remove(void __iomem *base, struct cpg_mssr_info *info)
info->mstp_table[i].sdis,
info->mstp_table[i].sen);
if (info->reg_layout == CLK_REG_LAYOUT_RCAR_V3U)
if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN4)
continue;
clrsetbits_le32(base + RMSTPCR(i),

View file

@ -17,7 +17,7 @@
enum clk_reg_layout {
CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3 = 0,
CLK_REG_LAYOUT_RCAR_V3U,
CLK_REG_LAYOUT_RCAR_GEN4,
};
struct cpg_mssr_info {
@ -134,7 +134,7 @@ int renesas_clk_remove(void __iomem *base, struct cpg_mssr_info *info);
* Module Standby and Software Reset register offets.
*
* If the registers exist, these are valid for SH-Mobile, R-Mobile,
* R-Car Gen2, R-Car Gen3, and RZ/G1.
* R-Car Gen2, R-Car Gen3, R-Car Gen4 and RZ/G1.
* These are NOT valid for R-Car Gen1 and RZ/A1!
*/
@ -147,9 +147,11 @@ static const u16 mstpsr[] = {
0x9A0, 0x9A4, 0x9A8, 0x9AC,
};
static const u16 mstpsr_for_v3u[] = {
static const u16 mstpsr_for_gen4[] = {
0x2E00, 0x2E04, 0x2E08, 0x2E0C, 0x2E10, 0x2E14, 0x2E18, 0x2E1C,
0x2E20, 0x2E24, 0x2E28, 0x2E2C, 0x2E30, 0x2E34, 0x2E38,
0x2E20, 0x2E24, 0x2E28, 0x2E2C, 0x2E30, 0x2E34, 0x2E38, 0x2E3C,
0x2E40, 0x2E44, 0x2E48, 0x2E4C, 0x2E50, 0x2E54, 0x2E58, 0x2E5C,
0x2E60, 0x2E64, 0x2E68, 0x2E6C,
};
/*
@ -161,9 +163,11 @@ static const u16 smstpcr[] = {
0x990, 0x994, 0x998, 0x99C,
};
static const u16 mstpcr_for_v3u[] = {
static const u16 mstpcr_for_gen4[] = {
0x2D00, 0x2D04, 0x2D08, 0x2D0C, 0x2D10, 0x2D14, 0x2D18, 0x2D1C,
0x2D20, 0x2D24, 0x2D28, 0x2D2C, 0x2D30, 0x2D34, 0x2D38,
0x2D20, 0x2D24, 0x2D28, 0x2D2C, 0x2D30, 0x2D34, 0x2D38, 0x2D3C,
0x2D40, 0x2D44, 0x2D48, 0x2D4C, 0x2D50, 0x2D54, 0x2D58, 0x2D5C,
0x2D60, 0x2D64, 0x2D68, 0x2D6C,
};
/*
@ -175,9 +179,11 @@ static const u16 srcr[] = {
0x920, 0x924, 0x928, 0x92C,
};
static const u16 srcr_for_v3u[] = {
static const u16 srcr_for_gen4[] = {
0x2C00, 0x2C04, 0x2C08, 0x2C0C, 0x2C10, 0x2C14, 0x2C18, 0x2C1C,
0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38,
0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38, 0x2C3C,
0x2C40, 0x2C44, 0x2C48, 0x2C4C, 0x2C50, 0x2C54, 0x2C58, 0x2C5C,
0x2C60, 0x2C64, 0x2C68, 0x2C6C,
};
/* Realtime Module Stop Control Register offsets */
@ -193,9 +199,11 @@ static const u16 srstclr[] = {
0x960, 0x964, 0x968, 0x96C,
};
static const u16 srstclr_for_v3u[] = {
static const u16 srstclr_for_gen4[] = {
0x2C80, 0x2C84, 0x2C88, 0x2C8C, 0x2C90, 0x2C94, 0x2C98, 0x2C9C,
0x2CA0, 0x2CA4, 0x2CA8, 0x2CAC, 0x2CB0, 0x2CB4, 0x2CB8,
0x2CA0, 0x2CA4, 0x2CA8, 0x2CAC, 0x2CB0, 0x2CB4, 0x2CB8, 0x2CBC,
0x2CC0, 0x2CC4, 0x2CC8, 0x2CCC, 0x2CD0, 0x2CD4, 0x2CD8, 0x2CDC,
0x2CE0, 0x2CE4, 0x2CE8, 0x2CEC,
};
#endif /* __DRIVERS_CLK_RENESAS_CPG_MSSR__ */