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; 2440d21680cSYann Gautier uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ 2450d21680cSYann Gautier uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ 2467839a050SYann Gautier }; 2477839a050SYann Gautier 2487839a050SYann Gautier struct stm32mp1_clk_sel { 2497839a050SYann Gautier uint16_t offset; 2507839a050SYann Gautier uint8_t src; 2517839a050SYann Gautier uint8_t msk; 2527839a050SYann Gautier uint8_t nb_parent; 2537839a050SYann Gautier const uint8_t *parent; 2547839a050SYann Gautier }; 2557839a050SYann Gautier 2567839a050SYann Gautier #define REFCLK_SIZE 4 2577839a050SYann Gautier struct stm32mp1_clk_pll { 2587839a050SYann Gautier enum stm32mp1_plltype plltype; 2597839a050SYann Gautier uint16_t rckxselr; 2607839a050SYann Gautier uint16_t pllxcfgr1; 2617839a050SYann Gautier uint16_t pllxcfgr2; 2627839a050SYann Gautier uint16_t pllxfracr; 2637839a050SYann Gautier uint16_t pllxcr; 2647839a050SYann Gautier uint16_t pllxcsgr; 2657839a050SYann Gautier enum stm32mp_osc_id refclk[REFCLK_SIZE]; 2667839a050SYann Gautier }; 2677839a050SYann Gautier 2680d21680cSYann Gautier /* Clocks with selectable source and non set/clr register access */ 2690d21680cSYann Gautier #define _CLK_SELEC(off, b, idx, s) \ 2707839a050SYann Gautier { \ 2717839a050SYann Gautier .offset = (off), \ 2727839a050SYann Gautier .bit = (b), \ 2737839a050SYann Gautier .index = (idx), \ 2747839a050SYann Gautier .set_clr = 0, \ 2757839a050SYann Gautier .sel = (s), \ 2767839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 2777839a050SYann Gautier } 2787839a050SYann Gautier 2790d21680cSYann Gautier /* Clocks with fixed source and non set/clr register access */ 2800d21680cSYann Gautier #define _CLK_FIXED(off, b, idx, f) \ 2817839a050SYann Gautier { \ 2827839a050SYann Gautier .offset = (off), \ 2837839a050SYann Gautier .bit = (b), \ 2847839a050SYann Gautier .index = (idx), \ 2857839a050SYann Gautier .set_clr = 0, \ 2867839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 2877839a050SYann Gautier .fixed = (f), \ 2887839a050SYann Gautier } 2897839a050SYann Gautier 2900d21680cSYann Gautier /* Clocks with selectable source and set/clr register access */ 2910d21680cSYann Gautier #define _CLK_SC_SELEC(off, b, idx, s) \ 2927839a050SYann Gautier { \ 2937839a050SYann Gautier .offset = (off), \ 2947839a050SYann Gautier .bit = (b), \ 2957839a050SYann Gautier .index = (idx), \ 2967839a050SYann Gautier .set_clr = 1, \ 2977839a050SYann Gautier .sel = (s), \ 2987839a050SYann Gautier .fixed = _UNKNOWN_ID, \ 2997839a050SYann Gautier } 3007839a050SYann Gautier 3010d21680cSYann Gautier /* Clocks with fixed source and set/clr register access */ 3020d21680cSYann Gautier #define _CLK_SC_FIXED(off, b, idx, f) \ 3037839a050SYann Gautier { \ 3047839a050SYann Gautier .offset = (off), \ 3057839a050SYann Gautier .bit = (b), \ 3067839a050SYann Gautier .index = (idx), \ 3077839a050SYann Gautier .set_clr = 1, \ 3087839a050SYann Gautier .sel = _UNKNOWN_SEL, \ 3097839a050SYann Gautier .fixed = (f), \ 3107839a050SYann Gautier } 3117839a050SYann Gautier 312d4151d2fSYann Gautier #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents) \ 313d4151d2fSYann Gautier [_ ## _label ## _SEL] = { \ 314d4151d2fSYann Gautier .offset = _rcc_selr, \ 315d4151d2fSYann Gautier .src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \ 3168ae08dcdSEtienne Carriere .msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \ 3178ae08dcdSEtienne Carriere (_rcc_selr ## _ ## _label ## SRC_SHIFT), \ 318d4151d2fSYann Gautier .parent = (_parents), \ 319d4151d2fSYann Gautier .nb_parent = ARRAY_SIZE(_parents) \ 3207839a050SYann Gautier } 3217839a050SYann Gautier 3220d21680cSYann Gautier #define _CLK_PLL(idx, type, off1, off2, off3, \ 3237839a050SYann Gautier off4, off5, off6, \ 3247839a050SYann Gautier p1, p2, p3, p4) \ 3257839a050SYann Gautier [(idx)] = { \ 3267839a050SYann Gautier .plltype = (type), \ 3277839a050SYann Gautier .rckxselr = (off1), \ 3287839a050SYann Gautier .pllxcfgr1 = (off2), \ 3297839a050SYann Gautier .pllxcfgr2 = (off3), \ 3307839a050SYann Gautier .pllxfracr = (off4), \ 3317839a050SYann Gautier .pllxcr = (off5), \ 3327839a050SYann Gautier .pllxcsgr = (off6), \ 3337839a050SYann Gautier .refclk[0] = (p1), \ 3347839a050SYann Gautier .refclk[1] = (p2), \ 3357839a050SYann Gautier .refclk[2] = (p3), \ 3367839a050SYann Gautier .refclk[3] = (p4), \ 3377839a050SYann Gautier } 3387839a050SYann Gautier 3390d21680cSYann Gautier #define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) 3400d21680cSYann Gautier 3417839a050SYann Gautier static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { 3420d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK), 3430d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK), 3440d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK), 3450d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK), 3460d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), 3470d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), 3480d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), 3490d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), 3500d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK), 3510d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), 3520d21680cSYann Gautier _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), 3537839a050SYann Gautier 3540d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), 3550d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), 3560d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), 3570d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), 3580d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), 3590d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), 3600d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), 3610d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), 3620d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), 3630d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), 3640d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), 3657839a050SYann Gautier 3660d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), 3670d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), 3687839a050SYann Gautier 369f33b2433SYann Gautier _CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), 370f33b2433SYann Gautier 3710d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), 3720d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), 3730d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), 3747839a050SYann Gautier 3750d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), 3760d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), 3770d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), 378d4151d2fSYann Gautier _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL), 3790d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), 3800d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), 3810d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), 3820d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), 3830d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), 3840d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), 3850d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), 3867839a050SYann Gautier 3870d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), 3880d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), 3897839a050SYann Gautier 3900d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), 3910d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), 3920d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), 3930d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), 3940d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), 3950d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), 3960d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), 3970d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), 3980d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), 3990d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), 4000d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), 4017839a050SYann Gautier 4020d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), 4030d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), 4040d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), 4050d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), 4060d21680cSYann Gautier _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), 4077839a050SYann Gautier 4080d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), 4090d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), 4100d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), 4110d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), 4120d21680cSYann Gautier _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), 4137839a050SYann Gautier 414016af006SEtienne Carriere _CLK_SELEC(RCC_BDCR, 20, RTC, _RTC_SEL), 4150d21680cSYann Gautier _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), 4167839a050SYann Gautier }; 4177839a050SYann Gautier 4180d21680cSYann Gautier static const uint8_t i2c12_parents[] = { 4190d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4200d21680cSYann Gautier }; 4210d21680cSYann Gautier 4220d21680cSYann Gautier static const uint8_t i2c35_parents[] = { 4230d21680cSYann Gautier _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 4240d21680cSYann Gautier }; 4250d21680cSYann Gautier 4260d21680cSYann Gautier static const uint8_t stgen_parents[] = { 4270d21680cSYann Gautier _HSI_KER, _HSE_KER 4280d21680cSYann Gautier }; 4290d21680cSYann Gautier 4300d21680cSYann Gautier static const uint8_t i2c46_parents[] = { 4310d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER 4320d21680cSYann Gautier }; 4330d21680cSYann Gautier 4340d21680cSYann Gautier static const uint8_t spi6_parents[] = { 4350d21680cSYann Gautier _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q 4360d21680cSYann Gautier }; 4370d21680cSYann Gautier 4380d21680cSYann Gautier static const uint8_t usart1_parents[] = { 4390d21680cSYann Gautier _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER 4400d21680cSYann Gautier }; 4410d21680cSYann Gautier 4420d21680cSYann Gautier static const uint8_t rng1_parents[] = { 4430d21680cSYann Gautier _CSI, _PLL4_R, _LSE, _LSI 4440d21680cSYann Gautier }; 4450d21680cSYann Gautier 4460d21680cSYann Gautier static const uint8_t uart6_parents[] = { 4470d21680cSYann Gautier _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4480d21680cSYann Gautier }; 4490d21680cSYann Gautier 4500d21680cSYann Gautier static const uint8_t uart234578_parents[] = { 4510d21680cSYann Gautier _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4520d21680cSYann Gautier }; 4530d21680cSYann Gautier 4540d21680cSYann Gautier static const uint8_t sdmmc12_parents[] = { 4550d21680cSYann Gautier _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER 4560d21680cSYann Gautier }; 4570d21680cSYann Gautier 4580d21680cSYann Gautier static const uint8_t sdmmc3_parents[] = { 4590d21680cSYann Gautier _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER 4600d21680cSYann Gautier }; 4610d21680cSYann Gautier 4620d21680cSYann Gautier static const uint8_t qspi_parents[] = { 4630d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4640d21680cSYann Gautier }; 4650d21680cSYann Gautier 4660d21680cSYann Gautier static const uint8_t fmc_parents[] = { 4670d21680cSYann Gautier _ACLK, _PLL3_R, _PLL4_P, _CK_PER 4680d21680cSYann Gautier }; 4690d21680cSYann Gautier 470b8fe48b6SEtienne Carriere static const uint8_t axiss_parents[] = { 471b8fe48b6SEtienne Carriere _HSI, _HSE, _PLL2_P 4720d21680cSYann Gautier }; 4730d21680cSYann Gautier 474b8fe48b6SEtienne Carriere static const uint8_t mcuss_parents[] = { 475b8fe48b6SEtienne Carriere _HSI, _HSE, _CSI, _PLL3_P 476b053a22eSYann Gautier }; 477b053a22eSYann Gautier 4780d21680cSYann Gautier static const uint8_t usbphy_parents[] = { 4790d21680cSYann Gautier _HSE_KER, _PLL4_R, _HSE_KER_DIV2 4800d21680cSYann Gautier }; 4810d21680cSYann Gautier 4820d21680cSYann Gautier static const uint8_t usbo_parents[] = { 4830d21680cSYann Gautier _PLL4_R, _USB_PHY_48 4840d21680cSYann Gautier }; 4857839a050SYann Gautier 4868fbcd9e4SEtienne Carriere static const uint8_t mpu_parents[] = { 4878fbcd9e4SEtienne Carriere _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ 4888fbcd9e4SEtienne Carriere }; 4898fbcd9e4SEtienne Carriere 4908fbcd9e4SEtienne Carriere static const uint8_t per_parents[] = { 4918fbcd9e4SEtienne Carriere _HSI, _HSE, _CSI, 4928fbcd9e4SEtienne Carriere }; 4938fbcd9e4SEtienne Carriere 494016af006SEtienne Carriere static const uint8_t rtc_parents[] = { 495cbd2e8a6SGabriel Fernandez _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC 496016af006SEtienne Carriere }; 497016af006SEtienne Carriere 4987839a050SYann Gautier static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { 499d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), 500d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), 501d4151d2fSYann Gautier _CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents), 502d4151d2fSYann Gautier _CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents), 503d4151d2fSYann Gautier _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), 504d4151d2fSYann Gautier _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), 505d4151d2fSYann Gautier _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), 5068fbcd9e4SEtienne Carriere _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents), 507288f5cf2SYann Gautier _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents), 508016af006SEtienne Carriere _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents), 509d4151d2fSYann Gautier _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), 510d4151d2fSYann Gautier _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), 511d4151d2fSYann Gautier _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), 512d4151d2fSYann Gautier _CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents), 513d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents), 514d4151d2fSYann Gautier _CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents), 515d4151d2fSYann Gautier _CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents), 516d4151d2fSYann Gautier _CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents), 517b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents), 518b8fe48b6SEtienne Carriere _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents), 519d4151d2fSYann Gautier _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents), 520d4151d2fSYann Gautier _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents), 5217839a050SYann Gautier }; 5227839a050SYann Gautier 5237839a050SYann Gautier /* Define characteristic of PLL according type */ 5247839a050SYann Gautier #define DIVN_MIN 24 5257839a050SYann Gautier static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { 5267839a050SYann Gautier [PLL_800] = { 5277839a050SYann Gautier .refclk_min = 4, 5287839a050SYann Gautier .refclk_max = 16, 5297839a050SYann Gautier .divn_max = 99, 5307839a050SYann Gautier }, 5317839a050SYann Gautier [PLL_1600] = { 5327839a050SYann Gautier .refclk_min = 8, 5337839a050SYann Gautier .refclk_max = 16, 5347839a050SYann Gautier .divn_max = 199, 5357839a050SYann Gautier }, 5367839a050SYann Gautier }; 5377839a050SYann Gautier 5387839a050SYann Gautier /* PLLNCFGR2 register divider by output */ 5397839a050SYann Gautier static const uint8_t pllncfgr2[_DIV_NB] = { 5407839a050SYann Gautier [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, 5417839a050SYann Gautier [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, 5420d21680cSYann Gautier [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, 5437839a050SYann Gautier }; 5447839a050SYann Gautier 5457839a050SYann Gautier static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { 5460d21680cSYann Gautier _CLK_PLL(_PLL1, PLL_1600, 5477839a050SYann Gautier RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, 5487839a050SYann Gautier RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, 5497839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5500d21680cSYann Gautier _CLK_PLL(_PLL2, PLL_1600, 5517839a050SYann Gautier RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, 5527839a050SYann Gautier RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, 5537839a050SYann Gautier _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5540d21680cSYann Gautier _CLK_PLL(_PLL3, PLL_800, 5557839a050SYann Gautier RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, 5567839a050SYann Gautier RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, 5577839a050SYann Gautier _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), 5580d21680cSYann Gautier _CLK_PLL(_PLL4, PLL_800, 5597839a050SYann Gautier RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, 5607839a050SYann Gautier RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, 5617839a050SYann Gautier _HSI, _HSE, _CSI, _I2S_CKIN), 5627839a050SYann Gautier }; 5637839a050SYann Gautier 5647839a050SYann Gautier /* Prescaler table lookups for clock computation */ 565b053a22eSYann Gautier /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ 566b053a22eSYann Gautier static const uint8_t stm32mp1_mcu_div[16] = { 567b053a22eSYann Gautier 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 568b053a22eSYann Gautier }; 5697839a050SYann Gautier 5707839a050SYann Gautier /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ 5717839a050SYann Gautier #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div 5727839a050SYann Gautier #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div 5737839a050SYann Gautier static const uint8_t stm32mp1_mpu_apbx_div[8] = { 5747839a050SYann Gautier 0, 1, 2, 3, 4, 4, 4, 4 5757839a050SYann Gautier }; 5767839a050SYann Gautier 5777839a050SYann Gautier /* div = /1 /2 /3 /4 */ 5787839a050SYann Gautier static const uint8_t stm32mp1_axi_div[8] = { 5797839a050SYann Gautier 1, 2, 3, 4, 4, 4, 4, 4 5807839a050SYann Gautier }; 5817839a050SYann Gautier 58237e8295aSEtienne Carriere static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { 58337e8295aSEtienne Carriere [_HSI] = "HSI", 58437e8295aSEtienne Carriere [_HSE] = "HSE", 58537e8295aSEtienne Carriere [_CSI] = "CSI", 58637e8295aSEtienne Carriere [_LSI] = "LSI", 58737e8295aSEtienne Carriere [_LSE] = "LSE", 58837e8295aSEtienne Carriere [_I2S_CKIN] = "I2S_CKIN", 58937e8295aSEtienne Carriere [_HSI_KER] = "HSI_KER", 59037e8295aSEtienne Carriere [_HSE_KER] = "HSE_KER", 59137e8295aSEtienne Carriere [_HSE_KER_DIV2] = "HSE_KER_DIV2", 592cbd2e8a6SGabriel Fernandez [_HSE_RTC] = "HSE_RTC", 59337e8295aSEtienne Carriere [_CSI_KER] = "CSI_KER", 59437e8295aSEtienne Carriere [_PLL1_P] = "PLL1_P", 59537e8295aSEtienne Carriere [_PLL1_Q] = "PLL1_Q", 59637e8295aSEtienne Carriere [_PLL1_R] = "PLL1_R", 59737e8295aSEtienne Carriere [_PLL2_P] = "PLL2_P", 59837e8295aSEtienne Carriere [_PLL2_Q] = "PLL2_Q", 59937e8295aSEtienne Carriere [_PLL2_R] = "PLL2_R", 60037e8295aSEtienne Carriere [_PLL3_P] = "PLL3_P", 60137e8295aSEtienne Carriere [_PLL3_Q] = "PLL3_Q", 60237e8295aSEtienne Carriere [_PLL3_R] = "PLL3_R", 60337e8295aSEtienne Carriere [_PLL4_P] = "PLL4_P", 60437e8295aSEtienne Carriere [_PLL4_Q] = "PLL4_Q", 60537e8295aSEtienne Carriere [_PLL4_R] = "PLL4_R", 60637e8295aSEtienne Carriere [_ACLK] = "ACLK", 60737e8295aSEtienne Carriere [_PCLK1] = "PCLK1", 60837e8295aSEtienne Carriere [_PCLK2] = "PCLK2", 60937e8295aSEtienne Carriere [_PCLK3] = "PCLK3", 61037e8295aSEtienne Carriere [_PCLK4] = "PCLK4", 61137e8295aSEtienne Carriere [_PCLK5] = "PCLK5", 61237e8295aSEtienne Carriere [_HCLK6] = "KCLK6", 61337e8295aSEtienne Carriere [_HCLK2] = "HCLK2", 61437e8295aSEtienne Carriere [_CK_PER] = "CK_PER", 61537e8295aSEtienne Carriere [_CK_MPU] = "CK_MPU", 61637e8295aSEtienne Carriere [_CK_MCU] = "CK_MCU", 61737e8295aSEtienne Carriere [_USB_PHY_48] = "USB_PHY_48", 61837e8295aSEtienne Carriere }; 61937e8295aSEtienne Carriere 6200d21680cSYann Gautier /* RCC clock device driver private */ 6210d21680cSYann Gautier static unsigned long stm32mp1_osc[NB_OSC]; 6220d21680cSYann Gautier static struct spinlock reg_lock; 6230d21680cSYann Gautier static unsigned int gate_refcounts[NB_GATES]; 6240d21680cSYann Gautier static struct spinlock refcount_lock; 6257839a050SYann Gautier 6260d21680cSYann Gautier static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) 6270d21680cSYann Gautier { 6280d21680cSYann Gautier return &stm32mp1_clk_gate[idx]; 6290d21680cSYann Gautier } 6307839a050SYann Gautier 6310d21680cSYann Gautier static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) 6320d21680cSYann Gautier { 6330d21680cSYann Gautier return &stm32mp1_clk_sel[idx]; 6340d21680cSYann Gautier } 6350d21680cSYann Gautier 6360d21680cSYann Gautier static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) 6370d21680cSYann Gautier { 6380d21680cSYann Gautier return &stm32mp1_clk_pll[idx]; 6390d21680cSYann Gautier } 6400d21680cSYann Gautier 6410d21680cSYann Gautier static void stm32mp1_clk_lock(struct spinlock *lock) 6420d21680cSYann Gautier { 643e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6440d21680cSYann Gautier /* Assume interrupts are masked */ 6450d21680cSYann Gautier spin_lock(lock); 6460d21680cSYann Gautier } 647e463d3f4SYann Gautier } 6480d21680cSYann Gautier 6490d21680cSYann Gautier static void stm32mp1_clk_unlock(struct spinlock *lock) 6500d21680cSYann Gautier { 651e463d3f4SYann Gautier if (stm32mp_lock_available()) { 6520d21680cSYann Gautier spin_unlock(lock); 6530d21680cSYann Gautier } 654e463d3f4SYann Gautier } 6550d21680cSYann Gautier 6560d21680cSYann Gautier bool stm32mp1_rcc_is_secure(void) 6570d21680cSYann Gautier { 6580d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6591bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN; 6600d21680cSYann Gautier 6611bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 6620d21680cSYann Gautier } 6630d21680cSYann Gautier 664b053a22eSYann Gautier bool stm32mp1_rcc_is_mckprot(void) 665b053a22eSYann Gautier { 666b053a22eSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 6671bb9072aSEtienne Carriere uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; 668b053a22eSYann Gautier 6691bb9072aSEtienne Carriere return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; 670b053a22eSYann Gautier } 671b053a22eSYann Gautier 6720d21680cSYann Gautier void stm32mp1_clk_rcc_regs_lock(void) 6730d21680cSYann Gautier { 6740d21680cSYann Gautier stm32mp1_clk_lock(®_lock); 6750d21680cSYann Gautier } 6760d21680cSYann Gautier 6770d21680cSYann Gautier void stm32mp1_clk_rcc_regs_unlock(void) 6780d21680cSYann Gautier { 6790d21680cSYann Gautier stm32mp1_clk_unlock(®_lock); 6800d21680cSYann Gautier } 6810d21680cSYann Gautier 6820d21680cSYann Gautier static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) 6837839a050SYann Gautier { 6847839a050SYann Gautier if (idx >= NB_OSC) { 6857839a050SYann Gautier return 0; 6867839a050SYann Gautier } 6877839a050SYann Gautier 6880d21680cSYann Gautier return stm32mp1_osc[idx]; 6897839a050SYann Gautier } 6907839a050SYann Gautier 6910d21680cSYann Gautier static int stm32mp1_clk_get_gated_id(unsigned long id) 6927839a050SYann Gautier { 6930d21680cSYann Gautier unsigned int i; 6947839a050SYann Gautier 6950d21680cSYann Gautier for (i = 0U; i < NB_GATES; i++) { 6960d21680cSYann Gautier if (gate_ref(i)->index == id) { 6977839a050SYann Gautier return i; 6987839a050SYann Gautier } 6997839a050SYann Gautier } 7007839a050SYann Gautier 70144fb470bSYann Gautier ERROR("%s: clk id %lu not found\n", __func__, id); 7027839a050SYann Gautier 7037839a050SYann Gautier return -EINVAL; 7047839a050SYann Gautier } 7057839a050SYann Gautier 7060d21680cSYann Gautier static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) 7077839a050SYann Gautier { 7080d21680cSYann Gautier return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); 7097839a050SYann Gautier } 7107839a050SYann Gautier 7110d21680cSYann Gautier static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) 7127839a050SYann Gautier { 7130d21680cSYann Gautier return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); 7147839a050SYann Gautier } 7157839a050SYann Gautier 7160d21680cSYann Gautier static int stm32mp1_clk_get_parent(unsigned long id) 7177839a050SYann Gautier { 7180d21680cSYann Gautier const struct stm32mp1_clk_sel *sel; 7198fbcd9e4SEtienne Carriere uint32_t p_sel; 7207839a050SYann Gautier int i; 7217839a050SYann Gautier enum stm32mp1_parent_id p; 7227839a050SYann Gautier enum stm32mp1_parent_sel s; 7230d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7247839a050SYann Gautier 7258fbcd9e4SEtienne Carriere /* Few non gateable clock have a static parent ID, find them */ 7268fbcd9e4SEtienne Carriere i = (int)clock_id2parent_id(id); 7278fbcd9e4SEtienne Carriere if (i != _UNKNOWN_ID) { 7288fbcd9e4SEtienne Carriere return i; 7297839a050SYann Gautier } 7307839a050SYann Gautier 7310d21680cSYann Gautier i = stm32mp1_clk_get_gated_id(id); 7327839a050SYann Gautier if (i < 0) { 7330d21680cSYann Gautier panic(); 7347839a050SYann Gautier } 7357839a050SYann Gautier 7360d21680cSYann Gautier p = stm32mp1_clk_get_fixed_parent(i); 7377839a050SYann Gautier if (p < _PARENT_NB) { 7387839a050SYann Gautier return (int)p; 7397839a050SYann Gautier } 7407839a050SYann Gautier 7410d21680cSYann Gautier s = stm32mp1_clk_get_sel(i); 7420d21680cSYann Gautier if (s == _UNKNOWN_SEL) { 7430d21680cSYann Gautier return -EINVAL; 7440d21680cSYann Gautier } 7457839a050SYann Gautier if (s >= _PARENT_SEL_NB) { 7460d21680cSYann Gautier panic(); 7477839a050SYann Gautier } 7487839a050SYann Gautier 7490d21680cSYann Gautier sel = clk_sel_ref(s); 7508ae08dcdSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) & 7518ae08dcdSEtienne Carriere (sel->msk << sel->src)) >> sel->src; 7520d21680cSYann Gautier if (p_sel < sel->nb_parent) { 7530d21680cSYann Gautier return (int)sel->parent[p_sel]; 7547839a050SYann Gautier } 7557839a050SYann Gautier 7567839a050SYann Gautier return -EINVAL; 7577839a050SYann Gautier } 7587839a050SYann Gautier 7590d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) 7607839a050SYann Gautier { 7610d21680cSYann Gautier uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); 7620d21680cSYann Gautier uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; 7637839a050SYann Gautier 7640d21680cSYann Gautier return stm32mp1_clk_get_fixed(pll->refclk[src]); 7657839a050SYann Gautier } 7667839a050SYann Gautier 7677839a050SYann Gautier /* 7687839a050SYann Gautier * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL 7697839a050SYann Gautier * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) 7707839a050SYann Gautier * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) 7717839a050SYann Gautier * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) 7727839a050SYann Gautier */ 7730d21680cSYann Gautier static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) 7747839a050SYann Gautier { 7757839a050SYann Gautier unsigned long refclk, fvco; 7767839a050SYann Gautier uint32_t cfgr1, fracr, divm, divn; 7770d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 7787839a050SYann Gautier 7790d21680cSYann Gautier cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); 7800d21680cSYann Gautier fracr = mmio_read_32(rcc_base + pll->pllxfracr); 7817839a050SYann Gautier 7827839a050SYann Gautier divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; 7837839a050SYann Gautier divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; 7847839a050SYann Gautier 7850d21680cSYann Gautier refclk = stm32mp1_pll_get_fref(pll); 7867839a050SYann Gautier 7877839a050SYann Gautier /* 7887839a050SYann Gautier * With FRACV : 7897839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) 7907839a050SYann Gautier * Without FRACV 7917839a050SYann Gautier * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) 7927839a050SYann Gautier */ 7937839a050SYann Gautier if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { 7940d21680cSYann Gautier uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> 7950d21680cSYann Gautier RCC_PLLNFRACR_FRACV_SHIFT; 7967839a050SYann Gautier unsigned long long numerator, denominator; 7977839a050SYann Gautier 7980d21680cSYann Gautier numerator = (((unsigned long long)divn + 1U) << 13) + fracv; 7990d21680cSYann Gautier numerator = refclk * numerator; 8007839a050SYann Gautier denominator = ((unsigned long long)divm + 1U) << 13; 8017839a050SYann Gautier fvco = (unsigned long)(numerator / denominator); 8027839a050SYann Gautier } else { 8037839a050SYann Gautier fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); 8047839a050SYann Gautier } 8057839a050SYann Gautier 8067839a050SYann Gautier return fvco; 8077839a050SYann Gautier } 8087839a050SYann Gautier 8090d21680cSYann Gautier static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, 8107839a050SYann Gautier enum stm32mp1_div_id div_id) 8117839a050SYann Gautier { 8120d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 8137839a050SYann Gautier unsigned long dfout; 8147839a050SYann Gautier uint32_t cfgr2, divy; 8157839a050SYann Gautier 8167839a050SYann Gautier if (div_id >= _DIV_NB) { 8177839a050SYann Gautier return 0; 8187839a050SYann Gautier } 8197839a050SYann Gautier 8200d21680cSYann Gautier cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); 8217839a050SYann Gautier divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; 8227839a050SYann Gautier 8230d21680cSYann Gautier dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); 8247839a050SYann Gautier 8257839a050SYann Gautier return dfout; 8267839a050SYann Gautier } 8277839a050SYann Gautier 8280d21680cSYann Gautier static unsigned long get_clock_rate(int p) 8297839a050SYann Gautier { 8307839a050SYann Gautier uint32_t reg, clkdiv; 8317839a050SYann Gautier unsigned long clock = 0; 8320d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 8337839a050SYann Gautier 8347839a050SYann Gautier switch (p) { 8357839a050SYann Gautier case _CK_MPU: 8367839a050SYann Gautier /* MPU sub system */ 8370d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKSELR); 8387839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8397839a050SYann Gautier case RCC_MPCKSELR_HSI: 8400d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8417839a050SYann Gautier break; 8427839a050SYann Gautier case RCC_MPCKSELR_HSE: 8430d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8447839a050SYann Gautier break; 8457839a050SYann Gautier case RCC_MPCKSELR_PLL: 8460d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8477839a050SYann Gautier break; 8487839a050SYann Gautier case RCC_MPCKSELR_PLL_MPUDIV: 8490d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 8507839a050SYann Gautier 8510d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); 8527839a050SYann Gautier clkdiv = reg & RCC_MPUDIV_MASK; 853602ae2f2SGabriel Fernandez clock >>= stm32mp1_mpu_div[clkdiv]; 8547839a050SYann Gautier break; 8557839a050SYann Gautier default: 8567839a050SYann Gautier break; 8577839a050SYann Gautier } 8587839a050SYann Gautier break; 8597839a050SYann Gautier /* AXI sub system */ 8607839a050SYann Gautier case _ACLK: 8617839a050SYann Gautier case _HCLK2: 8627839a050SYann Gautier case _HCLK6: 8637839a050SYann Gautier case _PCLK4: 8647839a050SYann Gautier case _PCLK5: 8650d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); 8667839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 8677839a050SYann Gautier case RCC_ASSCKSELR_HSI: 8680d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 8697839a050SYann Gautier break; 8707839a050SYann Gautier case RCC_ASSCKSELR_HSE: 8710d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 8727839a050SYann Gautier break; 8737839a050SYann Gautier case RCC_ASSCKSELR_PLL: 8740d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 8757839a050SYann Gautier break; 8767839a050SYann Gautier default: 8777839a050SYann Gautier break; 8787839a050SYann Gautier } 8797839a050SYann Gautier 8807839a050SYann Gautier /* System clock divider */ 8810d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_AXIDIVR); 8827839a050SYann Gautier clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; 8837839a050SYann Gautier 8847839a050SYann Gautier switch (p) { 8857839a050SYann Gautier case _PCLK4: 8860d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB4DIVR); 8877839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8887839a050SYann Gautier break; 8897839a050SYann Gautier case _PCLK5: 8900d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB5DIVR); 8917839a050SYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8927839a050SYann Gautier break; 8937839a050SYann Gautier default: 8947839a050SYann Gautier break; 8957839a050SYann Gautier } 8967839a050SYann Gautier break; 897b053a22eSYann Gautier /* MCU sub system */ 898b053a22eSYann Gautier case _CK_MCU: 899b053a22eSYann Gautier case _PCLK1: 900b053a22eSYann Gautier case _PCLK2: 901b053a22eSYann Gautier case _PCLK3: 902b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); 903b053a22eSYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 904b053a22eSYann Gautier case RCC_MSSCKSELR_HSI: 905b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 906b053a22eSYann Gautier break; 907b053a22eSYann Gautier case RCC_MSSCKSELR_HSE: 908b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 909b053a22eSYann Gautier break; 910b053a22eSYann Gautier case RCC_MSSCKSELR_CSI: 911b053a22eSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 912b053a22eSYann Gautier break; 913b053a22eSYann Gautier case RCC_MSSCKSELR_PLL: 914b053a22eSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 915b053a22eSYann Gautier break; 916b053a22eSYann Gautier default: 917b053a22eSYann Gautier break; 918b053a22eSYann Gautier } 919b053a22eSYann Gautier 920b053a22eSYann Gautier /* MCU clock divider */ 921b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_MCUDIVR); 922b053a22eSYann Gautier clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; 923b053a22eSYann Gautier 924b053a22eSYann Gautier switch (p) { 925b053a22eSYann Gautier case _PCLK1: 926b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB1DIVR); 927b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 928b053a22eSYann Gautier break; 929b053a22eSYann Gautier case _PCLK2: 930b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB2DIVR); 931b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 932b053a22eSYann Gautier break; 933b053a22eSYann Gautier case _PCLK3: 934b053a22eSYann Gautier reg = mmio_read_32(rcc_base + RCC_APB3DIVR); 935b053a22eSYann Gautier clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 936b053a22eSYann Gautier break; 937b053a22eSYann Gautier case _CK_MCU: 938b053a22eSYann Gautier default: 939b053a22eSYann Gautier break; 940b053a22eSYann Gautier } 941b053a22eSYann Gautier break; 9427839a050SYann Gautier case _CK_PER: 9430d21680cSYann Gautier reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); 9447839a050SYann Gautier switch (reg & RCC_SELR_SRC_MASK) { 9457839a050SYann Gautier case RCC_CPERCKSELR_HSI: 9460d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9477839a050SYann Gautier break; 9487839a050SYann Gautier case RCC_CPERCKSELR_HSE: 9490d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9507839a050SYann Gautier break; 9517839a050SYann Gautier case RCC_CPERCKSELR_CSI: 9520d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9537839a050SYann Gautier break; 9547839a050SYann Gautier default: 9557839a050SYann Gautier break; 9567839a050SYann Gautier } 9577839a050SYann Gautier break; 9587839a050SYann Gautier case _HSI: 9597839a050SYann Gautier case _HSI_KER: 9600d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSI); 9617839a050SYann Gautier break; 9627839a050SYann Gautier case _CSI: 9637839a050SYann Gautier case _CSI_KER: 9640d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_CSI); 9657839a050SYann Gautier break; 9667839a050SYann Gautier case _HSE: 9677839a050SYann Gautier case _HSE_KER: 9680d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE); 9697839a050SYann Gautier break; 9707839a050SYann Gautier case _HSE_KER_DIV2: 9710d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_HSE) >> 1; 9727839a050SYann Gautier break; 973cbd2e8a6SGabriel Fernandez case _HSE_RTC: 974cbd2e8a6SGabriel Fernandez clock = stm32mp1_clk_get_fixed(_HSE); 975cbd2e8a6SGabriel Fernandez clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; 976cbd2e8a6SGabriel Fernandez break; 9777839a050SYann Gautier case _LSI: 9780d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSI); 9797839a050SYann Gautier break; 9807839a050SYann Gautier case _LSE: 9810d21680cSYann Gautier clock = stm32mp1_clk_get_fixed(_LSE); 9827839a050SYann Gautier break; 9837839a050SYann Gautier /* PLL */ 9847839a050SYann Gautier case _PLL1_P: 9850d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 9867839a050SYann Gautier break; 9877839a050SYann Gautier case _PLL1_Q: 9880d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); 9897839a050SYann Gautier break; 9907839a050SYann Gautier case _PLL1_R: 9910d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); 9927839a050SYann Gautier break; 9937839a050SYann Gautier case _PLL2_P: 9940d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 9957839a050SYann Gautier break; 9967839a050SYann Gautier case _PLL2_Q: 9970d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); 9987839a050SYann Gautier break; 9997839a050SYann Gautier case _PLL2_R: 10000d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); 10017839a050SYann Gautier break; 10027839a050SYann Gautier case _PLL3_P: 10030d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 10047839a050SYann Gautier break; 10057839a050SYann Gautier case _PLL3_Q: 10060d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); 10077839a050SYann Gautier break; 10087839a050SYann Gautier case _PLL3_R: 10090d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); 10107839a050SYann Gautier break; 10117839a050SYann Gautier case _PLL4_P: 10120d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); 10137839a050SYann Gautier break; 10147839a050SYann Gautier case _PLL4_Q: 10150d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); 10167839a050SYann Gautier break; 10177839a050SYann Gautier case _PLL4_R: 10180d21680cSYann Gautier clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); 10197839a050SYann Gautier break; 10207839a050SYann Gautier /* Other */ 10217839a050SYann Gautier case _USB_PHY_48: 10220d21680cSYann Gautier clock = USB_PHY_48_MHZ; 10237839a050SYann Gautier break; 10247839a050SYann Gautier default: 10257839a050SYann Gautier break; 10267839a050SYann Gautier } 10277839a050SYann Gautier 10287839a050SYann Gautier return clock; 10297839a050SYann Gautier } 10307839a050SYann Gautier 10310d21680cSYann Gautier static void __clk_enable(struct stm32mp1_clk_gate const *gate) 10320d21680cSYann Gautier { 10330d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10340d21680cSYann Gautier 103525be845eSEtienne Carriere VERBOSE("Enable clock %u\n", gate->index); 103625be845eSEtienne Carriere 10370d21680cSYann Gautier if (gate->set_clr != 0U) { 10380d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); 10390d21680cSYann Gautier } else { 10400d21680cSYann Gautier mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10410d21680cSYann Gautier } 10420d21680cSYann Gautier } 10430d21680cSYann Gautier 10440d21680cSYann Gautier static void __clk_disable(struct stm32mp1_clk_gate const *gate) 10450d21680cSYann Gautier { 10460d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10470d21680cSYann Gautier 104825be845eSEtienne Carriere VERBOSE("Disable clock %u\n", gate->index); 104925be845eSEtienne Carriere 10500d21680cSYann Gautier if (gate->set_clr != 0U) { 10510d21680cSYann Gautier mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, 10520d21680cSYann Gautier BIT(gate->bit)); 10530d21680cSYann Gautier } else { 10540d21680cSYann Gautier mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit)); 10550d21680cSYann Gautier } 10560d21680cSYann Gautier } 10570d21680cSYann Gautier 10580d21680cSYann Gautier static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) 10590d21680cSYann Gautier { 10600d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 10610d21680cSYann Gautier 10620d21680cSYann Gautier return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); 10630d21680cSYann Gautier } 10640d21680cSYann Gautier 106535848200SEtienne Carriere /* Oscillators and PLLs are not gated at runtime */ 106635848200SEtienne Carriere static bool clock_is_always_on(unsigned long id) 106735848200SEtienne Carriere { 106835848200SEtienne Carriere switch (id) { 106935848200SEtienne Carriere case CK_HSE: 107035848200SEtienne Carriere case CK_CSI: 107135848200SEtienne Carriere case CK_LSI: 107235848200SEtienne Carriere case CK_LSE: 107335848200SEtienne Carriere case CK_HSI: 107435848200SEtienne Carriere case CK_HSE_DIV2: 107535848200SEtienne Carriere case PLL1_Q: 107635848200SEtienne Carriere case PLL1_R: 107735848200SEtienne Carriere case PLL2_P: 107835848200SEtienne Carriere case PLL2_Q: 107935848200SEtienne Carriere case PLL2_R: 108035848200SEtienne Carriere case PLL3_P: 108135848200SEtienne Carriere case PLL3_Q: 108235848200SEtienne Carriere case PLL3_R: 1083bf39318dSYann Gautier case CK_AXI: 1084bf39318dSYann Gautier case CK_MPU: 1085bf39318dSYann Gautier case CK_MCU: 10865b111c74SHE Shushan case RTC: 108735848200SEtienne Carriere return true; 108835848200SEtienne Carriere default: 108935848200SEtienne Carriere return false; 109035848200SEtienne Carriere } 109135848200SEtienne Carriere } 109235848200SEtienne Carriere 1093*2444d231SYann Gautier static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt) 10940d21680cSYann Gautier { 10950d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 109635848200SEtienne Carriere int i; 10970d21680cSYann Gautier 109835848200SEtienne Carriere if (clock_is_always_on(id)) { 109935848200SEtienne Carriere return; 110035848200SEtienne Carriere } 110135848200SEtienne Carriere 110235848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11030d21680cSYann Gautier if (i < 0) { 110444fb470bSYann Gautier ERROR("Clock %lu can't be enabled\n", id); 11050d21680cSYann Gautier panic(); 11060d21680cSYann Gautier } 11070d21680cSYann Gautier 11080d21680cSYann Gautier gate = gate_ref(i); 1109*2444d231SYann Gautier 1110*2444d231SYann Gautier if (!with_refcnt) { 1111*2444d231SYann Gautier __clk_enable(gate); 1112*2444d231SYann Gautier return; 1113*2444d231SYann Gautier } 11140d21680cSYann Gautier 11150d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11160d21680cSYann Gautier 1117*2444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11180d21680cSYann Gautier __clk_enable(gate); 11190d21680cSYann Gautier } 11200d21680cSYann Gautier 1121*2444d231SYann Gautier gate_refcounts[i]++; 1122*2444d231SYann Gautier if (gate_refcounts[i] == UINT_MAX) { 1123*2444d231SYann Gautier ERROR("Clock %lu refcount reached max value\n", id); 1124*2444d231SYann Gautier panic(); 1125*2444d231SYann Gautier } 1126*2444d231SYann Gautier 11270d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11280d21680cSYann Gautier } 11290d21680cSYann Gautier 1130*2444d231SYann Gautier static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt) 11310d21680cSYann Gautier { 11320d21680cSYann Gautier const struct stm32mp1_clk_gate *gate; 113335848200SEtienne Carriere int i; 11340d21680cSYann Gautier 113535848200SEtienne Carriere if (clock_is_always_on(id)) { 113635848200SEtienne Carriere return; 113735848200SEtienne Carriere } 113835848200SEtienne Carriere 113935848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11400d21680cSYann Gautier if (i < 0) { 114144fb470bSYann Gautier ERROR("Clock %lu can't be disabled\n", id); 11420d21680cSYann Gautier panic(); 11430d21680cSYann Gautier } 11440d21680cSYann Gautier 11450d21680cSYann Gautier gate = gate_ref(i); 1146*2444d231SYann Gautier 1147*2444d231SYann Gautier if (!with_refcnt) { 1148*2444d231SYann Gautier __clk_disable(gate); 1149*2444d231SYann Gautier return; 1150*2444d231SYann Gautier } 11510d21680cSYann Gautier 11520d21680cSYann Gautier stm32mp1_clk_lock(&refcount_lock); 11530d21680cSYann Gautier 1154*2444d231SYann Gautier if (gate_refcounts[i] == 0U) { 1155*2444d231SYann Gautier ERROR("Clock %lu refcount reached 0\n", id); 1156*2444d231SYann Gautier panic(); 1157*2444d231SYann Gautier } 1158*2444d231SYann Gautier gate_refcounts[i]--; 1159*2444d231SYann Gautier 1160*2444d231SYann Gautier if (gate_refcounts[i] == 0U) { 11610d21680cSYann Gautier __clk_disable(gate); 11620d21680cSYann Gautier } 11630d21680cSYann Gautier 11640d21680cSYann Gautier stm32mp1_clk_unlock(&refcount_lock); 11650d21680cSYann Gautier } 11660d21680cSYann Gautier 116733667d29SYann Gautier static int stm32mp_clk_enable(unsigned long id) 11680d21680cSYann Gautier { 11690d21680cSYann Gautier __stm32mp1_clk_enable(id, true); 117033667d29SYann Gautier 117133667d29SYann Gautier return 0; 11720d21680cSYann Gautier } 11730d21680cSYann Gautier 117433667d29SYann Gautier static void stm32mp_clk_disable(unsigned long id) 11750d21680cSYann Gautier { 11760d21680cSYann Gautier __stm32mp1_clk_disable(id, true); 11770d21680cSYann Gautier } 11780d21680cSYann Gautier 117933667d29SYann Gautier static bool stm32mp_clk_is_enabled(unsigned long id) 11807839a050SYann Gautier { 118135848200SEtienne Carriere int i; 11827839a050SYann Gautier 118335848200SEtienne Carriere if (clock_is_always_on(id)) { 118435848200SEtienne Carriere return true; 118535848200SEtienne Carriere } 118635848200SEtienne Carriere 118735848200SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 11887839a050SYann Gautier if (i < 0) { 11890d21680cSYann Gautier panic(); 11907839a050SYann Gautier } 11917839a050SYann Gautier 11920d21680cSYann Gautier return __clk_is_enabled(gate_ref(i)); 11937839a050SYann Gautier } 11947839a050SYann Gautier 119533667d29SYann Gautier static unsigned long stm32mp_clk_get_rate(unsigned long id) 11967839a050SYann Gautier { 119733667d29SYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 11980d21680cSYann Gautier int p = stm32mp1_clk_get_parent(id); 119933667d29SYann Gautier uint32_t prescaler, timpre; 120033667d29SYann Gautier unsigned long parent_rate; 12017839a050SYann Gautier 12027839a050SYann Gautier if (p < 0) { 12037839a050SYann Gautier return 0; 12047839a050SYann Gautier } 12057839a050SYann Gautier 120633667d29SYann Gautier parent_rate = get_clock_rate(p); 120733667d29SYann Gautier 120833667d29SYann Gautier switch (id) { 120933667d29SYann Gautier case TIM2_K: 121033667d29SYann Gautier case TIM3_K: 121133667d29SYann Gautier case TIM4_K: 121233667d29SYann Gautier case TIM5_K: 121333667d29SYann Gautier case TIM6_K: 121433667d29SYann Gautier case TIM7_K: 121533667d29SYann Gautier case TIM12_K: 121633667d29SYann Gautier case TIM13_K: 121733667d29SYann Gautier case TIM14_K: 121833667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) & 121933667d29SYann Gautier RCC_APBXDIV_MASK; 122033667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & 122133667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 122233667d29SYann Gautier break; 122333667d29SYann Gautier 122433667d29SYann Gautier case TIM1_K: 122533667d29SYann Gautier case TIM8_K: 122633667d29SYann Gautier case TIM15_K: 122733667d29SYann Gautier case TIM16_K: 122833667d29SYann Gautier case TIM17_K: 122933667d29SYann Gautier prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) & 123033667d29SYann Gautier RCC_APBXDIV_MASK; 123133667d29SYann Gautier timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & 123233667d29SYann Gautier RCC_TIMGXPRER_TIMGXPRE; 123333667d29SYann Gautier break; 123433667d29SYann Gautier 123533667d29SYann Gautier default: 123633667d29SYann Gautier return parent_rate; 123733667d29SYann Gautier } 123833667d29SYann Gautier 123933667d29SYann Gautier if (prescaler == 0U) { 124033667d29SYann Gautier return parent_rate; 124133667d29SYann Gautier } 124233667d29SYann Gautier 124333667d29SYann Gautier return parent_rate * (timpre + 1U) * 2U; 12447839a050SYann Gautier } 12457839a050SYann Gautier 12460d21680cSYann Gautier static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) 12477839a050SYann Gautier { 12480d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12497839a050SYann Gautier 12500d21680cSYann Gautier if (enable) { 12517839a050SYann Gautier mmio_setbits_32(address, mask_on); 12527839a050SYann Gautier } else { 12537839a050SYann Gautier mmio_clrbits_32(address, mask_on); 12547839a050SYann Gautier } 12557839a050SYann Gautier } 12567839a050SYann Gautier 12570d21680cSYann Gautier static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) 12587839a050SYann Gautier { 12590d21680cSYann Gautier uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; 12600d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12610d21680cSYann Gautier 12620d21680cSYann Gautier mmio_write_32(address, mask_on); 12637839a050SYann Gautier } 12647839a050SYann Gautier 12650d21680cSYann Gautier static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) 12667839a050SYann Gautier { 1267dfdb057aSYann Gautier uint64_t timeout; 12687839a050SYann Gautier uint32_t mask_test; 12690d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + offset; 12707839a050SYann Gautier 12710d21680cSYann Gautier if (enable) { 12727839a050SYann Gautier mask_test = mask_rdy; 12737839a050SYann Gautier } else { 12747839a050SYann Gautier mask_test = 0; 12757839a050SYann Gautier } 12767839a050SYann Gautier 1277dfdb057aSYann Gautier timeout = timeout_init_us(OSCRDY_TIMEOUT); 12787839a050SYann Gautier while ((mmio_read_32(address) & mask_rdy) != mask_test) { 1279dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 12800d21680cSYann Gautier ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", 12817839a050SYann Gautier mask_rdy, address, enable, mmio_read_32(address)); 12827839a050SYann Gautier return -ETIMEDOUT; 12837839a050SYann Gautier } 12847839a050SYann Gautier } 12857839a050SYann Gautier 12867839a050SYann Gautier return 0; 12877839a050SYann Gautier } 12887839a050SYann Gautier 12890d21680cSYann Gautier static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) 12907839a050SYann Gautier { 12917839a050SYann Gautier uint32_t value; 12920d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 12937839a050SYann Gautier 12940d21680cSYann Gautier if (digbyp) { 12950d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); 12960d21680cSYann Gautier } 12970d21680cSYann Gautier 12980d21680cSYann Gautier if (bypass || digbyp) { 12990d21680cSYann Gautier mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); 13007839a050SYann Gautier } 13017839a050SYann Gautier 13027839a050SYann Gautier /* 13037839a050SYann Gautier * Warning: not recommended to switch directly from "high drive" 13047839a050SYann Gautier * to "medium low drive", and vice-versa. 13057839a050SYann Gautier */ 13060d21680cSYann Gautier value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> 13077839a050SYann Gautier RCC_BDCR_LSEDRV_SHIFT; 13087839a050SYann Gautier 13097839a050SYann Gautier while (value != lsedrv) { 13107839a050SYann Gautier if (value > lsedrv) { 13117839a050SYann Gautier value--; 13127839a050SYann Gautier } else { 13137839a050SYann Gautier value++; 13147839a050SYann Gautier } 13157839a050SYann Gautier 13160d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_BDCR, 13177839a050SYann Gautier RCC_BDCR_LSEDRV_MASK, 13187839a050SYann Gautier value << RCC_BDCR_LSEDRV_SHIFT); 13197839a050SYann Gautier } 13207839a050SYann Gautier 13210d21680cSYann Gautier stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); 13227839a050SYann Gautier } 13237839a050SYann Gautier 13240d21680cSYann Gautier static void stm32mp1_lse_wait(void) 13257839a050SYann Gautier { 13260d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { 13277839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13287839a050SYann Gautier } 13297839a050SYann Gautier } 13307839a050SYann Gautier 13310d21680cSYann Gautier static void stm32mp1_lsi_set(bool enable) 13327839a050SYann Gautier { 13330d21680cSYann Gautier stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); 13340d21680cSYann Gautier 13350d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { 13367839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13377839a050SYann Gautier } 13387839a050SYann Gautier } 13397839a050SYann Gautier 13400d21680cSYann Gautier static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) 13417839a050SYann Gautier { 13420d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13430d21680cSYann Gautier 13440d21680cSYann Gautier if (digbyp) { 13450d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); 13467839a050SYann Gautier } 13477839a050SYann Gautier 13480d21680cSYann Gautier if (bypass || digbyp) { 13490d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); 13500d21680cSYann Gautier } 13510d21680cSYann Gautier 13520d21680cSYann Gautier stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); 13530d21680cSYann Gautier if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { 13547839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13557839a050SYann Gautier } 13567839a050SYann Gautier 13577839a050SYann Gautier if (css) { 13580d21680cSYann Gautier mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); 13597839a050SYann Gautier } 136031e9750bSLionel Debieve 136131e9750bSLionel Debieve #if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER 136231e9750bSLionel Debieve if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) && 136331e9750bSLionel Debieve (!(digbyp || bypass))) { 136431e9750bSLionel Debieve panic(); 136531e9750bSLionel Debieve } 136631e9750bSLionel Debieve #endif 13677839a050SYann Gautier } 13687839a050SYann Gautier 13690d21680cSYann Gautier static void stm32mp1_csi_set(bool enable) 13707839a050SYann Gautier { 13710d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); 13720d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { 13737839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13747839a050SYann Gautier } 13757839a050SYann Gautier } 13767839a050SYann Gautier 13770d21680cSYann Gautier static void stm32mp1_hsi_set(bool enable) 13787839a050SYann Gautier { 13790d21680cSYann Gautier stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); 13800d21680cSYann Gautier if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { 13817839a050SYann Gautier VERBOSE("%s: failed\n", __func__); 13827839a050SYann Gautier } 13837839a050SYann Gautier } 13847839a050SYann Gautier 13850d21680cSYann Gautier static int stm32mp1_set_hsidiv(uint8_t hsidiv) 13867839a050SYann Gautier { 1387dfdb057aSYann Gautier uint64_t timeout; 13880d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 13890d21680cSYann Gautier uintptr_t address = rcc_base + RCC_OCRDYR; 13907839a050SYann Gautier 13910d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, 13927839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK, 13937839a050SYann Gautier RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); 13947839a050SYann Gautier 1395dfdb057aSYann Gautier timeout = timeout_init_us(HSIDIV_TIMEOUT); 13967839a050SYann Gautier while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { 1397dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 13980d21680cSYann Gautier ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", 13997839a050SYann Gautier address, mmio_read_32(address)); 14007839a050SYann Gautier return -ETIMEDOUT; 14017839a050SYann Gautier } 14027839a050SYann Gautier } 14037839a050SYann Gautier 14047839a050SYann Gautier return 0; 14057839a050SYann Gautier } 14067839a050SYann Gautier 14070d21680cSYann Gautier static int stm32mp1_hsidiv(unsigned long hsifreq) 14087839a050SYann Gautier { 14097839a050SYann Gautier uint8_t hsidiv; 14107839a050SYann Gautier uint32_t hsidivfreq = MAX_HSI_HZ; 14117839a050SYann Gautier 14127839a050SYann Gautier for (hsidiv = 0; hsidiv < 4U; hsidiv++) { 14137839a050SYann Gautier if (hsidivfreq == hsifreq) { 14147839a050SYann Gautier break; 14157839a050SYann Gautier } 14167839a050SYann Gautier 14177839a050SYann Gautier hsidivfreq /= 2U; 14187839a050SYann Gautier } 14197839a050SYann Gautier 14207839a050SYann Gautier if (hsidiv == 4U) { 14217839a050SYann Gautier ERROR("Invalid clk-hsi frequency\n"); 14227839a050SYann Gautier return -1; 14237839a050SYann Gautier } 14247839a050SYann Gautier 14257839a050SYann Gautier if (hsidiv != 0U) { 14260d21680cSYann Gautier return stm32mp1_set_hsidiv(hsidiv); 14277839a050SYann Gautier } 14287839a050SYann Gautier 14297839a050SYann Gautier return 0; 14307839a050SYann Gautier } 14317839a050SYann Gautier 14320d21680cSYann Gautier static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, 14330d21680cSYann Gautier unsigned int clksrc, 14340d21680cSYann Gautier uint32_t *pllcfg, int plloff) 14357839a050SYann Gautier { 14360d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 14370d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 14380d21680cSYann Gautier uintptr_t pllxcr = rcc_base + pll->pllxcr; 14390d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 14400d21680cSYann Gautier uintptr_t clksrc_address = rcc_base + (clksrc >> 4); 14410d21680cSYann Gautier unsigned long refclk; 14420d21680cSYann Gautier uint32_t ifrge = 0U; 1443be858cffSAndre Przywara uint32_t src, value, fracv = 0; 1444be858cffSAndre Przywara void *fdt; 14457839a050SYann Gautier 14460d21680cSYann Gautier /* Check PLL output */ 14470d21680cSYann Gautier if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { 14480d21680cSYann Gautier return false; 14497839a050SYann Gautier } 14507839a050SYann Gautier 14510d21680cSYann Gautier /* Check current clksrc */ 14520d21680cSYann Gautier src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; 14530d21680cSYann Gautier if (src != (clksrc & RCC_SELR_SRC_MASK)) { 14540d21680cSYann Gautier return false; 14550d21680cSYann Gautier } 14560d21680cSYann Gautier 14570d21680cSYann Gautier /* Check Div */ 14580d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; 14590d21680cSYann Gautier 14600d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 14610d21680cSYann Gautier (pllcfg[PLLCFG_M] + 1U); 14620d21680cSYann Gautier 14630d21680cSYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 14640d21680cSYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 14650d21680cSYann Gautier return false; 14660d21680cSYann Gautier } 14670d21680cSYann Gautier 14680d21680cSYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 14690d21680cSYann Gautier ifrge = 1U; 14700d21680cSYann Gautier } 14710d21680cSYann Gautier 14720d21680cSYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 14730d21680cSYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 14740d21680cSYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 14750d21680cSYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 14760d21680cSYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 14770d21680cSYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 14780d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { 14790d21680cSYann Gautier return false; 14800d21680cSYann Gautier } 14810d21680cSYann Gautier 14820d21680cSYann Gautier /* Fractional configuration */ 1483be858cffSAndre Przywara if (fdt_get_address(&fdt) == 1) { 1484be858cffSAndre Przywara fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1485be858cffSAndre Przywara } 14860d21680cSYann Gautier 14870d21680cSYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 14880d21680cSYann Gautier value |= RCC_PLLNFRACR_FRACLE; 14890d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { 14900d21680cSYann Gautier return false; 14910d21680cSYann Gautier } 14920d21680cSYann Gautier 14930d21680cSYann Gautier /* Output config */ 14940d21680cSYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 14950d21680cSYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 14960d21680cSYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 14970d21680cSYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 14980d21680cSYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 14990d21680cSYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15000d21680cSYann Gautier if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { 15010d21680cSYann Gautier return false; 15020d21680cSYann Gautier } 15030d21680cSYann Gautier 15040d21680cSYann Gautier return true; 15050d21680cSYann Gautier } 15060d21680cSYann Gautier 15070d21680cSYann Gautier static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) 15087839a050SYann Gautier { 15090d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15100d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 15110d21680cSYann Gautier 1512dd98aec8SYann Gautier /* Preserve RCC_PLLNCR_SSCG_CTRL value */ 1513dd98aec8SYann Gautier mmio_clrsetbits_32(pllxcr, 1514dd98aec8SYann Gautier RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 1515dd98aec8SYann Gautier RCC_PLLNCR_DIVREN, 1516dd98aec8SYann Gautier RCC_PLLNCR_PLLON); 15170d21680cSYann Gautier } 15180d21680cSYann Gautier 15190d21680cSYann Gautier static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) 15200d21680cSYann Gautier { 15210d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15220d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1523dfdb057aSYann Gautier uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); 15247839a050SYann Gautier 15257839a050SYann Gautier /* Wait PLL lock */ 15267839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { 1527dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15280d21680cSYann Gautier ERROR("PLL%d start failed @ 0x%lx: 0x%x\n", 15297839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15307839a050SYann Gautier return -ETIMEDOUT; 15317839a050SYann Gautier } 15327839a050SYann Gautier } 15337839a050SYann Gautier 15347839a050SYann Gautier /* Start the requested output */ 15357839a050SYann Gautier mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); 15367839a050SYann Gautier 15377839a050SYann Gautier return 0; 15387839a050SYann Gautier } 15397839a050SYann Gautier 15400d21680cSYann Gautier static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) 15417839a050SYann Gautier { 15420d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15430d21680cSYann Gautier uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; 1544dfdb057aSYann Gautier uint64_t timeout; 15457839a050SYann Gautier 15467839a050SYann Gautier /* Stop all output */ 15477839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | 15487839a050SYann Gautier RCC_PLLNCR_DIVREN); 15497839a050SYann Gautier 15507839a050SYann Gautier /* Stop PLL */ 15517839a050SYann Gautier mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); 15527839a050SYann Gautier 1553dfdb057aSYann Gautier timeout = timeout_init_us(PLLRDY_TIMEOUT); 15547839a050SYann Gautier /* Wait PLL stopped */ 15557839a050SYann Gautier while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { 1556dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 15570d21680cSYann Gautier ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n", 15587839a050SYann Gautier pll_id, pllxcr, mmio_read_32(pllxcr)); 15597839a050SYann Gautier return -ETIMEDOUT; 15607839a050SYann Gautier } 15617839a050SYann Gautier } 15627839a050SYann Gautier 15637839a050SYann Gautier return 0; 15647839a050SYann Gautier } 15657839a050SYann Gautier 15660d21680cSYann Gautier static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, 15677839a050SYann Gautier uint32_t *pllcfg) 15687839a050SYann Gautier { 15690d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15700d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 15717839a050SYann Gautier uint32_t value; 15727839a050SYann Gautier 15737839a050SYann Gautier value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & 15747839a050SYann Gautier RCC_PLLNCFGR2_DIVP_MASK; 15757839a050SYann Gautier value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & 15767839a050SYann Gautier RCC_PLLNCFGR2_DIVQ_MASK; 15777839a050SYann Gautier value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & 15787839a050SYann Gautier RCC_PLLNCFGR2_DIVR_MASK; 15790d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr2, value); 15807839a050SYann Gautier } 15817839a050SYann Gautier 15820d21680cSYann Gautier static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, 15837839a050SYann Gautier uint32_t *pllcfg, uint32_t fracv) 15847839a050SYann Gautier { 15850d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 15860d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 15870d21680cSYann Gautier enum stm32mp1_plltype type = pll->plltype; 15887839a050SYann Gautier unsigned long refclk; 15897839a050SYann Gautier uint32_t ifrge = 0; 15907839a050SYann Gautier uint32_t src, value; 15917839a050SYann Gautier 15920d21680cSYann Gautier src = mmio_read_32(rcc_base + pll->rckxselr) & 15937839a050SYann Gautier RCC_SELR_REFCLK_SRC_MASK; 15947839a050SYann Gautier 15950d21680cSYann Gautier refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / 15967839a050SYann Gautier (pllcfg[PLLCFG_M] + 1U); 15977839a050SYann Gautier 15987839a050SYann Gautier if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || 15997839a050SYann Gautier (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { 16007839a050SYann Gautier return -EINVAL; 16017839a050SYann Gautier } 16027839a050SYann Gautier 16037839a050SYann Gautier if ((type == PLL_800) && (refclk >= 8000000U)) { 16047839a050SYann Gautier ifrge = 1U; 16057839a050SYann Gautier } 16067839a050SYann Gautier 16077839a050SYann Gautier value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & 16087839a050SYann Gautier RCC_PLLNCFGR1_DIVN_MASK; 16097839a050SYann Gautier value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & 16107839a050SYann Gautier RCC_PLLNCFGR1_DIVM_MASK; 16117839a050SYann Gautier value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & 16127839a050SYann Gautier RCC_PLLNCFGR1_IFRGE_MASK; 16130d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxcfgr1, value); 16147839a050SYann Gautier 16157839a050SYann Gautier /* Fractional configuration */ 16167839a050SYann Gautier value = 0; 16170d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16187839a050SYann Gautier 16197839a050SYann Gautier value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; 16200d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16217839a050SYann Gautier 16227839a050SYann Gautier value |= RCC_PLLNFRACR_FRACLE; 16230d21680cSYann Gautier mmio_write_32(rcc_base + pll->pllxfracr, value); 16247839a050SYann Gautier 16250d21680cSYann Gautier stm32mp1_pll_config_output(pll_id, pllcfg); 16267839a050SYann Gautier 16277839a050SYann Gautier return 0; 16287839a050SYann Gautier } 16297839a050SYann Gautier 16300d21680cSYann Gautier static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) 16317839a050SYann Gautier { 16320d21680cSYann Gautier const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 16337839a050SYann Gautier uint32_t pllxcsg = 0; 16347839a050SYann Gautier 16357839a050SYann Gautier pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & 16367839a050SYann Gautier RCC_PLLNCSGR_MOD_PER_MASK; 16377839a050SYann Gautier 16387839a050SYann Gautier pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & 16397839a050SYann Gautier RCC_PLLNCSGR_INC_STEP_MASK; 16407839a050SYann Gautier 16417839a050SYann Gautier pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & 16427839a050SYann Gautier RCC_PLLNCSGR_SSCG_MODE_MASK; 16437839a050SYann Gautier 16440d21680cSYann Gautier mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); 1645dd98aec8SYann Gautier 1646dd98aec8SYann Gautier mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, 1647dd98aec8SYann Gautier RCC_PLLNCR_SSCG_CTRL); 16487839a050SYann Gautier } 16497839a050SYann Gautier 16500d21680cSYann Gautier static int stm32mp1_set_clksrc(unsigned int clksrc) 16517839a050SYann Gautier { 16520d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 1653dfdb057aSYann Gautier uint64_t timeout; 16547839a050SYann Gautier 16550d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, 16567839a050SYann Gautier clksrc & RCC_SELR_SRC_MASK); 16577839a050SYann Gautier 1658dfdb057aSYann Gautier timeout = timeout_init_us(CLKSRC_TIMEOUT); 16590d21680cSYann Gautier while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { 1660dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 16610d21680cSYann Gautier ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, 16620d21680cSYann Gautier clksrc_address, mmio_read_32(clksrc_address)); 16637839a050SYann Gautier return -ETIMEDOUT; 16647839a050SYann Gautier } 16657839a050SYann Gautier } 16667839a050SYann Gautier 16677839a050SYann Gautier return 0; 16687839a050SYann Gautier } 16697839a050SYann Gautier 16700d21680cSYann Gautier static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) 16717839a050SYann Gautier { 1672dfdb057aSYann Gautier uint64_t timeout; 16737839a050SYann Gautier 16747839a050SYann Gautier mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, 16757839a050SYann Gautier clkdiv & RCC_DIVR_DIV_MASK); 16767839a050SYann Gautier 1677dfdb057aSYann Gautier timeout = timeout_init_us(CLKDIV_TIMEOUT); 16787839a050SYann Gautier while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { 1679dfdb057aSYann Gautier if (timeout_elapsed(timeout)) { 16800d21680cSYann Gautier ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", 16817839a050SYann Gautier clkdiv, address, mmio_read_32(address)); 16827839a050SYann Gautier return -ETIMEDOUT; 16837839a050SYann Gautier } 16847839a050SYann Gautier } 16857839a050SYann Gautier 16867839a050SYann Gautier return 0; 16877839a050SYann Gautier } 16887839a050SYann Gautier 16890d21680cSYann Gautier static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) 16907839a050SYann Gautier { 16910d21680cSYann Gautier uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); 16927839a050SYann Gautier 16937839a050SYann Gautier /* 16947839a050SYann Gautier * Binding clksrc : 16957839a050SYann Gautier * bit15-4 offset 16967839a050SYann Gautier * bit3: disable 16977839a050SYann Gautier * bit2-0: MCOSEL[2:0] 16987839a050SYann Gautier */ 16997839a050SYann Gautier if ((clksrc & 0x8U) != 0U) { 17000d21680cSYann Gautier mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17017839a050SYann Gautier } else { 17020d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17037839a050SYann Gautier RCC_MCOCFG_MCOSRC_MASK, 17047839a050SYann Gautier clksrc & RCC_MCOCFG_MCOSRC_MASK); 17050d21680cSYann Gautier mmio_clrsetbits_32(clksrc_address, 17067839a050SYann Gautier RCC_MCOCFG_MCODIV_MASK, 17077839a050SYann Gautier clkdiv << RCC_MCOCFG_MCODIV_SHIFT); 17080d21680cSYann Gautier mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); 17097839a050SYann Gautier } 17107839a050SYann Gautier } 17117839a050SYann Gautier 17120d21680cSYann Gautier static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) 17137839a050SYann Gautier { 17140d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; 17157839a050SYann Gautier 17167839a050SYann Gautier if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || 17177839a050SYann Gautier (clksrc != (uint32_t)CLK_RTC_DISABLED)) { 17187839a050SYann Gautier mmio_clrsetbits_32(address, 17197839a050SYann Gautier RCC_BDCR_RTCSRC_MASK, 172015509093SYann Gautier (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT); 17217839a050SYann Gautier 17227839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_RTCCKEN); 17237839a050SYann Gautier } 17247839a050SYann Gautier 17257839a050SYann Gautier if (lse_css) { 17267839a050SYann Gautier mmio_setbits_32(address, RCC_BDCR_LSECSSON); 17277839a050SYann Gautier } 17287839a050SYann Gautier } 17297839a050SYann Gautier 17300d21680cSYann Gautier static void stm32mp1_stgen_config(void) 17317839a050SYann Gautier { 17327839a050SYann Gautier uint32_t cntfid0; 17337839a050SYann Gautier unsigned long rate; 17347839a050SYann Gautier unsigned long long counter; 17357839a050SYann Gautier 1736ade9ce03SYann Gautier cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF); 17370d21680cSYann Gautier rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); 17380d21680cSYann Gautier 17390d21680cSYann Gautier if (cntfid0 == rate) { 17400d21680cSYann Gautier return; 17410d21680cSYann Gautier } 17420d21680cSYann Gautier 1743ade9ce03SYann Gautier mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 1744ade9ce03SYann Gautier counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF); 1745ade9ce03SYann Gautier counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF)) << 32; 17467839a050SYann Gautier counter = (counter * rate / cntfid0); 17470d21680cSYann Gautier 1748ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter); 1749ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32)); 1750ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTFID_OFF, rate); 1751ade9ce03SYann Gautier mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 17527839a050SYann Gautier 17537839a050SYann Gautier write_cntfrq((u_register_t)rate); 17547839a050SYann Gautier 17557839a050SYann Gautier /* Need to update timer with new frequency */ 17567839a050SYann Gautier generic_delay_timer_init(); 17577839a050SYann Gautier } 17587839a050SYann Gautier 17597839a050SYann Gautier void stm32mp1_stgen_increment(unsigned long long offset_in_ms) 17607839a050SYann Gautier { 17617839a050SYann Gautier unsigned long long cnt; 17627839a050SYann Gautier 1763ade9ce03SYann Gautier cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) | 1764ade9ce03SYann Gautier mmio_read_32(STGEN_BASE + CNTCVL_OFF); 17657839a050SYann Gautier 1766ade9ce03SYann Gautier cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U; 17677839a050SYann Gautier 1768ade9ce03SYann Gautier mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 1769ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt); 1770ade9ce03SYann Gautier mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32)); 1771ade9ce03SYann Gautier mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); 17727839a050SYann Gautier } 17737839a050SYann Gautier 17740d21680cSYann Gautier static void stm32mp1_pkcs_config(uint32_t pkcs) 17757839a050SYann Gautier { 17760d21680cSYann Gautier uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); 17777839a050SYann Gautier uint32_t value = pkcs & 0xFU; 17787839a050SYann Gautier uint32_t mask = 0xFU; 17797839a050SYann Gautier 17807839a050SYann Gautier if ((pkcs & BIT(31)) != 0U) { 17817839a050SYann Gautier mask <<= 4; 17827839a050SYann Gautier value <<= 4; 17837839a050SYann Gautier } 17847839a050SYann Gautier 17857839a050SYann Gautier mmio_clrsetbits_32(address, mask, value); 17867839a050SYann Gautier } 17877839a050SYann Gautier 1788964e5ff1SNicolas Le Bayon static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, 1789964e5ff1SNicolas Le Bayon uint32_t *fracv, uint32_t *csg, 1790964e5ff1SNicolas Le Bayon bool *csg_set) 1791964e5ff1SNicolas Le Bayon { 1792964e5ff1SNicolas Le Bayon void *fdt; 1793964e5ff1SNicolas Le Bayon int ret; 1794964e5ff1SNicolas Le Bayon 1795964e5ff1SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 1796964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1797964e5ff1SNicolas Le Bayon } 1798964e5ff1SNicolas Le Bayon 1799964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB, 1800964e5ff1SNicolas Le Bayon pllcfg); 1801964e5ff1SNicolas Le Bayon if (ret < 0) { 1802964e5ff1SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 1803964e5ff1SNicolas Le Bayon } 1804964e5ff1SNicolas Le Bayon 1805964e5ff1SNicolas Le Bayon *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); 1806964e5ff1SNicolas Le Bayon 1807964e5ff1SNicolas Le Bayon ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB, 1808964e5ff1SNicolas Le Bayon csg); 1809964e5ff1SNicolas Le Bayon 1810964e5ff1SNicolas Le Bayon *csg_set = (ret == 0); 1811964e5ff1SNicolas Le Bayon 1812964e5ff1SNicolas Le Bayon if (ret == -FDT_ERR_NOTFOUND) { 1813964e5ff1SNicolas Le Bayon ret = 0; 1814964e5ff1SNicolas Le Bayon } 1815964e5ff1SNicolas Le Bayon 1816964e5ff1SNicolas Le Bayon return ret; 1817964e5ff1SNicolas Le Bayon } 1818964e5ff1SNicolas Le Bayon 18197839a050SYann Gautier int stm32mp1_clk_init(void) 18207839a050SYann Gautier { 18210d21680cSYann Gautier uintptr_t rcc_base = stm32mp_rcc_base(); 1822964e5ff1SNicolas Le Bayon uint32_t pllfracv[_PLL_NB]; 1823964e5ff1SNicolas Le Bayon uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; 18247839a050SYann Gautier unsigned int clksrc[CLKSRC_NB]; 18257839a050SYann Gautier unsigned int clkdiv[CLKDIV_NB]; 18267839a050SYann Gautier unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; 18277839a050SYann Gautier int plloff[_PLL_NB]; 18287839a050SYann Gautier int ret, len; 18297839a050SYann Gautier enum stm32mp1_pll_id i; 1830964e5ff1SNicolas Le Bayon bool pllcsg_set[_PLL_NB]; 1831964e5ff1SNicolas Le Bayon bool pllcfg_valid[_PLL_NB]; 18327839a050SYann Gautier bool lse_css = false; 18330d21680cSYann Gautier bool pll3_preserve = false; 18340d21680cSYann Gautier bool pll4_preserve = false; 18350d21680cSYann Gautier bool pll4_bootrom = false; 18363e6fab43SYann Gautier const fdt32_t *pkcs_cell; 183752a616b4SAndre Przywara void *fdt; 1838bf1af154SPatrick Delaunay int stgen_p = stm32mp1_clk_get_parent(STGEN_K); 1839bf1af154SPatrick Delaunay int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K); 184052a616b4SAndre Przywara 184152a616b4SAndre Przywara if (fdt_get_address(&fdt) == 0) { 18428f97c4faSYann Gautier return -FDT_ERR_NOTFOUND; 184352a616b4SAndre Przywara } 18447839a050SYann Gautier 18457839a050SYann Gautier /* Check status field to disable security */ 18467839a050SYann Gautier if (!fdt_get_rcc_secure_status()) { 18470d21680cSYann Gautier mmio_write_32(rcc_base + RCC_TZCR, 0); 18487839a050SYann Gautier } 18497839a050SYann Gautier 185052a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, 185152a616b4SAndre Przywara clksrc); 18527839a050SYann Gautier if (ret < 0) { 18537839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18547839a050SYann Gautier } 18557839a050SYann Gautier 185652a616b4SAndre Przywara ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, 185752a616b4SAndre Przywara clkdiv); 18587839a050SYann Gautier if (ret < 0) { 18597839a050SYann Gautier return -FDT_ERR_NOTFOUND; 18607839a050SYann Gautier } 18617839a050SYann Gautier 18627839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 18637839a050SYann Gautier char name[12]; 18647839a050SYann Gautier 186539b6cc66SAntonio Nino Diaz snprintf(name, sizeof(name), "st,pll@%d", i); 18667839a050SYann Gautier plloff[i] = fdt_rcc_subnode_offset(name); 18677839a050SYann Gautier 1868964e5ff1SNicolas Le Bayon pllcfg_valid[i] = fdt_check_node(plloff[i]); 1869964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 18707839a050SYann Gautier continue; 18717839a050SYann Gautier } 18727839a050SYann Gautier 1873964e5ff1SNicolas Le Bayon ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], 1874964e5ff1SNicolas Le Bayon &pllfracv[i], pllcsg[i], 1875964e5ff1SNicolas Le Bayon &pllcsg_set[i]); 1876964e5ff1SNicolas Le Bayon if (ret != 0) { 1877964e5ff1SNicolas Le Bayon return ret; 18787839a050SYann Gautier } 18797839a050SYann Gautier } 18807839a050SYann Gautier 18810d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); 18820d21680cSYann Gautier stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); 18837839a050SYann Gautier 18847839a050SYann Gautier /* 18857839a050SYann Gautier * Switch ON oscillator found in device-tree. 18867839a050SYann Gautier * Note: HSI already ON after BootROM stage. 18877839a050SYann Gautier */ 18880d21680cSYann Gautier if (stm32mp1_osc[_LSI] != 0U) { 18890d21680cSYann Gautier stm32mp1_lsi_set(true); 18907839a050SYann Gautier } 18910d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 1892b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_LSE]; 18930d21680cSYann Gautier bool bypass, digbyp; 18947839a050SYann Gautier uint32_t lsedrv; 18957839a050SYann Gautier 1896b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1897b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1898b208e3daSGabriel Fernandez lse_css = fdt_clk_read_bool(name, "st,css"); 1899b208e3daSGabriel Fernandez lsedrv = fdt_clk_read_uint32_default(name, "st,drive", 19007839a050SYann Gautier LSEDRV_MEDIUM_HIGH); 19010d21680cSYann Gautier stm32mp1_lse_enable(bypass, digbyp, lsedrv); 19027839a050SYann Gautier } 19030d21680cSYann Gautier if (stm32mp1_osc[_HSE] != 0U) { 1904b208e3daSGabriel Fernandez const char *name = stm32mp_osc_node_label[_HSE]; 19050d21680cSYann Gautier bool bypass, digbyp, css; 19067839a050SYann Gautier 1907b208e3daSGabriel Fernandez bypass = fdt_clk_read_bool(name, "st,bypass"); 1908b208e3daSGabriel Fernandez digbyp = fdt_clk_read_bool(name, "st,digbypass"); 1909b208e3daSGabriel Fernandez css = fdt_clk_read_bool(name, "st,css"); 19100d21680cSYann Gautier stm32mp1_hse_enable(bypass, digbyp, css); 19117839a050SYann Gautier } 19127839a050SYann Gautier /* 19137839a050SYann Gautier * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) 19147839a050SYann Gautier * => switch on CSI even if node is not present in device tree 19157839a050SYann Gautier */ 19160d21680cSYann Gautier stm32mp1_csi_set(true); 19177839a050SYann Gautier 19187839a050SYann Gautier /* Come back to HSI */ 19190d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_MPU_HSI); 19207839a050SYann Gautier if (ret != 0) { 19217839a050SYann Gautier return ret; 19227839a050SYann Gautier } 19230d21680cSYann Gautier ret = stm32mp1_set_clksrc(CLK_AXI_HSI); 19247839a050SYann Gautier if (ret != 0) { 19257839a050SYann Gautier return ret; 19267839a050SYann Gautier } 1927b053a22eSYann Gautier ret = stm32mp1_set_clksrc(CLK_MCU_HSI); 1928b053a22eSYann Gautier if (ret != 0) { 1929b053a22eSYann Gautier return ret; 1930b053a22eSYann Gautier } 19317839a050SYann Gautier 19320d21680cSYann Gautier if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & 19330d21680cSYann Gautier RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { 19340d21680cSYann Gautier pll3_preserve = stm32mp1_check_pll_conf(_PLL3, 19350d21680cSYann Gautier clksrc[CLKSRC_PLL3], 19360d21680cSYann Gautier pllcfg[_PLL3], 19370d21680cSYann Gautier plloff[_PLL3]); 19380d21680cSYann Gautier pll4_preserve = stm32mp1_check_pll_conf(_PLL4, 19390d21680cSYann Gautier clksrc[CLKSRC_PLL4], 19400d21680cSYann Gautier pllcfg[_PLL4], 19410d21680cSYann Gautier plloff[_PLL4]); 19420d21680cSYann Gautier } 1943bf1af154SPatrick Delaunay /* Don't initialize PLL4, when used by BOOTROM */ 1944bf1af154SPatrick Delaunay if ((stm32mp_get_boot_itf_selected() == 1945bf1af154SPatrick Delaunay BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) && 1946bf1af154SPatrick Delaunay ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { 1947bf1af154SPatrick Delaunay pll4_bootrom = true; 1948bf1af154SPatrick Delaunay pll4_preserve = true; 1949bf1af154SPatrick Delaunay } 19500d21680cSYann Gautier 19517839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 19520d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 19530d21680cSYann Gautier ((i == _PLL4) && pll4_preserve)) { 19547839a050SYann Gautier continue; 19550d21680cSYann Gautier } 19560d21680cSYann Gautier 19570d21680cSYann Gautier ret = stm32mp1_pll_stop(i); 19587839a050SYann Gautier if (ret != 0) { 19597839a050SYann Gautier return ret; 19607839a050SYann Gautier } 19617839a050SYann Gautier } 19627839a050SYann Gautier 19637839a050SYann Gautier /* Configure HSIDIV */ 19640d21680cSYann Gautier if (stm32mp1_osc[_HSI] != 0U) { 19650d21680cSYann Gautier ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); 19667839a050SYann Gautier if (ret != 0) { 19677839a050SYann Gautier return ret; 19687839a050SYann Gautier } 19690d21680cSYann Gautier stm32mp1_stgen_config(); 19707839a050SYann Gautier } 19717839a050SYann Gautier 19727839a050SYann Gautier /* Select DIV */ 19737839a050SYann Gautier /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ 19740d21680cSYann Gautier mmio_write_32(rcc_base + RCC_MPCKDIVR, 19757839a050SYann Gautier clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 19760d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); 19777839a050SYann Gautier if (ret != 0) { 19787839a050SYann Gautier return ret; 19797839a050SYann Gautier } 19800d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); 19817839a050SYann Gautier if (ret != 0) { 19827839a050SYann Gautier return ret; 19837839a050SYann Gautier } 19840d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); 19857839a050SYann Gautier if (ret != 0) { 19867839a050SYann Gautier return ret; 19877839a050SYann Gautier } 1988b053a22eSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); 1989b053a22eSYann Gautier if (ret != 0) { 1990b053a22eSYann Gautier return ret; 1991b053a22eSYann Gautier } 19920d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); 19937839a050SYann Gautier if (ret != 0) { 19947839a050SYann Gautier return ret; 19957839a050SYann Gautier } 19960d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); 19977839a050SYann Gautier if (ret != 0) { 19987839a050SYann Gautier return ret; 19997839a050SYann Gautier } 20000d21680cSYann Gautier ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); 20017839a050SYann Gautier if (ret != 0) { 20027839a050SYann Gautier return ret; 20037839a050SYann Gautier } 20047839a050SYann Gautier 20057839a050SYann Gautier /* No ready bit for RTC */ 20060d21680cSYann Gautier mmio_write_32(rcc_base + RCC_RTCDIVR, 20077839a050SYann Gautier clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); 20087839a050SYann Gautier 20097839a050SYann Gautier /* Configure PLLs source */ 20100d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); 20117839a050SYann Gautier if (ret != 0) { 20127839a050SYann Gautier return ret; 20137839a050SYann Gautier } 20147839a050SYann Gautier 20150d21680cSYann Gautier if (!pll3_preserve) { 20160d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); 20177839a050SYann Gautier if (ret != 0) { 20187839a050SYann Gautier return ret; 20197839a050SYann Gautier } 20200d21680cSYann Gautier } 20210d21680cSYann Gautier 20220d21680cSYann Gautier if (!pll4_preserve) { 20230d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); 20240d21680cSYann Gautier if (ret != 0) { 20250d21680cSYann Gautier return ret; 20260d21680cSYann Gautier } 20270d21680cSYann Gautier } 20287839a050SYann Gautier 20297839a050SYann Gautier /* Configure and start PLLs */ 20307839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 20310d21680cSYann Gautier if (((i == _PLL3) && pll3_preserve) || 20320d21680cSYann Gautier ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { 20330d21680cSYann Gautier continue; 20340d21680cSYann Gautier } 20350d21680cSYann Gautier 2036964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20377839a050SYann Gautier continue; 20387839a050SYann Gautier } 20397839a050SYann Gautier 20400d21680cSYann Gautier if ((i == _PLL4) && pll4_bootrom) { 20410d21680cSYann Gautier /* Set output divider if not done by the Bootrom */ 20420d21680cSYann Gautier stm32mp1_pll_config_output(i, pllcfg[i]); 20430d21680cSYann Gautier continue; 20440d21680cSYann Gautier } 20450d21680cSYann Gautier 2046964e5ff1SNicolas Le Bayon ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); 20477839a050SYann Gautier if (ret != 0) { 20487839a050SYann Gautier return ret; 20497839a050SYann Gautier } 2050964e5ff1SNicolas Le Bayon 2051964e5ff1SNicolas Le Bayon if (pllcsg_set[i]) { 2052964e5ff1SNicolas Le Bayon stm32mp1_pll_csg(i, pllcsg[i]); 20537839a050SYann Gautier } 20547839a050SYann Gautier 20550d21680cSYann Gautier stm32mp1_pll_start(i); 20567839a050SYann Gautier } 20577839a050SYann Gautier /* Wait and start PLLs ouptut when ready */ 20587839a050SYann Gautier for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 2059964e5ff1SNicolas Le Bayon if (!pllcfg_valid[i]) { 20607839a050SYann Gautier continue; 20617839a050SYann Gautier } 20627839a050SYann Gautier 20630d21680cSYann Gautier ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); 20647839a050SYann Gautier if (ret != 0) { 20657839a050SYann Gautier return ret; 20667839a050SYann Gautier } 20677839a050SYann Gautier } 20687839a050SYann Gautier /* Wait LSE ready before to use it */ 20690d21680cSYann Gautier if (stm32mp1_osc[_LSE] != 0U) { 20700d21680cSYann Gautier stm32mp1_lse_wait(); 20717839a050SYann Gautier } 20727839a050SYann Gautier 20737839a050SYann Gautier /* Configure with expected clock source */ 20740d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); 20757839a050SYann Gautier if (ret != 0) { 20767839a050SYann Gautier return ret; 20777839a050SYann Gautier } 20780d21680cSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); 20797839a050SYann Gautier if (ret != 0) { 20807839a050SYann Gautier return ret; 20817839a050SYann Gautier } 2082b053a22eSYann Gautier ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); 2083b053a22eSYann Gautier if (ret != 0) { 2084b053a22eSYann Gautier return ret; 2085b053a22eSYann Gautier } 20860d21680cSYann Gautier stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); 20877839a050SYann Gautier 20887839a050SYann Gautier /* Configure PKCK */ 20897839a050SYann Gautier pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); 20907839a050SYann Gautier if (pkcs_cell != NULL) { 20917839a050SYann Gautier bool ckper_disabled = false; 20927839a050SYann Gautier uint32_t j; 2093bf1af154SPatrick Delaunay uint32_t usbreg_bootrom = 0U; 2094bf1af154SPatrick Delaunay 2095bf1af154SPatrick Delaunay if (pll4_bootrom) { 2096bf1af154SPatrick Delaunay usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); 2097bf1af154SPatrick Delaunay } 20987839a050SYann Gautier 20997839a050SYann Gautier for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { 21003e6fab43SYann Gautier uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); 21017839a050SYann Gautier 21027839a050SYann Gautier if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { 21037839a050SYann Gautier ckper_disabled = true; 21047839a050SYann Gautier continue; 21057839a050SYann Gautier } 21060d21680cSYann Gautier stm32mp1_pkcs_config(pkcs); 21077839a050SYann Gautier } 21087839a050SYann Gautier 21097839a050SYann Gautier /* 21107839a050SYann Gautier * CKPER is source for some peripheral clocks 21117839a050SYann Gautier * (FMC-NAND / QPSI-NOR) and switching source is allowed 21127839a050SYann Gautier * only if previous clock is still ON 21137839a050SYann Gautier * => deactivated CKPER only after switching clock 21147839a050SYann Gautier */ 21157839a050SYann Gautier if (ckper_disabled) { 21160d21680cSYann Gautier stm32mp1_pkcs_config(CLK_CKPER_DISABLED); 21177839a050SYann Gautier } 2118bf1af154SPatrick Delaunay 2119bf1af154SPatrick Delaunay if (pll4_bootrom) { 2120bf1af154SPatrick Delaunay uint32_t usbreg_value, usbreg_mask; 2121bf1af154SPatrick Delaunay const struct stm32mp1_clk_sel *sel; 2122bf1af154SPatrick Delaunay 2123bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBPHY_SEL); 2124bf1af154SPatrick Delaunay usbreg_mask = (uint32_t)sel->msk << sel->src; 2125bf1af154SPatrick Delaunay sel = clk_sel_ref(_USBO_SEL); 2126bf1af154SPatrick Delaunay usbreg_mask |= (uint32_t)sel->msk << sel->src; 2127bf1af154SPatrick Delaunay 2128bf1af154SPatrick Delaunay usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & 2129bf1af154SPatrick Delaunay usbreg_mask; 2130bf1af154SPatrick Delaunay usbreg_bootrom &= usbreg_mask; 2131bf1af154SPatrick Delaunay if (usbreg_bootrom != usbreg_value) { 2132bf1af154SPatrick Delaunay VERBOSE("forbidden new USB clk path\n"); 2133bf1af154SPatrick Delaunay VERBOSE("vs bootrom on USB boot\n"); 2134bf1af154SPatrick Delaunay return -FDT_ERR_BADVALUE; 2135bf1af154SPatrick Delaunay } 2136bf1af154SPatrick Delaunay } 21377839a050SYann Gautier } 21387839a050SYann Gautier 21397839a050SYann Gautier /* Switch OFF HSI if not found in device-tree */ 21400d21680cSYann Gautier if (stm32mp1_osc[_HSI] == 0U) { 21410d21680cSYann Gautier stm32mp1_hsi_set(false); 21427839a050SYann Gautier } 21430d21680cSYann Gautier stm32mp1_stgen_config(); 21447839a050SYann Gautier 21457839a050SYann Gautier /* Software Self-Refresh mode (SSR) during DDR initilialization */ 21460d21680cSYann Gautier mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, 21477839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_MASK, 21487839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SSR << 21497839a050SYann Gautier RCC_DDRITFCR_DDRCKMOD_SHIFT); 21507839a050SYann Gautier 21517839a050SYann Gautier return 0; 21527839a050SYann Gautier } 21537839a050SYann Gautier 21547839a050SYann Gautier static void stm32mp1_osc_clk_init(const char *name, 21557839a050SYann Gautier enum stm32mp_osc_id index) 21567839a050SYann Gautier { 21577839a050SYann Gautier uint32_t frequency; 21587839a050SYann Gautier 21590d21680cSYann Gautier if (fdt_osc_read_freq(name, &frequency) == 0) { 21600d21680cSYann Gautier stm32mp1_osc[index] = frequency; 21617839a050SYann Gautier } 21627839a050SYann Gautier } 21637839a050SYann Gautier 21647839a050SYann Gautier static void stm32mp1_osc_init(void) 21657839a050SYann Gautier { 21667839a050SYann Gautier enum stm32mp_osc_id i; 21677839a050SYann Gautier 21687839a050SYann Gautier for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { 21690d21680cSYann Gautier stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); 21707839a050SYann Gautier } 21717839a050SYann Gautier } 21727839a050SYann Gautier 217337e8295aSEtienne Carriere #ifdef STM32MP_SHARED_RESOURCES 217437e8295aSEtienne Carriere /* 217537e8295aSEtienne Carriere * Get the parent ID of the target parent clock, for tagging as secure 217637e8295aSEtienne Carriere * shared clock dependencies. 217737e8295aSEtienne Carriere */ 217837e8295aSEtienne Carriere static int get_parent_id_parent(unsigned int parent_id) 217937e8295aSEtienne Carriere { 218037e8295aSEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 218137e8295aSEtienne Carriere enum stm32mp1_pll_id pll_id; 218237e8295aSEtienne Carriere uint32_t p_sel; 218337e8295aSEtienne Carriere uintptr_t rcc_base = stm32mp_rcc_base(); 218437e8295aSEtienne Carriere 218537e8295aSEtienne Carriere switch (parent_id) { 218637e8295aSEtienne Carriere case _ACLK: 218737e8295aSEtienne Carriere case _PCLK4: 218837e8295aSEtienne Carriere case _PCLK5: 218937e8295aSEtienne Carriere s = _AXIS_SEL; 219037e8295aSEtienne Carriere break; 219137e8295aSEtienne Carriere case _PLL1_P: 219237e8295aSEtienne Carriere case _PLL1_Q: 219337e8295aSEtienne Carriere case _PLL1_R: 219437e8295aSEtienne Carriere pll_id = _PLL1; 219537e8295aSEtienne Carriere break; 219637e8295aSEtienne Carriere case _PLL2_P: 219737e8295aSEtienne Carriere case _PLL2_Q: 219837e8295aSEtienne Carriere case _PLL2_R: 219937e8295aSEtienne Carriere pll_id = _PLL2; 220037e8295aSEtienne Carriere break; 220137e8295aSEtienne Carriere case _PLL3_P: 220237e8295aSEtienne Carriere case _PLL3_Q: 220337e8295aSEtienne Carriere case _PLL3_R: 220437e8295aSEtienne Carriere pll_id = _PLL3; 220537e8295aSEtienne Carriere break; 220637e8295aSEtienne Carriere case _PLL4_P: 220737e8295aSEtienne Carriere case _PLL4_Q: 220837e8295aSEtienne Carriere case _PLL4_R: 220937e8295aSEtienne Carriere pll_id = _PLL4; 221037e8295aSEtienne Carriere break; 221137e8295aSEtienne Carriere case _PCLK1: 221237e8295aSEtienne Carriere case _PCLK2: 221337e8295aSEtienne Carriere case _HCLK2: 221437e8295aSEtienne Carriere case _HCLK6: 221537e8295aSEtienne Carriere case _CK_PER: 221637e8295aSEtienne Carriere case _CK_MPU: 221737e8295aSEtienne Carriere case _CK_MCU: 221837e8295aSEtienne Carriere case _USB_PHY_48: 221937e8295aSEtienne Carriere /* We do not expect to access these */ 222037e8295aSEtienne Carriere panic(); 222137e8295aSEtienne Carriere break; 222237e8295aSEtienne Carriere default: 222337e8295aSEtienne Carriere /* Other parents have no parent */ 222437e8295aSEtienne Carriere return -1; 222537e8295aSEtienne Carriere } 222637e8295aSEtienne Carriere 222737e8295aSEtienne Carriere if (s != _UNKNOWN_SEL) { 222837e8295aSEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 222937e8295aSEtienne Carriere 223037e8295aSEtienne Carriere p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & 223137e8295aSEtienne Carriere sel->msk; 223237e8295aSEtienne Carriere 223337e8295aSEtienne Carriere if (p_sel < sel->nb_parent) { 223437e8295aSEtienne Carriere return (int)sel->parent[p_sel]; 223537e8295aSEtienne Carriere } 223637e8295aSEtienne Carriere } else { 223737e8295aSEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 223837e8295aSEtienne Carriere 223937e8295aSEtienne Carriere p_sel = mmio_read_32(rcc_base + pll->rckxselr) & 224037e8295aSEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 224137e8295aSEtienne Carriere 224237e8295aSEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { 224337e8295aSEtienne Carriere return (int)pll->refclk[p_sel]; 224437e8295aSEtienne Carriere } 224537e8295aSEtienne Carriere } 224637e8295aSEtienne Carriere 224737e8295aSEtienne Carriere VERBOSE("No parent selected for %s\n", 224837e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 224937e8295aSEtienne Carriere 225037e8295aSEtienne Carriere return -1; 225137e8295aSEtienne Carriere } 225237e8295aSEtienne Carriere 225337e8295aSEtienne Carriere static void secure_parent_clocks(unsigned long parent_id) 225437e8295aSEtienne Carriere { 225537e8295aSEtienne Carriere int grandparent_id; 225637e8295aSEtienne Carriere 225737e8295aSEtienne Carriere switch (parent_id) { 225837e8295aSEtienne Carriere case _PLL3_P: 225937e8295aSEtienne Carriere case _PLL3_Q: 226037e8295aSEtienne Carriere case _PLL3_R: 226137e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 226237e8295aSEtienne Carriere break; 226337e8295aSEtienne Carriere 226437e8295aSEtienne Carriere /* These clocks are always secure when RCC is secure */ 226537e8295aSEtienne Carriere case _ACLK: 226637e8295aSEtienne Carriere case _HCLK2: 226737e8295aSEtienne Carriere case _HCLK6: 226837e8295aSEtienne Carriere case _PCLK4: 226937e8295aSEtienne Carriere case _PCLK5: 227037e8295aSEtienne Carriere case _PLL1_P: 227137e8295aSEtienne Carriere case _PLL1_Q: 227237e8295aSEtienne Carriere case _PLL1_R: 227337e8295aSEtienne Carriere case _PLL2_P: 227437e8295aSEtienne Carriere case _PLL2_Q: 227537e8295aSEtienne Carriere case _PLL2_R: 227637e8295aSEtienne Carriere case _HSI: 227737e8295aSEtienne Carriere case _HSI_KER: 227837e8295aSEtienne Carriere case _LSI: 227937e8295aSEtienne Carriere case _CSI: 228037e8295aSEtienne Carriere case _CSI_KER: 228137e8295aSEtienne Carriere case _HSE: 228237e8295aSEtienne Carriere case _HSE_KER: 228337e8295aSEtienne Carriere case _HSE_KER_DIV2: 2284cbd2e8a6SGabriel Fernandez case _HSE_RTC: 228537e8295aSEtienne Carriere case _LSE: 228637e8295aSEtienne Carriere break; 228737e8295aSEtienne Carriere 228837e8295aSEtienne Carriere default: 228937e8295aSEtienne Carriere VERBOSE("Cannot secure parent clock %s\n", 229037e8295aSEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 229137e8295aSEtienne Carriere panic(); 229237e8295aSEtienne Carriere } 229337e8295aSEtienne Carriere 229437e8295aSEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 229537e8295aSEtienne Carriere if (grandparent_id >= 0) { 229637e8295aSEtienne Carriere secure_parent_clocks(grandparent_id); 229737e8295aSEtienne Carriere } 229837e8295aSEtienne Carriere } 229937e8295aSEtienne Carriere 230037e8295aSEtienne Carriere void stm32mp1_register_clock_parents_secure(unsigned long clock_id) 230137e8295aSEtienne Carriere { 230237e8295aSEtienne Carriere int parent_id; 230337e8295aSEtienne Carriere 230437e8295aSEtienne Carriere if (!stm32mp1_rcc_is_secure()) { 230537e8295aSEtienne Carriere return; 230637e8295aSEtienne Carriere } 230737e8295aSEtienne Carriere 230837e8295aSEtienne Carriere switch (clock_id) { 230937e8295aSEtienne Carriere case PLL1: 231037e8295aSEtienne Carriere case PLL2: 231137e8295aSEtienne Carriere /* PLL1/PLL2 are always secure: nothing to do */ 231237e8295aSEtienne Carriere break; 231337e8295aSEtienne Carriere case PLL3: 231437e8295aSEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 231537e8295aSEtienne Carriere break; 231637e8295aSEtienne Carriere case PLL4: 231737e8295aSEtienne Carriere ERROR("PLL4 cannot be secured\n"); 231837e8295aSEtienne Carriere panic(); 231937e8295aSEtienne Carriere break; 232037e8295aSEtienne Carriere default: 232137e8295aSEtienne Carriere /* Others are expected gateable clock */ 232237e8295aSEtienne Carriere parent_id = stm32mp1_clk_get_parent(clock_id); 232337e8295aSEtienne Carriere if (parent_id < 0) { 232437e8295aSEtienne Carriere INFO("No parent found for clock %lu\n", clock_id); 232537e8295aSEtienne Carriere } else { 232637e8295aSEtienne Carriere secure_parent_clocks(parent_id); 232737e8295aSEtienne Carriere } 232837e8295aSEtienne Carriere break; 232937e8295aSEtienne Carriere } 233037e8295aSEtienne Carriere } 233137e8295aSEtienne Carriere #endif /* STM32MP_SHARED_RESOURCES */ 233237e8295aSEtienne Carriere 23336cb45f89SYann Gautier static void sync_earlyboot_clocks_state(void) 23346cb45f89SYann Gautier { 2335033b6c3aSEtienne Carriere unsigned int idx; 2336033b6c3aSEtienne Carriere const unsigned long secure_enable[] = { 2337033b6c3aSEtienne Carriere AXIDCG, 2338033b6c3aSEtienne Carriere BSEC, 2339033b6c3aSEtienne Carriere DDRC1, DDRC1LP, 2340033b6c3aSEtienne Carriere DDRC2, DDRC2LP, 2341033b6c3aSEtienne Carriere DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, 2342033b6c3aSEtienne Carriere DDRPHYC, DDRPHYCLP, 2343373f06beSLionel Debieve RTCAPB, 2344033b6c3aSEtienne Carriere TZC1, TZC2, 2345033b6c3aSEtienne Carriere TZPC, 2346033b6c3aSEtienne Carriere STGEN_K, 2347033b6c3aSEtienne Carriere }; 2348033b6c3aSEtienne Carriere 2349033b6c3aSEtienne Carriere for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { 2350033b6c3aSEtienne Carriere stm32mp_clk_enable(secure_enable[idx]); 2351033b6c3aSEtienne Carriere } 23526cb45f89SYann Gautier } 23536cb45f89SYann Gautier 235433667d29SYann Gautier static const struct clk_ops stm32mp_clk_ops = { 235533667d29SYann Gautier .enable = stm32mp_clk_enable, 235633667d29SYann Gautier .disable = stm32mp_clk_disable, 235733667d29SYann Gautier .is_enabled = stm32mp_clk_is_enabled, 235833667d29SYann Gautier .get_rate = stm32mp_clk_get_rate, 235933667d29SYann Gautier .get_parent = stm32mp1_clk_get_parent, 236033667d29SYann Gautier }; 236133667d29SYann Gautier 23627839a050SYann Gautier int stm32mp1_clk_probe(void) 23637839a050SYann Gautier { 23647839a050SYann Gautier stm32mp1_osc_init(); 23657839a050SYann Gautier 23666cb45f89SYann Gautier sync_earlyboot_clocks_state(); 23676cb45f89SYann Gautier 236833667d29SYann Gautier clk_register(&stm32mp_clk_ops); 236933667d29SYann Gautier 23707839a050SYann Gautier return 0; 23717839a050SYann Gautier } 2372