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> 1809d40e0eSAntonio Nino Diaz #include <drivers/generic_delay_timer.h> 19447b2b13SYann Gautier #include <drivers/st/stm32mp_clkfunc.h> 2009d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_clk.h> 2109d40e0eSAntonio Nino Diaz #include <drivers/st/stm32mp1_rcc.h> 2209d40e0eSAntonio Nino Diaz #include <dt-bindings/clock/stm32mp1-clksrc.h> 2309d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 240d21680cSYann Gautier #include <lib/spinlock.h> 2509d40e0eSAntonio Nino Diaz #include <lib/utils_def.h> 26964e5ff1SNicolas Le Bayon #include <libfdt.h> 2709d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 2809d40e0eSAntonio Nino Diaz 29964e5ff1SNicolas Le Bayon #include <platform_def.h> 30964e5ff1SNicolas Le Bayon 317839a050SYann Gautier #define MAX_HSI_HZ 64000000 320d21680cSYann Gautier #define USB_PHY_48_MHZ 48000000 337839a050SYann Gautier 34dfdb057aSYann Gautier #define TIMEOUT_US_200MS U(200000) 35dfdb057aSYann Gautier #define TIMEOUT_US_1S U(1000000) 367839a050SYann Gautier 37dfdb057aSYann Gautier #define PLLRDY_TIMEOUT TIMEOUT_US_200MS 38dfdb057aSYann Gautier #define CLKSRC_TIMEOUT TIMEOUT_US_200MS 39dfdb057aSYann Gautier #define CLKDIV_TIMEOUT TIMEOUT_US_200MS 40dfdb057aSYann Gautier #define HSIDIV_TIMEOUT TIMEOUT_US_200MS 41dfdb057aSYann Gautier #define OSCRDY_TIMEOUT TIMEOUT_US_1S 427839a050SYann Gautier 43f66358afSYann Gautier const char *stm32mp_osc_node_label[NB_OSC] = { 44f66358afSYann Gautier [_LSI] = "clk-lsi", 45f66358afSYann Gautier [_LSE] = "clk-lse", 46f66358afSYann Gautier [_HSI] = "clk-hsi", 47f66358afSYann Gautier [_HSE] = "clk-hse", 48f66358afSYann Gautier [_CSI] = "clk-csi", 49f66358afSYann Gautier [_I2S_CKIN] = "i2s_ckin", 50f66358afSYann Gautier }; 51f66358afSYann Gautier 527839a050SYann Gautier enum stm32mp1_parent_id { 537839a050SYann Gautier /* Oscillators are defined in enum stm32mp_osc_id */ 547839a050SYann Gautier 557839a050SYann Gautier /* Other parent source */ 567839a050SYann Gautier _HSI_KER = NB_OSC, 577839a050SYann Gautier _HSE_KER, 587839a050SYann Gautier _HSE_KER_DIV2, 59cbd2e8a6SGabriel Fernandez _HSE_RTC, 607839a050SYann Gautier _CSI_KER, 617839a050SYann Gautier _PLL1_P, 627839a050SYann Gautier _PLL1_Q, 637839a050SYann Gautier _PLL1_R, 647839a050SYann Gautier _PLL2_P, 657839a050SYann Gautier _PLL2_Q, 667839a050SYann Gautier _PLL2_R, 677839a050SYann Gautier _PLL3_P, 687839a050SYann Gautier _PLL3_Q, 697839a050SYann Gautier _PLL3_R, 707839a050SYann Gautier _PLL4_P, 717839a050SYann Gautier _PLL4_Q, 727839a050SYann Gautier _PLL4_R, 737839a050SYann Gautier _ACLK, 747839a050SYann Gautier _PCLK1, 757839a050SYann Gautier _PCLK2, 767839a050SYann Gautier _PCLK3, 777839a050SYann Gautier _PCLK4, 787839a050SYann Gautier _PCLK5, 797839a050SYann Gautier _HCLK6, 807839a050SYann Gautier _HCLK2, 817839a050SYann Gautier _CK_PER, 827839a050SYann Gautier _CK_MPU, 83b053a22eSYann Gautier _CK_MCU, 840d21680cSYann Gautier _USB_PHY_48, 857839a050SYann Gautier _PARENT_NB, 867839a050SYann Gautier _UNKNOWN_ID = 0xff, 877839a050SYann Gautier }; 887839a050SYann Gautier 890d21680cSYann Gautier /* Lists only the parent clock we are interested in */ 907839a050SYann Gautier enum stm32mp1_parent_sel { 910d21680cSYann Gautier _I2C12_SEL, 920d21680cSYann Gautier _I2C35_SEL, 930d21680cSYann Gautier _STGEN_SEL, 947839a050SYann Gautier _I2C46_SEL, 950d21680cSYann Gautier _SPI6_SEL, 96d4151d2fSYann Gautier _UART1_SEL, 970d21680cSYann Gautier _RNG1_SEL, 987839a050SYann Gautier _UART6_SEL, 997839a050SYann Gautier _UART24_SEL, 1007839a050SYann Gautier _UART35_SEL, 1017839a050SYann Gautier _UART78_SEL, 1027839a050SYann Gautier _SDMMC12_SEL, 1037839a050SYann Gautier _SDMMC3_SEL, 1047839a050SYann Gautier _QSPI_SEL, 1057839a050SYann Gautier _FMC_SEL, 106d4151d2fSYann Gautier _AXIS_SEL, 107d4151d2fSYann Gautier _MCUS_SEL, 1087839a050SYann Gautier _USBPHY_SEL, 1097839a050SYann Gautier _USBO_SEL, 1108fbcd9e4SEtienne Carriere _MPU_SEL, 111288f5cf2SYann Gautier _CKPER_SEL, 112016af006SEtienne Carriere _RTC_SEL, 1137839a050SYann Gautier _PARENT_SEL_NB, 1147839a050SYann Gautier _UNKNOWN_SEL = 0xff, 1157839a050SYann Gautier }; 1167839a050SYann Gautier 1178fbcd9e4SEtienne Carriere /* State the parent clock ID straight related to a clock */ 1188fbcd9e4SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = { 1198fbcd9e4SEtienne Carriere [_HSE] = CK_HSE, 1208fbcd9e4SEtienne Carriere [_HSI] = CK_HSI, 1218fbcd9e4SEtienne Carriere [_CSI] = CK_CSI, 1228fbcd9e4SEtienne Carriere [_LSE] = CK_LSE, 1238fbcd9e4SEtienne Carriere [_LSI] = CK_LSI, 1248fbcd9e4SEtienne Carriere [_I2S_CKIN] = _UNKNOWN_ID, 1258fbcd9e4SEtienne Carriere [_USB_PHY_48] = _UNKNOWN_ID, 1268fbcd9e4SEtienne Carriere [_HSI_KER] = CK_HSI, 1278fbcd9e4SEtienne Carriere [_HSE_KER] = CK_HSE, 1288fbcd9e4SEtienne Carriere [_HSE_KER_DIV2] = CK_HSE_DIV2, 129cbd2e8a6SGabriel Fernandez [_HSE_RTC] = _UNKNOWN_ID, 1308fbcd9e4SEtienne Carriere [_CSI_KER] = CK_CSI, 1318fbcd9e4SEtienne Carriere [_PLL1_P] = PLL1_P, 1328fbcd9e4SEtienne Carriere [_PLL1_Q] = PLL1_Q, 1338fbcd9e4SEtienne Carriere [_PLL1_R] = PLL1_R, 1348fbcd9e4SEtienne Carriere [_PLL2_P] = PLL2_P, 1358fbcd9e4SEtienne Carriere [_PLL2_Q] = PLL2_Q, 1368fbcd9e4SEtienne Carriere [_PLL2_R] = PLL2_R, 1378fbcd9e4SEtienne Carriere [_PLL3_P] = PLL3_P, 1388fbcd9e4SEtienne Carriere [_PLL3_Q] = PLL3_Q, 1398fbcd9e4SEtienne Carriere [_PLL3_R] = PLL3_R, 1408fbcd9e4SEtienne Carriere [_PLL4_P] = PLL4_P, 1418fbcd9e4SEtienne Carriere [_PLL4_Q] = PLL4_Q, 1428fbcd9e4SEtienne Carriere [_PLL4_R] = PLL4_R, 1438fbcd9e4SEtienne Carriere [_ACLK] = CK_AXI, 1448fbcd9e4SEtienne Carriere [_PCLK1] = CK_AXI, 1458fbcd9e4SEtienne Carriere [_PCLK2] = CK_AXI, 1468fbcd9e4SEtienne Carriere [_PCLK3] = CK_AXI, 1478fbcd9e4SEtienne Carriere [_PCLK4] = CK_AXI, 1488fbcd9e4SEtienne Carriere [_PCLK5] = CK_AXI, 1498fbcd9e4SEtienne Carriere [_CK_PER] = CK_PER, 1508fbcd9e4SEtienne Carriere [_CK_MPU] = CK_MPU, 1518fbcd9e4SEtienne Carriere [_CK_MCU] = CK_MCU, 1528fbcd9e4SEtienne Carriere }; 1538fbcd9e4SEtienne Carriere 1548fbcd9e4SEtienne Carriere static unsigned int clock_id2parent_id(unsigned long id) 1558fbcd9e4SEtienne Carriere { 1568fbcd9e4SEtienne Carriere unsigned int n; 1578fbcd9e4SEtienne Carriere 1588fbcd9e4SEtienne Carriere for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) { 1598fbcd9e4SEtienne Carriere if (parent_id_clock_id[n] == id) { 1608fbcd9e4SEtienne Carriere return n; 1618fbcd9e4SEtienne Carriere } 1628fbcd9e4SEtienne Carriere } 1638fbcd9e4SEtienne Carriere 1648fbcd9e4SEtienne Carriere return _UNKNOWN_ID; 1658fbcd9e4SEtienne Carriere } 1668fbcd9e4SEtienne Carriere 1677839a050SYann Gautier enum stm32mp1_pll_id { 1687839a050SYann Gautier _PLL1, 1697839a050SYann Gautier _PLL2, 1707839a050SYann Gautier _PLL3, 1717839a050SYann Gautier _PLL4, 1727839a050SYann Gautier _PLL_NB 1737839a050SYann Gautier }; 1747839a050SYann Gautier 1757839a050SYann Gautier enum stm32mp1_div_id { 1767839a050SYann Gautier _DIV_P, 1777839a050SYann Gautier _DIV_Q, 1787839a050SYann Gautier _DIV_R, 1797839a050SYann Gautier _DIV_NB, 1807839a050SYann Gautier }; 1817839a050SYann Gautier 1827839a050SYann Gautier enum stm32mp1_clksrc_id { 1837839a050SYann Gautier CLKSRC_MPU, 1847839a050SYann Gautier CLKSRC_AXI, 185b053a22eSYann Gautier CLKSRC_MCU, 1867839a050SYann Gautier CLKSRC_PLL12, 1877839a050SYann Gautier CLKSRC_PLL3, 1887839a050SYann Gautier CLKSRC_PLL4, 1897839a050SYann Gautier CLKSRC_RTC, 1907839a050SYann Gautier CLKSRC_MCO1, 1917839a050SYann Gautier CLKSRC_MCO2, 1927839a050SYann Gautier CLKSRC_NB 1937839a050SYann Gautier }; 1947839a050SYann Gautier 1957839a050SYann Gautier enum stm32mp1_clkdiv_id { 1967839a050SYann Gautier CLKDIV_MPU, 1977839a050SYann Gautier CLKDIV_AXI, 198b053a22eSYann Gautier CLKDIV_MCU, 1997839a050SYann Gautier CLKDIV_APB1, 2007839a050SYann Gautier CLKDIV_APB2, 2017839a050SYann Gautier CLKDIV_APB3, 2027839a050SYann Gautier CLKDIV_APB4, 2037839a050SYann Gautier CLKDIV_APB5, 2047839a050SYann Gautier CLKDIV_RTC, 2057839a050SYann Gautier CLKDIV_MCO1, 2067839a050SYann Gautier CLKDIV_MCO2, 2077839a050SYann Gautier CLKDIV_NB 2087839a050SYann Gautier }; 2097839a050SYann Gautier 2107839a050SYann Gautier enum stm32mp1_pllcfg { 2117839a050SYann Gautier PLLCFG_M, 2127839a050SYann Gautier PLLCFG_N, 2137839a050SYann Gautier PLLCFG_P, 2147839a050SYann Gautier PLLCFG_Q, 2157839a050SYann Gautier PLLCFG_R, 2167839a050SYann Gautier PLLCFG_O, 2177839a050SYann Gautier PLLCFG_NB 2187839a050SYann Gautier }; 2197839a050SYann Gautier 2207839a050SYann Gautier enum stm32mp1_pllcsg { 2217839a050SYann Gautier PLLCSG_MOD_PER, 2227839a050SYann Gautier PLLCSG_INC_STEP, 2237839a050SYann Gautier PLLCSG_SSCG_MODE, 2247839a050SYann Gautier PLLCSG_NB 2257839a050SYann Gautier }; 2267839a050SYann Gautier 2277839a050SYann Gautier enum stm32mp1_plltype { 2287839a050SYann Gautier PLL_800, 2297839a050SYann Gautier PLL_1600, 2307839a050SYann Gautier PLL_TYPE_NB 2317839a050SYann Gautier }; 2327839a050SYann Gautier 2337839a050SYann Gautier struct stm32mp1_pll { 2347839a050SYann Gautier uint8_t refclk_min; 2357839a050SYann Gautier uint8_t refclk_max; 2367839a050SYann Gautier uint8_t divn_max; 2377839a050SYann Gautier }; 2387839a050SYann Gautier 2397839a050SYann Gautier struct stm32mp1_clk_gate { 2407839a050SYann Gautier uint16_t offset; 2417839a050SYann Gautier uint8_t bit; 2427839a050SYann Gautier uint8_t index; 2437839a050SYann Gautier uint8_t set_clr; 244aaa09b71SYann Gautier uint8_t secure; 2450d21680cSYann Gautier uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ 2460d21680cSYann Gautier uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ 2477839a050SYann Gautier }; 2487839a050SYann Gautier 2497839a050SYann Gautier struct stm32mp1_clk_sel { 2507839a050SYann Gautier uint16_t offset; 2517839a050SYann Gautier uint8_t src; 2527839a050SYann Gautier uint8_t msk; 2537839a050SYann Gautier uint8_t nb_parent; 2547839a050SYann Gautier const uint8_t *parent; 2557839a050SYann Gautier }; 2567839a050SYann Gautier 2577839a050SYann Gautier #define REFCLK_SIZE 4 2587839a050SYann Gautier struct stm32mp1_clk_pll { 2597839a050SYann Gautier enum stm32mp1_plltype plltype; 2607839a050SYann Gautier uint16_t rckxselr; 2617839a050SYann Gautier uint16_t pllxcfgr1; 2627839a050SYann Gautier uint16_t pllxcfgr2; 2637839a050SYann Gautier uint16_t pllxfracr; 2647839a050SYann Gautier uint16_t pllxcr; 2657839a050SYann Gautier uint16_t pllxcsgr; 2667839a050SYann Gautier enum stm32mp_osc_id refclk[REFCLK_SIZE]; 2677839a050SYann Gautier }; 2687839a050SYann Gautier 2690d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */ 270aaa09b71SYann Gautier #define _CLK_SELEC(sec, off, b, idx, s) \ 2717839a050SYann Gautier { \ 2727839a050SYann Gautier .offset = (off), \ 2737839a050SYann Gautier .bit = (b), \ 2747839a050SYann Gautier .index = (idx), \ 2757839a050SYann Gautier .set_clr = 0, \ 276aaa09b71SYann Gautier .secure = (sec), \ 2777839a050SYann Gautier .sel = (s), \ 2787839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 2797839a050SYann Gautier } 2807839a050SYann Gautier 2810d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */ 282aaa09b71SYann Gautier #define _CLK_FIXED(sec, off, b, idx, f) \ 2837839a050SYann Gautier { \ 2847839a050SYann Gautier .offset = (off), \ 2857839a050SYann Gautier .bit = (b), \ 2867839a050SYann Gautier .index = (idx), \ 2877839a050SYann Gautier .set_clr = 0, \ 288aaa09b71SYann Gautier .secure = (sec), \ 2897839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 2907839a050SYann Gautier .fixed = (f), \ 2917839a050SYann Gautier } 2927839a050SYann Gautier 2930d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */ 294aaa09b71SYann Gautier #define _CLK_SC_SELEC(sec, off, b, idx, s) \ 2957839a050SYann Gautier { \ 2967839a050SYann Gautier .offset = (off), \ 2977839a050SYann Gautier .bit = (b), \ 2987839a050SYann Gautier .index = (idx), \ 2997839a050SYann Gautier .set_clr = 1, \ 300aaa09b71SYann Gautier .secure = (sec), \ 3017839a050SYann Gautier .sel = (s), \ 3027839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 3037839a050SYann Gautier } 3047839a050SYann Gautier 3050d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */ 306aaa09b71SYann Gautier #define _CLK_SC_FIXED(sec, off, b, idx, f) \ 3077839a050SYann Gautier { \ 3087839a050SYann Gautier .offset = (off), \ 3097839a050SYann Gautier .bit = (b), \ 3107839a050SYann Gautier .index = (idx), \ 3117839a050SYann Gautier .set_clr = 1, \ 312aaa09b71SYann Gautier .secure = (sec), \ 3137839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 3147839a050SYann Gautier .fixed = (f), \ 3157839a050SYann Gautier } 3167839a050SYann Gautier 317d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents) \ 318d4151d2fSYann Gautier [_ ## _label ## _SEL] = { \ 319d4151d2fSYann Gautier .offset = _rcc_selr, \ 320d4151d2fSYann Gautier .src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \ 3218ae08dcdSEtienne Carriere .msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \ 3228ae08dcdSEtienne Carriere (_rcc_selr ## _ ## _label ## SRC_SHIFT), \ 323d4151d2fSYann Gautier .parent = (_parents), \ 324d4151d2fSYann Gautier .nb_parent = ARRAY_SIZE(_parents) \ 3257839a050SYann Gautier } 3267839a050SYann Gautier 3270d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3, \ 3287839a050SYann Gautier off4, off5, off6, \ 3297839a050SYann Gautier p1, p2, p3, p4) \ 3307839a050SYann Gautier [(idx)] = { \ 3317839a050SYann Gautier .plltype = (type), \ 3327839a050SYann Gautier .rckxselr = (off1), \ 3337839a050SYann Gautier .pllxcfgr1 = (off2), \ 3347839a050SYann Gautier .pllxcfgr2 = (off3), \ 3357839a050SYann Gautier .pllxfracr = (off4), \ 3367839a050SYann Gautier .pllxcr = (off5), \ 3377839a050SYann Gautier .pllxcsgr = (off6), \ 3387839a050SYann Gautier .refclk[0] = (p1), \ 3397839a050SYann Gautier .refclk[1] = (p2), \ 3407839a050SYann Gautier .refclk[2] = (p3), \ 3417839a050SYann Gautier .refclk[3] = (p4), \ 3427839a050SYann Gautier } 3437839a050SYann Gautier 3440d21680cSYann Gautier #define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) 3450d21680cSYann Gautier 346aaa09b71SYann Gautier #define SEC 1 347aaa09b71SYann Gautier #define N_S 0 348aaa09b71SYann Gautier 3497839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { 350aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK), 351aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK), 352aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK), 353aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK), 354aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), 355aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), 356aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), 357aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), 358aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK), 359aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), 360aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), 3617839a050SYann Gautier 362*7418cf39SYann Gautier #if defined(IMAGE_BL32) 363aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), 364*7418cf39SYann Gautier #endif 365aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), 366aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), 367aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), 368aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), 369aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), 370aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), 371aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), 372aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), 373aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), 374aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), 3757839a050SYann Gautier 376*7418cf39SYann Gautier #if defined(IMAGE_BL32) 377aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), 378*7418cf39SYann Gautier #endif 379aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), 3807839a050SYann Gautier 381aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), 382f33b2433SYann Gautier 383aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), 384aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), 385aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), 3867839a050SYann Gautier 387aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), 388aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), 389aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), 390aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL), 391aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), 392aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), 393aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), 394aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), 395aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), 396aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), 397aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), 3987839a050SYann Gautier 399*7418cf39SYann Gautier #if defined(IMAGE_BL32) 400aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), 401aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), 402*7418cf39SYann Gautier #endif 4037839a050SYann Gautier 404aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), 405aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), 406aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), 407aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), 408aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), 409aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), 410aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), 411aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), 412aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), 413aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), 414aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), 4157839a050SYann Gautier 416aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), 417aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), 418aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), 419aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), 420aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), 4217839a050SYann Gautier 422*7418cf39SYann Gautier #if defined(IMAGE_BL2) 423aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), 424aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), 425*7418cf39SYann Gautier #endif 426aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), 427aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), 428*7418cf39SYann Gautier #if defined(IMAGE_BL32) 429aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), 430*7418cf39SYann Gautier #endif 4317839a050SYann Gautier 432aaa09b71SYann Gautier _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL), 433aaa09b71SYann Gautier _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), 4347839a050SYann Gautier }; 4357839a050SYann Gautier 4360d21680cSYann Gautier static const uint8_t i2c12_parents[] = { 4370d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4380d21680cSYann Gautier }; 4390d21680cSYann Gautier 4400d21680cSYann Gautier static const uint8_t i2c35_parents[] = { 4410d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4420d21680cSYann Gautier }; 4430d21680cSYann Gautier 4440d21680cSYann Gautier static const uint8_t stgen_parents[] = { 4450d21680cSYann Gautier _HSI_KER, _HSE_KER 4460d21680cSYann Gautier }; 4470d21680cSYann Gautier 4480d21680cSYann Gautier static const uint8_t i2c46_parents[] = { 4490d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER 4500d21680cSYann Gautier }; 4510d21680cSYann Gautier 4520d21680cSYann Gautier static const uint8_t spi6_parents[] = { 4530d21680cSYann Gautier _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q 4540d21680cSYann Gautier }; 4550d21680cSYann Gautier 4560d21680cSYann Gautier static const uint8_t usart1_parents[] = { 4570d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER 4580d21680cSYann Gautier }; 4590d21680cSYann Gautier 4600d21680cSYann Gautier static const uint8_t rng1_parents[] = { 4610d21680cSYann Gautier _CSI, _PLL4_R, _LSE, _LSI 4620d21680cSYann Gautier }; 4630d21680cSYann Gautier 4640d21680cSYann Gautier static const uint8_t uart6_parents[] = { 4650d21680cSYann Gautier _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4660d21680cSYann Gautier }; 4670d21680cSYann Gautier 4680d21680cSYann Gautier static const uint8_t uart234578_parents[] = { 4690d21680cSYann Gautier _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4700d21680cSYann Gautier }; 4710d21680cSYann Gautier 4720d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = { 4730d21680cSYann Gautier _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER 4740d21680cSYann Gautier }; 4750d21680cSYann Gautier 4760d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = { 4770d21680cSYann Gautier _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER 4780d21680cSYann Gautier }; 4790d21680cSYann Gautier 4800d21680cSYann Gautier static const uint8_t qspi_parents[] = { 4810d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4820d21680cSYann Gautier }; 4830d21680cSYann Gautier 4840d21680cSYann Gautier static const uint8_t fmc_parents[] = { 4850d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4860d21680cSYann Gautier }; 4870d21680cSYann Gautier 488b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = { 489b8fe48b6SEtienne Carriere _HSI, _HSE, _PLL2_P 4900d21680cSYann Gautier }; 4910d21680cSYann Gautier 492b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = { 493b8fe48b6SEtienne Carriere _HSI, _HSE, _CSI, _PLL3_P 494b053a22eSYann Gautier }; 495b053a22eSYann Gautier 4960d21680cSYann Gautier static const uint8_t usbphy_parents[] = { 4970d21680cSYann Gautier _HSE_KER, _PLL4_R, _HSE_KER_DIV2 4980d21680cSYann Gautier }; 4990d21680cSYann Gautier 5000d21680cSYann Gautier static const uint8_t usbo_parents[] = { 5010d21680cSYann Gautier _PLL4_R, _USB_PHY_48 5020d21680cSYann Gautier }; 5037839a050SYann Gautier 5048fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = { 5058fbcd9e4SEtienne Carriere _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ 5068fbcd9e4SEtienne Carriere }; 5078fbcd9e4SEtienne Carriere 5088fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = { 5098fbcd9e4SEtienne Carriere _HSI, _HSE, _CSI, 5108fbcd9e4SEtienne Carriere }; 5118fbcd9e4SEtienne Carriere 512016af006SEtienne Carriere static const uint8_t rtc_parents[] = { 513cbd2e8a6SGabriel Fernandez _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC 514016af006SEtienne Carriere }; 515016af006SEtienne Carriere 5167839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { 517d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), 518d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), 519d4151d2fSYann Gautier _CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents), 520d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents), 521d4151d2fSYann Gautier _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), 522d4151d2fSYann Gautier _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), 523d4151d2fSYann Gautier _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), 5248fbcd9e4SEtienne Carriere _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents), 525288f5cf2SYann Gautier _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents), 526016af006SEtienne Carriere _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents), 527d4151d2fSYann Gautier _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), 528d4151d2fSYann Gautier _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), 529d4151d2fSYann Gautier _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), 530d4151d2fSYann Gautier _CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents), 531d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents), 532d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents), 533d4151d2fSYann Gautier _CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents), 534d4151d2fSYann Gautier _CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents), 535b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents), 536b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents), 537d4151d2fSYann Gautier _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents), 538d4151d2fSYann Gautier _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents), 5397839a050SYann Gautier }; 5407839a050SYann Gautier 5417839a050SYann Gautier /* Define characteristic of PLL according type */ 5427839a050SYann Gautier #define DIVN_MIN 24 5437839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { 5447839a050SYann Gautier [PLL_800] = { 5457839a050SYann Gautier .refclk_min = 4, 5467839a050SYann Gautier .refclk_max = 16, 5477839a050SYann Gautier .divn_max = 99, 5487839a050SYann Gautier }, 5497839a050SYann Gautier [PLL_1600] = { 5507839a050SYann Gautier .refclk_min = 8, 5517839a050SYann Gautier .refclk_max = 16, 5527839a050SYann Gautier .divn_max = 199, 5537839a050SYann Gautier }, 5547839a050SYann Gautier }; 5557839a050SYann Gautier 5567839a050SYann Gautier /* PLLNCFGR2 register divider by output */ 5577839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = { 5587839a050SYann Gautier [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, 5597839a050SYann Gautier [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, 5600d21680cSYann Gautier [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, 5617839a050SYann Gautier }; 5627839a050SYann Gautier 5637839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { 5640d21680cSYann Gautier _CLK_PLL(_PLL1, PLL_1600, 5657839a050SYann Gautier RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, 5667839a050SYann Gautier RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, 5677839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5680d21680cSYann Gautier _CLK_PLL(_PLL2, PLL_1600, 5697839a050SYann Gautier RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, 5707839a050SYann Gautier RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, 5717839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5720d21680cSYann Gautier _CLK_PLL(_PLL3, PLL_800, 5737839a050SYann Gautier RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, 5747839a050SYann Gautier RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, 5757839a050SYann Gautier _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), 5760d21680cSYann Gautier _CLK_PLL(_PLL4, PLL_800, 5777839a050SYann Gautier RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, 5787839a050SYann Gautier RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, 5797839a050SYann Gautier _HSI, _HSE, _CSI, _I2S_CKIN), 5807839a050SYann Gautier }; 5817839a050SYann Gautier 5827839a050SYann Gautier /* Prescaler table lookups for clock computation */ 583b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ 584b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = { 585b053a22eSYann Gautier 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 586b053a22eSYann Gautier }; 5877839a050SYann Gautier 5887839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ 5897839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div 5907839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div 5917839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = { 5927839a050SYann Gautier 0, 1, 2, 3, 4, 4, 4, 4 5937839a050SYann Gautier }; 5947839a050SYann Gautier 5957839a050SYann Gautier /* div = /1 /2 /3 /4 */ 5967839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = { 5977839a050SYann Gautier 1, 2, 3, 4, 4, 4, 4, 4 5987839a050SYann Gautier }; 5997839a050SYann Gautier 60037e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { 60137e8295aSEtienne Carriere [_HSI] = "HSI", 60237e8295aSEtienne Carriere [_HSE] = "HSE", 60337e8295aSEtienne Carriere [_CSI] = "CSI", 60437e8295aSEtienne Carriere [_LSI] = "LSI", 60537e8295aSEtienne Carriere [_LSE] = "LSE", 60637e8295aSEtienne Carriere [_I2S_CKIN] = "I2S_CKIN", 60737e8295aSEtienne Carriere [_HSI_KER] = "HSI_KER", 60837e8295aSEtienne Carriere [_HSE_KER] = "HSE_KER", 60937e8295aSEtienne Carriere [_HSE_KER_DIV2] = "HSE_KER_DIV2", 610cbd2e8a6SGabriel Fernandez [_HSE_RTC] = "HSE_RTC", 61137e8295aSEtienne Carriere [_CSI_KER] = "CSI_KER", 61237e8295aSEtienne Carriere [_PLL1_P] = "PLL1_P", 61337e8295aSEtienne Carriere [_PLL1_Q] = "PLL1_Q", 61437e8295aSEtienne Carriere [_PLL1_R] = "PLL1_R", 61537e8295aSEtienne Carriere [_PLL2_P] = "PLL2_P", 61637e8295aSEtienne Carriere [_PLL2_Q] = "PLL2_Q", 61737e8295aSEtienne Carriere [_PLL2_R] = "PLL2_R", 61837e8295aSEtienne Carriere [_PLL3_P] = "PLL3_P", 61937e8295aSEtienne Carriere [_PLL3_Q] = "PLL3_Q", 62037e8295aSEtienne Carriere [_PLL3_R] = "PLL3_R", 62137e8295aSEtienne Carriere [_PLL4_P] = "PLL4_P", 62237e8295aSEtienne Carriere [_PLL4_Q] = "PLL4_Q", 62337e8295aSEtienne Carriere [_PLL4_R] = "PLL4_R", 62437e8295aSEtienne Carriere [_ACLK] = "ACLK", 62537e8295aSEtienne Carriere [_PCLK1] = "PCLK1", 62637e8295aSEtienne Carriere [_PCLK2] = "PCLK2", 62737e8295aSEtienne Carriere [_PCLK3] = "PCLK3", 62837e8295aSEtienne Carriere [_PCLK4] = "PCLK4", 62937e8295aSEtienne Carriere [_PCLK5] = "PCLK5", 63037e8295aSEtienne Carriere [_HCLK6] = "KCLK6", 63137e8295aSEtienne Carriere [_HCLK2] = "HCLK2", 63237e8295aSEtienne Carriere [_CK_PER] = "CK_PER", 63337e8295aSEtienne Carriere [_CK_MPU] = "CK_MPU", 63437e8295aSEtienne Carriere [_CK_MCU] = "CK_MCU", 63537e8295aSEtienne Carriere [_USB_PHY_48] = "USB_PHY_48", 63637e8295aSEtienne Carriere }; 63737e8295aSEtienne Carriere 6380d21680cSYann Gautier /* RCC clock device driver private */ 6390d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC]; 6400d21680cSYann Gautier static struct spinlock reg_lock; 6410d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES]; 6420d21680cSYann Gautier static struct spinlock refcount_lock; 6437839a050SYann Gautier 6440d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) 6450d21680cSYann Gautier { 6460d21680cSYann Gautier return &stm32mp1_clk_gate[idx]; 6470d21680cSYann Gautier } 6487839a050SYann Gautier 6493d69149aSYann Gautier #if defined(IMAGE_BL32) 6503d69149aSYann Gautier static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate) 6513d69149aSYann Gautier { 6523d69149aSYann Gautier return gate->secure == N_S; 6533d69149aSYann Gautier } 6543d69149aSYann Gautier #endif 6553d69149aSYann Gautier 6560d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) 6570d21680cSYann Gautier { 6580d21680cSYann Gautier return &stm32mp1_clk_sel[idx]; 6590d21680cSYann Gautier } 6600d21680cSYann Gautier 6610d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) 6620d21680cSYann Gautier { 6630d21680cSYann Gautier return &stm32mp1_clk_pll[idx]; 6640d21680cSYann Gautier } 6650d21680cSYann Gautier 6660d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock) 6670d21680cSYann Gautier { 668e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6690d21680cSYann Gautier /* Assume interrupts are masked */ 6700d21680cSYann Gautier spin_lock(lock); 6710d21680cSYann Gautier } 672e463d3f4SYann Gautier } 6730d21680cSYann Gautier 6740d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock) 6750d21680cSYann Gautier { 676e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6770d21680cSYann Gautier spin_unlock(lock); 6780d21680cSYann Gautier } 679e463d3f4SYann Gautier } 6800d21680cSYann Gautier 6810d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void) 6820d21680cSYann Gautier { 6830d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6841bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN; 6850d21680cSYann Gautier 6861bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 6870d21680cSYann Gautier } 6880d21680cSYann Gautier 689b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void) 690b053a22eSYann Gautier { 691b053a22eSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6921bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; 693b053a22eSYann Gautier 6941bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 695b053a22eSYann Gautier } 696b053a22eSYann Gautier 6970d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void) 6980d21680cSYann Gautier { 6990d21680cSYann Gautier stm32mp1_clk_lock(®_lock); 7000d21680cSYann Gautier } 7010d21680cSYann Gautier 7020d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void) 7030d21680cSYann Gautier { 7040d21680cSYann Gautier stm32mp1_clk_unlock(®_lock); 7050d21680cSYann Gautier } 7060d21680cSYann Gautier 7070d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) 7087839a050SYann Gautier { 7097839a050SYann Gautier if (idx >= NB_OSC) { 7107839a050SYann Gautier return 0; 7117839a050SYann Gautier } 7127839a050SYann Gautier 7130d21680cSYann Gautier return stm32mp1_osc[idx]; 7147839a050SYann Gautier } 7157839a050SYann Gautier 7160d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id) 7177839a050SYann Gautier { 7180d21680cSYann Gautier unsigned int i; 7197839a050SYann Gautier 7200d21680cSYann Gautier for (i = 0U; i < NB_GATES; i++) { 7210d21680cSYann Gautier if (gate_ref(i)->index == id) { 7227839a050SYann Gautier return i; 7237839a050SYann Gautier } 7247839a050SYann Gautier } 7257839a050SYann Gautier 72644fb470bSYann Gautier ERROR("%s: clk id %lu not found\n", __func__, id); 7277839a050SYann Gautier 7287839a050SYann Gautier return -EINVAL; 7297839a050SYann Gautier } 7307839a050SYann Gautier 7310d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) 7327839a050SYann Gautier { 7330d21680cSYann Gautier return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); 7347839a050SYann Gautier } 7357839a050SYann Gautier 7360d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) 7377839a050SYann Gautier { 7380d21680cSYann Gautier return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); 7397839a050SYann Gautier } 7407839a050SYann Gautier 7410d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id) 7427839a050SYann Gautier { 7430d21680cSYann Gautier const struct stm32mp1_clk_sel *sel; 7448fbcd9e4SEtienne Carriere uint32_t p_sel; 7457839a050SYann Gautier int i; 7467839a050SYann Gautier enum stm32mp1_parent_id p; 7477839a050SYann Gautier enum stm32mp1_parent_sel s; 7480d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7497839a050SYann Gautier 7508fbcd9e4SEtienne Carriere /* Few non gateable clock have a static parent ID, find them */ 7518fbcd9e4SEtienne Carriere i = (int)clock_id2parent_id(id); 7528fbcd9e4SEtienne Carriere if (i != _UNKNOWN_ID) { 7538fbcd9e4SEtienne Carriere return i; 7547839a050SYann Gautier } 7557839a050SYann Gautier 7560d21680cSYann Gautier i = stm32mp1_clk_get_gated_id(id); 7577839a050SYann Gautier if (i < 0) { 7580d21680cSYann Gautier panic(); 7597839a050SYann Gautier } 7607839a050SYann Gautier 7610d21680cSYann Gautier p = stm32mp1_clk_get_fixed_parent(i); 7627839a050SYann Gautier if (p < _PARENT_NB) { 7637839a050SYann Gautier return (int)p; 7647839a050SYann Gautier } 7657839a050SYann Gautier 7660d21680cSYann Gautier s = stm32mp1_clk_get_sel(i); 7670d21680cSYann Gautier if (s == _UNKNOWN_SEL) { 7680d21680cSYann Gautier return -EINVAL; 7690d21680cSYann Gautier } 7707839a050SYann Gautier if (s >= _PARENT_SEL_NB) { 7710d21680cSYann Gautier panic(); 7727839a050SYann Gautier } 7737839a050SYann Gautier 7740d21680cSYann Gautier sel = clk_sel_ref(s); 7758ae08dcdSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) & 7768ae08dcdSEtienne Carriere (sel->msk << sel->src)) >> sel->src; 7770d21680cSYann Gautier if (p_sel < sel->nb_parent) { 7780d21680cSYann Gautier return (int)sel->parent[p_sel]; 7797839a050SYann Gautier } 7807839a050SYann Gautier 7817839a050SYann Gautier return -EINVAL; 7827839a050SYann Gautier } 7837839a050SYann Gautier 7840d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) 7857839a050SYann Gautier { 7860d21680cSYann Gautier uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); 7870d21680cSYann Gautier uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; 7887839a050SYann Gautier 7890d21680cSYann Gautier return stm32mp1_clk_get_fixed(pll->refclk[src]); 7907839a050SYann Gautier } 7917839a050SYann Gautier 7927839a050SYann Gautier /* 7937839a050SYann Gautier * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL 7947839a050SYann Gautier * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) 7957839a050SYann Gautier * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) 7967839a050SYann Gautier * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) 7977839a050SYann Gautier */ 7980d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) 7997839a050SYann Gautier { 8007839a050SYann Gautier unsigned long refclk, fvco; 8017839a050SYann Gautier uint32_t cfgr1, fracr, divm, divn; 8020d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8037839a050SYann Gautier 8040d21680cSYann Gautier cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); 8050d21680cSYann Gautier fracr = mmio_read_32(rcc_base + pll->pllxfracr); 8067839a050SYann Gautier 8077839a050SYann Gautier divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; 8087839a050SYann Gautier divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; 8097839a050SYann Gautier 8100d21680cSYann Gautier refclk = stm32mp1_pll_get_fref(pll); 8117839a050SYann Gautier 8127839a050SYann Gautier /* 8137839a050SYann Gautier * With FRACV : 8147839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) 8157839a050SYann Gautier * Without FRACV 8167839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) 8177839a050SYann Gautier */ 8187839a050SYann Gautier if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { 8190d21680cSYann Gautier uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> 8200d21680cSYann Gautier RCC_PLLNFRACR_FRACV_SHIFT; 8217839a050SYann Gautier unsigned long long numerator, denominator; 8227839a050SYann Gautier 8230d21680cSYann Gautier numerator = (((unsigned long long)divn + 1U) << 13) + fracv; 8240d21680cSYann Gautier numerator = refclk * numerator; 8257839a050SYann Gautier denominator = ((unsigned long long)divm + 1U) << 13; 8267839a050SYann Gautier fvco = (unsigned long)(numerator / denominator); 8277839a050SYann Gautier } else { 8287839a050SYann Gautier fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); 8297839a050SYann Gautier } 8307839a050SYann Gautier 8317839a050SYann Gautier return fvco; 8327839a050SYann Gautier } 8337839a050SYann Gautier 8340d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, 8357839a050SYann Gautier enum stm32mp1_div_id div_id) 8367839a050SYann Gautier { 8370d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 8387839a050SYann Gautier unsigned long dfout; 8397839a050SYann Gautier uint32_t cfgr2, divy; 8407839a050SYann Gautier 8417839a050SYann Gautier if (div_id >= _DIV_NB) { 8427839a050SYann Gautier return 0; 8437839a050SYann Gautier } 8447839a050SYann Gautier 8450d21680cSYann Gautier cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); 8467839a050SYann Gautier divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; 8477839a050SYann Gautier 8480d21680cSYann Gautier dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); 8497839a050SYann Gautier 8507839a050SYann Gautier return dfout; 8517839a050SYann Gautier } 8527839a050SYann Gautier 8530d21680cSYann Gautier static unsigned long get_clock_rate(int p) 8547839a050SYann Gautier { 8557839a050SYann Gautier uint32_t reg, clkdiv; 8567839a050SYann Gautier unsigned long clock = 0; 8570d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8587839a050SYann Gautier 8597839a050SYann Gautier switch (p) { 8607839a050SYann Gautier case _CK_MPU: 8617839a050SYann Gautier /* MPU sub system */ 8620d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKSELR); 8637839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8647839a050SYann Gautier case RCC_MPCKSELR_HSI: 8650d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8667839a050SYann Gautier break; 8677839a050SYann Gautier case RCC_MPCKSELR_HSE: 8680d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8697839a050SYann Gautier break; 8707839a050SYann Gautier case RCC_MPCKSELR_PLL: 8710d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8727839a050SYann Gautier break; 8737839a050SYann Gautier case RCC_MPCKSELR_PLL_MPUDIV: 8740d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8757839a050SYann Gautier 8760d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); 8777839a050SYann Gautier clkdiv = reg & RCC_MPUDIV_MASK; 878602ae2f2SGabriel Fernandez clock >>= stm32mp1_mpu_div[clkdiv]; 8797839a050SYann Gautier break; 8807839a050SYann Gautier default: 8817839a050SYann Gautier break; 8827839a050SYann Gautier } 8837839a050SYann Gautier break; 8847839a050SYann Gautier /* AXI sub system */ 8857839a050SYann Gautier case _ACLK: 8867839a050SYann Gautier case _HCLK2: 8877839a050SYann Gautier case _HCLK6: 8887839a050SYann Gautier case _PCLK4: 8897839a050SYann Gautier case _PCLK5: 8900d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); 8917839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8927839a050SYann Gautier case RCC_ASSCKSELR_HSI: 8930d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8947839a050SYann Gautier break; 8957839a050SYann Gautier case RCC_ASSCKSELR_HSE: 8960d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8977839a050SYann Gautier break; 8987839a050SYann Gautier case RCC_ASSCKSELR_PLL: 8990d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 9007839a050SYann Gautier break; 9017839a050SYann Gautier default: 9027839a050SYann Gautier break; 9037839a050SYann Gautier } 9047839a050SYann Gautier 9057839a050SYann Gautier /* System clock divider */ 9060d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_AXIDIVR); 9077839a050SYann Gautier clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; 9087839a050SYann Gautier 9097839a050SYann Gautier switch (p) { 9107839a050SYann Gautier case _PCLK4: 9110d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB4DIVR); 9127839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9137839a050SYann Gautier break; 9147839a050SYann Gautier case _PCLK5: 9150d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB5DIVR); 9167839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9177839a050SYann Gautier break; 9187839a050SYann Gautier default: 9197839a050SYann Gautier break; 9207839a050SYann Gautier } 9217839a050SYann Gautier break; 922b053a22eSYann Gautier /* MCU sub system */ 923b053a22eSYann Gautier case _CK_MCU: 924b053a22eSYann Gautier case _PCLK1: 925b053a22eSYann Gautier case _PCLK2: 926b053a22eSYann Gautier case _PCLK3: 927b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); 928b053a22eSYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 929b053a22eSYann Gautier case RCC_MSSCKSELR_HSI: 930b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 931b053a22eSYann Gautier break; 932b053a22eSYann Gautier case RCC_MSSCKSELR_HSE: 933b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 934b053a22eSYann Gautier break; 935b053a22eSYann Gautier case RCC_MSSCKSELR_CSI: 936b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 937b053a22eSYann Gautier break; 938b053a22eSYann Gautier case RCC_MSSCKSELR_PLL: 939b053a22eSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 940b053a22eSYann Gautier break; 941b053a22eSYann Gautier default: 942b053a22eSYann Gautier break; 943b053a22eSYann Gautier } 944b053a22eSYann Gautier 945b053a22eSYann Gautier /* MCU clock divider */ 946b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MCUDIVR); 947b053a22eSYann Gautier clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; 948b053a22eSYann Gautier 949b053a22eSYann Gautier switch (p) { 950b053a22eSYann Gautier case _PCLK1: 951b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB1DIVR); 952b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 953b053a22eSYann Gautier break; 954b053a22eSYann Gautier case _PCLK2: 955b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB2DIVR); 956b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 957b053a22eSYann Gautier break; 958b053a22eSYann Gautier case _PCLK3: 959b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB3DIVR); 960b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 961b053a22eSYann Gautier break; 962b053a22eSYann Gautier case _CK_MCU: 963b053a22eSYann Gautier default: 964b053a22eSYann Gautier break; 965b053a22eSYann Gautier } 966b053a22eSYann Gautier break; 9677839a050SYann Gautier case _CK_PER: 9680d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); 9697839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 9707839a050SYann Gautier case RCC_CPERCKSELR_HSI: 9710d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9727839a050SYann Gautier break; 9737839a050SYann Gautier case RCC_CPERCKSELR_HSE: 9740d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9757839a050SYann Gautier break; 9767839a050SYann Gautier case RCC_CPERCKSELR_CSI: 9770d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9787839a050SYann Gautier break; 9797839a050SYann Gautier default: 9807839a050SYann Gautier break; 9817839a050SYann Gautier } 9827839a050SYann Gautier break; 9837839a050SYann Gautier case _HSI: 9847839a050SYann Gautier case _HSI_KER: 9850d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9867839a050SYann Gautier break; 9877839a050SYann Gautier case _CSI: 9887839a050SYann Gautier case _CSI_KER: 9890d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9907839a050SYann Gautier break; 9917839a050SYann Gautier case _HSE: 9927839a050SYann Gautier case _HSE_KER: 9930d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9947839a050SYann Gautier break; 9957839a050SYann Gautier case _HSE_KER_DIV2: 9960d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE) >> 1; 9977839a050SYann Gautier break; 998cbd2e8a6SGabriel Fernandez case _HSE_RTC: 999cbd2e8a6SGabriel Fernandez clock = stm32mp1_clk_get_fixed(_HSE); 1000cbd2e8a6SGabriel Fernandez clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; 1001cbd2e8a6SGabriel Fernandez break; 10027839a050SYann Gautier case _LSI: 10030d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSI); 10047839a050SYann Gautier break; 10057839a050SYann Gautier case _LSE: 10060d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSE); 10077839a050SYann Gautier break; 10087839a050SYann Gautier /* PLL */ 10097839a050SYann Gautier case _PLL1_P: 10100d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 10117839a050SYann Gautier break; 10127839a050SYann Gautier case _PLL1_Q: 10130d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); 10147839a050SYann Gautier break; 10157839a050SYann Gautier case _PLL1_R: 10160d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); 10177839a050SYann Gautier break; 10187839a050SYann Gautier case _PLL2_P: 10190d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 10207839a050SYann Gautier break; 10217839a050SYann Gautier case _PLL2_Q: 10220d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); 10237839a050SYann Gautier break; 10247839a050SYann Gautier case _PLL2_R: 10250d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); 10267839a050SYann Gautier break; 10277839a050SYann Gautier case _PLL3_P: 10280d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 10297839a050SYann Gautier break; 10307839a050SYann Gautier case _PLL3_Q: 10310d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); 10327839a050SYann Gautier break; 10337839a050SYann Gautier case _PLL3_R: 10340d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); 10357839a050SYann Gautier break; 10367839a050SYann Gautier case _PLL4_P: 10370d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); 10387839a050SYann Gautier break; 10397839a050SYann Gautier case _PLL4_Q: 10400d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); 10417839a050SYann Gautier break; 10427839a050SYann Gautier case _PLL4_R: 10430d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); 10447839a050SYann Gautier break; 10457839a050SYann Gautier /* Other */ 10467839a050SYann Gautier case _USB_PHY_48: 10470d21680cSYann Gautier clock = USB_PHY_48_MHZ; 10487839a050SYann Gautier break; 10497839a050SYann Gautier default: 10507839a050SYann Gautier break; 10517839a050SYann Gautier } 10527839a050SYann Gautier 10537839a050SYann Gautier return clock; 10547839a050SYann Gautier } 10557839a050SYann Gautier 10560d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate) 10570d21680cSYann Gautier { 10580d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10590d21680cSYann Gautier 106025be845eSEtienne Carriere VERBOSE("Enable clock %u\n", gate->index); 106125be845eSEtienne Carriere 10620d21680cSYann Gautier if (gate->set_clr != 0U) { 10630d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); 10640d21680cSYann Gautier } else { 10650d21680cSYann Gautier mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10660d21680cSYann Gautier } 10670d21680cSYann Gautier } 10680d21680cSYann Gautier 10690d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate) 10700d21680cSYann Gautier { 10710d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10720d21680cSYann Gautier 107325be845eSEtienne Carriere VERBOSE("Disable clock %u\n", gate->index); 107425be845eSEtienne Carriere 10750d21680cSYann Gautier if (gate->set_clr != 0U) { 10760d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, 10770d21680cSYann Gautier BIT(gate->bit)); 10780d21680cSYann Gautier } else { 10790d21680cSYann Gautier mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10800d21680cSYann Gautier } 10810d21680cSYann Gautier } 10820d21680cSYann Gautier 10830d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) 10840d21680cSYann Gautier { 10850d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10860d21680cSYann Gautier 10870d21680cSYann Gautier return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); 10880d21680cSYann Gautier } 10890d21680cSYann Gautier 109035848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */ 109135848200SEtienne Carriere static bool clock_is_always_on(unsigned long id) 109235848200SEtienne Carriere { 109335848200SEtienne Carriere switch (id) { 109435848200SEtienne Carriere case CK_HSE: 109535848200SEtienne Carriere case CK_CSI: 109635848200SEtienne Carriere case CK_LSI: 109735848200SEtienne Carriere case CK_LSE: 109835848200SEtienne Carriere case CK_HSI: 109935848200SEtienne Carriere case CK_HSE_DIV2: 110035848200SEtienne Carriere case PLL1_Q: 110135848200SEtienne Carriere case PLL1_R: 110235848200SEtienne Carriere case PLL2_P: 110335848200SEtienne Carriere case PLL2_Q: 110435848200SEtienne Carriere case PLL2_R: 110535848200SEtienne Carriere case PLL3_P: 110635848200SEtienne Carriere case PLL3_Q: 110735848200SEtienne Carriere case PLL3_R: 1108bf39318dSYann Gautier case CK_AXI: 1109bf39318dSYann Gautier case CK_MPU: 1110bf39318dSYann Gautier case CK_MCU: 11115b111c74SHE Shushan case RTC: 111235848200SEtienne Carriere return true; 111335848200SEtienne Carriere default: 111435848200SEtienne Carriere return false; 111535848200SEtienne Carriere } 111635848200SEtienne Carriere } 111735848200SEtienne Carriere 11182444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt) 11190d21680cSYann Gautier { 11200d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 112135848200SEtienne Carriere int i; 11220d21680cSYann Gautier 112335848200SEtienne Carriere if (clock_is_always_on(id)) { 112435848200SEtienne Carriere return; 112535848200SEtienne Carriere } 112635848200SEtienne Carriere 112735848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11280d21680cSYann Gautier if (i < 0) { 112944fb470bSYann Gautier ERROR("Clock %lu can't be enabled\n", id); 11300d21680cSYann Gautier panic(); 11310d21680cSYann Gautier } 11320d21680cSYann Gautier 11330d21680cSYann Gautier gate = gate_ref(i); 11342444d231SYann Gautier 11352444d231SYann Gautier if (!with_refcnt) { 11362444d231SYann Gautier __clk_enable(gate); 11372444d231SYann Gautier return; 11382444d231SYann Gautier } 11390d21680cSYann Gautier 11403d69149aSYann Gautier #if defined(IMAGE_BL32) 11413d69149aSYann Gautier if (gate_is_non_secure(gate)) { 11423d69149aSYann Gautier /* Enable non-secure clock w/o any refcounting */ 11433d69149aSYann Gautier __clk_enable(gate); 11443d69149aSYann Gautier return; 11453d69149aSYann Gautier } 11463d69149aSYann Gautier #endif 11473d69149aSYann Gautier 11480d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11490d21680cSYann Gautier 11502444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11510d21680cSYann Gautier __clk_enable(gate); 11520d21680cSYann Gautier } 11530d21680cSYann Gautier 11542444d231SYann Gautier gate_refcounts[i]++; 11552444d231SYann Gautier if (gate_refcounts[i] == UINT_MAX) { 11562444d231SYann Gautier ERROR("Clock %lu refcount reached max value\n", id); 11572444d231SYann Gautier panic(); 11582444d231SYann Gautier } 11592444d231SYann Gautier 11600d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11610d21680cSYann Gautier } 11620d21680cSYann Gautier 11632444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt) 11640d21680cSYann Gautier { 11650d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 116635848200SEtienne Carriere int i; 11670d21680cSYann Gautier 116835848200SEtienne Carriere if (clock_is_always_on(id)) { 116935848200SEtienne Carriere return; 117035848200SEtienne Carriere } 117135848200SEtienne Carriere 117235848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11730d21680cSYann Gautier if (i < 0) { 117444fb470bSYann Gautier ERROR("Clock %lu can't be disabled\n", id); 11750d21680cSYann Gautier panic(); 11760d21680cSYann Gautier } 11770d21680cSYann Gautier 11780d21680cSYann Gautier gate = gate_ref(i); 11792444d231SYann Gautier 11802444d231SYann Gautier if (!with_refcnt) { 11812444d231SYann Gautier __clk_disable(gate); 11822444d231SYann Gautier return; 11832444d231SYann Gautier } 11840d21680cSYann Gautier 11853d69149aSYann Gautier #if defined(IMAGE_BL32) 11863d69149aSYann Gautier if (gate_is_non_secure(gate)) { 11873d69149aSYann Gautier /* Don't disable non-secure clocks */ 11883d69149aSYann Gautier return; 11893d69149aSYann Gautier } 11903d69149aSYann Gautier #endif 11913d69149aSYann Gautier 11920d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11930d21680cSYann Gautier 11942444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11952444d231SYann Gautier ERROR("Clock %lu refcount reached 0\n", id); 11962444d231SYann Gautier panic(); 11972444d231SYann Gautier } 11982444d231SYann Gautier gate_refcounts[i]--; 11992444d231SYann Gautier 12002444d231SYann Gautier if (gate_refcounts[i] == 0U) { 12010d21680cSYann Gautier __clk_disable(gate); 12020d21680cSYann Gautier } 12030d21680cSYann Gautier 12040d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 12050d21680cSYann Gautier } 12060d21680cSYann Gautier 120733667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id) 12080d21680cSYann Gautier { 12090d21680cSYann Gautier __stm32mp1_clk_enable(id, true); 121033667d29SYann Gautier 121133667d29SYann Gautier return 0; 12120d21680cSYann Gautier } 12130d21680cSYann Gautier 121433667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id) 12150d21680cSYann Gautier { 12160d21680cSYann Gautier __stm32mp1_clk_disable(id, true); 12170d21680cSYann Gautier } 12180d21680cSYann Gautier 121933667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id) 12207839a050SYann Gautier { 122135848200SEtienne Carriere int i; 12227839a050SYann Gautier 122335848200SEtienne Carriere if (clock_is_always_on(id)) { 122435848200SEtienne Carriere return true; 122535848200SEtienne Carriere } 122635848200SEtienne Carriere 122735848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 12287839a050SYann Gautier if (i < 0) { 12290d21680cSYann Gautier panic(); 12307839a050SYann Gautier } 12317839a050SYann Gautier 12320d21680cSYann Gautier return __clk_is_enabled(gate_ref(i)); 12337839a050SYann Gautier } 12347839a050SYann Gautier 123533667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id) 12367839a050SYann Gautier { 123733667d29SYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 12380d21680cSYann Gautier int p = stm32mp1_clk_get_parent(id); 123933667d29SYann Gautier uint32_t prescaler, timpre; 124033667d29SYann Gautier unsigned long parent_rate; 12417839a050SYann Gautier 12427839a050SYann Gautier if (p < 0) { 12437839a050SYann Gautier return 0; 12447839a050SYann Gautier } 12457839a050SYann Gautier 124633667d29SYann Gautier parent_rate = get_clock_rate(p); 124733667d29SYann Gautier 124833667d29SYann Gautier switch (id) { 124933667d29SYann Gautier case TIM2_K: 125033667d29SYann Gautier case TIM3_K: 125133667d29SYann Gautier case TIM4_K: 125233667d29SYann Gautier case TIM5_K: 125333667d29SYann Gautier case TIM6_K: 125433667d29SYann Gautier case TIM7_K: 125533667d29SYann Gautier case TIM12_K: 125633667d29SYann Gautier case TIM13_K: 125733667d29SYann Gautier case TIM14_K: 125833667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) & 125933667d29SYann Gautier RCC_APBXDIV_MASK; 126033667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & 126133667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 126233667d29SYann Gautier break; 126333667d29SYann Gautier 126433667d29SYann Gautier case TIM1_K: 126533667d29SYann Gautier case TIM8_K: 126633667d29SYann Gautier case TIM15_K: 126733667d29SYann Gautier case TIM16_K: 126833667d29SYann Gautier case TIM17_K: 126933667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) & 127033667d29SYann Gautier RCC_APBXDIV_MASK; 127133667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & 127233667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 127333667d29SYann Gautier break; 127433667d29SYann Gautier 127533667d29SYann Gautier default: 127633667d29SYann Gautier return parent_rate; 127733667d29SYann Gautier } 127833667d29SYann Gautier 127933667d29SYann Gautier if (prescaler == 0U) { 128033667d29SYann Gautier return parent_rate; 128133667d29SYann Gautier } 128233667d29SYann Gautier 128333667d29SYann Gautier return parent_rate * (timpre + 1U) * 2U; 12847839a050SYann Gautier } 12857839a050SYann Gautier 12860d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) 12877839a050SYann Gautier { 12880d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12897839a050SYann Gautier 12900d21680cSYann Gautier if (enable) { 12917839a050SYann Gautier mmio_setbits_32(address, mask_on); 12927839a050SYann Gautier } else { 12937839a050SYann Gautier mmio_clrbits_32(address, mask_on); 12947839a050SYann Gautier } 12957839a050SYann Gautier } 12967839a050SYann Gautier 12970d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) 12987839a050SYann Gautier { 12990d21680cSYann Gautier uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; 13000d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 13010d21680cSYann Gautier 13020d21680cSYann Gautier mmio_write_32(address, mask_on); 13037839a050SYann Gautier } 13047839a050SYann Gautier 13050d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) 13067839a050SYann Gautier { 1307dfdb057aSYann Gautier uint64_t timeout; 13087839a050SYann Gautier uint32_t mask_test; 13090d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 13107839a050SYann Gautier 13110d21680cSYann Gautier if (enable) { 13127839a050SYann Gautier mask_test = mask_rdy; 13137839a050SYann Gautier } else { 13147839a050SYann Gautier mask_test = 0; 13157839a050SYann Gautier } 13167839a050SYann Gautier 1317dfdb057aSYann Gautier timeout = timeout_init_us(OSCRDY_TIMEOUT); 13187839a050SYann Gautier while ((mmio_read_32(address) & mask_rdy) != mask_test) { 1319dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 13200d21680cSYann Gautier ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", 13217839a050SYann Gautier mask_rdy, address, enable, mmio_read_32(address)); 13227839a050SYann Gautier return -ETIMEDOUT; 13237839a050SYann Gautier } 13247839a050SYann Gautier } 13257839a050SYann Gautier 13267839a050SYann Gautier return 0; 13277839a050SYann Gautier } 13287839a050SYann Gautier 13290d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) 13307839a050SYann Gautier { 13317839a050SYann Gautier uint32_t value; 13320d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13337839a050SYann Gautier 13340d21680cSYann Gautier if (digbyp) { 13350d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); 13360d21680cSYann Gautier } 13370d21680cSYann Gautier 13380d21680cSYann Gautier if (bypass || digbyp) { 13390d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); 13407839a050SYann Gautier } 13417839a050SYann Gautier 13427839a050SYann Gautier /* 13437839a050SYann Gautier * Warning: not recommended to switch directly from "high drive" 13447839a050SYann Gautier * to "medium low drive", and vice-versa. 13457839a050SYann Gautier */ 13460d21680cSYann Gautier value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> 13477839a050SYann Gautier RCC_BDCR_LSEDRV_SHIFT; 13487839a050SYann Gautier 13497839a050SYann Gautier while (value != lsedrv) { 13507839a050SYann Gautier if (value > lsedrv) { 13517839a050SYann Gautier value--; 13527839a050SYann Gautier } else { 13537839a050SYann Gautier value++; 13547839a050SYann Gautier } 13557839a050SYann Gautier 13560d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_BDCR, 13577839a050SYann Gautier RCC_BDCR_LSEDRV_MASK, 13587839a050SYann Gautier value << RCC_BDCR_LSEDRV_SHIFT); 13597839a050SYann Gautier } 13607839a050SYann Gautier 13610d21680cSYann Gautier stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); 13627839a050SYann Gautier } 13637839a050SYann Gautier 13640d21680cSYann Gautier static void stm32mp1_lse_wait(void) 13657839a050SYann Gautier { 13660d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { 13677839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13687839a050SYann Gautier } 13697839a050SYann Gautier } 13707839a050SYann Gautier 13710d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable) 13727839a050SYann Gautier { 13730d21680cSYann Gautier stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); 13740d21680cSYann Gautier 13750d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { 13767839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13777839a050SYann Gautier } 13787839a050SYann Gautier } 13797839a050SYann Gautier 13800d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) 13817839a050SYann Gautier { 13820d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13830d21680cSYann Gautier 13840d21680cSYann Gautier if (digbyp) { 13850d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); 13867839a050SYann Gautier } 13877839a050SYann Gautier 13880d21680cSYann Gautier if (bypass || digbyp) { 13890d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); 13900d21680cSYann Gautier } 13910d21680cSYann Gautier 13920d21680cSYann Gautier stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); 13930d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { 13947839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13957839a050SYann Gautier } 13967839a050SYann Gautier 13977839a050SYann Gautier if (css) { 13980d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); 13997839a050SYann Gautier } 140031e9750bSLionel Debieve 140131e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER 140231e9750bSLionel Debieve if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) && 140331e9750bSLionel Debieve (!(digbyp || bypass))) { 140431e9750bSLionel Debieve panic(); 140531e9750bSLionel Debieve } 140631e9750bSLionel Debieve #endif 14077839a050SYann Gautier } 14087839a050SYann Gautier 14090d21680cSYann Gautier static void stm32mp1_csi_set(bool enable) 14107839a050SYann Gautier { 14110d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); 14120d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { 14137839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14147839a050SYann Gautier } 14157839a050SYann Gautier } 14167839a050SYann Gautier 14170d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable) 14187839a050SYann Gautier { 14190d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); 14200d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { 14217839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 14227839a050SYann Gautier } 14237839a050SYann Gautier } 14247839a050SYann Gautier 14250d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv) 14267839a050SYann Gautier { 1427dfdb057aSYann Gautier uint64_t timeout; 14280d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14290d21680cSYann Gautier uintptr_t address = rcc_base + RCC_OCRDYR; 14307839a050SYann Gautier 14310d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, 14327839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK, 14337839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); 14347839a050SYann Gautier 1435dfdb057aSYann Gautier timeout = timeout_init_us(HSIDIV_TIMEOUT); 14367839a050SYann Gautier while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { 1437dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 14380d21680cSYann Gautier ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", 14397839a050SYann Gautier address, mmio_read_32(address)); 14407839a050SYann Gautier return -ETIMEDOUT; 14417839a050SYann Gautier } 14427839a050SYann Gautier } 14437839a050SYann Gautier 14447839a050SYann Gautier return 0; 14457839a050SYann Gautier } 14467839a050SYann Gautier 14470d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq) 14487839a050SYann Gautier { 14497839a050SYann Gautier uint8_t hsidiv; 14507839a050SYann Gautier uint32_t hsidivfreq = MAX_HSI_HZ; 14517839a050SYann Gautier 14527839a050SYann Gautier for (hsidiv = 0; hsidiv < 4U; hsidiv++) { 14537839a050SYann Gautier if (hsidivfreq == hsifreq) { 14547839a050SYann Gautier break; 14557839a050SYann Gautier } 14567839a050SYann Gautier 14577839a050SYann Gautier hsidivfreq /= 2U; 14587839a050SYann Gautier } 14597839a050SYann Gautier 14607839a050SYann Gautier if (hsidiv == 4U) { 14617839a050SYann Gautier ERROR("Invalid clk-hsi frequency\n"); 14627839a050SYann Gautier return -1; 14637839a050SYann Gautier } 14647839a050SYann Gautier 14657839a050SYann Gautier if (hsidiv != 0U) { 14660d21680cSYann Gautier return stm32mp1_set_hsidiv(hsidiv); 14677839a050SYann Gautier } 14687839a050SYann Gautier 14697839a050SYann Gautier return 0; 14707839a050SYann Gautier } 14717839a050SYann Gautier 14720d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, 14730d21680cSYann Gautier unsigned int clksrc, 14740d21680cSYann Gautier uint32_t *pllcfg, int plloff) 14757839a050SYann Gautier { 14760d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 14770d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14780d21680cSYann Gautier uintptr_t pllxcr = rcc_base + pll->pllxcr; 14790d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 14800d21680cSYann Gautier uintptr_t clksrc_address = rcc_base + (clksrc >> 4); 14810d21680cSYann Gautier unsigned long refclk; 14820d21680cSYann Gautier uint32_t ifrge = 0U; 1483be858cffSAndre Przywara uint32_t src, value, fracv = 0; 1484be858cffSAndre Przywara void *fdt; 14857839a050SYann Gautier 14860d21680cSYann Gautier /* Check PLL output */ 14870d21680cSYann Gautier if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { 14880d21680cSYann Gautier return false; 14897839a050SYann Gautier } 14907839a050SYann Gautier 14910d21680cSYann Gautier /* Check current clksrc */ 14920d21680cSYann Gautier src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; 14930d21680cSYann Gautier if (src != (clksrc & RCC_SELR_SRC_MASK)) { 14940d21680cSYann Gautier return false; 14950d21680cSYann Gautier } 14960d21680cSYann Gautier 14970d21680cSYann Gautier /* Check Div */ 14980d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; 14990d21680cSYann Gautier 15000d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 15010d21680cSYann Gautier (pllcfg[PLLCFG_M] + 1U); 15020d21680cSYann Gautier 15030d21680cSYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 15040d21680cSYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 15050d21680cSYann Gautier return false; 15060d21680cSYann Gautier } 15070d21680cSYann Gautier 15080d21680cSYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 15090d21680cSYann Gautier ifrge = 1U; 15100d21680cSYann Gautier } 15110d21680cSYann Gautier 15120d21680cSYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 15130d21680cSYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 15140d21680cSYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 15150d21680cSYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 15160d21680cSYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 15170d21680cSYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 15180d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { 15190d21680cSYann Gautier return false; 15200d21680cSYann Gautier } 15210d21680cSYann Gautier 15220d21680cSYann Gautier /* Fractional configuration */ 1523be858cffSAndre Przywara if (fdt_get_address(&fdt) == 1) { 1524be858cffSAndre Przywara fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1525be858cffSAndre Przywara } 15260d21680cSYann Gautier 15270d21680cSYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 15280d21680cSYann Gautier value |= RCC_PLLNFRACR_FRACLE; 15290d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { 15300d21680cSYann Gautier return false; 15310d21680cSYann Gautier } 15320d21680cSYann Gautier 15330d21680cSYann Gautier /* Output config */ 15340d21680cSYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15350d21680cSYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15360d21680cSYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15370d21680cSYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15380d21680cSYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15390d21680cSYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15400d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { 15410d21680cSYann Gautier return false; 15420d21680cSYann Gautier } 15430d21680cSYann Gautier 15440d21680cSYann Gautier return true; 15450d21680cSYann Gautier } 15460d21680cSYann Gautier 15470d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) 15487839a050SYann Gautier { 15490d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15500d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 15510d21680cSYann Gautier 1552dd98aec8SYann Gautier /* Preserve RCC_PLLNCR_SSCG_CTRL value */ 1553dd98aec8SYann Gautier mmio_clrsetbits_32(pllxcr, 1554dd98aec8SYann Gautier RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 1555dd98aec8SYann Gautier RCC_PLLNCR_DIVREN, 1556dd98aec8SYann Gautier RCC_PLLNCR_PLLON); 15570d21680cSYann Gautier } 15580d21680cSYann Gautier 15590d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) 15600d21680cSYann Gautier { 15610d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15620d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1563dfdb057aSYann Gautier uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); 15647839a050SYann Gautier 15657839a050SYann Gautier /* Wait PLL lock */ 15667839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { 1567dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15680d21680cSYann Gautier ERROR("PLL%d start failed @ 0x%lx: 0x%x\n", 15697839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15707839a050SYann Gautier return -ETIMEDOUT; 15717839a050SYann Gautier } 15727839a050SYann Gautier } 15737839a050SYann Gautier 15747839a050SYann Gautier /* Start the requested output */ 15757839a050SYann Gautier mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); 15767839a050SYann Gautier 15777839a050SYann Gautier return 0; 15787839a050SYann Gautier } 15797839a050SYann Gautier 15800d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) 15817839a050SYann Gautier { 15820d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15830d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1584dfdb057aSYann Gautier uint64_t timeout; 15857839a050SYann Gautier 15867839a050SYann Gautier /* Stop all output */ 15877839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 15887839a050SYann Gautier RCC_PLLNCR_DIVREN); 15897839a050SYann Gautier 15907839a050SYann Gautier /* Stop PLL */ 15917839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); 15927839a050SYann Gautier 1593dfdb057aSYann Gautier timeout = timeout_init_us(PLLRDY_TIMEOUT); 15947839a050SYann Gautier /* Wait PLL stopped */ 15957839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { 1596dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15970d21680cSYann Gautier ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n", 15987839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15997839a050SYann Gautier return -ETIMEDOUT; 16007839a050SYann Gautier } 16017839a050SYann Gautier } 16027839a050SYann Gautier 16037839a050SYann Gautier return 0; 16047839a050SYann Gautier } 16057839a050SYann Gautier 16060d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, 16077839a050SYann Gautier uint32_t *pllcfg) 16087839a050SYann Gautier { 16090d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16100d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16117839a050SYann Gautier uint32_t value; 16127839a050SYann Gautier 16137839a050SYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 16147839a050SYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 16157839a050SYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 16167839a050SYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 16177839a050SYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 16187839a050SYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 16190d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr2, value); 16207839a050SYann Gautier } 16217839a050SYann Gautier 16220d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, 16237839a050SYann Gautier uint32_t *pllcfg, uint32_t fracv) 16247839a050SYann Gautier { 16250d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16260d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 16270d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 16287839a050SYann Gautier unsigned long refclk; 16297839a050SYann Gautier uint32_t ifrge = 0; 16307839a050SYann Gautier uint32_t src, value; 16317839a050SYann Gautier 16320d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & 16337839a050SYann Gautier RCC_SELR_REFCLK_SRC_MASK; 16347839a050SYann Gautier 16350d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 16367839a050SYann Gautier (pllcfg[PLLCFG_M] + 1U); 16377839a050SYann Gautier 16387839a050SYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 16397839a050SYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 16407839a050SYann Gautier return -EINVAL; 16417839a050SYann Gautier } 16427839a050SYann Gautier 16437839a050SYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 16447839a050SYann Gautier ifrge = 1U; 16457839a050SYann Gautier } 16467839a050SYann Gautier 16477839a050SYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 16487839a050SYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 16497839a050SYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 16507839a050SYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 16517839a050SYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 16527839a050SYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 16530d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr1, value); 16547839a050SYann Gautier 16557839a050SYann Gautier /* Fractional configuration */ 16567839a050SYann Gautier value = 0; 16570d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16587839a050SYann Gautier 16597839a050SYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 16600d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16617839a050SYann Gautier 16627839a050SYann Gautier value |= RCC_PLLNFRACR_FRACLE; 16630d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16647839a050SYann Gautier 16650d21680cSYann Gautier stm32mp1_pll_config_output(pll_id, pllcfg); 16667839a050SYann Gautier 16677839a050SYann Gautier return 0; 16687839a050SYann Gautier } 16697839a050SYann Gautier 16700d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) 16717839a050SYann Gautier { 16720d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16737839a050SYann Gautier uint32_t pllxcsg = 0; 16747839a050SYann Gautier 16757839a050SYann Gautier pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & 16767839a050SYann Gautier RCC_PLLNCSGR_MOD_PER_MASK; 16777839a050SYann Gautier 16787839a050SYann Gautier pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & 16797839a050SYann Gautier RCC_PLLNCSGR_INC_STEP_MASK; 16807839a050SYann Gautier 16817839a050SYann Gautier pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & 16827839a050SYann Gautier RCC_PLLNCSGR_SSCG_MODE_MASK; 16837839a050SYann Gautier 16840d21680cSYann Gautier mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); 1685dd98aec8SYann Gautier 1686dd98aec8SYann Gautier mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, 1687dd98aec8SYann Gautier RCC_PLLNCR_SSCG_CTRL); 16887839a050SYann Gautier } 16897839a050SYann Gautier 16900d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc) 16917839a050SYann Gautier { 16920d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 1693dfdb057aSYann Gautier uint64_t timeout; 16947839a050SYann Gautier 16950d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, 16967839a050SYann Gautier clksrc & RCC_SELR_SRC_MASK); 16977839a050SYann Gautier 1698dfdb057aSYann Gautier timeout = timeout_init_us(CLKSRC_TIMEOUT); 16990d21680cSYann Gautier while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { 1700dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17010d21680cSYann Gautier ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, 17020d21680cSYann Gautier clksrc_address, mmio_read_32(clksrc_address)); 17037839a050SYann Gautier return -ETIMEDOUT; 17047839a050SYann Gautier } 17057839a050SYann Gautier } 17067839a050SYann Gautier 17077839a050SYann Gautier return 0; 17087839a050SYann Gautier } 17097839a050SYann Gautier 17100d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) 17117839a050SYann Gautier { 1712dfdb057aSYann Gautier uint64_t timeout; 17137839a050SYann Gautier 17147839a050SYann Gautier mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, 17157839a050SYann Gautier clkdiv & RCC_DIVR_DIV_MASK); 17167839a050SYann Gautier 1717dfdb057aSYann Gautier timeout = timeout_init_us(CLKDIV_TIMEOUT); 17187839a050SYann Gautier while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { 1719dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 17200d21680cSYann Gautier ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", 17217839a050SYann Gautier clkdiv, address, mmio_read_32(address)); 17227839a050SYann Gautier return -ETIMEDOUT; 17237839a050SYann Gautier } 17247839a050SYann Gautier } 17257839a050SYann Gautier 17267839a050SYann Gautier return 0; 17277839a050SYann Gautier } 17287839a050SYann Gautier 17290d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) 17307839a050SYann Gautier { 17310d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 17327839a050SYann Gautier 17337839a050SYann Gautier /* 17347839a050SYann Gautier * Binding clksrc : 17357839a050SYann Gautier * bit15-4 offset 17367839a050SYann Gautier * bit3: disable 17377839a050SYann Gautier * bit2-0: MCOSEL[2:0] 17387839a050SYann Gautier */ 17397839a050SYann Gautier if ((clksrc & 0x8U) != 0U) { 17400d21680cSYann Gautier mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17417839a050SYann Gautier } else { 17420d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17437839a050SYann Gautier RCC_MCOCFG_MCOSRC_MASK, 17447839a050SYann Gautier clksrc & RCC_MCOCFG_MCOSRC_MASK); 17450d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17467839a050SYann Gautier RCC_MCOCFG_MCODIV_MASK, 17477839a050SYann Gautier clkdiv << RCC_MCOCFG_MCODIV_SHIFT); 17480d21680cSYann Gautier mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17497839a050SYann Gautier } 17507839a050SYann Gautier } 17517839a050SYann Gautier 17520d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) 17537839a050SYann Gautier { 17540d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; 17557839a050SYann Gautier 17567839a050SYann Gautier if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || 17577839a050SYann Gautier (clksrc != (uint32_t)CLK_RTC_DISABLED)) { 17587839a050SYann Gautier mmio_clrsetbits_32(address, 17597839a050SYann Gautier RCC_BDCR_RTCSRC_MASK, 176015509093SYann Gautier (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); 17617839a050SYann Gautier 17627839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_RTCCKEN); 17637839a050SYann Gautier } 17647839a050SYann Gautier 17657839a050SYann Gautier if (lse_css) { 17667839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_LSECSSON); 17677839a050SYann Gautier } 17687839a050SYann Gautier } 17697839a050SYann Gautier 17700d21680cSYann Gautier static void stm32mp1_stgen_config(void) 17717839a050SYann Gautier { 17727839a050SYann Gautier uint32_t cntfid0; 17737839a050SYann Gautier unsigned long rate; 17747839a050SYann Gautier unsigned long long counter; 17757839a050SYann Gautier 1776ade9ce03SYann Gautier cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF); 17770d21680cSYann Gautier rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); 17780d21680cSYann Gautier 17790d21680cSYann Gautier if (cntfid0 == rate) { 17800d21680cSYann Gautier return; 17810d21680cSYann Gautier } 17820d21680cSYann Gautier 1783ade9ce03SYann Gautier mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 1784ade9ce03SYann Gautier counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF); 1785ade9ce03SYann Gautier counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF)) << 32; 17867839a050SYann Gautier counter = (counter * rate / cntfid0); 17870d21680cSYann Gautier 1788ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter); 1789ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32)); 1790ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTFID_OFF, rate); 1791ade9ce03SYann Gautier mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 17927839a050SYann Gautier 17937839a050SYann Gautier write_cntfrq((u_register_t)rate); 17947839a050SYann Gautier 17957839a050SYann Gautier /* Need to update timer with new frequency */ 17967839a050SYann Gautier generic_delay_timer_init(); 17977839a050SYann Gautier } 17987839a050SYann Gautier 17997839a050SYann Gautier void stm32mp1_stgen_increment(unsigned long long offset_in_ms) 18007839a050SYann Gautier { 18017839a050SYann Gautier unsigned long long cnt; 18027839a050SYann Gautier 1803ade9ce03SYann Gautier cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) | 1804ade9ce03SYann Gautier mmio_read_32(STGEN_BASE + CNTCVL_OFF); 18057839a050SYann Gautier 1806ade9ce03SYann Gautier cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U; 18077839a050SYann Gautier 1808ade9ce03SYann Gautier mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 1809ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt); 1810ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32)); 1811ade9ce03SYann Gautier mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 18127839a050SYann Gautier } 18137839a050SYann Gautier 18140d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs) 18157839a050SYann Gautier { 18160d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); 18177839a050SYann Gautier uint32_t value = pkcs & 0xFU; 18187839a050SYann Gautier uint32_t mask = 0xFU; 18197839a050SYann Gautier 18207839a050SYann Gautier if ((pkcs & BIT(31)) != 0U) { 18217839a050SYann Gautier mask <<= 4; 18227839a050SYann Gautier value <<= 4; 18237839a050SYann Gautier } 18247839a050SYann Gautier 18257839a050SYann Gautier mmio_clrsetbits_32(address, mask, value); 18267839a050SYann Gautier } 18277839a050SYann Gautier 1828964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, 1829964e5ff1SNicolas Le Bayon uint32_t *fracv, uint32_t *csg, 1830964e5ff1SNicolas Le Bayon bool *csg_set) 1831964e5ff1SNicolas Le Bayon { 1832964e5ff1SNicolas Le Bayon void *fdt; 1833964e5ff1SNicolas Le Bayon int ret; 1834964e5ff1SNicolas Le Bayon 1835964e5ff1SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 1836964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1837964e5ff1SNicolas Le Bayon } 1838964e5ff1SNicolas Le Bayon 1839964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB, 1840964e5ff1SNicolas Le Bayon pllcfg); 1841964e5ff1SNicolas Le Bayon if (ret < 0) { 1842964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1843964e5ff1SNicolas Le Bayon } 1844964e5ff1SNicolas Le Bayon 1845964e5ff1SNicolas Le Bayon *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1846964e5ff1SNicolas Le Bayon 1847964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB, 1848964e5ff1SNicolas Le Bayon csg); 1849964e5ff1SNicolas Le Bayon 1850964e5ff1SNicolas Le Bayon *csg_set = (ret == 0); 1851964e5ff1SNicolas Le Bayon 1852964e5ff1SNicolas Le Bayon if (ret == -FDT_ERR_NOTFOUND) { 1853964e5ff1SNicolas Le Bayon ret = 0; 1854964e5ff1SNicolas Le Bayon } 1855964e5ff1SNicolas Le Bayon 1856964e5ff1SNicolas Le Bayon return ret; 1857964e5ff1SNicolas Le Bayon } 1858964e5ff1SNicolas Le Bayon 18597839a050SYann Gautier int stm32mp1_clk_init(void) 18607839a050SYann Gautier { 18610d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 1862964e5ff1SNicolas Le Bayon uint32_t pllfracv[_PLL_NB]; 1863964e5ff1SNicolas Le Bayon uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; 18647839a050SYann Gautier unsigned int clksrc[CLKSRC_NB]; 18657839a050SYann Gautier unsigned int clkdiv[CLKDIV_NB]; 18667839a050SYann Gautier unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; 18677839a050SYann Gautier int plloff[_PLL_NB]; 18687839a050SYann Gautier int ret, len; 18697839a050SYann Gautier enum stm32mp1_pll_id i; 1870964e5ff1SNicolas Le Bayon bool pllcsg_set[_PLL_NB]; 1871964e5ff1SNicolas Le Bayon bool pllcfg_valid[_PLL_NB]; 18727839a050SYann Gautier bool lse_css = false; 18730d21680cSYann Gautier bool pll3_preserve = false; 18740d21680cSYann Gautier bool pll4_preserve = false; 18750d21680cSYann Gautier bool pll4_bootrom = false; 18763e6fab43SYann Gautier const fdt32_t *pkcs_cell; 187752a616b4SAndre Przywara void *fdt; 1878bf1af154SPatrick Delaunay int stgen_p = stm32mp1_clk_get_parent(STGEN_K); 1879bf1af154SPatrick Delaunay int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K); 188052a616b4SAndre Przywara 188152a616b4SAndre Przywara if (fdt_get_address(&fdt) == 0) { 18828f97c4faSYann Gautier return -FDT_ERR_NOTFOUND; 188352a616b4SAndre Przywara } 18847839a050SYann Gautier 18857839a050SYann Gautier /* Check status field to disable security */ 18867839a050SYann Gautier if (!fdt_get_rcc_secure_status()) { 18870d21680cSYann Gautier mmio_write_32(rcc_base + RCC_TZCR, 0); 18887839a050SYann Gautier } 18897839a050SYann Gautier 189052a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, 189152a616b4SAndre Przywara clksrc); 18927839a050SYann Gautier if (ret < 0) { 18937839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18947839a050SYann Gautier } 18957839a050SYann Gautier 189652a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, 189752a616b4SAndre Przywara clkdiv); 18987839a050SYann Gautier if (ret < 0) { 18997839a050SYann Gautier return -FDT_ERR_NOTFOUND; 19007839a050SYann Gautier } 19017839a050SYann Gautier 19027839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19037839a050SYann Gautier char name[12]; 19047839a050SYann Gautier 190539b6cc66SAntonio Nino Diaz snprintf(name, sizeof(name), "st,pll@%d", i); 19067839a050SYann Gautier plloff[i] = fdt_rcc_subnode_offset(name); 19077839a050SYann Gautier 1908964e5ff1SNicolas Le Bayon pllcfg_valid[i] = fdt_check_node(plloff[i]); 1909964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 19107839a050SYann Gautier continue; 19117839a050SYann Gautier } 19127839a050SYann Gautier 1913964e5ff1SNicolas Le Bayon ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], 1914964e5ff1SNicolas Le Bayon &pllfracv[i], pllcsg[i], 1915964e5ff1SNicolas Le Bayon &pllcsg_set[i]); 1916964e5ff1SNicolas Le Bayon if (ret != 0) { 1917964e5ff1SNicolas Le Bayon return ret; 19187839a050SYann Gautier } 19197839a050SYann Gautier } 19207839a050SYann Gautier 19210d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); 19220d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); 19237839a050SYann Gautier 19247839a050SYann Gautier /* 19257839a050SYann Gautier * Switch ON oscillator found in device-tree. 19267839a050SYann Gautier * Note: HSI already ON after BootROM stage. 19277839a050SYann Gautier */ 19280d21680cSYann Gautier if (stm32mp1_osc[_LSI] != 0U) { 19290d21680cSYann Gautier stm32mp1_lsi_set(true); 19307839a050SYann Gautier } 19310d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 1932b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_LSE]; 19330d21680cSYann Gautier bool bypass, digbyp; 19347839a050SYann Gautier uint32_t lsedrv; 19357839a050SYann Gautier 1936b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1937b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1938b208e3daSGabriel Fernandez lse_css = fdt_clk_read_bool(name, "st,css"); 1939b208e3daSGabriel Fernandez lsedrv = fdt_clk_read_uint32_default(name, "st,drive", 19407839a050SYann Gautier LSEDRV_MEDIUM_HIGH); 19410d21680cSYann Gautier stm32mp1_lse_enable(bypass, digbyp, lsedrv); 19427839a050SYann Gautier } 19430d21680cSYann Gautier if (stm32mp1_osc[_HSE] != 0U) { 1944b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_HSE]; 19450d21680cSYann Gautier bool bypass, digbyp, css; 19467839a050SYann Gautier 1947b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1948b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1949b208e3daSGabriel Fernandez css = fdt_clk_read_bool(name, "st,css"); 19500d21680cSYann Gautier stm32mp1_hse_enable(bypass, digbyp, css); 19517839a050SYann Gautier } 19527839a050SYann Gautier /* 19537839a050SYann Gautier * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) 19547839a050SYann Gautier * => switch on CSI even if node is not present in device tree 19557839a050SYann Gautier */ 19560d21680cSYann Gautier stm32mp1_csi_set(true); 19577839a050SYann Gautier 19587839a050SYann Gautier /* Come back to HSI */ 19590d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_MPU_HSI); 19607839a050SYann Gautier if (ret != 0) { 19617839a050SYann Gautier return ret; 19627839a050SYann Gautier } 19630d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_AXI_HSI); 19647839a050SYann Gautier if (ret != 0) { 19657839a050SYann Gautier return ret; 19667839a050SYann Gautier } 1967b053a22eSYann Gautier ret = stm32mp1_set_clksrc(CLK_MCU_HSI); 1968b053a22eSYann Gautier if (ret != 0) { 1969b053a22eSYann Gautier return ret; 1970b053a22eSYann Gautier } 19717839a050SYann Gautier 19720d21680cSYann Gautier if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & 19730d21680cSYann Gautier RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { 19740d21680cSYann Gautier pll3_preserve = stm32mp1_check_pll_conf(_PLL3, 19750d21680cSYann Gautier clksrc[CLKSRC_PLL3], 19760d21680cSYann Gautier pllcfg[_PLL3], 19770d21680cSYann Gautier plloff[_PLL3]); 19780d21680cSYann Gautier pll4_preserve = stm32mp1_check_pll_conf(_PLL4, 19790d21680cSYann Gautier clksrc[CLKSRC_PLL4], 19800d21680cSYann Gautier pllcfg[_PLL4], 19810d21680cSYann Gautier plloff[_PLL4]); 19820d21680cSYann Gautier } 1983bf1af154SPatrick Delaunay /* Don't initialize PLL4, when used by BOOTROM */ 1984bf1af154SPatrick Delaunay if ((stm32mp_get_boot_itf_selected() == 1985bf1af154SPatrick Delaunay BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) && 1986bf1af154SPatrick Delaunay ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { 1987bf1af154SPatrick Delaunay pll4_bootrom = true; 1988bf1af154SPatrick Delaunay pll4_preserve = true; 1989bf1af154SPatrick Delaunay } 19900d21680cSYann Gautier 19917839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19920d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 19930d21680cSYann Gautier ((i == _PLL4) && pll4_preserve)) { 19947839a050SYann Gautier continue; 19950d21680cSYann Gautier } 19960d21680cSYann Gautier 19970d21680cSYann Gautier ret = stm32mp1_pll_stop(i); 19987839a050SYann Gautier if (ret != 0) { 19997839a050SYann Gautier return ret; 20007839a050SYann Gautier } 20017839a050SYann Gautier } 20027839a050SYann Gautier 20037839a050SYann Gautier /* Configure HSIDIV */ 20040d21680cSYann Gautier if (stm32mp1_osc[_HSI] != 0U) { 20050d21680cSYann Gautier ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); 20067839a050SYann Gautier if (ret != 0) { 20077839a050SYann Gautier return ret; 20087839a050SYann Gautier } 20090d21680cSYann Gautier stm32mp1_stgen_config(); 20107839a050SYann Gautier } 20117839a050SYann Gautier 20127839a050SYann Gautier /* Select DIV */ 20137839a050SYann Gautier /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ 20140d21680cSYann Gautier mmio_write_32(rcc_base + RCC_MPCKDIVR, 20157839a050SYann Gautier clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 20160d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); 20177839a050SYann Gautier if (ret != 0) { 20187839a050SYann Gautier return ret; 20197839a050SYann Gautier } 20200d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); 20217839a050SYann Gautier if (ret != 0) { 20227839a050SYann Gautier return ret; 20237839a050SYann Gautier } 20240d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); 20257839a050SYann Gautier if (ret != 0) { 20267839a050SYann Gautier return ret; 20277839a050SYann Gautier } 2028b053a22eSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); 2029b053a22eSYann Gautier if (ret != 0) { 2030b053a22eSYann Gautier return ret; 2031b053a22eSYann Gautier } 20320d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); 20337839a050SYann Gautier if (ret != 0) { 20347839a050SYann Gautier return ret; 20357839a050SYann Gautier } 20360d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); 20377839a050SYann Gautier if (ret != 0) { 20387839a050SYann Gautier return ret; 20397839a050SYann Gautier } 20400d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); 20417839a050SYann Gautier if (ret != 0) { 20427839a050SYann Gautier return ret; 20437839a050SYann Gautier } 20447839a050SYann Gautier 20457839a050SYann Gautier /* No ready bit for RTC */ 20460d21680cSYann Gautier mmio_write_32(rcc_base + RCC_RTCDIVR, 20477839a050SYann Gautier clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); 20487839a050SYann Gautier 20497839a050SYann Gautier /* Configure PLLs source */ 20500d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); 20517839a050SYann Gautier if (ret != 0) { 20527839a050SYann Gautier return ret; 20537839a050SYann Gautier } 20547839a050SYann Gautier 20550d21680cSYann Gautier if (!pll3_preserve) { 20560d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); 20577839a050SYann Gautier if (ret != 0) { 20587839a050SYann Gautier return ret; 20597839a050SYann Gautier } 20600d21680cSYann Gautier } 20610d21680cSYann Gautier 20620d21680cSYann Gautier if (!pll4_preserve) { 20630d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); 20640d21680cSYann Gautier if (ret != 0) { 20650d21680cSYann Gautier return ret; 20660d21680cSYann Gautier } 20670d21680cSYann Gautier } 20687839a050SYann Gautier 20697839a050SYann Gautier /* Configure and start PLLs */ 20707839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 20710d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 20720d21680cSYann Gautier ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { 20730d21680cSYann Gautier continue; 20740d21680cSYann Gautier } 20750d21680cSYann Gautier 2076964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20777839a050SYann Gautier continue; 20787839a050SYann Gautier } 20797839a050SYann Gautier 20800d21680cSYann Gautier if ((i == _PLL4) && pll4_bootrom) { 20810d21680cSYann Gautier /* Set output divider if not done by the Bootrom */ 20820d21680cSYann Gautier stm32mp1_pll_config_output(i, pllcfg[i]); 20830d21680cSYann Gautier continue; 20840d21680cSYann Gautier } 20850d21680cSYann Gautier 2086964e5ff1SNicolas Le Bayon ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); 20877839a050SYann Gautier if (ret != 0) { 20887839a050SYann Gautier return ret; 20897839a050SYann Gautier } 2090964e5ff1SNicolas Le Bayon 2091964e5ff1SNicolas Le Bayon if (pllcsg_set[i]) { 2092964e5ff1SNicolas Le Bayon stm32mp1_pll_csg(i, pllcsg[i]); 20937839a050SYann Gautier } 20947839a050SYann Gautier 20950d21680cSYann Gautier stm32mp1_pll_start(i); 20967839a050SYann Gautier } 20977839a050SYann Gautier /* Wait and start PLLs ouptut when ready */ 20987839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 2099964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 21007839a050SYann Gautier continue; 21017839a050SYann Gautier } 21027839a050SYann Gautier 21030d21680cSYann Gautier ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); 21047839a050SYann Gautier if (ret != 0) { 21057839a050SYann Gautier return ret; 21067839a050SYann Gautier } 21077839a050SYann Gautier } 21087839a050SYann Gautier /* Wait LSE ready before to use it */ 21090d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 21100d21680cSYann Gautier stm32mp1_lse_wait(); 21117839a050SYann Gautier } 21127839a050SYann Gautier 21137839a050SYann Gautier /* Configure with expected clock source */ 21140d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); 21157839a050SYann Gautier if (ret != 0) { 21167839a050SYann Gautier return ret; 21177839a050SYann Gautier } 21180d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); 21197839a050SYann Gautier if (ret != 0) { 21207839a050SYann Gautier return ret; 21217839a050SYann Gautier } 2122b053a22eSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); 2123b053a22eSYann Gautier if (ret != 0) { 2124b053a22eSYann Gautier return ret; 2125b053a22eSYann Gautier } 21260d21680cSYann Gautier stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); 21277839a050SYann Gautier 21287839a050SYann Gautier /* Configure PKCK */ 21297839a050SYann Gautier pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); 21307839a050SYann Gautier if (pkcs_cell != NULL) { 21317839a050SYann Gautier bool ckper_disabled = false; 21327839a050SYann Gautier uint32_t j; 2133bf1af154SPatrick Delaunay uint32_t usbreg_bootrom = 0U; 2134bf1af154SPatrick Delaunay 2135bf1af154SPatrick Delaunay if (pll4_bootrom) { 2136bf1af154SPatrick Delaunay usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); 2137bf1af154SPatrick Delaunay } 21387839a050SYann Gautier 21397839a050SYann Gautier for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { 21403e6fab43SYann Gautier uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); 21417839a050SYann Gautier 21427839a050SYann Gautier if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { 21437839a050SYann Gautier ckper_disabled = true; 21447839a050SYann Gautier continue; 21457839a050SYann Gautier } 21460d21680cSYann Gautier stm32mp1_pkcs_config(pkcs); 21477839a050SYann Gautier } 21487839a050SYann Gautier 21497839a050SYann Gautier /* 21507839a050SYann Gautier * CKPER is source for some peripheral clocks 21517839a050SYann Gautier * (FMC-NAND / QPSI-NOR) and switching source is allowed 21527839a050SYann Gautier * only if previous clock is still ON 21537839a050SYann Gautier * => deactivated CKPER only after switching clock 21547839a050SYann Gautier */ 21557839a050SYann Gautier if (ckper_disabled) { 21560d21680cSYann Gautier stm32mp1_pkcs_config(CLK_CKPER_DISABLED); 21577839a050SYann Gautier } 2158bf1af154SPatrick Delaunay 2159bf1af154SPatrick Delaunay if (pll4_bootrom) { 2160bf1af154SPatrick Delaunay uint32_t usbreg_value, usbreg_mask; 2161bf1af154SPatrick Delaunay const struct stm32mp1_clk_sel *sel; 2162bf1af154SPatrick Delaunay 2163bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBPHY_SEL); 2164bf1af154SPatrick Delaunay usbreg_mask = (uint32_t)sel->msk << sel->src; 2165bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBO_SEL); 2166bf1af154SPatrick Delaunay usbreg_mask |= (uint32_t)sel->msk << sel->src; 2167bf1af154SPatrick Delaunay 2168bf1af154SPatrick Delaunay usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & 2169bf1af154SPatrick Delaunay usbreg_mask; 2170bf1af154SPatrick Delaunay usbreg_bootrom &= usbreg_mask; 2171bf1af154SPatrick Delaunay if (usbreg_bootrom != usbreg_value) { 2172bf1af154SPatrick Delaunay VERBOSE("forbidden new USB clk path\n"); 2173bf1af154SPatrick Delaunay VERBOSE("vs bootrom on USB boot\n"); 2174bf1af154SPatrick Delaunay return -FDT_ERR_BADVALUE; 2175bf1af154SPatrick Delaunay } 2176bf1af154SPatrick Delaunay } 21777839a050SYann Gautier } 21787839a050SYann Gautier 21797839a050SYann Gautier /* Switch OFF HSI if not found in device-tree */ 21800d21680cSYann Gautier if (stm32mp1_osc[_HSI] == 0U) { 21810d21680cSYann Gautier stm32mp1_hsi_set(false); 21827839a050SYann Gautier } 21830d21680cSYann Gautier stm32mp1_stgen_config(); 21847839a050SYann Gautier 21857839a050SYann Gautier /* Software Self-Refresh mode (SSR) during DDR initilialization */ 21860d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, 21877839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_MASK, 21887839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SSR << 21897839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SHIFT); 21907839a050SYann Gautier 21917839a050SYann Gautier return 0; 21927839a050SYann Gautier } 21937839a050SYann Gautier 21947839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name, 21957839a050SYann Gautier enum stm32mp_osc_id index) 21967839a050SYann Gautier { 21977839a050SYann Gautier uint32_t frequency; 21987839a050SYann Gautier 21990d21680cSYann Gautier if (fdt_osc_read_freq(name, &frequency) == 0) { 22000d21680cSYann Gautier stm32mp1_osc[index] = frequency; 22017839a050SYann Gautier } 22027839a050SYann Gautier } 22037839a050SYann Gautier 22047839a050SYann Gautier static void stm32mp1_osc_init(void) 22057839a050SYann Gautier { 22067839a050SYann Gautier enum stm32mp_osc_id i; 22077839a050SYann Gautier 22087839a050SYann Gautier for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { 22090d21680cSYann Gautier stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); 22107839a050SYann Gautier } 22117839a050SYann Gautier } 22127839a050SYann Gautier 221337e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES 221437e8295aSEtienne Carriere /* 221537e8295aSEtienne Carriere * Get the parent ID of the target parent clock, for tagging as secure 221637e8295aSEtienne Carriere * shared clock dependencies. 221737e8295aSEtienne Carriere */ 221837e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id) 221937e8295aSEtienne Carriere { 222037e8295aSEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 222137e8295aSEtienne Carriere enum stm32mp1_pll_id pll_id; 222237e8295aSEtienne Carriere uint32_t p_sel; 222337e8295aSEtienne Carriere uintptr_t rcc_base = stm32mp_rcc_base(); 222437e8295aSEtienne Carriere 222537e8295aSEtienne Carriere switch (parent_id) { 222637e8295aSEtienne Carriere case _ACLK: 222737e8295aSEtienne Carriere case _PCLK4: 222837e8295aSEtienne Carriere case _PCLK5: 222937e8295aSEtienne Carriere s = _AXIS_SEL; 223037e8295aSEtienne Carriere break; 223137e8295aSEtienne Carriere case _PLL1_P: 223237e8295aSEtienne Carriere case _PLL1_Q: 223337e8295aSEtienne Carriere case _PLL1_R: 223437e8295aSEtienne Carriere pll_id = _PLL1; 223537e8295aSEtienne Carriere break; 223637e8295aSEtienne Carriere case _PLL2_P: 223737e8295aSEtienne Carriere case _PLL2_Q: 223837e8295aSEtienne Carriere case _PLL2_R: 223937e8295aSEtienne Carriere pll_id = _PLL2; 224037e8295aSEtienne Carriere break; 224137e8295aSEtienne Carriere case _PLL3_P: 224237e8295aSEtienne Carriere case _PLL3_Q: 224337e8295aSEtienne Carriere case _PLL3_R: 224437e8295aSEtienne Carriere pll_id = _PLL3; 224537e8295aSEtienne Carriere break; 224637e8295aSEtienne Carriere case _PLL4_P: 224737e8295aSEtienne Carriere case _PLL4_Q: 224837e8295aSEtienne Carriere case _PLL4_R: 224937e8295aSEtienne Carriere pll_id = _PLL4; 225037e8295aSEtienne Carriere break; 225137e8295aSEtienne Carriere case _PCLK1: 225237e8295aSEtienne Carriere case _PCLK2: 225337e8295aSEtienne Carriere case _HCLK2: 225437e8295aSEtienne Carriere case _HCLK6: 225537e8295aSEtienne Carriere case _CK_PER: 225637e8295aSEtienne Carriere case _CK_MPU: 225737e8295aSEtienne Carriere case _CK_MCU: 225837e8295aSEtienne Carriere case _USB_PHY_48: 225937e8295aSEtienne Carriere /* We do not expect to access these */ 226037e8295aSEtienne Carriere panic(); 226137e8295aSEtienne Carriere break; 226237e8295aSEtienne Carriere default: 226337e8295aSEtienne Carriere /* Other parents have no parent */ 226437e8295aSEtienne Carriere return -1; 226537e8295aSEtienne Carriere } 226637e8295aSEtienne Carriere 226737e8295aSEtienne Carriere if (s != _UNKNOWN_SEL) { 226837e8295aSEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 226937e8295aSEtienne Carriere 227037e8295aSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & 227137e8295aSEtienne Carriere sel->msk; 227237e8295aSEtienne Carriere 227337e8295aSEtienne Carriere if (p_sel < sel->nb_parent) { 227437e8295aSEtienne Carriere return (int)sel->parent[p_sel]; 227537e8295aSEtienne Carriere } 227637e8295aSEtienne Carriere } else { 227737e8295aSEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 227837e8295aSEtienne Carriere 227937e8295aSEtienne Carriere p_sel = mmio_read_32(rcc_base + pll->rckxselr) & 228037e8295aSEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 228137e8295aSEtienne Carriere 228237e8295aSEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { 228337e8295aSEtienne Carriere return (int)pll->refclk[p_sel]; 228437e8295aSEtienne Carriere } 228537e8295aSEtienne Carriere } 228637e8295aSEtienne Carriere 228737e8295aSEtienne Carriere VERBOSE("No parent selected for %s\n", 228837e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 228937e8295aSEtienne Carriere 229037e8295aSEtienne Carriere return -1; 229137e8295aSEtienne Carriere } 229237e8295aSEtienne Carriere 229337e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id) 229437e8295aSEtienne Carriere { 229537e8295aSEtienne Carriere int grandparent_id; 229637e8295aSEtienne Carriere 229737e8295aSEtienne Carriere switch (parent_id) { 229837e8295aSEtienne Carriere case _PLL3_P: 229937e8295aSEtienne Carriere case _PLL3_Q: 230037e8295aSEtienne Carriere case _PLL3_R: 230137e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 230237e8295aSEtienne Carriere break; 230337e8295aSEtienne Carriere 230437e8295aSEtienne Carriere /* These clocks are always secure when RCC is secure */ 230537e8295aSEtienne Carriere case _ACLK: 230637e8295aSEtienne Carriere case _HCLK2: 230737e8295aSEtienne Carriere case _HCLK6: 230837e8295aSEtienne Carriere case _PCLK4: 230937e8295aSEtienne Carriere case _PCLK5: 231037e8295aSEtienne Carriere case _PLL1_P: 231137e8295aSEtienne Carriere case _PLL1_Q: 231237e8295aSEtienne Carriere case _PLL1_R: 231337e8295aSEtienne Carriere case _PLL2_P: 231437e8295aSEtienne Carriere case _PLL2_Q: 231537e8295aSEtienne Carriere case _PLL2_R: 231637e8295aSEtienne Carriere case _HSI: 231737e8295aSEtienne Carriere case _HSI_KER: 231837e8295aSEtienne Carriere case _LSI: 231937e8295aSEtienne Carriere case _CSI: 232037e8295aSEtienne Carriere case _CSI_KER: 232137e8295aSEtienne Carriere case _HSE: 232237e8295aSEtienne Carriere case _HSE_KER: 232337e8295aSEtienne Carriere case _HSE_KER_DIV2: 2324cbd2e8a6SGabriel Fernandez case _HSE_RTC: 232537e8295aSEtienne Carriere case _LSE: 232637e8295aSEtienne Carriere break; 232737e8295aSEtienne Carriere 232837e8295aSEtienne Carriere default: 232937e8295aSEtienne Carriere VERBOSE("Cannot secure parent clock %s\n", 233037e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 233137e8295aSEtienne Carriere panic(); 233237e8295aSEtienne Carriere } 233337e8295aSEtienne Carriere 233437e8295aSEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 233537e8295aSEtienne Carriere if (grandparent_id >= 0) { 233637e8295aSEtienne Carriere secure_parent_clocks(grandparent_id); 233737e8295aSEtienne Carriere } 233837e8295aSEtienne Carriere } 233937e8295aSEtienne Carriere 234037e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id) 234137e8295aSEtienne Carriere { 234237e8295aSEtienne Carriere int parent_id; 234337e8295aSEtienne Carriere 234437e8295aSEtienne Carriere if (!stm32mp1_rcc_is_secure()) { 234537e8295aSEtienne Carriere return; 234637e8295aSEtienne Carriere } 234737e8295aSEtienne Carriere 234837e8295aSEtienne Carriere switch (clock_id) { 234937e8295aSEtienne Carriere case PLL1: 235037e8295aSEtienne Carriere case PLL2: 235137e8295aSEtienne Carriere /* PLL1/PLL2 are always secure: nothing to do */ 235237e8295aSEtienne Carriere break; 235337e8295aSEtienne Carriere case PLL3: 235437e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 235537e8295aSEtienne Carriere break; 235637e8295aSEtienne Carriere case PLL4: 235737e8295aSEtienne Carriere ERROR("PLL4 cannot be secured\n"); 235837e8295aSEtienne Carriere panic(); 235937e8295aSEtienne Carriere break; 236037e8295aSEtienne Carriere default: 236137e8295aSEtienne Carriere /* Others are expected gateable clock */ 236237e8295aSEtienne Carriere parent_id = stm32mp1_clk_get_parent(clock_id); 236337e8295aSEtienne Carriere if (parent_id < 0) { 236437e8295aSEtienne Carriere INFO("No parent found for clock %lu\n", clock_id); 236537e8295aSEtienne Carriere } else { 236637e8295aSEtienne Carriere secure_parent_clocks(parent_id); 236737e8295aSEtienne Carriere } 236837e8295aSEtienne Carriere break; 236937e8295aSEtienne Carriere } 237037e8295aSEtienne Carriere } 237137e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */ 237237e8295aSEtienne Carriere 23736cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void) 23746cb45f89SYann Gautier { 2375033b6c3aSEtienne Carriere unsigned int idx; 2376033b6c3aSEtienne Carriere const unsigned long secure_enable[] = { 2377033b6c3aSEtienne Carriere AXIDCG, 2378033b6c3aSEtienne Carriere BSEC, 2379033b6c3aSEtienne Carriere DDRC1, DDRC1LP, 2380033b6c3aSEtienne Carriere DDRC2, DDRC2LP, 2381033b6c3aSEtienne Carriere DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, 2382033b6c3aSEtienne Carriere DDRPHYC, DDRPHYCLP, 2383373f06beSLionel Debieve RTCAPB, 2384033b6c3aSEtienne Carriere TZC1, TZC2, 2385033b6c3aSEtienne Carriere TZPC, 2386033b6c3aSEtienne Carriere STGEN_K, 2387033b6c3aSEtienne Carriere }; 2388033b6c3aSEtienne Carriere 2389033b6c3aSEtienne Carriere for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { 2390033b6c3aSEtienne Carriere stm32mp_clk_enable(secure_enable[idx]); 2391033b6c3aSEtienne Carriere } 23926cb45f89SYann Gautier } 23936cb45f89SYann Gautier 239433667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = { 239533667d29SYann Gautier .enable = stm32mp_clk_enable, 239633667d29SYann Gautier .disable = stm32mp_clk_disable, 239733667d29SYann Gautier .is_enabled = stm32mp_clk_is_enabled, 239833667d29SYann Gautier .get_rate = stm32mp_clk_get_rate, 239933667d29SYann Gautier .get_parent = stm32mp1_clk_get_parent, 240033667d29SYann Gautier }; 240133667d29SYann Gautier 24027839a050SYann Gautier int stm32mp1_clk_probe(void) 24037839a050SYann Gautier { 24047839a050SYann Gautier stm32mp1_osc_init(); 24057839a050SYann Gautier 24066cb45f89SYann Gautier sync_earlyboot_clocks_state(); 24076cb45f89SYann Gautier 240833667d29SYann Gautier clk_register(&stm32mp_clk_ops); 240933667d29SYann Gautier 24107839a050SYann Gautier return 0; 24117839a050SYann Gautier } 2412