17839a050SYann Gautier /* 2964e5ff1SNicolas Le Bayon * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved 37839a050SYann Gautier * 47839a050SYann Gautier * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 57839a050SYann Gautier */ 67839a050SYann Gautier 77839a050SYann Gautier #include <assert.h> 87839a050SYann Gautier #include <errno.h> 97839a050SYann Gautier #include <stdint.h> 1039b6cc66SAntonio Nino Diaz #include <stdio.h> 1109d40e0eSAntonio Nino Diaz 1209d40e0eSAntonio Nino Diaz #include <arch.h> 1309d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1409d40e0eSAntonio Nino Diaz #include <common/debug.h> 1552a616b4SAndre Przywara #include <common/fdt_wrappers.h> 1633667d29SYann Gautier #include <drivers/clk.h> 1709d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 18447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h> 1909d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h> 2009d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h> 2109d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h> 2209d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 230d21680cSYann Gautier #include <lib/spinlock.h> 2409d40e0eSAntonio Nino Diaz #include <lib/utils_def.h> 25964e5ff1SNicolas Le Bayon #include <libfdt.h> 2609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 2709d40e0eSAntonio Nino Diaz 28964e5ff1SNicolas Le Bayon #include <platform_def.h> 29964e5ff1SNicolas Le Bayon 307839a050SYann Gautier #define MAX_HSI_HZ 64000000 310d21680cSYann Gautier #define USB_PHY_48_MHZ 48000000 327839a050SYann Gautier 33dfdb057aSYann Gautier #define TIMEOUT_US_200MS U(200000) 34dfdb057aSYann Gautier #define TIMEOUT_US_1S U(1000000) 357839a050SYann Gautier 36dfdb057aSYann Gautier #define PLLRDY_TIMEOUT TIMEOUT_US_200MS 37dfdb057aSYann Gautier #define CLKSRC_TIMEOUT TIMEOUT_US_200MS 38dfdb057aSYann Gautier #define CLKDIV_TIMEOUT TIMEOUT_US_200MS 39dfdb057aSYann Gautier #define HSIDIV_TIMEOUT TIMEOUT_US_200MS 40dfdb057aSYann Gautier #define OSCRDY_TIMEOUT TIMEOUT_US_1S 417839a050SYann Gautier 42f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = { 43f66358afSYann Gautier [_LSI] = "clk-lsi", 44f66358afSYann Gautier [_LSE] = "clk-lse", 45f66358afSYann Gautier [_HSI] = "clk-hsi", 46f66358afSYann Gautier [_HSE] = "clk-hse", 47f66358afSYann Gautier [_CSI] = "clk-csi", 48f66358afSYann Gautier [_I2S_CKIN] = "i2s_ckin", 49f66358afSYann Gautier }; 50f66358afSYann Gautier 517839a050SYann Gautier enum stm32mp1_parent_id { 527839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */ 537839a050SYann Gautier 547839a050SYann Gautier /* Other parent source */ 557839a050SYann Gautier _HSI_KER = NB_OSC, 567839a050SYann Gautier _HSE_KER, 577839a050SYann Gautier _HSE_KER_DIV2, 58cbd2e8a6SGabriel Fernandez _HSE_RTC, 597839a050SYann Gautier _CSI_KER, 607839a050SYann Gautier _PLL1_P, 617839a050SYann Gautier _PLL1_Q, 627839a050SYann Gautier _PLL1_R, 637839a050SYann Gautier _PLL2_P, 647839a050SYann Gautier _PLL2_Q, 657839a050SYann Gautier _PLL2_R, 667839a050SYann Gautier _PLL3_P, 677839a050SYann Gautier _PLL3_Q, 687839a050SYann Gautier _PLL3_R, 697839a050SYann Gautier _PLL4_P, 707839a050SYann Gautier _PLL4_Q, 717839a050SYann Gautier _PLL4_R, 727839a050SYann Gautier _ACLK, 737839a050SYann Gautier _PCLK1, 747839a050SYann Gautier _PCLK2, 757839a050SYann Gautier _PCLK3, 767839a050SYann Gautier _PCLK4, 777839a050SYann Gautier _PCLK5, 787839a050SYann Gautier _HCLK6, 797839a050SYann Gautier _HCLK2, 807839a050SYann Gautier _CK_PER, 817839a050SYann Gautier _CK_MPU, 82b053a22eSYann Gautier _CK_MCU, 830d21680cSYann Gautier _USB_PHY_48, 847839a050SYann Gautier _PARENT_NB, 857839a050SYann Gautier _UNKNOWN_ID = 0xff, 867839a050SYann Gautier }; 877839a050SYann Gautier 880d21680cSYann Gautier /* Lists only the parent clock we are interested in */ 897839a050SYann Gautier enum stm32mp1_parent_sel { 900d21680cSYann Gautier _I2C12_SEL, 910d21680cSYann Gautier _I2C35_SEL, 920d21680cSYann Gautier _STGEN_SEL, 937839a050SYann Gautier _I2C46_SEL, 940d21680cSYann Gautier _SPI6_SEL, 95d4151d2fSYann Gautier _UART1_SEL, 960d21680cSYann Gautier _RNG1_SEL, 977839a050SYann Gautier _UART6_SEL, 987839a050SYann Gautier _UART24_SEL, 997839a050SYann Gautier _UART35_SEL, 1007839a050SYann Gautier _UART78_SEL, 1017839a050SYann Gautier _SDMMC12_SEL, 1027839a050SYann Gautier _SDMMC3_SEL, 1037839a050SYann Gautier _QSPI_SEL, 1047839a050SYann Gautier _FMC_SEL, 105d4151d2fSYann Gautier _AXIS_SEL, 106d4151d2fSYann Gautier _MCUS_SEL, 1077839a050SYann Gautier _USBPHY_SEL, 1087839a050SYann Gautier _USBO_SEL, 1098fbcd9e4SEtienne Carriere _MPU_SEL, 110288f5cf2SYann Gautier _CKPER_SEL, 111016af006SEtienne Carriere _RTC_SEL, 1127839a050SYann Gautier _PARENT_SEL_NB, 1137839a050SYann Gautier _UNKNOWN_SEL = 0xff, 1147839a050SYann Gautier }; 1157839a050SYann Gautier 1168fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */ 1178fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = { 1188fbcd9e4SEtienne Carriere [_HSE] = CK_HSE, 1198fbcd9e4SEtienne Carriere [_HSI] = CK_HSI, 1208fbcd9e4SEtienne Carriere [_CSI] = CK_CSI, 1218fbcd9e4SEtienne Carriere [_LSE] = CK_LSE, 1228fbcd9e4SEtienne Carriere [_LSI] = CK_LSI, 1238fbcd9e4SEtienne Carriere [_I2S_CKIN] = _UNKNOWN_ID, 1248fbcd9e4SEtienne Carriere [_USB_PHY_48] = _UNKNOWN_ID, 1258fbcd9e4SEtienne Carriere [_HSI_KER] = CK_HSI, 1268fbcd9e4SEtienne Carriere [_HSE_KER] = CK_HSE, 1278fbcd9e4SEtienne Carriere [_HSE_KER_DIV2] = CK_HSE_DIV2, 128cbd2e8a6SGabriel Fernandez [_HSE_RTC] = _UNKNOWN_ID, 1298fbcd9e4SEtienne Carriere [_CSI_KER] = CK_CSI, 1308fbcd9e4SEtienne Carriere [_PLL1_P] = PLL1_P, 1318fbcd9e4SEtienne Carriere [_PLL1_Q] = PLL1_Q, 1328fbcd9e4SEtienne Carriere [_PLL1_R] = PLL1_R, 1338fbcd9e4SEtienne Carriere [_PLL2_P] = PLL2_P, 1348fbcd9e4SEtienne Carriere [_PLL2_Q] = PLL2_Q, 1358fbcd9e4SEtienne Carriere [_PLL2_R] = PLL2_R, 1368fbcd9e4SEtienne Carriere [_PLL3_P] = PLL3_P, 1378fbcd9e4SEtienne Carriere [_PLL3_Q] = PLL3_Q, 1388fbcd9e4SEtienne Carriere [_PLL3_R] = PLL3_R, 1398fbcd9e4SEtienne Carriere [_PLL4_P] = PLL4_P, 1408fbcd9e4SEtienne Carriere [_PLL4_Q] = PLL4_Q, 1418fbcd9e4SEtienne Carriere [_PLL4_R] = PLL4_R, 1428fbcd9e4SEtienne Carriere [_ACLK] = CK_AXI, 1438fbcd9e4SEtienne Carriere [_PCLK1] = CK_AXI, 1448fbcd9e4SEtienne Carriere [_PCLK2] = CK_AXI, 1458fbcd9e4SEtienne Carriere [_PCLK3] = CK_AXI, 1468fbcd9e4SEtienne Carriere [_PCLK4] = CK_AXI, 1478fbcd9e4SEtienne Carriere [_PCLK5] = CK_AXI, 1488fbcd9e4SEtienne Carriere [_CK_PER] = CK_PER, 1498fbcd9e4SEtienne Carriere [_CK_MPU] = CK_MPU, 1508fbcd9e4SEtienne Carriere [_CK_MCU] = CK_MCU, 1518fbcd9e4SEtienne Carriere }; 1528fbcd9e4SEtienne Carriere 1538fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id) 1548fbcd9e4SEtienne Carriere { 1558fbcd9e4SEtienne Carriere unsigned int n; 1568fbcd9e4SEtienne Carriere 1578fbcd9e4SEtienne Carriere for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) { 1588fbcd9e4SEtienne Carriere if (parent_id_clock_id[n] == id) { 1598fbcd9e4SEtienne Carriere return n; 1608fbcd9e4SEtienne Carriere } 1618fbcd9e4SEtienne Carriere } 1628fbcd9e4SEtienne Carriere 1638fbcd9e4SEtienne Carriere return _UNKNOWN_ID; 1648fbcd9e4SEtienne Carriere } 1658fbcd9e4SEtienne Carriere 1667839a050SYann Gautier enum stm32mp1_pll_id { 1677839a050SYann Gautier _PLL1, 1687839a050SYann Gautier _PLL2, 1697839a050SYann Gautier _PLL3, 1707839a050SYann Gautier _PLL4, 1717839a050SYann Gautier _PLL_NB 1727839a050SYann Gautier }; 1737839a050SYann Gautier 1747839a050SYann Gautier enum stm32mp1_div_id { 1757839a050SYann Gautier _DIV_P, 1767839a050SYann Gautier _DIV_Q, 1777839a050SYann Gautier _DIV_R, 1787839a050SYann Gautier _DIV_NB, 1797839a050SYann Gautier }; 1807839a050SYann Gautier 1817839a050SYann Gautier enum stm32mp1_clksrc_id { 1827839a050SYann Gautier CLKSRC_MPU, 1837839a050SYann Gautier CLKSRC_AXI, 184b053a22eSYann Gautier CLKSRC_MCU, 1857839a050SYann Gautier CLKSRC_PLL12, 1867839a050SYann Gautier CLKSRC_PLL3, 1877839a050SYann Gautier CLKSRC_PLL4, 1887839a050SYann Gautier CLKSRC_RTC, 1897839a050SYann Gautier CLKSRC_MCO1, 1907839a050SYann Gautier CLKSRC_MCO2, 1917839a050SYann Gautier CLKSRC_NB 1927839a050SYann Gautier }; 1937839a050SYann Gautier 1947839a050SYann Gautier enum stm32mp1_clkdiv_id { 1957839a050SYann Gautier CLKDIV_MPU, 1967839a050SYann Gautier CLKDIV_AXI, 197b053a22eSYann Gautier CLKDIV_MCU, 1987839a050SYann Gautier CLKDIV_APB1, 1997839a050SYann Gautier CLKDIV_APB2, 2007839a050SYann Gautier CLKDIV_APB3, 2017839a050SYann Gautier CLKDIV_APB4, 2027839a050SYann Gautier CLKDIV_APB5, 2037839a050SYann Gautier CLKDIV_RTC, 2047839a050SYann Gautier CLKDIV_MCO1, 2057839a050SYann Gautier CLKDIV_MCO2, 2067839a050SYann Gautier CLKDIV_NB 2077839a050SYann Gautier }; 2087839a050SYann Gautier 2097839a050SYann Gautier enum stm32mp1_pllcfg { 2107839a050SYann Gautier PLLCFG_M, 2117839a050SYann Gautier PLLCFG_N, 2127839a050SYann Gautier PLLCFG_P, 2137839a050SYann Gautier PLLCFG_Q, 2147839a050SYann Gautier PLLCFG_R, 2157839a050SYann Gautier PLLCFG_O, 2167839a050SYann Gautier PLLCFG_NB 2177839a050SYann Gautier }; 2187839a050SYann Gautier 2197839a050SYann Gautier enum stm32mp1_pllcsg { 2207839a050SYann Gautier PLLCSG_MOD_PER, 2217839a050SYann Gautier PLLCSG_INC_STEP, 2227839a050SYann Gautier PLLCSG_SSCG_MODE, 2237839a050SYann Gautier PLLCSG_NB 2247839a050SYann Gautier }; 2257839a050SYann Gautier 2267839a050SYann Gautier enum stm32mp1_plltype { 2277839a050SYann Gautier PLL_800, 2287839a050SYann Gautier PLL_1600, 2297839a050SYann Gautier PLL_TYPE_NB 2307839a050SYann Gautier }; 2317839a050SYann Gautier 2327839a050SYann Gautier struct stm32mp1_pll { 2337839a050SYann Gautier uint8_t refclk_min; 2347839a050SYann Gautier uint8_t refclk_max; 2357839a050SYann Gautier uint8_t divn_max; 2367839a050SYann Gautier }; 2377839a050SYann Gautier 2387839a050SYann Gautier struct stm32mp1_clk_gate { 2397839a050SYann Gautier uint16_t offset; 2407839a050SYann Gautier uint8_t bit; 2417839a050SYann Gautier uint8_t index; 2427839a050SYann Gautier uint8_t set_clr; 243aaa09b71SYann Gautier uint8_t secure; 2440d21680cSYann Gautier uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ 2450d21680cSYann Gautier uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ 2467839a050SYann Gautier }; 2477839a050SYann Gautier 2487839a050SYann Gautier struct stm32mp1_clk_sel { 2497839a050SYann Gautier uint16_t offset; 2507839a050SYann Gautier uint8_t src; 2517839a050SYann Gautier uint8_t msk; 2527839a050SYann Gautier uint8_t nb_parent; 2537839a050SYann Gautier const uint8_t *parent; 2547839a050SYann Gautier }; 2557839a050SYann Gautier 2567839a050SYann Gautier #define REFCLK_SIZE 4 2577839a050SYann Gautier struct stm32mp1_clk_pll { 2587839a050SYann Gautier enum stm32mp1_plltype plltype; 2597839a050SYann Gautier uint16_t rckxselr; 2607839a050SYann Gautier uint16_t pllxcfgr1; 2617839a050SYann Gautier uint16_t pllxcfgr2; 2627839a050SYann Gautier uint16_t pllxfracr; 2637839a050SYann Gautier uint16_t pllxcr; 2647839a050SYann Gautier uint16_t pllxcsgr; 2657839a050SYann Gautier enum stm32mp_osc_id refclk[REFCLK_SIZE]; 2667839a050SYann Gautier }; 2677839a050SYann Gautier 2680d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */ 269aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s) \ 2707839a050SYann Gautier { \ 2717839a050SYann Gautier .offset = (off), \ 2727839a050SYann Gautier .bit = (b), \ 2737839a050SYann Gautier .index = (idx), \ 2747839a050SYann Gautier .set_clr = 0, \ 275aaa09b71SYann Gautier .secure = (sec), \ 2767839a050SYann Gautier .sel = (s), \ 2777839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 2787839a050SYann Gautier } 2797839a050SYann Gautier 2800d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */ 281aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f) \ 2827839a050SYann Gautier { \ 2837839a050SYann Gautier .offset = (off), \ 2847839a050SYann Gautier .bit = (b), \ 2857839a050SYann Gautier .index = (idx), \ 2867839a050SYann Gautier .set_clr = 0, \ 287aaa09b71SYann Gautier .secure = (sec), \ 2887839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 2897839a050SYann Gautier .fixed = (f), \ 2907839a050SYann Gautier } 2917839a050SYann Gautier 2920d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */ 293aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s) \ 2947839a050SYann Gautier { \ 2957839a050SYann Gautier .offset = (off), \ 2967839a050SYann Gautier .bit = (b), \ 2977839a050SYann Gautier .index = (idx), \ 2987839a050SYann Gautier .set_clr = 1, \ 299aaa09b71SYann Gautier .secure = (sec), \ 3007839a050SYann Gautier .sel = (s), \ 3017839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 3027839a050SYann Gautier } 3037839a050SYann Gautier 3040d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */ 305aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f) \ 3067839a050SYann Gautier { \ 3077839a050SYann Gautier .offset = (off), \ 3087839a050SYann Gautier .bit = (b), \ 3097839a050SYann Gautier .index = (idx), \ 3107839a050SYann Gautier .set_clr = 1, \ 311aaa09b71SYann Gautier .secure = (sec), \ 3127839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 3137839a050SYann Gautier .fixed = (f), \ 3147839a050SYann Gautier } 3157839a050SYann Gautier 316d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents) \ 317d4151d2fSYann Gautier [_ ## _label ## _SEL] = { \ 318d4151d2fSYann Gautier .offset = _rcc_selr, \ 319d4151d2fSYann Gautier .src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \ 3208ae08dcdSEtienne Carriere .msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \ 3218ae08dcdSEtienne Carriere (_rcc_selr ## _ ## _label ## SRC_SHIFT), \ 322d4151d2fSYann Gautier .parent = (_parents), \ 323d4151d2fSYann Gautier .nb_parent = ARRAY_SIZE(_parents) \ 3247839a050SYann Gautier } 3257839a050SYann Gautier 3260d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3, \ 3277839a050SYann Gautier off4, off5, off6, \ 3287839a050SYann Gautier p1, p2, p3, p4) \ 3297839a050SYann Gautier [(idx)] = { \ 3307839a050SYann Gautier .plltype = (type), \ 3317839a050SYann Gautier .rckxselr = (off1), \ 3327839a050SYann Gautier .pllxcfgr1 = (off2), \ 3337839a050SYann Gautier .pllxcfgr2 = (off3), \ 3347839a050SYann Gautier .pllxfracr = (off4), \ 3357839a050SYann Gautier .pllxcr = (off5), \ 3367839a050SYann Gautier .pllxcsgr = (off6), \ 3377839a050SYann Gautier .refclk[0] = (p1), \ 3387839a050SYann Gautier .refclk[1] = (p2), \ 3397839a050SYann Gautier .refclk[2] = (p3), \ 3407839a050SYann Gautier .refclk[3] = (p4), \ 3417839a050SYann Gautier } 3427839a050SYann Gautier 3430d21680cSYann Gautier #define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) 3440d21680cSYann Gautier 345aaa09b71SYann Gautier #define SEC 1 346aaa09b71SYann Gautier #define N_S 0 347aaa09b71SYann Gautier 3487839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { 349aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK), 350aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK), 351aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK), 352aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK), 353aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), 354aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), 355aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), 356aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), 357aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK), 358aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), 359aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), 3607839a050SYann Gautier 3617418cf39SYann Gautier #if defined(IMAGE_BL32) 362aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), 3637418cf39SYann Gautier #endif 364aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), 365aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), 366aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), 367aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), 368aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), 369aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), 370aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), 371aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), 372aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), 373aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), 3747839a050SYann Gautier 3757418cf39SYann Gautier #if defined(IMAGE_BL32) 376aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), 3777418cf39SYann Gautier #endif 378aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), 3797839a050SYann Gautier 380aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), 381f33b2433SYann Gautier 382aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), 383aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), 384aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), 3857839a050SYann Gautier 386aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), 387aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), 388aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), 389aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL), 390aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), 391aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), 392aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), 393aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), 394aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), 395aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), 396aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), 3977839a050SYann Gautier 3987418cf39SYann Gautier #if defined(IMAGE_BL32) 399aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), 400aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), 4017418cf39SYann Gautier #endif 4027839a050SYann Gautier 403aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), 404aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), 405aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), 406aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), 407aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), 408aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), 409aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), 410aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), 411aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), 412aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), 413aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), 4147839a050SYann Gautier 415aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), 416aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), 417aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), 418aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), 419aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), 4207839a050SYann Gautier 4217418cf39SYann Gautier #if defined(IMAGE_BL2) 422aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), 423aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), 4247418cf39SYann Gautier #endif 425aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), 426aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), 4277418cf39SYann Gautier #if defined(IMAGE_BL32) 428aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), 4297418cf39SYann Gautier #endif 4307839a050SYann Gautier 431aaa09b71SYann Gautier _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL), 432aaa09b71SYann Gautier _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), 4337839a050SYann Gautier }; 4347839a050SYann Gautier 4350d21680cSYann Gautier static const uint8_t i2c12_parents[] = { 4360d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4370d21680cSYann Gautier }; 4380d21680cSYann Gautier 4390d21680cSYann Gautier static const uint8_t i2c35_parents[] = { 4400d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4410d21680cSYann Gautier }; 4420d21680cSYann Gautier 4430d21680cSYann Gautier static const uint8_t stgen_parents[] = { 4440d21680cSYann Gautier _HSI_KER, _HSE_KER 4450d21680cSYann Gautier }; 4460d21680cSYann Gautier 4470d21680cSYann Gautier static const uint8_t i2c46_parents[] = { 4480d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER 4490d21680cSYann Gautier }; 4500d21680cSYann Gautier 4510d21680cSYann Gautier static const uint8_t spi6_parents[] = { 4520d21680cSYann Gautier _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q 4530d21680cSYann Gautier }; 4540d21680cSYann Gautier 4550d21680cSYann Gautier static const uint8_t usart1_parents[] = { 4560d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER 4570d21680cSYann Gautier }; 4580d21680cSYann Gautier 4590d21680cSYann Gautier static const uint8_t rng1_parents[] = { 4600d21680cSYann Gautier _CSI, _PLL4_R, _LSE, _LSI 4610d21680cSYann Gautier }; 4620d21680cSYann Gautier 4630d21680cSYann Gautier static const uint8_t uart6_parents[] = { 4640d21680cSYann Gautier _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4650d21680cSYann Gautier }; 4660d21680cSYann Gautier 4670d21680cSYann Gautier static const uint8_t uart234578_parents[] = { 4680d21680cSYann Gautier _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4690d21680cSYann Gautier }; 4700d21680cSYann Gautier 4710d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = { 4720d21680cSYann Gautier _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER 4730d21680cSYann Gautier }; 4740d21680cSYann Gautier 4750d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = { 4760d21680cSYann Gautier _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER 4770d21680cSYann Gautier }; 4780d21680cSYann Gautier 4790d21680cSYann Gautier static const uint8_t qspi_parents[] = { 4800d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4810d21680cSYann Gautier }; 4820d21680cSYann Gautier 4830d21680cSYann Gautier static const uint8_t fmc_parents[] = { 4840d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4850d21680cSYann Gautier }; 4860d21680cSYann Gautier 487b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = { 488b8fe48b6SEtienne Carriere _HSI, _HSE, _PLL2_P 4890d21680cSYann Gautier }; 4900d21680cSYann Gautier 491b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = { 492b8fe48b6SEtienne Carriere _HSI, _HSE, _CSI, _PLL3_P 493b053a22eSYann Gautier }; 494b053a22eSYann Gautier 4950d21680cSYann Gautier static const uint8_t usbphy_parents[] = { 4960d21680cSYann Gautier _HSE_KER, _PLL4_R, _HSE_KER_DIV2 4970d21680cSYann Gautier }; 4980d21680cSYann Gautier 4990d21680cSYann Gautier static const uint8_t usbo_parents[] = { 5000d21680cSYann Gautier _PLL4_R, _USB_PHY_48 5010d21680cSYann Gautier }; 5027839a050SYann Gautier 5038fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = { 5048fbcd9e4SEtienne Carriere _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ 5058fbcd9e4SEtienne Carriere }; 5068fbcd9e4SEtienne Carriere 5078fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = { 5088fbcd9e4SEtienne Carriere _HSI, _HSE, _CSI, 5098fbcd9e4SEtienne Carriere }; 5108fbcd9e4SEtienne Carriere 511016af006SEtienne Carriere static const uint8_t rtc_parents[] = { 512cbd2e8a6SGabriel Fernandez _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC 513016af006SEtienne Carriere }; 514016af006SEtienne Carriere 5157839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { 516d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), 517d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), 518d4151d2fSYann Gautier _CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents), 519d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents), 520d4151d2fSYann Gautier _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), 521d4151d2fSYann Gautier _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), 522d4151d2fSYann Gautier _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), 5238fbcd9e4SEtienne Carriere _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents), 524288f5cf2SYann Gautier _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents), 525016af006SEtienne Carriere _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents), 526d4151d2fSYann Gautier _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), 527d4151d2fSYann Gautier _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), 528d4151d2fSYann Gautier _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), 529d4151d2fSYann Gautier _CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents), 530d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents), 531d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents), 532d4151d2fSYann Gautier _CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents), 533d4151d2fSYann Gautier _CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents), 534b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents), 535b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents), 536d4151d2fSYann Gautier _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents), 537d4151d2fSYann Gautier _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents), 5387839a050SYann Gautier }; 5397839a050SYann Gautier 5407839a050SYann Gautier /* Define characteristic of PLL according type */ 5417839a050SYann Gautier #define DIVN_MIN 24 5427839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { 5437839a050SYann Gautier [PLL_800] = { 5447839a050SYann Gautier .refclk_min = 4, 5457839a050SYann Gautier .refclk_max = 16, 5467839a050SYann Gautier .divn_max = 99, 5477839a050SYann Gautier }, 5487839a050SYann Gautier [PLL_1600] = { 5497839a050SYann Gautier .refclk_min = 8, 5507839a050SYann Gautier .refclk_max = 16, 5517839a050SYann Gautier .divn_max = 199, 5527839a050SYann Gautier }, 5537839a050SYann Gautier }; 5547839a050SYann Gautier 5557839a050SYann Gautier /* PLLNCFGR2 register divider by output */ 5567839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = { 5577839a050SYann Gautier [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, 5587839a050SYann Gautier [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, 5590d21680cSYann Gautier [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, 5607839a050SYann Gautier }; 5617839a050SYann Gautier 5627839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { 5630d21680cSYann Gautier _CLK_PLL(_PLL1, PLL_1600, 5647839a050SYann Gautier RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, 5657839a050SYann Gautier RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, 5667839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5670d21680cSYann Gautier _CLK_PLL(_PLL2, PLL_1600, 5687839a050SYann Gautier RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, 5697839a050SYann Gautier RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, 5707839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5710d21680cSYann Gautier _CLK_PLL(_PLL3, PLL_800, 5727839a050SYann Gautier RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, 5737839a050SYann Gautier RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, 5747839a050SYann Gautier _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), 5750d21680cSYann Gautier _CLK_PLL(_PLL4, PLL_800, 5767839a050SYann Gautier RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, 5777839a050SYann Gautier RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, 5787839a050SYann Gautier _HSI, _HSE, _CSI, _I2S_CKIN), 5797839a050SYann Gautier }; 5807839a050SYann Gautier 5817839a050SYann Gautier /* Prescaler table lookups for clock computation */ 582b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ 583b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = { 584b053a22eSYann Gautier 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 585b053a22eSYann Gautier }; 5867839a050SYann Gautier 5877839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ 5887839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div 5897839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div 5907839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = { 5917839a050SYann Gautier 0, 1, 2, 3, 4, 4, 4, 4 5927839a050SYann Gautier }; 5937839a050SYann Gautier 5947839a050SYann Gautier /* div = /1 /2 /3 /4 */ 5957839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = { 5967839a050SYann Gautier 1, 2, 3, 4, 4, 4, 4, 4 5977839a050SYann Gautier }; 5987839a050SYann Gautier 59937e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { 60037e8295aSEtienne Carriere [_HSI] = "HSI", 60137e8295aSEtienne Carriere [_HSE] = "HSE", 60237e8295aSEtienne Carriere [_CSI] = "CSI", 60337e8295aSEtienne Carriere [_LSI] = "LSI", 60437e8295aSEtienne Carriere [_LSE] = "LSE", 60537e8295aSEtienne Carriere [_I2S_CKIN] = "I2S_CKIN", 60637e8295aSEtienne Carriere [_HSI_KER] = "HSI_KER", 60737e8295aSEtienne Carriere [_HSE_KER] = "HSE_KER", 60837e8295aSEtienne Carriere [_HSE_KER_DIV2] = "HSE_KER_DIV2", 609cbd2e8a6SGabriel Fernandez [_HSE_RTC] = "HSE_RTC", 61037e8295aSEtienne Carriere [_CSI_KER] = "CSI_KER", 61137e8295aSEtienne Carriere [_PLL1_P] = "PLL1_P", 61237e8295aSEtienne Carriere [_PLL1_Q] = "PLL1_Q", 61337e8295aSEtienne Carriere [_PLL1_R] = "PLL1_R", 61437e8295aSEtienne Carriere [_PLL2_P] = "PLL2_P", 61537e8295aSEtienne Carriere [_PLL2_Q] = "PLL2_Q", 61637e8295aSEtienne Carriere [_PLL2_R] = "PLL2_R", 61737e8295aSEtienne Carriere [_PLL3_P] = "PLL3_P", 61837e8295aSEtienne Carriere [_PLL3_Q] = "PLL3_Q", 61937e8295aSEtienne Carriere [_PLL3_R] = "PLL3_R", 62037e8295aSEtienne Carriere [_PLL4_P] = "PLL4_P", 62137e8295aSEtienne Carriere [_PLL4_Q] = "PLL4_Q", 62237e8295aSEtienne Carriere [_PLL4_R] = "PLL4_R", 62337e8295aSEtienne Carriere [_ACLK] = "ACLK", 62437e8295aSEtienne Carriere [_PCLK1] = "PCLK1", 62537e8295aSEtienne Carriere [_PCLK2] = "PCLK2", 62637e8295aSEtienne Carriere [_PCLK3] = "PCLK3", 62737e8295aSEtienne Carriere [_PCLK4] = "PCLK4", 62837e8295aSEtienne Carriere [_PCLK5] = "PCLK5", 62937e8295aSEtienne Carriere [_HCLK6] = "KCLK6", 63037e8295aSEtienne Carriere [_HCLK2] = "HCLK2", 63137e8295aSEtienne Carriere [_CK_PER] = "CK_PER", 63237e8295aSEtienne Carriere [_CK_MPU] = "CK_MPU", 63337e8295aSEtienne Carriere [_CK_MCU] = "CK_MCU", 63437e8295aSEtienne Carriere [_USB_PHY_48] = "USB_PHY_48", 63537e8295aSEtienne Carriere }; 63637e8295aSEtienne Carriere 6370d21680cSYann Gautier /* RCC clock device driver private */ 6380d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC]; 6390d21680cSYann Gautier static struct spinlock reg_lock; 6400d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES]; 6410d21680cSYann Gautier static struct spinlock refcount_lock; 6427839a050SYann Gautier 6430d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) 6440d21680cSYann Gautier { 6450d21680cSYann Gautier return &stm32mp1_clk_gate[idx]; 6460d21680cSYann Gautier } 6477839a050SYann Gautier 6483d69149aSYann Gautier #if defined(IMAGE_BL32) 6493d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate) 6503d69149aSYann Gautier { 6513d69149aSYann Gautier return gate->secure == N_S; 6523d69149aSYann Gautier } 6533d69149aSYann Gautier #endif 6543d69149aSYann Gautier 6550d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) 6560d21680cSYann Gautier { 6570d21680cSYann Gautier return &stm32mp1_clk_sel[idx]; 6580d21680cSYann Gautier } 6590d21680cSYann Gautier 6600d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) 6610d21680cSYann Gautier { 6620d21680cSYann Gautier return &stm32mp1_clk_pll[idx]; 6630d21680cSYann Gautier } 6640d21680cSYann Gautier 6650d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock) 6660d21680cSYann Gautier { 667e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6680d21680cSYann Gautier /* Assume interrupts are masked */ 6690d21680cSYann Gautier spin_lock(lock); 6700d21680cSYann Gautier } 671e463d3f4SYann Gautier } 6720d21680cSYann Gautier 6730d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock) 6740d21680cSYann Gautier { 675e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6760d21680cSYann Gautier spin_unlock(lock); 6770d21680cSYann Gautier } 678e463d3f4SYann Gautier } 6790d21680cSYann Gautier 6800d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void) 6810d21680cSYann Gautier { 6820d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6831bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN; 6840d21680cSYann Gautier 6851bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 6860d21680cSYann Gautier } 6870d21680cSYann Gautier 688b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void) 689b053a22eSYann Gautier { 690b053a22eSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6911bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; 692b053a22eSYann Gautier 6931bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 694b053a22eSYann Gautier } 695b053a22eSYann Gautier 6960d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void) 6970d21680cSYann Gautier { 6980d21680cSYann Gautier stm32mp1_clk_lock(®_lock); 6990d21680cSYann Gautier } 7000d21680cSYann Gautier 7010d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void) 7020d21680cSYann Gautier { 7030d21680cSYann Gautier stm32mp1_clk_unlock(®_lock); 7040d21680cSYann Gautier } 7050d21680cSYann Gautier 7060d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) 7077839a050SYann Gautier { 7087839a050SYann Gautier if (idx >= NB_OSC) { 7097839a050SYann Gautier return 0; 7107839a050SYann Gautier } 7117839a050SYann Gautier 7120d21680cSYann Gautier return stm32mp1_osc[idx]; 7137839a050SYann Gautier } 7147839a050SYann Gautier 7150d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id) 7167839a050SYann Gautier { 7170d21680cSYann Gautier unsigned int i; 7187839a050SYann Gautier 7190d21680cSYann Gautier for (i = 0U; i < NB_GATES; i++) { 7200d21680cSYann Gautier if (gate_ref(i)->index == id) { 7217839a050SYann Gautier return i; 7227839a050SYann Gautier } 7237839a050SYann Gautier } 7247839a050SYann Gautier 72544fb470bSYann Gautier ERROR("%s: clk id %lu not found\n", __func__, id); 7267839a050SYann Gautier 7277839a050SYann Gautier return -EINVAL; 7287839a050SYann Gautier } 7297839a050SYann Gautier 7300d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) 7317839a050SYann Gautier { 7320d21680cSYann Gautier return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); 7337839a050SYann Gautier } 7347839a050SYann Gautier 7350d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) 7367839a050SYann Gautier { 7370d21680cSYann Gautier return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); 7387839a050SYann Gautier } 7397839a050SYann Gautier 7400d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id) 7417839a050SYann Gautier { 7420d21680cSYann Gautier const struct stm32mp1_clk_sel *sel; 7438fbcd9e4SEtienne Carriere uint32_t p_sel; 7447839a050SYann Gautier int i; 7457839a050SYann Gautier enum stm32mp1_parent_id p; 7467839a050SYann Gautier enum stm32mp1_parent_sel s; 7470d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7487839a050SYann Gautier 7498fbcd9e4SEtienne Carriere /* Few non gateable clock have a static parent ID, find them */ 7508fbcd9e4SEtienne Carriere i = (int)clock_id2parent_id(id); 7518fbcd9e4SEtienne Carriere if (i != _UNKNOWN_ID) { 7528fbcd9e4SEtienne Carriere return i; 7537839a050SYann Gautier } 7547839a050SYann Gautier 7550d21680cSYann Gautier i = stm32mp1_clk_get_gated_id(id); 7567839a050SYann Gautier if (i < 0) { 7570d21680cSYann Gautier panic(); 7587839a050SYann Gautier } 7597839a050SYann Gautier 7600d21680cSYann Gautier p = stm32mp1_clk_get_fixed_parent(i); 7617839a050SYann Gautier if (p < _PARENT_NB) { 7627839a050SYann Gautier return (int)p; 7637839a050SYann Gautier } 7647839a050SYann Gautier 7650d21680cSYann Gautier s = stm32mp1_clk_get_sel(i); 7660d21680cSYann Gautier if (s == _UNKNOWN_SEL) { 7670d21680cSYann Gautier return -EINVAL; 7680d21680cSYann Gautier } 7697839a050SYann Gautier if (s >= _PARENT_SEL_NB) { 7700d21680cSYann Gautier panic(); 7717839a050SYann Gautier } 7727839a050SYann Gautier 7730d21680cSYann Gautier sel = clk_sel_ref(s); 7748ae08dcdSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) & 7758ae08dcdSEtienne Carriere (sel->msk << sel->src)) >> sel->src; 7760d21680cSYann Gautier if (p_sel < sel->nb_parent) { 7770d21680cSYann Gautier return (int)sel->parent[p_sel]; 7787839a050SYann Gautier } 7797839a050SYann Gautier 7807839a050SYann Gautier return -EINVAL; 7817839a050SYann Gautier } 7827839a050SYann Gautier 7830d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) 7847839a050SYann Gautier { 7850d21680cSYann Gautier uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); 7860d21680cSYann Gautier uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; 7877839a050SYann Gautier 7880d21680cSYann Gautier return stm32mp1_clk_get_fixed(pll->refclk[src]); 7897839a050SYann Gautier } 7907839a050SYann Gautier 7917839a050SYann Gautier /* 7927839a050SYann Gautier * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL 7937839a050SYann Gautier * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) 7947839a050SYann Gautier * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) 7957839a050SYann Gautier * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) 7967839a050SYann Gautier */ 7970d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) 7987839a050SYann Gautier { 7997839a050SYann Gautier unsigned long refclk, fvco; 8007839a050SYann Gautier uint32_t cfgr1, fracr, divm, divn; 8010d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8027839a050SYann Gautier 8030d21680cSYann Gautier cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); 8040d21680cSYann Gautier fracr = mmio_read_32(rcc_base + pll->pllxfracr); 8057839a050SYann Gautier 8067839a050SYann Gautier divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; 8077839a050SYann Gautier divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; 8087839a050SYann Gautier 8090d21680cSYann Gautier refclk = stm32mp1_pll_get_fref(pll); 8107839a050SYann Gautier 8117839a050SYann Gautier /* 8127839a050SYann Gautier * With FRACV : 8137839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) 8147839a050SYann Gautier * Without FRACV 8157839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) 8167839a050SYann Gautier */ 8177839a050SYann Gautier if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { 8180d21680cSYann Gautier uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> 8190d21680cSYann Gautier RCC_PLLNFRACR_FRACV_SHIFT; 8207839a050SYann Gautier unsigned long long numerator, denominator; 8217839a050SYann Gautier 8220d21680cSYann Gautier numerator = (((unsigned long long)divn + 1U) << 13) + fracv; 8230d21680cSYann Gautier numerator = refclk * numerator; 8247839a050SYann Gautier denominator = ((unsigned long long)divm + 1U) << 13; 8257839a050SYann Gautier fvco = (unsigned long)(numerator / denominator); 8267839a050SYann Gautier } else { 8277839a050SYann Gautier fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); 8287839a050SYann Gautier } 8297839a050SYann Gautier 8307839a050SYann Gautier return fvco; 8317839a050SYann Gautier } 8327839a050SYann Gautier 8330d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, 8347839a050SYann Gautier enum stm32mp1_div_id div_id) 8357839a050SYann Gautier { 8360d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 8377839a050SYann Gautier unsigned long dfout; 8387839a050SYann Gautier uint32_t cfgr2, divy; 8397839a050SYann Gautier 8407839a050SYann Gautier if (div_id >= _DIV_NB) { 8417839a050SYann Gautier return 0; 8427839a050SYann Gautier } 8437839a050SYann Gautier 8440d21680cSYann Gautier cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); 8457839a050SYann Gautier divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; 8467839a050SYann Gautier 8470d21680cSYann Gautier dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); 8487839a050SYann Gautier 8497839a050SYann Gautier return dfout; 8507839a050SYann Gautier } 8517839a050SYann Gautier 8520d21680cSYann Gautier static unsigned long get_clock_rate(int p) 8537839a050SYann Gautier { 8547839a050SYann Gautier uint32_t reg, clkdiv; 8557839a050SYann Gautier unsigned long clock = 0; 8560d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8577839a050SYann Gautier 8587839a050SYann Gautier switch (p) { 8597839a050SYann Gautier case _CK_MPU: 8607839a050SYann Gautier /* MPU sub system */ 8610d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKSELR); 8627839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8637839a050SYann Gautier case RCC_MPCKSELR_HSI: 8640d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8657839a050SYann Gautier break; 8667839a050SYann Gautier case RCC_MPCKSELR_HSE: 8670d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8687839a050SYann Gautier break; 8697839a050SYann Gautier case RCC_MPCKSELR_PLL: 8700d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8717839a050SYann Gautier break; 8727839a050SYann Gautier case RCC_MPCKSELR_PLL_MPUDIV: 8730d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8747839a050SYann Gautier 8750d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); 8767839a050SYann Gautier clkdiv = reg & RCC_MPUDIV_MASK; 877602ae2f2SGabriel Fernandez clock >>= stm32mp1_mpu_div[clkdiv]; 8787839a050SYann Gautier break; 8797839a050SYann Gautier default: 8807839a050SYann Gautier break; 8817839a050SYann Gautier } 8827839a050SYann Gautier break; 8837839a050SYann Gautier /* AXI sub system */ 8847839a050SYann Gautier case _ACLK: 8857839a050SYann Gautier case _HCLK2: 8867839a050SYann Gautier case _HCLK6: 8877839a050SYann Gautier case _PCLK4: 8887839a050SYann Gautier case _PCLK5: 8890d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); 8907839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8917839a050SYann Gautier case RCC_ASSCKSELR_HSI: 8920d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8937839a050SYann Gautier break; 8947839a050SYann Gautier case RCC_ASSCKSELR_HSE: 8950d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8967839a050SYann Gautier break; 8977839a050SYann Gautier case RCC_ASSCKSELR_PLL: 8980d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 8997839a050SYann Gautier break; 9007839a050SYann Gautier default: 9017839a050SYann Gautier break; 9027839a050SYann Gautier } 9037839a050SYann Gautier 9047839a050SYann Gautier /* System clock divider */ 9050d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_AXIDIVR); 9067839a050SYann Gautier clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; 9077839a050SYann Gautier 9087839a050SYann Gautier switch (p) { 9097839a050SYann Gautier case _PCLK4: 9100d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB4DIVR); 9117839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9127839a050SYann Gautier break; 9137839a050SYann Gautier case _PCLK5: 9140d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB5DIVR); 9157839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9167839a050SYann Gautier break; 9177839a050SYann Gautier default: 9187839a050SYann Gautier break; 9197839a050SYann Gautier } 9207839a050SYann Gautier break; 921b053a22eSYann Gautier /* MCU sub system */ 922b053a22eSYann Gautier case _CK_MCU: 923b053a22eSYann Gautier case _PCLK1: 924b053a22eSYann Gautier case _PCLK2: 925b053a22eSYann Gautier case _PCLK3: 926b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); 927b053a22eSYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 928b053a22eSYann Gautier case RCC_MSSCKSELR_HSI: 929b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 930b053a22eSYann Gautier break; 931b053a22eSYann Gautier case RCC_MSSCKSELR_HSE: 932b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 933b053a22eSYann Gautier break; 934b053a22eSYann Gautier case RCC_MSSCKSELR_CSI: 935b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 936b053a22eSYann Gautier break; 937b053a22eSYann Gautier case RCC_MSSCKSELR_PLL: 938b053a22eSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 939b053a22eSYann Gautier break; 940b053a22eSYann Gautier default: 941b053a22eSYann Gautier break; 942b053a22eSYann Gautier } 943b053a22eSYann Gautier 944b053a22eSYann Gautier /* MCU clock divider */ 945b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MCUDIVR); 946b053a22eSYann Gautier clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; 947b053a22eSYann Gautier 948b053a22eSYann Gautier switch (p) { 949b053a22eSYann Gautier case _PCLK1: 950b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB1DIVR); 951b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 952b053a22eSYann Gautier break; 953b053a22eSYann Gautier case _PCLK2: 954b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB2DIVR); 955b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 956b053a22eSYann Gautier break; 957b053a22eSYann Gautier case _PCLK3: 958b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB3DIVR); 959b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 960b053a22eSYann Gautier break; 961b053a22eSYann Gautier case _CK_MCU: 962b053a22eSYann Gautier default: 963b053a22eSYann Gautier break; 964b053a22eSYann Gautier } 965b053a22eSYann Gautier break; 9667839a050SYann Gautier case _CK_PER: 9670d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); 9687839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 9697839a050SYann Gautier case RCC_CPERCKSELR_HSI: 9700d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9717839a050SYann Gautier break; 9727839a050SYann Gautier case RCC_CPERCKSELR_HSE: 9730d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9747839a050SYann Gautier break; 9757839a050SYann Gautier case RCC_CPERCKSELR_CSI: 9760d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9777839a050SYann Gautier break; 9787839a050SYann Gautier default: 9797839a050SYann Gautier break; 9807839a050SYann Gautier } 9817839a050SYann Gautier break; 9827839a050SYann Gautier case _HSI: 9837839a050SYann Gautier case _HSI_KER: 9840d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9857839a050SYann Gautier break; 9867839a050SYann Gautier case _CSI: 9877839a050SYann Gautier case _CSI_KER: 9880d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9897839a050SYann Gautier break; 9907839a050SYann Gautier case _HSE: 9917839a050SYann Gautier case _HSE_KER: 9920d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9937839a050SYann Gautier break; 9947839a050SYann Gautier case _HSE_KER_DIV2: 9950d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE) >> 1; 9967839a050SYann Gautier break; 997cbd2e8a6SGabriel Fernandez case _HSE_RTC: 998cbd2e8a6SGabriel Fernandez clock = stm32mp1_clk_get_fixed(_HSE); 999cbd2e8a6SGabriel Fernandez clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; 1000cbd2e8a6SGabriel Fernandez break; 10017839a050SYann Gautier case _LSI: 10020d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSI); 10037839a050SYann Gautier break; 10047839a050SYann Gautier case _LSE: 10050d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSE); 10067839a050SYann Gautier break; 10077839a050SYann Gautier /* PLL */ 10087839a050SYann Gautier case _PLL1_P: 10090d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 10107839a050SYann Gautier break; 10117839a050SYann Gautier case _PLL1_Q: 10120d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); 10137839a050SYann Gautier break; 10147839a050SYann Gautier case _PLL1_R: 10150d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); 10167839a050SYann Gautier break; 10177839a050SYann Gautier case _PLL2_P: 10180d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 10197839a050SYann Gautier break; 10207839a050SYann Gautier case _PLL2_Q: 10210d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); 10227839a050SYann Gautier break; 10237839a050SYann Gautier case _PLL2_R: 10240d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); 10257839a050SYann Gautier break; 10267839a050SYann Gautier case _PLL3_P: 10270d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 10287839a050SYann Gautier break; 10297839a050SYann Gautier case _PLL3_Q: 10300d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); 10317839a050SYann Gautier break; 10327839a050SYann Gautier case _PLL3_R: 10330d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); 10347839a050SYann Gautier break; 10357839a050SYann Gautier case _PLL4_P: 10360d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); 10377839a050SYann Gautier break; 10387839a050SYann Gautier case _PLL4_Q: 10390d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); 10407839a050SYann Gautier break; 10417839a050SYann Gautier case _PLL4_R: 10420d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); 10437839a050SYann Gautier break; 10447839a050SYann Gautier /* Other */ 10457839a050SYann Gautier case _USB_PHY_48: 10460d21680cSYann Gautier clock = USB_PHY_48_MHZ; 10477839a050SYann Gautier break; 10487839a050SYann Gautier default: 10497839a050SYann Gautier break; 10507839a050SYann Gautier } 10517839a050SYann Gautier 10527839a050SYann Gautier return clock; 10537839a050SYann Gautier } 10547839a050SYann Gautier 10550d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate) 10560d21680cSYann Gautier { 10570d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10580d21680cSYann Gautier 105925be845eSEtienne Carriere VERBOSE("Enable clock %u\n", gate->index); 106025be845eSEtienne Carriere 10610d21680cSYann Gautier if (gate->set_clr != 0U) { 10620d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); 10630d21680cSYann Gautier } else { 10640d21680cSYann Gautier mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10650d21680cSYann Gautier } 10660d21680cSYann Gautier } 10670d21680cSYann Gautier 10680d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate) 10690d21680cSYann Gautier { 10700d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10710d21680cSYann Gautier 107225be845eSEtienne Carriere VERBOSE("Disable clock %u\n", gate->index); 107325be845eSEtienne Carriere 10740d21680cSYann Gautier if (gate->set_clr != 0U) { 10750d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, 10760d21680cSYann Gautier BIT(gate->bit)); 10770d21680cSYann Gautier } else { 10780d21680cSYann Gautier mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10790d21680cSYann Gautier } 10800d21680cSYann Gautier } 10810d21680cSYann Gautier 10820d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) 10830d21680cSYann Gautier { 10840d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10850d21680cSYann Gautier 10860d21680cSYann Gautier return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); 10870d21680cSYann Gautier } 10880d21680cSYann Gautier 108935848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */ 109035848200SEtienne Carriere static bool clock_is_always_on(unsigned long id) 109135848200SEtienne Carriere { 109235848200SEtienne Carriere switch (id) { 109335848200SEtienne Carriere case CK_HSE: 109435848200SEtienne Carriere case CK_CSI: 109535848200SEtienne Carriere case CK_LSI: 109635848200SEtienne Carriere case CK_LSE: 109735848200SEtienne Carriere case CK_HSI: 109835848200SEtienne Carriere case CK_HSE_DIV2: 109935848200SEtienne Carriere case PLL1_Q: 110035848200SEtienne Carriere case PLL1_R: 110135848200SEtienne Carriere case PLL2_P: 110235848200SEtienne Carriere case PLL2_Q: 110335848200SEtienne Carriere case PLL2_R: 110435848200SEtienne Carriere case PLL3_P: 110535848200SEtienne Carriere case PLL3_Q: 110635848200SEtienne Carriere case PLL3_R: 1107bf39318dSYann Gautier case CK_AXI: 1108bf39318dSYann Gautier case CK_MPU: 1109bf39318dSYann Gautier case CK_MCU: 11105b111c74SHE Shushan case RTC: 111135848200SEtienne Carriere return true; 111235848200SEtienne Carriere default: 111335848200SEtienne Carriere return false; 111435848200SEtienne Carriere } 111535848200SEtienne Carriere } 111635848200SEtienne Carriere 11172444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt) 11180d21680cSYann Gautier { 11190d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 112035848200SEtienne Carriere int i; 11210d21680cSYann Gautier 112235848200SEtienne Carriere if (clock_is_always_on(id)) { 112335848200SEtienne Carriere return; 112435848200SEtienne Carriere } 112535848200SEtienne Carriere 112635848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11270d21680cSYann Gautier if (i < 0) { 112844fb470bSYann Gautier ERROR("Clock %lu can't be enabled\n", id); 11290d21680cSYann Gautier panic(); 11300d21680cSYann Gautier } 11310d21680cSYann Gautier 11320d21680cSYann Gautier gate = gate_ref(i); 11332444d231SYann Gautier 11342444d231SYann Gautier if (!with_refcnt) { 11352444d231SYann Gautier __clk_enable(gate); 11362444d231SYann Gautier return; 11372444d231SYann Gautier } 11380d21680cSYann Gautier 11393d69149aSYann Gautier #if defined(IMAGE_BL32) 11403d69149aSYann Gautier if (gate_is_non_secure(gate)) { 11413d69149aSYann Gautier /* Enable non-secure clock w/o any refcounting */ 11423d69149aSYann Gautier __clk_enable(gate); 11433d69149aSYann Gautier return; 11443d69149aSYann Gautier } 11453d69149aSYann Gautier #endif 11463d69149aSYann Gautier 11470d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11480d21680cSYann Gautier 11492444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11500d21680cSYann Gautier __clk_enable(gate); 11510d21680cSYann Gautier } 11520d21680cSYann Gautier 11532444d231SYann Gautier gate_refcounts[i]++; 11542444d231SYann Gautier if (gate_refcounts[i] == UINT_MAX) { 11552444d231SYann Gautier ERROR("Clock %lu refcount reached max value\n", id); 11562444d231SYann Gautier panic(); 11572444d231SYann Gautier } 11582444d231SYann Gautier 11590d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11600d21680cSYann Gautier } 11610d21680cSYann Gautier 11622444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt) 11630d21680cSYann Gautier { 11640d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 116535848200SEtienne Carriere int i; 11660d21680cSYann Gautier 116735848200SEtienne Carriere if (clock_is_always_on(id)) { 116835848200SEtienne Carriere return; 116935848200SEtienne Carriere } 117035848200SEtienne Carriere 117135848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11720d21680cSYann Gautier if (i < 0) { 117344fb470bSYann Gautier ERROR("Clock %lu can't be disabled\n", id); 11740d21680cSYann Gautier panic(); 11750d21680cSYann Gautier } 11760d21680cSYann Gautier 11770d21680cSYann Gautier gate = gate_ref(i); 11782444d231SYann Gautier 11792444d231SYann Gautier if (!with_refcnt) { 11802444d231SYann Gautier __clk_disable(gate); 11812444d231SYann Gautier return; 11822444d231SYann Gautier } 11830d21680cSYann Gautier 11843d69149aSYann Gautier #if defined(IMAGE_BL32) 11853d69149aSYann Gautier if (gate_is_non_secure(gate)) { 11863d69149aSYann Gautier /* Don't disable non-secure clocks */ 11873d69149aSYann Gautier return; 11883d69149aSYann Gautier } 11893d69149aSYann Gautier #endif 11903d69149aSYann Gautier 11910d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11920d21680cSYann Gautier 11932444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11942444d231SYann Gautier ERROR("Clock %lu refcount reached 0\n", id); 11952444d231SYann Gautier panic(); 11962444d231SYann Gautier } 11972444d231SYann Gautier gate_refcounts[i]--; 11982444d231SYann Gautier 11992444d231SYann Gautier if (gate_refcounts[i] == 0U) { 12000d21680cSYann Gautier __clk_disable(gate); 12010d21680cSYann Gautier } 12020d21680cSYann Gautier 12030d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 12040d21680cSYann Gautier } 12050d21680cSYann Gautier 120633667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id) 12070d21680cSYann Gautier { 12080d21680cSYann Gautier __stm32mp1_clk_enable(id, true); 120933667d29SYann Gautier 121033667d29SYann Gautier return 0; 12110d21680cSYann Gautier } 12120d21680cSYann Gautier 121333667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id) 12140d21680cSYann Gautier { 12150d21680cSYann Gautier __stm32mp1_clk_disable(id, true); 12160d21680cSYann Gautier } 12170d21680cSYann Gautier 121833667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id) 12197839a050SYann Gautier { 122035848200SEtienne Carriere int i; 12217839a050SYann Gautier 122235848200SEtienne Carriere if (clock_is_always_on(id)) { 122335848200SEtienne Carriere return true; 122435848200SEtienne Carriere } 122535848200SEtienne Carriere 122635848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 12277839a050SYann Gautier if (i < 0) { 12280d21680cSYann Gautier panic(); 12297839a050SYann Gautier } 12307839a050SYann Gautier 12310d21680cSYann Gautier return __clk_is_enabled(gate_ref(i)); 12327839a050SYann Gautier } 12337839a050SYann Gautier 123433667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id) 12357839a050SYann Gautier { 123633667d29SYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 12370d21680cSYann Gautier int p = stm32mp1_clk_get_parent(id); 123833667d29SYann Gautier uint32_t prescaler, timpre; 123933667d29SYann Gautier unsigned long parent_rate; 12407839a050SYann Gautier 12417839a050SYann Gautier if (p < 0) { 12427839a050SYann Gautier return 0; 12437839a050SYann Gautier } 12447839a050SYann Gautier 124533667d29SYann Gautier parent_rate = get_clock_rate(p); 124633667d29SYann Gautier 124733667d29SYann Gautier switch (id) { 124833667d29SYann Gautier case TIM2_K: 124933667d29SYann Gautier case TIM3_K: 125033667d29SYann Gautier case TIM4_K: 125133667d29SYann Gautier case TIM5_K: 125233667d29SYann Gautier case TIM6_K: 125333667d29SYann Gautier case TIM7_K: 125433667d29SYann Gautier case TIM12_K: 125533667d29SYann Gautier case TIM13_K: 125633667d29SYann Gautier case TIM14_K: 125733667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) & 125833667d29SYann Gautier RCC_APBXDIV_MASK; 125933667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & 126033667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 126133667d29SYann Gautier break; 126233667d29SYann Gautier 126333667d29SYann Gautier case TIM1_K: 126433667d29SYann Gautier case TIM8_K: 126533667d29SYann Gautier case TIM15_K: 126633667d29SYann Gautier case TIM16_K: 126733667d29SYann Gautier case TIM17_K: 126833667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) & 126933667d29SYann Gautier RCC_APBXDIV_MASK; 127033667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & 127133667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 127233667d29SYann Gautier break; 127333667d29SYann Gautier 127433667d29SYann Gautier default: 127533667d29SYann Gautier return parent_rate; 127633667d29SYann Gautier } 127733667d29SYann Gautier 127833667d29SYann Gautier if (prescaler == 0U) { 127933667d29SYann Gautier return parent_rate; 128033667d29SYann Gautier } 128133667d29SYann Gautier 128233667d29SYann Gautier return parent_rate * (timpre + 1U) * 2U; 12837839a050SYann Gautier } 12847839a050SYann Gautier 12850d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) 12867839a050SYann Gautier { 12870d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12887839a050SYann Gautier 12890d21680cSYann Gautier if (enable) { 12907839a050SYann Gautier mmio_setbits_32(address, mask_on); 12917839a050SYann Gautier } else { 12927839a050SYann Gautier mmio_clrbits_32(address, mask_on); 12937839a050SYann Gautier } 12947839a050SYann Gautier } 12957839a050SYann Gautier 12960d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) 12977839a050SYann Gautier { 12980d21680cSYann Gautier uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; 12990d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 13000d21680cSYann Gautier 13010d21680cSYann Gautier mmio_write_32(address, mask_on); 13027839a050SYann Gautier } 13037839a050SYann Gautier 13040d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) 13057839a050SYann Gautier { 1306dfdb057aSYann Gautier uint64_t timeout; 13077839a050SYann Gautier uint32_t mask_test; 13080d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 13097839a050SYann Gautier 13100d21680cSYann Gautier if (enable) { 13117839a050SYann Gautier mask_test = mask_rdy; 13127839a050SYann Gautier } else { 13137839a050SYann Gautier mask_test = 0; 13147839a050SYann Gautier } 13157839a050SYann Gautier 1316dfdb057aSYann Gautier timeout = timeout_init_us(OSCRDY_TIMEOUT); 13177839a050SYann Gautier while ((mmio_read_32(address) & mask_rdy) != mask_test) { 1318dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 13190d21680cSYann Gautier ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", 13207839a050SYann Gautier mask_rdy, address, enable, mmio_read_32(address)); 13217839a050SYann Gautier return -ETIMEDOUT; 13227839a050SYann Gautier } 13237839a050SYann Gautier } 13247839a050SYann Gautier 13257839a050SYann Gautier return 0; 13267839a050SYann Gautier } 13277839a050SYann Gautier 13280d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) 13297839a050SYann Gautier { 13307839a050SYann Gautier uint32_t value; 13310d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13327839a050SYann Gautier 13330d21680cSYann Gautier if (digbyp) { 13340d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); 13350d21680cSYann Gautier } 13360d21680cSYann Gautier 13370d21680cSYann Gautier if (bypass || digbyp) { 13380d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); 13397839a050SYann Gautier } 13407839a050SYann Gautier 13417839a050SYann Gautier /* 13427839a050SYann Gautier * Warning: not recommended to switch directly from "high drive" 13437839a050SYann Gautier * to "medium low drive", and vice-versa. 13447839a050SYann Gautier */ 13450d21680cSYann Gautier value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> 13467839a050SYann Gautier RCC_BDCR_LSEDRV_SHIFT; 13477839a050SYann Gautier 13487839a050SYann Gautier while (value != lsedrv) { 13497839a050SYann Gautier if (value > lsedrv) { 13507839a050SYann Gautier value--; 13517839a050SYann Gautier } else { 13527839a050SYann Gautier value++; 13537839a050SYann Gautier } 13547839a050SYann Gautier 13550d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_BDCR, 13567839a050SYann Gautier RCC_BDCR_LSEDRV_MASK, 13577839a050SYann Gautier value << RCC_BDCR_LSEDRV_SHIFT); 13587839a050SYann Gautier } 13597839a050SYann Gautier 13600d21680cSYann Gautier stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); 13617839a050SYann Gautier } 13627839a050SYann Gautier 13630d21680cSYann Gautier static void stm32mp1_lse_wait(void) 13647839a050SYann Gautier { 13650d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { 13667839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13677839a050SYann Gautier } 13687839a050SYann Gautier } 13697839a050SYann Gautier 13700d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable) 13717839a050SYann Gautier { 13720d21680cSYann Gautier stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); 13730d21680cSYann Gautier 13740d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { 13757839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13767839a050SYann Gautier } 13777839a050SYann Gautier } 13787839a050SYann Gautier 13790d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) 13807839a050SYann Gautier { 13810d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13820d21680cSYann Gautier 13830d21680cSYann Gautier if (digbyp) { 13840d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); 13857839a050SYann Gautier } 13867839a050SYann Gautier 13870d21680cSYann Gautier if (bypass || digbyp) { 13880d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); 13890d21680cSYann Gautier } 13900d21680cSYann Gautier 13910d21680cSYann Gautier stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); 13920d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { 13937839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13947839a050SYann Gautier } 13957839a050SYann Gautier 13967839a050SYann Gautier if (css) { 13970d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); 13987839a050SYann Gautier } 139931e9750bSLionel Debieve 140031e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER 140131e9750bSLionel Debieve if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) && 140231e9750bSLionel Debieve (!(digbyp || bypass))) { 140331e9750bSLionel Debieve panic(); 140431e9750bSLionel Debieve } 140531e9750bSLionel Debieve #endif 14067839a050SYann Gautier } 14077839a050SYann Gautier 14080d21680cSYann Gautier static void stm32mp1_csi_set(bool enable) 14097839a050SYann Gautier { 14100d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); 14110d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { 14127839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14137839a050SYann Gautier } 14147839a050SYann Gautier } 14157839a050SYann Gautier 14160d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable) 14177839a050SYann Gautier { 14180d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); 14190d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { 14207839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14217839a050SYann Gautier } 14227839a050SYann Gautier } 14237839a050SYann Gautier 14240d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv) 14257839a050SYann Gautier { 1426dfdb057aSYann Gautier uint64_t timeout; 14270d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14280d21680cSYann Gautier uintptr_t address = rcc_base + RCC_OCRDYR; 14297839a050SYann Gautier 14300d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, 14317839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK, 14327839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); 14337839a050SYann Gautier 1434dfdb057aSYann Gautier timeout = timeout_init_us(HSIDIV_TIMEOUT); 14357839a050SYann Gautier while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { 1436dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 14370d21680cSYann Gautier ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", 14387839a050SYann Gautier address, mmio_read_32(address)); 14397839a050SYann Gautier return -ETIMEDOUT; 14407839a050SYann Gautier } 14417839a050SYann Gautier } 14427839a050SYann Gautier 14437839a050SYann Gautier return 0; 14447839a050SYann Gautier } 14457839a050SYann Gautier 14460d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq) 14477839a050SYann Gautier { 14487839a050SYann Gautier uint8_t hsidiv; 14497839a050SYann Gautier uint32_t hsidivfreq = MAX_HSI_HZ; 14507839a050SYann Gautier 14517839a050SYann Gautier for (hsidiv = 0; hsidiv < 4U; hsidiv++) { 14527839a050SYann Gautier if (hsidivfreq == hsifreq) { 14537839a050SYann Gautier break; 14547839a050SYann Gautier } 14557839a050SYann Gautier 14567839a050SYann Gautier hsidivfreq /= 2U; 14577839a050SYann Gautier } 14587839a050SYann Gautier 14597839a050SYann Gautier if (hsidiv == 4U) { 14607839a050SYann Gautier ERROR("Invalid clk-hsi frequency\n"); 14617839a050SYann Gautier return -1; 14627839a050SYann Gautier } 14637839a050SYann Gautier 14647839a050SYann Gautier if (hsidiv != 0U) { 14650d21680cSYann Gautier return stm32mp1_set_hsidiv(hsidiv); 14667839a050SYann Gautier } 14677839a050SYann Gautier 14687839a050SYann Gautier return 0; 14697839a050SYann Gautier } 14707839a050SYann Gautier 14710d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, 14720d21680cSYann Gautier unsigned int clksrc, 14730d21680cSYann Gautier uint32_t *pllcfg, int plloff) 14747839a050SYann Gautier { 14750d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 14760d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14770d21680cSYann Gautier uintptr_t pllxcr = rcc_base + pll->pllxcr; 14780d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 14790d21680cSYann Gautier uintptr_t clksrc_address = rcc_base + (clksrc >> 4); 14800d21680cSYann Gautier unsigned long refclk; 14810d21680cSYann Gautier uint32_t ifrge = 0U; 1482be858cffSAndre Przywara uint32_t src, value, fracv = 0; 1483be858cffSAndre Przywara void *fdt; 14847839a050SYann Gautier 14850d21680cSYann Gautier /* Check PLL output */ 14860d21680cSYann Gautier if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { 14870d21680cSYann Gautier return false; 14887839a050SYann Gautier } 14897839a050SYann Gautier 14900d21680cSYann Gautier /* Check current clksrc */ 14910d21680cSYann Gautier src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; 14920d21680cSYann Gautier if (src != (clksrc & RCC_SELR_SRC_MASK)) { 14930d21680cSYann Gautier return false; 14940d21680cSYann Gautier } 14950d21680cSYann Gautier 14960d21680cSYann Gautier /* Check Div */ 14970d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; 14980d21680cSYann Gautier 14990d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 15000d21680cSYann Gautier (pllcfg[PLLCFG_M] + 1U); 15010d21680cSYann Gautier 15020d21680cSYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 15030d21680cSYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 15040d21680cSYann Gautier return false; 15050d21680cSYann Gautier } 15060d21680cSYann Gautier 15070d21680cSYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 15080d21680cSYann Gautier ifrge = 1U; 15090d21680cSYann Gautier } 15100d21680cSYann Gautier 15110d21680cSYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 15120d21680cSYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 15130d21680cSYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 15140d21680cSYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 15150d21680cSYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 15160d21680cSYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 15170d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { 15180d21680cSYann Gautier return false; 15190d21680cSYann Gautier } 15200d21680cSYann Gautier 15210d21680cSYann Gautier /* Fractional configuration */ 1522be858cffSAndre Przywara if (fdt_get_address(&fdt) == 1) { 1523be858cffSAndre Przywara fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1524be858cffSAndre Przywara } 15250d21680cSYann Gautier 15260d21680cSYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 15270d21680cSYann Gautier value |= RCC_PLLNFRACR_FRACLE; 15280d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { 15290d21680cSYann Gautier return false; 15300d21680cSYann Gautier } 15310d21680cSYann Gautier 15320d21680cSYann Gautier /* Output config */ 15330d21680cSYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15340d21680cSYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15350d21680cSYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15360d21680cSYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15370d21680cSYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15380d21680cSYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15390d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { 15400d21680cSYann Gautier return false; 15410d21680cSYann Gautier } 15420d21680cSYann Gautier 15430d21680cSYann Gautier return true; 15440d21680cSYann Gautier } 15450d21680cSYann Gautier 15460d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) 15477839a050SYann Gautier { 15480d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15490d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 15500d21680cSYann Gautier 1551dd98aec8SYann Gautier /* Preserve RCC_PLLNCR_SSCG_CTRL value */ 1552dd98aec8SYann Gautier mmio_clrsetbits_32(pllxcr, 1553dd98aec8SYann Gautier RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 1554dd98aec8SYann Gautier RCC_PLLNCR_DIVREN, 1555dd98aec8SYann Gautier RCC_PLLNCR_PLLON); 15560d21680cSYann Gautier } 15570d21680cSYann Gautier 15580d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) 15590d21680cSYann Gautier { 15600d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15610d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1562dfdb057aSYann Gautier uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); 15637839a050SYann Gautier 15647839a050SYann Gautier /* Wait PLL lock */ 15657839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { 1566dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 1567*9fa9a0c5SYann Gautier ERROR("PLL%u start failed @ 0x%lx: 0x%x\n", 15687839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15697839a050SYann Gautier return -ETIMEDOUT; 15707839a050SYann Gautier } 15717839a050SYann Gautier } 15727839a050SYann Gautier 15737839a050SYann Gautier /* Start the requested output */ 15747839a050SYann Gautier mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); 15757839a050SYann Gautier 15767839a050SYann Gautier return 0; 15777839a050SYann Gautier } 15787839a050SYann Gautier 15790d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) 15807839a050SYann Gautier { 15810d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15820d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1583dfdb057aSYann Gautier uint64_t timeout; 15847839a050SYann Gautier 15857839a050SYann Gautier /* Stop all output */ 15867839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 15877839a050SYann Gautier RCC_PLLNCR_DIVREN); 15887839a050SYann Gautier 15897839a050SYann Gautier /* Stop PLL */ 15907839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); 15917839a050SYann Gautier 1592dfdb057aSYann Gautier timeout = timeout_init_us(PLLRDY_TIMEOUT); 15937839a050SYann Gautier /* Wait PLL stopped */ 15947839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { 1595dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 1596*9fa9a0c5SYann Gautier ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n", 15977839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15987839a050SYann Gautier return -ETIMEDOUT; 15997839a050SYann Gautier } 16007839a050SYann Gautier } 16017839a050SYann Gautier 16027839a050SYann Gautier return 0; 16037839a050SYann Gautier } 16047839a050SYann Gautier 16050d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, 16067839a050SYann Gautier uint32_t *pllcfg) 16077839a050SYann Gautier { 16080d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16090d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16107839a050SYann Gautier uint32_t value; 16117839a050SYann Gautier 16127839a050SYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 16137839a050SYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 16147839a050SYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 16157839a050SYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 16167839a050SYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 16177839a050SYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 16180d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr2, value); 16197839a050SYann Gautier } 16207839a050SYann Gautier 16210d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, 16227839a050SYann Gautier uint32_t *pllcfg, uint32_t fracv) 16237839a050SYann Gautier { 16240d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16250d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16260d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 16277839a050SYann Gautier unsigned long refclk; 16287839a050SYann Gautier uint32_t ifrge = 0; 16297839a050SYann Gautier uint32_t src, value; 16307839a050SYann Gautier 16310d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & 16327839a050SYann Gautier RCC_SELR_REFCLK_SRC_MASK; 16337839a050SYann Gautier 16340d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 16357839a050SYann Gautier (pllcfg[PLLCFG_M] + 1U); 16367839a050SYann Gautier 16377839a050SYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 16387839a050SYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 16397839a050SYann Gautier return -EINVAL; 16407839a050SYann Gautier } 16417839a050SYann Gautier 16427839a050SYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 16437839a050SYann Gautier ifrge = 1U; 16447839a050SYann Gautier } 16457839a050SYann Gautier 16467839a050SYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 16477839a050SYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 16487839a050SYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 16497839a050SYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 16507839a050SYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 16517839a050SYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 16520d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr1, value); 16537839a050SYann Gautier 16547839a050SYann Gautier /* Fractional configuration */ 16557839a050SYann Gautier value = 0; 16560d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16577839a050SYann Gautier 16587839a050SYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 16590d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16607839a050SYann Gautier 16617839a050SYann Gautier value |= RCC_PLLNFRACR_FRACLE; 16620d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16637839a050SYann Gautier 16640d21680cSYann Gautier stm32mp1_pll_config_output(pll_id, pllcfg); 16657839a050SYann Gautier 16667839a050SYann Gautier return 0; 16677839a050SYann Gautier } 16687839a050SYann Gautier 16690d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) 16707839a050SYann Gautier { 16710d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16727839a050SYann Gautier uint32_t pllxcsg = 0; 16737839a050SYann Gautier 16747839a050SYann Gautier pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & 16757839a050SYann Gautier RCC_PLLNCSGR_MOD_PER_MASK; 16767839a050SYann Gautier 16777839a050SYann Gautier pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & 16787839a050SYann Gautier RCC_PLLNCSGR_INC_STEP_MASK; 16797839a050SYann Gautier 16807839a050SYann Gautier pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & 16817839a050SYann Gautier RCC_PLLNCSGR_SSCG_MODE_MASK; 16827839a050SYann Gautier 16830d21680cSYann Gautier mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); 1684dd98aec8SYann Gautier 1685dd98aec8SYann Gautier mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, 1686dd98aec8SYann Gautier RCC_PLLNCR_SSCG_CTRL); 16877839a050SYann Gautier } 16887839a050SYann Gautier 16890d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc) 16907839a050SYann Gautier { 16910d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 1692dfdb057aSYann Gautier uint64_t timeout; 16937839a050SYann Gautier 16940d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, 16957839a050SYann Gautier clksrc & RCC_SELR_SRC_MASK); 16967839a050SYann Gautier 1697dfdb057aSYann Gautier timeout = timeout_init_us(CLKSRC_TIMEOUT); 16980d21680cSYann Gautier while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { 1699dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17000d21680cSYann Gautier ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, 17010d21680cSYann Gautier clksrc_address, mmio_read_32(clksrc_address)); 17027839a050SYann Gautier return -ETIMEDOUT; 17037839a050SYann Gautier } 17047839a050SYann Gautier } 17057839a050SYann Gautier 17067839a050SYann Gautier return 0; 17077839a050SYann Gautier } 17087839a050SYann Gautier 17090d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) 17107839a050SYann Gautier { 1711dfdb057aSYann Gautier uint64_t timeout; 17127839a050SYann Gautier 17137839a050SYann Gautier mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, 17147839a050SYann Gautier clkdiv & RCC_DIVR_DIV_MASK); 17157839a050SYann Gautier 1716dfdb057aSYann Gautier timeout = timeout_init_us(CLKDIV_TIMEOUT); 17177839a050SYann Gautier while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { 1718dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17190d21680cSYann Gautier ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", 17207839a050SYann Gautier clkdiv, address, mmio_read_32(address)); 17217839a050SYann Gautier return -ETIMEDOUT; 17227839a050SYann Gautier } 17237839a050SYann Gautier } 17247839a050SYann Gautier 17257839a050SYann Gautier return 0; 17267839a050SYann Gautier } 17277839a050SYann Gautier 17280d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) 17297839a050SYann Gautier { 17300d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 17317839a050SYann Gautier 17327839a050SYann Gautier /* 17337839a050SYann Gautier * Binding clksrc : 17347839a050SYann Gautier * bit15-4 offset 17357839a050SYann Gautier * bit3: disable 17367839a050SYann Gautier * bit2-0: MCOSEL[2:0] 17377839a050SYann Gautier */ 17387839a050SYann Gautier if ((clksrc & 0x8U) != 0U) { 17390d21680cSYann Gautier mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17407839a050SYann Gautier } else { 17410d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17427839a050SYann Gautier RCC_MCOCFG_MCOSRC_MASK, 17437839a050SYann Gautier clksrc & RCC_MCOCFG_MCOSRC_MASK); 17440d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17457839a050SYann Gautier RCC_MCOCFG_MCODIV_MASK, 17467839a050SYann Gautier clkdiv << RCC_MCOCFG_MCODIV_SHIFT); 17470d21680cSYann Gautier mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17487839a050SYann Gautier } 17497839a050SYann Gautier } 17507839a050SYann Gautier 17510d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) 17527839a050SYann Gautier { 17530d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; 17547839a050SYann Gautier 17557839a050SYann Gautier if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || 17567839a050SYann Gautier (clksrc != (uint32_t)CLK_RTC_DISABLED)) { 17577839a050SYann Gautier mmio_clrsetbits_32(address, 17587839a050SYann Gautier RCC_BDCR_RTCSRC_MASK, 175915509093SYann Gautier (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); 17607839a050SYann Gautier 17617839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_RTCCKEN); 17627839a050SYann Gautier } 17637839a050SYann Gautier 17647839a050SYann Gautier if (lse_css) { 17657839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_LSECSSON); 17667839a050SYann Gautier } 17677839a050SYann Gautier } 17687839a050SYann Gautier 17690d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs) 17707839a050SYann Gautier { 17710d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); 17727839a050SYann Gautier uint32_t value = pkcs & 0xFU; 17737839a050SYann Gautier uint32_t mask = 0xFU; 17747839a050SYann Gautier 17757839a050SYann Gautier if ((pkcs & BIT(31)) != 0U) { 17767839a050SYann Gautier mask <<= 4; 17777839a050SYann Gautier value <<= 4; 17787839a050SYann Gautier } 17797839a050SYann Gautier 17807839a050SYann Gautier mmio_clrsetbits_32(address, mask, value); 17817839a050SYann Gautier } 17827839a050SYann Gautier 1783964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, 1784964e5ff1SNicolas Le Bayon uint32_t *fracv, uint32_t *csg, 1785964e5ff1SNicolas Le Bayon bool *csg_set) 1786964e5ff1SNicolas Le Bayon { 1787964e5ff1SNicolas Le Bayon void *fdt; 1788964e5ff1SNicolas Le Bayon int ret; 1789964e5ff1SNicolas Le Bayon 1790964e5ff1SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 1791964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1792964e5ff1SNicolas Le Bayon } 1793964e5ff1SNicolas Le Bayon 1794964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB, 1795964e5ff1SNicolas Le Bayon pllcfg); 1796964e5ff1SNicolas Le Bayon if (ret < 0) { 1797964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1798964e5ff1SNicolas Le Bayon } 1799964e5ff1SNicolas Le Bayon 1800964e5ff1SNicolas Le Bayon *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1801964e5ff1SNicolas Le Bayon 1802964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB, 1803964e5ff1SNicolas Le Bayon csg); 1804964e5ff1SNicolas Le Bayon 1805964e5ff1SNicolas Le Bayon *csg_set = (ret == 0); 1806964e5ff1SNicolas Le Bayon 1807964e5ff1SNicolas Le Bayon if (ret == -FDT_ERR_NOTFOUND) { 1808964e5ff1SNicolas Le Bayon ret = 0; 1809964e5ff1SNicolas Le Bayon } 1810964e5ff1SNicolas Le Bayon 1811964e5ff1SNicolas Le Bayon return ret; 1812964e5ff1SNicolas Le Bayon } 1813964e5ff1SNicolas Le Bayon 18147839a050SYann Gautier int stm32mp1_clk_init(void) 18157839a050SYann Gautier { 18160d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 1817964e5ff1SNicolas Le Bayon uint32_t pllfracv[_PLL_NB]; 1818964e5ff1SNicolas Le Bayon uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; 18197839a050SYann Gautier unsigned int clksrc[CLKSRC_NB]; 18207839a050SYann Gautier unsigned int clkdiv[CLKDIV_NB]; 18217839a050SYann Gautier unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; 18227839a050SYann Gautier int plloff[_PLL_NB]; 18237839a050SYann Gautier int ret, len; 18247839a050SYann Gautier enum stm32mp1_pll_id i; 1825964e5ff1SNicolas Le Bayon bool pllcsg_set[_PLL_NB]; 1826964e5ff1SNicolas Le Bayon bool pllcfg_valid[_PLL_NB]; 18277839a050SYann Gautier bool lse_css = false; 18280d21680cSYann Gautier bool pll3_preserve = false; 18290d21680cSYann Gautier bool pll4_preserve = false; 18300d21680cSYann Gautier bool pll4_bootrom = false; 18313e6fab43SYann Gautier const fdt32_t *pkcs_cell; 183252a616b4SAndre Przywara void *fdt; 1833bf1af154SPatrick Delaunay int stgen_p = stm32mp1_clk_get_parent(STGEN_K); 1834bf1af154SPatrick Delaunay int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K); 183552a616b4SAndre Przywara 183652a616b4SAndre Przywara if (fdt_get_address(&fdt) == 0) { 18378f97c4faSYann Gautier return -FDT_ERR_NOTFOUND; 183852a616b4SAndre Przywara } 18397839a050SYann Gautier 184052a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, 184152a616b4SAndre Przywara clksrc); 18427839a050SYann Gautier if (ret < 0) { 18437839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18447839a050SYann Gautier } 18457839a050SYann Gautier 184652a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, 184752a616b4SAndre Przywara clkdiv); 18487839a050SYann Gautier if (ret < 0) { 18497839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18507839a050SYann Gautier } 18517839a050SYann Gautier 18527839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 18537839a050SYann Gautier char name[12]; 18547839a050SYann Gautier 1855*9fa9a0c5SYann Gautier snprintf(name, sizeof(name), "st,pll@%u", i); 18567839a050SYann Gautier plloff[i] = fdt_rcc_subnode_offset(name); 18577839a050SYann Gautier 1858964e5ff1SNicolas Le Bayon pllcfg_valid[i] = fdt_check_node(plloff[i]); 1859964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 18607839a050SYann Gautier continue; 18617839a050SYann Gautier } 18627839a050SYann Gautier 1863964e5ff1SNicolas Le Bayon ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], 1864964e5ff1SNicolas Le Bayon &pllfracv[i], pllcsg[i], 1865964e5ff1SNicolas Le Bayon &pllcsg_set[i]); 1866964e5ff1SNicolas Le Bayon if (ret != 0) { 1867964e5ff1SNicolas Le Bayon return ret; 18687839a050SYann Gautier } 18697839a050SYann Gautier } 18707839a050SYann Gautier 18710d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); 18720d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); 18737839a050SYann Gautier 18747839a050SYann Gautier /* 18757839a050SYann Gautier * Switch ON oscillator found in device-tree. 18767839a050SYann Gautier * Note: HSI already ON after BootROM stage. 18777839a050SYann Gautier */ 18780d21680cSYann Gautier if (stm32mp1_osc[_LSI] != 0U) { 18790d21680cSYann Gautier stm32mp1_lsi_set(true); 18807839a050SYann Gautier } 18810d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 1882b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_LSE]; 18830d21680cSYann Gautier bool bypass, digbyp; 18847839a050SYann Gautier uint32_t lsedrv; 18857839a050SYann Gautier 1886b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1887b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1888b208e3daSGabriel Fernandez lse_css = fdt_clk_read_bool(name, "st,css"); 1889b208e3daSGabriel Fernandez lsedrv = fdt_clk_read_uint32_default(name, "st,drive", 18907839a050SYann Gautier LSEDRV_MEDIUM_HIGH); 18910d21680cSYann Gautier stm32mp1_lse_enable(bypass, digbyp, lsedrv); 18927839a050SYann Gautier } 18930d21680cSYann Gautier if (stm32mp1_osc[_HSE] != 0U) { 1894b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_HSE]; 18950d21680cSYann Gautier bool bypass, digbyp, css; 18967839a050SYann Gautier 1897b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1898b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1899b208e3daSGabriel Fernandez css = fdt_clk_read_bool(name, "st,css"); 19000d21680cSYann Gautier stm32mp1_hse_enable(bypass, digbyp, css); 19017839a050SYann Gautier } 19027839a050SYann Gautier /* 19037839a050SYann Gautier * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) 19047839a050SYann Gautier * => switch on CSI even if node is not present in device tree 19057839a050SYann Gautier */ 19060d21680cSYann Gautier stm32mp1_csi_set(true); 19077839a050SYann Gautier 19087839a050SYann Gautier /* Come back to HSI */ 19090d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_MPU_HSI); 19107839a050SYann Gautier if (ret != 0) { 19117839a050SYann Gautier return ret; 19127839a050SYann Gautier } 19130d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_AXI_HSI); 19147839a050SYann Gautier if (ret != 0) { 19157839a050SYann Gautier return ret; 19167839a050SYann Gautier } 1917b053a22eSYann Gautier ret = stm32mp1_set_clksrc(CLK_MCU_HSI); 1918b053a22eSYann Gautier if (ret != 0) { 1919b053a22eSYann Gautier return ret; 1920b053a22eSYann Gautier } 19217839a050SYann Gautier 19220d21680cSYann Gautier if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & 19230d21680cSYann Gautier RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { 19240d21680cSYann Gautier pll3_preserve = stm32mp1_check_pll_conf(_PLL3, 19250d21680cSYann Gautier clksrc[CLKSRC_PLL3], 19260d21680cSYann Gautier pllcfg[_PLL3], 19270d21680cSYann Gautier plloff[_PLL3]); 19280d21680cSYann Gautier pll4_preserve = stm32mp1_check_pll_conf(_PLL4, 19290d21680cSYann Gautier clksrc[CLKSRC_PLL4], 19300d21680cSYann Gautier pllcfg[_PLL4], 19310d21680cSYann Gautier plloff[_PLL4]); 19320d21680cSYann Gautier } 1933bf1af154SPatrick Delaunay /* Don't initialize PLL4, when used by BOOTROM */ 1934bf1af154SPatrick Delaunay if ((stm32mp_get_boot_itf_selected() == 1935bf1af154SPatrick Delaunay BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) && 1936bf1af154SPatrick Delaunay ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { 1937bf1af154SPatrick Delaunay pll4_bootrom = true; 1938bf1af154SPatrick Delaunay pll4_preserve = true; 1939bf1af154SPatrick Delaunay } 19400d21680cSYann Gautier 19417839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19420d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 19430d21680cSYann Gautier ((i == _PLL4) && pll4_preserve)) { 19447839a050SYann Gautier continue; 19450d21680cSYann Gautier } 19460d21680cSYann Gautier 19470d21680cSYann Gautier ret = stm32mp1_pll_stop(i); 19487839a050SYann Gautier if (ret != 0) { 19497839a050SYann Gautier return ret; 19507839a050SYann Gautier } 19517839a050SYann Gautier } 19527839a050SYann Gautier 19537839a050SYann Gautier /* Configure HSIDIV */ 19540d21680cSYann Gautier if (stm32mp1_osc[_HSI] != 0U) { 19550d21680cSYann Gautier ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); 19567839a050SYann Gautier if (ret != 0) { 19577839a050SYann Gautier return ret; 19587839a050SYann Gautier } 1959591d80c8SLionel Debieve 1960591d80c8SLionel Debieve stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K)); 19617839a050SYann Gautier } 19627839a050SYann Gautier 19637839a050SYann Gautier /* Select DIV */ 19647839a050SYann Gautier /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ 19650d21680cSYann Gautier mmio_write_32(rcc_base + RCC_MPCKDIVR, 19667839a050SYann Gautier clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 19670d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); 19687839a050SYann Gautier if (ret != 0) { 19697839a050SYann Gautier return ret; 19707839a050SYann Gautier } 19710d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); 19727839a050SYann Gautier if (ret != 0) { 19737839a050SYann Gautier return ret; 19747839a050SYann Gautier } 19750d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); 19767839a050SYann Gautier if (ret != 0) { 19777839a050SYann Gautier return ret; 19787839a050SYann Gautier } 1979b053a22eSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); 1980b053a22eSYann Gautier if (ret != 0) { 1981b053a22eSYann Gautier return ret; 1982b053a22eSYann Gautier } 19830d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); 19847839a050SYann Gautier if (ret != 0) { 19857839a050SYann Gautier return ret; 19867839a050SYann Gautier } 19870d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); 19887839a050SYann Gautier if (ret != 0) { 19897839a050SYann Gautier return ret; 19907839a050SYann Gautier } 19910d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); 19927839a050SYann Gautier if (ret != 0) { 19937839a050SYann Gautier return ret; 19947839a050SYann Gautier } 19957839a050SYann Gautier 19967839a050SYann Gautier /* No ready bit for RTC */ 19970d21680cSYann Gautier mmio_write_32(rcc_base + RCC_RTCDIVR, 19987839a050SYann Gautier clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); 19997839a050SYann Gautier 20007839a050SYann Gautier /* Configure PLLs source */ 20010d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); 20027839a050SYann Gautier if (ret != 0) { 20037839a050SYann Gautier return ret; 20047839a050SYann Gautier } 20057839a050SYann Gautier 20060d21680cSYann Gautier if (!pll3_preserve) { 20070d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); 20087839a050SYann Gautier if (ret != 0) { 20097839a050SYann Gautier return ret; 20107839a050SYann Gautier } 20110d21680cSYann Gautier } 20120d21680cSYann Gautier 20130d21680cSYann Gautier if (!pll4_preserve) { 20140d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); 20150d21680cSYann Gautier if (ret != 0) { 20160d21680cSYann Gautier return ret; 20170d21680cSYann Gautier } 20180d21680cSYann Gautier } 20197839a050SYann Gautier 20207839a050SYann Gautier /* Configure and start PLLs */ 20217839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 20220d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 20230d21680cSYann Gautier ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { 20240d21680cSYann Gautier continue; 20250d21680cSYann Gautier } 20260d21680cSYann Gautier 2027964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20287839a050SYann Gautier continue; 20297839a050SYann Gautier } 20307839a050SYann Gautier 20310d21680cSYann Gautier if ((i == _PLL4) && pll4_bootrom) { 20320d21680cSYann Gautier /* Set output divider if not done by the Bootrom */ 20330d21680cSYann Gautier stm32mp1_pll_config_output(i, pllcfg[i]); 20340d21680cSYann Gautier continue; 20350d21680cSYann Gautier } 20360d21680cSYann Gautier 2037964e5ff1SNicolas Le Bayon ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); 20387839a050SYann Gautier if (ret != 0) { 20397839a050SYann Gautier return ret; 20407839a050SYann Gautier } 2041964e5ff1SNicolas Le Bayon 2042964e5ff1SNicolas Le Bayon if (pllcsg_set[i]) { 2043964e5ff1SNicolas Le Bayon stm32mp1_pll_csg(i, pllcsg[i]); 20447839a050SYann Gautier } 20457839a050SYann Gautier 20460d21680cSYann Gautier stm32mp1_pll_start(i); 20477839a050SYann Gautier } 20487839a050SYann Gautier /* Wait and start PLLs ouptut when ready */ 20497839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 2050964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20517839a050SYann Gautier continue; 20527839a050SYann Gautier } 20537839a050SYann Gautier 20540d21680cSYann Gautier ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); 20557839a050SYann Gautier if (ret != 0) { 20567839a050SYann Gautier return ret; 20577839a050SYann Gautier } 20587839a050SYann Gautier } 20597839a050SYann Gautier /* Wait LSE ready before to use it */ 20600d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 20610d21680cSYann Gautier stm32mp1_lse_wait(); 20627839a050SYann Gautier } 20637839a050SYann Gautier 20647839a050SYann Gautier /* Configure with expected clock source */ 20650d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); 20667839a050SYann Gautier if (ret != 0) { 20677839a050SYann Gautier return ret; 20687839a050SYann Gautier } 20690d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); 20707839a050SYann Gautier if (ret != 0) { 20717839a050SYann Gautier return ret; 20727839a050SYann Gautier } 2073b053a22eSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); 2074b053a22eSYann Gautier if (ret != 0) { 2075b053a22eSYann Gautier return ret; 2076b053a22eSYann Gautier } 20770d21680cSYann Gautier stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); 20787839a050SYann Gautier 20797839a050SYann Gautier /* Configure PKCK */ 20807839a050SYann Gautier pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); 20817839a050SYann Gautier if (pkcs_cell != NULL) { 20827839a050SYann Gautier bool ckper_disabled = false; 20837839a050SYann Gautier uint32_t j; 2084bf1af154SPatrick Delaunay uint32_t usbreg_bootrom = 0U; 2085bf1af154SPatrick Delaunay 2086bf1af154SPatrick Delaunay if (pll4_bootrom) { 2087bf1af154SPatrick Delaunay usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); 2088bf1af154SPatrick Delaunay } 20897839a050SYann Gautier 20907839a050SYann Gautier for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { 20913e6fab43SYann Gautier uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); 20927839a050SYann Gautier 20937839a050SYann Gautier if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { 20947839a050SYann Gautier ckper_disabled = true; 20957839a050SYann Gautier continue; 20967839a050SYann Gautier } 20970d21680cSYann Gautier stm32mp1_pkcs_config(pkcs); 20987839a050SYann Gautier } 20997839a050SYann Gautier 21007839a050SYann Gautier /* 21017839a050SYann Gautier * CKPER is source for some peripheral clocks 21027839a050SYann Gautier * (FMC-NAND / QPSI-NOR) and switching source is allowed 21037839a050SYann Gautier * only if previous clock is still ON 21047839a050SYann Gautier * => deactivated CKPER only after switching clock 21057839a050SYann Gautier */ 21067839a050SYann Gautier if (ckper_disabled) { 21070d21680cSYann Gautier stm32mp1_pkcs_config(CLK_CKPER_DISABLED); 21087839a050SYann Gautier } 2109bf1af154SPatrick Delaunay 2110bf1af154SPatrick Delaunay if (pll4_bootrom) { 2111bf1af154SPatrick Delaunay uint32_t usbreg_value, usbreg_mask; 2112bf1af154SPatrick Delaunay const struct stm32mp1_clk_sel *sel; 2113bf1af154SPatrick Delaunay 2114bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBPHY_SEL); 2115bf1af154SPatrick Delaunay usbreg_mask = (uint32_t)sel->msk << sel->src; 2116bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBO_SEL); 2117bf1af154SPatrick Delaunay usbreg_mask |= (uint32_t)sel->msk << sel->src; 2118bf1af154SPatrick Delaunay 2119bf1af154SPatrick Delaunay usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & 2120bf1af154SPatrick Delaunay usbreg_mask; 2121bf1af154SPatrick Delaunay usbreg_bootrom &= usbreg_mask; 2122bf1af154SPatrick Delaunay if (usbreg_bootrom != usbreg_value) { 2123bf1af154SPatrick Delaunay VERBOSE("forbidden new USB clk path\n"); 2124bf1af154SPatrick Delaunay VERBOSE("vs bootrom on USB boot\n"); 2125bf1af154SPatrick Delaunay return -FDT_ERR_BADVALUE; 2126bf1af154SPatrick Delaunay } 2127bf1af154SPatrick Delaunay } 21287839a050SYann Gautier } 21297839a050SYann Gautier 21307839a050SYann Gautier /* Switch OFF HSI if not found in device-tree */ 21310d21680cSYann Gautier if (stm32mp1_osc[_HSI] == 0U) { 21320d21680cSYann Gautier stm32mp1_hsi_set(false); 21337839a050SYann Gautier } 2134591d80c8SLionel Debieve 2135591d80c8SLionel Debieve stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K)); 21367839a050SYann Gautier 21377839a050SYann Gautier /* Software Self-Refresh mode (SSR) during DDR initilialization */ 21380d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, 21397839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_MASK, 21407839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SSR << 21417839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SHIFT); 21427839a050SYann Gautier 21437839a050SYann Gautier return 0; 21447839a050SYann Gautier } 21457839a050SYann Gautier 21467839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name, 21477839a050SYann Gautier enum stm32mp_osc_id index) 21487839a050SYann Gautier { 21497839a050SYann Gautier uint32_t frequency; 21507839a050SYann Gautier 21510d21680cSYann Gautier if (fdt_osc_read_freq(name, &frequency) == 0) { 21520d21680cSYann Gautier stm32mp1_osc[index] = frequency; 21537839a050SYann Gautier } 21547839a050SYann Gautier } 21557839a050SYann Gautier 21567839a050SYann Gautier static void stm32mp1_osc_init(void) 21577839a050SYann Gautier { 21587839a050SYann Gautier enum stm32mp_osc_id i; 21597839a050SYann Gautier 21607839a050SYann Gautier for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { 21610d21680cSYann Gautier stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); 21627839a050SYann Gautier } 21637839a050SYann Gautier } 21647839a050SYann Gautier 216537e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES 216637e8295aSEtienne Carriere /* 216737e8295aSEtienne Carriere * Get the parent ID of the target parent clock, for tagging as secure 216837e8295aSEtienne Carriere * shared clock dependencies. 216937e8295aSEtienne Carriere */ 217037e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id) 217137e8295aSEtienne Carriere { 217237e8295aSEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 217337e8295aSEtienne Carriere enum stm32mp1_pll_id pll_id; 217437e8295aSEtienne Carriere uint32_t p_sel; 217537e8295aSEtienne Carriere uintptr_t rcc_base = stm32mp_rcc_base(); 217637e8295aSEtienne Carriere 217737e8295aSEtienne Carriere switch (parent_id) { 217837e8295aSEtienne Carriere case _ACLK: 217937e8295aSEtienne Carriere case _PCLK4: 218037e8295aSEtienne Carriere case _PCLK5: 218137e8295aSEtienne Carriere s = _AXIS_SEL; 218237e8295aSEtienne Carriere break; 218337e8295aSEtienne Carriere case _PLL1_P: 218437e8295aSEtienne Carriere case _PLL1_Q: 218537e8295aSEtienne Carriere case _PLL1_R: 218637e8295aSEtienne Carriere pll_id = _PLL1; 218737e8295aSEtienne Carriere break; 218837e8295aSEtienne Carriere case _PLL2_P: 218937e8295aSEtienne Carriere case _PLL2_Q: 219037e8295aSEtienne Carriere case _PLL2_R: 219137e8295aSEtienne Carriere pll_id = _PLL2; 219237e8295aSEtienne Carriere break; 219337e8295aSEtienne Carriere case _PLL3_P: 219437e8295aSEtienne Carriere case _PLL3_Q: 219537e8295aSEtienne Carriere case _PLL3_R: 219637e8295aSEtienne Carriere pll_id = _PLL3; 219737e8295aSEtienne Carriere break; 219837e8295aSEtienne Carriere case _PLL4_P: 219937e8295aSEtienne Carriere case _PLL4_Q: 220037e8295aSEtienne Carriere case _PLL4_R: 220137e8295aSEtienne Carriere pll_id = _PLL4; 220237e8295aSEtienne Carriere break; 220337e8295aSEtienne Carriere case _PCLK1: 220437e8295aSEtienne Carriere case _PCLK2: 220537e8295aSEtienne Carriere case _HCLK2: 220637e8295aSEtienne Carriere case _HCLK6: 220737e8295aSEtienne Carriere case _CK_PER: 220837e8295aSEtienne Carriere case _CK_MPU: 220937e8295aSEtienne Carriere case _CK_MCU: 221037e8295aSEtienne Carriere case _USB_PHY_48: 221137e8295aSEtienne Carriere /* We do not expect to access these */ 221237e8295aSEtienne Carriere panic(); 221337e8295aSEtienne Carriere break; 221437e8295aSEtienne Carriere default: 221537e8295aSEtienne Carriere /* Other parents have no parent */ 221637e8295aSEtienne Carriere return -1; 221737e8295aSEtienne Carriere } 221837e8295aSEtienne Carriere 221937e8295aSEtienne Carriere if (s != _UNKNOWN_SEL) { 222037e8295aSEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 222137e8295aSEtienne Carriere 222237e8295aSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & 222337e8295aSEtienne Carriere sel->msk; 222437e8295aSEtienne Carriere 222537e8295aSEtienne Carriere if (p_sel < sel->nb_parent) { 222637e8295aSEtienne Carriere return (int)sel->parent[p_sel]; 222737e8295aSEtienne Carriere } 222837e8295aSEtienne Carriere } else { 222937e8295aSEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 223037e8295aSEtienne Carriere 223137e8295aSEtienne Carriere p_sel = mmio_read_32(rcc_base + pll->rckxselr) & 223237e8295aSEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 223337e8295aSEtienne Carriere 223437e8295aSEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { 223537e8295aSEtienne Carriere return (int)pll->refclk[p_sel]; 223637e8295aSEtienne Carriere } 223737e8295aSEtienne Carriere } 223837e8295aSEtienne Carriere 223937e8295aSEtienne Carriere VERBOSE("No parent selected for %s\n", 224037e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 224137e8295aSEtienne Carriere 224237e8295aSEtienne Carriere return -1; 224337e8295aSEtienne Carriere } 224437e8295aSEtienne Carriere 224537e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id) 224637e8295aSEtienne Carriere { 224737e8295aSEtienne Carriere int grandparent_id; 224837e8295aSEtienne Carriere 224937e8295aSEtienne Carriere switch (parent_id) { 225037e8295aSEtienne Carriere case _PLL3_P: 225137e8295aSEtienne Carriere case _PLL3_Q: 225237e8295aSEtienne Carriere case _PLL3_R: 225337e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 225437e8295aSEtienne Carriere break; 225537e8295aSEtienne Carriere 225637e8295aSEtienne Carriere /* These clocks are always secure when RCC is secure */ 225737e8295aSEtienne Carriere case _ACLK: 225837e8295aSEtienne Carriere case _HCLK2: 225937e8295aSEtienne Carriere case _HCLK6: 226037e8295aSEtienne Carriere case _PCLK4: 226137e8295aSEtienne Carriere case _PCLK5: 226237e8295aSEtienne Carriere case _PLL1_P: 226337e8295aSEtienne Carriere case _PLL1_Q: 226437e8295aSEtienne Carriere case _PLL1_R: 226537e8295aSEtienne Carriere case _PLL2_P: 226637e8295aSEtienne Carriere case _PLL2_Q: 226737e8295aSEtienne Carriere case _PLL2_R: 226837e8295aSEtienne Carriere case _HSI: 226937e8295aSEtienne Carriere case _HSI_KER: 227037e8295aSEtienne Carriere case _LSI: 227137e8295aSEtienne Carriere case _CSI: 227237e8295aSEtienne Carriere case _CSI_KER: 227337e8295aSEtienne Carriere case _HSE: 227437e8295aSEtienne Carriere case _HSE_KER: 227537e8295aSEtienne Carriere case _HSE_KER_DIV2: 2276cbd2e8a6SGabriel Fernandez case _HSE_RTC: 227737e8295aSEtienne Carriere case _LSE: 227837e8295aSEtienne Carriere break; 227937e8295aSEtienne Carriere 228037e8295aSEtienne Carriere default: 228137e8295aSEtienne Carriere VERBOSE("Cannot secure parent clock %s\n", 228237e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 228337e8295aSEtienne Carriere panic(); 228437e8295aSEtienne Carriere } 228537e8295aSEtienne Carriere 228637e8295aSEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 228737e8295aSEtienne Carriere if (grandparent_id >= 0) { 228837e8295aSEtienne Carriere secure_parent_clocks(grandparent_id); 228937e8295aSEtienne Carriere } 229037e8295aSEtienne Carriere } 229137e8295aSEtienne Carriere 229237e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id) 229337e8295aSEtienne Carriere { 229437e8295aSEtienne Carriere int parent_id; 229537e8295aSEtienne Carriere 229637e8295aSEtienne Carriere if (!stm32mp1_rcc_is_secure()) { 229737e8295aSEtienne Carriere return; 229837e8295aSEtienne Carriere } 229937e8295aSEtienne Carriere 230037e8295aSEtienne Carriere switch (clock_id) { 230137e8295aSEtienne Carriere case PLL1: 230237e8295aSEtienne Carriere case PLL2: 230337e8295aSEtienne Carriere /* PLL1/PLL2 are always secure: nothing to do */ 230437e8295aSEtienne Carriere break; 230537e8295aSEtienne Carriere case PLL3: 230637e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 230737e8295aSEtienne Carriere break; 230837e8295aSEtienne Carriere case PLL4: 230937e8295aSEtienne Carriere ERROR("PLL4 cannot be secured\n"); 231037e8295aSEtienne Carriere panic(); 231137e8295aSEtienne Carriere break; 231237e8295aSEtienne Carriere default: 231337e8295aSEtienne Carriere /* Others are expected gateable clock */ 231437e8295aSEtienne Carriere parent_id = stm32mp1_clk_get_parent(clock_id); 231537e8295aSEtienne Carriere if (parent_id < 0) { 231637e8295aSEtienne Carriere INFO("No parent found for clock %lu\n", clock_id); 231737e8295aSEtienne Carriere } else { 231837e8295aSEtienne Carriere secure_parent_clocks(parent_id); 231937e8295aSEtienne Carriere } 232037e8295aSEtienne Carriere break; 232137e8295aSEtienne Carriere } 232237e8295aSEtienne Carriere } 232337e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */ 232437e8295aSEtienne Carriere 23256cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void) 23266cb45f89SYann Gautier { 2327033b6c3aSEtienne Carriere unsigned int idx; 2328033b6c3aSEtienne Carriere const unsigned long secure_enable[] = { 2329033b6c3aSEtienne Carriere AXIDCG, 2330033b6c3aSEtienne Carriere BSEC, 2331033b6c3aSEtienne Carriere DDRC1, DDRC1LP, 2332033b6c3aSEtienne Carriere DDRC2, DDRC2LP, 2333033b6c3aSEtienne Carriere DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, 2334033b6c3aSEtienne Carriere DDRPHYC, DDRPHYCLP, 2335373f06beSLionel Debieve RTCAPB, 2336033b6c3aSEtienne Carriere TZC1, TZC2, 2337033b6c3aSEtienne Carriere TZPC, 2338033b6c3aSEtienne Carriere STGEN_K, 2339033b6c3aSEtienne Carriere }; 2340033b6c3aSEtienne Carriere 2341033b6c3aSEtienne Carriere for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { 2342033b6c3aSEtienne Carriere stm32mp_clk_enable(secure_enable[idx]); 2343033b6c3aSEtienne Carriere } 23446cb45f89SYann Gautier } 23456cb45f89SYann Gautier 234633667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = { 234733667d29SYann Gautier .enable = stm32mp_clk_enable, 234833667d29SYann Gautier .disable = stm32mp_clk_disable, 234933667d29SYann Gautier .is_enabled = stm32mp_clk_is_enabled, 235033667d29SYann Gautier .get_rate = stm32mp_clk_get_rate, 235133667d29SYann Gautier .get_parent = stm32mp1_clk_get_parent, 235233667d29SYann Gautier }; 235333667d29SYann Gautier 23547839a050SYann Gautier int stm32mp1_clk_probe(void) 23557839a050SYann Gautier { 2356812daf91SLionel Debieve #if defined(IMAGE_BL32) 2357812daf91SLionel Debieve if (!fdt_get_rcc_secure_state()) { 2358812daf91SLionel Debieve mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U); 2359812daf91SLionel Debieve } 2360812daf91SLionel Debieve #endif 2361812daf91SLionel Debieve 23627839a050SYann Gautier stm32mp1_osc_init(); 23637839a050SYann Gautier 23646cb45f89SYann Gautier sync_earlyboot_clocks_state(); 23656cb45f89SYann Gautier 236633667d29SYann Gautier clk_register(&stm32mp_clk_ops); 236733667d29SYann Gautier 23687839a050SYann Gautier return 0; 23697839a050SYann Gautier } 2370