17839a050SYann Gautier /* 2964e5ff1SNicolas Le Bayon * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved 37839a050SYann Gautier * 47839a050SYann Gautier * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 57839a050SYann Gautier */ 67839a050SYann Gautier 77839a050SYann Gautier #include <assert.h> 87839a050SYann Gautier #include <errno.h> 97839a050SYann Gautier #include <stdint.h> 1039b6cc66SAntonio Nino Diaz #include <stdio.h> 1109d40e0eSAntonio Nino Diaz 1209d40e0eSAntonio Nino Diaz #include <arch.h> 1309d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1409d40e0eSAntonio Nino Diaz #include <common/debug.h> 1552a616b4SAndre Przywara #include <common/fdt_wrappers.h> 1633667d29SYann Gautier #include <drivers/clk.h> 1709d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 18447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h> 1909d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h> 2009d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h> 2109d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h> 2209d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 230d21680cSYann Gautier #include <lib/spinlock.h> 2409d40e0eSAntonio Nino Diaz #include <lib/utils_def.h> 25964e5ff1SNicolas Le Bayon #include <libfdt.h> 2609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 2709d40e0eSAntonio Nino Diaz 28964e5ff1SNicolas Le Bayon #include <platform_def.h> 29964e5ff1SNicolas Le Bayon 307839a050SYann Gautier #define MAX_HSI_HZ 64000000 310d21680cSYann Gautier #define USB_PHY_48_MHZ 48000000 327839a050SYann Gautier 33dfdb057aSYann Gautier #define TIMEOUT_US_200MS U(200000) 34dfdb057aSYann Gautier #define TIMEOUT_US_1S U(1000000) 357839a050SYann Gautier 36dfdb057aSYann Gautier #define PLLRDY_TIMEOUT TIMEOUT_US_200MS 37dfdb057aSYann Gautier #define CLKSRC_TIMEOUT TIMEOUT_US_200MS 38dfdb057aSYann Gautier #define CLKDIV_TIMEOUT TIMEOUT_US_200MS 39dfdb057aSYann Gautier #define HSIDIV_TIMEOUT TIMEOUT_US_200MS 40dfdb057aSYann Gautier #define OSCRDY_TIMEOUT TIMEOUT_US_1S 417839a050SYann Gautier 42f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = { 43f66358afSYann Gautier [_LSI] = "clk-lsi", 44f66358afSYann Gautier [_LSE] = "clk-lse", 45f66358afSYann Gautier [_HSI] = "clk-hsi", 46f66358afSYann Gautier [_HSE] = "clk-hse", 47f66358afSYann Gautier [_CSI] = "clk-csi", 48f66358afSYann Gautier [_I2S_CKIN] = "i2s_ckin", 49f66358afSYann Gautier }; 50f66358afSYann Gautier 517839a050SYann Gautier enum stm32mp1_parent_id { 527839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */ 537839a050SYann Gautier 547839a050SYann Gautier /* Other parent source */ 557839a050SYann Gautier _HSI_KER = NB_OSC, 567839a050SYann Gautier _HSE_KER, 577839a050SYann Gautier _HSE_KER_DIV2, 58cbd2e8a6SGabriel Fernandez _HSE_RTC, 597839a050SYann Gautier _CSI_KER, 607839a050SYann Gautier _PLL1_P, 617839a050SYann Gautier _PLL1_Q, 627839a050SYann Gautier _PLL1_R, 637839a050SYann Gautier _PLL2_P, 647839a050SYann Gautier _PLL2_Q, 657839a050SYann Gautier _PLL2_R, 667839a050SYann Gautier _PLL3_P, 677839a050SYann Gautier _PLL3_Q, 687839a050SYann Gautier _PLL3_R, 697839a050SYann Gautier _PLL4_P, 707839a050SYann Gautier _PLL4_Q, 717839a050SYann Gautier _PLL4_R, 727839a050SYann Gautier _ACLK, 737839a050SYann Gautier _PCLK1, 747839a050SYann Gautier _PCLK2, 757839a050SYann Gautier _PCLK3, 767839a050SYann Gautier _PCLK4, 777839a050SYann Gautier _PCLK5, 787839a050SYann Gautier _HCLK6, 797839a050SYann Gautier _HCLK2, 807839a050SYann Gautier _CK_PER, 817839a050SYann Gautier _CK_MPU, 82b053a22eSYann Gautier _CK_MCU, 830d21680cSYann Gautier _USB_PHY_48, 847839a050SYann Gautier _PARENT_NB, 857839a050SYann Gautier _UNKNOWN_ID = 0xff, 867839a050SYann Gautier }; 877839a050SYann Gautier 880d21680cSYann Gautier /* Lists only the parent clock we are interested in */ 897839a050SYann Gautier enum stm32mp1_parent_sel { 900d21680cSYann Gautier _I2C12_SEL, 910d21680cSYann Gautier _I2C35_SEL, 920d21680cSYann Gautier _STGEN_SEL, 937839a050SYann Gautier _I2C46_SEL, 940d21680cSYann Gautier _SPI6_SEL, 95d4151d2fSYann Gautier _UART1_SEL, 960d21680cSYann Gautier _RNG1_SEL, 977839a050SYann Gautier _UART6_SEL, 987839a050SYann Gautier _UART24_SEL, 997839a050SYann Gautier _UART35_SEL, 1007839a050SYann Gautier _UART78_SEL, 1017839a050SYann Gautier _SDMMC12_SEL, 1027839a050SYann Gautier _SDMMC3_SEL, 1037839a050SYann Gautier _QSPI_SEL, 1047839a050SYann Gautier _FMC_SEL, 105d4151d2fSYann Gautier _AXIS_SEL, 106d4151d2fSYann Gautier _MCUS_SEL, 1077839a050SYann Gautier _USBPHY_SEL, 1087839a050SYann Gautier _USBO_SEL, 1098fbcd9e4SEtienne Carriere _MPU_SEL, 110288f5cf2SYann Gautier _CKPER_SEL, 111016af006SEtienne Carriere _RTC_SEL, 1127839a050SYann Gautier _PARENT_SEL_NB, 1137839a050SYann Gautier _UNKNOWN_SEL = 0xff, 1147839a050SYann Gautier }; 1157839a050SYann Gautier 1168fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */ 1178fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = { 1188fbcd9e4SEtienne Carriere [_HSE] = CK_HSE, 1198fbcd9e4SEtienne Carriere [_HSI] = CK_HSI, 1208fbcd9e4SEtienne Carriere [_CSI] = CK_CSI, 1218fbcd9e4SEtienne Carriere [_LSE] = CK_LSE, 1228fbcd9e4SEtienne Carriere [_LSI] = CK_LSI, 1238fbcd9e4SEtienne Carriere [_I2S_CKIN] = _UNKNOWN_ID, 1248fbcd9e4SEtienne Carriere [_USB_PHY_48] = _UNKNOWN_ID, 1258fbcd9e4SEtienne Carriere [_HSI_KER] = CK_HSI, 1268fbcd9e4SEtienne Carriere [_HSE_KER] = CK_HSE, 1278fbcd9e4SEtienne Carriere [_HSE_KER_DIV2] = CK_HSE_DIV2, 128cbd2e8a6SGabriel Fernandez [_HSE_RTC] = _UNKNOWN_ID, 1298fbcd9e4SEtienne Carriere [_CSI_KER] = CK_CSI, 1308fbcd9e4SEtienne Carriere [_PLL1_P] = PLL1_P, 1318fbcd9e4SEtienne Carriere [_PLL1_Q] = PLL1_Q, 1328fbcd9e4SEtienne Carriere [_PLL1_R] = PLL1_R, 1338fbcd9e4SEtienne Carriere [_PLL2_P] = PLL2_P, 1348fbcd9e4SEtienne Carriere [_PLL2_Q] = PLL2_Q, 1358fbcd9e4SEtienne Carriere [_PLL2_R] = PLL2_R, 1368fbcd9e4SEtienne Carriere [_PLL3_P] = PLL3_P, 1378fbcd9e4SEtienne Carriere [_PLL3_Q] = PLL3_Q, 1388fbcd9e4SEtienne Carriere [_PLL3_R] = PLL3_R, 1398fbcd9e4SEtienne Carriere [_PLL4_P] = PLL4_P, 1408fbcd9e4SEtienne Carriere [_PLL4_Q] = PLL4_Q, 1418fbcd9e4SEtienne Carriere [_PLL4_R] = PLL4_R, 1428fbcd9e4SEtienne Carriere [_ACLK] = CK_AXI, 1438fbcd9e4SEtienne Carriere [_PCLK1] = CK_AXI, 1448fbcd9e4SEtienne Carriere [_PCLK2] = CK_AXI, 1458fbcd9e4SEtienne Carriere [_PCLK3] = CK_AXI, 1468fbcd9e4SEtienne Carriere [_PCLK4] = CK_AXI, 1478fbcd9e4SEtienne Carriere [_PCLK5] = CK_AXI, 1488fbcd9e4SEtienne Carriere [_CK_PER] = CK_PER, 1498fbcd9e4SEtienne Carriere [_CK_MPU] = CK_MPU, 1508fbcd9e4SEtienne Carriere [_CK_MCU] = CK_MCU, 1518fbcd9e4SEtienne Carriere }; 1528fbcd9e4SEtienne Carriere 1538fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id) 1548fbcd9e4SEtienne Carriere { 1558fbcd9e4SEtienne Carriere unsigned int n; 1568fbcd9e4SEtienne Carriere 1578fbcd9e4SEtienne Carriere for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) { 1588fbcd9e4SEtienne Carriere if (parent_id_clock_id[n] == id) { 1598fbcd9e4SEtienne Carriere return n; 1608fbcd9e4SEtienne Carriere } 1618fbcd9e4SEtienne Carriere } 1628fbcd9e4SEtienne Carriere 1638fbcd9e4SEtienne Carriere return _UNKNOWN_ID; 1648fbcd9e4SEtienne Carriere } 1658fbcd9e4SEtienne Carriere 1667839a050SYann Gautier enum stm32mp1_pll_id { 1677839a050SYann Gautier _PLL1, 1687839a050SYann Gautier _PLL2, 1697839a050SYann Gautier _PLL3, 1707839a050SYann Gautier _PLL4, 1717839a050SYann Gautier _PLL_NB 1727839a050SYann Gautier }; 1737839a050SYann Gautier 1747839a050SYann Gautier enum stm32mp1_div_id { 1757839a050SYann Gautier _DIV_P, 1767839a050SYann Gautier _DIV_Q, 1777839a050SYann Gautier _DIV_R, 1787839a050SYann Gautier _DIV_NB, 1797839a050SYann Gautier }; 1807839a050SYann Gautier 1817839a050SYann Gautier enum stm32mp1_clksrc_id { 1827839a050SYann Gautier CLKSRC_MPU, 1837839a050SYann Gautier CLKSRC_AXI, 184b053a22eSYann Gautier CLKSRC_MCU, 1857839a050SYann Gautier CLKSRC_PLL12, 1867839a050SYann Gautier CLKSRC_PLL3, 1877839a050SYann Gautier CLKSRC_PLL4, 1887839a050SYann Gautier CLKSRC_RTC, 1897839a050SYann Gautier CLKSRC_MCO1, 1907839a050SYann Gautier CLKSRC_MCO2, 1917839a050SYann Gautier CLKSRC_NB 1927839a050SYann Gautier }; 1937839a050SYann Gautier 1947839a050SYann Gautier enum stm32mp1_clkdiv_id { 1957839a050SYann Gautier CLKDIV_MPU, 1967839a050SYann Gautier CLKDIV_AXI, 197b053a22eSYann Gautier CLKDIV_MCU, 1987839a050SYann Gautier CLKDIV_APB1, 1997839a050SYann Gautier CLKDIV_APB2, 2007839a050SYann Gautier CLKDIV_APB3, 2017839a050SYann Gautier CLKDIV_APB4, 2027839a050SYann Gautier CLKDIV_APB5, 2037839a050SYann Gautier CLKDIV_RTC, 2047839a050SYann Gautier CLKDIV_MCO1, 2057839a050SYann Gautier CLKDIV_MCO2, 2067839a050SYann Gautier CLKDIV_NB 2077839a050SYann Gautier }; 2087839a050SYann Gautier 2097839a050SYann Gautier enum stm32mp1_pllcfg { 2107839a050SYann Gautier PLLCFG_M, 2117839a050SYann Gautier PLLCFG_N, 2127839a050SYann Gautier PLLCFG_P, 2137839a050SYann Gautier PLLCFG_Q, 2147839a050SYann Gautier PLLCFG_R, 2157839a050SYann Gautier PLLCFG_O, 2167839a050SYann Gautier PLLCFG_NB 2177839a050SYann Gautier }; 2187839a050SYann Gautier 2197839a050SYann Gautier enum stm32mp1_pllcsg { 2207839a050SYann Gautier PLLCSG_MOD_PER, 2217839a050SYann Gautier PLLCSG_INC_STEP, 2227839a050SYann Gautier PLLCSG_SSCG_MODE, 2237839a050SYann Gautier PLLCSG_NB 2247839a050SYann Gautier }; 2257839a050SYann Gautier 2267839a050SYann Gautier enum stm32mp1_plltype { 2277839a050SYann Gautier PLL_800, 2287839a050SYann Gautier PLL_1600, 2297839a050SYann Gautier PLL_TYPE_NB 2307839a050SYann Gautier }; 2317839a050SYann Gautier 2327839a050SYann Gautier struct stm32mp1_pll { 2337839a050SYann Gautier uint8_t refclk_min; 2347839a050SYann Gautier uint8_t refclk_max; 2357839a050SYann Gautier }; 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 13300d21680cSYann Gautier if (digbyp) { 13310d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); 13320d21680cSYann Gautier } 13330d21680cSYann Gautier 13340d21680cSYann Gautier if (bypass || digbyp) { 13350d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); 13367839a050SYann Gautier } 13377839a050SYann Gautier 13387839a050SYann Gautier /* 13397839a050SYann Gautier * Warning: not recommended to switch directly from "high drive" 13407839a050SYann Gautier * to "medium low drive", and vice-versa. 13417839a050SYann Gautier */ 13420d21680cSYann Gautier value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> 13437839a050SYann Gautier RCC_BDCR_LSEDRV_SHIFT; 13447839a050SYann Gautier 13457839a050SYann Gautier while (value != lsedrv) { 13467839a050SYann Gautier if (value > lsedrv) { 13477839a050SYann Gautier value--; 13487839a050SYann Gautier } else { 13497839a050SYann Gautier value++; 13507839a050SYann Gautier } 13517839a050SYann Gautier 13520d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_BDCR, 13537839a050SYann Gautier RCC_BDCR_LSEDRV_MASK, 13547839a050SYann Gautier value << RCC_BDCR_LSEDRV_SHIFT); 13557839a050SYann Gautier } 13567839a050SYann Gautier 13570d21680cSYann Gautier stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); 13587839a050SYann Gautier } 13597839a050SYann Gautier 13600d21680cSYann Gautier static void stm32mp1_lse_wait(void) 13617839a050SYann Gautier { 13620d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { 13637839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13647839a050SYann Gautier } 13657839a050SYann Gautier } 13667839a050SYann Gautier 13670d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable) 13687839a050SYann Gautier { 13690d21680cSYann Gautier stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); 13700d21680cSYann Gautier 13710d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { 13727839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13737839a050SYann Gautier } 13747839a050SYann Gautier } 13757839a050SYann Gautier 13760d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) 13777839a050SYann Gautier { 13780d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13790d21680cSYann Gautier 13800d21680cSYann Gautier if (digbyp) { 13810d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); 13827839a050SYann Gautier } 13837839a050SYann Gautier 13840d21680cSYann Gautier if (bypass || digbyp) { 13850d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); 13860d21680cSYann Gautier } 13870d21680cSYann Gautier 13880d21680cSYann Gautier stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); 13890d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { 13907839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13917839a050SYann Gautier } 13927839a050SYann Gautier 13937839a050SYann Gautier if (css) { 13940d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); 13957839a050SYann Gautier } 139631e9750bSLionel Debieve 139731e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER 139831e9750bSLionel Debieve if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) && 139931e9750bSLionel Debieve (!(digbyp || bypass))) { 140031e9750bSLionel Debieve panic(); 140131e9750bSLionel Debieve } 140231e9750bSLionel Debieve #endif 14037839a050SYann Gautier } 14047839a050SYann Gautier 14050d21680cSYann Gautier static void stm32mp1_csi_set(bool enable) 14067839a050SYann Gautier { 14070d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); 14080d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { 14097839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14107839a050SYann Gautier } 14117839a050SYann Gautier } 14127839a050SYann Gautier 14130d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable) 14147839a050SYann Gautier { 14150d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); 14160d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { 14177839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14187839a050SYann Gautier } 14197839a050SYann Gautier } 14207839a050SYann Gautier 14210d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv) 14227839a050SYann Gautier { 1423dfdb057aSYann Gautier uint64_t timeout; 14240d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14250d21680cSYann Gautier uintptr_t address = rcc_base + RCC_OCRDYR; 14267839a050SYann Gautier 14270d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, 14287839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK, 14297839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); 14307839a050SYann Gautier 1431dfdb057aSYann Gautier timeout = timeout_init_us(HSIDIV_TIMEOUT); 14327839a050SYann Gautier while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { 1433dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 14340d21680cSYann Gautier ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", 14357839a050SYann Gautier address, mmio_read_32(address)); 14367839a050SYann Gautier return -ETIMEDOUT; 14377839a050SYann Gautier } 14387839a050SYann Gautier } 14397839a050SYann Gautier 14407839a050SYann Gautier return 0; 14417839a050SYann Gautier } 14427839a050SYann Gautier 14430d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq) 14447839a050SYann Gautier { 14457839a050SYann Gautier uint8_t hsidiv; 14467839a050SYann Gautier uint32_t hsidivfreq = MAX_HSI_HZ; 14477839a050SYann Gautier 14487839a050SYann Gautier for (hsidiv = 0; hsidiv < 4U; hsidiv++) { 14497839a050SYann Gautier if (hsidivfreq == hsifreq) { 14507839a050SYann Gautier break; 14517839a050SYann Gautier } 14527839a050SYann Gautier 14537839a050SYann Gautier hsidivfreq /= 2U; 14547839a050SYann Gautier } 14557839a050SYann Gautier 14567839a050SYann Gautier if (hsidiv == 4U) { 14577839a050SYann Gautier ERROR("Invalid clk-hsi frequency\n"); 14587839a050SYann Gautier return -1; 14597839a050SYann Gautier } 14607839a050SYann Gautier 14617839a050SYann Gautier if (hsidiv != 0U) { 14620d21680cSYann Gautier return stm32mp1_set_hsidiv(hsidiv); 14637839a050SYann Gautier } 14647839a050SYann Gautier 14657839a050SYann Gautier return 0; 14667839a050SYann Gautier } 14677839a050SYann Gautier 14680d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, 14690d21680cSYann Gautier unsigned int clksrc, 14700d21680cSYann Gautier uint32_t *pllcfg, int plloff) 14717839a050SYann Gautier { 14720d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 14730d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14740d21680cSYann Gautier uintptr_t pllxcr = rcc_base + pll->pllxcr; 14750d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 14760d21680cSYann Gautier uintptr_t clksrc_address = rcc_base + (clksrc >> 4); 14770d21680cSYann Gautier unsigned long refclk; 14780d21680cSYann Gautier uint32_t ifrge = 0U; 1479be858cffSAndre Przywara uint32_t src, value, fracv = 0; 1480be858cffSAndre Przywara void *fdt; 14817839a050SYann Gautier 14820d21680cSYann Gautier /* Check PLL output */ 14830d21680cSYann Gautier if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { 14840d21680cSYann Gautier return false; 14857839a050SYann Gautier } 14867839a050SYann Gautier 14870d21680cSYann Gautier /* Check current clksrc */ 14880d21680cSYann Gautier src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; 14890d21680cSYann Gautier if (src != (clksrc & RCC_SELR_SRC_MASK)) { 14900d21680cSYann Gautier return false; 14910d21680cSYann Gautier } 14920d21680cSYann Gautier 14930d21680cSYann Gautier /* Check Div */ 14940d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; 14950d21680cSYann Gautier 14960d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 14970d21680cSYann Gautier (pllcfg[PLLCFG_M] + 1U); 14980d21680cSYann Gautier 14990d21680cSYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 15000d21680cSYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 15010d21680cSYann Gautier return false; 15020d21680cSYann Gautier } 15030d21680cSYann Gautier 15040d21680cSYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 15050d21680cSYann Gautier ifrge = 1U; 15060d21680cSYann Gautier } 15070d21680cSYann Gautier 15080d21680cSYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 15090d21680cSYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 15100d21680cSYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 15110d21680cSYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 15120d21680cSYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 15130d21680cSYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 15140d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { 15150d21680cSYann Gautier return false; 15160d21680cSYann Gautier } 15170d21680cSYann Gautier 15180d21680cSYann Gautier /* Fractional configuration */ 1519be858cffSAndre Przywara if (fdt_get_address(&fdt) == 1) { 1520be858cffSAndre Przywara fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1521be858cffSAndre Przywara } 15220d21680cSYann Gautier 15230d21680cSYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 15240d21680cSYann Gautier value |= RCC_PLLNFRACR_FRACLE; 15250d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { 15260d21680cSYann Gautier return false; 15270d21680cSYann Gautier } 15280d21680cSYann Gautier 15290d21680cSYann Gautier /* Output config */ 15300d21680cSYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15310d21680cSYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15320d21680cSYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15330d21680cSYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15340d21680cSYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15350d21680cSYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15360d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { 15370d21680cSYann Gautier return false; 15380d21680cSYann Gautier } 15390d21680cSYann Gautier 15400d21680cSYann Gautier return true; 15410d21680cSYann Gautier } 15420d21680cSYann Gautier 15430d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) 15447839a050SYann Gautier { 15450d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15460d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 15470d21680cSYann Gautier 1548dd98aec8SYann Gautier /* Preserve RCC_PLLNCR_SSCG_CTRL value */ 1549dd98aec8SYann Gautier mmio_clrsetbits_32(pllxcr, 1550dd98aec8SYann Gautier RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 1551dd98aec8SYann Gautier RCC_PLLNCR_DIVREN, 1552dd98aec8SYann Gautier RCC_PLLNCR_PLLON); 15530d21680cSYann Gautier } 15540d21680cSYann Gautier 15550d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) 15560d21680cSYann Gautier { 15570d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15580d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1559dfdb057aSYann Gautier uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); 15607839a050SYann Gautier 15617839a050SYann Gautier /* Wait PLL lock */ 15627839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { 1563dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15649fa9a0c5SYann Gautier ERROR("PLL%u start failed @ 0x%lx: 0x%x\n", 15657839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15667839a050SYann Gautier return -ETIMEDOUT; 15677839a050SYann Gautier } 15687839a050SYann Gautier } 15697839a050SYann Gautier 15707839a050SYann Gautier /* Start the requested output */ 15717839a050SYann Gautier mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); 15727839a050SYann Gautier 15737839a050SYann Gautier return 0; 15747839a050SYann Gautier } 15757839a050SYann Gautier 15760d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) 15777839a050SYann Gautier { 15780d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15790d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1580dfdb057aSYann Gautier uint64_t timeout; 15817839a050SYann Gautier 15827839a050SYann Gautier /* Stop all output */ 15837839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 15847839a050SYann Gautier RCC_PLLNCR_DIVREN); 15857839a050SYann Gautier 15867839a050SYann Gautier /* Stop PLL */ 15877839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); 15887839a050SYann Gautier 1589dfdb057aSYann Gautier timeout = timeout_init_us(PLLRDY_TIMEOUT); 15907839a050SYann Gautier /* Wait PLL stopped */ 15917839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { 1592dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15939fa9a0c5SYann Gautier ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n", 15947839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15957839a050SYann Gautier return -ETIMEDOUT; 15967839a050SYann Gautier } 15977839a050SYann Gautier } 15987839a050SYann Gautier 15997839a050SYann Gautier return 0; 16007839a050SYann Gautier } 16017839a050SYann Gautier 16020d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, 16037839a050SYann Gautier uint32_t *pllcfg) 16047839a050SYann Gautier { 16050d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16060d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16077839a050SYann Gautier uint32_t value; 16087839a050SYann Gautier 16097839a050SYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 16107839a050SYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 16117839a050SYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 16127839a050SYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 16137839a050SYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 16147839a050SYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 16150d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr2, value); 16167839a050SYann Gautier } 16177839a050SYann Gautier 16180d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, 16197839a050SYann Gautier uint32_t *pllcfg, uint32_t fracv) 16207839a050SYann Gautier { 16210d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16220d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16230d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 16247839a050SYann Gautier unsigned long refclk; 16257839a050SYann Gautier uint32_t ifrge = 0; 16267839a050SYann Gautier uint32_t src, value; 16277839a050SYann Gautier 16280d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & 16297839a050SYann Gautier RCC_SELR_REFCLK_SRC_MASK; 16307839a050SYann Gautier 16310d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 16327839a050SYann Gautier (pllcfg[PLLCFG_M] + 1U); 16337839a050SYann Gautier 16347839a050SYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 16357839a050SYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 16367839a050SYann Gautier return -EINVAL; 16377839a050SYann Gautier } 16387839a050SYann Gautier 16397839a050SYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 16407839a050SYann Gautier ifrge = 1U; 16417839a050SYann Gautier } 16427839a050SYann Gautier 16437839a050SYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 16447839a050SYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 16457839a050SYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 16467839a050SYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 16477839a050SYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 16487839a050SYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 16490d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr1, value); 16507839a050SYann Gautier 16517839a050SYann Gautier /* Fractional configuration */ 16527839a050SYann Gautier value = 0; 16530d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16547839a050SYann Gautier 16557839a050SYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 16560d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16577839a050SYann Gautier 16587839a050SYann Gautier value |= RCC_PLLNFRACR_FRACLE; 16590d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16607839a050SYann Gautier 16610d21680cSYann Gautier stm32mp1_pll_config_output(pll_id, pllcfg); 16627839a050SYann Gautier 16637839a050SYann Gautier return 0; 16647839a050SYann Gautier } 16657839a050SYann Gautier 16660d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) 16677839a050SYann Gautier { 16680d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16697839a050SYann Gautier uint32_t pllxcsg = 0; 16707839a050SYann Gautier 16717839a050SYann Gautier pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & 16727839a050SYann Gautier RCC_PLLNCSGR_MOD_PER_MASK; 16737839a050SYann Gautier 16747839a050SYann Gautier pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & 16757839a050SYann Gautier RCC_PLLNCSGR_INC_STEP_MASK; 16767839a050SYann Gautier 16777839a050SYann Gautier pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & 16787839a050SYann Gautier RCC_PLLNCSGR_SSCG_MODE_MASK; 16797839a050SYann Gautier 16800d21680cSYann Gautier mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); 1681dd98aec8SYann Gautier 1682dd98aec8SYann Gautier mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, 1683dd98aec8SYann Gautier RCC_PLLNCR_SSCG_CTRL); 16847839a050SYann Gautier } 16857839a050SYann Gautier 16860d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc) 16877839a050SYann Gautier { 16880d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 1689dfdb057aSYann Gautier uint64_t timeout; 16907839a050SYann Gautier 16910d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, 16927839a050SYann Gautier clksrc & RCC_SELR_SRC_MASK); 16937839a050SYann Gautier 1694dfdb057aSYann Gautier timeout = timeout_init_us(CLKSRC_TIMEOUT); 16950d21680cSYann Gautier while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { 1696dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 16970d21680cSYann Gautier ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, 16980d21680cSYann Gautier clksrc_address, mmio_read_32(clksrc_address)); 16997839a050SYann Gautier return -ETIMEDOUT; 17007839a050SYann Gautier } 17017839a050SYann Gautier } 17027839a050SYann Gautier 17037839a050SYann Gautier return 0; 17047839a050SYann Gautier } 17057839a050SYann Gautier 17060d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) 17077839a050SYann Gautier { 1708dfdb057aSYann Gautier uint64_t timeout; 17097839a050SYann Gautier 17107839a050SYann Gautier mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, 17117839a050SYann Gautier clkdiv & RCC_DIVR_DIV_MASK); 17127839a050SYann Gautier 1713dfdb057aSYann Gautier timeout = timeout_init_us(CLKDIV_TIMEOUT); 17147839a050SYann Gautier while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { 1715dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17160d21680cSYann Gautier ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", 17177839a050SYann Gautier clkdiv, address, mmio_read_32(address)); 17187839a050SYann Gautier return -ETIMEDOUT; 17197839a050SYann Gautier } 17207839a050SYann Gautier } 17217839a050SYann Gautier 17227839a050SYann Gautier return 0; 17237839a050SYann Gautier } 17247839a050SYann Gautier 17250d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) 17267839a050SYann Gautier { 17270d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 17287839a050SYann Gautier 17297839a050SYann Gautier /* 17307839a050SYann Gautier * Binding clksrc : 17317839a050SYann Gautier * bit15-4 offset 17327839a050SYann Gautier * bit3: disable 17337839a050SYann Gautier * bit2-0: MCOSEL[2:0] 17347839a050SYann Gautier */ 17357839a050SYann Gautier if ((clksrc & 0x8U) != 0U) { 17360d21680cSYann Gautier mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17377839a050SYann Gautier } else { 17380d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17397839a050SYann Gautier RCC_MCOCFG_MCOSRC_MASK, 17407839a050SYann Gautier clksrc & RCC_MCOCFG_MCOSRC_MASK); 17410d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17427839a050SYann Gautier RCC_MCOCFG_MCODIV_MASK, 17437839a050SYann Gautier clkdiv << RCC_MCOCFG_MCODIV_SHIFT); 17440d21680cSYann Gautier mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17457839a050SYann Gautier } 17467839a050SYann Gautier } 17477839a050SYann Gautier 17480d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) 17497839a050SYann Gautier { 17500d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; 17517839a050SYann Gautier 17527839a050SYann Gautier if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || 17537839a050SYann Gautier (clksrc != (uint32_t)CLK_RTC_DISABLED)) { 17547839a050SYann Gautier mmio_clrsetbits_32(address, 17557839a050SYann Gautier RCC_BDCR_RTCSRC_MASK, 175615509093SYann Gautier (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); 17577839a050SYann Gautier 17587839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_RTCCKEN); 17597839a050SYann Gautier } 17607839a050SYann Gautier 17617839a050SYann Gautier if (lse_css) { 17627839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_LSECSSON); 17637839a050SYann Gautier } 17647839a050SYann Gautier } 17657839a050SYann Gautier 17660d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs) 17677839a050SYann Gautier { 17680d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); 17697839a050SYann Gautier uint32_t value = pkcs & 0xFU; 17707839a050SYann Gautier uint32_t mask = 0xFU; 17717839a050SYann Gautier 17727839a050SYann Gautier if ((pkcs & BIT(31)) != 0U) { 17737839a050SYann Gautier mask <<= 4; 17747839a050SYann Gautier value <<= 4; 17757839a050SYann Gautier } 17767839a050SYann Gautier 17777839a050SYann Gautier mmio_clrsetbits_32(address, mask, value); 17787839a050SYann Gautier } 17797839a050SYann Gautier 1780964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, 1781964e5ff1SNicolas Le Bayon uint32_t *fracv, uint32_t *csg, 1782964e5ff1SNicolas Le Bayon bool *csg_set) 1783964e5ff1SNicolas Le Bayon { 1784964e5ff1SNicolas Le Bayon void *fdt; 1785964e5ff1SNicolas Le Bayon int ret; 1786964e5ff1SNicolas Le Bayon 1787964e5ff1SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 1788964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1789964e5ff1SNicolas Le Bayon } 1790964e5ff1SNicolas Le Bayon 1791964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB, 1792964e5ff1SNicolas Le Bayon pllcfg); 1793964e5ff1SNicolas Le Bayon if (ret < 0) { 1794964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1795964e5ff1SNicolas Le Bayon } 1796964e5ff1SNicolas Le Bayon 1797964e5ff1SNicolas Le Bayon *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1798964e5ff1SNicolas Le Bayon 1799964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB, 1800964e5ff1SNicolas Le Bayon csg); 1801964e5ff1SNicolas Le Bayon 1802964e5ff1SNicolas Le Bayon *csg_set = (ret == 0); 1803964e5ff1SNicolas Le Bayon 1804964e5ff1SNicolas Le Bayon if (ret == -FDT_ERR_NOTFOUND) { 1805964e5ff1SNicolas Le Bayon ret = 0; 1806964e5ff1SNicolas Le Bayon } 1807964e5ff1SNicolas Le Bayon 1808964e5ff1SNicolas Le Bayon return ret; 1809964e5ff1SNicolas Le Bayon } 1810964e5ff1SNicolas Le Bayon 18117839a050SYann Gautier int stm32mp1_clk_init(void) 18127839a050SYann Gautier { 18130d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 1814964e5ff1SNicolas Le Bayon uint32_t pllfracv[_PLL_NB]; 1815964e5ff1SNicolas Le Bayon uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; 18167839a050SYann Gautier unsigned int clksrc[CLKSRC_NB]; 18177839a050SYann Gautier unsigned int clkdiv[CLKDIV_NB]; 18187839a050SYann Gautier unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; 18197839a050SYann Gautier int plloff[_PLL_NB]; 18207839a050SYann Gautier int ret, len; 18217839a050SYann Gautier enum stm32mp1_pll_id i; 1822964e5ff1SNicolas Le Bayon bool pllcsg_set[_PLL_NB]; 1823964e5ff1SNicolas Le Bayon bool pllcfg_valid[_PLL_NB]; 18247839a050SYann Gautier bool lse_css = false; 18250d21680cSYann Gautier bool pll3_preserve = false; 18260d21680cSYann Gautier bool pll4_preserve = false; 18270d21680cSYann Gautier bool pll4_bootrom = false; 18283e6fab43SYann Gautier const fdt32_t *pkcs_cell; 182952a616b4SAndre Przywara void *fdt; 1830bf1af154SPatrick Delaunay int stgen_p = stm32mp1_clk_get_parent(STGEN_K); 1831bf1af154SPatrick Delaunay int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K); 183252a616b4SAndre Przywara 183352a616b4SAndre Przywara if (fdt_get_address(&fdt) == 0) { 18348f97c4faSYann Gautier return -FDT_ERR_NOTFOUND; 183552a616b4SAndre Przywara } 18367839a050SYann Gautier 183752a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, 183852a616b4SAndre Przywara clksrc); 18397839a050SYann Gautier if (ret < 0) { 18407839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18417839a050SYann Gautier } 18427839a050SYann Gautier 184352a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, 184452a616b4SAndre Przywara clkdiv); 18457839a050SYann Gautier if (ret < 0) { 18467839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18477839a050SYann Gautier } 18487839a050SYann Gautier 18497839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 18507839a050SYann Gautier char name[12]; 18517839a050SYann Gautier 18529fa9a0c5SYann Gautier snprintf(name, sizeof(name), "st,pll@%u", i); 18537839a050SYann Gautier plloff[i] = fdt_rcc_subnode_offset(name); 18547839a050SYann Gautier 1855964e5ff1SNicolas Le Bayon pllcfg_valid[i] = fdt_check_node(plloff[i]); 1856964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 18577839a050SYann Gautier continue; 18587839a050SYann Gautier } 18597839a050SYann Gautier 1860964e5ff1SNicolas Le Bayon ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], 1861964e5ff1SNicolas Le Bayon &pllfracv[i], pllcsg[i], 1862964e5ff1SNicolas Le Bayon &pllcsg_set[i]); 1863964e5ff1SNicolas Le Bayon if (ret != 0) { 1864964e5ff1SNicolas Le Bayon return ret; 18657839a050SYann Gautier } 18667839a050SYann Gautier } 18677839a050SYann Gautier 18680d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); 18690d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); 18707839a050SYann Gautier 18717839a050SYann Gautier /* 18727839a050SYann Gautier * Switch ON oscillator found in device-tree. 18737839a050SYann Gautier * Note: HSI already ON after BootROM stage. 18747839a050SYann Gautier */ 18750d21680cSYann Gautier if (stm32mp1_osc[_LSI] != 0U) { 18760d21680cSYann Gautier stm32mp1_lsi_set(true); 18777839a050SYann Gautier } 18780d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 1879b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_LSE]; 18800d21680cSYann Gautier bool bypass, digbyp; 18817839a050SYann Gautier uint32_t lsedrv; 18827839a050SYann Gautier 1883b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1884b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1885b208e3daSGabriel Fernandez lse_css = fdt_clk_read_bool(name, "st,css"); 1886b208e3daSGabriel Fernandez lsedrv = fdt_clk_read_uint32_default(name, "st,drive", 18877839a050SYann Gautier LSEDRV_MEDIUM_HIGH); 18880d21680cSYann Gautier stm32mp1_lse_enable(bypass, digbyp, lsedrv); 18897839a050SYann Gautier } 18900d21680cSYann Gautier if (stm32mp1_osc[_HSE] != 0U) { 1891b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_HSE]; 18920d21680cSYann Gautier bool bypass, digbyp, css; 18937839a050SYann Gautier 1894b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1895b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1896b208e3daSGabriel Fernandez css = fdt_clk_read_bool(name, "st,css"); 18970d21680cSYann Gautier stm32mp1_hse_enable(bypass, digbyp, css); 18987839a050SYann Gautier } 18997839a050SYann Gautier /* 19007839a050SYann Gautier * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) 19017839a050SYann Gautier * => switch on CSI even if node is not present in device tree 19027839a050SYann Gautier */ 19030d21680cSYann Gautier stm32mp1_csi_set(true); 19047839a050SYann Gautier 19057839a050SYann Gautier /* Come back to HSI */ 19060d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_MPU_HSI); 19077839a050SYann Gautier if (ret != 0) { 19087839a050SYann Gautier return ret; 19097839a050SYann Gautier } 19100d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_AXI_HSI); 19117839a050SYann Gautier if (ret != 0) { 19127839a050SYann Gautier return ret; 19137839a050SYann Gautier } 1914b053a22eSYann Gautier ret = stm32mp1_set_clksrc(CLK_MCU_HSI); 1915b053a22eSYann Gautier if (ret != 0) { 1916b053a22eSYann Gautier return ret; 1917b053a22eSYann Gautier } 19187839a050SYann Gautier 19190d21680cSYann Gautier if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & 19200d21680cSYann Gautier RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { 1921175758b2SYann Gautier if (pllcfg_valid[_PLL3]) { 1922175758b2SYann Gautier pll3_preserve = 1923175758b2SYann Gautier stm32mp1_check_pll_conf(_PLL3, 19240d21680cSYann Gautier clksrc[CLKSRC_PLL3], 19250d21680cSYann Gautier pllcfg[_PLL3], 19260d21680cSYann Gautier plloff[_PLL3]); 1927175758b2SYann Gautier } 1928175758b2SYann Gautier 1929175758b2SYann Gautier if (pllcfg_valid[_PLL4]) { 1930175758b2SYann Gautier pll4_preserve = 1931175758b2SYann Gautier stm32mp1_check_pll_conf(_PLL4, 19320d21680cSYann Gautier clksrc[CLKSRC_PLL4], 19330d21680cSYann Gautier pllcfg[_PLL4], 19340d21680cSYann Gautier plloff[_PLL4]); 19350d21680cSYann Gautier } 1936175758b2SYann Gautier } 1937bf1af154SPatrick Delaunay /* Don't initialize PLL4, when used by BOOTROM */ 1938bf1af154SPatrick Delaunay if ((stm32mp_get_boot_itf_selected() == 1939bf1af154SPatrick Delaunay BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) && 1940bf1af154SPatrick Delaunay ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { 1941bf1af154SPatrick Delaunay pll4_bootrom = true; 1942bf1af154SPatrick Delaunay pll4_preserve = true; 1943bf1af154SPatrick Delaunay } 19440d21680cSYann Gautier 19457839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19460d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 19470d21680cSYann Gautier ((i == _PLL4) && pll4_preserve)) { 19487839a050SYann Gautier continue; 19490d21680cSYann Gautier } 19500d21680cSYann Gautier 19510d21680cSYann Gautier ret = stm32mp1_pll_stop(i); 19527839a050SYann Gautier if (ret != 0) { 19537839a050SYann Gautier return ret; 19547839a050SYann Gautier } 19557839a050SYann Gautier } 19567839a050SYann Gautier 19577839a050SYann Gautier /* Configure HSIDIV */ 19580d21680cSYann Gautier if (stm32mp1_osc[_HSI] != 0U) { 19590d21680cSYann Gautier ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); 19607839a050SYann Gautier if (ret != 0) { 19617839a050SYann Gautier return ret; 19627839a050SYann Gautier } 1963591d80c8SLionel Debieve 1964591d80c8SLionel Debieve stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K)); 19657839a050SYann Gautier } 19667839a050SYann Gautier 19677839a050SYann Gautier /* Select DIV */ 19687839a050SYann Gautier /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ 19690d21680cSYann Gautier mmio_write_32(rcc_base + RCC_MPCKDIVR, 19707839a050SYann Gautier clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 19710d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); 19727839a050SYann Gautier if (ret != 0) { 19737839a050SYann Gautier return ret; 19747839a050SYann Gautier } 19750d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); 19767839a050SYann Gautier if (ret != 0) { 19777839a050SYann Gautier return ret; 19787839a050SYann Gautier } 19790d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); 19807839a050SYann Gautier if (ret != 0) { 19817839a050SYann Gautier return ret; 19827839a050SYann Gautier } 1983b053a22eSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); 1984b053a22eSYann Gautier if (ret != 0) { 1985b053a22eSYann Gautier return ret; 1986b053a22eSYann Gautier } 19870d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); 19887839a050SYann Gautier if (ret != 0) { 19897839a050SYann Gautier return ret; 19907839a050SYann Gautier } 19910d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); 19927839a050SYann Gautier if (ret != 0) { 19937839a050SYann Gautier return ret; 19947839a050SYann Gautier } 19950d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); 19967839a050SYann Gautier if (ret != 0) { 19977839a050SYann Gautier return ret; 19987839a050SYann Gautier } 19997839a050SYann Gautier 20007839a050SYann Gautier /* No ready bit for RTC */ 20010d21680cSYann Gautier mmio_write_32(rcc_base + RCC_RTCDIVR, 20027839a050SYann Gautier clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); 20037839a050SYann Gautier 20047839a050SYann Gautier /* Configure PLLs source */ 20050d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); 20067839a050SYann Gautier if (ret != 0) { 20077839a050SYann Gautier return ret; 20087839a050SYann Gautier } 20097839a050SYann Gautier 20100d21680cSYann Gautier if (!pll3_preserve) { 20110d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); 20127839a050SYann Gautier if (ret != 0) { 20137839a050SYann Gautier return ret; 20147839a050SYann Gautier } 20150d21680cSYann Gautier } 20160d21680cSYann Gautier 20170d21680cSYann Gautier if (!pll4_preserve) { 20180d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); 20190d21680cSYann Gautier if (ret != 0) { 20200d21680cSYann Gautier return ret; 20210d21680cSYann Gautier } 20220d21680cSYann Gautier } 20237839a050SYann Gautier 20247839a050SYann Gautier /* Configure and start PLLs */ 20257839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 20260d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 20270d21680cSYann Gautier ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { 20280d21680cSYann Gautier continue; 20290d21680cSYann Gautier } 20300d21680cSYann Gautier 2031964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20327839a050SYann Gautier continue; 20337839a050SYann Gautier } 20347839a050SYann Gautier 20350d21680cSYann Gautier if ((i == _PLL4) && pll4_bootrom) { 20360d21680cSYann Gautier /* Set output divider if not done by the Bootrom */ 20370d21680cSYann Gautier stm32mp1_pll_config_output(i, pllcfg[i]); 20380d21680cSYann Gautier continue; 20390d21680cSYann Gautier } 20400d21680cSYann Gautier 2041964e5ff1SNicolas Le Bayon ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); 20427839a050SYann Gautier if (ret != 0) { 20437839a050SYann Gautier return ret; 20447839a050SYann Gautier } 2045964e5ff1SNicolas Le Bayon 2046964e5ff1SNicolas Le Bayon if (pllcsg_set[i]) { 2047964e5ff1SNicolas Le Bayon stm32mp1_pll_csg(i, pllcsg[i]); 20487839a050SYann Gautier } 20497839a050SYann Gautier 20500d21680cSYann Gautier stm32mp1_pll_start(i); 20517839a050SYann Gautier } 2052*1b491eeaSElyes Haouas /* Wait and start PLLs output when ready */ 20537839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 2054964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20557839a050SYann Gautier continue; 20567839a050SYann Gautier } 20577839a050SYann Gautier 20580d21680cSYann Gautier ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); 20597839a050SYann Gautier if (ret != 0) { 20607839a050SYann Gautier return ret; 20617839a050SYann Gautier } 20627839a050SYann Gautier } 20637839a050SYann Gautier /* Wait LSE ready before to use it */ 20640d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 20650d21680cSYann Gautier stm32mp1_lse_wait(); 20667839a050SYann Gautier } 20677839a050SYann Gautier 20687839a050SYann Gautier /* Configure with expected clock source */ 20690d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); 20707839a050SYann Gautier if (ret != 0) { 20717839a050SYann Gautier return ret; 20727839a050SYann Gautier } 20730d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); 20747839a050SYann Gautier if (ret != 0) { 20757839a050SYann Gautier return ret; 20767839a050SYann Gautier } 2077b053a22eSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); 2078b053a22eSYann Gautier if (ret != 0) { 2079b053a22eSYann Gautier return ret; 2080b053a22eSYann Gautier } 20810d21680cSYann Gautier stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); 20827839a050SYann Gautier 20837839a050SYann Gautier /* Configure PKCK */ 20847839a050SYann Gautier pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); 20857839a050SYann Gautier if (pkcs_cell != NULL) { 20867839a050SYann Gautier bool ckper_disabled = false; 20877839a050SYann Gautier uint32_t j; 2088bf1af154SPatrick Delaunay uint32_t usbreg_bootrom = 0U; 2089bf1af154SPatrick Delaunay 2090bf1af154SPatrick Delaunay if (pll4_bootrom) { 2091bf1af154SPatrick Delaunay usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); 2092bf1af154SPatrick Delaunay } 20937839a050SYann Gautier 20947839a050SYann Gautier for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { 20953e6fab43SYann Gautier uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); 20967839a050SYann Gautier 20977839a050SYann Gautier if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { 20987839a050SYann Gautier ckper_disabled = true; 20997839a050SYann Gautier continue; 21007839a050SYann Gautier } 21010d21680cSYann Gautier stm32mp1_pkcs_config(pkcs); 21027839a050SYann Gautier } 21037839a050SYann Gautier 21047839a050SYann Gautier /* 21057839a050SYann Gautier * CKPER is source for some peripheral clocks 21067839a050SYann Gautier * (FMC-NAND / QPSI-NOR) and switching source is allowed 21077839a050SYann Gautier * only if previous clock is still ON 21087839a050SYann Gautier * => deactivated CKPER only after switching clock 21097839a050SYann Gautier */ 21107839a050SYann Gautier if (ckper_disabled) { 21110d21680cSYann Gautier stm32mp1_pkcs_config(CLK_CKPER_DISABLED); 21127839a050SYann Gautier } 2113bf1af154SPatrick Delaunay 2114bf1af154SPatrick Delaunay if (pll4_bootrom) { 2115bf1af154SPatrick Delaunay uint32_t usbreg_value, usbreg_mask; 2116bf1af154SPatrick Delaunay const struct stm32mp1_clk_sel *sel; 2117bf1af154SPatrick Delaunay 2118bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBPHY_SEL); 2119bf1af154SPatrick Delaunay usbreg_mask = (uint32_t)sel->msk << sel->src; 2120bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBO_SEL); 2121bf1af154SPatrick Delaunay usbreg_mask |= (uint32_t)sel->msk << sel->src; 2122bf1af154SPatrick Delaunay 2123bf1af154SPatrick Delaunay usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & 2124bf1af154SPatrick Delaunay usbreg_mask; 2125bf1af154SPatrick Delaunay usbreg_bootrom &= usbreg_mask; 2126bf1af154SPatrick Delaunay if (usbreg_bootrom != usbreg_value) { 2127bf1af154SPatrick Delaunay VERBOSE("forbidden new USB clk path\n"); 2128bf1af154SPatrick Delaunay VERBOSE("vs bootrom on USB boot\n"); 2129bf1af154SPatrick Delaunay return -FDT_ERR_BADVALUE; 2130bf1af154SPatrick Delaunay } 2131bf1af154SPatrick Delaunay } 21327839a050SYann Gautier } 21337839a050SYann Gautier 21347839a050SYann Gautier /* Switch OFF HSI if not found in device-tree */ 21350d21680cSYann Gautier if (stm32mp1_osc[_HSI] == 0U) { 21360d21680cSYann Gautier stm32mp1_hsi_set(false); 21377839a050SYann Gautier } 2138591d80c8SLionel Debieve 2139591d80c8SLionel Debieve stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K)); 21407839a050SYann Gautier 21417839a050SYann Gautier /* Software Self-Refresh mode (SSR) during DDR initilialization */ 21420d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, 21437839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_MASK, 21447839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SSR << 21457839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SHIFT); 21467839a050SYann Gautier 21477839a050SYann Gautier return 0; 21487839a050SYann Gautier } 21497839a050SYann Gautier 21507839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name, 21517839a050SYann Gautier enum stm32mp_osc_id index) 21527839a050SYann Gautier { 21537839a050SYann Gautier uint32_t frequency; 21547839a050SYann Gautier 21550d21680cSYann Gautier if (fdt_osc_read_freq(name, &frequency) == 0) { 21560d21680cSYann Gautier stm32mp1_osc[index] = frequency; 21577839a050SYann Gautier } 21587839a050SYann Gautier } 21597839a050SYann Gautier 21607839a050SYann Gautier static void stm32mp1_osc_init(void) 21617839a050SYann Gautier { 21627839a050SYann Gautier enum stm32mp_osc_id i; 21637839a050SYann Gautier 21647839a050SYann Gautier for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { 21650d21680cSYann Gautier stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); 21667839a050SYann Gautier } 21677839a050SYann Gautier } 21687839a050SYann Gautier 216937e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES 217037e8295aSEtienne Carriere /* 217137e8295aSEtienne Carriere * Get the parent ID of the target parent clock, for tagging as secure 217237e8295aSEtienne Carriere * shared clock dependencies. 217337e8295aSEtienne Carriere */ 217437e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id) 217537e8295aSEtienne Carriere { 217637e8295aSEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 217737e8295aSEtienne Carriere enum stm32mp1_pll_id pll_id; 217837e8295aSEtienne Carriere uint32_t p_sel; 217937e8295aSEtienne Carriere uintptr_t rcc_base = stm32mp_rcc_base(); 218037e8295aSEtienne Carriere 218137e8295aSEtienne Carriere switch (parent_id) { 218237e8295aSEtienne Carriere case _ACLK: 218337e8295aSEtienne Carriere case _PCLK4: 218437e8295aSEtienne Carriere case _PCLK5: 218537e8295aSEtienne Carriere s = _AXIS_SEL; 218637e8295aSEtienne Carriere break; 218737e8295aSEtienne Carriere case _PLL1_P: 218837e8295aSEtienne Carriere case _PLL1_Q: 218937e8295aSEtienne Carriere case _PLL1_R: 219037e8295aSEtienne Carriere pll_id = _PLL1; 219137e8295aSEtienne Carriere break; 219237e8295aSEtienne Carriere case _PLL2_P: 219337e8295aSEtienne Carriere case _PLL2_Q: 219437e8295aSEtienne Carriere case _PLL2_R: 219537e8295aSEtienne Carriere pll_id = _PLL2; 219637e8295aSEtienne Carriere break; 219737e8295aSEtienne Carriere case _PLL3_P: 219837e8295aSEtienne Carriere case _PLL3_Q: 219937e8295aSEtienne Carriere case _PLL3_R: 220037e8295aSEtienne Carriere pll_id = _PLL3; 220137e8295aSEtienne Carriere break; 220237e8295aSEtienne Carriere case _PLL4_P: 220337e8295aSEtienne Carriere case _PLL4_Q: 220437e8295aSEtienne Carriere case _PLL4_R: 220537e8295aSEtienne Carriere pll_id = _PLL4; 220637e8295aSEtienne Carriere break; 220737e8295aSEtienne Carriere case _PCLK1: 220837e8295aSEtienne Carriere case _PCLK2: 220937e8295aSEtienne Carriere case _HCLK2: 221037e8295aSEtienne Carriere case _HCLK6: 221137e8295aSEtienne Carriere case _CK_PER: 221237e8295aSEtienne Carriere case _CK_MPU: 221337e8295aSEtienne Carriere case _CK_MCU: 221437e8295aSEtienne Carriere case _USB_PHY_48: 221537e8295aSEtienne Carriere /* We do not expect to access these */ 221637e8295aSEtienne Carriere panic(); 221737e8295aSEtienne Carriere break; 221837e8295aSEtienne Carriere default: 221937e8295aSEtienne Carriere /* Other parents have no parent */ 222037e8295aSEtienne Carriere return -1; 222137e8295aSEtienne Carriere } 222237e8295aSEtienne Carriere 222337e8295aSEtienne Carriere if (s != _UNKNOWN_SEL) { 222437e8295aSEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 222537e8295aSEtienne Carriere 222637e8295aSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & 222737e8295aSEtienne Carriere sel->msk; 222837e8295aSEtienne Carriere 222937e8295aSEtienne Carriere if (p_sel < sel->nb_parent) { 223037e8295aSEtienne Carriere return (int)sel->parent[p_sel]; 223137e8295aSEtienne Carriere } 223237e8295aSEtienne Carriere } else { 223337e8295aSEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 223437e8295aSEtienne Carriere 223537e8295aSEtienne Carriere p_sel = mmio_read_32(rcc_base + pll->rckxselr) & 223637e8295aSEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 223737e8295aSEtienne Carriere 223837e8295aSEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { 223937e8295aSEtienne Carriere return (int)pll->refclk[p_sel]; 224037e8295aSEtienne Carriere } 224137e8295aSEtienne Carriere } 224237e8295aSEtienne Carriere 224337e8295aSEtienne Carriere VERBOSE("No parent selected for %s\n", 224437e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 224537e8295aSEtienne Carriere 224637e8295aSEtienne Carriere return -1; 224737e8295aSEtienne Carriere } 224837e8295aSEtienne Carriere 224937e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id) 225037e8295aSEtienne Carriere { 225137e8295aSEtienne Carriere int grandparent_id; 225237e8295aSEtienne Carriere 225337e8295aSEtienne Carriere switch (parent_id) { 225437e8295aSEtienne Carriere case _PLL3_P: 225537e8295aSEtienne Carriere case _PLL3_Q: 225637e8295aSEtienne Carriere case _PLL3_R: 225737e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 225837e8295aSEtienne Carriere break; 225937e8295aSEtienne Carriere 226037e8295aSEtienne Carriere /* These clocks are always secure when RCC is secure */ 226137e8295aSEtienne Carriere case _ACLK: 226237e8295aSEtienne Carriere case _HCLK2: 226337e8295aSEtienne Carriere case _HCLK6: 226437e8295aSEtienne Carriere case _PCLK4: 226537e8295aSEtienne Carriere case _PCLK5: 226637e8295aSEtienne Carriere case _PLL1_P: 226737e8295aSEtienne Carriere case _PLL1_Q: 226837e8295aSEtienne Carriere case _PLL1_R: 226937e8295aSEtienne Carriere case _PLL2_P: 227037e8295aSEtienne Carriere case _PLL2_Q: 227137e8295aSEtienne Carriere case _PLL2_R: 227237e8295aSEtienne Carriere case _HSI: 227337e8295aSEtienne Carriere case _HSI_KER: 227437e8295aSEtienne Carriere case _LSI: 227537e8295aSEtienne Carriere case _CSI: 227637e8295aSEtienne Carriere case _CSI_KER: 227737e8295aSEtienne Carriere case _HSE: 227837e8295aSEtienne Carriere case _HSE_KER: 227937e8295aSEtienne Carriere case _HSE_KER_DIV2: 2280cbd2e8a6SGabriel Fernandez case _HSE_RTC: 228137e8295aSEtienne Carriere case _LSE: 228237e8295aSEtienne Carriere break; 228337e8295aSEtienne Carriere 228437e8295aSEtienne Carriere default: 228537e8295aSEtienne Carriere VERBOSE("Cannot secure parent clock %s\n", 228637e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 228737e8295aSEtienne Carriere panic(); 228837e8295aSEtienne Carriere } 228937e8295aSEtienne Carriere 229037e8295aSEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 229137e8295aSEtienne Carriere if (grandparent_id >= 0) { 229237e8295aSEtienne Carriere secure_parent_clocks(grandparent_id); 229337e8295aSEtienne Carriere } 229437e8295aSEtienne Carriere } 229537e8295aSEtienne Carriere 229637e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id) 229737e8295aSEtienne Carriere { 229837e8295aSEtienne Carriere int parent_id; 229937e8295aSEtienne Carriere 230037e8295aSEtienne Carriere if (!stm32mp1_rcc_is_secure()) { 230137e8295aSEtienne Carriere return; 230237e8295aSEtienne Carriere } 230337e8295aSEtienne Carriere 230437e8295aSEtienne Carriere switch (clock_id) { 230537e8295aSEtienne Carriere case PLL1: 230637e8295aSEtienne Carriere case PLL2: 230737e8295aSEtienne Carriere /* PLL1/PLL2 are always secure: nothing to do */ 230837e8295aSEtienne Carriere break; 230937e8295aSEtienne Carriere case PLL3: 231037e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 231137e8295aSEtienne Carriere break; 231237e8295aSEtienne Carriere case PLL4: 231337e8295aSEtienne Carriere ERROR("PLL4 cannot be secured\n"); 231437e8295aSEtienne Carriere panic(); 231537e8295aSEtienne Carriere break; 231637e8295aSEtienne Carriere default: 231737e8295aSEtienne Carriere /* Others are expected gateable clock */ 231837e8295aSEtienne Carriere parent_id = stm32mp1_clk_get_parent(clock_id); 231937e8295aSEtienne Carriere if (parent_id < 0) { 232037e8295aSEtienne Carriere INFO("No parent found for clock %lu\n", clock_id); 232137e8295aSEtienne Carriere } else { 232237e8295aSEtienne Carriere secure_parent_clocks(parent_id); 232337e8295aSEtienne Carriere } 232437e8295aSEtienne Carriere break; 232537e8295aSEtienne Carriere } 232637e8295aSEtienne Carriere } 232737e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */ 232837e8295aSEtienne Carriere 23296cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void) 23306cb45f89SYann Gautier { 2331033b6c3aSEtienne Carriere unsigned int idx; 2332033b6c3aSEtienne Carriere const unsigned long secure_enable[] = { 2333033b6c3aSEtienne Carriere AXIDCG, 2334033b6c3aSEtienne Carriere BSEC, 2335033b6c3aSEtienne Carriere DDRC1, DDRC1LP, 2336033b6c3aSEtienne Carriere DDRC2, DDRC2LP, 2337033b6c3aSEtienne Carriere DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, 2338033b6c3aSEtienne Carriere DDRPHYC, DDRPHYCLP, 2339373f06beSLionel Debieve RTCAPB, 2340033b6c3aSEtienne Carriere TZC1, TZC2, 2341033b6c3aSEtienne Carriere TZPC, 2342033b6c3aSEtienne Carriere STGEN_K, 2343033b6c3aSEtienne Carriere }; 2344033b6c3aSEtienne Carriere 2345033b6c3aSEtienne Carriere for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { 2346033b6c3aSEtienne Carriere stm32mp_clk_enable(secure_enable[idx]); 2347033b6c3aSEtienne Carriere } 23486cb45f89SYann Gautier } 23496cb45f89SYann Gautier 235033667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = { 235133667d29SYann Gautier .enable = stm32mp_clk_enable, 235233667d29SYann Gautier .disable = stm32mp_clk_disable, 235333667d29SYann Gautier .is_enabled = stm32mp_clk_is_enabled, 235433667d29SYann Gautier .get_rate = stm32mp_clk_get_rate, 235533667d29SYann Gautier .get_parent = stm32mp1_clk_get_parent, 235633667d29SYann Gautier }; 235733667d29SYann Gautier 23587839a050SYann Gautier int stm32mp1_clk_probe(void) 23597839a050SYann Gautier { 2360812daf91SLionel Debieve #if defined(IMAGE_BL32) 2361812daf91SLionel Debieve if (!fdt_get_rcc_secure_state()) { 2362812daf91SLionel Debieve mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U); 2363812daf91SLionel Debieve } 2364812daf91SLionel Debieve #endif 2365812daf91SLionel Debieve 23667839a050SYann Gautier stm32mp1_osc_init(); 23677839a050SYann Gautier 23686cb45f89SYann Gautier sync_earlyboot_clocks_state(); 23696cb45f89SYann Gautier 237033667d29SYann Gautier clk_register(&stm32mp_clk_ops); 237133667d29SYann Gautier 23727839a050SYann Gautier return 0; 23737839a050SYann Gautier } 2374