16b651796SEtienne Carriere // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0+) 26b651796SEtienne Carriere /* 31e1e5a4dSGatien Chevallier * Copyright (C) 2018-2022, STMicroelectronics 46b651796SEtienne Carriere */ 56b651796SEtienne Carriere 66b651796SEtienne Carriere #include <assert.h> 76b651796SEtienne Carriere #include <config.h> 86b651796SEtienne Carriere #include <drivers/stm32mp1_rcc.h> 96b651796SEtienne Carriere #include <drivers/clk.h> 106b651796SEtienne Carriere #include <drivers/clk_dt.h> 111e1e5a4dSGatien Chevallier #include <drivers/stm32_shared_io.h> 1237010ab7SGatien Chevallier #include <drivers/stm32mp_dt_bindings.h> 136b651796SEtienne Carriere #include <initcall.h> 146b651796SEtienne Carriere #include <io.h> 156b651796SEtienne Carriere #include <keep.h> 166b651796SEtienne Carriere #include <kernel/dt.h> 179e3c57c8SEtienne Carriere #include <kernel/dt_driver.h> 186b651796SEtienne Carriere #include <kernel/boot.h> 196b651796SEtienne Carriere #include <kernel/panic.h> 206b651796SEtienne Carriere #include <kernel/spinlock.h> 216b651796SEtienne Carriere #include <libfdt.h> 226b651796SEtienne Carriere #include <platform_config.h> 236b651796SEtienne Carriere #include <stdio.h> 246b651796SEtienne Carriere #include <stm32_util.h> 256b651796SEtienne Carriere #include <trace.h> 266b651796SEtienne Carriere #include <util.h> 276b651796SEtienne Carriere 286b651796SEtienne Carriere /* Identifiers for root oscillators */ 296b651796SEtienne Carriere enum stm32mp_osc_id { 30bb73802dSEtienne Carriere OSC_HSI, 31bb73802dSEtienne Carriere OSC_HSE, 32bb73802dSEtienne Carriere OSC_CSI, 33bb73802dSEtienne Carriere OSC_LSI, 34bb73802dSEtienne Carriere OSC_LSE, 35bb73802dSEtienne Carriere OSC_I2S_CKIN, 36bb73802dSEtienne Carriere OSC_USB_PHY_48, 376b651796SEtienne Carriere NB_OSC, 386b651796SEtienne Carriere _UNKNOWN_OSC_ID = 0xffU 396b651796SEtienne Carriere }; 406b651796SEtienne Carriere 416b651796SEtienne Carriere /* Identifiers for parent clocks */ 426b651796SEtienne Carriere enum stm32mp1_parent_id { 43bb73802dSEtienne Carriere _HSI, 44bb73802dSEtienne Carriere _HSE, 45bb73802dSEtienne Carriere _CSI, 46bb73802dSEtienne Carriere _LSI, 47bb73802dSEtienne Carriere _LSE, 48bb73802dSEtienne Carriere _I2S_CKIN, 49bb73802dSEtienne Carriere _USB_PHY_48, 50bb73802dSEtienne Carriere _HSI_KER, 516b651796SEtienne Carriere _HSE_KER, 526b651796SEtienne Carriere _HSE_KER_DIV2, 5362bb2715SEtienne Carriere _HSE_RTC, 546b651796SEtienne Carriere _CSI_KER, 556b651796SEtienne Carriere _PLL1_P, 566b651796SEtienne Carriere _PLL1_Q, 576b651796SEtienne Carriere _PLL1_R, 586b651796SEtienne Carriere _PLL2_P, 596b651796SEtienne Carriere _PLL2_Q, 606b651796SEtienne Carriere _PLL2_R, 616b651796SEtienne Carriere _PLL3_P, 626b651796SEtienne Carriere _PLL3_Q, 636b651796SEtienne Carriere _PLL3_R, 646b651796SEtienne Carriere _PLL4_P, 656b651796SEtienne Carriere _PLL4_Q, 666b651796SEtienne Carriere _PLL4_R, 676b651796SEtienne Carriere _ACLK, 686b651796SEtienne Carriere _PCLK1, 696b651796SEtienne Carriere _PCLK2, 706b651796SEtienne Carriere _PCLK3, 716b651796SEtienne Carriere _PCLK4, 726b651796SEtienne Carriere _PCLK5, 736b651796SEtienne Carriere _HCLK5, 746b651796SEtienne Carriere _HCLK6, 756b651796SEtienne Carriere _HCLK2, 766b651796SEtienne Carriere _CK_PER, 776b651796SEtienne Carriere _CK_MPU, 786b651796SEtienne Carriere _CK_MCU, 796b651796SEtienne Carriere _PARENT_NB, 806b651796SEtienne Carriere _UNKNOWN_ID = 0xff, 816b651796SEtienne Carriere }; 826b651796SEtienne Carriere 836b651796SEtienne Carriere /* 846b651796SEtienne Carriere * Identifiers for parent clock selectors. 856b651796SEtienne Carriere * This enum lists only the parent clocks we are interested in. 866b651796SEtienne Carriere */ 876b651796SEtienne Carriere enum stm32mp1_parent_sel { 886b651796SEtienne Carriere _STGEN_SEL, 89a3009556SMichael Scott _I2C35_SEL, 906b651796SEtienne Carriere _I2C46_SEL, 916b651796SEtienne Carriere _SPI6_SEL, 926b651796SEtienne Carriere _USART1_SEL, 936b651796SEtienne Carriere _RNG1_SEL, 946b651796SEtienne Carriere _UART6_SEL, 956b651796SEtienne Carriere _UART24_SEL, 966b651796SEtienne Carriere _UART35_SEL, 976b651796SEtienne Carriere _UART78_SEL, 986b651796SEtienne Carriere _AXISS_SEL, 996b651796SEtienne Carriere _MCUSS_SEL, 1006b651796SEtienne Carriere _USBPHY_SEL, 1016b651796SEtienne Carriere _USBO_SEL, 1026b651796SEtienne Carriere _RTC_SEL, 10362bb2715SEtienne Carriere _MPU_SEL, 1046b651796SEtienne Carriere _PARENT_SEL_NB, 1056b651796SEtienne Carriere _UNKNOWN_SEL = 0xff, 1066b651796SEtienne Carriere }; 1076b651796SEtienne Carriere 1086b651796SEtienne Carriere static const uint8_t parent_id_clock_id[_PARENT_NB] = { 1096b651796SEtienne Carriere [_HSE] = CK_HSE, 1106b651796SEtienne Carriere [_HSI] = CK_HSI, 1116b651796SEtienne Carriere [_CSI] = CK_CSI, 1126b651796SEtienne Carriere [_LSE] = CK_LSE, 1136b651796SEtienne Carriere [_LSI] = CK_LSI, 1146b651796SEtienne Carriere [_I2S_CKIN] = _UNKNOWN_ID, 1156b651796SEtienne Carriere [_USB_PHY_48] = _UNKNOWN_ID, 1166b651796SEtienne Carriere [_HSI_KER] = CK_HSI, 1176b651796SEtienne Carriere [_HSE_KER] = CK_HSE, 1186b651796SEtienne Carriere [_HSE_KER_DIV2] = CK_HSE_DIV2, 11962bb2715SEtienne Carriere [_HSE_RTC] = _UNKNOWN_ID, 1206b651796SEtienne Carriere [_CSI_KER] = CK_CSI, 1216b651796SEtienne Carriere [_PLL1_P] = PLL1_P, 1226b651796SEtienne Carriere [_PLL1_Q] = PLL1_Q, 1236b651796SEtienne Carriere [_PLL1_R] = PLL1_R, 1246b651796SEtienne Carriere [_PLL2_P] = PLL2_P, 1256b651796SEtienne Carriere [_PLL2_Q] = PLL2_Q, 1266b651796SEtienne Carriere [_PLL2_R] = PLL2_R, 1276b651796SEtienne Carriere [_PLL3_P] = PLL3_P, 1286b651796SEtienne Carriere [_PLL3_Q] = PLL3_Q, 1296b651796SEtienne Carriere [_PLL3_R] = PLL3_R, 1306b651796SEtienne Carriere [_PLL4_P] = PLL4_P, 1316b651796SEtienne Carriere [_PLL4_Q] = PLL4_Q, 1326b651796SEtienne Carriere [_PLL4_R] = PLL4_R, 1336b651796SEtienne Carriere [_ACLK] = CK_AXI, 1346b651796SEtienne Carriere [_PCLK1] = CK_AXI, 1356b651796SEtienne Carriere [_PCLK2] = CK_AXI, 1366b651796SEtienne Carriere [_PCLK3] = CK_AXI, 1376b651796SEtienne Carriere [_PCLK4] = CK_AXI, 1386b651796SEtienne Carriere [_PCLK5] = CK_AXI, 1396b651796SEtienne Carriere [_HCLK5] = CK_AXI, 1406b651796SEtienne Carriere [_HCLK6] = CK_AXI, 1416b651796SEtienne Carriere [_HCLK2] = CK_AXI, 1426b651796SEtienne Carriere [_CK_PER] = CK_PER, 1436b651796SEtienne Carriere [_CK_MPU] = CK_MPU, 1446b651796SEtienne Carriere [_CK_MCU] = CK_MCU, 1456b651796SEtienne Carriere }; 1466b651796SEtienne Carriere 147bb73802dSEtienne Carriere static enum stm32mp1_parent_id osc_id2parent_id(enum stm32mp_osc_id osc_id) 148bb73802dSEtienne Carriere { 149bb73802dSEtienne Carriere assert(osc_id >= OSC_HSI && osc_id < NB_OSC); 150bb73802dSEtienne Carriere COMPILE_TIME_ASSERT((int)OSC_HSI == (int)_HSI && 151bb73802dSEtienne Carriere (int)OSC_HSE == (int)_HSE && 152bb73802dSEtienne Carriere (int)OSC_CSI == (int)_CSI && 153bb73802dSEtienne Carriere (int)OSC_LSI == (int)_LSI && 154bb73802dSEtienne Carriere (int)OSC_LSE == (int)_LSE && 155bb73802dSEtienne Carriere (int)OSC_I2S_CKIN == (int)_I2S_CKIN && 156bb73802dSEtienne Carriere (int)OSC_USB_PHY_48 == (int)_USB_PHY_48); 157bb73802dSEtienne Carriere 158bb73802dSEtienne Carriere return (enum stm32mp1_parent_id)osc_id; 159bb73802dSEtienne Carriere } 160bb73802dSEtienne Carriere 1616b651796SEtienne Carriere static enum stm32mp1_parent_id clock_id2parent_id(unsigned long id) 1626b651796SEtienne Carriere { 1636b651796SEtienne Carriere size_t n = 0; 1646b651796SEtienne Carriere 1656b651796SEtienne Carriere COMPILE_TIME_ASSERT(STM32MP1_LAST_CLK < _UNKNOWN_ID); 1666b651796SEtienne Carriere 1676b651796SEtienne Carriere for (n = 0; n < ARRAY_SIZE(parent_id_clock_id); n++) 1686b651796SEtienne Carriere if (parent_id_clock_id[n] == id) 1696b651796SEtienne Carriere return (enum stm32mp1_parent_id)n; 1706b651796SEtienne Carriere 1716b651796SEtienne Carriere return _UNKNOWN_ID; 1726b651796SEtienne Carriere } 1736b651796SEtienne Carriere 1746b651796SEtienne Carriere /* Identifiers for PLLs and their configuration resources */ 1756b651796SEtienne Carriere enum stm32mp1_pll_id { 1766b651796SEtienne Carriere _PLL1, 1776b651796SEtienne Carriere _PLL2, 1786b651796SEtienne Carriere _PLL3, 1796b651796SEtienne Carriere _PLL4, 1806b651796SEtienne Carriere _PLL_NB 1816b651796SEtienne Carriere }; 1826b651796SEtienne Carriere 1836b651796SEtienne Carriere enum stm32mp1_div_id { 1846b651796SEtienne Carriere _DIV_P, 1856b651796SEtienne Carriere _DIV_Q, 1866b651796SEtienne Carriere _DIV_R, 1876b651796SEtienne Carriere _DIV_NB, 1886b651796SEtienne Carriere }; 1896b651796SEtienne Carriere 1906b651796SEtienne Carriere enum stm32mp1_plltype { 1916b651796SEtienne Carriere PLL_800, 1926b651796SEtienne Carriere PLL_1600, 1936b651796SEtienne Carriere PLL_TYPE_NB 1946b651796SEtienne Carriere }; 1956b651796SEtienne Carriere 1966b651796SEtienne Carriere /* 1976b651796SEtienne Carriere * Clock generic gates clocks which state is controlled by a single RCC bit 1986b651796SEtienne Carriere * 1996b651796SEtienne Carriere * @offset: RCC register byte offset from RCC base where clock is controlled 2006b651796SEtienne Carriere * @bit: Bit position in the RCC 32bit register 2016b651796SEtienne Carriere * @clock_id: Identifier used for the clock in the clock driver API 2026b651796SEtienne Carriere * @set_clr: Non-null if and only-if RCC register is a CLEAR/SET register 2036b651796SEtienne Carriere * (CLEAR register is at offset RCC_MP_ENCLRR_OFFSET from SET register) 2046b651796SEtienne Carriere * @secure: One of N_S or SEC, defined below 2056b651796SEtienne Carriere * @sel: _UNKNOWN_ID (fixed parent) or reference to parent clock selector 2066b651796SEtienne Carriere * (8bit storage of ID from enum stm32mp1_parent_sel) 2076b651796SEtienne Carriere * @fixed: _UNKNOWN_ID (selectable paranet) or reference to parent clock 2086b651796SEtienne Carriere * (8bit storage of ID from enum stm32mp1_parent_id) 2096b651796SEtienne Carriere */ 2106b651796SEtienne Carriere struct stm32mp1_clk_gate { 2116b651796SEtienne Carriere uint16_t offset; 2126b651796SEtienne Carriere uint8_t bit; 2136b651796SEtienne Carriere uint8_t clock_id; 2146b651796SEtienne Carriere uint8_t set_clr; 2156b651796SEtienne Carriere uint8_t secure; 2166b651796SEtienne Carriere uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ 2176b651796SEtienne Carriere uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ 2186b651796SEtienne Carriere }; 2196b651796SEtienne Carriere 2206b651796SEtienne Carriere /* Parent clock selection: select register info, parent clocks references */ 2216b651796SEtienne Carriere struct stm32mp1_clk_sel { 2226b651796SEtienne Carriere uint16_t offset; 2236b651796SEtienne Carriere uint8_t src; 2246b651796SEtienne Carriere uint8_t msk; 2256b651796SEtienne Carriere uint8_t nb_parent; 2266b651796SEtienne Carriere const uint8_t *parent; 2276b651796SEtienne Carriere }; 2286b651796SEtienne Carriere 2296b651796SEtienne Carriere #define REFCLK_SIZE 4 2306b651796SEtienne Carriere /* PLL control: type, control register offsets, up-to-4 selectable parent */ 2316b651796SEtienne Carriere struct stm32mp1_clk_pll { 2326b651796SEtienne Carriere enum stm32mp1_plltype plltype; 2336b651796SEtienne Carriere uint16_t rckxselr; 2346b651796SEtienne Carriere uint16_t pllxcfgr1; 2356b651796SEtienne Carriere uint16_t pllxcfgr2; 2366b651796SEtienne Carriere uint16_t pllxfracr; 2376b651796SEtienne Carriere uint16_t pllxcr; 2386b651796SEtienne Carriere uint16_t pllxcsgr; 2396b651796SEtienne Carriere enum stm32mp_osc_id refclk[REFCLK_SIZE]; 2406b651796SEtienne Carriere }; 2416b651796SEtienne Carriere 2426b651796SEtienne Carriere #define N_S 0 /* Non-secure can access RCC interface */ 2436b651796SEtienne Carriere #define SEC 1 /* RCC[TZEN] protects RCC interface */ 2446b651796SEtienne Carriere 2456b651796SEtienne Carriere /* Clocks with selectable source and not set/clr register access */ 2466b651796SEtienne Carriere #define _CLK_SELEC(_sec, _offset, _bit, _clock_id, _parent_sel) \ 2476b651796SEtienne Carriere { \ 2486b651796SEtienne Carriere .offset = (_offset), \ 2496b651796SEtienne Carriere .bit = (_bit), \ 2506b651796SEtienne Carriere .clock_id = (_clock_id), \ 2516b651796SEtienne Carriere .set_clr = 0, \ 2526b651796SEtienne Carriere .secure = (_sec), \ 2536b651796SEtienne Carriere .sel = (_parent_sel), \ 2546b651796SEtienne Carriere .fixed = _UNKNOWN_ID, \ 2556b651796SEtienne Carriere } 2566b651796SEtienne Carriere 2576b651796SEtienne Carriere /* Clocks with fixed source and not set/clr register access */ 2586b651796SEtienne Carriere #define _CLK_FIXED(_sec, _offset, _bit, _clock_id, _parent) \ 2596b651796SEtienne Carriere { \ 2606b651796SEtienne Carriere .offset = (_offset), \ 2616b651796SEtienne Carriere .bit = (_bit), \ 2626b651796SEtienne Carriere .clock_id = (_clock_id), \ 2636b651796SEtienne Carriere .set_clr = 0, \ 2646b651796SEtienne Carriere .secure = (_sec), \ 2656b651796SEtienne Carriere .sel = _UNKNOWN_SEL, \ 2666b651796SEtienne Carriere .fixed = (_parent), \ 2676b651796SEtienne Carriere } 2686b651796SEtienne Carriere 2696b651796SEtienne Carriere /* Clocks with selectable source and set/clr register access */ 2706b651796SEtienne Carriere #define _CLK_SC_SELEC(_sec, _offset, _bit, _clock_id, _parent_sel) \ 2716b651796SEtienne Carriere { \ 2726b651796SEtienne Carriere .offset = (_offset), \ 2736b651796SEtienne Carriere .bit = (_bit), \ 2746b651796SEtienne Carriere .clock_id = (_clock_id), \ 2756b651796SEtienne Carriere .set_clr = 1, \ 2766b651796SEtienne Carriere .secure = (_sec), \ 2776b651796SEtienne Carriere .sel = (_parent_sel), \ 2786b651796SEtienne Carriere .fixed = _UNKNOWN_ID, \ 2796b651796SEtienne Carriere } 2806b651796SEtienne Carriere 2816b651796SEtienne Carriere /* Clocks with fixed source and set/clr register access */ 2826b651796SEtienne Carriere #define _CLK_SC_FIXED(_sec, _offset, _bit, _clock_id, _parent) \ 2836b651796SEtienne Carriere { \ 2846b651796SEtienne Carriere .offset = (_offset), \ 2856b651796SEtienne Carriere .bit = (_bit), \ 2866b651796SEtienne Carriere .clock_id = (_clock_id), \ 2876b651796SEtienne Carriere .set_clr = 1, \ 2886b651796SEtienne Carriere .secure = (_sec), \ 2896b651796SEtienne Carriere .sel = _UNKNOWN_SEL, \ 2906b651796SEtienne Carriere .fixed = (_parent), \ 2916b651796SEtienne Carriere } 2926b651796SEtienne Carriere 2936b651796SEtienne Carriere /* 2946b651796SEtienne Carriere * Clocks with selectable source and set/clr register access 2956b651796SEtienne Carriere * and enable bit position defined by a label (argument _bit) 2966b651796SEtienne Carriere */ 2976b651796SEtienne Carriere #define _CLK_SC2_SELEC(_sec, _offset, _bit, _clock_id, _parent_sel) \ 2986b651796SEtienne Carriere { \ 2996b651796SEtienne Carriere .offset = (_offset), \ 3006b651796SEtienne Carriere .clock_id = (_clock_id), \ 3016b651796SEtienne Carriere .bit = _offset ## _ ## _bit ## _POS, \ 3026b651796SEtienne Carriere .set_clr = 1, \ 3036b651796SEtienne Carriere .secure = (_sec), \ 3046b651796SEtienne Carriere .sel = (_parent_sel), \ 3056b651796SEtienne Carriere .fixed = _UNKNOWN_ID, \ 3066b651796SEtienne Carriere } 3076b651796SEtienne Carriere #define _CLK_SC2_FIXED(_sec, _offset, _bit, _clock_id, _parent) \ 3086b651796SEtienne Carriere { \ 3096b651796SEtienne Carriere .offset = (_offset), \ 3106b651796SEtienne Carriere .clock_id = (_clock_id), \ 3116b651796SEtienne Carriere .bit = _offset ## _ ## _bit ## _POS, \ 3126b651796SEtienne Carriere .set_clr = 1, \ 3136b651796SEtienne Carriere .secure = (_sec), \ 3146b651796SEtienne Carriere .sel = _UNKNOWN_SEL, \ 3156b651796SEtienne Carriere .fixed = (_parent), \ 3166b651796SEtienne Carriere } 3176b651796SEtienne Carriere 3186b651796SEtienne Carriere #define _CLK_PARENT(idx, _offset, _src, _mask, _parent) \ 3196b651796SEtienne Carriere [(idx)] = { \ 3206b651796SEtienne Carriere .offset = (_offset), \ 3216b651796SEtienne Carriere .src = (_src), \ 3226b651796SEtienne Carriere .msk = (_mask), \ 3236b651796SEtienne Carriere .parent = (_parent), \ 3246b651796SEtienne Carriere .nb_parent = ARRAY_SIZE(_parent) \ 3256b651796SEtienne Carriere } 3266b651796SEtienne Carriere 3276b651796SEtienne Carriere #define _CLK_PLL(_idx, _type, _off1, _off2, _off3, _off4, \ 3286b651796SEtienne Carriere _off5, _off6, _p1, _p2, _p3, _p4) \ 3296b651796SEtienne Carriere [(_idx)] = { \ 3306b651796SEtienne Carriere .plltype = (_type), \ 3316b651796SEtienne Carriere .rckxselr = (_off1), \ 3326b651796SEtienne Carriere .pllxcfgr1 = (_off2), \ 3336b651796SEtienne Carriere .pllxcfgr2 = (_off3), \ 3346b651796SEtienne Carriere .pllxfracr = (_off4), \ 3356b651796SEtienne Carriere .pllxcr = (_off5), \ 3366b651796SEtienne Carriere .pllxcsgr = (_off6), \ 3376b651796SEtienne Carriere .refclk[0] = (_p1), \ 3386b651796SEtienne Carriere .refclk[1] = (_p2), \ 3396b651796SEtienne Carriere .refclk[2] = (_p3), \ 3406b651796SEtienne Carriere .refclk[3] = (_p4), \ 3416b651796SEtienne Carriere } 3426b651796SEtienne Carriere 3436b651796SEtienne Carriere #define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) 3446b651796SEtienne Carriere 3456b651796SEtienne Carriere static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { 3466b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK), 3476b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK), 3486b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK), 3496b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK), 3506b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), 3516b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), 3526b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), 3536b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), 3546b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK), 3556b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), 3566b651796SEtienne Carriere _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), 3576b651796SEtienne Carriere 3586b651796SEtienne Carriere _CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, SPI6EN, SPI6_K, _SPI6_SEL), 3596b651796SEtienne Carriere _CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, I2C4EN, I2C4_K, _I2C46_SEL), 3606b651796SEtienne Carriere _CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, I2C6EN, I2C6_K, _I2C46_SEL), 3616b651796SEtienne Carriere _CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, USART1EN, USART1_K, _USART1_SEL), 3626b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, RTCAPBEN, RTCAPB, _PCLK5), 3636b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, TZC1EN, TZC1, _PCLK5), 3646b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, TZC2EN, TZC2, _PCLK5), 3656b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, TZPCEN, TZPC, _PCLK5), 3666b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, IWDG1APBEN, IWDG1, _PCLK5), 3676b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, BSECEN, BSEC, _PCLK5), 3686b651796SEtienne Carriere _CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, STGENEN, STGEN_K, _STGEN_SEL), 3696b651796SEtienne Carriere 3706b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, GPIOZEN, GPIOZ, _HCLK5), 3716b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, CRYP1EN, CRYP1, _HCLK5), 3726b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, HASH1EN, HASH1, _HCLK5), 3736b651796SEtienne Carriere _CLK_SC2_SELEC(SEC, RCC_MP_AHB5ENSETR, RNG1EN, RNG1_K, _RNG1_SEL), 3743e3bea3dSEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, BKPSRAMEN, BKPSRAM, _HCLK5), 3756b651796SEtienne Carriere 3766b651796SEtienne Carriere _CLK_SC2_FIXED(SEC, RCC_MP_TZAHB6ENSETR, MDMA, MDMA, _HCLK6), 3776b651796SEtienne Carriere 3786b651796SEtienne Carriere _CLK_SELEC(SEC, RCC_BDCR, RCC_BDCR_RTCCKEN_POS, RTC, _RTC_SEL), 3796b651796SEtienne Carriere 3806b651796SEtienne Carriere /* Non-secure clocks */ 381a3009556SMichael Scott #ifdef CFG_WITH_NSEC_I2CS 382a3009556SMichael Scott _CLK_SC2_SELEC(N_S, RCC_MP_APB1ENSETR, I2C5EN, I2C5_K, _I2C35_SEL), 383a3009556SMichael Scott #endif 384a3009556SMichael Scott 3856b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_GPIOS 3866b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_ID), 3876b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_ID), 3886b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_ID), 3896b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_ID), 3906b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_ID), 3916b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_ID), 3926b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_ID), 3936b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_ID), 3946b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_ID), 3956b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_ID), 3966b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_ID), 3976b651796SEtienne Carriere #endif 3986b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), 3996b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS 4006b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), 4016b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), 4026b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), 4036b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), 4046b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), 4056b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), 4066b651796SEtienne Carriere #endif 4076b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), 4086b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS 4096b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), 4106b651796SEtienne Carriere #endif 4116b651796SEtienne Carriere _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), 4126b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), 4136b651796SEtienne Carriere _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), 4146b651796SEtienne Carriere 4156b651796SEtienne Carriere _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), 4166b651796SEtienne Carriere }; 4176b651796SEtienne Carriere DECLARE_KEEP_PAGER(stm32mp1_clk_gate); 4186b651796SEtienne Carriere 4196b651796SEtienne Carriere const uint8_t stm32mp1_clk_on[] = { 4206b651796SEtienne Carriere CK_HSE, CK_CSI, CK_LSI, CK_LSE, CK_HSI, CK_HSE_DIV2, 4216b651796SEtienne Carriere PLL1_P, PLL1_Q, PLL1_R, PLL2_P, PLL2_Q, PLL2_R, PLL3_P, PLL3_Q, PLL3_R, 4226b651796SEtienne Carriere CK_AXI, CK_MPU, CK_MCU, 4236b651796SEtienne Carriere }; 4246b651796SEtienne Carriere 4256b651796SEtienne Carriere /* Parents for secure aware clocks in the xxxSELR value ordering */ 4266b651796SEtienne Carriere static const uint8_t stgen_parents[] = { 4276b651796SEtienne Carriere _HSI_KER, _HSE_KER 4286b651796SEtienne Carriere }; 4296b651796SEtienne Carriere 430a3009556SMichael Scott #ifdef CFG_WITH_NSEC_I2CS 431a3009556SMichael Scott static const uint8_t i2c35_parents[] = { 432a3009556SMichael Scott _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER 433a3009556SMichael Scott }; 434a3009556SMichael Scott #endif 435a3009556SMichael Scott 4366b651796SEtienne Carriere static const uint8_t i2c46_parents[] = { 4376b651796SEtienne Carriere _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER 4386b651796SEtienne Carriere }; 4396b651796SEtienne Carriere 4406b651796SEtienne Carriere static const uint8_t spi6_parents[] = { 4416b651796SEtienne Carriere _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q 4426b651796SEtienne Carriere }; 4436b651796SEtienne Carriere 4446b651796SEtienne Carriere static const uint8_t usart1_parents[] = { 4456b651796SEtienne Carriere _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER 4466b651796SEtienne Carriere }; 4476b651796SEtienne Carriere 4486b651796SEtienne Carriere static const uint8_t rng1_parents[] = { 4496b651796SEtienne Carriere _CSI, _PLL4_R, _LSE, _LSI 4506b651796SEtienne Carriere }; 4516b651796SEtienne Carriere 45262bb2715SEtienne Carriere static const uint8_t mpu_parents[] = { 45362bb2715SEtienne Carriere _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ 45462bb2715SEtienne Carriere }; 45562bb2715SEtienne Carriere 4566b651796SEtienne Carriere /* Parents for (some) non-secure clocks */ 4576b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS 4586b651796SEtienne Carriere static const uint8_t uart6_parents[] = { 4596b651796SEtienne Carriere _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4606b651796SEtienne Carriere }; 4616b651796SEtienne Carriere 4626b651796SEtienne Carriere static const uint8_t uart234578_parents[] = { 4636b651796SEtienne Carriere _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER 4646b651796SEtienne Carriere }; 4656b651796SEtienne Carriere #endif 4666b651796SEtienne Carriere 4676b651796SEtienne Carriere static const uint8_t axiss_parents[] = { 4686b651796SEtienne Carriere _HSI, _HSE, _PLL2_P 4696b651796SEtienne Carriere }; 4706b651796SEtienne Carriere 4716b651796SEtienne Carriere static const uint8_t mcuss_parents[] = { 4726b651796SEtienne Carriere _HSI, _HSE, _CSI, _PLL3_P 4736b651796SEtienne Carriere }; 4746b651796SEtienne Carriere 4756b651796SEtienne Carriere static const uint8_t rtc_parents[] = { 47662bb2715SEtienne Carriere _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC 4776b651796SEtienne Carriere }; 4786b651796SEtienne Carriere 4796b651796SEtienne Carriere static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { 4806b651796SEtienne Carriere /* Secure aware clocks */ 4816b651796SEtienne Carriere _CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), 4826b651796SEtienne Carriere _CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents), 4836b651796SEtienne Carriere _CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents), 4846b651796SEtienne Carriere _CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents), 4856b651796SEtienne Carriere _CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents), 48662bb2715SEtienne Carriere _CLK_PARENT(_RTC_SEL, RCC_BDCR, 16, 0x3, rtc_parents), 48762bb2715SEtienne Carriere _CLK_PARENT(_MPU_SEL, RCC_MPCKSELR, 0, 0x3, mpu_parents), 4886b651796SEtienne Carriere /* Always non-secure clocks (maybe used in some way in secure world) */ 489a3009556SMichael Scott #ifdef CFG_WITH_NSEC_I2CS 490a3009556SMichael Scott _CLK_PARENT(_I2C35_SEL, RCC_I2C35CKSELR, 0, 0x7, i2c35_parents), 491a3009556SMichael Scott #endif 4926b651796SEtienne Carriere #ifdef CFG_WITH_NSEC_UARTS 4936b651796SEtienne Carriere _CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), 4946b651796SEtienne Carriere _CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, uart234578_parents), 4956b651796SEtienne Carriere _CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, uart234578_parents), 4966b651796SEtienne Carriere _CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, uart234578_parents), 4976b651796SEtienne Carriere #endif 4986b651796SEtienne Carriere _CLK_PARENT(_AXISS_SEL, RCC_ASSCKSELR, 0, 0x3, axiss_parents), 4996b651796SEtienne Carriere _CLK_PARENT(_MCUSS_SEL, RCC_MSSCKSELR, 0, 0x3, mcuss_parents), 5006b651796SEtienne Carriere }; 5016b651796SEtienne Carriere 5026b651796SEtienne Carriere /* PLLNCFGR2 register divider by output */ 5036b651796SEtienne Carriere static const uint8_t pllncfgr2[_DIV_NB] = { 5046b651796SEtienne Carriere [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, 5056b651796SEtienne Carriere [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, 5066b651796SEtienne Carriere [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, 5076b651796SEtienne Carriere }; 5086b651796SEtienne Carriere 5096b651796SEtienne Carriere static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { 5106b651796SEtienne Carriere _CLK_PLL(_PLL1, PLL_1600, 5116b651796SEtienne Carriere RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, 5126b651796SEtienne Carriere RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, 513bb73802dSEtienne Carriere OSC_HSI, OSC_HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5146b651796SEtienne Carriere _CLK_PLL(_PLL2, PLL_1600, 5156b651796SEtienne Carriere RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, 5166b651796SEtienne Carriere RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, 517bb73802dSEtienne Carriere OSC_HSI, OSC_HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), 5186b651796SEtienne Carriere _CLK_PLL(_PLL3, PLL_800, 5196b651796SEtienne Carriere RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, 5206b651796SEtienne Carriere RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, 521bb73802dSEtienne Carriere OSC_HSI, OSC_HSE, OSC_CSI, _UNKNOWN_OSC_ID), 5226b651796SEtienne Carriere _CLK_PLL(_PLL4, PLL_800, 5236b651796SEtienne Carriere RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, 5246b651796SEtienne Carriere RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, 525bb73802dSEtienne Carriere OSC_HSI, OSC_HSE, OSC_CSI, OSC_I2S_CKIN), 5266b651796SEtienne Carriere }; 5276b651796SEtienne Carriere 5286b651796SEtienne Carriere /* Prescaler table lookups for clock computation */ 5296b651796SEtienne Carriere /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ 5306b651796SEtienne Carriere static const uint8_t stm32mp1_mcu_div[16] = { 5316b651796SEtienne Carriere 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 5326b651796SEtienne Carriere }; 5336b651796SEtienne Carriere 5346b651796SEtienne Carriere /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ 5356b651796SEtienne Carriere #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div 5366b651796SEtienne Carriere #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div 5376b651796SEtienne Carriere static const uint8_t stm32mp1_mpu_apbx_div[8] = { 5386b651796SEtienne Carriere 0, 1, 2, 3, 4, 4, 4, 4 5396b651796SEtienne Carriere }; 5406b651796SEtienne Carriere 5416b651796SEtienne Carriere /* div = /1 /2 /3 /4 */ 5426b651796SEtienne Carriere static const uint8_t stm32mp1_axi_div[8] = { 5436b651796SEtienne Carriere 1, 2, 3, 4, 4, 4, 4, 4 5446b651796SEtienne Carriere }; 5456b651796SEtienne Carriere 5466b651796SEtienne Carriere static const char __maybe_unused *const stm32mp1_clk_parent_name[_PARENT_NB] = { 5476b651796SEtienne Carriere [_HSI] = "HSI", 5486b651796SEtienne Carriere [_HSE] = "HSE", 5496b651796SEtienne Carriere [_CSI] = "CSI", 5506b651796SEtienne Carriere [_LSI] = "LSI", 5516b651796SEtienne Carriere [_LSE] = "LSE", 5526b651796SEtienne Carriere [_I2S_CKIN] = "I2S_CKIN", 5536b651796SEtienne Carriere [_HSI_KER] = "HSI_KER", 5546b651796SEtienne Carriere [_HSE_KER] = "HSE_KER", 5556b651796SEtienne Carriere [_HSE_KER_DIV2] = "HSE_KER_DIV2", 55662bb2715SEtienne Carriere [_HSE_RTC] = "HSE_RTC", 5576b651796SEtienne Carriere [_CSI_KER] = "CSI_KER", 5586b651796SEtienne Carriere [_PLL1_P] = "PLL1_P", 5596b651796SEtienne Carriere [_PLL1_Q] = "PLL1_Q", 5606b651796SEtienne Carriere [_PLL1_R] = "PLL1_R", 5616b651796SEtienne Carriere [_PLL2_P] = "PLL2_P", 5626b651796SEtienne Carriere [_PLL2_Q] = "PLL2_Q", 5636b651796SEtienne Carriere [_PLL2_R] = "PLL2_R", 5646b651796SEtienne Carriere [_PLL3_P] = "PLL3_P", 5656b651796SEtienne Carriere [_PLL3_Q] = "PLL3_Q", 5666b651796SEtienne Carriere [_PLL3_R] = "PLL3_R", 5676b651796SEtienne Carriere [_PLL4_P] = "PLL4_P", 5686b651796SEtienne Carriere [_PLL4_Q] = "PLL4_Q", 5696b651796SEtienne Carriere [_PLL4_R] = "PLL4_R", 5706b651796SEtienne Carriere [_ACLK] = "ACLK", 5716b651796SEtienne Carriere [_PCLK1] = "PCLK1", 5726b651796SEtienne Carriere [_PCLK2] = "PCLK2", 5736b651796SEtienne Carriere [_PCLK3] = "PCLK3", 5746b651796SEtienne Carriere [_PCLK4] = "PCLK4", 5756b651796SEtienne Carriere [_PCLK5] = "PCLK5", 576af73626dSEtienne Carriere [_HCLK2] = "HCLK2", 5776b651796SEtienne Carriere [_HCLK5] = "HCLK5", 5786b651796SEtienne Carriere [_HCLK6] = "HCLK6", 5796b651796SEtienne Carriere [_CK_PER] = "CK_PER", 5806b651796SEtienne Carriere [_CK_MPU] = "CK_MPU", 5816b651796SEtienne Carriere [_CK_MCU] = "CK_MCU", 5826b651796SEtienne Carriere [_USB_PHY_48] = "USB_PHY_48", 5836b651796SEtienne Carriere }; 5846b651796SEtienne Carriere 5856b651796SEtienne Carriere /* 5866b651796SEtienne Carriere * Oscillator frequency in Hz. This array shall be initialized 5876b651796SEtienne Carriere * according to platform. 5886b651796SEtienne Carriere */ 5896b651796SEtienne Carriere static unsigned long stm32mp1_osc[NB_OSC]; 5906b651796SEtienne Carriere 5916b651796SEtienne Carriere static unsigned long osc_frequency(enum stm32mp_osc_id idx) 5926b651796SEtienne Carriere { 5936b651796SEtienne Carriere if (idx >= ARRAY_SIZE(stm32mp1_osc)) { 5946b651796SEtienne Carriere DMSG("clk id %d not found", idx); 5956b651796SEtienne Carriere return 0; 5966b651796SEtienne Carriere } 5976b651796SEtienne Carriere 5986b651796SEtienne Carriere return stm32mp1_osc[idx]; 5996b651796SEtienne Carriere } 6006b651796SEtienne Carriere 6016b651796SEtienne Carriere static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) 6026b651796SEtienne Carriere { 6036b651796SEtienne Carriere return &stm32mp1_clk_gate[idx]; 6046b651796SEtienne Carriere } 6056b651796SEtienne Carriere 6066b651796SEtienne Carriere static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) 6076b651796SEtienne Carriere { 6086b651796SEtienne Carriere return &stm32mp1_clk_sel[idx]; 6096b651796SEtienne Carriere } 6106b651796SEtienne Carriere 6116b651796SEtienne Carriere static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) 6126b651796SEtienne Carriere { 6136b651796SEtienne Carriere return &stm32mp1_clk_pll[idx]; 6146b651796SEtienne Carriere } 6156b651796SEtienne Carriere 6166b651796SEtienne Carriere static int stm32mp1_clk_get_gated_id(unsigned long id) 6176b651796SEtienne Carriere { 6186b651796SEtienne Carriere unsigned int i = 0; 6196b651796SEtienne Carriere 6206b651796SEtienne Carriere for (i = 0; i < NB_GATES; i++) 6216b651796SEtienne Carriere if (gate_ref(i)->clock_id == id) 6226b651796SEtienne Carriere return i; 6236b651796SEtienne Carriere 6246b651796SEtienne Carriere DMSG("clk id %lu not found", id); 6256b651796SEtienne Carriere return -1; 6266b651796SEtienne Carriere } 6276b651796SEtienne Carriere 6286b651796SEtienne Carriere static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) 6296b651796SEtienne Carriere { 6306b651796SEtienne Carriere return (enum stm32mp1_parent_sel)gate_ref(i)->sel; 6316b651796SEtienne Carriere } 6326b651796SEtienne Carriere 6336b651796SEtienne Carriere static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) 6346b651796SEtienne Carriere { 6356b651796SEtienne Carriere return (enum stm32mp1_parent_id)gate_ref(i)->fixed; 6366b651796SEtienne Carriere } 6376b651796SEtienne Carriere 6386b651796SEtienne Carriere static int stm32mp1_clk_get_parent(unsigned long id) 6396b651796SEtienne Carriere { 6406b651796SEtienne Carriere const struct stm32mp1_clk_sel *sel = NULL; 6416b651796SEtienne Carriere enum stm32mp1_parent_id parent_id = 0; 6426b651796SEtienne Carriere uint32_t p_sel = 0; 6436b651796SEtienne Carriere int i = 0; 6446b651796SEtienne Carriere enum stm32mp1_parent_id p = _UNKNOWN_ID; 6456b651796SEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 6466b651796SEtienne Carriere vaddr_t rcc_base = stm32_rcc_base(); 6476b651796SEtienne Carriere 6486b651796SEtienne Carriere parent_id = clock_id2parent_id(id); 6496b651796SEtienne Carriere if (parent_id != _UNKNOWN_ID) 6506b651796SEtienne Carriere return (int)parent_id; 6516b651796SEtienne Carriere 6526b651796SEtienne Carriere i = stm32mp1_clk_get_gated_id(id); 6536b651796SEtienne Carriere if (i < 0) 6546b651796SEtienne Carriere panic(); 6556b651796SEtienne Carriere 6566b651796SEtienne Carriere p = stm32mp1_clk_get_fixed_parent(i); 6576b651796SEtienne Carriere if (p < _PARENT_NB) 6586b651796SEtienne Carriere return (int)p; 6596b651796SEtienne Carriere 6606b651796SEtienne Carriere s = stm32mp1_clk_get_sel(i); 6616b651796SEtienne Carriere if (s == _UNKNOWN_SEL) 6626b651796SEtienne Carriere return -1; 6636b651796SEtienne Carriere if (s >= _PARENT_SEL_NB) 6646b651796SEtienne Carriere panic(); 6656b651796SEtienne Carriere 6666b651796SEtienne Carriere sel = clk_sel_ref(s); 6676b651796SEtienne Carriere p_sel = (io_read32(rcc_base + sel->offset) >> sel->src) & sel->msk; 6686b651796SEtienne Carriere if (p_sel < sel->nb_parent) 6696b651796SEtienne Carriere return (int)sel->parent[p_sel]; 6706b651796SEtienne Carriere 6716b651796SEtienne Carriere DMSG("No parent selected for clk %lu", id); 6726b651796SEtienne Carriere return -1; 6736b651796SEtienne Carriere } 6746b651796SEtienne Carriere 6756b651796SEtienne Carriere static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) 6766b651796SEtienne Carriere { 6776b651796SEtienne Carriere uint32_t selr = io_read32(stm32_rcc_base() + pll->rckxselr); 6786b651796SEtienne Carriere uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; 6796b651796SEtienne Carriere 6806b651796SEtienne Carriere return osc_frequency(pll->refclk[src]); 6816b651796SEtienne Carriere } 6826b651796SEtienne Carriere 6836b651796SEtienne Carriere /* 6846b651796SEtienne Carriere * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL 6856b651796SEtienne Carriere * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) 6866b651796SEtienne Carriere * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) 6876b651796SEtienne Carriere * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) 6886b651796SEtienne Carriere */ 6896b651796SEtienne Carriere static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) 6906b651796SEtienne Carriere { 6916b651796SEtienne Carriere unsigned long refclk = 0; 6926b651796SEtienne Carriere unsigned long fvco = 0; 6936b651796SEtienne Carriere uint32_t cfgr1 = 0; 6946b651796SEtienne Carriere uint32_t fracr = 0; 6956b651796SEtienne Carriere uint32_t divm = 0; 6966b651796SEtienne Carriere uint32_t divn = 0; 6976b651796SEtienne Carriere 6986b651796SEtienne Carriere cfgr1 = io_read32(stm32_rcc_base() + pll->pllxcfgr1); 6996b651796SEtienne Carriere fracr = io_read32(stm32_rcc_base() + pll->pllxfracr); 7006b651796SEtienne Carriere 7016b651796SEtienne Carriere divm = (cfgr1 & RCC_PLLNCFGR1_DIVM_MASK) >> RCC_PLLNCFGR1_DIVM_SHIFT; 7026b651796SEtienne Carriere divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; 7036b651796SEtienne Carriere 7046b651796SEtienne Carriere refclk = stm32mp1_pll_get_fref(pll); 7056b651796SEtienne Carriere 7066b651796SEtienne Carriere /* 7076b651796SEtienne Carriere * With FRACV : 7086b651796SEtienne Carriere * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) 7096b651796SEtienne Carriere * Without FRACV 7106b651796SEtienne Carriere * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) 7116b651796SEtienne Carriere */ 7126b651796SEtienne Carriere if (fracr & RCC_PLLNFRACR_FRACLE) { 7136b651796SEtienne Carriere unsigned long long numerator = 0; 7146b651796SEtienne Carriere unsigned long long denominator = 0; 7156b651796SEtienne Carriere uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> 7166b651796SEtienne Carriere RCC_PLLNFRACR_FRACV_SHIFT; 7176b651796SEtienne Carriere 7186b651796SEtienne Carriere numerator = (((unsigned long long)divn + 1U) << 13) + fracv; 7196b651796SEtienne Carriere numerator = refclk * numerator; 7206b651796SEtienne Carriere denominator = ((unsigned long long)divm + 1U) << 13; 7216b651796SEtienne Carriere fvco = (unsigned long)(numerator / denominator); 7226b651796SEtienne Carriere } else { 7236b651796SEtienne Carriere fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); 7246b651796SEtienne Carriere } 7256b651796SEtienne Carriere 7266b651796SEtienne Carriere return fvco; 7276b651796SEtienne Carriere } 7286b651796SEtienne Carriere 7296b651796SEtienne Carriere static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, 7306b651796SEtienne Carriere enum stm32mp1_div_id div_id) 7316b651796SEtienne Carriere { 7326b651796SEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 7336b651796SEtienne Carriere unsigned long dfout = 0; 7346b651796SEtienne Carriere uint32_t cfgr2 = 0; 7356b651796SEtienne Carriere uint32_t divy = 0; 7366b651796SEtienne Carriere 7376b651796SEtienne Carriere if (div_id >= _DIV_NB) 7386b651796SEtienne Carriere return 0; 7396b651796SEtienne Carriere 7406b651796SEtienne Carriere cfgr2 = io_read32(stm32_rcc_base() + pll->pllxcfgr2); 7416b651796SEtienne Carriere divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; 7426b651796SEtienne Carriere 7436b651796SEtienne Carriere dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); 7446b651796SEtienne Carriere 7456b651796SEtienne Carriere return dfout; 7466b651796SEtienne Carriere } 7476b651796SEtienne Carriere 748bb73802dSEtienne Carriere static unsigned long get_clock_rate(enum stm32mp1_parent_id p) 7496b651796SEtienne Carriere { 7506b651796SEtienne Carriere uint32_t reg = 0; 7516b651796SEtienne Carriere unsigned long clock = 0; 7526b651796SEtienne Carriere vaddr_t rcc_base = stm32_rcc_base(); 7536b651796SEtienne Carriere 7546b651796SEtienne Carriere switch (p) { 7556b651796SEtienne Carriere case _CK_MPU: 7566b651796SEtienne Carriere /* MPU sub system */ 7576b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_MPCKSELR); 7586b651796SEtienne Carriere switch (reg & RCC_SELR_SRC_MASK) { 7596b651796SEtienne Carriere case RCC_MPCKSELR_HSI: 760bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSI); 7616b651796SEtienne Carriere break; 7626b651796SEtienne Carriere case RCC_MPCKSELR_HSE: 763bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSE); 7646b651796SEtienne Carriere break; 7656b651796SEtienne Carriere case RCC_MPCKSELR_PLL: 7666b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 7676b651796SEtienne Carriere break; 7686b651796SEtienne Carriere case RCC_MPCKSELR_PLL_MPUDIV: 7696b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_MPCKDIVR); 7706b651796SEtienne Carriere if (reg & RCC_MPUDIV_MASK) 7716b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P) >> 7726b651796SEtienne Carriere stm32mp1_mpu_div[reg & RCC_MPUDIV_MASK]; 7736b651796SEtienne Carriere else 7746b651796SEtienne Carriere clock = 0; 7756b651796SEtienne Carriere break; 7766b651796SEtienne Carriere default: 7776b651796SEtienne Carriere break; 7786b651796SEtienne Carriere } 7796b651796SEtienne Carriere break; 7806b651796SEtienne Carriere /* AXI sub system */ 7816b651796SEtienne Carriere case _ACLK: 7826b651796SEtienne Carriere case _HCLK2: 7836b651796SEtienne Carriere case _HCLK5: 7846b651796SEtienne Carriere case _HCLK6: 7856b651796SEtienne Carriere case _PCLK4: 7866b651796SEtienne Carriere case _PCLK5: 7876b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_ASSCKSELR); 7886b651796SEtienne Carriere switch (reg & RCC_SELR_SRC_MASK) { 7896b651796SEtienne Carriere case RCC_ASSCKSELR_HSI: 790bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSI); 7916b651796SEtienne Carriere break; 7926b651796SEtienne Carriere case RCC_ASSCKSELR_HSE: 793bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSE); 7946b651796SEtienne Carriere break; 7956b651796SEtienne Carriere case RCC_ASSCKSELR_PLL: 7966b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 7976b651796SEtienne Carriere break; 7986b651796SEtienne Carriere default: 7996b651796SEtienne Carriere break; 8006b651796SEtienne Carriere } 8016b651796SEtienne Carriere 8026b651796SEtienne Carriere /* System clock divider */ 8036b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_AXIDIVR); 8046b651796SEtienne Carriere clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; 8056b651796SEtienne Carriere 8066b651796SEtienne Carriere switch (p) { 8076b651796SEtienne Carriere case _PCLK4: 8086b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_APB4DIVR); 8096b651796SEtienne Carriere clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8106b651796SEtienne Carriere break; 8116b651796SEtienne Carriere case _PCLK5: 8126b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_APB5DIVR); 8136b651796SEtienne Carriere clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8146b651796SEtienne Carriere break; 8156b651796SEtienne Carriere default: 8166b651796SEtienne Carriere break; 8176b651796SEtienne Carriere } 8186b651796SEtienne Carriere break; 8196b651796SEtienne Carriere /* MCU sub system */ 8206b651796SEtienne Carriere case _CK_MCU: 8216b651796SEtienne Carriere case _PCLK1: 8226b651796SEtienne Carriere case _PCLK2: 8236b651796SEtienne Carriere case _PCLK3: 8246b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_MSSCKSELR); 8256b651796SEtienne Carriere switch (reg & RCC_SELR_SRC_MASK) { 8266b651796SEtienne Carriere case RCC_MSSCKSELR_HSI: 827bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSI); 8286b651796SEtienne Carriere break; 8296b651796SEtienne Carriere case RCC_MSSCKSELR_HSE: 830bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSE); 8316b651796SEtienne Carriere break; 8326b651796SEtienne Carriere case RCC_MSSCKSELR_CSI: 833bb73802dSEtienne Carriere clock = osc_frequency(OSC_CSI); 8346b651796SEtienne Carriere break; 8356b651796SEtienne Carriere case RCC_MSSCKSELR_PLL: 8366b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 8376b651796SEtienne Carriere break; 8386b651796SEtienne Carriere default: 8396b651796SEtienne Carriere break; 8406b651796SEtienne Carriere } 8416b651796SEtienne Carriere 8426b651796SEtienne Carriere /* MCU clock divider */ 8436b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_MCUDIVR); 8446b651796SEtienne Carriere clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; 8456b651796SEtienne Carriere 8466b651796SEtienne Carriere switch (p) { 8476b651796SEtienne Carriere case _PCLK1: 8486b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_APB1DIVR); 8496b651796SEtienne Carriere clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8506b651796SEtienne Carriere break; 8516b651796SEtienne Carriere case _PCLK2: 8526b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_APB2DIVR); 8536b651796SEtienne Carriere clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8546b651796SEtienne Carriere break; 8556b651796SEtienne Carriere case _PCLK3: 8566b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_APB3DIVR); 8576b651796SEtienne Carriere clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; 8586b651796SEtienne Carriere break; 8596b651796SEtienne Carriere case _CK_MCU: 8606b651796SEtienne Carriere default: 8616b651796SEtienne Carriere break; 8626b651796SEtienne Carriere } 8636b651796SEtienne Carriere break; 8646b651796SEtienne Carriere case _CK_PER: 8656b651796SEtienne Carriere reg = io_read32(rcc_base + RCC_CPERCKSELR); 8666b651796SEtienne Carriere switch (reg & RCC_SELR_SRC_MASK) { 8676b651796SEtienne Carriere case RCC_CPERCKSELR_HSI: 868bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSI); 8696b651796SEtienne Carriere break; 8706b651796SEtienne Carriere case RCC_CPERCKSELR_HSE: 871bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSE); 8726b651796SEtienne Carriere break; 8736b651796SEtienne Carriere case RCC_CPERCKSELR_CSI: 874bb73802dSEtienne Carriere clock = osc_frequency(OSC_CSI); 8756b651796SEtienne Carriere break; 8766b651796SEtienne Carriere default: 8776b651796SEtienne Carriere break; 8786b651796SEtienne Carriere } 8796b651796SEtienne Carriere break; 8806b651796SEtienne Carriere case _HSI: 8816b651796SEtienne Carriere case _HSI_KER: 882bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSI); 8836b651796SEtienne Carriere break; 8846b651796SEtienne Carriere case _CSI: 8856b651796SEtienne Carriere case _CSI_KER: 886bb73802dSEtienne Carriere clock = osc_frequency(OSC_CSI); 8876b651796SEtienne Carriere break; 8886b651796SEtienne Carriere case _HSE: 8896b651796SEtienne Carriere case _HSE_KER: 890bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSE); 8916b651796SEtienne Carriere break; 8926b651796SEtienne Carriere case _HSE_KER_DIV2: 893bb73802dSEtienne Carriere clock = osc_frequency(OSC_HSE) >> 1; 894bb73802dSEtienne Carriere break; 89562bb2715SEtienne Carriere case _HSE_RTC: 89662bb2715SEtienne Carriere clock = osc_frequency(OSC_HSE); 89762bb2715SEtienne Carriere clock /= (io_read32(rcc_base + RCC_RTCDIVR) & 89862bb2715SEtienne Carriere RCC_DIVR_DIV_MASK) + 1; 8996b651796SEtienne Carriere break; 9006b651796SEtienne Carriere case _LSI: 901bb73802dSEtienne Carriere clock = osc_frequency(OSC_LSI); 9026b651796SEtienne Carriere break; 9036b651796SEtienne Carriere case _LSE: 904bb73802dSEtienne Carriere clock = osc_frequency(OSC_LSE); 9056b651796SEtienne Carriere break; 9066b651796SEtienne Carriere /* PLL */ 9076b651796SEtienne Carriere case _PLL1_P: 9086b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); 9096b651796SEtienne Carriere break; 9106b651796SEtienne Carriere case _PLL1_Q: 9116b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); 9126b651796SEtienne Carriere break; 9136b651796SEtienne Carriere case _PLL1_R: 9146b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); 9156b651796SEtienne Carriere break; 9166b651796SEtienne Carriere case _PLL2_P: 9176b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); 9186b651796SEtienne Carriere break; 9196b651796SEtienne Carriere case _PLL2_Q: 9206b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); 9216b651796SEtienne Carriere break; 9226b651796SEtienne Carriere case _PLL2_R: 9236b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); 9246b651796SEtienne Carriere break; 9256b651796SEtienne Carriere case _PLL3_P: 9266b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); 9276b651796SEtienne Carriere break; 9286b651796SEtienne Carriere case _PLL3_Q: 9296b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); 9306b651796SEtienne Carriere break; 9316b651796SEtienne Carriere case _PLL3_R: 9326b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); 9336b651796SEtienne Carriere break; 9346b651796SEtienne Carriere case _PLL4_P: 9356b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); 9366b651796SEtienne Carriere break; 9376b651796SEtienne Carriere case _PLL4_Q: 9386b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); 9396b651796SEtienne Carriere break; 9406b651796SEtienne Carriere case _PLL4_R: 9416b651796SEtienne Carriere clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); 9426b651796SEtienne Carriere break; 9436b651796SEtienne Carriere /* Other */ 9446b651796SEtienne Carriere case _USB_PHY_48: 945bb73802dSEtienne Carriere clock = osc_frequency(OSC_USB_PHY_48); 9466b651796SEtienne Carriere break; 9476b651796SEtienne Carriere default: 9486b651796SEtienne Carriere break; 9496b651796SEtienne Carriere } 9506b651796SEtienne Carriere 9516b651796SEtienne Carriere return clock; 9526b651796SEtienne Carriere } 9536b651796SEtienne Carriere 9546b651796SEtienne Carriere static void __clk_enable(const struct stm32mp1_clk_gate *gate) 9556b651796SEtienne Carriere { 9566b651796SEtienne Carriere vaddr_t base = stm32_rcc_base(); 9576b651796SEtienne Carriere uint32_t bit = BIT(gate->bit); 9586b651796SEtienne Carriere 9596b651796SEtienne Carriere if (gate->set_clr) 9606b651796SEtienne Carriere io_write32(base + gate->offset, bit); 9616b651796SEtienne Carriere else 9626b651796SEtienne Carriere io_setbits32_stm32shregs(base + gate->offset, bit); 9636b651796SEtienne Carriere 9646b651796SEtienne Carriere FMSG("Clock %u has been enabled", gate->clock_id); 9656b651796SEtienne Carriere } 9666b651796SEtienne Carriere 9676b651796SEtienne Carriere static void __clk_disable(const struct stm32mp1_clk_gate *gate) 9686b651796SEtienne Carriere { 9696b651796SEtienne Carriere vaddr_t base = stm32_rcc_base(); 9706b651796SEtienne Carriere uint32_t bit = BIT(gate->bit); 9716b651796SEtienne Carriere 9726b651796SEtienne Carriere if (gate->set_clr) 9736b651796SEtienne Carriere io_write32(base + gate->offset + RCC_MP_ENCLRR_OFFSET, bit); 9746b651796SEtienne Carriere else 9756b651796SEtienne Carriere io_clrbits32_stm32shregs(base + gate->offset, bit); 9766b651796SEtienne Carriere 9776b651796SEtienne Carriere FMSG("Clock %u has been disabled", gate->clock_id); 9786b651796SEtienne Carriere } 9796b651796SEtienne Carriere 9806b651796SEtienne Carriere static long get_timer_rate(long parent_rate, unsigned int apb_bus) 9816b651796SEtienne Carriere { 9826b651796SEtienne Carriere uint32_t timgxpre = 0; 9836b651796SEtienne Carriere uint32_t apbxdiv = 0; 9846b651796SEtienne Carriere vaddr_t rcc_base = stm32_rcc_base(); 9856b651796SEtienne Carriere 9866b651796SEtienne Carriere switch (apb_bus) { 9876b651796SEtienne Carriere case 1: 9886b651796SEtienne Carriere apbxdiv = io_read32(rcc_base + RCC_APB1DIVR) & 9896b651796SEtienne Carriere RCC_APBXDIV_MASK; 9906b651796SEtienne Carriere timgxpre = io_read32(rcc_base + RCC_TIMG1PRER) & 9916b651796SEtienne Carriere RCC_TIMGXPRER_TIMGXPRE; 9926b651796SEtienne Carriere break; 9936b651796SEtienne Carriere case 2: 9946b651796SEtienne Carriere apbxdiv = io_read32(rcc_base + RCC_APB2DIVR) & 9956b651796SEtienne Carriere RCC_APBXDIV_MASK; 9966b651796SEtienne Carriere timgxpre = io_read32(rcc_base + RCC_TIMG2PRER) & 9976b651796SEtienne Carriere RCC_TIMGXPRER_TIMGXPRE; 9986b651796SEtienne Carriere break; 9996b651796SEtienne Carriere default: 10006b651796SEtienne Carriere panic(); 10016b651796SEtienne Carriere break; 10026b651796SEtienne Carriere } 10036b651796SEtienne Carriere 10046b651796SEtienne Carriere if (apbxdiv == 0) 10056b651796SEtienne Carriere return parent_rate; 10066b651796SEtienne Carriere 10076b651796SEtienne Carriere return parent_rate * (timgxpre + 1) * 2; 10086b651796SEtienne Carriere } 10096b651796SEtienne Carriere 10106b651796SEtienne Carriere static unsigned long _stm32_clock_get_rate(unsigned long id) 10116b651796SEtienne Carriere { 1012bb73802dSEtienne Carriere enum stm32mp1_parent_id p = _UNKNOWN_ID; 10136b651796SEtienne Carriere unsigned long rate = 0; 10146b651796SEtienne Carriere 10156b651796SEtienne Carriere p = stm32mp1_clk_get_parent(id); 10166b651796SEtienne Carriere if (p < 0) 10176b651796SEtienne Carriere return 0; 10186b651796SEtienne Carriere 10196b651796SEtienne Carriere rate = get_clock_rate(p); 10206b651796SEtienne Carriere 10216b651796SEtienne Carriere if ((id >= TIM2_K) && (id <= TIM14_K)) 10226b651796SEtienne Carriere rate = get_timer_rate(rate, 1); 10236b651796SEtienne Carriere 10246b651796SEtienne Carriere if ((id >= TIM1_K) && (id <= TIM17_K)) 10256b651796SEtienne Carriere rate = get_timer_rate(rate, 2); 10266b651796SEtienne Carriere 10276b651796SEtienne Carriere return rate; 10286b651796SEtienne Carriere } 10296b651796SEtienne Carriere 10306b651796SEtienne Carriere /* 10316b651796SEtienne Carriere * Get the parent ID of the target parent clock, or -1 if no parent found. 10326b651796SEtienne Carriere */ 1033bb73802dSEtienne Carriere static enum stm32mp1_parent_id get_parent_id_parent(enum stm32mp1_parent_id id) 10346b651796SEtienne Carriere { 10356b651796SEtienne Carriere enum stm32mp1_parent_sel s = _UNKNOWN_SEL; 10366b651796SEtienne Carriere enum stm32mp1_pll_id pll_id = _PLL_NB; 10376b651796SEtienne Carriere uint32_t p_sel = 0; 10386b651796SEtienne Carriere 1039bb73802dSEtienne Carriere switch (id) { 10406b651796SEtienne Carriere case _ACLK: 10413e3bea3dSEtienne Carriere case _HCLK5: 104211bee8b0SEtienne Carriere case _HCLK6: 10436b651796SEtienne Carriere case _PCLK4: 10446b651796SEtienne Carriere case _PCLK5: 10456b651796SEtienne Carriere s = _AXISS_SEL; 10466b651796SEtienne Carriere break; 10476b651796SEtienne Carriere case _PLL1_P: 10486b651796SEtienne Carriere case _PLL1_Q: 10496b651796SEtienne Carriere case _PLL1_R: 10506b651796SEtienne Carriere pll_id = _PLL1; 10516b651796SEtienne Carriere break; 10526b651796SEtienne Carriere case _PLL2_P: 10536b651796SEtienne Carriere case _PLL2_Q: 10546b651796SEtienne Carriere case _PLL2_R: 10556b651796SEtienne Carriere pll_id = _PLL2; 10566b651796SEtienne Carriere break; 10576b651796SEtienne Carriere case _PLL3_P: 10586b651796SEtienne Carriere case _PLL3_Q: 10596b651796SEtienne Carriere case _PLL3_R: 10606b651796SEtienne Carriere pll_id = _PLL3; 10616b651796SEtienne Carriere break; 10626b651796SEtienne Carriere case _PLL4_P: 10636b651796SEtienne Carriere case _PLL4_Q: 10646b651796SEtienne Carriere case _PLL4_R: 10656b651796SEtienne Carriere pll_id = _PLL4; 10666b651796SEtienne Carriere break; 10676b651796SEtienne Carriere case _PCLK1: 10686b651796SEtienne Carriere case _PCLK2: 10696b651796SEtienne Carriere case _HCLK2: 10706b651796SEtienne Carriere case _CK_PER: 10716b651796SEtienne Carriere case _CK_MPU: 10726b651796SEtienne Carriere case _CK_MCU: 10736b651796SEtienne Carriere case _USB_PHY_48: 10746b651796SEtienne Carriere /* We do not expected to access these */ 10756b651796SEtienne Carriere panic(); 10766b651796SEtienne Carriere break; 10776b651796SEtienne Carriere default: 10786b651796SEtienne Carriere /* Other parents have no parent */ 10796b651796SEtienne Carriere return -1; 10806b651796SEtienne Carriere } 10816b651796SEtienne Carriere 10826b651796SEtienne Carriere if (s != _UNKNOWN_SEL) { 10836b651796SEtienne Carriere const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); 10846b651796SEtienne Carriere vaddr_t rcc_base = stm32_rcc_base(); 10856b651796SEtienne Carriere 10866b651796SEtienne Carriere p_sel = (io_read32(rcc_base + sel->offset) >> sel->src) & 10876b651796SEtienne Carriere sel->msk; 10886b651796SEtienne Carriere 10896b651796SEtienne Carriere if (p_sel < sel->nb_parent) 10906b651796SEtienne Carriere return sel->parent[p_sel]; 10916b651796SEtienne Carriere } else { 10926b651796SEtienne Carriere const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); 10936b651796SEtienne Carriere 10946b651796SEtienne Carriere p_sel = io_read32(stm32_rcc_base() + pll->rckxselr) & 10956b651796SEtienne Carriere RCC_SELR_REFCLK_SRC_MASK; 10966b651796SEtienne Carriere 10976b651796SEtienne Carriere if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) 1098bb73802dSEtienne Carriere return osc_id2parent_id(pll->refclk[p_sel]); 10996b651796SEtienne Carriere } 11006b651796SEtienne Carriere 1101bb73802dSEtienne Carriere FMSG("No parent found for %s", stm32mp1_clk_parent_name[id]); 11026b651796SEtienne Carriere return -1; 11036b651796SEtienne Carriere } 11046b651796SEtienne Carriere 11056b651796SEtienne Carriere /* We are only interested in knowing if PLL3 shall be secure or not */ 1106bb73802dSEtienne Carriere static void secure_parent_clocks(enum stm32mp1_parent_id parent_id) 11076b651796SEtienne Carriere { 1108bb73802dSEtienne Carriere enum stm32mp1_parent_id grandparent_id = _UNKNOWN_ID; 11096b651796SEtienne Carriere 11106b651796SEtienne Carriere switch (parent_id) { 11116b651796SEtienne Carriere case _ACLK: 11126b651796SEtienne Carriere case _HCLK2: 11136b651796SEtienne Carriere case _HCLK5: 11146b651796SEtienne Carriere case _HCLK6: 11156b651796SEtienne Carriere case _PCLK4: 11166b651796SEtienne Carriere case _PCLK5: 11176b651796SEtienne Carriere /* Intermediate clock mux or clock, go deeper in clock tree */ 11186b651796SEtienne Carriere break; 11196b651796SEtienne Carriere case _HSI: 11206b651796SEtienne Carriere case _HSI_KER: 11216b651796SEtienne Carriere case _LSI: 11226b651796SEtienne Carriere case _CSI: 11236b651796SEtienne Carriere case _CSI_KER: 11246b651796SEtienne Carriere case _HSE: 11256b651796SEtienne Carriere case _HSE_KER: 11266b651796SEtienne Carriere case _HSE_KER_DIV2: 112762bb2715SEtienne Carriere case _HSE_RTC: 11286b651796SEtienne Carriere case _LSE: 11296b651796SEtienne Carriere case _PLL1_P: 11306b651796SEtienne Carriere case _PLL1_Q: 11316b651796SEtienne Carriere case _PLL1_R: 11326b651796SEtienne Carriere case _PLL2_P: 11336b651796SEtienne Carriere case _PLL2_Q: 11346b651796SEtienne Carriere case _PLL2_R: 11356b651796SEtienne Carriere /* Always secure clocks, no need to go further */ 11366b651796SEtienne Carriere return; 11376b651796SEtienne Carriere case _PLL3_P: 11386b651796SEtienne Carriere case _PLL3_Q: 11396b651796SEtienne Carriere case _PLL3_R: 11406b651796SEtienne Carriere /* PLL3 is a shared resource, registered and don't go further */ 11416b651796SEtienne Carriere stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); 11426b651796SEtienne Carriere return; 11436b651796SEtienne Carriere default: 11446b651796SEtienne Carriere DMSG("Cannot lookup parent clock %s", 11456b651796SEtienne Carriere stm32mp1_clk_parent_name[parent_id]); 11466b651796SEtienne Carriere panic(); 11476b651796SEtienne Carriere } 11486b651796SEtienne Carriere 11496b651796SEtienne Carriere grandparent_id = get_parent_id_parent(parent_id); 11506b651796SEtienne Carriere if (grandparent_id >= 0) 11516b651796SEtienne Carriere secure_parent_clocks(grandparent_id); 11526b651796SEtienne Carriere } 11536b651796SEtienne Carriere 11546b651796SEtienne Carriere void stm32mp_register_clock_parents_secure(unsigned long clock_id) 11556b651796SEtienne Carriere { 1156bb73802dSEtienne Carriere enum stm32mp1_parent_id parent_id = stm32mp1_clk_get_parent(clock_id); 11576b651796SEtienne Carriere 11586b651796SEtienne Carriere if (parent_id < 0) { 11596b651796SEtienne Carriere DMSG("No parent for clock %lu", clock_id); 11606b651796SEtienne Carriere return; 11616b651796SEtienne Carriere } 11626b651796SEtienne Carriere 11636b651796SEtienne Carriere secure_parent_clocks(parent_id); 11646b651796SEtienne Carriere } 11656b651796SEtienne Carriere 11666b651796SEtienne Carriere static const char *stm32mp_osc_node_label[NB_OSC] = { 1167bb73802dSEtienne Carriere [OSC_LSI] = "clk-lsi", 1168bb73802dSEtienne Carriere [OSC_LSE] = "clk-lse", 1169bb73802dSEtienne Carriere [OSC_HSI] = "clk-hsi", 1170bb73802dSEtienne Carriere [OSC_HSE] = "clk-hse", 1171bb73802dSEtienne Carriere [OSC_CSI] = "clk-csi", 1172bb73802dSEtienne Carriere [OSC_I2S_CKIN] = "i2s_ckin", 1173bb73802dSEtienne Carriere [OSC_USB_PHY_48] = "ck_usbo_48m" 11746b651796SEtienne Carriere }; 11756b651796SEtienne Carriere 11766b651796SEtienne Carriere static unsigned int clk_freq_prop(const void *fdt, int node) 11776b651796SEtienne Carriere { 11786b651796SEtienne Carriere const fdt32_t *cuint = NULL; 11796b651796SEtienne Carriere int ret = 0; 11806b651796SEtienne Carriere 11816b651796SEtienne Carriere /* Disabled clocks report null rate */ 1182f354a5d8SGatien Chevallier if (fdt_get_status(fdt, node) == DT_STATUS_DISABLED) 11836b651796SEtienne Carriere return 0; 11846b651796SEtienne Carriere 11856b651796SEtienne Carriere cuint = fdt_getprop(fdt, node, "clock-frequency", &ret); 11866b651796SEtienne Carriere if (!cuint) 11876b651796SEtienne Carriere panic(); 11886b651796SEtienne Carriere 11896b651796SEtienne Carriere return fdt32_to_cpu(*cuint); 11906b651796SEtienne Carriere } 11916b651796SEtienne Carriere 11926b651796SEtienne Carriere static void get_osc_freq_from_dt(const void *fdt) 11936b651796SEtienne Carriere { 11946b651796SEtienne Carriere enum stm32mp_osc_id idx = _UNKNOWN_OSC_ID; 11956b651796SEtienne Carriere int clk_node = fdt_path_offset(fdt, "/clocks"); 11966b651796SEtienne Carriere 11976b651796SEtienne Carriere if (clk_node < 0) 11986b651796SEtienne Carriere panic(); 11996b651796SEtienne Carriere 1200bb73802dSEtienne Carriere COMPILE_TIME_ASSERT((int)OSC_HSI == 0); 1201bb73802dSEtienne Carriere for (idx = OSC_HSI; idx < NB_OSC; idx++) { 12026b651796SEtienne Carriere const char *name = stm32mp_osc_node_label[idx]; 12036b651796SEtienne Carriere int subnode = 0; 12046b651796SEtienne Carriere 12056b651796SEtienne Carriere fdt_for_each_subnode(subnode, fdt, clk_node) { 12066b651796SEtienne Carriere const char *cchar = NULL; 12076b651796SEtienne Carriere int ret = 0; 12086b651796SEtienne Carriere 12096b651796SEtienne Carriere cchar = fdt_get_name(fdt, subnode, &ret); 12106b651796SEtienne Carriere if (!cchar) 12116b651796SEtienne Carriere panic(); 12126b651796SEtienne Carriere 12136b651796SEtienne Carriere if (strncmp(cchar, name, (size_t)ret) == 0) { 12146b651796SEtienne Carriere stm32mp1_osc[idx] = clk_freq_prop(fdt, subnode); 12156b651796SEtienne Carriere 12166b651796SEtienne Carriere DMSG("Osc %s: %lu Hz", name, stm32mp1_osc[idx]); 12176b651796SEtienne Carriere break; 12186b651796SEtienne Carriere } 12196b651796SEtienne Carriere } 12206b651796SEtienne Carriere 12216b651796SEtienne Carriere if (!stm32mp1_osc[idx]) 12226b651796SEtienne Carriere DMSG("Osc %s: no frequency info", name); 12236b651796SEtienne Carriere } 12246b651796SEtienne Carriere } 12256b651796SEtienne Carriere 12266b651796SEtienne Carriere static void enable_static_secure_clocks(void) 12276b651796SEtienne Carriere { 12286b651796SEtienne Carriere unsigned int idx = 0; 12296b651796SEtienne Carriere const unsigned long secure_enable[] = { 12306b651796SEtienne Carriere DDRC1, DDRC1LP, DDRC2, DDRC2LP, DDRPHYC, DDRPHYCLP, DDRCAPB, 12316b651796SEtienne Carriere AXIDCG, DDRPHYCAPB, DDRPHYCAPBLP, TZPC, TZC1, TZC2, STGEN_K, 12326b651796SEtienne Carriere BSEC, 12336b651796SEtienne Carriere }; 12346b651796SEtienne Carriere 12356b651796SEtienne Carriere for (idx = 0; idx < ARRAY_SIZE(secure_enable); idx++) { 1236488c73c0SGatien Chevallier clk_enable(stm32mp_rcc_clock_id_to_clk(secure_enable[idx])); 12376b651796SEtienne Carriere stm32mp_register_clock_parents_secure(secure_enable[idx]); 12386b651796SEtienne Carriere } 12396b651796SEtienne Carriere 12406b651796SEtienne Carriere if (CFG_TEE_CORE_NB_CORE > 1) 1241488c73c0SGatien Chevallier clk_enable(stm32mp_rcc_clock_id_to_clk(RTCAPB)); 12426b651796SEtienne Carriere } 12436b651796SEtienne Carriere 12446b651796SEtienne Carriere static void __maybe_unused enable_rcc_tzen(void) 12456b651796SEtienne Carriere { 12466b651796SEtienne Carriere io_setbits32(stm32_rcc_base() + RCC_TZCR, RCC_TZCR_TZEN); 12476b651796SEtienne Carriere } 12486b651796SEtienne Carriere 12496b651796SEtienne Carriere static void __maybe_unused disable_rcc_tzen(void) 12506b651796SEtienne Carriere { 12516b651796SEtienne Carriere IMSG("RCC is non-secure"); 12526b651796SEtienne Carriere io_clrbits32(stm32_rcc_base() + RCC_TZCR, RCC_TZCR_TZEN); 12536b651796SEtienne Carriere } 12546b651796SEtienne Carriere 12556b651796SEtienne Carriere static TEE_Result stm32mp1_clk_fdt_init(const void *fdt, int node) 12566b651796SEtienne Carriere { 12576b651796SEtienne Carriere unsigned int i = 0; 12586b651796SEtienne Carriere int len = 0; 12596b651796SEtienne Carriere int ignored = 0; 12606b651796SEtienne Carriere 12616b651796SEtienne Carriere get_osc_freq_from_dt(fdt); 12626b651796SEtienne Carriere 12636b651796SEtienne Carriere /* 12646b651796SEtienne Carriere * OP-TEE core is not in charge of configuring clock parenthood. 12656b651796SEtienne Carriere * This is expected from an earlier boot stage. Modifying the clock 12666b651796SEtienne Carriere * tree parenthood here may jeopardize already configured clocks. 12676b651796SEtienne Carriere * The sequence below ignores such DT directives with a friendly 12686b651796SEtienne Carriere * debug trace. 12696b651796SEtienne Carriere */ 12706b651796SEtienne Carriere if (fdt_getprop(fdt, node, "st,clksrc", &len)) { 12716b651796SEtienne Carriere DMSG("Ignore source clocks configuration from DT"); 12726b651796SEtienne Carriere ignored++; 12736b651796SEtienne Carriere } 12746b651796SEtienne Carriere if (fdt_getprop(fdt, node, "st,clkdiv", &len)) { 12756b651796SEtienne Carriere DMSG("Ignore clock divisors configuration from DT"); 12766b651796SEtienne Carriere ignored++; 12776b651796SEtienne Carriere } 12786b651796SEtienne Carriere if (fdt_getprop(fdt, node, "st,pkcs", &len)) { 12796b651796SEtienne Carriere DMSG("Ignore peripheral clocks tree configuration from DT"); 12806b651796SEtienne Carriere ignored++; 12816b651796SEtienne Carriere } 12826b651796SEtienne Carriere for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { 12836b651796SEtienne Carriere char name[] = "st,pll@X"; 12846b651796SEtienne Carriere 12856b651796SEtienne Carriere snprintf(name, sizeof(name), "st,pll@%d", i); 12866b651796SEtienne Carriere node = fdt_subnode_offset(fdt, node, name); 12876b651796SEtienne Carriere if (node < 0) 12886b651796SEtienne Carriere continue; 12896b651796SEtienne Carriere 12906b651796SEtienne Carriere if (fdt_getprop(fdt, node, "cfg", &len) || 12916b651796SEtienne Carriere fdt_getprop(fdt, node, "frac", &len)) { 12926b651796SEtienne Carriere DMSG("Ignore PLL%u configurations from DT", i); 12936b651796SEtienne Carriere ignored++; 12946b651796SEtienne Carriere } 12956b651796SEtienne Carriere } 12966b651796SEtienne Carriere 12976b651796SEtienne Carriere if (ignored != 0) 12986b651796SEtienne Carriere IMSG("DT clock tree configurations were ignored"); 12996b651796SEtienne Carriere 13006b651796SEtienne Carriere return TEE_SUCCESS; 13016b651796SEtienne Carriere } 13026b651796SEtienne Carriere 13036b651796SEtienne Carriere /* 13046b651796SEtienne Carriere * Conversion between clk references and clock gates and clock on internals 13056b651796SEtienne Carriere * 13066b651796SEtienne Carriere * stm32mp1_clk first cells follow stm32mp1_clk_gate[] ordering. 13076b651796SEtienne Carriere * stm32mp1_clk last cells follow stm32mp1_clk_on[] ordering. 13086b651796SEtienne Carriere */ 13096b651796SEtienne Carriere static struct clk stm32mp1_clk[ARRAY_SIZE(stm32mp1_clk_gate) + 13106b651796SEtienne Carriere ARRAY_SIZE(stm32mp1_clk_on)]; 13116b651796SEtienne Carriere 13126b651796SEtienne Carriere #define CLK_ON_INDEX_OFFSET ((int)ARRAY_SIZE(stm32mp1_clk_gate)) 13136b651796SEtienne Carriere 13146b651796SEtienne Carriere static bool clk_is_gate(struct clk *clk) 13156b651796SEtienne Carriere { 13166b651796SEtienne Carriere int clk_index = clk - stm32mp1_clk; 13176b651796SEtienne Carriere 13186b651796SEtienne Carriere assert(clk_index >= 0 && clk_index < (int)ARRAY_SIZE(stm32mp1_clk)); 13196b651796SEtienne Carriere return clk_index < CLK_ON_INDEX_OFFSET; 13206b651796SEtienne Carriere } 13216b651796SEtienne Carriere 13226b651796SEtienne Carriere static unsigned long clk_to_clock_id(struct clk *clk) 13236b651796SEtienne Carriere { 13246b651796SEtienne Carriere int gate_index = clk - stm32mp1_clk; 13256b651796SEtienne Carriere int on_index = gate_index - CLK_ON_INDEX_OFFSET; 13266b651796SEtienne Carriere 13276b651796SEtienne Carriere if (clk_is_gate(clk)) 13286b651796SEtienne Carriere return stm32mp1_clk_gate[gate_index].clock_id; 13296b651796SEtienne Carriere 13306b651796SEtienne Carriere return stm32mp1_clk_on[on_index]; 13316b651796SEtienne Carriere } 13326b651796SEtienne Carriere 13336b651796SEtienne Carriere static const struct stm32mp1_clk_gate *clk_to_gate_ref(struct clk *clk) 13346b651796SEtienne Carriere { 13356b651796SEtienne Carriere int gate_index = clk - stm32mp1_clk; 13366b651796SEtienne Carriere 13376b651796SEtienne Carriere assert(clk_is_gate(clk)); 13386b651796SEtienne Carriere 13396b651796SEtienne Carriere return stm32mp1_clk_gate + gate_index; 13406b651796SEtienne Carriere } 13416b651796SEtienne Carriere 13426b651796SEtienne Carriere static int clock_id_to_gate_index(unsigned long clock_id) 13436b651796SEtienne Carriere { 13446b651796SEtienne Carriere size_t n = 0; 13456b651796SEtienne Carriere 13466b651796SEtienne Carriere for (n = 0; n < ARRAY_SIZE(stm32mp1_clk_gate); n++) 13476b651796SEtienne Carriere if (stm32mp1_clk_gate[n].clock_id == clock_id) 13486b651796SEtienne Carriere return n; 13496b651796SEtienne Carriere 13506b651796SEtienne Carriere return -1; 13516b651796SEtienne Carriere } 13526b651796SEtienne Carriere 13536b651796SEtienne Carriere static int clock_id_to_always_on_index(unsigned long clock_id) 13546b651796SEtienne Carriere { 13556b651796SEtienne Carriere size_t n = 0; 13566b651796SEtienne Carriere 13576b651796SEtienne Carriere for (n = 0; n < ARRAY_SIZE(stm32mp1_clk_on); n++) 13586b651796SEtienne Carriere if (stm32mp1_clk_on[n] == clock_id) 13596b651796SEtienne Carriere return n; 13606b651796SEtienne Carriere 13616b651796SEtienne Carriere return -1; 13626b651796SEtienne Carriere } 13636b651796SEtienne Carriere 13646b651796SEtienne Carriere static struct clk *clock_id_to_clk(unsigned long clock_id) 13656b651796SEtienne Carriere { 13666b651796SEtienne Carriere int gate_index = clock_id_to_gate_index(clock_id); 13676b651796SEtienne Carriere int on_index = clock_id_to_always_on_index(clock_id); 13686b651796SEtienne Carriere 13696b651796SEtienne Carriere if (gate_index >= 0) 13706b651796SEtienne Carriere return stm32mp1_clk + gate_index; 13716b651796SEtienne Carriere 13726b651796SEtienne Carriere if (on_index >= 0) 13736b651796SEtienne Carriere return stm32mp1_clk + CLK_ON_INDEX_OFFSET + on_index; 13746b651796SEtienne Carriere 13756b651796SEtienne Carriere return NULL; 13766b651796SEtienne Carriere } 13776b651796SEtienne Carriere 1378d4535b58SEtienne Carriere struct clk *stm32mp_rcc_clock_id_to_clk(unsigned long clock_id) 1379d4535b58SEtienne Carriere { 1380d4535b58SEtienne Carriere return clock_id_to_clk(clock_id); 1381d4535b58SEtienne Carriere } 1382d4535b58SEtienne Carriere 13831a3d47c5SEtienne Carriere #if (CFG_TEE_CORE_LOG_LEVEL >= TRACE_DEBUG) && defined(CFG_TEE_CORE_DEBUG) 13846b651796SEtienne Carriere struct clk_name { 13856b651796SEtienne Carriere unsigned int clock_id; 13866b651796SEtienne Carriere const char *name; 13876b651796SEtienne Carriere }; 13886b651796SEtienne Carriere 13896b651796SEtienne Carriere #define CLOCK_NAME(_binding, _name) \ 13906b651796SEtienne Carriere { .clock_id = (_binding), .name = (_name) } 13916b651796SEtienne Carriere 13926b651796SEtienne Carriere /* Store names only for some clocks */ 13936b651796SEtienne Carriere const struct clk_name exposed_clk_name[] = { 13946b651796SEtienne Carriere /* Clocks used by platform drivers not yet probed from DT */ 13956b651796SEtienne Carriere CLOCK_NAME(CK_DBG, "dbg"), 13966b651796SEtienne Carriere CLOCK_NAME(CK_MCU, "mcu"), 13976b651796SEtienne Carriere CLOCK_NAME(RTCAPB, "rtcapb"), 13986b651796SEtienne Carriere CLOCK_NAME(BKPSRAM, "bkpsram"), 13996b651796SEtienne Carriere CLOCK_NAME(RTC, "rtc"), 14006b651796SEtienne Carriere CLOCK_NAME(CRYP1, "crpy1"), 14016b651796SEtienne Carriere CLOCK_NAME(SYSCFG, "syscfg"), 14026b651796SEtienne Carriere CLOCK_NAME(GPIOA, "gpioa"), 14036b651796SEtienne Carriere CLOCK_NAME(GPIOB, "gpiob"), 14046b651796SEtienne Carriere CLOCK_NAME(GPIOC, "gpioc"), 14056b651796SEtienne Carriere CLOCK_NAME(GPIOD, "gpiod"), 14066b651796SEtienne Carriere CLOCK_NAME(GPIOE, "gpioe"), 14076b651796SEtienne Carriere CLOCK_NAME(GPIOF, "gpiof"), 14086b651796SEtienne Carriere CLOCK_NAME(GPIOG, "gpiog"), 14096b651796SEtienne Carriere CLOCK_NAME(GPIOH, "gpioh"), 14106b651796SEtienne Carriere CLOCK_NAME(GPIOI, "gpioi"), 14116b651796SEtienne Carriere CLOCK_NAME(GPIOJ, "gpioj"), 14126b651796SEtienne Carriere CLOCK_NAME(GPIOK, "gpiok"), 14136b651796SEtienne Carriere CLOCK_NAME(GPIOZ, "gpioz"), 14146b651796SEtienne Carriere /* Clock exposed by SCMI. SCMI clock fmro DT bindings to come... */ 14156b651796SEtienne Carriere CLOCK_NAME(CK_HSE, "hse"), 14166b651796SEtienne Carriere CLOCK_NAME(CK_HSI, "hsi"), 14176b651796SEtienne Carriere CLOCK_NAME(CK_CSI, "csi"), 14186b651796SEtienne Carriere CLOCK_NAME(CK_LSE, "lse"), 14196b651796SEtienne Carriere CLOCK_NAME(CK_LSI, "lsi"), 14206b651796SEtienne Carriere CLOCK_NAME(PLL2_Q, "pll2q"), 14216b651796SEtienne Carriere CLOCK_NAME(PLL2_R, "pll2r"), 14226b651796SEtienne Carriere CLOCK_NAME(PLL3_Q, "pll3q"), 14236b651796SEtienne Carriere CLOCK_NAME(PLL3_R, "pll3r"), 14246b651796SEtienne Carriere CLOCK_NAME(CRYP1, "cryp1"), 14256b651796SEtienne Carriere CLOCK_NAME(HASH1, "hash1"), 14266b651796SEtienne Carriere CLOCK_NAME(I2C4_K, "i2c4"), 14276b651796SEtienne Carriere CLOCK_NAME(I2C6_K, "i2c6"), 14286b651796SEtienne Carriere CLOCK_NAME(IWDG1, "iwdg"), 14296b651796SEtienne Carriere CLOCK_NAME(RNG1_K, "rng1"), 14306b651796SEtienne Carriere CLOCK_NAME(SPI6_K, "spi6"), 14316b651796SEtienne Carriere CLOCK_NAME(USART1_K, "usart1"), 14326b651796SEtienne Carriere CLOCK_NAME(CK_MCU, "mcu"), 14336b651796SEtienne Carriere }; 14346b651796SEtienne Carriere DECLARE_KEEP_PAGER(exposed_clk_name); 14356b651796SEtienne Carriere 14366b651796SEtienne Carriere static const char *clk_op_get_name(struct clk *clk) 14376b651796SEtienne Carriere { 14386b651796SEtienne Carriere unsigned long clock_id = clk_to_clock_id(clk); 14396b651796SEtienne Carriere size_t n = 0; 14406b651796SEtienne Carriere 14416b651796SEtienne Carriere for (n = 0; n < ARRAY_SIZE(exposed_clk_name); n++) 14426b651796SEtienne Carriere if (exposed_clk_name[n].clock_id == clock_id) 14436b651796SEtienne Carriere return exposed_clk_name[n].name; 14446b651796SEtienne Carriere 14456b651796SEtienne Carriere return NULL; 14466b651796SEtienne Carriere } 14476b651796SEtienne Carriere #else 14486b651796SEtienne Carriere static const char *clk_op_get_name(struct clk *clk __unused) 14496b651796SEtienne Carriere { 14506b651796SEtienne Carriere return NULL; 14516b651796SEtienne Carriere } 14526b651796SEtienne Carriere #endif /*CFG_TEE_CORE_LOG_LEVEL*/ 14536b651796SEtienne Carriere 14546b651796SEtienne Carriere static unsigned long clk_op_compute_rate(struct clk *clk, 14556b651796SEtienne Carriere unsigned long parent_rate __unused) 14566b651796SEtienne Carriere { 14576b651796SEtienne Carriere return _stm32_clock_get_rate(clk_to_clock_id(clk)); 14586b651796SEtienne Carriere } 14596b651796SEtienne Carriere 14606b651796SEtienne Carriere static TEE_Result clk_op_enable(struct clk *clk) 14616b651796SEtienne Carriere { 14626b651796SEtienne Carriere if (clk_is_gate(clk)) 14636b651796SEtienne Carriere __clk_enable(clk_to_gate_ref(clk)); 14646b651796SEtienne Carriere 14656b651796SEtienne Carriere return TEE_SUCCESS; 14666b651796SEtienne Carriere } 14676b651796SEtienne Carriere DECLARE_KEEP_PAGER(clk_op_enable); 14686b651796SEtienne Carriere 14696b651796SEtienne Carriere static void clk_op_disable(struct clk *clk) 14706b651796SEtienne Carriere { 14716b651796SEtienne Carriere if (clk_is_gate(clk)) 14726b651796SEtienne Carriere __clk_disable(clk_to_gate_ref(clk)); 14736b651796SEtienne Carriere } 14746b651796SEtienne Carriere DECLARE_KEEP_PAGER(clk_op_disable); 14756b651796SEtienne Carriere 14766b651796SEtienne Carriere /* This variable is weak to break its dependency chain when linked as unpaged */ 14776b651796SEtienne Carriere const struct clk_ops stm32mp1_clk_ops 147839e8c200SJerome Forissier __weak __relrodata_unpaged("stm32mp1_clk_ops") = { 14796b651796SEtienne Carriere .enable = clk_op_enable, 14806b651796SEtienne Carriere .disable = clk_op_disable, 14816b651796SEtienne Carriere .get_rate = clk_op_compute_rate, 14826b651796SEtienne Carriere }; 14836b651796SEtienne Carriere 14846b651796SEtienne Carriere static TEE_Result register_stm32mp1_clocks(void) 14856b651796SEtienne Carriere { 14866b651796SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 14876b651796SEtienne Carriere size_t n = 0; 14886b651796SEtienne Carriere 14896b651796SEtienne Carriere for (n = 0; n < ARRAY_SIZE(stm32mp1_clk); n++) { 14906b651796SEtienne Carriere stm32mp1_clk[n].ops = &stm32mp1_clk_ops; 14916b651796SEtienne Carriere stm32mp1_clk[n].name = clk_op_get_name(stm32mp1_clk + n); 14926b651796SEtienne Carriere refcount_set(&stm32mp1_clk[n].enabled_count, 0); 14936b651796SEtienne Carriere 14946b651796SEtienne Carriere res = clk_register(stm32mp1_clk + n); 14956b651796SEtienne Carriere if (res) 14966b651796SEtienne Carriere return res; 14976b651796SEtienne Carriere } 14986b651796SEtienne Carriere 14996b651796SEtienne Carriere return TEE_SUCCESS; 15006b651796SEtienne Carriere } 15016b651796SEtienne Carriere 1502*b357d34fSEtienne Carriere static TEE_Result stm32mp1_clk_dt_get_clk(struct dt_pargs *pargs, 1503*b357d34fSEtienne Carriere void *data __unused, 1504*b357d34fSEtienne Carriere struct clk **out_clk) 15056b651796SEtienne Carriere { 15066b651796SEtienne Carriere unsigned long clock_id = pargs->args[0]; 15076b651796SEtienne Carriere struct clk *clk = NULL; 15086b651796SEtienne Carriere 15096b651796SEtienne Carriere if (pargs->args_count != 1) 1510*b357d34fSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 15116b651796SEtienne Carriere 15126b651796SEtienne Carriere clk = clock_id_to_clk(clock_id); 15136b651796SEtienne Carriere if (!clk) 1514*b357d34fSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 15156b651796SEtienne Carriere 1516*b357d34fSEtienne Carriere *out_clk = clk; 1517*b357d34fSEtienne Carriere 1518*b357d34fSEtienne Carriere return TEE_SUCCESS; 15196b651796SEtienne Carriere } 15206b651796SEtienne Carriere 15216b651796SEtienne Carriere /* Non-null reference for compat data */ 15226b651796SEtienne Carriere static const uint8_t non_secure_rcc; 15236b651796SEtienne Carriere 15246b651796SEtienne Carriere static TEE_Result stm32mp1_clock_provider_probe(const void *fdt, int offs, 15256b651796SEtienne Carriere const void *compat_data) 15266b651796SEtienne Carriere { 15276b651796SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 15286b651796SEtienne Carriere 15296b651796SEtienne Carriere if (compat_data == &non_secure_rcc) 15306b651796SEtienne Carriere disable_rcc_tzen(); 15316b651796SEtienne Carriere else 15326b651796SEtienne Carriere enable_rcc_tzen(); 15336b651796SEtienne Carriere 15346b651796SEtienne Carriere res = stm32mp1_clk_fdt_init(fdt, offs); 15356b651796SEtienne Carriere if (res) { 15366b651796SEtienne Carriere EMSG("Failed to initialize clocks from DT: %#"PRIx32, res); 15376b651796SEtienne Carriere panic(); 15386b651796SEtienne Carriere } 15396b651796SEtienne Carriere 15406b651796SEtienne Carriere res = register_stm32mp1_clocks(); 15416b651796SEtienne Carriere if (res) { 15426b651796SEtienne Carriere EMSG("Failed to register clocks: %#"PRIx32, res); 15436b651796SEtienne Carriere panic(); 15446b651796SEtienne Carriere } 15456b651796SEtienne Carriere 15466b651796SEtienne Carriere res = clk_dt_register_clk_provider(fdt, offs, stm32mp1_clk_dt_get_clk, 15476b651796SEtienne Carriere NULL); 15486b651796SEtienne Carriere if (res) { 15496b651796SEtienne Carriere EMSG("Failed to register clock provider: %#"PRIx32, res); 15506b651796SEtienne Carriere panic(); 15516b651796SEtienne Carriere } 15526b651796SEtienne Carriere 15536b651796SEtienne Carriere enable_static_secure_clocks(); 15546b651796SEtienne Carriere 15556b651796SEtienne Carriere return TEE_SUCCESS; 15566b651796SEtienne Carriere } 15576b651796SEtienne Carriere 15586b651796SEtienne Carriere static const struct dt_device_match stm32mp1_clock_match_table[] = { 15596b651796SEtienne Carriere { .compatible = "st,stm32mp1-rcc", .compat_data = &non_secure_rcc, }, 15606b651796SEtienne Carriere { .compatible = "st,stm32mp1-rcc-secure", }, 15616b651796SEtienne Carriere { } 15626b651796SEtienne Carriere }; 15636b651796SEtienne Carriere 15646b651796SEtienne Carriere DEFINE_DT_DRIVER(stm32mp1_clock_dt_driver) = { 15656b651796SEtienne Carriere .name = "stm32mp1_clock", 15666b651796SEtienne Carriere .type = DT_DRIVER_CLK, 15676b651796SEtienne Carriere .match_table = stm32mp1_clock_match_table, 15686b651796SEtienne Carriere .probe = stm32mp1_clock_provider_probe, 15696b651796SEtienne Carriere }; 1570