17839a050SYann Gautier /* 277b4ca0bSLionel Debieve * Copyright (C) 2018-2024, 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 }; 2367839a050SYann Gautier 2377839a050SYann Gautier struct stm32mp1_clk_gate { 2387839a050SYann Gautier uint16_t offset; 2397839a050SYann Gautier uint8_t bit; 2407839a050SYann Gautier uint8_t index; 2417839a050SYann Gautier uint8_t set_clr; 242aaa09b71SYann Gautier uint8_t secure; 2430d21680cSYann Gautier uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ 2440d21680cSYann Gautier uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ 2457839a050SYann Gautier }; 2467839a050SYann Gautier 2477839a050SYann Gautier struct stm32mp1_clk_sel { 2487839a050SYann Gautier uint16_t offset; 2497839a050SYann Gautier uint8_t src; 2507839a050SYann Gautier uint8_t msk; 2517839a050SYann Gautier uint8_t nb_parent; 2527839a050SYann Gautier const uint8_t *parent; 2537839a050SYann Gautier }; 2547839a050SYann Gautier 2557839a050SYann Gautier #define REFCLK_SIZE 4 2567839a050SYann Gautier struct stm32mp1_clk_pll { 2577839a050SYann Gautier enum stm32mp1_plltype plltype; 2587839a050SYann Gautier uint16_t rckxselr; 2597839a050SYann Gautier uint16_t pllxcfgr1; 2607839a050SYann Gautier uint16_t pllxcfgr2; 2617839a050SYann Gautier uint16_t pllxfracr; 2627839a050SYann Gautier uint16_t pllxcr; 2637839a050SYann Gautier uint16_t pllxcsgr; 2647839a050SYann Gautier enum stm32mp_osc_id refclk[REFCLK_SIZE]; 2657839a050SYann Gautier }; 2667839a050SYann Gautier 2670d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */ 268aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s) \ 2697839a050SYann Gautier { \ 2707839a050SYann Gautier .offset = (off), \ 2717839a050SYann Gautier .bit = (b), \ 2727839a050SYann Gautier .index = (idx), \ 2737839a050SYann Gautier .set_clr = 0, \ 274aaa09b71SYann Gautier .secure = (sec), \ 2757839a050SYann Gautier .sel = (s), \ 2767839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 2777839a050SYann Gautier } 2787839a050SYann Gautier 2790d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */ 280aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f) \ 2817839a050SYann Gautier { \ 2827839a050SYann Gautier .offset = (off), \ 2837839a050SYann Gautier .bit = (b), \ 2847839a050SYann Gautier .index = (idx), \ 2857839a050SYann Gautier .set_clr = 0, \ 286aaa09b71SYann Gautier .secure = (sec), \ 2877839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 2887839a050SYann Gautier .fixed = (f), \ 2897839a050SYann Gautier } 2907839a050SYann Gautier 2910d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */ 292aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s) \ 2937839a050SYann Gautier { \ 2947839a050SYann Gautier .offset = (off), \ 2957839a050SYann Gautier .bit = (b), \ 2967839a050SYann Gautier .index = (idx), \ 2977839a050SYann Gautier .set_clr = 1, \ 298aaa09b71SYann Gautier .secure = (sec), \ 2997839a050SYann Gautier .sel = (s), \ 3007839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 3017839a050SYann Gautier } 3027839a050SYann Gautier 3030d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */ 304aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f) \ 3057839a050SYann Gautier { \ 3067839a050SYann Gautier .offset = (off), \ 3077839a050SYann Gautier .bit = (b), \ 3087839a050SYann Gautier .index = (idx), \ 3097839a050SYann Gautier .set_clr = 1, \ 310aaa09b71SYann Gautier .secure = (sec), \ 3117839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 3127839a050SYann Gautier .fixed = (f), \ 3137839a050SYann Gautier } 3147839a050SYann Gautier 315d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents) \ 316d4151d2fSYann Gautier [_ ## _label ## _SEL] = { \ 317d4151d2fSYann Gautier .offset = _rcc_selr, \ 318d4151d2fSYann Gautier .src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \ 3198ae08dcdSEtienne Carriere .msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \ 3208ae08dcdSEtienne Carriere (_rcc_selr ## _ ## _label ## SRC_SHIFT), \ 321d4151d2fSYann Gautier .parent = (_parents), \ 322d4151d2fSYann Gautier .nb_parent = ARRAY_SIZE(_parents) \ 3237839a050SYann Gautier } 3247839a050SYann Gautier 3250d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3, \ 3267839a050SYann Gautier off4, off5, off6, \ 3277839a050SYann Gautier p1, p2, p3, p4) \ 3287839a050SYann Gautier [(idx)] = { \ 3297839a050SYann Gautier .plltype = (type), \ 3307839a050SYann Gautier .rckxselr = (off1), \ 3317839a050SYann Gautier .pllxcfgr1 = (off2), \ 3327839a050SYann Gautier .pllxcfgr2 = (off3), \ 3337839a050SYann Gautier .pllxfracr = (off4), \ 3347839a050SYann Gautier .pllxcr = (off5), \ 3357839a050SYann Gautier .pllxcsgr = (off6), \ 3367839a050SYann Gautier .refclk[0] = (p1), \ 3377839a050SYann Gautier .refclk[1] = (p2), \ 3387839a050SYann Gautier .refclk[2] = (p3), \ 3397839a050SYann Gautier .refclk[3] = (p4), \ 3407839a050SYann Gautier } 3417839a050SYann Gautier 3420d21680cSYann Gautier #define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) 3430d21680cSYann Gautier 344aaa09b71SYann Gautier #define SEC 1 345aaa09b71SYann Gautier #define N_S 0 346aaa09b71SYann Gautier 3477839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { 348aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK), 349aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK), 350aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK), 351aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK), 352aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), 353aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), 354aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), 355aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), 356aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK), 357aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), 358aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), 3597839a050SYann Gautier 3607418cf39SYann Gautier #if defined(IMAGE_BL32) 361aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), 3627418cf39SYann Gautier #endif 363aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), 364aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), 365aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), 366aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), 367aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), 368aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), 369aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), 370aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), 371aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), 372aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), 3737839a050SYann Gautier 3747418cf39SYann Gautier #if defined(IMAGE_BL32) 375aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), 3767418cf39SYann Gautier #endif 377aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), 3787839a050SYann Gautier 379aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), 380f33b2433SYann Gautier 381aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), 382aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), 383aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), 3847839a050SYann Gautier 385aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), 386aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), 387aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), 388aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL), 389aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), 390aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), 391aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), 392aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), 393aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), 394aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), 395aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), 3967839a050SYann Gautier 3977418cf39SYann Gautier #if defined(IMAGE_BL32) 398aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), 399aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), 4007418cf39SYann Gautier #endif 4017839a050SYann Gautier 402aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), 403aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), 404aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), 405aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), 406aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), 407aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), 408aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), 409aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), 410aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), 411aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), 412aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), 4137839a050SYann Gautier 414aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), 415aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), 416aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), 417aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), 418aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), 4197839a050SYann Gautier 4207418cf39SYann Gautier #if defined(IMAGE_BL2) 421aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), 422aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), 4237418cf39SYann Gautier #endif 424aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), 425aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), 4267418cf39SYann Gautier #if defined(IMAGE_BL32) 427aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), 4287418cf39SYann Gautier #endif 4297839a050SYann Gautier 430aaa09b71SYann Gautier _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL), 431aaa09b71SYann Gautier _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), 4327839a050SYann Gautier }; 4337839a050SYann Gautier 4340d21680cSYann Gautier static const uint8_t i2c12_parents[] = { 4350d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4360d21680cSYann Gautier }; 4370d21680cSYann Gautier 4380d21680cSYann Gautier static const uint8_t i2c35_parents[] = { 4390d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4400d21680cSYann Gautier }; 4410d21680cSYann Gautier 4420d21680cSYann Gautier static const uint8_t stgen_parents[] = { 4430d21680cSYann Gautier _HSI_KER, _HSE_KER 4440d21680cSYann Gautier }; 4450d21680cSYann Gautier 4460d21680cSYann Gautier static const uint8_t i2c46_parents[] = { 4470d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER 4480d21680cSYann Gautier }; 4490d21680cSYann Gautier 4500d21680cSYann Gautier static const uint8_t spi6_parents[] = { 4510d21680cSYann Gautier _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q 4520d21680cSYann Gautier }; 4530d21680cSYann Gautier 4540d21680cSYann Gautier static const uint8_t usart1_parents[] = { 4550d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER 4560d21680cSYann Gautier }; 4570d21680cSYann Gautier 4580d21680cSYann Gautier static const uint8_t rng1_parents[] = { 4590d21680cSYann Gautier _CSI, _PLL4_R, _LSE, _LSI 4600d21680cSYann Gautier }; 4610d21680cSYann Gautier 4620d21680cSYann Gautier static const uint8_t uart6_parents[] = { 4630d21680cSYann Gautier _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4640d21680cSYann Gautier }; 4650d21680cSYann Gautier 4660d21680cSYann Gautier static const uint8_t uart234578_parents[] = { 4670d21680cSYann Gautier _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4680d21680cSYann Gautier }; 4690d21680cSYann Gautier 4700d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = { 4710d21680cSYann Gautier _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER 4720d21680cSYann Gautier }; 4730d21680cSYann Gautier 4740d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = { 4750d21680cSYann Gautier _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER 4760d21680cSYann Gautier }; 4770d21680cSYann Gautier 4780d21680cSYann Gautier static const uint8_t qspi_parents[] = { 4790d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4800d21680cSYann Gautier }; 4810d21680cSYann Gautier 4820d21680cSYann Gautier static const uint8_t fmc_parents[] = { 4830d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4840d21680cSYann Gautier }; 4850d21680cSYann Gautier 486b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = { 487b8fe48b6SEtienne Carriere _HSI, _HSE, _PLL2_P 4880d21680cSYann Gautier }; 4890d21680cSYann Gautier 490b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = { 491b8fe48b6SEtienne Carriere _HSI, _HSE, _CSI, _PLL3_P 492b053a22eSYann Gautier }; 493b053a22eSYann Gautier 4940d21680cSYann Gautier static const uint8_t usbphy_parents[] = { 4950d21680cSYann Gautier _HSE_KER, _PLL4_R, _HSE_KER_DIV2 4960d21680cSYann Gautier }; 4970d21680cSYann Gautier 4980d21680cSYann Gautier static const uint8_t usbo_parents[] = { 4990d21680cSYann Gautier _PLL4_R, _USB_PHY_48 5000d21680cSYann Gautier }; 5017839a050SYann Gautier 5028fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = { 5038fbcd9e4SEtienne Carriere _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ 5048fbcd9e4SEtienne Carriere }; 5058fbcd9e4SEtienne Carriere 5068fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = { 5078fbcd9e4SEtienne Carriere _HSI, _HSE, _CSI, 5088fbcd9e4SEtienne Carriere }; 5098fbcd9e4SEtienne Carriere 510016af006SEtienne Carriere static const uint8_t rtc_parents[] = { 511cbd2e8a6SGabriel Fernandez _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC 512016af006SEtienne Carriere }; 513016af006SEtienne Carriere 5147839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { 515d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), 516d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), 517d4151d2fSYann Gautier _CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents), 518d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents), 519d4151d2fSYann Gautier _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), 520d4151d2fSYann Gautier _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), 521d4151d2fSYann Gautier _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), 5228fbcd9e4SEtienne Carriere _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents), 523288f5cf2SYann Gautier _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents), 524016af006SEtienne Carriere _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents), 525d4151d2fSYann Gautier _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), 526d4151d2fSYann Gautier _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), 527d4151d2fSYann Gautier _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), 528d4151d2fSYann Gautier _CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents), 529d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents), 530d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents), 531d4151d2fSYann Gautier _CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents), 532d4151d2fSYann Gautier _CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents), 533b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents), 534b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents), 535d4151d2fSYann Gautier _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents), 536d4151d2fSYann Gautier _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents), 5377839a050SYann Gautier }; 5387839a050SYann Gautier 5397839a050SYann Gautier /* Define characteristic of PLL according type */ 5407839a050SYann Gautier #define DIVN_MIN 24 5417839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { 5427839a050SYann Gautier [PLL_800] = { 5437839a050SYann Gautier .refclk_min = 4, 5447839a050SYann Gautier .refclk_max = 16, 5457839a050SYann Gautier }, 5467839a050SYann Gautier [PLL_1600] = { 5477839a050SYann Gautier .refclk_min = 8, 5487839a050SYann Gautier .refclk_max = 16, 5497839a050SYann Gautier }, 5507839a050SYann Gautier }; 5517839a050SYann Gautier 5527839a050SYann Gautier /* PLLNCFGR2 register divider by output */ 5537839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = { 5547839a050SYann Gautier [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, 5557839a050SYann Gautier [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, 5560d21680cSYann Gautier [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, 5577839a050SYann Gautier }; 5587839a050SYann Gautier 5597839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { 5600d21680cSYann Gautier _CLK_PLL(_PLL1, PLL_1600, 5617839a050SYann Gautier RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, 5627839a050SYann Gautier RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, 5637839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5640d21680cSYann Gautier _CLK_PLL(_PLL2, PLL_1600, 5657839a050SYann Gautier RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, 5667839a050SYann Gautier RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, 5677839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5680d21680cSYann Gautier _CLK_PLL(_PLL3, PLL_800, 5697839a050SYann Gautier RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, 5707839a050SYann Gautier RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, 5717839a050SYann Gautier _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), 5720d21680cSYann Gautier _CLK_PLL(_PLL4, PLL_800, 5737839a050SYann Gautier RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, 5747839a050SYann Gautier RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, 5757839a050SYann Gautier _HSI, _HSE, _CSI, _I2S_CKIN), 5767839a050SYann Gautier }; 5777839a050SYann Gautier 5787839a050SYann Gautier /* Prescaler table lookups for clock computation */ 579b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ 580b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = { 581b053a22eSYann Gautier 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 582b053a22eSYann Gautier }; 5837839a050SYann Gautier 5847839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ 5857839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div 5867839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div 5877839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = { 5887839a050SYann Gautier 0, 1, 2, 3, 4, 4, 4, 4 5897839a050SYann Gautier }; 5907839a050SYann Gautier 5917839a050SYann Gautier /* div = /1 /2 /3 /4 */ 5927839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = { 5937839a050SYann Gautier 1, 2, 3, 4, 4, 4, 4, 4 5947839a050SYann Gautier }; 5957839a050SYann Gautier 59637e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { 59737e8295aSEtienne Carriere [_HSI] = "HSI", 59837e8295aSEtienne Carriere [_HSE] = "HSE", 59937e8295aSEtienne Carriere [_CSI] = "CSI", 60037e8295aSEtienne Carriere [_LSI] = "LSI", 60137e8295aSEtienne Carriere [_LSE] = "LSE", 60237e8295aSEtienne Carriere [_I2S_CKIN] = "I2S_CKIN", 60337e8295aSEtienne Carriere [_HSI_KER] = "HSI_KER", 60437e8295aSEtienne Carriere [_HSE_KER] = "HSE_KER", 60537e8295aSEtienne Carriere [_HSE_KER_DIV2] = "HSE_KER_DIV2", 606cbd2e8a6SGabriel Fernandez [_HSE_RTC] = "HSE_RTC", 60737e8295aSEtienne Carriere [_CSI_KER] = "CSI_KER", 60837e8295aSEtienne Carriere [_PLL1_P] = "PLL1_P", 60937e8295aSEtienne Carriere [_PLL1_Q] = "PLL1_Q", 61037e8295aSEtienne Carriere [_PLL1_R] = "PLL1_R", 61137e8295aSEtienne Carriere [_PLL2_P] = "PLL2_P", 61237e8295aSEtienne Carriere [_PLL2_Q] = "PLL2_Q", 61337e8295aSEtienne Carriere [_PLL2_R] = "PLL2_R", 61437e8295aSEtienne Carriere [_PLL3_P] = "PLL3_P", 61537e8295aSEtienne Carriere [_PLL3_Q] = "PLL3_Q", 61637e8295aSEtienne Carriere [_PLL3_R] = "PLL3_R", 61737e8295aSEtienne Carriere [_PLL4_P] = "PLL4_P", 61837e8295aSEtienne Carriere [_PLL4_Q] = "PLL4_Q", 61937e8295aSEtienne Carriere [_PLL4_R] = "PLL4_R", 62037e8295aSEtienne Carriere [_ACLK] = "ACLK", 62137e8295aSEtienne Carriere [_PCLK1] = "PCLK1", 62237e8295aSEtienne Carriere [_PCLK2] = "PCLK2", 62337e8295aSEtienne Carriere [_PCLK3] = "PCLK3", 62437e8295aSEtienne Carriere [_PCLK4] = "PCLK4", 62537e8295aSEtienne Carriere [_PCLK5] = "PCLK5", 62637e8295aSEtienne Carriere [_HCLK6] = "KCLK6", 62737e8295aSEtienne Carriere [_HCLK2] = "HCLK2", 62837e8295aSEtienne Carriere [_CK_PER] = "CK_PER", 62937e8295aSEtienne Carriere [_CK_MPU] = "CK_MPU", 63037e8295aSEtienne Carriere [_CK_MCU] = "CK_MCU", 63137e8295aSEtienne Carriere [_USB_PHY_48] = "USB_PHY_48", 63237e8295aSEtienne Carriere }; 63337e8295aSEtienne Carriere 6340d21680cSYann Gautier /* RCC clock device driver private */ 6350d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC]; 6360d21680cSYann Gautier static struct spinlock reg_lock; 6370d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES]; 6380d21680cSYann Gautier static struct spinlock refcount_lock; 6397839a050SYann Gautier 6400d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) 6410d21680cSYann Gautier { 6420d21680cSYann Gautier return &stm32mp1_clk_gate[idx]; 6430d21680cSYann Gautier } 6447839a050SYann Gautier 6453d69149aSYann Gautier #if defined(IMAGE_BL32) 6463d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate) 6473d69149aSYann Gautier { 6483d69149aSYann Gautier return gate->secure == N_S; 6493d69149aSYann Gautier } 6503d69149aSYann Gautier #endif 6513d69149aSYann Gautier 6520d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) 6530d21680cSYann Gautier { 6540d21680cSYann Gautier return &stm32mp1_clk_sel[idx]; 6550d21680cSYann Gautier } 6560d21680cSYann Gautier 6570d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) 6580d21680cSYann Gautier { 6590d21680cSYann Gautier return &stm32mp1_clk_pll[idx]; 6600d21680cSYann Gautier } 6610d21680cSYann Gautier 6620d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock) 6630d21680cSYann Gautier { 664e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6650d21680cSYann Gautier /* Assume interrupts are masked */ 6660d21680cSYann Gautier spin_lock(lock); 6670d21680cSYann Gautier } 668e463d3f4SYann Gautier } 6690d21680cSYann Gautier 6700d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock) 6710d21680cSYann Gautier { 672e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6730d21680cSYann Gautier spin_unlock(lock); 6740d21680cSYann Gautier } 675e463d3f4SYann Gautier } 6760d21680cSYann Gautier 6770d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void) 6780d21680cSYann Gautier { 6790d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6801bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN; 6810d21680cSYann Gautier 6821bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 6830d21680cSYann Gautier } 6840d21680cSYann Gautier 685b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void) 686b053a22eSYann Gautier { 687b053a22eSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6881bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; 689b053a22eSYann Gautier 6901bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 691b053a22eSYann Gautier } 692b053a22eSYann Gautier 6930d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void) 6940d21680cSYann Gautier { 6950d21680cSYann Gautier stm32mp1_clk_lock(®_lock); 6960d21680cSYann Gautier } 6970d21680cSYann Gautier 6980d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void) 6990d21680cSYann Gautier { 7000d21680cSYann Gautier stm32mp1_clk_unlock(®_lock); 7010d21680cSYann Gautier } 7020d21680cSYann Gautier 7030d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) 7047839a050SYann Gautier { 7057839a050SYann Gautier if (idx >= NB_OSC) { 7067839a050SYann Gautier return 0; 7077839a050SYann Gautier } 7087839a050SYann Gautier 7090d21680cSYann Gautier return stm32mp1_osc[idx]; 7107839a050SYann Gautier } 7117839a050SYann Gautier 7120d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id) 7137839a050SYann Gautier { 7140d21680cSYann Gautier unsigned int i; 7157839a050SYann Gautier 7160d21680cSYann Gautier for (i = 0U; i < NB_GATES; i++) { 7170d21680cSYann Gautier if (gate_ref(i)->index == id) { 7187839a050SYann Gautier return i; 7197839a050SYann Gautier } 7207839a050SYann Gautier } 7217839a050SYann Gautier 72244fb470bSYann Gautier ERROR("%s: clk id %lu not found\n", __func__, id); 7237839a050SYann Gautier 7247839a050SYann Gautier return -EINVAL; 7257839a050SYann Gautier } 7267839a050SYann Gautier 7270d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) 7287839a050SYann Gautier { 7290d21680cSYann Gautier return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); 7307839a050SYann Gautier } 7317839a050SYann Gautier 7320d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) 7337839a050SYann Gautier { 7340d21680cSYann Gautier return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); 7357839a050SYann Gautier } 7367839a050SYann Gautier 7370d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id) 7387839a050SYann Gautier { 7390d21680cSYann Gautier const struct stm32mp1_clk_sel *sel; 7408fbcd9e4SEtienne Carriere uint32_t p_sel; 7417839a050SYann Gautier int i; 7427839a050SYann Gautier enum stm32mp1_parent_id p; 7437839a050SYann Gautier enum stm32mp1_parent_sel s; 7440d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7457839a050SYann Gautier 7468fbcd9e4SEtienne Carriere /* Few non gateable clock have a static parent ID, find them */ 7478fbcd9e4SEtienne Carriere i = (int)clock_id2parent_id(id); 7488fbcd9e4SEtienne Carriere if (i != _UNKNOWN_ID) { 7498fbcd9e4SEtienne Carriere return i; 7507839a050SYann Gautier } 7517839a050SYann Gautier 7520d21680cSYann Gautier i = stm32mp1_clk_get_gated_id(id); 7537839a050SYann Gautier if (i < 0) { 7540d21680cSYann Gautier panic(); 7557839a050SYann Gautier } 7567839a050SYann Gautier 7570d21680cSYann Gautier p = stm32mp1_clk_get_fixed_parent(i); 7587839a050SYann Gautier if (p < _PARENT_NB) { 7597839a050SYann Gautier return (int)p; 7607839a050SYann Gautier } 7617839a050SYann Gautier 7620d21680cSYann Gautier s = stm32mp1_clk_get_sel(i); 7630d21680cSYann Gautier if (s == _UNKNOWN_SEL) { 7640d21680cSYann Gautier return -EINVAL; 7650d21680cSYann Gautier } 7667839a050SYann Gautier if (s >= _PARENT_SEL_NB) { 7670d21680cSYann Gautier panic(); 7687839a050SYann Gautier } 7697839a050SYann Gautier 7700d21680cSYann Gautier sel = clk_sel_ref(s); 7718ae08dcdSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) & 7728ae08dcdSEtienne Carriere (sel->msk << sel->src)) >> sel->src; 7730d21680cSYann Gautier if (p_sel < sel->nb_parent) { 7740d21680cSYann Gautier return (int)sel->parent[p_sel]; 7757839a050SYann Gautier } 7767839a050SYann Gautier 7777839a050SYann Gautier return -EINVAL; 7787839a050SYann Gautier } 7797839a050SYann Gautier 7800d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) 7817839a050SYann Gautier { 7820d21680cSYann Gautier uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); 7830d21680cSYann Gautier uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; 7847839a050SYann Gautier 7850d21680cSYann Gautier return stm32mp1_clk_get_fixed(pll->refclk[src]); 7867839a050SYann Gautier } 7877839a050SYann Gautier 7887839a050SYann Gautier /* 7897839a050SYann Gautier * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL 7907839a050SYann Gautier * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) 7917839a050SYann Gautier * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) 7927839a050SYann Gautier * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) 7937839a050SYann Gautier */ 7940d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) 7957839a050SYann Gautier { 7967839a050SYann Gautier unsigned long refclk, fvco; 7977839a050SYann Gautier uint32_t cfgr1, fracr, divm, divn; 7980d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7997839a050SYann Gautier 8000d21680cSYann Gautier cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); 8010d21680cSYann Gautier fracr = mmio_read_32(rcc_base + pll->pllxfracr); 8027839a050SYann Gautier 8037839a050SYann Gautier divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; 8047839a050SYann Gautier divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; 8057839a050SYann Gautier 8060d21680cSYann Gautier refclk = stm32mp1_pll_get_fref(pll); 8077839a050SYann Gautier 8087839a050SYann Gautier /* 8097839a050SYann Gautier * With FRACV : 8107839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) 8117839a050SYann Gautier * Without FRACV 8127839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) 8137839a050SYann Gautier */ 8147839a050SYann Gautier if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { 8150d21680cSYann Gautier uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> 8160d21680cSYann Gautier RCC_PLLNFRACR_FRACV_SHIFT; 8177839a050SYann Gautier unsigned long long numerator, denominator; 8187839a050SYann Gautier 8190d21680cSYann Gautier numerator = (((unsigned long long)divn + 1U) << 13) + fracv; 8200d21680cSYann Gautier numerator = refclk * numerator; 8217839a050SYann Gautier denominator = ((unsigned long long)divm + 1U) << 13; 8227839a050SYann Gautier fvco = (unsigned long)(numerator / denominator); 8237839a050SYann Gautier } else { 8247839a050SYann Gautier fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); 8257839a050SYann Gautier } 8267839a050SYann Gautier 8277839a050SYann Gautier return fvco; 8287839a050SYann Gautier } 8297839a050SYann Gautier 8300d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, 8317839a050SYann Gautier enum stm32mp1_div_id div_id) 8327839a050SYann Gautier { 8330d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 8347839a050SYann Gautier unsigned long dfout; 8357839a050SYann Gautier uint32_t cfgr2, divy; 8367839a050SYann Gautier 8377839a050SYann Gautier if (div_id >= _DIV_NB) { 8387839a050SYann Gautier return 0; 8397839a050SYann Gautier } 8407839a050SYann Gautier 8410d21680cSYann Gautier cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); 8427839a050SYann Gautier divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; 8437839a050SYann Gautier 8440d21680cSYann Gautier dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); 8457839a050SYann Gautier 8467839a050SYann Gautier return dfout; 8477839a050SYann Gautier } 8487839a050SYann Gautier 8490d21680cSYann Gautier static unsigned long get_clock_rate(int p) 8507839a050SYann Gautier { 8517839a050SYann Gautier uint32_t reg, clkdiv; 8527839a050SYann Gautier unsigned long clock = 0; 8530d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8547839a050SYann Gautier 8557839a050SYann Gautier switch (p) { 8567839a050SYann Gautier case _CK_MPU: 8577839a050SYann Gautier /* MPU sub system */ 8580d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKSELR); 8597839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8607839a050SYann Gautier case RCC_MPCKSELR_HSI: 8610d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8627839a050SYann Gautier break; 8637839a050SYann Gautier case RCC_MPCKSELR_HSE: 8640d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8657839a050SYann Gautier break; 8667839a050SYann Gautier case RCC_MPCKSELR_PLL: 8670d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8687839a050SYann Gautier break; 8697839a050SYann Gautier case RCC_MPCKSELR_PLL_MPUDIV: 8700d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8717839a050SYann Gautier 8720d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); 8737839a050SYann Gautier clkdiv = reg & RCC_MPUDIV_MASK; 874602ae2f2SGabriel Fernandez clock >>= stm32mp1_mpu_div[clkdiv]; 8757839a050SYann Gautier break; 8767839a050SYann Gautier default: 8777839a050SYann Gautier break; 8787839a050SYann Gautier } 8797839a050SYann Gautier break; 8807839a050SYann Gautier /* AXI sub system */ 8817839a050SYann Gautier case _ACLK: 8827839a050SYann Gautier case _HCLK2: 8837839a050SYann Gautier case _HCLK6: 8847839a050SYann Gautier case _PCLK4: 8857839a050SYann Gautier case _PCLK5: 8860d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); 8877839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8887839a050SYann Gautier case RCC_ASSCKSELR_HSI: 8890d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8907839a050SYann Gautier break; 8917839a050SYann Gautier case RCC_ASSCKSELR_HSE: 8920d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8937839a050SYann Gautier break; 8947839a050SYann Gautier case RCC_ASSCKSELR_PLL: 8950d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 8967839a050SYann Gautier break; 8977839a050SYann Gautier default: 8987839a050SYann Gautier break; 8997839a050SYann Gautier } 9007839a050SYann Gautier 9017839a050SYann Gautier /* System clock divider */ 9020d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_AXIDIVR); 9037839a050SYann Gautier clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; 9047839a050SYann Gautier 9057839a050SYann Gautier switch (p) { 9067839a050SYann Gautier case _PCLK4: 9070d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB4DIVR); 9087839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9097839a050SYann Gautier break; 9107839a050SYann Gautier case _PCLK5: 9110d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB5DIVR); 9127839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9137839a050SYann Gautier break; 9147839a050SYann Gautier default: 9157839a050SYann Gautier break; 9167839a050SYann Gautier } 9177839a050SYann Gautier break; 918b053a22eSYann Gautier /* MCU sub system */ 919b053a22eSYann Gautier case _CK_MCU: 920b053a22eSYann Gautier case _PCLK1: 921b053a22eSYann Gautier case _PCLK2: 922b053a22eSYann Gautier case _PCLK3: 923b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); 924b053a22eSYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 925b053a22eSYann Gautier case RCC_MSSCKSELR_HSI: 926b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 927b053a22eSYann Gautier break; 928b053a22eSYann Gautier case RCC_MSSCKSELR_HSE: 929b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 930b053a22eSYann Gautier break; 931b053a22eSYann Gautier case RCC_MSSCKSELR_CSI: 932b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 933b053a22eSYann Gautier break; 934b053a22eSYann Gautier case RCC_MSSCKSELR_PLL: 935b053a22eSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 936b053a22eSYann Gautier break; 937b053a22eSYann Gautier default: 938b053a22eSYann Gautier break; 939b053a22eSYann Gautier } 940b053a22eSYann Gautier 941b053a22eSYann Gautier /* MCU clock divider */ 942b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MCUDIVR); 943b053a22eSYann Gautier clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; 944b053a22eSYann Gautier 945b053a22eSYann Gautier switch (p) { 946b053a22eSYann Gautier case _PCLK1: 947b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB1DIVR); 948b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 949b053a22eSYann Gautier break; 950b053a22eSYann Gautier case _PCLK2: 951b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB2DIVR); 952b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 953b053a22eSYann Gautier break; 954b053a22eSYann Gautier case _PCLK3: 955b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB3DIVR); 956b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 957b053a22eSYann Gautier break; 958b053a22eSYann Gautier case _CK_MCU: 959b053a22eSYann Gautier default: 960b053a22eSYann Gautier break; 961b053a22eSYann Gautier } 962b053a22eSYann Gautier break; 9637839a050SYann Gautier case _CK_PER: 9640d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); 9657839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 9667839a050SYann Gautier case RCC_CPERCKSELR_HSI: 9670d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9687839a050SYann Gautier break; 9697839a050SYann Gautier case RCC_CPERCKSELR_HSE: 9700d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9717839a050SYann Gautier break; 9727839a050SYann Gautier case RCC_CPERCKSELR_CSI: 9730d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9747839a050SYann Gautier break; 9757839a050SYann Gautier default: 9767839a050SYann Gautier break; 9777839a050SYann Gautier } 9787839a050SYann Gautier break; 9797839a050SYann Gautier case _HSI: 9807839a050SYann Gautier case _HSI_KER: 9810d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9827839a050SYann Gautier break; 9837839a050SYann Gautier case _CSI: 9847839a050SYann Gautier case _CSI_KER: 9850d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9867839a050SYann Gautier break; 9877839a050SYann Gautier case _HSE: 9887839a050SYann Gautier case _HSE_KER: 9890d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9907839a050SYann Gautier break; 9917839a050SYann Gautier case _HSE_KER_DIV2: 9920d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE) >> 1; 9937839a050SYann Gautier break; 994cbd2e8a6SGabriel Fernandez case _HSE_RTC: 995cbd2e8a6SGabriel Fernandez clock = stm32mp1_clk_get_fixed(_HSE); 996cbd2e8a6SGabriel Fernandez clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; 997cbd2e8a6SGabriel Fernandez break; 9987839a050SYann Gautier case _LSI: 9990d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSI); 10007839a050SYann Gautier break; 10017839a050SYann Gautier case _LSE: 10020d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSE); 10037839a050SYann Gautier break; 10047839a050SYann Gautier /* PLL */ 10057839a050SYann Gautier case _PLL1_P: 10060d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 10077839a050SYann Gautier break; 10087839a050SYann Gautier case _PLL1_Q: 10090d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); 10107839a050SYann Gautier break; 10117839a050SYann Gautier case _PLL1_R: 10120d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); 10137839a050SYann Gautier break; 10147839a050SYann Gautier case _PLL2_P: 10150d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 10167839a050SYann Gautier break; 10177839a050SYann Gautier case _PLL2_Q: 10180d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); 10197839a050SYann Gautier break; 10207839a050SYann Gautier case _PLL2_R: 10210d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); 10227839a050SYann Gautier break; 10237839a050SYann Gautier case _PLL3_P: 10240d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 10257839a050SYann Gautier break; 10267839a050SYann Gautier case _PLL3_Q: 10270d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); 10287839a050SYann Gautier break; 10297839a050SYann Gautier case _PLL3_R: 10300d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); 10317839a050SYann Gautier break; 10327839a050SYann Gautier case _PLL4_P: 10330d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); 10347839a050SYann Gautier break; 10357839a050SYann Gautier case _PLL4_Q: 10360d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); 10377839a050SYann Gautier break; 10387839a050SYann Gautier case _PLL4_R: 10390d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); 10407839a050SYann Gautier break; 10417839a050SYann Gautier /* Other */ 10427839a050SYann Gautier case _USB_PHY_48: 10430d21680cSYann Gautier clock = USB_PHY_48_MHZ; 10447839a050SYann Gautier break; 10457839a050SYann Gautier default: 10467839a050SYann Gautier break; 10477839a050SYann Gautier } 10487839a050SYann Gautier 10497839a050SYann Gautier return clock; 10507839a050SYann Gautier } 10517839a050SYann Gautier 10520d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate) 10530d21680cSYann Gautier { 10540d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10550d21680cSYann Gautier 105625be845eSEtienne Carriere VERBOSE("Enable clock %u\n", gate->index); 105725be845eSEtienne Carriere 10580d21680cSYann Gautier if (gate->set_clr != 0U) { 10590d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); 10600d21680cSYann Gautier } else { 10610d21680cSYann Gautier mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10620d21680cSYann Gautier } 10630d21680cSYann Gautier } 10640d21680cSYann Gautier 10650d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate) 10660d21680cSYann Gautier { 10670d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10680d21680cSYann Gautier 106925be845eSEtienne Carriere VERBOSE("Disable clock %u\n", gate->index); 107025be845eSEtienne Carriere 10710d21680cSYann Gautier if (gate->set_clr != 0U) { 10720d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, 10730d21680cSYann Gautier BIT(gate->bit)); 10740d21680cSYann Gautier } else { 10750d21680cSYann Gautier mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10760d21680cSYann Gautier } 10770d21680cSYann Gautier } 10780d21680cSYann Gautier 10790d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) 10800d21680cSYann Gautier { 10810d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10820d21680cSYann Gautier 10830d21680cSYann Gautier return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); 10840d21680cSYann Gautier } 10850d21680cSYann Gautier 108635848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */ 108735848200SEtienne Carriere static bool clock_is_always_on(unsigned long id) 108835848200SEtienne Carriere { 108935848200SEtienne Carriere switch (id) { 109035848200SEtienne Carriere case CK_HSE: 109135848200SEtienne Carriere case CK_CSI: 109235848200SEtienne Carriere case CK_LSI: 109335848200SEtienne Carriere case CK_LSE: 109435848200SEtienne Carriere case CK_HSI: 109535848200SEtienne Carriere case CK_HSE_DIV2: 109635848200SEtienne Carriere case PLL1_Q: 109735848200SEtienne Carriere case PLL1_R: 109835848200SEtienne Carriere case PLL2_P: 109935848200SEtienne Carriere case PLL2_Q: 110035848200SEtienne Carriere case PLL2_R: 110135848200SEtienne Carriere case PLL3_P: 110235848200SEtienne Carriere case PLL3_Q: 110335848200SEtienne Carriere case PLL3_R: 1104bf39318dSYann Gautier case CK_AXI: 1105bf39318dSYann Gautier case CK_MPU: 1106bf39318dSYann Gautier case CK_MCU: 11075b111c74SHE Shushan case RTC: 110835848200SEtienne Carriere return true; 110935848200SEtienne Carriere default: 111035848200SEtienne Carriere return false; 111135848200SEtienne Carriere } 111235848200SEtienne Carriere } 111335848200SEtienne Carriere 11142444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt) 11150d21680cSYann Gautier { 11160d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 111735848200SEtienne Carriere int i; 11180d21680cSYann Gautier 111935848200SEtienne Carriere if (clock_is_always_on(id)) { 112035848200SEtienne Carriere return; 112135848200SEtienne Carriere } 112235848200SEtienne Carriere 112335848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11240d21680cSYann Gautier if (i < 0) { 112544fb470bSYann Gautier ERROR("Clock %lu can't be enabled\n", id); 11260d21680cSYann Gautier panic(); 11270d21680cSYann Gautier } 11280d21680cSYann Gautier 11290d21680cSYann Gautier gate = gate_ref(i); 11302444d231SYann Gautier 11312444d231SYann Gautier if (!with_refcnt) { 11322444d231SYann Gautier __clk_enable(gate); 11332444d231SYann Gautier return; 11342444d231SYann Gautier } 11350d21680cSYann Gautier 11363d69149aSYann Gautier #if defined(IMAGE_BL32) 11373d69149aSYann Gautier if (gate_is_non_secure(gate)) { 11383d69149aSYann Gautier /* Enable non-secure clock w/o any refcounting */ 11393d69149aSYann Gautier __clk_enable(gate); 11403d69149aSYann Gautier return; 11413d69149aSYann Gautier } 11423d69149aSYann Gautier #endif 11433d69149aSYann Gautier 11440d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11450d21680cSYann Gautier 11462444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11470d21680cSYann Gautier __clk_enable(gate); 11480d21680cSYann Gautier } 11490d21680cSYann Gautier 11502444d231SYann Gautier gate_refcounts[i]++; 11512444d231SYann Gautier if (gate_refcounts[i] == UINT_MAX) { 11522444d231SYann Gautier ERROR("Clock %lu refcount reached max value\n", id); 11532444d231SYann Gautier panic(); 11542444d231SYann Gautier } 11552444d231SYann Gautier 11560d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11570d21680cSYann Gautier } 11580d21680cSYann Gautier 11592444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt) 11600d21680cSYann Gautier { 11610d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 116235848200SEtienne Carriere int i; 11630d21680cSYann Gautier 116435848200SEtienne Carriere if (clock_is_always_on(id)) { 116535848200SEtienne Carriere return; 116635848200SEtienne Carriere } 116735848200SEtienne Carriere 116835848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11690d21680cSYann Gautier if (i < 0) { 117044fb470bSYann Gautier ERROR("Clock %lu can't be disabled\n", id); 11710d21680cSYann Gautier panic(); 11720d21680cSYann Gautier } 11730d21680cSYann Gautier 11740d21680cSYann Gautier gate = gate_ref(i); 11752444d231SYann Gautier 11762444d231SYann Gautier if (!with_refcnt) { 11772444d231SYann Gautier __clk_disable(gate); 11782444d231SYann Gautier return; 11792444d231SYann Gautier } 11800d21680cSYann Gautier 11813d69149aSYann Gautier #if defined(IMAGE_BL32) 11823d69149aSYann Gautier if (gate_is_non_secure(gate)) { 11833d69149aSYann Gautier /* Don't disable non-secure clocks */ 11843d69149aSYann Gautier return; 11853d69149aSYann Gautier } 11863d69149aSYann Gautier #endif 11873d69149aSYann Gautier 11880d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11890d21680cSYann Gautier 11902444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11912444d231SYann Gautier ERROR("Clock %lu refcount reached 0\n", id); 11922444d231SYann Gautier panic(); 11932444d231SYann Gautier } 11942444d231SYann Gautier gate_refcounts[i]--; 11952444d231SYann Gautier 11962444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11970d21680cSYann Gautier __clk_disable(gate); 11980d21680cSYann Gautier } 11990d21680cSYann Gautier 12000d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 12010d21680cSYann Gautier } 12020d21680cSYann Gautier 120333667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id) 12040d21680cSYann Gautier { 12050d21680cSYann Gautier __stm32mp1_clk_enable(id, true); 120633667d29SYann Gautier 120733667d29SYann Gautier return 0; 12080d21680cSYann Gautier } 12090d21680cSYann Gautier 121033667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id) 12110d21680cSYann Gautier { 12120d21680cSYann Gautier __stm32mp1_clk_disable(id, true); 12130d21680cSYann Gautier } 12140d21680cSYann Gautier 121533667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id) 12167839a050SYann Gautier { 121735848200SEtienne Carriere int i; 12187839a050SYann Gautier 121935848200SEtienne Carriere if (clock_is_always_on(id)) { 122035848200SEtienne Carriere return true; 122135848200SEtienne Carriere } 122235848200SEtienne Carriere 122335848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 12247839a050SYann Gautier if (i < 0) { 12250d21680cSYann Gautier panic(); 12267839a050SYann Gautier } 12277839a050SYann Gautier 12280d21680cSYann Gautier return __clk_is_enabled(gate_ref(i)); 12297839a050SYann Gautier } 12307839a050SYann Gautier 123133667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id) 12327839a050SYann Gautier { 123333667d29SYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 12340d21680cSYann Gautier int p = stm32mp1_clk_get_parent(id); 123533667d29SYann Gautier uint32_t prescaler, timpre; 123633667d29SYann Gautier unsigned long parent_rate; 12377839a050SYann Gautier 12387839a050SYann Gautier if (p < 0) { 12397839a050SYann Gautier return 0; 12407839a050SYann Gautier } 12417839a050SYann Gautier 124233667d29SYann Gautier parent_rate = get_clock_rate(p); 124333667d29SYann Gautier 124433667d29SYann Gautier switch (id) { 124533667d29SYann Gautier case TIM2_K: 124633667d29SYann Gautier case TIM3_K: 124733667d29SYann Gautier case TIM4_K: 124833667d29SYann Gautier case TIM5_K: 124933667d29SYann Gautier case TIM6_K: 125033667d29SYann Gautier case TIM7_K: 125133667d29SYann Gautier case TIM12_K: 125233667d29SYann Gautier case TIM13_K: 125333667d29SYann Gautier case TIM14_K: 125433667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) & 125533667d29SYann Gautier RCC_APBXDIV_MASK; 125633667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & 125733667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 125833667d29SYann Gautier break; 125933667d29SYann Gautier 126033667d29SYann Gautier case TIM1_K: 126133667d29SYann Gautier case TIM8_K: 126233667d29SYann Gautier case TIM15_K: 126333667d29SYann Gautier case TIM16_K: 126433667d29SYann Gautier case TIM17_K: 126533667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) & 126633667d29SYann Gautier RCC_APBXDIV_MASK; 126733667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & 126833667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 126933667d29SYann Gautier break; 127033667d29SYann Gautier 127133667d29SYann Gautier default: 127233667d29SYann Gautier return parent_rate; 127333667d29SYann Gautier } 127433667d29SYann Gautier 127533667d29SYann Gautier if (prescaler == 0U) { 127633667d29SYann Gautier return parent_rate; 127733667d29SYann Gautier } 127833667d29SYann Gautier 127933667d29SYann Gautier return parent_rate * (timpre + 1U) * 2U; 12807839a050SYann Gautier } 12817839a050SYann Gautier 12820d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) 12837839a050SYann Gautier { 12840d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12857839a050SYann Gautier 12860d21680cSYann Gautier if (enable) { 12877839a050SYann Gautier mmio_setbits_32(address, mask_on); 12887839a050SYann Gautier } else { 12897839a050SYann Gautier mmio_clrbits_32(address, mask_on); 12907839a050SYann Gautier } 12917839a050SYann Gautier } 12927839a050SYann Gautier 12930d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) 12947839a050SYann Gautier { 12950d21680cSYann Gautier uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; 12960d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12970d21680cSYann Gautier 12980d21680cSYann Gautier mmio_write_32(address, mask_on); 12997839a050SYann Gautier } 13007839a050SYann Gautier 13010d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) 13027839a050SYann Gautier { 1303dfdb057aSYann Gautier uint64_t timeout; 13047839a050SYann Gautier uint32_t mask_test; 13050d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 13067839a050SYann Gautier 13070d21680cSYann Gautier if (enable) { 13087839a050SYann Gautier mask_test = mask_rdy; 13097839a050SYann Gautier } else { 13107839a050SYann Gautier mask_test = 0; 13117839a050SYann Gautier } 13127839a050SYann Gautier 1313dfdb057aSYann Gautier timeout = timeout_init_us(OSCRDY_TIMEOUT); 13147839a050SYann Gautier while ((mmio_read_32(address) & mask_rdy) != mask_test) { 1315dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 13160d21680cSYann Gautier ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", 13177839a050SYann Gautier mask_rdy, address, enable, mmio_read_32(address)); 13187839a050SYann Gautier return -ETIMEDOUT; 13197839a050SYann Gautier } 13207839a050SYann Gautier } 13217839a050SYann Gautier 13227839a050SYann Gautier return 0; 13237839a050SYann Gautier } 13247839a050SYann Gautier 13250d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) 13267839a050SYann Gautier { 13277839a050SYann Gautier uint32_t value; 13280d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13297839a050SYann Gautier 1330*f4a2bb98SYann Gautier /* Do not reconfigure LSE if it is already ON */ 1331*f4a2bb98SYann Gautier if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEON) == RCC_BDCR_LSEON) { 1332*f4a2bb98SYann Gautier return; 1333*f4a2bb98SYann Gautier } 1334*f4a2bb98SYann Gautier 13350d21680cSYann Gautier if (digbyp) { 13360d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); 13370d21680cSYann Gautier } 13380d21680cSYann Gautier 13390d21680cSYann Gautier if (bypass || digbyp) { 13400d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); 13417839a050SYann Gautier } 13427839a050SYann Gautier 13437839a050SYann Gautier /* 13447839a050SYann Gautier * Warning: not recommended to switch directly from "high drive" 13457839a050SYann Gautier * to "medium low drive", and vice-versa. 13467839a050SYann Gautier */ 13470d21680cSYann Gautier value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> 13487839a050SYann Gautier RCC_BDCR_LSEDRV_SHIFT; 13497839a050SYann Gautier 13507839a050SYann Gautier while (value != lsedrv) { 13517839a050SYann Gautier if (value > lsedrv) { 13527839a050SYann Gautier value--; 13537839a050SYann Gautier } else { 13547839a050SYann Gautier value++; 13557839a050SYann Gautier } 13567839a050SYann Gautier 13570d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_BDCR, 13587839a050SYann Gautier RCC_BDCR_LSEDRV_MASK, 13597839a050SYann Gautier value << RCC_BDCR_LSEDRV_SHIFT); 13607839a050SYann Gautier } 13617839a050SYann Gautier 13620d21680cSYann Gautier stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); 13637839a050SYann Gautier } 13647839a050SYann Gautier 13650d21680cSYann Gautier static void stm32mp1_lse_wait(void) 13667839a050SYann Gautier { 13670d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { 13687839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13697839a050SYann Gautier } 13707839a050SYann Gautier } 13717839a050SYann Gautier 13720d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable) 13737839a050SYann Gautier { 13740d21680cSYann Gautier stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); 13750d21680cSYann Gautier 13760d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { 13777839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13787839a050SYann Gautier } 13797839a050SYann Gautier } 13807839a050SYann Gautier 13810d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) 13827839a050SYann Gautier { 13830d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13840d21680cSYann Gautier 13850d21680cSYann Gautier if (digbyp) { 13860d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); 13877839a050SYann Gautier } 13887839a050SYann Gautier 13890d21680cSYann Gautier if (bypass || digbyp) { 13900d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); 13910d21680cSYann Gautier } 13920d21680cSYann Gautier 13930d21680cSYann Gautier stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); 13940d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { 13957839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13967839a050SYann Gautier } 13977839a050SYann Gautier 13987839a050SYann Gautier if (css) { 13990d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); 14007839a050SYann Gautier } 140131e9750bSLionel Debieve 140231e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER 140331e9750bSLionel Debieve if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) && 140431e9750bSLionel Debieve (!(digbyp || bypass))) { 140531e9750bSLionel Debieve panic(); 140631e9750bSLionel Debieve } 140731e9750bSLionel Debieve #endif 14087839a050SYann Gautier } 14097839a050SYann Gautier 14100d21680cSYann Gautier static void stm32mp1_csi_set(bool enable) 14117839a050SYann Gautier { 14120d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); 14130d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { 14147839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14157839a050SYann Gautier } 14167839a050SYann Gautier } 14177839a050SYann Gautier 14180d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable) 14197839a050SYann Gautier { 14200d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); 14210d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { 14227839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14237839a050SYann Gautier } 14247839a050SYann Gautier } 14257839a050SYann Gautier 14260d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv) 14277839a050SYann Gautier { 1428dfdb057aSYann Gautier uint64_t timeout; 14290d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14300d21680cSYann Gautier uintptr_t address = rcc_base + RCC_OCRDYR; 14317839a050SYann Gautier 14320d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, 14337839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK, 14347839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); 14357839a050SYann Gautier 1436dfdb057aSYann Gautier timeout = timeout_init_us(HSIDIV_TIMEOUT); 14377839a050SYann Gautier while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { 1438dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 14390d21680cSYann Gautier ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", 14407839a050SYann Gautier address, mmio_read_32(address)); 14417839a050SYann Gautier return -ETIMEDOUT; 14427839a050SYann Gautier } 14437839a050SYann Gautier } 14447839a050SYann Gautier 14457839a050SYann Gautier return 0; 14467839a050SYann Gautier } 14477839a050SYann Gautier 14480d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq) 14497839a050SYann Gautier { 14507839a050SYann Gautier uint8_t hsidiv; 14517839a050SYann Gautier uint32_t hsidivfreq = MAX_HSI_HZ; 14527839a050SYann Gautier 14537839a050SYann Gautier for (hsidiv = 0; hsidiv < 4U; hsidiv++) { 14547839a050SYann Gautier if (hsidivfreq == hsifreq) { 14557839a050SYann Gautier break; 14567839a050SYann Gautier } 14577839a050SYann Gautier 14587839a050SYann Gautier hsidivfreq /= 2U; 14597839a050SYann Gautier } 14607839a050SYann Gautier 14617839a050SYann Gautier if (hsidiv == 4U) { 14627839a050SYann Gautier ERROR("Invalid clk-hsi frequency\n"); 14637839a050SYann Gautier return -1; 14647839a050SYann Gautier } 14657839a050SYann Gautier 14667839a050SYann Gautier if (hsidiv != 0U) { 14670d21680cSYann Gautier return stm32mp1_set_hsidiv(hsidiv); 14687839a050SYann Gautier } 14697839a050SYann Gautier 14707839a050SYann Gautier return 0; 14717839a050SYann Gautier } 14727839a050SYann Gautier 14730d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, 14740d21680cSYann Gautier unsigned int clksrc, 14750d21680cSYann Gautier uint32_t *pllcfg, int plloff) 14767839a050SYann Gautier { 14770d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 14780d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14790d21680cSYann Gautier uintptr_t pllxcr = rcc_base + pll->pllxcr; 14800d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 14810d21680cSYann Gautier uintptr_t clksrc_address = rcc_base + (clksrc >> 4); 14820d21680cSYann Gautier unsigned long refclk; 14830d21680cSYann Gautier uint32_t ifrge = 0U; 1484be858cffSAndre Przywara uint32_t src, value, fracv = 0; 1485be858cffSAndre Przywara void *fdt; 14867839a050SYann Gautier 14870d21680cSYann Gautier /* Check PLL output */ 14880d21680cSYann Gautier if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { 14890d21680cSYann Gautier return false; 14907839a050SYann Gautier } 14917839a050SYann Gautier 14920d21680cSYann Gautier /* Check current clksrc */ 14930d21680cSYann Gautier src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; 14940d21680cSYann Gautier if (src != (clksrc & RCC_SELR_SRC_MASK)) { 14950d21680cSYann Gautier return false; 14960d21680cSYann Gautier } 14970d21680cSYann Gautier 14980d21680cSYann Gautier /* Check Div */ 14990d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; 15000d21680cSYann Gautier 15010d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 15020d21680cSYann Gautier (pllcfg[PLLCFG_M] + 1U); 15030d21680cSYann Gautier 15040d21680cSYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 15050d21680cSYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 15060d21680cSYann Gautier return false; 15070d21680cSYann Gautier } 15080d21680cSYann Gautier 15090d21680cSYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 15100d21680cSYann Gautier ifrge = 1U; 15110d21680cSYann Gautier } 15120d21680cSYann Gautier 15130d21680cSYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 15140d21680cSYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 15150d21680cSYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 15160d21680cSYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 15170d21680cSYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 15180d21680cSYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 15190d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { 15200d21680cSYann Gautier return false; 15210d21680cSYann Gautier } 15220d21680cSYann Gautier 15230d21680cSYann Gautier /* Fractional configuration */ 1524be858cffSAndre Przywara if (fdt_get_address(&fdt) == 1) { 1525be858cffSAndre Przywara fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1526be858cffSAndre Przywara } 15270d21680cSYann Gautier 15280d21680cSYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 15290d21680cSYann Gautier value |= RCC_PLLNFRACR_FRACLE; 15300d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { 15310d21680cSYann Gautier return false; 15320d21680cSYann Gautier } 15330d21680cSYann Gautier 15340d21680cSYann Gautier /* Output config */ 15350d21680cSYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15360d21680cSYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15370d21680cSYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15380d21680cSYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15390d21680cSYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15400d21680cSYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15410d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { 15420d21680cSYann Gautier return false; 15430d21680cSYann Gautier } 15440d21680cSYann Gautier 15450d21680cSYann Gautier return true; 15460d21680cSYann Gautier } 15470d21680cSYann Gautier 15480d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) 15497839a050SYann Gautier { 15500d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15510d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 15520d21680cSYann Gautier 1553dd98aec8SYann Gautier /* Preserve RCC_PLLNCR_SSCG_CTRL value */ 1554dd98aec8SYann Gautier mmio_clrsetbits_32(pllxcr, 1555dd98aec8SYann Gautier RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 1556dd98aec8SYann Gautier RCC_PLLNCR_DIVREN, 1557dd98aec8SYann Gautier RCC_PLLNCR_PLLON); 15580d21680cSYann Gautier } 15590d21680cSYann Gautier 15600d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) 15610d21680cSYann Gautier { 15620d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15630d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1564dfdb057aSYann Gautier uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); 15657839a050SYann Gautier 15667839a050SYann Gautier /* Wait PLL lock */ 15677839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { 1568dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15699fa9a0c5SYann Gautier ERROR("PLL%u start failed @ 0x%lx: 0x%x\n", 15707839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15717839a050SYann Gautier return -ETIMEDOUT; 15727839a050SYann Gautier } 15737839a050SYann Gautier } 15747839a050SYann Gautier 15757839a050SYann Gautier /* Start the requested output */ 15767839a050SYann Gautier mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); 15777839a050SYann Gautier 15787839a050SYann Gautier return 0; 15797839a050SYann Gautier } 15807839a050SYann Gautier 15810d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) 15827839a050SYann Gautier { 15830d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15840d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1585dfdb057aSYann Gautier uint64_t timeout; 15867839a050SYann Gautier 15877839a050SYann Gautier /* Stop all output */ 15887839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 15897839a050SYann Gautier RCC_PLLNCR_DIVREN); 15907839a050SYann Gautier 15917839a050SYann Gautier /* Stop PLL */ 15927839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); 15937839a050SYann Gautier 1594dfdb057aSYann Gautier timeout = timeout_init_us(PLLRDY_TIMEOUT); 15957839a050SYann Gautier /* Wait PLL stopped */ 15967839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { 1597dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15989fa9a0c5SYann Gautier ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n", 15997839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 16007839a050SYann Gautier return -ETIMEDOUT; 16017839a050SYann Gautier } 16027839a050SYann Gautier } 16037839a050SYann Gautier 16047839a050SYann Gautier return 0; 16057839a050SYann Gautier } 16067839a050SYann Gautier 16070d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, 16087839a050SYann Gautier uint32_t *pllcfg) 16097839a050SYann Gautier { 16100d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16110d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16127839a050SYann Gautier uint32_t value; 16137839a050SYann Gautier 16147839a050SYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 16157839a050SYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 16167839a050SYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 16177839a050SYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 16187839a050SYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 16197839a050SYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 16200d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr2, value); 16217839a050SYann Gautier } 16227839a050SYann Gautier 16230d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, 16247839a050SYann Gautier uint32_t *pllcfg, uint32_t fracv) 16257839a050SYann Gautier { 16260d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16270d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16280d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 16297839a050SYann Gautier unsigned long refclk; 16307839a050SYann Gautier uint32_t ifrge = 0; 16317839a050SYann Gautier uint32_t src, value; 16327839a050SYann Gautier 16330d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & 16347839a050SYann Gautier RCC_SELR_REFCLK_SRC_MASK; 16357839a050SYann Gautier 16360d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 16377839a050SYann Gautier (pllcfg[PLLCFG_M] + 1U); 16387839a050SYann Gautier 16397839a050SYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 16407839a050SYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 16417839a050SYann Gautier return -EINVAL; 16427839a050SYann Gautier } 16437839a050SYann Gautier 16447839a050SYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 16457839a050SYann Gautier ifrge = 1U; 16467839a050SYann Gautier } 16477839a050SYann Gautier 16487839a050SYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 16497839a050SYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 16507839a050SYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 16517839a050SYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 16527839a050SYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 16537839a050SYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 16540d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr1, value); 16557839a050SYann Gautier 16567839a050SYann Gautier /* Fractional configuration */ 16577839a050SYann Gautier value = 0; 16580d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16597839a050SYann Gautier 16607839a050SYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 16610d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16627839a050SYann Gautier 16637839a050SYann Gautier value |= RCC_PLLNFRACR_FRACLE; 16640d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16657839a050SYann Gautier 16660d21680cSYann Gautier stm32mp1_pll_config_output(pll_id, pllcfg); 16677839a050SYann Gautier 16687839a050SYann Gautier return 0; 16697839a050SYann Gautier } 16707839a050SYann Gautier 16710d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) 16727839a050SYann Gautier { 16730d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16747839a050SYann Gautier uint32_t pllxcsg = 0; 16757839a050SYann Gautier 16767839a050SYann Gautier pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & 16777839a050SYann Gautier RCC_PLLNCSGR_MOD_PER_MASK; 16787839a050SYann Gautier 16797839a050SYann Gautier pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & 16807839a050SYann Gautier RCC_PLLNCSGR_INC_STEP_MASK; 16817839a050SYann Gautier 16827839a050SYann Gautier pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & 16837839a050SYann Gautier RCC_PLLNCSGR_SSCG_MODE_MASK; 16847839a050SYann Gautier 16850d21680cSYann Gautier mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); 1686dd98aec8SYann Gautier 1687dd98aec8SYann Gautier mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, 1688dd98aec8SYann Gautier RCC_PLLNCR_SSCG_CTRL); 16897839a050SYann Gautier } 16907839a050SYann Gautier 16910d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc) 16927839a050SYann Gautier { 16930d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 1694dfdb057aSYann Gautier uint64_t timeout; 16957839a050SYann Gautier 16960d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, 16977839a050SYann Gautier clksrc & RCC_SELR_SRC_MASK); 16987839a050SYann Gautier 1699dfdb057aSYann Gautier timeout = timeout_init_us(CLKSRC_TIMEOUT); 17000d21680cSYann Gautier while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { 1701dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17020d21680cSYann Gautier ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, 17030d21680cSYann Gautier clksrc_address, mmio_read_32(clksrc_address)); 17047839a050SYann Gautier return -ETIMEDOUT; 17057839a050SYann Gautier } 17067839a050SYann Gautier } 17077839a050SYann Gautier 17087839a050SYann Gautier return 0; 17097839a050SYann Gautier } 17107839a050SYann Gautier 17110d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) 17127839a050SYann Gautier { 1713dfdb057aSYann Gautier uint64_t timeout; 17147839a050SYann Gautier 17157839a050SYann Gautier mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, 17167839a050SYann Gautier clkdiv & RCC_DIVR_DIV_MASK); 17177839a050SYann Gautier 1718dfdb057aSYann Gautier timeout = timeout_init_us(CLKDIV_TIMEOUT); 17197839a050SYann Gautier while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { 1720dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17210d21680cSYann Gautier ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", 17227839a050SYann Gautier clkdiv, address, mmio_read_32(address)); 17237839a050SYann Gautier return -ETIMEDOUT; 17247839a050SYann Gautier } 17257839a050SYann Gautier } 17267839a050SYann Gautier 17277839a050SYann Gautier return 0; 17287839a050SYann Gautier } 17297839a050SYann Gautier 17300d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) 17317839a050SYann Gautier { 17320d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 17337839a050SYann Gautier 17347839a050SYann Gautier /* 17357839a050SYann Gautier * Binding clksrc : 17367839a050SYann Gautier * bit15-4 offset 17377839a050SYann Gautier * bit3: disable 17387839a050SYann Gautier * bit2-0: MCOSEL[2:0] 17397839a050SYann Gautier */ 17407839a050SYann Gautier if ((clksrc & 0x8U) != 0U) { 17410d21680cSYann Gautier mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17427839a050SYann Gautier } else { 17430d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17447839a050SYann Gautier RCC_MCOCFG_MCOSRC_MASK, 17457839a050SYann Gautier clksrc & RCC_MCOCFG_MCOSRC_MASK); 17460d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17477839a050SYann Gautier RCC_MCOCFG_MCODIV_MASK, 17487839a050SYann Gautier clkdiv << RCC_MCOCFG_MCODIV_SHIFT); 17490d21680cSYann Gautier mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17507839a050SYann Gautier } 17517839a050SYann Gautier } 17527839a050SYann Gautier 17530d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) 17547839a050SYann Gautier { 17550d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; 17567839a050SYann Gautier 17577839a050SYann Gautier if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || 17587839a050SYann Gautier (clksrc != (uint32_t)CLK_RTC_DISABLED)) { 17597839a050SYann Gautier mmio_clrsetbits_32(address, 17607839a050SYann Gautier RCC_BDCR_RTCSRC_MASK, 176115509093SYann Gautier (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); 17627839a050SYann Gautier 17637839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_RTCCKEN); 17647839a050SYann Gautier } 17657839a050SYann Gautier 17667839a050SYann Gautier if (lse_css) { 17677839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_LSECSSON); 17687839a050SYann Gautier } 17697839a050SYann Gautier } 17707839a050SYann Gautier 17710d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs) 17727839a050SYann Gautier { 17730d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); 17747839a050SYann Gautier uint32_t value = pkcs & 0xFU; 17757839a050SYann Gautier uint32_t mask = 0xFU; 17767839a050SYann Gautier 17777839a050SYann Gautier if ((pkcs & BIT(31)) != 0U) { 17787839a050SYann Gautier mask <<= 4; 17797839a050SYann Gautier value <<= 4; 17807839a050SYann Gautier } 17817839a050SYann Gautier 17827839a050SYann Gautier mmio_clrsetbits_32(address, mask, value); 17837839a050SYann Gautier } 17847839a050SYann Gautier 1785964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, 1786964e5ff1SNicolas Le Bayon uint32_t *fracv, uint32_t *csg, 1787964e5ff1SNicolas Le Bayon bool *csg_set) 1788964e5ff1SNicolas Le Bayon { 1789964e5ff1SNicolas Le Bayon void *fdt; 1790964e5ff1SNicolas Le Bayon int ret; 1791964e5ff1SNicolas Le Bayon 1792964e5ff1SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 1793964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1794964e5ff1SNicolas Le Bayon } 1795964e5ff1SNicolas Le Bayon 1796964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB, 1797964e5ff1SNicolas Le Bayon pllcfg); 1798964e5ff1SNicolas Le Bayon if (ret < 0) { 1799964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1800964e5ff1SNicolas Le Bayon } 1801964e5ff1SNicolas Le Bayon 1802964e5ff1SNicolas Le Bayon *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1803964e5ff1SNicolas Le Bayon 1804964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB, 1805964e5ff1SNicolas Le Bayon csg); 1806964e5ff1SNicolas Le Bayon 1807964e5ff1SNicolas Le Bayon *csg_set = (ret == 0); 1808964e5ff1SNicolas Le Bayon 1809964e5ff1SNicolas Le Bayon if (ret == -FDT_ERR_NOTFOUND) { 1810964e5ff1SNicolas Le Bayon ret = 0; 1811964e5ff1SNicolas Le Bayon } 1812964e5ff1SNicolas Le Bayon 1813964e5ff1SNicolas Le Bayon return ret; 1814964e5ff1SNicolas Le Bayon } 1815964e5ff1SNicolas Le Bayon 18167839a050SYann Gautier int stm32mp1_clk_init(void) 18177839a050SYann Gautier { 18180d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 1819964e5ff1SNicolas Le Bayon uint32_t pllfracv[_PLL_NB]; 1820964e5ff1SNicolas Le Bayon uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; 18217839a050SYann Gautier unsigned int clksrc[CLKSRC_NB]; 18227839a050SYann Gautier unsigned int clkdiv[CLKDIV_NB]; 18237839a050SYann Gautier unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; 18247839a050SYann Gautier int plloff[_PLL_NB]; 18257839a050SYann Gautier int ret, len; 18267839a050SYann Gautier enum stm32mp1_pll_id i; 1827964e5ff1SNicolas Le Bayon bool pllcsg_set[_PLL_NB]; 1828964e5ff1SNicolas Le Bayon bool pllcfg_valid[_PLL_NB]; 18297839a050SYann Gautier bool lse_css = false; 18300d21680cSYann Gautier bool pll3_preserve = false; 18310d21680cSYann Gautier bool pll4_preserve = false; 18320d21680cSYann Gautier bool pll4_bootrom = false; 18333e6fab43SYann Gautier const fdt32_t *pkcs_cell; 183452a616b4SAndre Przywara void *fdt; 1835bf1af154SPatrick Delaunay int stgen_p = stm32mp1_clk_get_parent(STGEN_K); 1836bf1af154SPatrick Delaunay int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K); 183752a616b4SAndre Przywara 183852a616b4SAndre Przywara if (fdt_get_address(&fdt) == 0) { 18398f97c4faSYann Gautier return -FDT_ERR_NOTFOUND; 184052a616b4SAndre Przywara } 18417839a050SYann Gautier 184252a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, 184352a616b4SAndre Przywara clksrc); 18447839a050SYann Gautier if (ret < 0) { 18457839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18467839a050SYann Gautier } 18477839a050SYann Gautier 184852a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, 184952a616b4SAndre Przywara clkdiv); 18507839a050SYann Gautier if (ret < 0) { 18517839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18527839a050SYann Gautier } 18537839a050SYann Gautier 18547839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 18557839a050SYann Gautier char name[12]; 18567839a050SYann Gautier 18579fa9a0c5SYann Gautier snprintf(name, sizeof(name), "st,pll@%u", i); 18587839a050SYann Gautier plloff[i] = fdt_rcc_subnode_offset(name); 18597839a050SYann Gautier 1860964e5ff1SNicolas Le Bayon pllcfg_valid[i] = fdt_check_node(plloff[i]); 1861964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 18627839a050SYann Gautier continue; 18637839a050SYann Gautier } 18647839a050SYann Gautier 1865964e5ff1SNicolas Le Bayon ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], 1866964e5ff1SNicolas Le Bayon &pllfracv[i], pllcsg[i], 1867964e5ff1SNicolas Le Bayon &pllcsg_set[i]); 1868964e5ff1SNicolas Le Bayon if (ret != 0) { 1869964e5ff1SNicolas Le Bayon return ret; 18707839a050SYann Gautier } 18717839a050SYann Gautier } 18727839a050SYann Gautier 18730d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); 18740d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); 18757839a050SYann Gautier 18767839a050SYann Gautier /* 18777839a050SYann Gautier * Switch ON oscillator found in device-tree. 18787839a050SYann Gautier * Note: HSI already ON after BootROM stage. 18797839a050SYann Gautier */ 18800d21680cSYann Gautier if (stm32mp1_osc[_LSI] != 0U) { 18810d21680cSYann Gautier stm32mp1_lsi_set(true); 18827839a050SYann Gautier } 18830d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 1884b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_LSE]; 18850d21680cSYann Gautier bool bypass, digbyp; 18867839a050SYann Gautier uint32_t lsedrv; 18877839a050SYann Gautier 1888b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1889b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1890b208e3daSGabriel Fernandez lse_css = fdt_clk_read_bool(name, "st,css"); 1891b208e3daSGabriel Fernandez lsedrv = fdt_clk_read_uint32_default(name, "st,drive", 18927839a050SYann Gautier LSEDRV_MEDIUM_HIGH); 18930d21680cSYann Gautier stm32mp1_lse_enable(bypass, digbyp, lsedrv); 18947839a050SYann Gautier } 18950d21680cSYann Gautier if (stm32mp1_osc[_HSE] != 0U) { 1896b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_HSE]; 18970d21680cSYann Gautier bool bypass, digbyp, css; 18987839a050SYann Gautier 1899b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1900b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1901b208e3daSGabriel Fernandez css = fdt_clk_read_bool(name, "st,css"); 19020d21680cSYann Gautier stm32mp1_hse_enable(bypass, digbyp, css); 19037839a050SYann Gautier } 19047839a050SYann Gautier /* 19057839a050SYann Gautier * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) 19067839a050SYann Gautier * => switch on CSI even if node is not present in device tree 19077839a050SYann Gautier */ 19080d21680cSYann Gautier stm32mp1_csi_set(true); 19097839a050SYann Gautier 19107839a050SYann Gautier /* Come back to HSI */ 19110d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_MPU_HSI); 19127839a050SYann Gautier if (ret != 0) { 19137839a050SYann Gautier return ret; 19147839a050SYann Gautier } 19150d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_AXI_HSI); 19167839a050SYann Gautier if (ret != 0) { 19177839a050SYann Gautier return ret; 19187839a050SYann Gautier } 1919b053a22eSYann Gautier ret = stm32mp1_set_clksrc(CLK_MCU_HSI); 1920b053a22eSYann Gautier if (ret != 0) { 1921b053a22eSYann Gautier return ret; 1922b053a22eSYann Gautier } 19237839a050SYann Gautier 19240d21680cSYann Gautier if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & 19250d21680cSYann Gautier RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { 1926175758b2SYann Gautier if (pllcfg_valid[_PLL3]) { 1927175758b2SYann Gautier pll3_preserve = 1928175758b2SYann Gautier stm32mp1_check_pll_conf(_PLL3, 19290d21680cSYann Gautier clksrc[CLKSRC_PLL3], 19300d21680cSYann Gautier pllcfg[_PLL3], 19310d21680cSYann Gautier plloff[_PLL3]); 1932175758b2SYann Gautier } 1933175758b2SYann Gautier 1934175758b2SYann Gautier if (pllcfg_valid[_PLL4]) { 1935175758b2SYann Gautier pll4_preserve = 1936175758b2SYann Gautier stm32mp1_check_pll_conf(_PLL4, 19370d21680cSYann Gautier clksrc[CLKSRC_PLL4], 19380d21680cSYann Gautier pllcfg[_PLL4], 19390d21680cSYann Gautier plloff[_PLL4]); 19400d21680cSYann Gautier } 1941175758b2SYann Gautier } 1942bf1af154SPatrick Delaunay /* Don't initialize PLL4, when used by BOOTROM */ 1943bf1af154SPatrick Delaunay if ((stm32mp_get_boot_itf_selected() == 1944bf1af154SPatrick Delaunay BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) && 1945bf1af154SPatrick Delaunay ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { 1946bf1af154SPatrick Delaunay pll4_bootrom = true; 1947bf1af154SPatrick Delaunay pll4_preserve = true; 1948bf1af154SPatrick Delaunay } 19490d21680cSYann Gautier 19507839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19510d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 19520d21680cSYann Gautier ((i == _PLL4) && pll4_preserve)) { 19537839a050SYann Gautier continue; 19540d21680cSYann Gautier } 19550d21680cSYann Gautier 19560d21680cSYann Gautier ret = stm32mp1_pll_stop(i); 19577839a050SYann Gautier if (ret != 0) { 19587839a050SYann Gautier return ret; 19597839a050SYann Gautier } 19607839a050SYann Gautier } 19617839a050SYann Gautier 19627839a050SYann Gautier /* Configure HSIDIV */ 19630d21680cSYann Gautier if (stm32mp1_osc[_HSI] != 0U) { 19640d21680cSYann Gautier ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); 19657839a050SYann Gautier if (ret != 0) { 19667839a050SYann Gautier return ret; 19677839a050SYann Gautier } 1968591d80c8SLionel Debieve 1969591d80c8SLionel Debieve stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K)); 19707839a050SYann Gautier } 19717839a050SYann Gautier 19727839a050SYann Gautier /* Select DIV */ 19737839a050SYann Gautier /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ 19740d21680cSYann Gautier mmio_write_32(rcc_base + RCC_MPCKDIVR, 19757839a050SYann Gautier clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 19760d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); 19777839a050SYann Gautier if (ret != 0) { 19787839a050SYann Gautier return ret; 19797839a050SYann Gautier } 19800d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); 19817839a050SYann Gautier if (ret != 0) { 19827839a050SYann Gautier return ret; 19837839a050SYann Gautier } 19840d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); 19857839a050SYann Gautier if (ret != 0) { 19867839a050SYann Gautier return ret; 19877839a050SYann Gautier } 1988b053a22eSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); 1989b053a22eSYann Gautier if (ret != 0) { 1990b053a22eSYann Gautier return ret; 1991b053a22eSYann Gautier } 19920d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); 19937839a050SYann Gautier if (ret != 0) { 19947839a050SYann Gautier return ret; 19957839a050SYann Gautier } 19960d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); 19977839a050SYann Gautier if (ret != 0) { 19987839a050SYann Gautier return ret; 19997839a050SYann Gautier } 20000d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); 20017839a050SYann Gautier if (ret != 0) { 20027839a050SYann Gautier return ret; 20037839a050SYann Gautier } 20047839a050SYann Gautier 20057839a050SYann Gautier /* No ready bit for RTC */ 20060d21680cSYann Gautier mmio_write_32(rcc_base + RCC_RTCDIVR, 20077839a050SYann Gautier clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); 20087839a050SYann Gautier 20097839a050SYann Gautier /* Configure PLLs source */ 20100d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); 20117839a050SYann Gautier if (ret != 0) { 20127839a050SYann Gautier return ret; 20137839a050SYann Gautier } 20147839a050SYann Gautier 20150d21680cSYann Gautier if (!pll3_preserve) { 20160d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); 20177839a050SYann Gautier if (ret != 0) { 20187839a050SYann Gautier return ret; 20197839a050SYann Gautier } 20200d21680cSYann Gautier } 20210d21680cSYann Gautier 20220d21680cSYann Gautier if (!pll4_preserve) { 20230d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); 20240d21680cSYann Gautier if (ret != 0) { 20250d21680cSYann Gautier return ret; 20260d21680cSYann Gautier } 20270d21680cSYann Gautier } 20287839a050SYann Gautier 20297839a050SYann Gautier /* Configure and start PLLs */ 20307839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 20310d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 20320d21680cSYann Gautier ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { 20330d21680cSYann Gautier continue; 20340d21680cSYann Gautier } 20350d21680cSYann Gautier 2036964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20377839a050SYann Gautier continue; 20387839a050SYann Gautier } 20397839a050SYann Gautier 20400d21680cSYann Gautier if ((i == _PLL4) && pll4_bootrom) { 20410d21680cSYann Gautier /* Set output divider if not done by the Bootrom */ 20420d21680cSYann Gautier stm32mp1_pll_config_output(i, pllcfg[i]); 20430d21680cSYann Gautier continue; 20440d21680cSYann Gautier } 20450d21680cSYann Gautier 2046964e5ff1SNicolas Le Bayon ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); 20477839a050SYann Gautier if (ret != 0) { 20487839a050SYann Gautier return ret; 20497839a050SYann Gautier } 2050964e5ff1SNicolas Le Bayon 2051964e5ff1SNicolas Le Bayon if (pllcsg_set[i]) { 2052964e5ff1SNicolas Le Bayon stm32mp1_pll_csg(i, pllcsg[i]); 20537839a050SYann Gautier } 20547839a050SYann Gautier 20550d21680cSYann Gautier stm32mp1_pll_start(i); 20567839a050SYann Gautier } 20571b491eeaSElyes Haouas /* Wait and start PLLs output when ready */ 20587839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 2059964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20607839a050SYann Gautier continue; 20617839a050SYann Gautier } 20627839a050SYann Gautier 20630d21680cSYann Gautier ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); 20647839a050SYann Gautier if (ret != 0) { 20657839a050SYann Gautier return ret; 20667839a050SYann Gautier } 20677839a050SYann Gautier } 20687839a050SYann Gautier /* Wait LSE ready before to use it */ 20690d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 20700d21680cSYann Gautier stm32mp1_lse_wait(); 20717839a050SYann Gautier } 20727839a050SYann Gautier 20737839a050SYann Gautier /* Configure with expected clock source */ 20740d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); 20757839a050SYann Gautier if (ret != 0) { 20767839a050SYann Gautier return ret; 20777839a050SYann Gautier } 20780d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); 20797839a050SYann Gautier if (ret != 0) { 20807839a050SYann Gautier return ret; 20817839a050SYann Gautier } 2082b053a22eSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); 2083b053a22eSYann Gautier if (ret != 0) { 2084b053a22eSYann Gautier return ret; 2085b053a22eSYann Gautier } 20860d21680cSYann Gautier stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); 20877839a050SYann Gautier 20887839a050SYann Gautier /* Configure PKCK */ 20897839a050SYann Gautier pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); 20907839a050SYann Gautier if (pkcs_cell != NULL) { 20917839a050SYann Gautier bool ckper_disabled = false; 20927839a050SYann Gautier uint32_t j; 2093bf1af154SPatrick Delaunay uint32_t usbreg_bootrom = 0U; 2094bf1af154SPatrick Delaunay 2095bf1af154SPatrick Delaunay if (pll4_bootrom) { 2096bf1af154SPatrick Delaunay usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); 2097bf1af154SPatrick Delaunay } 20987839a050SYann Gautier 20997839a050SYann Gautier for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { 21003e6fab43SYann Gautier uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); 21017839a050SYann Gautier 21027839a050SYann Gautier if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { 21037839a050SYann Gautier ckper_disabled = true; 21047839a050SYann Gautier continue; 21057839a050SYann Gautier } 21060d21680cSYann Gautier stm32mp1_pkcs_config(pkcs); 21077839a050SYann Gautier } 21087839a050SYann Gautier 21097839a050SYann Gautier /* 21107839a050SYann Gautier * CKPER is source for some peripheral clocks 21117839a050SYann Gautier * (FMC-NAND / QPSI-NOR) and switching source is allowed 21127839a050SYann Gautier * only if previous clock is still ON 21137839a050SYann Gautier * => deactivated CKPER only after switching clock 21147839a050SYann Gautier */ 21157839a050SYann Gautier if (ckper_disabled) { 21160d21680cSYann Gautier stm32mp1_pkcs_config(CLK_CKPER_DISABLED); 21177839a050SYann Gautier } 2118bf1af154SPatrick Delaunay 2119bf1af154SPatrick Delaunay if (pll4_bootrom) { 2120bf1af154SPatrick Delaunay uint32_t usbreg_value, usbreg_mask; 2121bf1af154SPatrick Delaunay const struct stm32mp1_clk_sel *sel; 2122bf1af154SPatrick Delaunay 2123bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBPHY_SEL); 2124bf1af154SPatrick Delaunay usbreg_mask = (uint32_t)sel->msk << sel->src; 2125bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBO_SEL); 2126bf1af154SPatrick Delaunay usbreg_mask |= (uint32_t)sel->msk << sel->src; 2127bf1af154SPatrick Delaunay 2128bf1af154SPatrick Delaunay usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & 2129bf1af154SPatrick Delaunay usbreg_mask; 2130bf1af154SPatrick Delaunay usbreg_bootrom &= usbreg_mask; 2131bf1af154SPatrick Delaunay if (usbreg_bootrom != usbreg_value) { 2132bf1af154SPatrick Delaunay VERBOSE("forbidden new USB clk path\n"); 2133bf1af154SPatrick Delaunay VERBOSE("vs bootrom on USB boot\n"); 2134bf1af154SPatrick Delaunay return -FDT_ERR_BADVALUE; 2135bf1af154SPatrick Delaunay } 2136bf1af154SPatrick Delaunay } 21377839a050SYann Gautier } 21387839a050SYann Gautier 21397839a050SYann Gautier /* Switch OFF HSI if not found in device-tree */ 21400d21680cSYann Gautier if (stm32mp1_osc[_HSI] == 0U) { 21410d21680cSYann Gautier stm32mp1_hsi_set(false); 21427839a050SYann Gautier } 2143591d80c8SLionel Debieve 2144591d80c8SLionel Debieve stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K)); 21457839a050SYann Gautier 21467839a050SYann Gautier /* Software Self-Refresh mode (SSR) during DDR initilialization */ 21470d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, 21487839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_MASK, 21497839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SSR << 21507839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SHIFT); 21517839a050SYann Gautier 21527839a050SYann Gautier return 0; 21537839a050SYann Gautier } 21547839a050SYann Gautier 21557839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name, 21567839a050SYann Gautier enum stm32mp_osc_id index) 21577839a050SYann Gautier { 21587839a050SYann Gautier uint32_t frequency; 21597839a050SYann Gautier 21600d21680cSYann Gautier if (fdt_osc_read_freq(name, &frequency) == 0) { 21610d21680cSYann Gautier stm32mp1_osc[index] = frequency; 21627839a050SYann Gautier } 21637839a050SYann Gautier } 21647839a050SYann Gautier 21657839a050SYann Gautier static void stm32mp1_osc_init(void) 21667839a050SYann Gautier { 21677839a050SYann Gautier enum stm32mp_osc_id i; 21687839a050SYann Gautier 21697839a050SYann Gautier for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { 21700d21680cSYann Gautier stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); 21717839a050SYann Gautier } 21727839a050SYann Gautier } 21737839a050SYann Gautier 217437e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES 217537e8295aSEtienne Carriere /* 217637e8295aSEtienne Carriere * Get the parent ID of the target parent clock, for tagging as secure 217737e8295aSEtienne Carriere * shared clock dependencies. 217837e8295aSEtienne Carriere */ 217937e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id) 218037e8295aSEtienne Carriere { 218137e8295aSEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 218237e8295aSEtienne Carriere enum stm32mp1_pll_id pll_id; 218337e8295aSEtienne Carriere uint32_t p_sel; 218437e8295aSEtienne Carriere uintptr_t rcc_base = stm32mp_rcc_base(); 218537e8295aSEtienne Carriere 218637e8295aSEtienne Carriere switch (parent_id) { 218737e8295aSEtienne Carriere case _ACLK: 218837e8295aSEtienne Carriere case _PCLK4: 218937e8295aSEtienne Carriere case _PCLK5: 219037e8295aSEtienne Carriere s = _AXIS_SEL; 219137e8295aSEtienne Carriere break; 219237e8295aSEtienne Carriere case _PLL1_P: 219337e8295aSEtienne Carriere case _PLL1_Q: 219437e8295aSEtienne Carriere case _PLL1_R: 219537e8295aSEtienne Carriere pll_id = _PLL1; 219637e8295aSEtienne Carriere break; 219737e8295aSEtienne Carriere case _PLL2_P: 219837e8295aSEtienne Carriere case _PLL2_Q: 219937e8295aSEtienne Carriere case _PLL2_R: 220037e8295aSEtienne Carriere pll_id = _PLL2; 220137e8295aSEtienne Carriere break; 220237e8295aSEtienne Carriere case _PLL3_P: 220337e8295aSEtienne Carriere case _PLL3_Q: 220437e8295aSEtienne Carriere case _PLL3_R: 220537e8295aSEtienne Carriere pll_id = _PLL3; 220637e8295aSEtienne Carriere break; 220737e8295aSEtienne Carriere case _PLL4_P: 220837e8295aSEtienne Carriere case _PLL4_Q: 220937e8295aSEtienne Carriere case _PLL4_R: 221037e8295aSEtienne Carriere pll_id = _PLL4; 221137e8295aSEtienne Carriere break; 221237e8295aSEtienne Carriere case _PCLK1: 221337e8295aSEtienne Carriere case _PCLK2: 221437e8295aSEtienne Carriere case _HCLK2: 221537e8295aSEtienne Carriere case _HCLK6: 221637e8295aSEtienne Carriere case _CK_PER: 221737e8295aSEtienne Carriere case _CK_MPU: 221837e8295aSEtienne Carriere case _CK_MCU: 221937e8295aSEtienne Carriere case _USB_PHY_48: 222037e8295aSEtienne Carriere /* We do not expect to access these */ 222137e8295aSEtienne Carriere panic(); 222237e8295aSEtienne Carriere break; 222337e8295aSEtienne Carriere default: 222437e8295aSEtienne Carriere /* Other parents have no parent */ 222537e8295aSEtienne Carriere return -1; 222637e8295aSEtienne Carriere } 222737e8295aSEtienne Carriere 222837e8295aSEtienne Carriere if (s != _UNKNOWN_SEL) { 222937e8295aSEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 223037e8295aSEtienne Carriere 223137e8295aSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & 223237e8295aSEtienne Carriere sel->msk; 223337e8295aSEtienne Carriere 223437e8295aSEtienne Carriere if (p_sel < sel->nb_parent) { 223537e8295aSEtienne Carriere return (int)sel->parent[p_sel]; 223637e8295aSEtienne Carriere } 223737e8295aSEtienne Carriere } else { 223837e8295aSEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 223937e8295aSEtienne Carriere 224037e8295aSEtienne Carriere p_sel = mmio_read_32(rcc_base + pll->rckxselr) & 224137e8295aSEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 224237e8295aSEtienne Carriere 224337e8295aSEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { 224437e8295aSEtienne Carriere return (int)pll->refclk[p_sel]; 224537e8295aSEtienne Carriere } 224637e8295aSEtienne Carriere } 224737e8295aSEtienne Carriere 224837e8295aSEtienne Carriere VERBOSE("No parent selected for %s\n", 224937e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 225037e8295aSEtienne Carriere 225137e8295aSEtienne Carriere return -1; 225237e8295aSEtienne Carriere } 225337e8295aSEtienne Carriere 225437e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id) 225537e8295aSEtienne Carriere { 225637e8295aSEtienne Carriere int grandparent_id; 225737e8295aSEtienne Carriere 225837e8295aSEtienne Carriere switch (parent_id) { 225937e8295aSEtienne Carriere case _PLL3_P: 226037e8295aSEtienne Carriere case _PLL3_Q: 226137e8295aSEtienne Carriere case _PLL3_R: 226237e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 226337e8295aSEtienne Carriere break; 226437e8295aSEtienne Carriere 226537e8295aSEtienne Carriere /* These clocks are always secure when RCC is secure */ 226637e8295aSEtienne Carriere case _ACLK: 226737e8295aSEtienne Carriere case _HCLK2: 226837e8295aSEtienne Carriere case _HCLK6: 226937e8295aSEtienne Carriere case _PCLK4: 227037e8295aSEtienne Carriere case _PCLK5: 227137e8295aSEtienne Carriere case _PLL1_P: 227237e8295aSEtienne Carriere case _PLL1_Q: 227337e8295aSEtienne Carriere case _PLL1_R: 227437e8295aSEtienne Carriere case _PLL2_P: 227537e8295aSEtienne Carriere case _PLL2_Q: 227637e8295aSEtienne Carriere case _PLL2_R: 227737e8295aSEtienne Carriere case _HSI: 227837e8295aSEtienne Carriere case _HSI_KER: 227937e8295aSEtienne Carriere case _LSI: 228037e8295aSEtienne Carriere case _CSI: 228137e8295aSEtienne Carriere case _CSI_KER: 228237e8295aSEtienne Carriere case _HSE: 228337e8295aSEtienne Carriere case _HSE_KER: 228437e8295aSEtienne Carriere case _HSE_KER_DIV2: 2285cbd2e8a6SGabriel Fernandez case _HSE_RTC: 228637e8295aSEtienne Carriere case _LSE: 228737e8295aSEtienne Carriere break; 228837e8295aSEtienne Carriere 228937e8295aSEtienne Carriere default: 229037e8295aSEtienne Carriere VERBOSE("Cannot secure parent clock %s\n", 229137e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 229237e8295aSEtienne Carriere panic(); 229337e8295aSEtienne Carriere } 229437e8295aSEtienne Carriere 229537e8295aSEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 229637e8295aSEtienne Carriere if (grandparent_id >= 0) { 229737e8295aSEtienne Carriere secure_parent_clocks(grandparent_id); 229837e8295aSEtienne Carriere } 229937e8295aSEtienne Carriere } 230037e8295aSEtienne Carriere 230137e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id) 230237e8295aSEtienne Carriere { 230337e8295aSEtienne Carriere int parent_id; 230437e8295aSEtienne Carriere 230537e8295aSEtienne Carriere if (!stm32mp1_rcc_is_secure()) { 230637e8295aSEtienne Carriere return; 230737e8295aSEtienne Carriere } 230837e8295aSEtienne Carriere 230937e8295aSEtienne Carriere switch (clock_id) { 231037e8295aSEtienne Carriere case PLL1: 231137e8295aSEtienne Carriere case PLL2: 231237e8295aSEtienne Carriere /* PLL1/PLL2 are always secure: nothing to do */ 231337e8295aSEtienne Carriere break; 231437e8295aSEtienne Carriere case PLL3: 231537e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 231637e8295aSEtienne Carriere break; 231737e8295aSEtienne Carriere case PLL4: 231837e8295aSEtienne Carriere ERROR("PLL4 cannot be secured\n"); 231937e8295aSEtienne Carriere panic(); 232037e8295aSEtienne Carriere break; 232137e8295aSEtienne Carriere default: 232237e8295aSEtienne Carriere /* Others are expected gateable clock */ 232337e8295aSEtienne Carriere parent_id = stm32mp1_clk_get_parent(clock_id); 232437e8295aSEtienne Carriere if (parent_id < 0) { 232537e8295aSEtienne Carriere INFO("No parent found for clock %lu\n", clock_id); 232637e8295aSEtienne Carriere } else { 232737e8295aSEtienne Carriere secure_parent_clocks(parent_id); 232837e8295aSEtienne Carriere } 232937e8295aSEtienne Carriere break; 233037e8295aSEtienne Carriere } 233137e8295aSEtienne Carriere } 233237e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */ 233337e8295aSEtienne Carriere 233477b4ca0bSLionel Debieve void stm32mp1_clk_mcuss_protect(bool enable) 233577b4ca0bSLionel Debieve { 233677b4ca0bSLionel Debieve uintptr_t rcc_base = stm32mp_rcc_base(); 233777b4ca0bSLionel Debieve 233877b4ca0bSLionel Debieve if (enable) { 233977b4ca0bSLionel Debieve mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); 234077b4ca0bSLionel Debieve } else { 234177b4ca0bSLionel Debieve mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); 234277b4ca0bSLionel Debieve } 234377b4ca0bSLionel Debieve } 234477b4ca0bSLionel Debieve 23456cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void) 23466cb45f89SYann Gautier { 2347033b6c3aSEtienne Carriere unsigned int idx; 2348033b6c3aSEtienne Carriere const unsigned long secure_enable[] = { 2349033b6c3aSEtienne Carriere AXIDCG, 2350033b6c3aSEtienne Carriere BSEC, 2351033b6c3aSEtienne Carriere DDRC1, DDRC1LP, 2352033b6c3aSEtienne Carriere DDRC2, DDRC2LP, 2353033b6c3aSEtienne Carriere DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, 2354033b6c3aSEtienne Carriere DDRPHYC, DDRPHYCLP, 2355373f06beSLionel Debieve RTCAPB, 2356033b6c3aSEtienne Carriere TZC1, TZC2, 2357033b6c3aSEtienne Carriere TZPC, 2358033b6c3aSEtienne Carriere STGEN_K, 2359033b6c3aSEtienne Carriere }; 2360033b6c3aSEtienne Carriere 2361033b6c3aSEtienne Carriere for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { 2362033b6c3aSEtienne Carriere stm32mp_clk_enable(secure_enable[idx]); 2363033b6c3aSEtienne Carriere } 23646cb45f89SYann Gautier } 23656cb45f89SYann Gautier 236633667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = { 236733667d29SYann Gautier .enable = stm32mp_clk_enable, 236833667d29SYann Gautier .disable = stm32mp_clk_disable, 236933667d29SYann Gautier .is_enabled = stm32mp_clk_is_enabled, 237033667d29SYann Gautier .get_rate = stm32mp_clk_get_rate, 237133667d29SYann Gautier .get_parent = stm32mp1_clk_get_parent, 237233667d29SYann Gautier }; 237333667d29SYann Gautier 23747839a050SYann Gautier int stm32mp1_clk_probe(void) 23757839a050SYann Gautier { 2376812daf91SLionel Debieve #if defined(IMAGE_BL32) 2377812daf91SLionel Debieve if (!fdt_get_rcc_secure_state()) { 2378812daf91SLionel Debieve mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U); 2379812daf91SLionel Debieve } 2380812daf91SLionel Debieve #endif 2381812daf91SLionel Debieve 23827839a050SYann Gautier stm32mp1_osc_init(); 23837839a050SYann Gautier 23846cb45f89SYann Gautier sync_earlyboot_clocks_state(); 23856cb45f89SYann Gautier 238633667d29SYann Gautier clk_register(&stm32mp_clk_ops); 238733667d29SYann Gautier 23887839a050SYann Gautier return 0; 23897839a050SYann Gautier } 2390