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; 244*aaa09b71SYann 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 */ 270*aaa09b71SYann 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, \ 276*aaa09b71SYann 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 */ 282*aaa09b71SYann 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, \ 288*aaa09b71SYann 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 */ 294*aaa09b71SYann 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, \ 300*aaa09b71SYann 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 */ 306*aaa09b71SYann 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, \ 312*aaa09b71SYann 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 346*aaa09b71SYann Gautier #define SEC 1 347*aaa09b71SYann Gautier #define N_S 0 348*aaa09b71SYann Gautier 3497839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { 350*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK), 351*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK), 352*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK), 353*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK), 354*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), 355*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), 356*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), 357*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), 358*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK), 359*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), 360*aaa09b71SYann Gautier _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), 3617839a050SYann Gautier 362*aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), 363*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), 364*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), 365*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), 366*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), 367*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), 368*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), 369*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), 370*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), 371*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), 372*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), 3737839a050SYann Gautier 374*aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), 375*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), 3767839a050SYann Gautier 377*aaa09b71SYann Gautier _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), 378f33b2433SYann Gautier 379*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), 380*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), 381*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), 3827839a050SYann Gautier 383*aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), 384*aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), 385*aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), 386*aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL), 387*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), 388*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), 389*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), 390*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), 391*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), 392*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), 393*aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), 3947839a050SYann Gautier 395*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), 396*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), 3977839a050SYann Gautier 398*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), 399*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), 400*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), 401*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), 402*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), 403*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), 404*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), 405*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), 406*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), 407*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), 408*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), 4097839a050SYann Gautier 410*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), 411*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), 412*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), 413*aaa09b71SYann Gautier _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), 414*aaa09b71SYann Gautier _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), 4157839a050SYann Gautier 416*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), 417*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), 418*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), 419*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), 420*aaa09b71SYann Gautier _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), 4217839a050SYann Gautier 422*aaa09b71SYann Gautier _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL), 423*aaa09b71SYann Gautier _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), 4247839a050SYann Gautier }; 4257839a050SYann Gautier 4260d21680cSYann Gautier static const uint8_t i2c12_parents[] = { 4270d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4280d21680cSYann Gautier }; 4290d21680cSYann Gautier 4300d21680cSYann Gautier static const uint8_t i2c35_parents[] = { 4310d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4320d21680cSYann Gautier }; 4330d21680cSYann Gautier 4340d21680cSYann Gautier static const uint8_t stgen_parents[] = { 4350d21680cSYann Gautier _HSI_KER, _HSE_KER 4360d21680cSYann Gautier }; 4370d21680cSYann Gautier 4380d21680cSYann Gautier static const uint8_t i2c46_parents[] = { 4390d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER 4400d21680cSYann Gautier }; 4410d21680cSYann Gautier 4420d21680cSYann Gautier static const uint8_t spi6_parents[] = { 4430d21680cSYann Gautier _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q 4440d21680cSYann Gautier }; 4450d21680cSYann Gautier 4460d21680cSYann Gautier static const uint8_t usart1_parents[] = { 4470d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER 4480d21680cSYann Gautier }; 4490d21680cSYann Gautier 4500d21680cSYann Gautier static const uint8_t rng1_parents[] = { 4510d21680cSYann Gautier _CSI, _PLL4_R, _LSE, _LSI 4520d21680cSYann Gautier }; 4530d21680cSYann Gautier 4540d21680cSYann Gautier static const uint8_t uart6_parents[] = { 4550d21680cSYann Gautier _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4560d21680cSYann Gautier }; 4570d21680cSYann Gautier 4580d21680cSYann Gautier static const uint8_t uart234578_parents[] = { 4590d21680cSYann Gautier _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4600d21680cSYann Gautier }; 4610d21680cSYann Gautier 4620d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = { 4630d21680cSYann Gautier _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER 4640d21680cSYann Gautier }; 4650d21680cSYann Gautier 4660d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = { 4670d21680cSYann Gautier _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER 4680d21680cSYann Gautier }; 4690d21680cSYann Gautier 4700d21680cSYann Gautier static const uint8_t qspi_parents[] = { 4710d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4720d21680cSYann Gautier }; 4730d21680cSYann Gautier 4740d21680cSYann Gautier static const uint8_t fmc_parents[] = { 4750d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4760d21680cSYann Gautier }; 4770d21680cSYann Gautier 478b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = { 479b8fe48b6SEtienne Carriere _HSI, _HSE, _PLL2_P 4800d21680cSYann Gautier }; 4810d21680cSYann Gautier 482b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = { 483b8fe48b6SEtienne Carriere _HSI, _HSE, _CSI, _PLL3_P 484b053a22eSYann Gautier }; 485b053a22eSYann Gautier 4860d21680cSYann Gautier static const uint8_t usbphy_parents[] = { 4870d21680cSYann Gautier _HSE_KER, _PLL4_R, _HSE_KER_DIV2 4880d21680cSYann Gautier }; 4890d21680cSYann Gautier 4900d21680cSYann Gautier static const uint8_t usbo_parents[] = { 4910d21680cSYann Gautier _PLL4_R, _USB_PHY_48 4920d21680cSYann Gautier }; 4937839a050SYann Gautier 4948fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = { 4958fbcd9e4SEtienne Carriere _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ 4968fbcd9e4SEtienne Carriere }; 4978fbcd9e4SEtienne Carriere 4988fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = { 4998fbcd9e4SEtienne Carriere _HSI, _HSE, _CSI, 5008fbcd9e4SEtienne Carriere }; 5018fbcd9e4SEtienne Carriere 502016af006SEtienne Carriere static const uint8_t rtc_parents[] = { 503cbd2e8a6SGabriel Fernandez _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC 504016af006SEtienne Carriere }; 505016af006SEtienne Carriere 5067839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { 507d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), 508d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), 509d4151d2fSYann Gautier _CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents), 510d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents), 511d4151d2fSYann Gautier _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), 512d4151d2fSYann Gautier _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), 513d4151d2fSYann Gautier _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), 5148fbcd9e4SEtienne Carriere _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents), 515288f5cf2SYann Gautier _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents), 516016af006SEtienne Carriere _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents), 517d4151d2fSYann Gautier _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), 518d4151d2fSYann Gautier _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), 519d4151d2fSYann Gautier _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), 520d4151d2fSYann Gautier _CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents), 521d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents), 522d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents), 523d4151d2fSYann Gautier _CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents), 524d4151d2fSYann Gautier _CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents), 525b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents), 526b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents), 527d4151d2fSYann Gautier _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents), 528d4151d2fSYann Gautier _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents), 5297839a050SYann Gautier }; 5307839a050SYann Gautier 5317839a050SYann Gautier /* Define characteristic of PLL according type */ 5327839a050SYann Gautier #define DIVN_MIN 24 5337839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { 5347839a050SYann Gautier [PLL_800] = { 5357839a050SYann Gautier .refclk_min = 4, 5367839a050SYann Gautier .refclk_max = 16, 5377839a050SYann Gautier .divn_max = 99, 5387839a050SYann Gautier }, 5397839a050SYann Gautier [PLL_1600] = { 5407839a050SYann Gautier .refclk_min = 8, 5417839a050SYann Gautier .refclk_max = 16, 5427839a050SYann Gautier .divn_max = 199, 5437839a050SYann Gautier }, 5447839a050SYann Gautier }; 5457839a050SYann Gautier 5467839a050SYann Gautier /* PLLNCFGR2 register divider by output */ 5477839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = { 5487839a050SYann Gautier [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, 5497839a050SYann Gautier [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, 5500d21680cSYann Gautier [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, 5517839a050SYann Gautier }; 5527839a050SYann Gautier 5537839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { 5540d21680cSYann Gautier _CLK_PLL(_PLL1, PLL_1600, 5557839a050SYann Gautier RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, 5567839a050SYann Gautier RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, 5577839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5580d21680cSYann Gautier _CLK_PLL(_PLL2, PLL_1600, 5597839a050SYann Gautier RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, 5607839a050SYann Gautier RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, 5617839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5620d21680cSYann Gautier _CLK_PLL(_PLL3, PLL_800, 5637839a050SYann Gautier RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, 5647839a050SYann Gautier RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, 5657839a050SYann Gautier _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), 5660d21680cSYann Gautier _CLK_PLL(_PLL4, PLL_800, 5677839a050SYann Gautier RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, 5687839a050SYann Gautier RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, 5697839a050SYann Gautier _HSI, _HSE, _CSI, _I2S_CKIN), 5707839a050SYann Gautier }; 5717839a050SYann Gautier 5727839a050SYann Gautier /* Prescaler table lookups for clock computation */ 573b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ 574b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = { 575b053a22eSYann Gautier 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 576b053a22eSYann Gautier }; 5777839a050SYann Gautier 5787839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ 5797839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div 5807839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div 5817839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = { 5827839a050SYann Gautier 0, 1, 2, 3, 4, 4, 4, 4 5837839a050SYann Gautier }; 5847839a050SYann Gautier 5857839a050SYann Gautier /* div = /1 /2 /3 /4 */ 5867839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = { 5877839a050SYann Gautier 1, 2, 3, 4, 4, 4, 4, 4 5887839a050SYann Gautier }; 5897839a050SYann Gautier 59037e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { 59137e8295aSEtienne Carriere [_HSI] = "HSI", 59237e8295aSEtienne Carriere [_HSE] = "HSE", 59337e8295aSEtienne Carriere [_CSI] = "CSI", 59437e8295aSEtienne Carriere [_LSI] = "LSI", 59537e8295aSEtienne Carriere [_LSE] = "LSE", 59637e8295aSEtienne Carriere [_I2S_CKIN] = "I2S_CKIN", 59737e8295aSEtienne Carriere [_HSI_KER] = "HSI_KER", 59837e8295aSEtienne Carriere [_HSE_KER] = "HSE_KER", 59937e8295aSEtienne Carriere [_HSE_KER_DIV2] = "HSE_KER_DIV2", 600cbd2e8a6SGabriel Fernandez [_HSE_RTC] = "HSE_RTC", 60137e8295aSEtienne Carriere [_CSI_KER] = "CSI_KER", 60237e8295aSEtienne Carriere [_PLL1_P] = "PLL1_P", 60337e8295aSEtienne Carriere [_PLL1_Q] = "PLL1_Q", 60437e8295aSEtienne Carriere [_PLL1_R] = "PLL1_R", 60537e8295aSEtienne Carriere [_PLL2_P] = "PLL2_P", 60637e8295aSEtienne Carriere [_PLL2_Q] = "PLL2_Q", 60737e8295aSEtienne Carriere [_PLL2_R] = "PLL2_R", 60837e8295aSEtienne Carriere [_PLL3_P] = "PLL3_P", 60937e8295aSEtienne Carriere [_PLL3_Q] = "PLL3_Q", 61037e8295aSEtienne Carriere [_PLL3_R] = "PLL3_R", 61137e8295aSEtienne Carriere [_PLL4_P] = "PLL4_P", 61237e8295aSEtienne Carriere [_PLL4_Q] = "PLL4_Q", 61337e8295aSEtienne Carriere [_PLL4_R] = "PLL4_R", 61437e8295aSEtienne Carriere [_ACLK] = "ACLK", 61537e8295aSEtienne Carriere [_PCLK1] = "PCLK1", 61637e8295aSEtienne Carriere [_PCLK2] = "PCLK2", 61737e8295aSEtienne Carriere [_PCLK3] = "PCLK3", 61837e8295aSEtienne Carriere [_PCLK4] = "PCLK4", 61937e8295aSEtienne Carriere [_PCLK5] = "PCLK5", 62037e8295aSEtienne Carriere [_HCLK6] = "KCLK6", 62137e8295aSEtienne Carriere [_HCLK2] = "HCLK2", 62237e8295aSEtienne Carriere [_CK_PER] = "CK_PER", 62337e8295aSEtienne Carriere [_CK_MPU] = "CK_MPU", 62437e8295aSEtienne Carriere [_CK_MCU] = "CK_MCU", 62537e8295aSEtienne Carriere [_USB_PHY_48] = "USB_PHY_48", 62637e8295aSEtienne Carriere }; 62737e8295aSEtienne Carriere 6280d21680cSYann Gautier /* RCC clock device driver private */ 6290d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC]; 6300d21680cSYann Gautier static struct spinlock reg_lock; 6310d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES]; 6320d21680cSYann Gautier static struct spinlock refcount_lock; 6337839a050SYann Gautier 6340d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) 6350d21680cSYann Gautier { 6360d21680cSYann Gautier return &stm32mp1_clk_gate[idx]; 6370d21680cSYann Gautier } 6387839a050SYann Gautier 6390d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) 6400d21680cSYann Gautier { 6410d21680cSYann Gautier return &stm32mp1_clk_sel[idx]; 6420d21680cSYann Gautier } 6430d21680cSYann Gautier 6440d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) 6450d21680cSYann Gautier { 6460d21680cSYann Gautier return &stm32mp1_clk_pll[idx]; 6470d21680cSYann Gautier } 6480d21680cSYann Gautier 6490d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock) 6500d21680cSYann Gautier { 651e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6520d21680cSYann Gautier /* Assume interrupts are masked */ 6530d21680cSYann Gautier spin_lock(lock); 6540d21680cSYann Gautier } 655e463d3f4SYann Gautier } 6560d21680cSYann Gautier 6570d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock) 6580d21680cSYann Gautier { 659e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6600d21680cSYann Gautier spin_unlock(lock); 6610d21680cSYann Gautier } 662e463d3f4SYann Gautier } 6630d21680cSYann Gautier 6640d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void) 6650d21680cSYann Gautier { 6660d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6671bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN; 6680d21680cSYann Gautier 6691bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 6700d21680cSYann Gautier } 6710d21680cSYann Gautier 672b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void) 673b053a22eSYann Gautier { 674b053a22eSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6751bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; 676b053a22eSYann Gautier 6771bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 678b053a22eSYann Gautier } 679b053a22eSYann Gautier 6800d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void) 6810d21680cSYann Gautier { 6820d21680cSYann Gautier stm32mp1_clk_lock(®_lock); 6830d21680cSYann Gautier } 6840d21680cSYann Gautier 6850d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void) 6860d21680cSYann Gautier { 6870d21680cSYann Gautier stm32mp1_clk_unlock(®_lock); 6880d21680cSYann Gautier } 6890d21680cSYann Gautier 6900d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) 6917839a050SYann Gautier { 6927839a050SYann Gautier if (idx >= NB_OSC) { 6937839a050SYann Gautier return 0; 6947839a050SYann Gautier } 6957839a050SYann Gautier 6960d21680cSYann Gautier return stm32mp1_osc[idx]; 6977839a050SYann Gautier } 6987839a050SYann Gautier 6990d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id) 7007839a050SYann Gautier { 7010d21680cSYann Gautier unsigned int i; 7027839a050SYann Gautier 7030d21680cSYann Gautier for (i = 0U; i < NB_GATES; i++) { 7040d21680cSYann Gautier if (gate_ref(i)->index == id) { 7057839a050SYann Gautier return i; 7067839a050SYann Gautier } 7077839a050SYann Gautier } 7087839a050SYann Gautier 70944fb470bSYann Gautier ERROR("%s: clk id %lu not found\n", __func__, id); 7107839a050SYann Gautier 7117839a050SYann Gautier return -EINVAL; 7127839a050SYann Gautier } 7137839a050SYann Gautier 7140d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) 7157839a050SYann Gautier { 7160d21680cSYann Gautier return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); 7177839a050SYann Gautier } 7187839a050SYann Gautier 7190d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) 7207839a050SYann Gautier { 7210d21680cSYann Gautier return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); 7227839a050SYann Gautier } 7237839a050SYann Gautier 7240d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id) 7257839a050SYann Gautier { 7260d21680cSYann Gautier const struct stm32mp1_clk_sel *sel; 7278fbcd9e4SEtienne Carriere uint32_t p_sel; 7287839a050SYann Gautier int i; 7297839a050SYann Gautier enum stm32mp1_parent_id p; 7307839a050SYann Gautier enum stm32mp1_parent_sel s; 7310d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7327839a050SYann Gautier 7338fbcd9e4SEtienne Carriere /* Few non gateable clock have a static parent ID, find them */ 7348fbcd9e4SEtienne Carriere i = (int)clock_id2parent_id(id); 7358fbcd9e4SEtienne Carriere if (i != _UNKNOWN_ID) { 7368fbcd9e4SEtienne Carriere return i; 7377839a050SYann Gautier } 7387839a050SYann Gautier 7390d21680cSYann Gautier i = stm32mp1_clk_get_gated_id(id); 7407839a050SYann Gautier if (i < 0) { 7410d21680cSYann Gautier panic(); 7427839a050SYann Gautier } 7437839a050SYann Gautier 7440d21680cSYann Gautier p = stm32mp1_clk_get_fixed_parent(i); 7457839a050SYann Gautier if (p < _PARENT_NB) { 7467839a050SYann Gautier return (int)p; 7477839a050SYann Gautier } 7487839a050SYann Gautier 7490d21680cSYann Gautier s = stm32mp1_clk_get_sel(i); 7500d21680cSYann Gautier if (s == _UNKNOWN_SEL) { 7510d21680cSYann Gautier return -EINVAL; 7520d21680cSYann Gautier } 7537839a050SYann Gautier if (s >= _PARENT_SEL_NB) { 7540d21680cSYann Gautier panic(); 7557839a050SYann Gautier } 7567839a050SYann Gautier 7570d21680cSYann Gautier sel = clk_sel_ref(s); 7588ae08dcdSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) & 7598ae08dcdSEtienne Carriere (sel->msk << sel->src)) >> sel->src; 7600d21680cSYann Gautier if (p_sel < sel->nb_parent) { 7610d21680cSYann Gautier return (int)sel->parent[p_sel]; 7627839a050SYann Gautier } 7637839a050SYann Gautier 7647839a050SYann Gautier return -EINVAL; 7657839a050SYann Gautier } 7667839a050SYann Gautier 7670d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) 7687839a050SYann Gautier { 7690d21680cSYann Gautier uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); 7700d21680cSYann Gautier uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; 7717839a050SYann Gautier 7720d21680cSYann Gautier return stm32mp1_clk_get_fixed(pll->refclk[src]); 7737839a050SYann Gautier } 7747839a050SYann Gautier 7757839a050SYann Gautier /* 7767839a050SYann Gautier * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL 7777839a050SYann Gautier * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) 7787839a050SYann Gautier * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) 7797839a050SYann Gautier * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) 7807839a050SYann Gautier */ 7810d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) 7827839a050SYann Gautier { 7837839a050SYann Gautier unsigned long refclk, fvco; 7847839a050SYann Gautier uint32_t cfgr1, fracr, divm, divn; 7850d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7867839a050SYann Gautier 7870d21680cSYann Gautier cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); 7880d21680cSYann Gautier fracr = mmio_read_32(rcc_base + pll->pllxfracr); 7897839a050SYann Gautier 7907839a050SYann Gautier divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; 7917839a050SYann Gautier divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; 7927839a050SYann Gautier 7930d21680cSYann Gautier refclk = stm32mp1_pll_get_fref(pll); 7947839a050SYann Gautier 7957839a050SYann Gautier /* 7967839a050SYann Gautier * With FRACV : 7977839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) 7987839a050SYann Gautier * Without FRACV 7997839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) 8007839a050SYann Gautier */ 8017839a050SYann Gautier if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { 8020d21680cSYann Gautier uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> 8030d21680cSYann Gautier RCC_PLLNFRACR_FRACV_SHIFT; 8047839a050SYann Gautier unsigned long long numerator, denominator; 8057839a050SYann Gautier 8060d21680cSYann Gautier numerator = (((unsigned long long)divn + 1U) << 13) + fracv; 8070d21680cSYann Gautier numerator = refclk * numerator; 8087839a050SYann Gautier denominator = ((unsigned long long)divm + 1U) << 13; 8097839a050SYann Gautier fvco = (unsigned long)(numerator / denominator); 8107839a050SYann Gautier } else { 8117839a050SYann Gautier fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); 8127839a050SYann Gautier } 8137839a050SYann Gautier 8147839a050SYann Gautier return fvco; 8157839a050SYann Gautier } 8167839a050SYann Gautier 8170d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, 8187839a050SYann Gautier enum stm32mp1_div_id div_id) 8197839a050SYann Gautier { 8200d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 8217839a050SYann Gautier unsigned long dfout; 8227839a050SYann Gautier uint32_t cfgr2, divy; 8237839a050SYann Gautier 8247839a050SYann Gautier if (div_id >= _DIV_NB) { 8257839a050SYann Gautier return 0; 8267839a050SYann Gautier } 8277839a050SYann Gautier 8280d21680cSYann Gautier cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); 8297839a050SYann Gautier divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; 8307839a050SYann Gautier 8310d21680cSYann Gautier dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); 8327839a050SYann Gautier 8337839a050SYann Gautier return dfout; 8347839a050SYann Gautier } 8357839a050SYann Gautier 8360d21680cSYann Gautier static unsigned long get_clock_rate(int p) 8377839a050SYann Gautier { 8387839a050SYann Gautier uint32_t reg, clkdiv; 8397839a050SYann Gautier unsigned long clock = 0; 8400d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8417839a050SYann Gautier 8427839a050SYann Gautier switch (p) { 8437839a050SYann Gautier case _CK_MPU: 8447839a050SYann Gautier /* MPU sub system */ 8450d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKSELR); 8467839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8477839a050SYann Gautier case RCC_MPCKSELR_HSI: 8480d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8497839a050SYann Gautier break; 8507839a050SYann Gautier case RCC_MPCKSELR_HSE: 8510d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8527839a050SYann Gautier break; 8537839a050SYann Gautier case RCC_MPCKSELR_PLL: 8540d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8557839a050SYann Gautier break; 8567839a050SYann Gautier case RCC_MPCKSELR_PLL_MPUDIV: 8570d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8587839a050SYann Gautier 8590d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); 8607839a050SYann Gautier clkdiv = reg & RCC_MPUDIV_MASK; 861602ae2f2SGabriel Fernandez clock >>= stm32mp1_mpu_div[clkdiv]; 8627839a050SYann Gautier break; 8637839a050SYann Gautier default: 8647839a050SYann Gautier break; 8657839a050SYann Gautier } 8667839a050SYann Gautier break; 8677839a050SYann Gautier /* AXI sub system */ 8687839a050SYann Gautier case _ACLK: 8697839a050SYann Gautier case _HCLK2: 8707839a050SYann Gautier case _HCLK6: 8717839a050SYann Gautier case _PCLK4: 8727839a050SYann Gautier case _PCLK5: 8730d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); 8747839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8757839a050SYann Gautier case RCC_ASSCKSELR_HSI: 8760d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8777839a050SYann Gautier break; 8787839a050SYann Gautier case RCC_ASSCKSELR_HSE: 8790d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8807839a050SYann Gautier break; 8817839a050SYann Gautier case RCC_ASSCKSELR_PLL: 8820d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 8837839a050SYann Gautier break; 8847839a050SYann Gautier default: 8857839a050SYann Gautier break; 8867839a050SYann Gautier } 8877839a050SYann Gautier 8887839a050SYann Gautier /* System clock divider */ 8890d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_AXIDIVR); 8907839a050SYann Gautier clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; 8917839a050SYann Gautier 8927839a050SYann Gautier switch (p) { 8937839a050SYann Gautier case _PCLK4: 8940d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB4DIVR); 8957839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8967839a050SYann Gautier break; 8977839a050SYann Gautier case _PCLK5: 8980d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB5DIVR); 8997839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 9007839a050SYann Gautier break; 9017839a050SYann Gautier default: 9027839a050SYann Gautier break; 9037839a050SYann Gautier } 9047839a050SYann Gautier break; 905b053a22eSYann Gautier /* MCU sub system */ 906b053a22eSYann Gautier case _CK_MCU: 907b053a22eSYann Gautier case _PCLK1: 908b053a22eSYann Gautier case _PCLK2: 909b053a22eSYann Gautier case _PCLK3: 910b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); 911b053a22eSYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 912b053a22eSYann Gautier case RCC_MSSCKSELR_HSI: 913b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 914b053a22eSYann Gautier break; 915b053a22eSYann Gautier case RCC_MSSCKSELR_HSE: 916b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 917b053a22eSYann Gautier break; 918b053a22eSYann Gautier case RCC_MSSCKSELR_CSI: 919b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 920b053a22eSYann Gautier break; 921b053a22eSYann Gautier case RCC_MSSCKSELR_PLL: 922b053a22eSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 923b053a22eSYann Gautier break; 924b053a22eSYann Gautier default: 925b053a22eSYann Gautier break; 926b053a22eSYann Gautier } 927b053a22eSYann Gautier 928b053a22eSYann Gautier /* MCU clock divider */ 929b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MCUDIVR); 930b053a22eSYann Gautier clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; 931b053a22eSYann Gautier 932b053a22eSYann Gautier switch (p) { 933b053a22eSYann Gautier case _PCLK1: 934b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB1DIVR); 935b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 936b053a22eSYann Gautier break; 937b053a22eSYann Gautier case _PCLK2: 938b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB2DIVR); 939b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 940b053a22eSYann Gautier break; 941b053a22eSYann Gautier case _PCLK3: 942b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB3DIVR); 943b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 944b053a22eSYann Gautier break; 945b053a22eSYann Gautier case _CK_MCU: 946b053a22eSYann Gautier default: 947b053a22eSYann Gautier break; 948b053a22eSYann Gautier } 949b053a22eSYann Gautier break; 9507839a050SYann Gautier case _CK_PER: 9510d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); 9527839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 9537839a050SYann Gautier case RCC_CPERCKSELR_HSI: 9540d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9557839a050SYann Gautier break; 9567839a050SYann Gautier case RCC_CPERCKSELR_HSE: 9570d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9587839a050SYann Gautier break; 9597839a050SYann Gautier case RCC_CPERCKSELR_CSI: 9600d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9617839a050SYann Gautier break; 9627839a050SYann Gautier default: 9637839a050SYann Gautier break; 9647839a050SYann Gautier } 9657839a050SYann Gautier break; 9667839a050SYann Gautier case _HSI: 9677839a050SYann Gautier case _HSI_KER: 9680d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9697839a050SYann Gautier break; 9707839a050SYann Gautier case _CSI: 9717839a050SYann Gautier case _CSI_KER: 9720d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9737839a050SYann Gautier break; 9747839a050SYann Gautier case _HSE: 9757839a050SYann Gautier case _HSE_KER: 9760d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9777839a050SYann Gautier break; 9787839a050SYann Gautier case _HSE_KER_DIV2: 9790d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE) >> 1; 9807839a050SYann Gautier break; 981cbd2e8a6SGabriel Fernandez case _HSE_RTC: 982cbd2e8a6SGabriel Fernandez clock = stm32mp1_clk_get_fixed(_HSE); 983cbd2e8a6SGabriel Fernandez clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; 984cbd2e8a6SGabriel Fernandez break; 9857839a050SYann Gautier case _LSI: 9860d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSI); 9877839a050SYann Gautier break; 9887839a050SYann Gautier case _LSE: 9890d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSE); 9907839a050SYann Gautier break; 9917839a050SYann Gautier /* PLL */ 9927839a050SYann Gautier case _PLL1_P: 9930d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 9947839a050SYann Gautier break; 9957839a050SYann Gautier case _PLL1_Q: 9960d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); 9977839a050SYann Gautier break; 9987839a050SYann Gautier case _PLL1_R: 9990d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); 10007839a050SYann Gautier break; 10017839a050SYann Gautier case _PLL2_P: 10020d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 10037839a050SYann Gautier break; 10047839a050SYann Gautier case _PLL2_Q: 10050d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); 10067839a050SYann Gautier break; 10077839a050SYann Gautier case _PLL2_R: 10080d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); 10097839a050SYann Gautier break; 10107839a050SYann Gautier case _PLL3_P: 10110d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 10127839a050SYann Gautier break; 10137839a050SYann Gautier case _PLL3_Q: 10140d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); 10157839a050SYann Gautier break; 10167839a050SYann Gautier case _PLL3_R: 10170d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); 10187839a050SYann Gautier break; 10197839a050SYann Gautier case _PLL4_P: 10200d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); 10217839a050SYann Gautier break; 10227839a050SYann Gautier case _PLL4_Q: 10230d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); 10247839a050SYann Gautier break; 10257839a050SYann Gautier case _PLL4_R: 10260d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); 10277839a050SYann Gautier break; 10287839a050SYann Gautier /* Other */ 10297839a050SYann Gautier case _USB_PHY_48: 10300d21680cSYann Gautier clock = USB_PHY_48_MHZ; 10317839a050SYann Gautier break; 10327839a050SYann Gautier default: 10337839a050SYann Gautier break; 10347839a050SYann Gautier } 10357839a050SYann Gautier 10367839a050SYann Gautier return clock; 10377839a050SYann Gautier } 10387839a050SYann Gautier 10390d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate) 10400d21680cSYann Gautier { 10410d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10420d21680cSYann Gautier 104325be845eSEtienne Carriere VERBOSE("Enable clock %u\n", gate->index); 104425be845eSEtienne Carriere 10450d21680cSYann Gautier if (gate->set_clr != 0U) { 10460d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); 10470d21680cSYann Gautier } else { 10480d21680cSYann Gautier mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10490d21680cSYann Gautier } 10500d21680cSYann Gautier } 10510d21680cSYann Gautier 10520d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate) 10530d21680cSYann Gautier { 10540d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10550d21680cSYann Gautier 105625be845eSEtienne Carriere VERBOSE("Disable clock %u\n", gate->index); 105725be845eSEtienne Carriere 10580d21680cSYann Gautier if (gate->set_clr != 0U) { 10590d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, 10600d21680cSYann Gautier BIT(gate->bit)); 10610d21680cSYann Gautier } else { 10620d21680cSYann Gautier mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10630d21680cSYann Gautier } 10640d21680cSYann Gautier } 10650d21680cSYann Gautier 10660d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) 10670d21680cSYann Gautier { 10680d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10690d21680cSYann Gautier 10700d21680cSYann Gautier return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); 10710d21680cSYann Gautier } 10720d21680cSYann Gautier 107335848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */ 107435848200SEtienne Carriere static bool clock_is_always_on(unsigned long id) 107535848200SEtienne Carriere { 107635848200SEtienne Carriere switch (id) { 107735848200SEtienne Carriere case CK_HSE: 107835848200SEtienne Carriere case CK_CSI: 107935848200SEtienne Carriere case CK_LSI: 108035848200SEtienne Carriere case CK_LSE: 108135848200SEtienne Carriere case CK_HSI: 108235848200SEtienne Carriere case CK_HSE_DIV2: 108335848200SEtienne Carriere case PLL1_Q: 108435848200SEtienne Carriere case PLL1_R: 108535848200SEtienne Carriere case PLL2_P: 108635848200SEtienne Carriere case PLL2_Q: 108735848200SEtienne Carriere case PLL2_R: 108835848200SEtienne Carriere case PLL3_P: 108935848200SEtienne Carriere case PLL3_Q: 109035848200SEtienne Carriere case PLL3_R: 1091bf39318dSYann Gautier case CK_AXI: 1092bf39318dSYann Gautier case CK_MPU: 1093bf39318dSYann Gautier case CK_MCU: 10945b111c74SHE Shushan case RTC: 109535848200SEtienne Carriere return true; 109635848200SEtienne Carriere default: 109735848200SEtienne Carriere return false; 109835848200SEtienne Carriere } 109935848200SEtienne Carriere } 110035848200SEtienne Carriere 11012444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt) 11020d21680cSYann Gautier { 11030d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 110435848200SEtienne Carriere int i; 11050d21680cSYann Gautier 110635848200SEtienne Carriere if (clock_is_always_on(id)) { 110735848200SEtienne Carriere return; 110835848200SEtienne Carriere } 110935848200SEtienne Carriere 111035848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11110d21680cSYann Gautier if (i < 0) { 111244fb470bSYann Gautier ERROR("Clock %lu can't be enabled\n", id); 11130d21680cSYann Gautier panic(); 11140d21680cSYann Gautier } 11150d21680cSYann Gautier 11160d21680cSYann Gautier gate = gate_ref(i); 11172444d231SYann Gautier 11182444d231SYann Gautier if (!with_refcnt) { 11192444d231SYann Gautier __clk_enable(gate); 11202444d231SYann Gautier return; 11212444d231SYann Gautier } 11220d21680cSYann Gautier 11230d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11240d21680cSYann Gautier 11252444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11260d21680cSYann Gautier __clk_enable(gate); 11270d21680cSYann Gautier } 11280d21680cSYann Gautier 11292444d231SYann Gautier gate_refcounts[i]++; 11302444d231SYann Gautier if (gate_refcounts[i] == UINT_MAX) { 11312444d231SYann Gautier ERROR("Clock %lu refcount reached max value\n", id); 11322444d231SYann Gautier panic(); 11332444d231SYann Gautier } 11342444d231SYann Gautier 11350d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11360d21680cSYann Gautier } 11370d21680cSYann Gautier 11382444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt) 11390d21680cSYann Gautier { 11400d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 114135848200SEtienne Carriere int i; 11420d21680cSYann Gautier 114335848200SEtienne Carriere if (clock_is_always_on(id)) { 114435848200SEtienne Carriere return; 114535848200SEtienne Carriere } 114635848200SEtienne Carriere 114735848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11480d21680cSYann Gautier if (i < 0) { 114944fb470bSYann Gautier ERROR("Clock %lu can't be disabled\n", id); 11500d21680cSYann Gautier panic(); 11510d21680cSYann Gautier } 11520d21680cSYann Gautier 11530d21680cSYann Gautier gate = gate_ref(i); 11542444d231SYann Gautier 11552444d231SYann Gautier if (!with_refcnt) { 11562444d231SYann Gautier __clk_disable(gate); 11572444d231SYann Gautier return; 11582444d231SYann Gautier } 11590d21680cSYann Gautier 11600d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11610d21680cSYann Gautier 11622444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11632444d231SYann Gautier ERROR("Clock %lu refcount reached 0\n", id); 11642444d231SYann Gautier panic(); 11652444d231SYann Gautier } 11662444d231SYann Gautier gate_refcounts[i]--; 11672444d231SYann Gautier 11682444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11690d21680cSYann Gautier __clk_disable(gate); 11700d21680cSYann Gautier } 11710d21680cSYann Gautier 11720d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11730d21680cSYann Gautier } 11740d21680cSYann Gautier 117533667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id) 11760d21680cSYann Gautier { 11770d21680cSYann Gautier __stm32mp1_clk_enable(id, true); 117833667d29SYann Gautier 117933667d29SYann Gautier return 0; 11800d21680cSYann Gautier } 11810d21680cSYann Gautier 118233667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id) 11830d21680cSYann Gautier { 11840d21680cSYann Gautier __stm32mp1_clk_disable(id, true); 11850d21680cSYann Gautier } 11860d21680cSYann Gautier 118733667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id) 11887839a050SYann Gautier { 118935848200SEtienne Carriere int i; 11907839a050SYann Gautier 119135848200SEtienne Carriere if (clock_is_always_on(id)) { 119235848200SEtienne Carriere return true; 119335848200SEtienne Carriere } 119435848200SEtienne Carriere 119535848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11967839a050SYann Gautier if (i < 0) { 11970d21680cSYann Gautier panic(); 11987839a050SYann Gautier } 11997839a050SYann Gautier 12000d21680cSYann Gautier return __clk_is_enabled(gate_ref(i)); 12017839a050SYann Gautier } 12027839a050SYann Gautier 120333667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id) 12047839a050SYann Gautier { 120533667d29SYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 12060d21680cSYann Gautier int p = stm32mp1_clk_get_parent(id); 120733667d29SYann Gautier uint32_t prescaler, timpre; 120833667d29SYann Gautier unsigned long parent_rate; 12097839a050SYann Gautier 12107839a050SYann Gautier if (p < 0) { 12117839a050SYann Gautier return 0; 12127839a050SYann Gautier } 12137839a050SYann Gautier 121433667d29SYann Gautier parent_rate = get_clock_rate(p); 121533667d29SYann Gautier 121633667d29SYann Gautier switch (id) { 121733667d29SYann Gautier case TIM2_K: 121833667d29SYann Gautier case TIM3_K: 121933667d29SYann Gautier case TIM4_K: 122033667d29SYann Gautier case TIM5_K: 122133667d29SYann Gautier case TIM6_K: 122233667d29SYann Gautier case TIM7_K: 122333667d29SYann Gautier case TIM12_K: 122433667d29SYann Gautier case TIM13_K: 122533667d29SYann Gautier case TIM14_K: 122633667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) & 122733667d29SYann Gautier RCC_APBXDIV_MASK; 122833667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & 122933667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 123033667d29SYann Gautier break; 123133667d29SYann Gautier 123233667d29SYann Gautier case TIM1_K: 123333667d29SYann Gautier case TIM8_K: 123433667d29SYann Gautier case TIM15_K: 123533667d29SYann Gautier case TIM16_K: 123633667d29SYann Gautier case TIM17_K: 123733667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) & 123833667d29SYann Gautier RCC_APBXDIV_MASK; 123933667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & 124033667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 124133667d29SYann Gautier break; 124233667d29SYann Gautier 124333667d29SYann Gautier default: 124433667d29SYann Gautier return parent_rate; 124533667d29SYann Gautier } 124633667d29SYann Gautier 124733667d29SYann Gautier if (prescaler == 0U) { 124833667d29SYann Gautier return parent_rate; 124933667d29SYann Gautier } 125033667d29SYann Gautier 125133667d29SYann Gautier return parent_rate * (timpre + 1U) * 2U; 12527839a050SYann Gautier } 12537839a050SYann Gautier 12540d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) 12557839a050SYann Gautier { 12560d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12577839a050SYann Gautier 12580d21680cSYann Gautier if (enable) { 12597839a050SYann Gautier mmio_setbits_32(address, mask_on); 12607839a050SYann Gautier } else { 12617839a050SYann Gautier mmio_clrbits_32(address, mask_on); 12627839a050SYann Gautier } 12637839a050SYann Gautier } 12647839a050SYann Gautier 12650d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) 12667839a050SYann Gautier { 12670d21680cSYann Gautier uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; 12680d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12690d21680cSYann Gautier 12700d21680cSYann Gautier mmio_write_32(address, mask_on); 12717839a050SYann Gautier } 12727839a050SYann Gautier 12730d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) 12747839a050SYann Gautier { 1275dfdb057aSYann Gautier uint64_t timeout; 12767839a050SYann Gautier uint32_t mask_test; 12770d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12787839a050SYann Gautier 12790d21680cSYann Gautier if (enable) { 12807839a050SYann Gautier mask_test = mask_rdy; 12817839a050SYann Gautier } else { 12827839a050SYann Gautier mask_test = 0; 12837839a050SYann Gautier } 12847839a050SYann Gautier 1285dfdb057aSYann Gautier timeout = timeout_init_us(OSCRDY_TIMEOUT); 12867839a050SYann Gautier while ((mmio_read_32(address) & mask_rdy) != mask_test) { 1287dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 12880d21680cSYann Gautier ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", 12897839a050SYann Gautier mask_rdy, address, enable, mmio_read_32(address)); 12907839a050SYann Gautier return -ETIMEDOUT; 12917839a050SYann Gautier } 12927839a050SYann Gautier } 12937839a050SYann Gautier 12947839a050SYann Gautier return 0; 12957839a050SYann Gautier } 12967839a050SYann Gautier 12970d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) 12987839a050SYann Gautier { 12997839a050SYann Gautier uint32_t value; 13000d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13017839a050SYann Gautier 13020d21680cSYann Gautier if (digbyp) { 13030d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); 13040d21680cSYann Gautier } 13050d21680cSYann Gautier 13060d21680cSYann Gautier if (bypass || digbyp) { 13070d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); 13087839a050SYann Gautier } 13097839a050SYann Gautier 13107839a050SYann Gautier /* 13117839a050SYann Gautier * Warning: not recommended to switch directly from "high drive" 13127839a050SYann Gautier * to "medium low drive", and vice-versa. 13137839a050SYann Gautier */ 13140d21680cSYann Gautier value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> 13157839a050SYann Gautier RCC_BDCR_LSEDRV_SHIFT; 13167839a050SYann Gautier 13177839a050SYann Gautier while (value != lsedrv) { 13187839a050SYann Gautier if (value > lsedrv) { 13197839a050SYann Gautier value--; 13207839a050SYann Gautier } else { 13217839a050SYann Gautier value++; 13227839a050SYann Gautier } 13237839a050SYann Gautier 13240d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_BDCR, 13257839a050SYann Gautier RCC_BDCR_LSEDRV_MASK, 13267839a050SYann Gautier value << RCC_BDCR_LSEDRV_SHIFT); 13277839a050SYann Gautier } 13287839a050SYann Gautier 13290d21680cSYann Gautier stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); 13307839a050SYann Gautier } 13317839a050SYann Gautier 13320d21680cSYann Gautier static void stm32mp1_lse_wait(void) 13337839a050SYann Gautier { 13340d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { 13357839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13367839a050SYann Gautier } 13377839a050SYann Gautier } 13387839a050SYann Gautier 13390d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable) 13407839a050SYann Gautier { 13410d21680cSYann Gautier stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); 13420d21680cSYann Gautier 13430d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { 13447839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13457839a050SYann Gautier } 13467839a050SYann Gautier } 13477839a050SYann Gautier 13480d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) 13497839a050SYann Gautier { 13500d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13510d21680cSYann Gautier 13520d21680cSYann Gautier if (digbyp) { 13530d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); 13547839a050SYann Gautier } 13557839a050SYann Gautier 13560d21680cSYann Gautier if (bypass || digbyp) { 13570d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); 13580d21680cSYann Gautier } 13590d21680cSYann Gautier 13600d21680cSYann Gautier stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); 13610d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { 13627839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13637839a050SYann Gautier } 13647839a050SYann Gautier 13657839a050SYann Gautier if (css) { 13660d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); 13677839a050SYann Gautier } 136831e9750bSLionel Debieve 136931e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER 137031e9750bSLionel Debieve if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) && 137131e9750bSLionel Debieve (!(digbyp || bypass))) { 137231e9750bSLionel Debieve panic(); 137331e9750bSLionel Debieve } 137431e9750bSLionel Debieve #endif 13757839a050SYann Gautier } 13767839a050SYann Gautier 13770d21680cSYann Gautier static void stm32mp1_csi_set(bool enable) 13787839a050SYann Gautier { 13790d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); 13800d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { 13817839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13827839a050SYann Gautier } 13837839a050SYann Gautier } 13847839a050SYann Gautier 13850d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable) 13867839a050SYann Gautier { 13870d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); 13880d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { 13897839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13907839a050SYann Gautier } 13917839a050SYann Gautier } 13927839a050SYann Gautier 13930d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv) 13947839a050SYann Gautier { 1395dfdb057aSYann Gautier uint64_t timeout; 13960d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13970d21680cSYann Gautier uintptr_t address = rcc_base + RCC_OCRDYR; 13987839a050SYann Gautier 13990d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, 14007839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK, 14017839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); 14027839a050SYann Gautier 1403dfdb057aSYann Gautier timeout = timeout_init_us(HSIDIV_TIMEOUT); 14047839a050SYann Gautier while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { 1405dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 14060d21680cSYann Gautier ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", 14077839a050SYann Gautier address, mmio_read_32(address)); 14087839a050SYann Gautier return -ETIMEDOUT; 14097839a050SYann Gautier } 14107839a050SYann Gautier } 14117839a050SYann Gautier 14127839a050SYann Gautier return 0; 14137839a050SYann Gautier } 14147839a050SYann Gautier 14150d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq) 14167839a050SYann Gautier { 14177839a050SYann Gautier uint8_t hsidiv; 14187839a050SYann Gautier uint32_t hsidivfreq = MAX_HSI_HZ; 14197839a050SYann Gautier 14207839a050SYann Gautier for (hsidiv = 0; hsidiv < 4U; hsidiv++) { 14217839a050SYann Gautier if (hsidivfreq == hsifreq) { 14227839a050SYann Gautier break; 14237839a050SYann Gautier } 14247839a050SYann Gautier 14257839a050SYann Gautier hsidivfreq /= 2U; 14267839a050SYann Gautier } 14277839a050SYann Gautier 14287839a050SYann Gautier if (hsidiv == 4U) { 14297839a050SYann Gautier ERROR("Invalid clk-hsi frequency\n"); 14307839a050SYann Gautier return -1; 14317839a050SYann Gautier } 14327839a050SYann Gautier 14337839a050SYann Gautier if (hsidiv != 0U) { 14340d21680cSYann Gautier return stm32mp1_set_hsidiv(hsidiv); 14357839a050SYann Gautier } 14367839a050SYann Gautier 14377839a050SYann Gautier return 0; 14387839a050SYann Gautier } 14397839a050SYann Gautier 14400d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, 14410d21680cSYann Gautier unsigned int clksrc, 14420d21680cSYann Gautier uint32_t *pllcfg, int plloff) 14437839a050SYann Gautier { 14440d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 14450d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14460d21680cSYann Gautier uintptr_t pllxcr = rcc_base + pll->pllxcr; 14470d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 14480d21680cSYann Gautier uintptr_t clksrc_address = rcc_base + (clksrc >> 4); 14490d21680cSYann Gautier unsigned long refclk; 14500d21680cSYann Gautier uint32_t ifrge = 0U; 1451be858cffSAndre Przywara uint32_t src, value, fracv = 0; 1452be858cffSAndre Przywara void *fdt; 14537839a050SYann Gautier 14540d21680cSYann Gautier /* Check PLL output */ 14550d21680cSYann Gautier if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { 14560d21680cSYann Gautier return false; 14577839a050SYann Gautier } 14587839a050SYann Gautier 14590d21680cSYann Gautier /* Check current clksrc */ 14600d21680cSYann Gautier src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; 14610d21680cSYann Gautier if (src != (clksrc & RCC_SELR_SRC_MASK)) { 14620d21680cSYann Gautier return false; 14630d21680cSYann Gautier } 14640d21680cSYann Gautier 14650d21680cSYann Gautier /* Check Div */ 14660d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; 14670d21680cSYann Gautier 14680d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 14690d21680cSYann Gautier (pllcfg[PLLCFG_M] + 1U); 14700d21680cSYann Gautier 14710d21680cSYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 14720d21680cSYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 14730d21680cSYann Gautier return false; 14740d21680cSYann Gautier } 14750d21680cSYann Gautier 14760d21680cSYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 14770d21680cSYann Gautier ifrge = 1U; 14780d21680cSYann Gautier } 14790d21680cSYann Gautier 14800d21680cSYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 14810d21680cSYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 14820d21680cSYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 14830d21680cSYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 14840d21680cSYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 14850d21680cSYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 14860d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { 14870d21680cSYann Gautier return false; 14880d21680cSYann Gautier } 14890d21680cSYann Gautier 14900d21680cSYann Gautier /* Fractional configuration */ 1491be858cffSAndre Przywara if (fdt_get_address(&fdt) == 1) { 1492be858cffSAndre Przywara fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1493be858cffSAndre Przywara } 14940d21680cSYann Gautier 14950d21680cSYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 14960d21680cSYann Gautier value |= RCC_PLLNFRACR_FRACLE; 14970d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { 14980d21680cSYann Gautier return false; 14990d21680cSYann Gautier } 15000d21680cSYann Gautier 15010d21680cSYann Gautier /* Output config */ 15020d21680cSYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15030d21680cSYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15040d21680cSYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15050d21680cSYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15060d21680cSYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15070d21680cSYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15080d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { 15090d21680cSYann Gautier return false; 15100d21680cSYann Gautier } 15110d21680cSYann Gautier 15120d21680cSYann Gautier return true; 15130d21680cSYann Gautier } 15140d21680cSYann Gautier 15150d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) 15167839a050SYann Gautier { 15170d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15180d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 15190d21680cSYann Gautier 1520dd98aec8SYann Gautier /* Preserve RCC_PLLNCR_SSCG_CTRL value */ 1521dd98aec8SYann Gautier mmio_clrsetbits_32(pllxcr, 1522dd98aec8SYann Gautier RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 1523dd98aec8SYann Gautier RCC_PLLNCR_DIVREN, 1524dd98aec8SYann Gautier RCC_PLLNCR_PLLON); 15250d21680cSYann Gautier } 15260d21680cSYann Gautier 15270d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) 15280d21680cSYann Gautier { 15290d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15300d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1531dfdb057aSYann Gautier uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); 15327839a050SYann Gautier 15337839a050SYann Gautier /* Wait PLL lock */ 15347839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { 1535dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15360d21680cSYann Gautier ERROR("PLL%d start failed @ 0x%lx: 0x%x\n", 15377839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15387839a050SYann Gautier return -ETIMEDOUT; 15397839a050SYann Gautier } 15407839a050SYann Gautier } 15417839a050SYann Gautier 15427839a050SYann Gautier /* Start the requested output */ 15437839a050SYann Gautier mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); 15447839a050SYann Gautier 15457839a050SYann Gautier return 0; 15467839a050SYann Gautier } 15477839a050SYann Gautier 15480d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) 15497839a050SYann Gautier { 15500d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15510d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1552dfdb057aSYann Gautier uint64_t timeout; 15537839a050SYann Gautier 15547839a050SYann Gautier /* Stop all output */ 15557839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 15567839a050SYann Gautier RCC_PLLNCR_DIVREN); 15577839a050SYann Gautier 15587839a050SYann Gautier /* Stop PLL */ 15597839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); 15607839a050SYann Gautier 1561dfdb057aSYann Gautier timeout = timeout_init_us(PLLRDY_TIMEOUT); 15627839a050SYann Gautier /* Wait PLL stopped */ 15637839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { 1564dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15650d21680cSYann Gautier ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n", 15667839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15677839a050SYann Gautier return -ETIMEDOUT; 15687839a050SYann Gautier } 15697839a050SYann Gautier } 15707839a050SYann Gautier 15717839a050SYann Gautier return 0; 15727839a050SYann Gautier } 15737839a050SYann Gautier 15740d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, 15757839a050SYann Gautier uint32_t *pllcfg) 15767839a050SYann Gautier { 15770d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15780d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 15797839a050SYann Gautier uint32_t value; 15807839a050SYann Gautier 15817839a050SYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15827839a050SYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15837839a050SYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15847839a050SYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15857839a050SYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15867839a050SYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15870d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr2, value); 15887839a050SYann Gautier } 15897839a050SYann Gautier 15900d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, 15917839a050SYann Gautier uint32_t *pllcfg, uint32_t fracv) 15927839a050SYann Gautier { 15930d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15940d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 15950d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 15967839a050SYann Gautier unsigned long refclk; 15977839a050SYann Gautier uint32_t ifrge = 0; 15987839a050SYann Gautier uint32_t src, value; 15997839a050SYann Gautier 16000d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & 16017839a050SYann Gautier RCC_SELR_REFCLK_SRC_MASK; 16027839a050SYann Gautier 16030d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 16047839a050SYann Gautier (pllcfg[PLLCFG_M] + 1U); 16057839a050SYann Gautier 16067839a050SYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 16077839a050SYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 16087839a050SYann Gautier return -EINVAL; 16097839a050SYann Gautier } 16107839a050SYann Gautier 16117839a050SYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 16127839a050SYann Gautier ifrge = 1U; 16137839a050SYann Gautier } 16147839a050SYann Gautier 16157839a050SYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 16167839a050SYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 16177839a050SYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 16187839a050SYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 16197839a050SYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 16207839a050SYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 16210d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr1, value); 16227839a050SYann Gautier 16237839a050SYann Gautier /* Fractional configuration */ 16247839a050SYann Gautier value = 0; 16250d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16267839a050SYann Gautier 16277839a050SYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 16280d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16297839a050SYann Gautier 16307839a050SYann Gautier value |= RCC_PLLNFRACR_FRACLE; 16310d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16327839a050SYann Gautier 16330d21680cSYann Gautier stm32mp1_pll_config_output(pll_id, pllcfg); 16347839a050SYann Gautier 16357839a050SYann Gautier return 0; 16367839a050SYann Gautier } 16377839a050SYann Gautier 16380d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) 16397839a050SYann Gautier { 16400d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16417839a050SYann Gautier uint32_t pllxcsg = 0; 16427839a050SYann Gautier 16437839a050SYann Gautier pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & 16447839a050SYann Gautier RCC_PLLNCSGR_MOD_PER_MASK; 16457839a050SYann Gautier 16467839a050SYann Gautier pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & 16477839a050SYann Gautier RCC_PLLNCSGR_INC_STEP_MASK; 16487839a050SYann Gautier 16497839a050SYann Gautier pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & 16507839a050SYann Gautier RCC_PLLNCSGR_SSCG_MODE_MASK; 16517839a050SYann Gautier 16520d21680cSYann Gautier mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); 1653dd98aec8SYann Gautier 1654dd98aec8SYann Gautier mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, 1655dd98aec8SYann Gautier RCC_PLLNCR_SSCG_CTRL); 16567839a050SYann Gautier } 16577839a050SYann Gautier 16580d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc) 16597839a050SYann Gautier { 16600d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 1661dfdb057aSYann Gautier uint64_t timeout; 16627839a050SYann Gautier 16630d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, 16647839a050SYann Gautier clksrc & RCC_SELR_SRC_MASK); 16657839a050SYann Gautier 1666dfdb057aSYann Gautier timeout = timeout_init_us(CLKSRC_TIMEOUT); 16670d21680cSYann Gautier while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { 1668dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 16690d21680cSYann Gautier ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, 16700d21680cSYann Gautier clksrc_address, mmio_read_32(clksrc_address)); 16717839a050SYann Gautier return -ETIMEDOUT; 16727839a050SYann Gautier } 16737839a050SYann Gautier } 16747839a050SYann Gautier 16757839a050SYann Gautier return 0; 16767839a050SYann Gautier } 16777839a050SYann Gautier 16780d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) 16797839a050SYann Gautier { 1680dfdb057aSYann Gautier uint64_t timeout; 16817839a050SYann Gautier 16827839a050SYann Gautier mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, 16837839a050SYann Gautier clkdiv & RCC_DIVR_DIV_MASK); 16847839a050SYann Gautier 1685dfdb057aSYann Gautier timeout = timeout_init_us(CLKDIV_TIMEOUT); 16867839a050SYann Gautier while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { 1687dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 16880d21680cSYann Gautier ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", 16897839a050SYann Gautier clkdiv, address, mmio_read_32(address)); 16907839a050SYann Gautier return -ETIMEDOUT; 16917839a050SYann Gautier } 16927839a050SYann Gautier } 16937839a050SYann Gautier 16947839a050SYann Gautier return 0; 16957839a050SYann Gautier } 16967839a050SYann Gautier 16970d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) 16987839a050SYann Gautier { 16990d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 17007839a050SYann Gautier 17017839a050SYann Gautier /* 17027839a050SYann Gautier * Binding clksrc : 17037839a050SYann Gautier * bit15-4 offset 17047839a050SYann Gautier * bit3: disable 17057839a050SYann Gautier * bit2-0: MCOSEL[2:0] 17067839a050SYann Gautier */ 17077839a050SYann Gautier if ((clksrc & 0x8U) != 0U) { 17080d21680cSYann Gautier mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17097839a050SYann Gautier } else { 17100d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17117839a050SYann Gautier RCC_MCOCFG_MCOSRC_MASK, 17127839a050SYann Gautier clksrc & RCC_MCOCFG_MCOSRC_MASK); 17130d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17147839a050SYann Gautier RCC_MCOCFG_MCODIV_MASK, 17157839a050SYann Gautier clkdiv << RCC_MCOCFG_MCODIV_SHIFT); 17160d21680cSYann Gautier mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17177839a050SYann Gautier } 17187839a050SYann Gautier } 17197839a050SYann Gautier 17200d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) 17217839a050SYann Gautier { 17220d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; 17237839a050SYann Gautier 17247839a050SYann Gautier if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || 17257839a050SYann Gautier (clksrc != (uint32_t)CLK_RTC_DISABLED)) { 17267839a050SYann Gautier mmio_clrsetbits_32(address, 17277839a050SYann Gautier RCC_BDCR_RTCSRC_MASK, 172815509093SYann Gautier (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); 17297839a050SYann Gautier 17307839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_RTCCKEN); 17317839a050SYann Gautier } 17327839a050SYann Gautier 17337839a050SYann Gautier if (lse_css) { 17347839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_LSECSSON); 17357839a050SYann Gautier } 17367839a050SYann Gautier } 17377839a050SYann Gautier 17380d21680cSYann Gautier static void stm32mp1_stgen_config(void) 17397839a050SYann Gautier { 17407839a050SYann Gautier uint32_t cntfid0; 17417839a050SYann Gautier unsigned long rate; 17427839a050SYann Gautier unsigned long long counter; 17437839a050SYann Gautier 1744ade9ce03SYann Gautier cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF); 17450d21680cSYann Gautier rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); 17460d21680cSYann Gautier 17470d21680cSYann Gautier if (cntfid0 == rate) { 17480d21680cSYann Gautier return; 17490d21680cSYann Gautier } 17500d21680cSYann Gautier 1751ade9ce03SYann Gautier mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 1752ade9ce03SYann Gautier counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF); 1753ade9ce03SYann Gautier counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF)) << 32; 17547839a050SYann Gautier counter = (counter * rate / cntfid0); 17550d21680cSYann Gautier 1756ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter); 1757ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32)); 1758ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTFID_OFF, rate); 1759ade9ce03SYann Gautier mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 17607839a050SYann Gautier 17617839a050SYann Gautier write_cntfrq((u_register_t)rate); 17627839a050SYann Gautier 17637839a050SYann Gautier /* Need to update timer with new frequency */ 17647839a050SYann Gautier generic_delay_timer_init(); 17657839a050SYann Gautier } 17667839a050SYann Gautier 17677839a050SYann Gautier void stm32mp1_stgen_increment(unsigned long long offset_in_ms) 17687839a050SYann Gautier { 17697839a050SYann Gautier unsigned long long cnt; 17707839a050SYann Gautier 1771ade9ce03SYann Gautier cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) | 1772ade9ce03SYann Gautier mmio_read_32(STGEN_BASE + CNTCVL_OFF); 17737839a050SYann Gautier 1774ade9ce03SYann Gautier cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U; 17757839a050SYann Gautier 1776ade9ce03SYann Gautier mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 1777ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt); 1778ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32)); 1779ade9ce03SYann Gautier mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 17807839a050SYann Gautier } 17817839a050SYann Gautier 17820d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs) 17837839a050SYann Gautier { 17840d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); 17857839a050SYann Gautier uint32_t value = pkcs & 0xFU; 17867839a050SYann Gautier uint32_t mask = 0xFU; 17877839a050SYann Gautier 17887839a050SYann Gautier if ((pkcs & BIT(31)) != 0U) { 17897839a050SYann Gautier mask <<= 4; 17907839a050SYann Gautier value <<= 4; 17917839a050SYann Gautier } 17927839a050SYann Gautier 17937839a050SYann Gautier mmio_clrsetbits_32(address, mask, value); 17947839a050SYann Gautier } 17957839a050SYann Gautier 1796964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, 1797964e5ff1SNicolas Le Bayon uint32_t *fracv, uint32_t *csg, 1798964e5ff1SNicolas Le Bayon bool *csg_set) 1799964e5ff1SNicolas Le Bayon { 1800964e5ff1SNicolas Le Bayon void *fdt; 1801964e5ff1SNicolas Le Bayon int ret; 1802964e5ff1SNicolas Le Bayon 1803964e5ff1SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 1804964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1805964e5ff1SNicolas Le Bayon } 1806964e5ff1SNicolas Le Bayon 1807964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB, 1808964e5ff1SNicolas Le Bayon pllcfg); 1809964e5ff1SNicolas Le Bayon if (ret < 0) { 1810964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1811964e5ff1SNicolas Le Bayon } 1812964e5ff1SNicolas Le Bayon 1813964e5ff1SNicolas Le Bayon *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1814964e5ff1SNicolas Le Bayon 1815964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB, 1816964e5ff1SNicolas Le Bayon csg); 1817964e5ff1SNicolas Le Bayon 1818964e5ff1SNicolas Le Bayon *csg_set = (ret == 0); 1819964e5ff1SNicolas Le Bayon 1820964e5ff1SNicolas Le Bayon if (ret == -FDT_ERR_NOTFOUND) { 1821964e5ff1SNicolas Le Bayon ret = 0; 1822964e5ff1SNicolas Le Bayon } 1823964e5ff1SNicolas Le Bayon 1824964e5ff1SNicolas Le Bayon return ret; 1825964e5ff1SNicolas Le Bayon } 1826964e5ff1SNicolas Le Bayon 18277839a050SYann Gautier int stm32mp1_clk_init(void) 18287839a050SYann Gautier { 18290d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 1830964e5ff1SNicolas Le Bayon uint32_t pllfracv[_PLL_NB]; 1831964e5ff1SNicolas Le Bayon uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; 18327839a050SYann Gautier unsigned int clksrc[CLKSRC_NB]; 18337839a050SYann Gautier unsigned int clkdiv[CLKDIV_NB]; 18347839a050SYann Gautier unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; 18357839a050SYann Gautier int plloff[_PLL_NB]; 18367839a050SYann Gautier int ret, len; 18377839a050SYann Gautier enum stm32mp1_pll_id i; 1838964e5ff1SNicolas Le Bayon bool pllcsg_set[_PLL_NB]; 1839964e5ff1SNicolas Le Bayon bool pllcfg_valid[_PLL_NB]; 18407839a050SYann Gautier bool lse_css = false; 18410d21680cSYann Gautier bool pll3_preserve = false; 18420d21680cSYann Gautier bool pll4_preserve = false; 18430d21680cSYann Gautier bool pll4_bootrom = false; 18443e6fab43SYann Gautier const fdt32_t *pkcs_cell; 184552a616b4SAndre Przywara void *fdt; 1846bf1af154SPatrick Delaunay int stgen_p = stm32mp1_clk_get_parent(STGEN_K); 1847bf1af154SPatrick Delaunay int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K); 184852a616b4SAndre Przywara 184952a616b4SAndre Przywara if (fdt_get_address(&fdt) == 0) { 18508f97c4faSYann Gautier return -FDT_ERR_NOTFOUND; 185152a616b4SAndre Przywara } 18527839a050SYann Gautier 18537839a050SYann Gautier /* Check status field to disable security */ 18547839a050SYann Gautier if (!fdt_get_rcc_secure_status()) { 18550d21680cSYann Gautier mmio_write_32(rcc_base + RCC_TZCR, 0); 18567839a050SYann Gautier } 18577839a050SYann Gautier 185852a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, 185952a616b4SAndre Przywara clksrc); 18607839a050SYann Gautier if (ret < 0) { 18617839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18627839a050SYann Gautier } 18637839a050SYann Gautier 186452a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, 186552a616b4SAndre Przywara clkdiv); 18667839a050SYann Gautier if (ret < 0) { 18677839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18687839a050SYann Gautier } 18697839a050SYann Gautier 18707839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 18717839a050SYann Gautier char name[12]; 18727839a050SYann Gautier 187339b6cc66SAntonio Nino Diaz snprintf(name, sizeof(name), "st,pll@%d", i); 18747839a050SYann Gautier plloff[i] = fdt_rcc_subnode_offset(name); 18757839a050SYann Gautier 1876964e5ff1SNicolas Le Bayon pllcfg_valid[i] = fdt_check_node(plloff[i]); 1877964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 18787839a050SYann Gautier continue; 18797839a050SYann Gautier } 18807839a050SYann Gautier 1881964e5ff1SNicolas Le Bayon ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], 1882964e5ff1SNicolas Le Bayon &pllfracv[i], pllcsg[i], 1883964e5ff1SNicolas Le Bayon &pllcsg_set[i]); 1884964e5ff1SNicolas Le Bayon if (ret != 0) { 1885964e5ff1SNicolas Le Bayon return ret; 18867839a050SYann Gautier } 18877839a050SYann Gautier } 18887839a050SYann Gautier 18890d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); 18900d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); 18917839a050SYann Gautier 18927839a050SYann Gautier /* 18937839a050SYann Gautier * Switch ON oscillator found in device-tree. 18947839a050SYann Gautier * Note: HSI already ON after BootROM stage. 18957839a050SYann Gautier */ 18960d21680cSYann Gautier if (stm32mp1_osc[_LSI] != 0U) { 18970d21680cSYann Gautier stm32mp1_lsi_set(true); 18987839a050SYann Gautier } 18990d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 1900b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_LSE]; 19010d21680cSYann Gautier bool bypass, digbyp; 19027839a050SYann Gautier uint32_t lsedrv; 19037839a050SYann Gautier 1904b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1905b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1906b208e3daSGabriel Fernandez lse_css = fdt_clk_read_bool(name, "st,css"); 1907b208e3daSGabriel Fernandez lsedrv = fdt_clk_read_uint32_default(name, "st,drive", 19087839a050SYann Gautier LSEDRV_MEDIUM_HIGH); 19090d21680cSYann Gautier stm32mp1_lse_enable(bypass, digbyp, lsedrv); 19107839a050SYann Gautier } 19110d21680cSYann Gautier if (stm32mp1_osc[_HSE] != 0U) { 1912b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_HSE]; 19130d21680cSYann Gautier bool bypass, digbyp, css; 19147839a050SYann Gautier 1915b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1916b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1917b208e3daSGabriel Fernandez css = fdt_clk_read_bool(name, "st,css"); 19180d21680cSYann Gautier stm32mp1_hse_enable(bypass, digbyp, css); 19197839a050SYann Gautier } 19207839a050SYann Gautier /* 19217839a050SYann Gautier * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) 19227839a050SYann Gautier * => switch on CSI even if node is not present in device tree 19237839a050SYann Gautier */ 19240d21680cSYann Gautier stm32mp1_csi_set(true); 19257839a050SYann Gautier 19267839a050SYann Gautier /* Come back to HSI */ 19270d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_MPU_HSI); 19287839a050SYann Gautier if (ret != 0) { 19297839a050SYann Gautier return ret; 19307839a050SYann Gautier } 19310d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_AXI_HSI); 19327839a050SYann Gautier if (ret != 0) { 19337839a050SYann Gautier return ret; 19347839a050SYann Gautier } 1935b053a22eSYann Gautier ret = stm32mp1_set_clksrc(CLK_MCU_HSI); 1936b053a22eSYann Gautier if (ret != 0) { 1937b053a22eSYann Gautier return ret; 1938b053a22eSYann Gautier } 19397839a050SYann Gautier 19400d21680cSYann Gautier if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & 19410d21680cSYann Gautier RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { 19420d21680cSYann Gautier pll3_preserve = stm32mp1_check_pll_conf(_PLL3, 19430d21680cSYann Gautier clksrc[CLKSRC_PLL3], 19440d21680cSYann Gautier pllcfg[_PLL3], 19450d21680cSYann Gautier plloff[_PLL3]); 19460d21680cSYann Gautier pll4_preserve = stm32mp1_check_pll_conf(_PLL4, 19470d21680cSYann Gautier clksrc[CLKSRC_PLL4], 19480d21680cSYann Gautier pllcfg[_PLL4], 19490d21680cSYann Gautier plloff[_PLL4]); 19500d21680cSYann Gautier } 1951bf1af154SPatrick Delaunay /* Don't initialize PLL4, when used by BOOTROM */ 1952bf1af154SPatrick Delaunay if ((stm32mp_get_boot_itf_selected() == 1953bf1af154SPatrick Delaunay BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) && 1954bf1af154SPatrick Delaunay ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { 1955bf1af154SPatrick Delaunay pll4_bootrom = true; 1956bf1af154SPatrick Delaunay pll4_preserve = true; 1957bf1af154SPatrick Delaunay } 19580d21680cSYann Gautier 19597839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19600d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 19610d21680cSYann Gautier ((i == _PLL4) && pll4_preserve)) { 19627839a050SYann Gautier continue; 19630d21680cSYann Gautier } 19640d21680cSYann Gautier 19650d21680cSYann Gautier ret = stm32mp1_pll_stop(i); 19667839a050SYann Gautier if (ret != 0) { 19677839a050SYann Gautier return ret; 19687839a050SYann Gautier } 19697839a050SYann Gautier } 19707839a050SYann Gautier 19717839a050SYann Gautier /* Configure HSIDIV */ 19720d21680cSYann Gautier if (stm32mp1_osc[_HSI] != 0U) { 19730d21680cSYann Gautier ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); 19747839a050SYann Gautier if (ret != 0) { 19757839a050SYann Gautier return ret; 19767839a050SYann Gautier } 19770d21680cSYann Gautier stm32mp1_stgen_config(); 19787839a050SYann Gautier } 19797839a050SYann Gautier 19807839a050SYann Gautier /* Select DIV */ 19817839a050SYann Gautier /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ 19820d21680cSYann Gautier mmio_write_32(rcc_base + RCC_MPCKDIVR, 19837839a050SYann Gautier clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 19840d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); 19857839a050SYann Gautier if (ret != 0) { 19867839a050SYann Gautier return ret; 19877839a050SYann Gautier } 19880d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); 19897839a050SYann Gautier if (ret != 0) { 19907839a050SYann Gautier return ret; 19917839a050SYann Gautier } 19920d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); 19937839a050SYann Gautier if (ret != 0) { 19947839a050SYann Gautier return ret; 19957839a050SYann Gautier } 1996b053a22eSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); 1997b053a22eSYann Gautier if (ret != 0) { 1998b053a22eSYann Gautier return ret; 1999b053a22eSYann Gautier } 20000d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); 20017839a050SYann Gautier if (ret != 0) { 20027839a050SYann Gautier return ret; 20037839a050SYann Gautier } 20040d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); 20057839a050SYann Gautier if (ret != 0) { 20067839a050SYann Gautier return ret; 20077839a050SYann Gautier } 20080d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); 20097839a050SYann Gautier if (ret != 0) { 20107839a050SYann Gautier return ret; 20117839a050SYann Gautier } 20127839a050SYann Gautier 20137839a050SYann Gautier /* No ready bit for RTC */ 20140d21680cSYann Gautier mmio_write_32(rcc_base + RCC_RTCDIVR, 20157839a050SYann Gautier clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); 20167839a050SYann Gautier 20177839a050SYann Gautier /* Configure PLLs source */ 20180d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); 20197839a050SYann Gautier if (ret != 0) { 20207839a050SYann Gautier return ret; 20217839a050SYann Gautier } 20227839a050SYann Gautier 20230d21680cSYann Gautier if (!pll3_preserve) { 20240d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); 20257839a050SYann Gautier if (ret != 0) { 20267839a050SYann Gautier return ret; 20277839a050SYann Gautier } 20280d21680cSYann Gautier } 20290d21680cSYann Gautier 20300d21680cSYann Gautier if (!pll4_preserve) { 20310d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); 20320d21680cSYann Gautier if (ret != 0) { 20330d21680cSYann Gautier return ret; 20340d21680cSYann Gautier } 20350d21680cSYann Gautier } 20367839a050SYann Gautier 20377839a050SYann Gautier /* Configure and start PLLs */ 20387839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 20390d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 20400d21680cSYann Gautier ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { 20410d21680cSYann Gautier continue; 20420d21680cSYann Gautier } 20430d21680cSYann Gautier 2044964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20457839a050SYann Gautier continue; 20467839a050SYann Gautier } 20477839a050SYann Gautier 20480d21680cSYann Gautier if ((i == _PLL4) && pll4_bootrom) { 20490d21680cSYann Gautier /* Set output divider if not done by the Bootrom */ 20500d21680cSYann Gautier stm32mp1_pll_config_output(i, pllcfg[i]); 20510d21680cSYann Gautier continue; 20520d21680cSYann Gautier } 20530d21680cSYann Gautier 2054964e5ff1SNicolas Le Bayon ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); 20557839a050SYann Gautier if (ret != 0) { 20567839a050SYann Gautier return ret; 20577839a050SYann Gautier } 2058964e5ff1SNicolas Le Bayon 2059964e5ff1SNicolas Le Bayon if (pllcsg_set[i]) { 2060964e5ff1SNicolas Le Bayon stm32mp1_pll_csg(i, pllcsg[i]); 20617839a050SYann Gautier } 20627839a050SYann Gautier 20630d21680cSYann Gautier stm32mp1_pll_start(i); 20647839a050SYann Gautier } 20657839a050SYann Gautier /* Wait and start PLLs ouptut when ready */ 20667839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 2067964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20687839a050SYann Gautier continue; 20697839a050SYann Gautier } 20707839a050SYann Gautier 20710d21680cSYann Gautier ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); 20727839a050SYann Gautier if (ret != 0) { 20737839a050SYann Gautier return ret; 20747839a050SYann Gautier } 20757839a050SYann Gautier } 20767839a050SYann Gautier /* Wait LSE ready before to use it */ 20770d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 20780d21680cSYann Gautier stm32mp1_lse_wait(); 20797839a050SYann Gautier } 20807839a050SYann Gautier 20817839a050SYann Gautier /* Configure with expected clock source */ 20820d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); 20837839a050SYann Gautier if (ret != 0) { 20847839a050SYann Gautier return ret; 20857839a050SYann Gautier } 20860d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); 20877839a050SYann Gautier if (ret != 0) { 20887839a050SYann Gautier return ret; 20897839a050SYann Gautier } 2090b053a22eSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); 2091b053a22eSYann Gautier if (ret != 0) { 2092b053a22eSYann Gautier return ret; 2093b053a22eSYann Gautier } 20940d21680cSYann Gautier stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); 20957839a050SYann Gautier 20967839a050SYann Gautier /* Configure PKCK */ 20977839a050SYann Gautier pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); 20987839a050SYann Gautier if (pkcs_cell != NULL) { 20997839a050SYann Gautier bool ckper_disabled = false; 21007839a050SYann Gautier uint32_t j; 2101bf1af154SPatrick Delaunay uint32_t usbreg_bootrom = 0U; 2102bf1af154SPatrick Delaunay 2103bf1af154SPatrick Delaunay if (pll4_bootrom) { 2104bf1af154SPatrick Delaunay usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); 2105bf1af154SPatrick Delaunay } 21067839a050SYann Gautier 21077839a050SYann Gautier for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { 21083e6fab43SYann Gautier uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); 21097839a050SYann Gautier 21107839a050SYann Gautier if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { 21117839a050SYann Gautier ckper_disabled = true; 21127839a050SYann Gautier continue; 21137839a050SYann Gautier } 21140d21680cSYann Gautier stm32mp1_pkcs_config(pkcs); 21157839a050SYann Gautier } 21167839a050SYann Gautier 21177839a050SYann Gautier /* 21187839a050SYann Gautier * CKPER is source for some peripheral clocks 21197839a050SYann Gautier * (FMC-NAND / QPSI-NOR) and switching source is allowed 21207839a050SYann Gautier * only if previous clock is still ON 21217839a050SYann Gautier * => deactivated CKPER only after switching clock 21227839a050SYann Gautier */ 21237839a050SYann Gautier if (ckper_disabled) { 21240d21680cSYann Gautier stm32mp1_pkcs_config(CLK_CKPER_DISABLED); 21257839a050SYann Gautier } 2126bf1af154SPatrick Delaunay 2127bf1af154SPatrick Delaunay if (pll4_bootrom) { 2128bf1af154SPatrick Delaunay uint32_t usbreg_value, usbreg_mask; 2129bf1af154SPatrick Delaunay const struct stm32mp1_clk_sel *sel; 2130bf1af154SPatrick Delaunay 2131bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBPHY_SEL); 2132bf1af154SPatrick Delaunay usbreg_mask = (uint32_t)sel->msk << sel->src; 2133bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBO_SEL); 2134bf1af154SPatrick Delaunay usbreg_mask |= (uint32_t)sel->msk << sel->src; 2135bf1af154SPatrick Delaunay 2136bf1af154SPatrick Delaunay usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & 2137bf1af154SPatrick Delaunay usbreg_mask; 2138bf1af154SPatrick Delaunay usbreg_bootrom &= usbreg_mask; 2139bf1af154SPatrick Delaunay if (usbreg_bootrom != usbreg_value) { 2140bf1af154SPatrick Delaunay VERBOSE("forbidden new USB clk path\n"); 2141bf1af154SPatrick Delaunay VERBOSE("vs bootrom on USB boot\n"); 2142bf1af154SPatrick Delaunay return -FDT_ERR_BADVALUE; 2143bf1af154SPatrick Delaunay } 2144bf1af154SPatrick Delaunay } 21457839a050SYann Gautier } 21467839a050SYann Gautier 21477839a050SYann Gautier /* Switch OFF HSI if not found in device-tree */ 21480d21680cSYann Gautier if (stm32mp1_osc[_HSI] == 0U) { 21490d21680cSYann Gautier stm32mp1_hsi_set(false); 21507839a050SYann Gautier } 21510d21680cSYann Gautier stm32mp1_stgen_config(); 21527839a050SYann Gautier 21537839a050SYann Gautier /* Software Self-Refresh mode (SSR) during DDR initilialization */ 21540d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, 21557839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_MASK, 21567839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SSR << 21577839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SHIFT); 21587839a050SYann Gautier 21597839a050SYann Gautier return 0; 21607839a050SYann Gautier } 21617839a050SYann Gautier 21627839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name, 21637839a050SYann Gautier enum stm32mp_osc_id index) 21647839a050SYann Gautier { 21657839a050SYann Gautier uint32_t frequency; 21667839a050SYann Gautier 21670d21680cSYann Gautier if (fdt_osc_read_freq(name, &frequency) == 0) { 21680d21680cSYann Gautier stm32mp1_osc[index] = frequency; 21697839a050SYann Gautier } 21707839a050SYann Gautier } 21717839a050SYann Gautier 21727839a050SYann Gautier static void stm32mp1_osc_init(void) 21737839a050SYann Gautier { 21747839a050SYann Gautier enum stm32mp_osc_id i; 21757839a050SYann Gautier 21767839a050SYann Gautier for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { 21770d21680cSYann Gautier stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); 21787839a050SYann Gautier } 21797839a050SYann Gautier } 21807839a050SYann Gautier 218137e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES 218237e8295aSEtienne Carriere /* 218337e8295aSEtienne Carriere * Get the parent ID of the target parent clock, for tagging as secure 218437e8295aSEtienne Carriere * shared clock dependencies. 218537e8295aSEtienne Carriere */ 218637e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id) 218737e8295aSEtienne Carriere { 218837e8295aSEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 218937e8295aSEtienne Carriere enum stm32mp1_pll_id pll_id; 219037e8295aSEtienne Carriere uint32_t p_sel; 219137e8295aSEtienne Carriere uintptr_t rcc_base = stm32mp_rcc_base(); 219237e8295aSEtienne Carriere 219337e8295aSEtienne Carriere switch (parent_id) { 219437e8295aSEtienne Carriere case _ACLK: 219537e8295aSEtienne Carriere case _PCLK4: 219637e8295aSEtienne Carriere case _PCLK5: 219737e8295aSEtienne Carriere s = _AXIS_SEL; 219837e8295aSEtienne Carriere break; 219937e8295aSEtienne Carriere case _PLL1_P: 220037e8295aSEtienne Carriere case _PLL1_Q: 220137e8295aSEtienne Carriere case _PLL1_R: 220237e8295aSEtienne Carriere pll_id = _PLL1; 220337e8295aSEtienne Carriere break; 220437e8295aSEtienne Carriere case _PLL2_P: 220537e8295aSEtienne Carriere case _PLL2_Q: 220637e8295aSEtienne Carriere case _PLL2_R: 220737e8295aSEtienne Carriere pll_id = _PLL2; 220837e8295aSEtienne Carriere break; 220937e8295aSEtienne Carriere case _PLL3_P: 221037e8295aSEtienne Carriere case _PLL3_Q: 221137e8295aSEtienne Carriere case _PLL3_R: 221237e8295aSEtienne Carriere pll_id = _PLL3; 221337e8295aSEtienne Carriere break; 221437e8295aSEtienne Carriere case _PLL4_P: 221537e8295aSEtienne Carriere case _PLL4_Q: 221637e8295aSEtienne Carriere case _PLL4_R: 221737e8295aSEtienne Carriere pll_id = _PLL4; 221837e8295aSEtienne Carriere break; 221937e8295aSEtienne Carriere case _PCLK1: 222037e8295aSEtienne Carriere case _PCLK2: 222137e8295aSEtienne Carriere case _HCLK2: 222237e8295aSEtienne Carriere case _HCLK6: 222337e8295aSEtienne Carriere case _CK_PER: 222437e8295aSEtienne Carriere case _CK_MPU: 222537e8295aSEtienne Carriere case _CK_MCU: 222637e8295aSEtienne Carriere case _USB_PHY_48: 222737e8295aSEtienne Carriere /* We do not expect to access these */ 222837e8295aSEtienne Carriere panic(); 222937e8295aSEtienne Carriere break; 223037e8295aSEtienne Carriere default: 223137e8295aSEtienne Carriere /* Other parents have no parent */ 223237e8295aSEtienne Carriere return -1; 223337e8295aSEtienne Carriere } 223437e8295aSEtienne Carriere 223537e8295aSEtienne Carriere if (s != _UNKNOWN_SEL) { 223637e8295aSEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 223737e8295aSEtienne Carriere 223837e8295aSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & 223937e8295aSEtienne Carriere sel->msk; 224037e8295aSEtienne Carriere 224137e8295aSEtienne Carriere if (p_sel < sel->nb_parent) { 224237e8295aSEtienne Carriere return (int)sel->parent[p_sel]; 224337e8295aSEtienne Carriere } 224437e8295aSEtienne Carriere } else { 224537e8295aSEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 224637e8295aSEtienne Carriere 224737e8295aSEtienne Carriere p_sel = mmio_read_32(rcc_base + pll->rckxselr) & 224837e8295aSEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 224937e8295aSEtienne Carriere 225037e8295aSEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { 225137e8295aSEtienne Carriere return (int)pll->refclk[p_sel]; 225237e8295aSEtienne Carriere } 225337e8295aSEtienne Carriere } 225437e8295aSEtienne Carriere 225537e8295aSEtienne Carriere VERBOSE("No parent selected for %s\n", 225637e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 225737e8295aSEtienne Carriere 225837e8295aSEtienne Carriere return -1; 225937e8295aSEtienne Carriere } 226037e8295aSEtienne Carriere 226137e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id) 226237e8295aSEtienne Carriere { 226337e8295aSEtienne Carriere int grandparent_id; 226437e8295aSEtienne Carriere 226537e8295aSEtienne Carriere switch (parent_id) { 226637e8295aSEtienne Carriere case _PLL3_P: 226737e8295aSEtienne Carriere case _PLL3_Q: 226837e8295aSEtienne Carriere case _PLL3_R: 226937e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 227037e8295aSEtienne Carriere break; 227137e8295aSEtienne Carriere 227237e8295aSEtienne Carriere /* These clocks are always secure when RCC is secure */ 227337e8295aSEtienne Carriere case _ACLK: 227437e8295aSEtienne Carriere case _HCLK2: 227537e8295aSEtienne Carriere case _HCLK6: 227637e8295aSEtienne Carriere case _PCLK4: 227737e8295aSEtienne Carriere case _PCLK5: 227837e8295aSEtienne Carriere case _PLL1_P: 227937e8295aSEtienne Carriere case _PLL1_Q: 228037e8295aSEtienne Carriere case _PLL1_R: 228137e8295aSEtienne Carriere case _PLL2_P: 228237e8295aSEtienne Carriere case _PLL2_Q: 228337e8295aSEtienne Carriere case _PLL2_R: 228437e8295aSEtienne Carriere case _HSI: 228537e8295aSEtienne Carriere case _HSI_KER: 228637e8295aSEtienne Carriere case _LSI: 228737e8295aSEtienne Carriere case _CSI: 228837e8295aSEtienne Carriere case _CSI_KER: 228937e8295aSEtienne Carriere case _HSE: 229037e8295aSEtienne Carriere case _HSE_KER: 229137e8295aSEtienne Carriere case _HSE_KER_DIV2: 2292cbd2e8a6SGabriel Fernandez case _HSE_RTC: 229337e8295aSEtienne Carriere case _LSE: 229437e8295aSEtienne Carriere break; 229537e8295aSEtienne Carriere 229637e8295aSEtienne Carriere default: 229737e8295aSEtienne Carriere VERBOSE("Cannot secure parent clock %s\n", 229837e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 229937e8295aSEtienne Carriere panic(); 230037e8295aSEtienne Carriere } 230137e8295aSEtienne Carriere 230237e8295aSEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 230337e8295aSEtienne Carriere if (grandparent_id >= 0) { 230437e8295aSEtienne Carriere secure_parent_clocks(grandparent_id); 230537e8295aSEtienne Carriere } 230637e8295aSEtienne Carriere } 230737e8295aSEtienne Carriere 230837e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id) 230937e8295aSEtienne Carriere { 231037e8295aSEtienne Carriere int parent_id; 231137e8295aSEtienne Carriere 231237e8295aSEtienne Carriere if (!stm32mp1_rcc_is_secure()) { 231337e8295aSEtienne Carriere return; 231437e8295aSEtienne Carriere } 231537e8295aSEtienne Carriere 231637e8295aSEtienne Carriere switch (clock_id) { 231737e8295aSEtienne Carriere case PLL1: 231837e8295aSEtienne Carriere case PLL2: 231937e8295aSEtienne Carriere /* PLL1/PLL2 are always secure: nothing to do */ 232037e8295aSEtienne Carriere break; 232137e8295aSEtienne Carriere case PLL3: 232237e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 232337e8295aSEtienne Carriere break; 232437e8295aSEtienne Carriere case PLL4: 232537e8295aSEtienne Carriere ERROR("PLL4 cannot be secured\n"); 232637e8295aSEtienne Carriere panic(); 232737e8295aSEtienne Carriere break; 232837e8295aSEtienne Carriere default: 232937e8295aSEtienne Carriere /* Others are expected gateable clock */ 233037e8295aSEtienne Carriere parent_id = stm32mp1_clk_get_parent(clock_id); 233137e8295aSEtienne Carriere if (parent_id < 0) { 233237e8295aSEtienne Carriere INFO("No parent found for clock %lu\n", clock_id); 233337e8295aSEtienne Carriere } else { 233437e8295aSEtienne Carriere secure_parent_clocks(parent_id); 233537e8295aSEtienne Carriere } 233637e8295aSEtienne Carriere break; 233737e8295aSEtienne Carriere } 233837e8295aSEtienne Carriere } 233937e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */ 234037e8295aSEtienne Carriere 23416cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void) 23426cb45f89SYann Gautier { 2343033b6c3aSEtienne Carriere unsigned int idx; 2344033b6c3aSEtienne Carriere const unsigned long secure_enable[] = { 2345033b6c3aSEtienne Carriere AXIDCG, 2346033b6c3aSEtienne Carriere BSEC, 2347033b6c3aSEtienne Carriere DDRC1, DDRC1LP, 2348033b6c3aSEtienne Carriere DDRC2, DDRC2LP, 2349033b6c3aSEtienne Carriere DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, 2350033b6c3aSEtienne Carriere DDRPHYC, DDRPHYCLP, 2351373f06beSLionel Debieve RTCAPB, 2352033b6c3aSEtienne Carriere TZC1, TZC2, 2353033b6c3aSEtienne Carriere TZPC, 2354033b6c3aSEtienne Carriere STGEN_K, 2355033b6c3aSEtienne Carriere }; 2356033b6c3aSEtienne Carriere 2357033b6c3aSEtienne Carriere for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { 2358033b6c3aSEtienne Carriere stm32mp_clk_enable(secure_enable[idx]); 2359033b6c3aSEtienne Carriere } 23606cb45f89SYann Gautier } 23616cb45f89SYann Gautier 236233667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = { 236333667d29SYann Gautier .enable = stm32mp_clk_enable, 236433667d29SYann Gautier .disable = stm32mp_clk_disable, 236533667d29SYann Gautier .is_enabled = stm32mp_clk_is_enabled, 236633667d29SYann Gautier .get_rate = stm32mp_clk_get_rate, 236733667d29SYann Gautier .get_parent = stm32mp1_clk_get_parent, 236833667d29SYann Gautier }; 236933667d29SYann Gautier 23707839a050SYann Gautier int stm32mp1_clk_probe(void) 23717839a050SYann Gautier { 23727839a050SYann Gautier stm32mp1_osc_init(); 23737839a050SYann Gautier 23746cb45f89SYann Gautier sync_earlyboot_clocks_state(); 23756cb45f89SYann Gautier 237633667d29SYann Gautier clk_register(&stm32mp_clk_ops); 237733667d29SYann Gautier 23787839a050SYann Gautier return 0; 23797839a050SYann Gautier } 2380