summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-01 13:53:43 +0100
committerMark Brown <broonie@kernel.org>2026-07-01 13:53:43 +0100
commitd82f21964819acffc3e1b9f2c1e09aaa8da17498 (patch)
treeef7c61d993f43c4892d2865720a00a5c773ede15
parent7f79a291c405f608d62b0021a6d64d8903b3b963 (diff)
parent91fb4643954379f8493dba649d520c23f0d1f4e6 (diff)
downloadlinux-next-d82f21964819acffc3e1b9f2c1e09aaa8da17498.tar.gz
linux-next-d82f21964819acffc3e1b9f2c1e09aaa8da17498.zip
Merge branch 'renesas-clk' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml6
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml2
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/clk/renesas/Kconfig6
-rw-r--r--drivers/clk/renesas/Makefile1
-rw-r--r--drivers/clk/renesas/r9a08g046-cpg.c130
-rw-r--r--drivers/clk/renesas/r9a09g047-cpg.c123
-rw-r--r--drivers/clk/renesas/r9a09g077-cpg.c375
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c20
-rw-r--r--drivers/clk/renesas/rzv2h-cpg-lib.c217
-rw-r--r--drivers/clk/renesas/rzv2h-cpg.c203
-rw-r--r--include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h2
-rw-r--r--include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h2
-rw-r--r--include/linux/clk/renesas.h34
14 files changed, 904 insertions, 223 deletions
diff --git a/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml b/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml
index f261445bf341..dd3e66a4559b 100644
--- a/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml
@@ -26,16 +26,22 @@ properties:
maxItems: 1
clocks:
+ minItems: 3
items:
- description: AUDIO_EXTAL clock input
- description: RTXIN clock input
- description: QEXTAL clock input
+ - description: AUDIO_CLKB clock input
+ - description: AUDIO_CLKC clock input
clock-names:
+ minItems: 3
items:
- const: audio_extal
- const: rtxin
- const: qextal
+ - const: audio_clkb
+ - const: audio_clkc
'#clock-cells':
description: |
diff --git a/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml b/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
index b339f1f9f072..990d287d0a90 100644
--- a/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas Versaclock7 Programmable Clock
maintainers:
- - Alex Helms <alexander.helms.jy@renesas.com>
+ - Biju Das <biju.das.jz@bp.renesas.com>
description: |
Renesas Versaclock7 is a family of configurable clock generator and
diff --git a/MAINTAINERS b/MAINTAINERS
index 377dc1f84d8e..2d157f4c9110 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23091,10 +23091,12 @@ L: linux-renesas-soc@vger.kernel.org
S: Maintained
F: drivers/phy/renesas/phy-rcar-gen3-usb*.c
-RENESAS VERSACLOCK 7 CLOCK DRIVER
-M: Alex Helms <alexander.helms.jy@renesas.com>
+RENESAS VERSACLOCK 3 and VERSACLOCK 7 CLOCK DRIVER
+M: Biju Das <biju.das.jz@bp.renesas.com>
S: Maintained
+F: Documentation/devicetree/bindings/clock/renesas,5p35023.yaml
F: Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
+F: drivers/clk/clk-versaclock3.c
F: drivers/clk/clk-versaclock7.c
RENESAS X9250 DIGITAL POTENTIOMETERS DRIVER
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 0203ecbb3882..5c0238e878b7 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -218,10 +218,12 @@ config CLK_R9A09G057
config CLK_R9A09G077
bool "RZ/T2H clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSSR
+ select CLK_RZV2H_CPG_LIB
config CLK_R9A09G087
bool "RZ/N2H clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSSR
+ select CLK_RZV2H_CPG_LIB
config CLK_SH73A0
bool "SH-Mobile AG5 clock support" if COMPILE_TEST
@@ -260,8 +262,12 @@ config CLK_RZG2L
config CLK_RZV2H
bool "RZ/{G3E,V2H(P)} family clock support" if COMPILE_TEST
+ select CLK_RZV2H_CPG_LIB
select RESET_CONTROLLER
+config CLK_RZV2H_CPG_LIB
+ bool "RZV2H CPG library functions" if COMPILE_TEST
+
config CLK_RENESAS_VBATTB
tristate "Renesas VBATTB clock controller"
depends on ARCH_RZG2L || COMPILE_TEST
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index bd2bed91ab29..ac790e56034b 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o
obj-$(CONFIG_CLK_RCAR_GEN4_CPG) += rcar-gen4-cpg.o
obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o
obj-$(CONFIG_CLK_RZG2L) += rzg2l-cpg.o
+obj-$(CONFIG_CLK_RZV2H_CPG_LIB) += rzv2h-cpg-lib.o
obj-$(CONFIG_CLK_RZV2H) += rzv2h-cpg.o
# Generic
diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c
index a57638734ce7..4488bd1988e8 100644
--- a/drivers/clk/renesas/r9a08g046-cpg.c
+++ b/drivers/clk/renesas/r9a08g046-cpg.c
@@ -17,10 +17,15 @@
/* RZ/G3L Specific registers. */
#define G3L_CPG_PL2_DDIV (0x204)
#define G3L_CPG_PL3_DDIV (0x208)
+#define G3L_CPG_SDHI_DDIV (0x218)
+#define G3L_CPG_GE3D_DDIV (0x224)
#define G3L_CPG_CA55CORE_DDIV (0x234)
#define G3L_CPG_RSCI_DDIV (0x238)
#define G3L_CPG_RSPI_DDIV (0x23c)
+#define G3L_CPG_SDHI_DSEL (0x244)
#define G3L_CLKDIVSTATUS (0x280)
+#define G3L_CLKSELSTATUS (0x284)
+#define G3L_CPG_GE3D_SSEL (0x40c)
#define G3L_CPG_ETH_SSEL (0x410)
#define G3L_CPG_RSCI_SSEL (0x414)
#define G3L_CPG_RSPI_SSEL (0x418)
@@ -30,6 +35,10 @@
#define G3L_DIVPL2A DDIV_PACK(G3L_CPG_PL2_DDIV, 0, 2)
#define G3L_DIVPL2B DDIV_PACK(G3L_CPG_PL2_DDIV, 4, 2)
#define G3L_DIVPL3A DDIV_PACK(G3L_CPG_PL3_DDIV, 0, 2)
+#define G3L_DIV_SDHI0 DDIV_PACK(G3L_CPG_SDHI_DDIV, 0, 2)
+#define G3L_DIV_SDHI1 DDIV_PACK(G3L_CPG_SDHI_DDIV, 4, 2)
+#define G3L_DIV_SDHI2 DDIV_PACK(G3L_CPG_SDHI_DDIV, 8, 2)
+#define G3L_DIV_GE3D DDIV_PACK(G3L_CPG_GE3D_DDIV, 0, 3)
#define G3L_DIV_CA55_CORE0 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 0, 3)
#define G3L_DIV_CA55_CORE1 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 4, 3)
#define G3L_DIV_CA55_CORE2 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 8, 3)
@@ -61,8 +70,19 @@
#define G3L_DIV_RSPI0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 20, 1)
#define G3L_DIV_RSPI1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 21, 1)
#define G3L_DIV_RSPI2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 22, 1)
+#define G3L_DIV_SDHI0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 24, 1)
+#define G3L_DIV_SDHI1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 25, 1)
+#define G3L_DIV_SDHI2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 26, 1)
+
+#define G3L_SEL_SDHI0_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 16, 1)
+#define G3L_SEL_SDHI1_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 17, 1)
+#define G3L_SEL_SDHI2_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 18, 1)
+#define G3L_DIV_GE3D_STS DDIV_PACK(G3L_CLKDIVSTATUS, 27, 1)
/* RZ/G3L Specific clocks select. */
+#define G3L_SEL_SDHI0 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 0, 2)
+#define G3L_SEL_SDHI1 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 4, 2)
+#define G3L_SEL_SDHI2 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 8, 2)
#define G3L_SEL_ETH0_TX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 0, 1)
#define G3L_SEL_ETH0_RX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 1, 1)
#define G3L_SEL_ETH0_RM SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 2, 1)
@@ -73,6 +93,7 @@
#define G3L_SEL_ETH1_RM SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 10, 1)
#define G3L_SEL_ETH1_CLK_TX_I SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 11, 1)
#define G3L_SEL_ETH1_CLK_RX_I SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 12, 1)
+#define G3L_SEL_GE3D SEL_PLL_PACK(G3L_CPG_GE3D_SSEL, 0, 2)
#define G3L_SEL_RSCI0 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 0, 2)
#define G3L_SEL_RSCI1 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 2, 2)
#define G3L_SEL_RSCI2 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 4, 2)
@@ -94,6 +115,7 @@ enum clk_ids {
/* Internal Core Clocks */
CLK_PLL1,
+ CLK_PLL1_DIV2,
CLK_PLL2,
CLK_PLL2_DIV2,
CLK_PLL2_DIV2_4,
@@ -102,6 +124,8 @@ enum clk_ids {
CLK_PLL2_DIV7,
CLK_PLL3,
CLK_PLL3_DIV2,
+ CLK_PLL3_DIV2_2,
+ CLK_PLL3_DIV3,
CLK_PLL6,
CLK_PLL6_DIV10,
CLK_SEL_ETH0_TX,
@@ -110,6 +134,7 @@ enum clk_ids {
CLK_SEL_ETH1_TX,
CLK_SEL_ETH1_RX,
CLK_SEL_ETH1_RM,
+ CLK_SEL_GE3D,
CLK_SEL_RSCI0,
CLK_SEL_RSCI1,
CLK_SEL_RSCI2,
@@ -117,16 +142,29 @@ enum clk_ids {
CLK_SEL_RSPI0,
CLK_SEL_RSPI1,
CLK_SEL_RSPI2,
+ CLK_SEL_SDHI0,
+ CLK_SEL_SDHI1,
+ CLK_SEL_SDHI2,
CLK_ETH0_TR,
CLK_ETH0_RM,
CLK_ETH1_TR,
CLK_ETH1_RM,
+ CLK_SD0_DIV2,
+ CLK_SD1_DIV2,
+ CLK_SD2_DIV2,
/* Module Clocks */
MOD_CLK_BASE,
};
/* Divider tables */
+static const struct clk_div_table dtable_1_4[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 0, 0 },
+};
+
static const struct clk_div_table dtable_1_8[] = {
{ 0, 1 },
{ 1, 2 },
@@ -189,12 +227,17 @@ static const char * const sel_eth0_rm[] = { ".pll6_div10", "eth0_rxc_rx_clk" };
static const char * const sel_eth1_tx[] = { ".div_eth1_tr", "eth1_txc_tx_clk" };
static const char * const sel_eth1_rx[] = { ".div_eth1_tr", "eth1_rxc_rx_clk" };
static const char * const sel_eth1_rm[] = { ".pll6_div10", "eth1_rxc_rx_clk" };
+static const char * const sel_ge3d[] = { ".pll1_div2", ".pll3_div3", ".pll6", ".pll3_div2_2" };
static const char * const sel_rsci_rspi[] = { ".pll2_div5", ".pll2_div6", ".pll2_div7", ".pll2_div2_4" };
+static const char * const sel_sdhi[] = { ".pll2_div2", ".pll1_div2", ".pll6", ".pll2_div6" };
static const char * const sel_eth0_clk_tx_i[] = { ".sel_eth0_tx", ".div_eth0_rm" };
static const char * const sel_eth0_clk_rx_i[] = { ".sel_eth0_rx", ".div_eth0_rm" };
static const char * const sel_eth1_clk_tx_i[] = { ".sel_eth1_tx", ".div_eth1_rm" };
static const char * const sel_eth1_clk_rx_i[] = { ".sel_eth1_rx", ".div_eth1_rm" };
+/* Mux clock indices tables. */
+static const u32 mtable_sd[] = { 0, 1, 2, 3 };
+
static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
@@ -210,13 +253,23 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = {
DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
DEF_G3L_PLL(".pll6", CLK_PLL6, CLK_EXTAL, CPG_PLL_CONF(0x50, 0),
500000000UL),
+ DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 1, 2),
DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
DEF_FIXED(".pll2_div2_4", CLK_PLL2_DIV2_4, CLK_PLL2_DIV2, 1, 4),
DEF_FIXED(".pll2_div5", CLK_PLL2_DIV5, CLK_PLL2, 1, 5),
DEF_FIXED(".pll2_div6", CLK_PLL2_DIV6, CLK_PLL2, 1, 6),
DEF_FIXED(".pll2_div7", CLK_PLL2_DIV7, CLK_PLL2, 1, 7),
DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
+ DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2),
+ DEF_FIXED(".pll3_div3", CLK_PLL3_DIV3, CLK_PLL3, 1, 3),
DEF_FIXED(".pll6_div10", CLK_PLL6_DIV10, CLK_PLL6, 1, 10),
+ DEF_SD_MUX(".sel_sdhi0", CLK_SEL_SDHI0, G3L_SEL_SDHI0, G3L_SEL_SDHI0_STS, sel_sdhi,
+ mtable_sd, 0, NULL),
+ DEF_SD_MUX(".sel_sdhi1", CLK_SEL_SDHI1, G3L_SEL_SDHI1, G3L_SEL_SDHI1_STS, sel_sdhi,
+ mtable_sd, 0, NULL),
+ DEF_SD_MUX(".sel_sdhi2", CLK_SEL_SDHI2, G3L_SEL_SDHI2, G3L_SEL_SDHI2_STS, sel_sdhi,
+ mtable_sd, 0, NULL),
+ DEF_MUX(".sel_ge3d", CLK_SEL_GE3D, G3L_SEL_GE3D, sel_ge3d),
DEF_MUX(".sel_rsci0", CLK_SEL_RSCI0, G3L_SEL_RSCI0, sel_rsci_rspi),
DEF_MUX(".sel_rsci1", CLK_SEL_RSCI1, G3L_SEL_RSCI1, sel_rsci_rspi),
DEF_MUX(".sel_rsci2", CLK_SEL_RSCI2, G3L_SEL_RSCI2, sel_rsci_rspi),
@@ -264,6 +317,18 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = {
dtable_1_8, 0, 200000000UL, 0, NULL),
DEF_G3S_DIV("P19", R9A08G046_CLK_P19, CLK_SEL_RSPI2, G3L_DIV_RSPI2, G3L_DIV_RSPI2_STS,
dtable_1_8, 0, 200000000UL, 0, NULL),
+ DEF_G3S_DIV("SD0", R9A08G046_CLK_SD0, CLK_SEL_SDHI0, G3L_DIV_SDHI0, G3L_DIV_SDHI0_STS,
+ dtable_1_4, 800000000UL, 600000000UL, CLK_SET_RATE_PARENT,
+ rzg3s_cpg_div_clk_notifier),
+ DEF_G3S_DIV("SD1", R9A08G046_CLK_SD1, CLK_SEL_SDHI1, G3L_DIV_SDHI1, G3L_DIV_SDHI1_STS,
+ dtable_1_4, 800000000UL, 600000000UL, CLK_SET_RATE_PARENT,
+ rzg3s_cpg_div_clk_notifier),
+ DEF_G3S_DIV("SD2", R9A08G046_CLK_SD2, CLK_SEL_SDHI2, G3L_DIV_SDHI2, G3L_DIV_SDHI2_STS,
+ dtable_1_4, 800000000UL, 600000000UL, CLK_SET_RATE_PARENT,
+ rzg3s_cpg_div_clk_notifier),
+ DEF_FIXED(".sd0_div2", CLK_SD0_DIV2, R9A08G046_CLK_SD0, 1, 2),
+ DEF_FIXED(".sd1_div2", CLK_SD1_DIV2, R9A08G046_CLK_SD1, 1, 2),
+ DEF_FIXED(".sd2_div2", CLK_SD2_DIV2, R9A08G046_CLK_SD2, 1, 2),
DEF_FIXED("HP", R9A08G046_CLK_HP, CLK_PLL6_DIV10, 1, 1),
DEF_MUX_FLAGS("ETHTX01", R9A08G046_CLK_ETHTX01, G3L_SEL_ETH0_CLK_TX_I, sel_eth0_clk_tx_i,
CLK_SET_RATE_PARENT),
@@ -279,6 +344,8 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = {
DEF_FIXED("ETHRM1", R9A08G046_CLK_ETHRM1, CLK_SEL_ETH1_RM, 1, 1),
DEF_FIXED("ETHTX12", R9A08G046_CLK_ETHTX12, CLK_SEL_ETH1_TX, 1, 1),
DEF_FIXED("ETHRX12", R9A08G046_CLK_ETHRX12, CLK_SEL_ETH1_RX, 1, 1),
+ DEF_G3S_DIV("G", R9A08G046_CLK_G, CLK_SEL_GE3D, G3L_DIV_GE3D, G3L_DIV_GE3D_STS,
+ dtable_1_32, 0, 0, 0, NULL),
DEF_FIXED("OSCCLK", R9A08G046_OSCCLK, CLK_EXTAL, 1, 1),
};
@@ -297,6 +364,42 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = {
MSTOP(BUS_REG0, BIT(0))),
DEF_MOD("wdt0_clk", R9A08G046_WDT0_CLK, R9A08G046_OSCCLK, 0x548, 1,
MSTOP(BUS_REG0, BIT(0))),
+ DEF_MOD("sdhi0_imclk", R9A08G046_SDHI0_IMCLK, CLK_SD0_DIV2, 0x554, 0,
+ MSTOP(BUS_PERI_COM, BIT(0))),
+ DEF_MOD("sdhi0_imclk2", R9A08G046_SDHI0_IMCLK2, CLK_SD0_DIV2, 0x554, 1,
+ MSTOP(BUS_PERI_COM, BIT(0))),
+ DEF_MOD("sdhi0_clk_hs", R9A08G046_SDHI0_CLK_HS, R9A08G046_CLK_SD0, 0x554, 2,
+ MSTOP(BUS_PERI_COM, BIT(0))),
+ DEF_MOD("sdhi0_iaclks", R9A08G046_SDHI0_IACLKS, R9A08G046_CLK_P1, 0x554, 3,
+ MSTOP(BUS_PERI_COM, BIT(0))),
+ DEF_MOD("sdhi0_iaclkm", R9A08G046_SDHI0_IACLKM, R9A08G046_CLK_P1, 0x554, 12,
+ MSTOP(BUS_PERI_COM, BIT(0))),
+ DEF_MOD("sdhi1_imclk", R9A08G046_SDHI1_IMCLK, CLK_SD1_DIV2, 0x554, 4,
+ MSTOP(BUS_PERI_COM, BIT(1))),
+ DEF_MOD("sdhi1_imclk2", R9A08G046_SDHI1_IMCLK2, CLK_SD1_DIV2, 0x554, 5,
+ MSTOP(BUS_PERI_COM, BIT(1))),
+ DEF_MOD("sdhi1_clk_hs", R9A08G046_SDHI1_CLK_HS, R9A08G046_CLK_SD1, 0x554, 6,
+ MSTOP(BUS_PERI_COM, BIT(1))),
+ DEF_MOD("sdhi1_iaclks", R9A08G046_SDHI1_IACLKS, R9A08G046_CLK_P1, 0x554, 7,
+ MSTOP(BUS_PERI_COM, BIT(1))),
+ DEF_MOD("sdhi1_iaclkm", R9A08G046_SDHI1_IACLKM, R9A08G046_CLK_P1, 0x554, 13,
+ MSTOP(BUS_PERI_COM, BIT(1))),
+ DEF_MOD("sdhi2_imclk", R9A08G046_SDHI2_IMCLK, CLK_SD2_DIV2, 0x554, 8,
+ MSTOP(BUS_PERI_COM, BIT(11))),
+ DEF_MOD("sdhi2_imclk2", R9A08G046_SDHI2_IMCLK2, CLK_SD2_DIV2, 0x554, 9,
+ MSTOP(BUS_PERI_COM, BIT(11))),
+ DEF_MOD("sdhi2_clk_hs", R9A08G046_SDHI2_CLK_HS, R9A08G046_CLK_SD2, 0x554, 10,
+ MSTOP(BUS_PERI_COM, BIT(11))),
+ DEF_MOD("sdhi2_iaclks", R9A08G046_SDHI2_IACLKS, R9A08G046_CLK_P1, 0x554, 11,
+ MSTOP(BUS_PERI_COM, BIT(11))),
+ DEF_MOD("sdhi2_iaclkm", R9A08G046_SDHI2_IACLKM, R9A08G046_CLK_P1, 0x554, 14,
+ MSTOP(BUS_PERI_COM, BIT(11))),
+ DEF_MOD("ge3d_clk", R9A08G046_GE3D_CLK, R9A08G046_CLK_G, 0x558, 0,
+ MSTOP(BUS_PERI_VIDEO, BIT(12))),
+ DEF_MOD("ge3d_axi_clk", R9A08G046_GE3D_AXI_CLK, R9A08G046_CLK_P1, 0x558, 1,
+ MSTOP(BUS_PERI_VIDEO, BIT(12))),
+ DEF_MOD("ge3d_ace_clk", R9A08G046_GE3D_ACE_CLK, R9A08G046_CLK_P1, 0x558, 2,
+ MSTOP(BUS_PERI_VIDEO, BIT(12))),
DEF_MOD("ssi0_pclk2", R9A08G046_SSI0_PCLK2, R9A08G046_CLK_P0, 0x570, 0,
MSTOP(BUS_MCPU1, BIT(10))),
DEF_MOD("ssi0_pclk_sfr", R9A08G046_SSI0_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 1,
@@ -313,6 +416,16 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = {
MSTOP(BUS_MCPU1, BIT(13))),
DEF_MOD("ssi3_pclk_sfr", R9A08G046_SSI3_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 7,
MSTOP(BUS_MCPU1, BIT(13))),
+ DEF_MOD("usb_u2h0_hclk", R9A08G046_USB_U2H0_HCLK, R9A08G046_CLK_P1, 0x578, 0,
+ MSTOP(BUS_PERI_COM, BIT(5))),
+ DEF_MOD("usb_u2h1_hclk", R9A08G046_USB_U2H1_HCLK, R9A08G046_CLK_P1, 0x578, 1,
+ MSTOP(BUS_PERI_COM, BIT(7))),
+ DEF_MOD("usb_u2p0_exr_cpuclk", R9A08G046_USB_U2P0_EXR_CPUCLK, R9A08G046_CLK_P1, 0x578, 2,
+ MSTOP(BUS_PERI_COM, BIT(6))),
+ DEF_MOD("usb_pclk", R9A08G046_USB_PCLK, R9A08G046_CLK_P1, 0x578, 3,
+ MSTOP(BUS_PERI_COM, BIT(4))),
+ DEF_MOD("usb_u2p1_exr_cpuclk", R9A08G046_USB_U2P1_EXR_CPUCLK, R9A08G046_CLK_P1, 0x578, 4,
+ MSTOP(BUS_PERI_COM, BIT(13))),
DEF_MOD("eth0_clk_axi", R9A08G046_ETH0_CLK_AXI, R9A08G046_CLK_P1, 0x57c, 0,
MSTOP(BUS_PERI_COM, BIT(2))),
DEF_MOD("eth1_clk_axi", R9A08G046_ETH1_CLK_AXI, R9A08G046_CLK_P1, 0x57c, 1,
@@ -412,10 +525,27 @@ static const struct rzg2l_reset r9a08g046_resets[] = {
DEF_RST(R9A08G046_DMAC_ARESETN, 0x82c, 0),
DEF_RST(R9A08G046_DMAC_RST_ASYNC, 0x82c, 1),
DEF_RST(R9A08G046_WDT0_PRESETN, 0x848, 0),
+ DEF_RST(R9A08G046_SDHI0_IXRST, 0x854, 0),
+ DEF_RST(R9A08G046_SDHI1_IXRST, 0x854, 1),
+ DEF_RST(R9A08G046_SDHI2_IXRST, 0x854, 2),
+ DEF_RST(R9A08G046_SDHI0_IXRSTAXIM, 0x854, 3),
+ DEF_RST(R9A08G046_SDHI0_IXRSTAXIS, 0x854, 4),
+ DEF_RST(R9A08G046_SDHI1_IXRSTAXIM, 0x854, 5),
+ DEF_RST(R9A08G046_SDHI1_IXRSTAXIS, 0x854, 6),
+ DEF_RST(R9A08G046_SDHI2_IXRSTAXIM, 0x854, 7),
+ DEF_RST(R9A08G046_SDHI2_IXRSTAXIS, 0x854, 8),
+ DEF_RST(R9A08G046_GE3D_RESETN, 0x858, 0),
+ DEF_RST(R9A08G046_GE3D_AXI_RESETN, 0x858, 1),
+ DEF_RST(R9A08G046_GE3D_ACE_RESETN, 0x858, 2),
DEF_RST(R9A08G046_SSI0_RST_M2_REG, 0x870, 0),
DEF_RST(R9A08G046_SSI1_RST_M2_REG, 0x870, 1),
DEF_RST(R9A08G046_SSI2_RST_M2_REG, 0x870, 2),
DEF_RST(R9A08G046_SSI3_RST_M2_REG, 0x870, 3),
+ DEF_RST(R9A08G046_USB_U2H0_HRESETN, 0x878, 0),
+ DEF_RST(R9A08G046_USB_U2H1_HRESETN, 0x878, 1),
+ DEF_RST(R9A08G046_USB_U2P0_EXL_SYSRST, 0x878, 2),
+ DEF_RST(R9A08G046_USB_PRESETN, 0x878, 3),
+ DEF_RST(R9A08G046_USB_U2P1_EXL_SYSRST, 0x878, 4),
DEF_RST(R9A08G046_ETH0_ARESET_N, 0x87c, 0),
DEF_RST(R9A08G046_ETH1_ARESET_N, 0x87c, 1),
DEF_RST(R9A08G046_I2C0_MRST, 0x880, 0),
diff --git a/drivers/clk/renesas/r9a09g047-cpg.c b/drivers/clk/renesas/r9a09g047-cpg.c
index 94158b6834e6..f576dd441a11 100644
--- a/drivers/clk/renesas/r9a09g047-cpg.c
+++ b/drivers/clk/renesas/r9a09g047-cpg.c
@@ -23,6 +23,8 @@ enum clk_ids {
CLK_AUDIO_EXTAL,
CLK_RTXIN,
CLK_QEXTAL,
+ CLK_AUDIO_CLKB,
+ CLK_AUDIO_CLKC,
/* PLL Clocks */
CLK_PLLCM33,
@@ -44,6 +46,7 @@ enum clk_ids {
CLK_SMUX2_XSPI_CLK1,
CLK_PLLCM33_XSPI,
CLK_PLLCLN_DIV2,
+ CLK_PLLCLN_DIV4,
CLK_PLLCLN_DIV8,
CLK_PLLCLN_DIV16,
CLK_PLLCLN_DIV20,
@@ -159,6 +162,8 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = {
DEF_INPUT("audio_extal", CLK_AUDIO_EXTAL),
DEF_INPUT("rtxin", CLK_RTXIN),
DEF_INPUT("qextal", CLK_QEXTAL),
+ DEF_INPUT("audio_clkb", CLK_AUDIO_CLKB),
+ DEF_INPUT("audio_clkc", CLK_AUDIO_CLKC),
/* PLL Clocks */
DEF_FIXED(".pllcm33", CLK_PLLCM33, CLK_QEXTAL, 200, 3),
@@ -183,6 +188,7 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = {
DEF_CSDIV(".pllcm33_xspi", CLK_PLLCM33_XSPI, CLK_SMUX2_XSPI_CLK1, CSDIV0_DIVCTL3,
dtable_2_16),
DEF_FIXED(".pllcln_div2", CLK_PLLCLN_DIV2, CLK_PLLCLN, 1, 2),
+ DEF_FIXED(".pllcln_div4", CLK_PLLCLN_DIV4, CLK_PLLCLN, 1, 4),
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),
@@ -194,6 +200,7 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = {
DEF_FIXED(".plldty_acpu_div2", CLK_PLLDTY_ACPU_DIV2, CLK_PLLDTY_ACPU, 1, 2),
DEF_FIXED(".plldty_acpu_div4", CLK_PLLDTY_ACPU_DIV4, CLK_PLLDTY_ACPU, 1, 4),
DEF_FIXED(".plldty_div8", CLK_PLLDTY_DIV8, CLK_PLLDTY, 1, 8),
+ DEF_FIXED(".plldty_div16", CLK_PLLDTY_DIV16, CLK_PLLDTY, 1, 16),
DEF_FIXED(".plleth_250_fix", CLK_PLLETH_DIV_250_FIX, CLK_PLLETH, 1, 4),
DEF_FIXED(".plleth_125_fix", CLK_PLLETH_DIV_125_FIX, CLK_PLLETH_DIV_250_FIX, 1, 2),
@@ -205,7 +212,6 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = {
DEF_SMUX(".smux2_gbe0_rxclk", CLK_SMUX2_GBE0_RXCLK, SSEL0_SELCTL3, smux2_gbe0_rxclk),
DEF_SMUX(".smux2_gbe1_txclk", CLK_SMUX2_GBE1_TXCLK, SSEL1_SELCTL0, smux2_gbe1_txclk),
DEF_SMUX(".smux2_gbe1_rxclk", CLK_SMUX2_GBE1_RXCLK, SSEL1_SELCTL1, smux2_gbe1_rxclk),
- DEF_FIXED(".plldty_div16", CLK_PLLDTY_DIV16, CLK_PLLDTY, 1, 16),
DEF_DDIV(".plldty_rcpu", CLK_PLLDTY_RCPU, CLK_PLLDTY, CDDIV3_DIVCTL2, dtable_2_64),
DEF_FIXED(".plldty_rcpu_div4", CLK_PLLDTY_RCPU_DIV4, CLK_PLLDTY_RCPU, 1, 4),
@@ -530,10 +536,110 @@ static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = {
BUS_MSTOP(3, BIT(4))),
DEF_MOD("ge3d_ace_clk", CLK_PLLDTY_ACPU_DIV2, 15, 2, 7, 18,
BUS_MSTOP(3, BIT(4))),
+ DEF_MOD("ssif_0_clk", CLK_PLLCLN_DIV8, 15, 5, 7, 21,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("scu_0_clk", CLK_PLLCLN_DIV8, 15, 6, 7, 22,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("scu_0_clkx2", CLK_PLLCLN_DIV4, 15, 7, 7, 23,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("dmacpp_0_clk", CLK_PLLCLN_DIV8, 15, 8, 7, 24,
+ BUS_MSTOP(2, BIT(5))),
+ DEF_MOD("adg_0_clks1", CLK_PLLCLN_DIV8, 15, 9, 7, 25,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_0_clk_195m", CLK_PLLCLN_DIV8, 15, 10, 7, 26,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_0_audio_clka", CLK_AUDIO_EXTAL, 15, 11, 7, 27,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_0_audio_clkb", CLK_AUDIO_CLKB, 15, 12, 7, 28,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_0_audio_clkc", CLK_AUDIO_CLKC, 15, 13, 7, 29,
+ BUS_MSTOP(2, BIT(2))),
DEF_MOD("tsu_1_pclk", CLK_QEXTAL, 16, 10, 8, 10,
BUS_MSTOP(2, BIT(15))),
+ DEF_MOD("adg_ssi0_clk", CLK_PLLCLN_DIV8, 22, 0, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi1_clk", CLK_PLLCLN_DIV8, 22, 1, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi2_clk", CLK_PLLCLN_DIV8, 22, 2, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi3_clk", CLK_PLLCLN_DIV8, 22, 3, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi4_clk", CLK_PLLCLN_DIV8, 22, 4, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi5_clk", CLK_PLLCLN_DIV8, 22, 5, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi6_clk", CLK_PLLCLN_DIV8, 22, 6, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi7_clk", CLK_PLLCLN_DIV8, 22, 7, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi8_clk", CLK_PLLCLN_DIV8, 22, 8, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("adg_ssi9_clk", CLK_PLLCLN_DIV8, 22, 9, -1, -1,
+ BUS_MSTOP(2, BIT(2))),
+ DEF_MOD("dvc0_clk", CLK_PLLCLN_DIV8, 23, 0, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("dvc1_clk", CLK_PLLCLN_DIV8, 23, 1, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("ctu0_mix0_clk", CLK_PLLCLN_DIV8, 23, 2, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("ctu1_mix1_clk", CLK_PLLCLN_DIV8, 23, 3, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src0_clk", CLK_PLLCLN_DIV8, 23, 4, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src1_clk", CLK_PLLCLN_DIV8, 23, 5, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src2_clk", CLK_PLLCLN_DIV8, 23, 6, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src3_clk", CLK_PLLCLN_DIV8, 23, 7, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src4_clk", CLK_PLLCLN_DIV8, 23, 8, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src5_clk", CLK_PLLCLN_DIV8, 23, 9, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src6_clk", CLK_PLLCLN_DIV8, 23, 10, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src7_clk", CLK_PLLCLN_DIV8, 23, 11, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src8_clk", CLK_PLLCLN_DIV8, 23, 12, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("src9_clk", CLK_PLLCLN_DIV8, 23, 13, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("scu_supply_clk", CLK_PLLCLN_DIV8, 23, 14, -1, -1,
+ BUS_MSTOP(2, BIT(0) | BIT(1))),
+ DEF_MOD("ssiu_supply_clk", CLK_PLLCLN_DIV8, 24, 0, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi0_clk", CLK_PLLCLN_DIV8, 24, 1, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi1_clk", CLK_PLLCLN_DIV8, 24, 2, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi2_clk", CLK_PLLCLN_DIV8, 24, 3, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi3_clk", CLK_PLLCLN_DIV8, 24, 4, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi4_clk", CLK_PLLCLN_DIV8, 24, 5, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi5_clk", CLK_PLLCLN_DIV8, 24, 6, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi6_clk", CLK_PLLCLN_DIV8, 24, 7, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi7_clk", CLK_PLLCLN_DIV8, 24, 8, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi8_clk", CLK_PLLCLN_DIV8, 24, 9, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
+ DEF_MOD("ssi9_clk", CLK_PLLCLN_DIV8, 24, 10, -1, -1,
+ BUS_MSTOP(2, BIT(3) | BIT(4))),
DEF_MOD("dsi_0_vclk2", CLK_SMUX2_DSI1_CLK, 25, 0, 10, 21,
BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("lvds_top_clk_ch0", CLK_PLLDSI0, 26, 0, 10, 22,
+ BUS_MSTOP(13, BIT(0))),
+ DEF_MOD("lvds_top_clk_ch1", CLK_PLLDSI1, 26, 1, 10, 23,
+ BUS_MSTOP(13, BIT(0))),
+ DEF_MOD("lvds_top_clk_dot_ch0", CLK_SMUX2_DSI0_CLK, 26, 2, 10, 24,
+ BUS_MSTOP(13, BIT(0))),
+ DEF_MOD("lvds_top_clk_dot_ch1", CLK_SMUX2_DSI1_CLK, 26, 3, 10, 25,
+ BUS_MSTOP(13, BIT(0))),
+ DEF_MOD("lvds_top_pclk", CLK_PLLDTY_DIV16, 26, 4, 10, 26,
+ BUS_MSTOP(13, BIT(0))),
DEF_MOD("lcdc_1_clk_a", CLK_PLLDTY_ACPU_DIV2, 26, 8, 10, 30,
BUS_MSTOP(13, BIT(5) | BIT(4) | BIT(3))),
DEF_MOD("lcdc_1_clk_p", CLK_PLLDTY_DIV16, 26, 9, 10, 31,
@@ -621,7 +727,22 @@ static const struct rzv2h_reset r9a09g047_resets[] __initconst = {
DEF_RST(13, 13, 6, 14), /* GE3D_RESETN */
DEF_RST(13, 14, 6, 15), /* GE3D_AXI_RESETN */
DEF_RST(13, 15, 6, 16), /* GE3D_ACE_RESETN */
+ DEF_RST(14, 1, 6, 18), /* SSIF_0_ASYNC_RESET_SSI */
+ DEF_RST(14, 2, 6, 19), /* SSIF_0_SYNC_RESET_SSI0 */
+ DEF_RST(14, 3, 6, 20), /* SSIF_0_SYNC_RESET_SSI1 */
+ DEF_RST(14, 4, 6, 21), /* SSIF_0_SYNC_RESET_SSI2 */
+ DEF_RST(14, 5, 6, 22), /* SSIF_0_SYNC_RESET_SSI3 */
+ DEF_RST(14, 6, 6, 23), /* SSIF_0_SYNC_RESET_SSI4 */
+ DEF_RST(14, 7, 6, 24), /* SSIF_0_SYNC_RESET_SSI5 */
+ DEF_RST(14, 8, 6, 25), /* SSIF_0_SYNC_RESET_SSI6 */
+ DEF_RST(14, 9, 6, 26), /* SSIF_0_SYNC_RESET_SSI7 */
+ DEF_RST(14, 10, 6, 27), /* SSIF_0_SYNC_RESET_SSI8 */
+ DEF_RST(14, 11, 6, 28), /* SSIF_0_SYNC_RESET_SSI9 */
+ DEF_RST(14, 12, 6, 29), /* SCU_0_RESET_SRU */
+ DEF_RST(14, 13, 6, 30), /* DMACpp_0_ARST */
+ DEF_RST(14, 14, 6, 31), /* ADG_0_RST_RESET_ADG */
DEF_RST(15, 8, 7, 9), /* TSU_1_PRESETN */
+ DEF_RST(17, 10, 8, 11), /* LVDS_TOP_RESET_N */
DEF_RST(17, 14, 8, 15), /* LCDC_1_RESET_N */
};
diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c
index f777601a23b9..5640c2035e5a 100644
--- a/drivers/clk/renesas/r9a09g077-cpg.c
+++ b/drivers/clk/renesas/r9a09g077-cpg.c
@@ -8,16 +8,23 @@
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
+#include <linux/clk/renesas.h>
#include <linux/device.h>
#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/math.h>
+#include <linux/module.h>
#include <linux/types.h>
+#include <linux/units.h>
#include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
#include <dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h>
#include "renesas-cpg-mssr.h"
+MODULE_IMPORT_NS("RZV2H_CPG");
+
#define RZT2H_REG_BLOCK_SHIFT 11
#define RZT2H_REG_OFFSET_MASK GENMASK(10, 0)
#define RZT2H_REG_CONF(block, offset) (((block) << RZT2H_REG_BLOCK_SHIFT) | \
@@ -66,11 +73,26 @@
#define DIVSCI2ASYNC CONF_PACK(SCKCR3, 10, 2)
#define DIVSCI3ASYNC CONF_PACK(SCKCR3, 12, 2)
#define DIVSCI4ASYNC CONF_PACK(SCKCR3, 14, 2)
+#define LCDCDIVSEL CONF_PACK(SCKCR3, 20, 4)
+
+#define PLL3EN FIELD_PREP_CONST(OFFSET_MASK, (0xc0))
+
+#define CPG_PLL_EN_EN BIT(0)
+#define CPG_PLL3_VCO_CTR0(x) ((x) + 0x4)
+#define CPG_PLL3_VCO_CTR0_PDIV GENMASK(21, 16)
+#define CPG_PLL3_VCO_CTR0_MDIV GENMASK(9, 0)
+#define CPG_PLL3_VCO_CTR1(x) ((x) + 0x8)
+#define CPG_PLL3_VCO_CTR1_KDIV GENMASK(31, 16)
+#define CPG_PLL3_VCO_CTR1_SDIV GENMASK(2, 0)
+#define CPG_PLL_MON(x) ((x) - 0x10)
+#define CPG_PLL_MON_LOCK BIT(0)
enum rzt2h_clk_types {
CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM, /* Clock with divider */
CLK_TYPE_RZT2H_MUX, /* Clock with clock source selector */
CLK_TYPE_RZT2H_FSELXSPI, /* Clock with FSELXSPIn source selector */
+ CLK_TYPE_RZT2H_PLL3, /* PLL3 Clock */
+ CLK_TYPE_RZT2H_LCDCDIV, /* LCDC divider clock */
};
#define DEF_DIV(_name, _id, _parent, _conf, _dtable) \
@@ -83,10 +105,51 @@ enum rzt2h_clk_types {
#define DEF_DIV_FSELXSPI(_name, _id, _parent, _conf, _dtable) \
DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_FSELXSPI, .conf = _conf, \
.parent = _parent, .dtable = _dtable, .flag = 0)
+#define DEF_PLL3(_name, _id, _parent, _conf) \
+ DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_PLL3, .conf = _conf, \
+ .parent = _parent)
+#define DEF_DIV_LCDC(_name, _id, _parent, _conf, _dtable) \
+ DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_LCDCDIV, .conf = _conf, \
+ .parent = _parent, .dtable = _dtable, .flag = CLK_SET_RATE_PARENT)
+
+struct pll_clk {
+ void __iomem *reg;
+ const struct rzv2h_pll_limits *limits;
+ struct device *dev;
+ struct rzv2h_pll_pars pll_parameters;
+ struct clk_hw hw;
+ unsigned long cur_rate;
+};
+
+#define to_pll(_hw) container_of(_hw, struct pll_clk, hw)
+
+struct r9a09g077_lcdc_div_clk {
+ const struct clk_div_table *dtable;
+ void __iomem *reg;
+ struct device *dev;
+ struct clk_hw hw;
+ u32 conf;
+ u8 divider;
+};
+
+#define to_lcdc_div_clk(_hw) \
+ container_of(_hw, struct r9a09g077_lcdc_div_clk, hw)
+
+#define RZT2H_MAX_LCDC_DIV_TABLES 16
+
+static const struct rzv2h_pll_limits r9a09g077_cpg_pll3_limits = {
+ .input_fref = 48 * MEGA,
+ .fout = { .min = 25 * MEGA, .max = 430 * MEGA },
+ .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA },
+ .m = { .min = 0x40, .max = 0x3ff },
+ .p = { .min = 0x2, .max = 0x8 },
+ .s = { .min = 0x0, .max = 0x6 },
+ .k = { .min = -32768, .max = 32767 },
+};
enum clk_ids {
/* Core Clock Outputs exported to DT */
- LAST_DT_CORE_CLK = R9A09G077_PCLKCAN,
+ LAST_DT_CORE_CLK = R9A09G077_PCLKRTC,
/* External Input Clocks */
CLK_EXTAL,
@@ -96,10 +159,12 @@ enum clk_ids {
CLK_PLL0,
CLK_PLL1,
CLK_PLL2,
+ CLK_PLL3,
CLK_PLL4,
CLK_SEL_CLK_PLL0,
CLK_SEL_CLK_PLL1,
CLK_SEL_CLK_PLL2,
+ CLK_SEL_CLK_PLL3,
CLK_SEL_CLK_PLL4,
CLK_PLL4D1,
CLK_PLL4D1_DIV3,
@@ -107,6 +172,7 @@ enum clk_ids {
CLK_PLL4D3,
CLK_PLL4D3_DIV10,
CLK_PLL4D3_DIV20,
+ CLK_PLL4D50,
CLK_SCI0ASYNC,
CLK_SCI1ASYNC,
CLK_SCI2ASYNC,
@@ -119,6 +185,7 @@ enum clk_ids {
CLK_SPI3ASYNC,
CLK_DIVSELXSPI0_SCKCR,
CLK_DIVSELXSPI1_SCKCR,
+ CLK_LCDDIVSEL,
/* Module Clocks */
MOD_CLK_BASE,
@@ -130,6 +197,26 @@ static const struct clk_div_table dtable_1_2[] = {
{0, 0},
};
+static const struct clk_div_table dtable_2_32[] = {
+ {0, 2},
+ {1, 4},
+ {2, 6},
+ {3, 8},
+ {4, 10},
+ {5, 12},
+ {6, 14},
+ {7, 16},
+ {8, 18},
+ {9, 20},
+ {10, 22},
+ {11, 24},
+ {12, 26},
+ {13, 28},
+ {14, 30},
+ {15, 32},
+ {0, 0},
+};
+
static const struct clk_div_table dtable_6_8_16_32_64[] = {
{6, 64},
{5, 32},
@@ -152,6 +239,7 @@ static const struct clk_div_table dtable_24_25_30_32[] = {
static const char * const sel_clk_pll0[] = { ".loco", ".pll0" };
static const char * const sel_clk_pll1[] = { ".loco", ".pll1" };
static const char * const sel_clk_pll2[] = { ".loco", ".pll2" };
+static const char * const sel_clk_pll3[] = { ".loco", ".pll3" };
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" };
@@ -173,10 +261,14 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY),
DEF_MUX(".sel_clk_pll2", CLK_SEL_CLK_PLL2, SEL_PLL,
sel_clk_pll2, ARRAY_SIZE(sel_clk_pll2), CLK_MUX_READ_ONLY),
+ DEF_MUX(".sel_clk_pll3", CLK_SEL_CLK_PLL3, SEL_PLL,
+ sel_clk_pll3, ARRAY_SIZE(sel_clk_pll3), CLK_MUX_READ_ONLY),
DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL,
sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY),
DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1),
+ DEF_FIXED(".pll4d50", CLK_PLL4D50, CLK_SEL_CLK_PLL4, 50, 1),
+ DEF_PLL3(".pll3", CLK_PLL3, CLK_PLL4D50, PLL3EN),
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),
@@ -229,6 +321,7 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1),
DEF_FIXED("PCLKAH", R9A09G077_CLK_PCLKAH, CLK_PLL4D1, 6, 1),
DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1),
+ DEF_FIXED("PCLKAL", R9A09G077_CLK_PCLKAL, CLK_PLL4D1, 24, 1),
DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1),
DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1),
DEF_FIXED("ETCLKA", R9A09G077_ETCLKA, CLK_SEL_CLK_PLL1, 5, 1),
@@ -242,6 +335,9 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
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),
+ DEF_DIV_LCDC("LCDC_CLKD", R9A09G077_LCDC_CLKD, CLK_SEL_CLK_PLL3, LCDCDIVSEL,
+ dtable_2_32),
+ DEF_FIXED("PCLKRTC", R9A09G077_PCLKRTC, CLK_EXTAL, 128, 1),
};
static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
@@ -272,6 +368,8 @@ static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC),
DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL),
DEF_MOD("spi3", 602, CLK_SPI3ASYNC),
+ DEF_MOD("rtc", 605, R9A09G077_CLK_PCLKL),
+ DEF_MOD("lcdc", 1204, R9A09G077_CLK_PCLKAL),
DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM),
DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM),
};
@@ -481,6 +579,276 @@ r9a09g077_cpg_fselxspi_div_clk_register(struct device *dev,
return hw->clk;
}
+static unsigned long r9a09g077_cpg_pll3_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ u32 ctr0, ctr1;
+ u8 pdiv, sdiv;
+ u64 rate;
+ u16 mdiv;
+ s16 kdiv;
+
+ ctr0 = readl(CPG_PLL3_VCO_CTR0(pll_clk->reg));
+ ctr1 = readl(CPG_PLL3_VCO_CTR1(pll_clk->reg));
+
+ pdiv = FIELD_GET(CPG_PLL3_VCO_CTR0_PDIV, ctr0);
+ mdiv = FIELD_GET(CPG_PLL3_VCO_CTR0_MDIV, ctr0);
+ kdiv = (s16)FIELD_GET(CPG_PLL3_VCO_CTR1_KDIV, ctr1);
+ sdiv = FIELD_GET(CPG_PLL3_VCO_CTR1_SDIV, ctr1);
+
+ rate = mul_u64_u32_shr(parent_rate, (mdiv << 16) + kdiv, 16 + sdiv);
+
+ return DIV_ROUND_CLOSEST_ULL(rate, pdiv);
+}
+
+static int r9a09g077_cpg_pll3_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ u64 rate_millihz;
+
+ if (req->rate == pll_clk->cur_rate)
+ return 0;
+
+ rate_millihz = mul_u32_u32(req->rate, MILLI);
+ if (!rzv2h_cpg_get_pll_pars(pll_clk->limits, &pll_clk->pll_parameters,
+ rate_millihz)) {
+ dev_dbg(pll_clk->dev,
+ "failed to determine rate for req->rate: %lu\n",
+ req->rate);
+ return -EINVAL;
+ }
+ req->rate = DIV_ROUND_CLOSEST_ULL(pll_clk->pll_parameters.freq_millihz, MILLI);
+ pll_clk->cur_rate = req->rate;
+
+ return 0;
+}
+
+static int r9a09g077_cpg_pll3_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzv2h_pll_pars *params = &pll_clk->pll_parameters;
+ void __iomem *offset = pll_clk->reg;
+ u32 val;
+ int ret;
+
+ /* Put PLL into standby mode */
+ writel(0, offset);
+ ret = readl_poll_timeout_atomic(CPG_PLL_MON(offset),
+ val, !(val & CPG_PLL_MON_LOCK),
+ 100, 2000);
+ if (ret) {
+ dev_err(pll_clk->dev, "Failed to put PLL into standby mode");
+ return ret;
+ }
+
+ /* Output clock setting 1 */
+ val = readl(CPG_PLL3_VCO_CTR0(offset));
+ FIELD_MODIFY(CPG_PLL3_VCO_CTR0_MDIV, &val, params->m);
+ FIELD_MODIFY(CPG_PLL3_VCO_CTR0_PDIV, &val, params->p);
+ writel(val, CPG_PLL3_VCO_CTR0(offset));
+
+ /* Output clock setting 2 */
+ val = readl(CPG_PLL3_VCO_CTR1(offset));
+ FIELD_MODIFY(CPG_PLL3_VCO_CTR1_KDIV, &val, params->k);
+ FIELD_MODIFY(CPG_PLL3_VCO_CTR1_SDIV, &val, params->s);
+ writel(val, CPG_PLL3_VCO_CTR1(offset));
+
+ writel(CPG_PLL_EN_EN, offset);
+
+ /* PLL normal mode transition, output clock stability check */
+ ret = readl_poll_timeout_atomic(CPG_PLL_MON(offset),
+ val, (val & CPG_PLL_MON_LOCK),
+ 100, 2000);
+ if (ret) {
+ writel(0, offset);
+ dev_err(pll_clk->dev, "Failed to put PLL into normal mode");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct clk_ops r9a09g077_cpg_pll3_ops = {
+ .recalc_rate = r9a09g077_cpg_pll3_clk_recalc_rate,
+ .determine_rate = r9a09g077_cpg_pll3_determine_rate,
+ .set_rate = r9a09g077_cpg_pll3_set_rate,
+};
+
+static struct clk * __init
+r9a09g077_cpg_pll3_clk_register(struct device *dev,
+ const struct cpg_core_clk *core,
+ void __iomem *addr,
+ struct cpg_mssr_pub *pub,
+ const struct rzv2h_pll_limits *limits)
+{
+ struct clk_init_data init = {};
+ const struct clk *parent;
+ const char *parent_name;
+ struct pll_clk *pll_clk;
+ int ret;
+
+ parent = pub->clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+ if (!pll_clk)
+ return ERR_PTR(-ENOMEM);
+
+ parent_name = __clk_get_name(parent);
+ init.name = core->name;
+ init.ops = &r9a09g077_cpg_pll3_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll_clk->dev = dev;
+ pll_clk->hw.init = &init;
+ pll_clk->reg = addr;
+ pll_clk->limits = limits;
+
+ ret = devm_clk_hw_register(dev, &pll_clk->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return pll_clk->hw.clk;
+}
+
+static int r9a09g077_cpg_lcdc_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct r9a09g077_lcdc_div_clk *dsi_div = to_lcdc_div_clk(hw);
+ struct clk_hw *mux_hw = clk_hw_get_parent(hw);
+ u8 table[RZT2H_MAX_LCDC_DIV_TABLES] = { 0 };
+ struct rzv2h_pll_div_pars dsi_params;
+ const struct clk_div_table *div;
+ struct pll_clk *pll_clk;
+ unsigned int i = 0;
+ u64 freq_millihz;
+
+ /* index 1 is always .pll3 in sel_clk_pll3[] */
+ pll_clk = to_pll(clk_hw_get_parent_by_index(mux_hw, 1));
+
+ for (div = dsi_div->dtable; div->div; div++) {
+ if (i >= RZT2H_MAX_LCDC_DIV_TABLES)
+ return -EINVAL;
+ table[i++] = div->div;
+ }
+
+ freq_millihz = mul_u32_u32(req->rate, MILLI);
+
+ if (!rzv2h_cpg_get_pll_divs_pars(pll_clk->limits, &dsi_params, table,
+ i, freq_millihz)) {
+ dev_err(dsi_div->dev,
+ "LCDC divider failed to determine rate for req->rate: %lu\n",
+ req->rate);
+ return -EINVAL;
+ }
+
+ req->rate = DIV_ROUND_CLOSEST_ULL(dsi_params.div.freq_millihz, MILLI);
+ req->best_parent_rate = req->rate * dsi_params.div.divider_value;
+ dsi_div->divider = dsi_params.div.divider_value;
+ pll_clk->cur_rate = req->best_parent_rate;
+ pll_clk->pll_parameters = dsi_params.pll;
+
+ return 0;
+}
+
+static int r9a09g077_cpg_lcdc_div_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct r9a09g077_lcdc_div_clk *dsi_div = to_lcdc_div_clk(hw);
+ const struct clk_div_table *clkt;
+ bool divider_found = false;
+ u32 val, shift;
+
+ for (clkt = dsi_div->dtable; clkt->div; clkt++) {
+ if (clkt->div == dsi_div->divider) {
+ divider_found = true;
+ break;
+ }
+ }
+
+ if (!divider_found)
+ return -EINVAL;
+
+ shift = GET_SHIFT(dsi_div->conf);
+ val = readl(dsi_div->reg);
+ val &= ~(clk_div_mask(GET_WIDTH(dsi_div->conf)) << shift);
+ val |= clkt->val << shift;
+ writel(val, dsi_div->reg);
+
+ return 0;
+}
+
+static unsigned long
+r9a09g077_cpg_lcdc_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct r9a09g077_lcdc_div_clk *dsi_div = to_lcdc_div_clk(hw);
+ u32 div;
+
+ div = readl(dsi_div->reg);
+ div >>= GET_SHIFT(dsi_div->conf);
+ div &= clk_div_mask(GET_WIDTH(dsi_div->conf));
+ div = dsi_div->dtable[div].div;
+
+ return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
+}
+
+static const struct clk_ops r9a09g077_cpg_lcdc_div_ops = {
+ .recalc_rate = r9a09g077_cpg_lcdc_div_recalc_rate,
+ .determine_rate = r9a09g077_cpg_lcdc_div_determine_rate,
+ .set_rate = r9a09g077_cpg_lcdc_div_set_rate,
+};
+
+static struct clk * __init
+r9a09g077_cpg_lcdc_div_clk_register(struct device *dev,
+ const struct cpg_core_clk *core,
+ void __iomem *addr,
+ struct cpg_mssr_pub *pub)
+{
+ struct r9a09g077_lcdc_div_clk *clk_hw_data;
+ struct clk_init_data init = {};
+ struct clk **clks = pub->clks;
+ const struct clk *parent;
+ const char *parent_name;
+ struct clk_hw *hw;
+ int ret;
+
+ parent = clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ clk_hw_data = devm_kzalloc(dev, sizeof(*clk_hw_data), GFP_KERNEL);
+ if (!clk_hw_data)
+ return ERR_PTR(-ENOMEM);
+
+ clk_hw_data->dtable = core->dtable;
+ clk_hw_data->reg = addr;
+ clk_hw_data->conf = core->conf;
+ clk_hw_data->dev = dev;
+ clk_hw_data->divider = 32; /* Initialize divider for LCDC */
+
+ parent_name = __clk_get_name(parent);
+ init.name = core->name;
+ init.ops = &r9a09g077_cpg_lcdc_div_ops;
+ init.flags = core->flag;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ hw = &clk_hw_data->hw;
+ hw->init = &init;
+ ret = devm_clk_hw_register(dev, hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return hw->clk;
+}
+
static struct clk * __init
r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
const struct cpg_mssr_info *info,
@@ -497,6 +865,11 @@ r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub);
case CLK_TYPE_RZT2H_FSELXSPI:
return r9a09g077_cpg_fselxspi_div_clk_register(dev, core, addr, pub);
+ case CLK_TYPE_RZT2H_PLL3:
+ return r9a09g077_cpg_pll3_clk_register(dev, core, pub->base1 + offset,
+ pub, &r9a09g077_cpg_pll3_limits);
+ case CLK_TYPE_RZT2H_LCDCDIV:
+ return r9a09g077_cpg_lcdc_div_clk_register(dev, core, addr, pub);
default:
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 5b84cbee030b..4ed056b18d31 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -253,6 +253,22 @@ static void cpg_rzt2h_mstp_write(struct cpg_mssr_priv *priv, u16 offset, u32 val
writel(value, base + RZT2H_MSTPCR_OFFSET(offset));
}
+static void cpg_rzt2h_mstp_delay(u32 idx, bool bit_valid)
+{
+ unsigned int mask = bit_valid ? GENMASK(31, 0) : GENMASK(31, 5);
+
+ if (idx == (MOD_CLK_PACK(1204) & mask)) {
+ /* LCDC needs 100 dummy reads, or 142us */
+ udelay(142);
+ } else if (idx == (MOD_CLK_PACK(605) & mask)) {
+ /* RTC needs 300 dummy reads, or 428us */
+ udelay(428);
+ } else {
+ /* default 7 dummy reads, or 10us */
+ udelay(10);
+ }
+}
+
static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
{
struct mstp_clock *clock = to_mstp_clock(hw);
@@ -312,7 +328,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
* register, we simply add a delay after the read operation.
*/
cpg_rzt2h_mstp_read(priv, priv->control_regs[reg]);
- udelay(10);
+ cpg_rzt2h_mstp_delay(clock->index, true);
return 0;
}
@@ -1142,7 +1158,7 @@ static int cpg_mssr_resume_noirq(struct device *dev)
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);
+ cpg_rzt2h_mstp_delay(reg * 32, false);
continue;
} else
writel(newval, priv->pub.base0 + priv->control_regs[reg]);
diff --git a/drivers/clk/renesas/rzv2h-cpg-lib.c b/drivers/clk/renesas/rzv2h-cpg-lib.c
new file mode 100644
index 000000000000..124239c7327e
--- /dev/null
+++ b/drivers/clk/renesas/rzv2h-cpg-lib.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZV2H CPG Library. This library provides common functions to calculate
+ * PLL parameters for the RZV2H SoC.
+ *
+ * Copyright (C) 2026 Renesas Electronics Corp.
+ *
+ */
+
+#include <linux/clk/renesas.h>
+#include <linux/export.h>
+#include <linux/math.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+/**
+ * rzv2h_cpg_get_pll_pars - Finds the best combination of PLL parameters
+ * for a given frequency.
+ *
+ * @limits: Pointer to the structure containing the limits for the PLL parameters
+ * @pars: Pointer to the structure where the best calculated PLL parameters values
+ * will be stored
+ * @freq_millihz: Target output frequency in millihertz
+ *
+ * This function calculates the best set of PLL parameters (M, K, P, S) to achieve
+ * the desired frequency.
+ * There is no direct formula to calculate the PLL parameters, as it's an open
+ * system of equations, therefore this function uses an iterative approach to
+ * determine the best solution. The best solution is one that minimizes the error
+ * (desired frequency - actual frequency).
+ *
+ * Return: true if a valid set of parameters values is found, false otherwise.
+ */
+bool rzv2h_cpg_get_pll_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_pars *pars, u64 freq_millihz)
+{
+ unsigned long input_fref = limits->input_fref ?: (24 * MEGA);
+ u64 fout_min_millihz = mul_u32_u32(limits->fout.min, MILLI);
+ u64 fout_max_millihz = mul_u32_u32(limits->fout.max, MILLI);
+ struct rzv2h_pll_pars p, best;
+
+ if (freq_millihz > fout_max_millihz ||
+ freq_millihz < fout_min_millihz)
+ return false;
+
+ /* Initialize best error to maximum possible value */
+ best.error_millihz = S64_MAX;
+
+ for (p.p = limits->p.min; p.p <= limits->p.max; p.p++) {
+ u32 fref = input_fref / p.p;
+ u16 divider;
+
+ for (divider = 1 << limits->s.min, p.s = limits->s.min;
+ p.s <= limits->s.max; p.s++, divider <<= 1) {
+ for (p.m = limits->m.min; p.m <= limits->m.max; p.m++) {
+ u64 output_m, output_k_range;
+ s64 pll_k, output_k;
+ u64 fvco, output;
+
+ /*
+ * The frequency generated by the PLL + divider
+ * is calculated as follows:
+ *
+ * With:
+ * Freq = Ffout = Ffvco / 2^(pll_s)
+ * Ffvco = (pll_m + (pll_k / 65536)) * Ffref
+ * Ffref = 24MHz / pll_p
+ *
+ * Freq can also be rewritten as:
+ * Freq = Ffvco / 2^(pll_s)
+ * = ((pll_m + (pll_k / 65536)) * Ffref) / 2^(pll_s)
+ * = (pll_m * Ffref) / 2^(pll_s) + ((pll_k / 65536) * Ffref) / 2^(pll_s)
+ * = output_m + output_k
+ *
+ * Every parameter has been determined at this
+ * point, but pll_k.
+ *
+ * Considering that:
+ * limits->k.min <= pll_k <= limits->k.max
+ * Then:
+ * -0.5 <= (pll_k / 65536) < 0.5
+ * Therefore:
+ * -Ffref / (2 * 2^(pll_s)) <= output_k < Ffref / (2 * 2^(pll_s))
+ */
+
+ /* Compute output M component (in mHz) */
+ output_m = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(p.m, fref) * MILLI,
+ divider);
+ /* Compute range for output K (in mHz) */
+ output_k_range = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(fref, MILLI),
+ 2 * divider);
+ /*
+ * No point in continuing if we can't achieve
+ * the desired frequency
+ */
+ if (freq_millihz < (output_m - output_k_range) ||
+ freq_millihz >= (output_m + output_k_range)) {
+ continue;
+ }
+
+ /*
+ * Compute the K component
+ *
+ * Since:
+ * Freq = output_m + output_k
+ * Then:
+ * output_k = Freq - output_m
+ * = ((pll_k / 65536) * Ffref) / 2^(pll_s)
+ * Therefore:
+ * pll_k = (output_k * 65536 * 2^(pll_s)) / Ffref
+ */
+ output_k = freq_millihz - output_m;
+ pll_k = div_s64(output_k * 65536ULL * divider,
+ fref);
+ pll_k = DIV_S64_ROUND_CLOSEST(pll_k, MILLI);
+
+ /* Validate K value within allowed limits */
+ if (pll_k < limits->k.min ||
+ pll_k > limits->k.max)
+ continue;
+
+ p.k = pll_k;
+
+ /* Compute (Ffvco * 65536) */
+ fvco = mul_u32_u32(p.m * 65536 + p.k, fref);
+ if (fvco < mul_u32_u32(limits->fvco.min, 65536) ||
+ fvco > mul_u32_u32(limits->fvco.max, 65536))
+ continue;
+
+ /* PLL_M component of (output * 65536 * PLL_P) */
+ output = mul_u32_u32(p.m * 65536, input_fref);
+ /* PLL_K component of (output * 65536 * PLL_P) */
+ output += p.k * input_fref;
+ /* Make it in mHz */
+ output *= MILLI;
+ output = DIV_U64_ROUND_CLOSEST(output, 65536 * p.p * divider);
+
+ /* Check output frequency against limits */
+ if (output < fout_min_millihz ||
+ output > fout_max_millihz)
+ continue;
+
+ p.error_millihz = freq_millihz - output;
+ p.freq_millihz = output;
+
+ /* If an exact match is found, return immediately */
+ if (p.error_millihz == 0) {
+ *pars = p;
+ return true;
+ }
+
+ /* Update best match if error is smaller */
+ if (abs(best.error_millihz) > abs(p.error_millihz))
+ best = p;
+ }
+ }
+ }
+
+ /* If no valid parameters were found, return false */
+ if (best.error_millihz == S64_MAX)
+ return false;
+
+ *pars = best;
+ return true;
+}
+EXPORT_SYMBOL_NS_GPL(rzv2h_cpg_get_pll_pars, "RZV2H_CPG");
+
+/*
+ * rzv2h_cpg_get_pll_divs_pars - Finds the best combination of PLL parameters
+ * and divider value for a given frequency.
+ *
+ * @limits: Pointer to the structure containing the limits for the PLL parameters
+ * @pars: Pointer to the structure where the best calculated PLL parameters and
+ * divider values will be stored
+ * @table: Pointer to the array of valid divider values
+ * @table_size: Size of the divider values array
+ * @freq_millihz: Target output frequency in millihertz
+ *
+ * This function calculates the best set of PLL parameters (M, K, P, S) and divider
+ * value to achieve the desired frequency. See rzv2h_cpg_get_pll_pars() for more
+ * details on how the PLL parameters are calculated.
+ *
+ * freq_millihz is the desired frequency generated by the PLL followed by a
+ * a gear.
+ */
+bool rzv2h_cpg_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const u8 *table, u8 table_size, u64 freq_millihz)
+{
+ struct rzv2h_pll_div_pars p, best;
+
+ best.div.error_millihz = S64_MAX;
+ p.div.error_millihz = S64_MAX;
+ for (unsigned int i = 0; i < table_size; i++) {
+ if (!rzv2h_cpg_get_pll_pars(limits, &p.pll, freq_millihz * table[i]))
+ continue;
+
+ p.div.divider_value = table[i];
+ p.div.freq_millihz = DIV_U64_ROUND_CLOSEST(p.pll.freq_millihz, table[i]);
+ p.div.error_millihz = freq_millihz - p.div.freq_millihz;
+
+ if (p.div.error_millihz == 0) {
+ *pars = p;
+ return true;
+ }
+
+ if (abs(best.div.error_millihz) > abs(p.div.error_millihz))
+ best = p;
+ }
+
+ if (best.div.error_millihz == S64_MAX)
+ return false;
+
+ *pars = best;
+ return true;
+}
+EXPORT_SYMBOL_NS_GPL(rzv2h_cpg_get_pll_divs_pars, "RZV2H_CPG");
diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c
index e271c04cee34..738dfafc6d9c 100644
--- a/drivers/clk/renesas/rzv2h-cpg.c
+++ b/drivers/clk/renesas/rzv2h-cpg.c
@@ -218,212 +218,9 @@ struct rzv2h_plldsi_div_clk {
#define to_plldsi_div_clk(_hw) \
container_of(_hw, struct rzv2h_plldsi_div_clk, hw)
-#define RZ_V2H_OSC_CLK_IN_MEGA (24 * MEGA)
#define RZV2H_MAX_DIV_TABLES (16)
/**
- * rzv2h_get_pll_pars - Finds the best combination of PLL parameters
- * for a given frequency.
- *
- * @limits: Pointer to the structure containing the limits for the PLL parameters
- * @pars: Pointer to the structure where the best calculated PLL parameters values
- * will be stored
- * @freq_millihz: Target output frequency in millihertz
- *
- * This function calculates the best set of PLL parameters (M, K, P, S) to achieve
- * the desired frequency.
- * There is no direct formula to calculate the PLL parameters, as it's an open
- * system of equations, therefore this function uses an iterative approach to
- * determine the best solution. The best solution is one that minimizes the error
- * (desired frequency - actual frequency).
- *
- * Return: true if a valid set of parameters values is found, false otherwise.
- */
-bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_pars *pars, u64 freq_millihz)
-{
- u64 fout_min_millihz = mul_u32_u32(limits->fout.min, MILLI);
- u64 fout_max_millihz = mul_u32_u32(limits->fout.max, MILLI);
- struct rzv2h_pll_pars p, best;
-
- if (freq_millihz > fout_max_millihz ||
- freq_millihz < fout_min_millihz)
- return false;
-
- /* Initialize best error to maximum possible value */
- best.error_millihz = S64_MAX;
-
- for (p.p = limits->p.min; p.p <= limits->p.max; p.p++) {
- u32 fref = RZ_V2H_OSC_CLK_IN_MEGA / p.p;
- u16 divider;
-
- for (divider = 1 << limits->s.min, p.s = limits->s.min;
- p.s <= limits->s.max; p.s++, divider <<= 1) {
- for (p.m = limits->m.min; p.m <= limits->m.max; p.m++) {
- u64 output_m, output_k_range;
- s64 pll_k, output_k;
- u64 fvco, output;
-
- /*
- * The frequency generated by the PLL + divider
- * is calculated as follows:
- *
- * With:
- * Freq = Ffout = Ffvco / 2^(pll_s)
- * Ffvco = (pll_m + (pll_k / 65536)) * Ffref
- * Ffref = 24MHz / pll_p
- *
- * Freq can also be rewritten as:
- * Freq = Ffvco / 2^(pll_s)
- * = ((pll_m + (pll_k / 65536)) * Ffref) / 2^(pll_s)
- * = (pll_m * Ffref) / 2^(pll_s) + ((pll_k / 65536) * Ffref) / 2^(pll_s)
- * = output_m + output_k
- *
- * Every parameter has been determined at this
- * point, but pll_k.
- *
- * Considering that:
- * limits->k.min <= pll_k <= limits->k.max
- * Then:
- * -0.5 <= (pll_k / 65536) < 0.5
- * Therefore:
- * -Ffref / (2 * 2^(pll_s)) <= output_k < Ffref / (2 * 2^(pll_s))
- */
-
- /* Compute output M component (in mHz) */
- output_m = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(p.m, fref) * MILLI,
- divider);
- /* Compute range for output K (in mHz) */
- output_k_range = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(fref, MILLI),
- 2 * divider);
- /*
- * No point in continuing if we can't achieve
- * the desired frequency
- */
- if (freq_millihz < (output_m - output_k_range) ||
- freq_millihz >= (output_m + output_k_range)) {
- continue;
- }
-
- /*
- * Compute the K component
- *
- * Since:
- * Freq = output_m + output_k
- * Then:
- * output_k = Freq - output_m
- * = ((pll_k / 65536) * Ffref) / 2^(pll_s)
- * Therefore:
- * pll_k = (output_k * 65536 * 2^(pll_s)) / Ffref
- */
- output_k = freq_millihz - output_m;
- pll_k = div_s64(output_k * 65536ULL * divider,
- fref);
- pll_k = DIV_S64_ROUND_CLOSEST(pll_k, MILLI);
-
- /* Validate K value within allowed limits */
- if (pll_k < limits->k.min ||
- pll_k > limits->k.max)
- continue;
-
- p.k = pll_k;
-
- /* Compute (Ffvco * 65536) */
- fvco = mul_u32_u32(p.m * 65536 + p.k, fref);
- if (fvco < mul_u32_u32(limits->fvco.min, 65536) ||
- fvco > mul_u32_u32(limits->fvco.max, 65536))
- continue;
-
- /* PLL_M component of (output * 65536 * PLL_P) */
- output = mul_u32_u32(p.m * 65536, RZ_V2H_OSC_CLK_IN_MEGA);
- /* PLL_K component of (output * 65536 * PLL_P) */
- output += p.k * RZ_V2H_OSC_CLK_IN_MEGA;
- /* Make it in mHz */
- output *= MILLI;
- output = DIV_U64_ROUND_CLOSEST(output, 65536 * p.p * divider);
-
- /* Check output frequency against limits */
- if (output < fout_min_millihz ||
- output > fout_max_millihz)
- continue;
-
- p.error_millihz = freq_millihz - output;
- p.freq_millihz = output;
-
- /* If an exact match is found, return immediately */
- if (p.error_millihz == 0) {
- *pars = p;
- return true;
- }
-
- /* Update best match if error is smaller */
- if (abs(best.error_millihz) > abs(p.error_millihz))
- best = p;
- }
- }
- }
-
- /* If no valid parameters were found, return false */
- if (best.error_millihz == S64_MAX)
- return false;
-
- *pars = best;
- return true;
-}
-EXPORT_SYMBOL_NS_GPL(rzv2h_get_pll_pars, "RZV2H_CPG");
-
-/*
- * rzv2h_get_pll_divs_pars - Finds the best combination of PLL parameters
- * and divider value for a given frequency.
- *
- * @limits: Pointer to the structure containing the limits for the PLL parameters
- * @pars: Pointer to the structure where the best calculated PLL parameters and
- * divider values will be stored
- * @table: Pointer to the array of valid divider values
- * @table_size: Size of the divider values array
- * @freq_millihz: Target output frequency in millihertz
- *
- * This function calculates the best set of PLL parameters (M, K, P, S) and divider
- * value to achieve the desired frequency. See rzv2h_get_pll_pars() for more details
- * on how the PLL parameters are calculated.
- *
- * freq_millihz is the desired frequency generated by the PLL followed by a
- * a gear.
- */
-bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_div_pars *pars,
- const u8 *table, u8 table_size, u64 freq_millihz)
-{
- struct rzv2h_pll_div_pars p, best;
-
- best.div.error_millihz = S64_MAX;
- p.div.error_millihz = S64_MAX;
- for (unsigned int i = 0; i < table_size; i++) {
- if (!rzv2h_get_pll_pars(limits, &p.pll, freq_millihz * table[i]))
- continue;
-
- p.div.divider_value = table[i];
- p.div.freq_millihz = DIV_U64_ROUND_CLOSEST(p.pll.freq_millihz, table[i]);
- p.div.error_millihz = freq_millihz - p.div.freq_millihz;
-
- if (p.div.error_millihz == 0) {
- *pars = p;
- return true;
- }
-
- if (abs(best.div.error_millihz) > abs(p.div.error_millihz))
- best = p;
- }
-
- if (best.div.error_millihz == S64_MAX)
- return false;
-
- *pars = best;
- return true;
-}
-EXPORT_SYMBOL_NS_GPL(rzv2h_get_pll_divs_pars, "RZV2H_CPG");
-
-/**
* struct rzv2h_plldsi_mux_clk - PLL DSI MUX clock
*
* @priv: CPG private data
diff --git a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h
index c4863e444458..aa47685f329a 100644
--- a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h
+++ b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h
@@ -34,5 +34,7 @@
#define R9A09G077_XSPI_CLK0 22
#define R9A09G077_XSPI_CLK1 23
#define R9A09G077_PCLKCAN 24
+#define R9A09G077_LCDC_CLKD 25
+#define R9A09G077_PCLKRTC 26
#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 0d53f1e65077..1c73d0dcef18 100644
--- a/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h
+++ b/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h
@@ -34,5 +34,7 @@
#define R9A09G087_XSPI_CLK0 22
#define R9A09G087_XSPI_CLK1 23
#define R9A09G087_PCLKCAN 24
+#define R9A09G087_LCDC_CLKD 25
+#define R9A09G087_PCLKRTC 26
#endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G087_CPG_H__ */
diff --git a/include/linux/clk/renesas.h b/include/linux/clk/renesas.h
index 0949400f44de..c9495558cd5c 100644
--- a/include/linux/clk/renesas.h
+++ b/include/linux/clk/renesas.h
@@ -53,6 +53,9 @@ static inline void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) { }
* various parameters used to configure a PLL. These limits ensure
* the PLL operates within valid and stable ranges.
*
+ * @input_fref: Reference input frequency to the PLL (in Hz). If set
+ * to 0, a default value of 24MHz is used.
+ *
* @fout: Output frequency range (in MHz)
* @fout.min: Minimum allowed output frequency
* @fout.max: Maximum allowed output frequency
@@ -78,6 +81,8 @@ static inline void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) { }
* @k.max: Maximum delta-sigma value
*/
struct rzv2h_pll_limits {
+ u32 input_fref;
+
struct {
u32 min;
u32 max;
@@ -184,28 +189,31 @@ struct rzv2h_pll_div_pars {
.k = { .min = -32768, .max = 32767 }, \
} \
-#ifdef CONFIG_CLK_RZV2H
-bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_pars *pars, u64 freq_millihz);
+#ifdef CONFIG_CLK_RZV2H_CPG_LIB
+bool rzv2h_cpg_get_pll_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_pars *pars, u64 freq_millihz);
-bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_div_pars *pars,
- const u8 *table, u8 table_size, u64 freq_millihz);
+bool rzv2h_cpg_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const u8 *table, u8 table_size, u64 freq_millihz);
#else
-static inline bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_pars *pars,
- u64 freq_millihz)
+static inline bool rzv2h_cpg_get_pll_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_pars *pars,
+ u64 freq_millihz)
{
return false;
}
-static inline bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_div_pars *pars,
- const u8 *table, u8 table_size,
- u64 freq_millihz)
+static inline bool rzv2h_cpg_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const u8 *table, u8 table_size,
+ u64 freq_millihz)
{
return false;
}
#endif
+#define rzv2h_get_pll_pars rzv2h_cpg_get_pll_pars
+#define rzv2h_get_pll_divs_pars rzv2h_cpg_get_pll_divs_pars
+
#endif