This commit is contained in:
Mark Brown
2026-07-31 14:45:08 +01:00
15 changed files with 913 additions and 223 deletions
@@ -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: |
@@ -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
+4 -2
View File
@@ -23103,10 +23103,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
+6
View File
@@ -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
+1
View File
@@ -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
+9
View File
@@ -77,6 +77,7 @@ enum clk_ids {
CLK_SEL_PLL4,
CLK_P1_DIV2,
CLK_P3_DIV2,
CLK_P4_DIV2,
CLK_SD0_DIV4,
CLK_SD1_DIV4,
CLK_SD2_DIV4,
@@ -172,6 +173,8 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = {
DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS,
dtable_1_32, 0, 0, 0, NULL),
DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2),
DEF_FIXED("P4", R9A08G045_CLK_P4, CLK_PLL2_DIV2, 1, 5),
DEF_FIXED("P4_DIV2", CLK_P4_DIV2, R9A08G045_CLK_P4, 1, 2),
DEF_FIXED("P5", R9A08G045_CLK_P5, CLK_PLL2_DIV2, 1, 4),
DEF_FIXED("ZT", R9A08G045_CLK_ZT, CLK_PLL3_DIV2_8, 1, 1),
DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2),
@@ -274,6 +277,10 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = {
MSTOP(BUS_MCPU2, BIT(5))),
DEF_MOD("scif5_clk_pck", R9A08G045_SCIF5_CLK_PCK, R9A08G045_CLK_P0, 0x584, 5,
MSTOP(BUS_MCPU3, BIT(4))),
DEF_MOD("canfd_pclk", R9A08G045_CANFD_PCLK, CLK_P4_DIV2, 0x594, 0,
MSTOP(BUS_MCPU2, BIT(9))),
DEF_MOD("canfd_clk_ram", R9A08G045_CANFD_CLK_RAM, R9A08G045_CLK_P4, 0x594, 1,
MSTOP(BUS_MCPU2, BIT(9))),
DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0,
MSTOP(BUS_PERI_CPU, BIT(6))),
DEF_MOD("adc_adclk", R9A08G045_ADC_ADCLK, R9A08G045_CLK_TSU, 0x5a8, 0,
@@ -324,6 +331,8 @@ static const struct rzg2l_reset r9a08g045_resets[] = {
DEF_RST(R9A08G045_SCIF3_RST_SYSTEM_N, 0x884, 3),
DEF_RST(R9A08G045_SCIF4_RST_SYSTEM_N, 0x884, 4),
DEF_RST(R9A08G045_SCIF5_RST_SYSTEM_N, 0x884, 5),
DEF_RST(R9A08G045_CANFD_RSTP_N, 0x894, 0),
DEF_RST(R9A08G045_CANFD_RSTC_N, 0x894, 1),
DEF_RST(R9A08G045_GPIO_RSTN, 0x898, 0),
DEF_RST(R9A08G045_GPIO_PORT_RESETN, 0x898, 1),
DEF_RST(R9A08G045_GPIO_SPARE_RESETN, 0x898, 2),
+130
View File
@@ -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),
+122 -1
View File
@@ -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 */
};
+374 -1
View File
@@ -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);
}
+18 -2
View File
@@ -252,6 +252,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);
@@ -311,7 +327,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;
}
@@ -1141,7 +1157,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]);
+217
View File
@@ -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");
-203
View File
@@ -217,211 +217,8 @@ 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
*
@@ -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__ */
@@ -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__ */
+21 -13
View File
@@ -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