Add support for RZ/A2 series. The clock HW is similar to RZ/A1, but with different dividers and additional clocks sources. Signed-off-by: Chris Brandt <chris.brandt@xxxxxxxxxxx> --- drivers/clk/renesas/Kconfig | 5 ++ drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/clk-mstp.c | 3 + drivers/clk/renesas/clk-rz.c | 155 ++++++++++++++++++++++++++++++++--------- 4 files changed, 130 insertions(+), 34 deletions(-) diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 9022bbe1297e..b08d44b8a476 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -3,6 +3,7 @@ config CLK_RENESAS default y if ARCH_RENESAS select CLK_EMEV2 if ARCH_EMEV2 select CLK_RZA1 if ARCH_R7S72100 + select CLK_RZA2 if ARCH_R7S9210 select CLK_R8A73A4 if ARCH_R8A73A4 select CLK_R8A7740 if ARCH_R8A7740 select CLK_R8A7743 if ARCH_R8A7743 @@ -45,6 +46,10 @@ config CLK_RZA1 bool "RZ/A1H clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP +config CLK_RZA2 + bool "RZ/A2 clock support" if COMPILE_TEST + select CLK_RENESAS_CPG_MSTP + config CLK_R8A73A4 bool "R-Mobile APE6 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index e4aa3d6143d2..6159ee43f7ca 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -2,6 +2,7 @@ # SoC obj-$(CONFIG_CLK_EMEV2) += clk-emev2.o obj-$(CONFIG_CLK_RZA1) += clk-rz.o +obj-$(CONFIG_CLK_RZA2) += clk-rz.o obj-$(CONFIG_CLK_R8A73A4) += clk-r8a73a4.o obj-$(CONFIG_CLK_R8A7740) += clk-r8a7740.o obj-$(CONFIG_CLK_R8A7743) += r8a7743-cpg-mssr.o diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index e82adcb16a52..9470ab8acc13 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -213,6 +213,9 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks")) group->width_8bit = true; + if (of_device_is_compatible(np, "renesas,r7s9210-mstp-clocks")) + group->width_8bit = true; + for (i = 0; i < MSTP_MAX_CLOCKS; ++i) clks[i] = ERR_PTR(-ENOENT); diff --git a/drivers/clk/renesas/clk-rz.c b/drivers/clk/renesas/clk-rz.c index ac2f86d626b6..199c6ae9704c 100644 --- a/drivers/clk/renesas/clk-rz.c +++ b/drivers/clk/renesas/clk-rz.c @@ -1,5 +1,5 @@ /* - * RZ/A1 Core CPG Clocks + * RZ/A Core CPG Clocks * * Copyright (C) 2013 Ideas On Board SPRL * Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@xxxxxxxxxxxxxxxxxxxx> @@ -24,44 +24,95 @@ struct rz_cpg { #define CPG_FRQCR 0x10 #define CPG_FRQCR2 0x14 +#define SWRSTCR3 0xFCFE0468 +/* RZ/A1 */ #define PPR0 0xFCFE3200 #define PIBC0 0xFCFE7000 -#define MD_CLK(x) ((x >> 2) & 1) /* P0_2 */ +/* RZ/A2 */ +#define PORTL_PIDR 0xFCFFE074 + +#define RZA1 1 +#define RZA2 2 /* ----------------------------------------------------------------------------- * Initialization */ +int detect_rz(void) +{ + void __iomem *swrstcr3; + static int rz_device; + + if (!rz_device) { + swrstcr3 = ioremap_nocache(SWRSTCR3, 1); + BUG_ON(!swrstcr3); + if (ioread8(swrstcr3)) + rz_device = RZA1; + else + rz_device = RZA2; + iounmap(swrstcr3); + } + return rz_device; +} -static u16 __init rz_cpg_read_mode_pins(void) +static u8 __init rz_cpg_read_mode_pin(void) { - void __iomem *ppr0, *pibc0; - u16 modes; - - ppr0 = ioremap_nocache(PPR0, 2); - pibc0 = ioremap_nocache(PIBC0, 2); - BUG_ON(!ppr0 || !pibc0); - iowrite16(4, pibc0); /* enable input buffer */ - modes = ioread16(ppr0); - iounmap(ppr0); - iounmap(pibc0); - - return modes; + void __iomem *ppr0, *pibc0, *pidr; + u8 mode; + + if (detect_rz() == RZA1) { + /* RZ/A1 */ + /* MD_CLK pin is P0_2 */ + ppr0 = ioremap_nocache(PPR0, 2); + pibc0 = ioremap_nocache(PIBC0, 2); + BUG_ON(!ppr0 || !pibc0); + iowrite16(4, pibc0); /* enable input buffer */ + mode = (u8)((ioread16(ppr0) >> 2) & 1); + iounmap(ppr0); + iounmap(pibc0); + } else { + /* RZ/A2 */ + /* MD_CLK pin is PL_1 */ + pidr = ioremap_nocache(PORTL_PIDR, 1); + BUG_ON(!pidr); + mode = (ioread8(pidr) >> 1) & 1; + iounmap(pidr); + } + + return mode; } static struct clk * __init rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name) { u32 val; - unsigned mult; - static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 }; + unsigned int mult, div; + static const unsigned int rza1_frqcr_tab[4] = { 3, 2, 0, 1 }; + static const unsigned int rza2_frqcr_tab[5][5] = { + /* I, G, B, P1, P0 */ + { 2, 4, 8, 16, 32 }, /* FRQCR = 0x012 */ + { 4, 4, 8, 16, 32 }, /* FRQCR = 0x112 */ + { 8, 4, 8, 16, 32 }, /* FRQCR = 0x212 */ + { 16, 8, 16, 16, 32 }, /* FRQCR = 0x322 */ + { 16, 16, 32, 32, 32 }, /* FRQCR = 0x333 */ + }; - if (strcmp(name, "pll") == 0) { - unsigned int cpg_mode = MD_CLK(rz_cpg_read_mode_pins()); - const char *parent_name = of_clk_get_parent_name(np, cpg_mode); + unsigned int cpg_mode = rz_cpg_read_mode_pin(); - mult = cpg_mode ? (32 / 4) : 30; + + if (strcmp(name, "pll") == 0) { + const char *parent_name; + + if (detect_rz() == RZA1) { + /* RZ/A1 */ + parent_name = of_clk_get_parent_name(np, cpg_mode); + mult = cpg_mode ? (32 / 4) : 30; + } else { + /* RZ/A2 */ + parent_name = of_clk_get_parent_name(np, 0); + mult = 88; + } return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1); } @@ -70,19 +121,55 @@ rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *na if (!cpg->reg) return ERR_PTR(-ENXIO); - /* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3) - * and the constraint that always g <= i. To get the rz platform started, - * let them run at fixed current speed and implement the details later. - */ - if (strcmp(name, "i") == 0) - val = (readl(cpg->reg + CPG_FRQCR) >> 8) & 3; - else if (strcmp(name, "g") == 0) - val = readl(cpg->reg + CPG_FRQCR2) & 3; - else - return ERR_PTR(-EINVAL); - - mult = frqcr_tab[val]; - return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3); + if (detect_rz() == RZA1) { + /* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3) + * and the constraint that always g <= i. To get the rz platform started, + * let them run at fixed current speed and implement the details later. + */ + if (strcmp(name, "i") == 0) + val = (readl(cpg->reg + CPG_FRQCR) >> 8) & 3; + else if (strcmp(name, "g") == 0) + val = readl(cpg->reg + CPG_FRQCR2) & 3; + else + return ERR_PTR(-EINVAL); + mult = rza1_frqcr_tab[val]; + div = 3; + } else { + /* RZ/A2 */ + val = clk_readl(cpg->reg + CPG_FRQCR) & 0xFFF; + if (val == 0x012) + val = 0; + else if (val == 0x112) + val = 1; + else if (val == 0x212) + val = 2; + else if (val == 0x322) + val = 3; + else if (val == 0x333) + val = 4; + else + BUG_ON(1); /* Illegal FRQCR value */ + + if (strcmp(name, "i") == 0) + div = rza2_frqcr_tab[val][0]; + else if (strcmp(name, "g") == 0) + div = rza2_frqcr_tab[val][1]; + else if (strcmp(name, "b") == 0) + div = rza2_frqcr_tab[val][2]; + else if ((strcmp(name, "p1") == 0) || + (strcmp(name, "p1c") == 0)) + div = rza2_frqcr_tab[val][3]; + else if (strcmp(name, "p0") == 0) + div = rza2_frqcr_tab[val][4]; + else + return ERR_PTR(-EINVAL); + + mult = 1; + if (cpg_mode) + div *= 2; /* div 2 circuit before PLL */ + + } + return clk_register_fixed_factor(NULL, name, "pll", 0, mult, div); } static void __init rz_cpg_clocks_init(struct device_node *np) -- 2.16.1