diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c index e4cc9b9e8..c9bb9ff2b 100644 --- a/drivers/st/clk/stm32mp1_clk.c +++ b/drivers/st/clk/stm32mp1_clk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -18,25 +18,27 @@ #include #include #include +#include #include #include #include -#include #include #include +#include #include #include -#define MAX_HSI_HZ 64000000 +#define MAX_HSI_HZ 64000000 +#define USB_PHY_48_MHZ 48000000 -#define TIMEOUT_200MS (plat_get_syscnt_freq2() / 5U) -#define TIMEOUT_1S plat_get_syscnt_freq2() +#define TIMEOUT_US_200MS U(200000) +#define TIMEOUT_US_1S U(1000000) -#define PLLRDY_TIMEOUT TIMEOUT_200MS -#define CLKSRC_TIMEOUT TIMEOUT_200MS -#define CLKDIV_TIMEOUT TIMEOUT_200MS -#define HSIDIV_TIMEOUT TIMEOUT_200MS -#define OSCRDY_TIMEOUT TIMEOUT_1S +#define PLLRDY_TIMEOUT TIMEOUT_US_200MS +#define CLKSRC_TIMEOUT TIMEOUT_US_200MS +#define CLKDIV_TIMEOUT TIMEOUT_US_200MS +#define HSIDIV_TIMEOUT TIMEOUT_US_200MS +#define OSCRDY_TIMEOUT TIMEOUT_US_1S enum stm32mp1_parent_id { /* Oscillators are defined in enum stm32mp_osc_id */ @@ -68,12 +70,20 @@ enum stm32mp1_parent_id { _HCLK2, _CK_PER, _CK_MPU, + _USB_PHY_48, _PARENT_NB, _UNKNOWN_ID = 0xff, }; +/* Lists only the parent clock we are interested in */ enum stm32mp1_parent_sel { + _I2C12_SEL, + _I2C35_SEL, + _STGEN_SEL, _I2C46_SEL, + _SPI6_SEL, + _USART1_SEL, + _RNG1_SEL, _UART6_SEL, _UART24_SEL, _UART35_SEL, @@ -82,9 +92,9 @@ enum stm32mp1_parent_sel { _SDMMC3_SEL, _QSPI_SEL, _FMC_SEL, + _ASS_SEL, _USBPHY_SEL, _USBO_SEL, - _STGEN_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -164,9 +174,8 @@ struct stm32mp1_clk_gate { uint8_t bit; uint8_t index; uint8_t set_clr; - enum stm32mp1_parent_sel sel; - enum stm32mp1_parent_id fixed; - bool secure; + uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ + uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ }; struct stm32mp1_clk_sel { @@ -189,21 +198,8 @@ struct stm32mp1_clk_pll { enum stm32mp_osc_id refclk[REFCLK_SIZE]; }; -struct stm32mp1_clk_data { - const struct stm32mp1_clk_gate *gate; - const struct stm32mp1_clk_sel *sel; - const struct stm32mp1_clk_pll *pll; - const int nb_gate; -}; - -struct stm32mp1_clk_priv { - uint32_t base; - const struct stm32mp1_clk_data *data; - unsigned long osc[NB_OSC]; - uint32_t pkcs_usb_value; -}; - -#define STM32MP1_CLK(off, b, idx, s) \ +/* Clocks with selectable source and non set/clr register access */ +#define _CLK_SELEC(off, b, idx, s) \ { \ .offset = (off), \ .bit = (b), \ @@ -211,10 +207,10 @@ struct stm32mp1_clk_priv { .set_clr = 0, \ .sel = (s), \ .fixed = _UNKNOWN_ID, \ - .secure = 0, \ } -#define STM32MP1_CLK_F(off, b, idx, f) \ +/* Clocks with fixed source and non set/clr register access */ +#define _CLK_FIXED(off, b, idx, f) \ { \ .offset = (off), \ .bit = (b), \ @@ -222,10 +218,10 @@ struct stm32mp1_clk_priv { .set_clr = 0, \ .sel = _UNKNOWN_SEL, \ .fixed = (f), \ - .secure = 0, \ } -#define STM32MP1_CLK_SET_CLR(off, b, idx, s) \ +/* Clocks with selectable source and set/clr register access */ +#define _CLK_SC_SELEC(off, b, idx, s) \ { \ .offset = (off), \ .bit = (b), \ @@ -233,10 +229,10 @@ struct stm32mp1_clk_priv { .set_clr = 1, \ .sel = (s), \ .fixed = _UNKNOWN_ID, \ - .secure = 0, \ } -#define STM32MP1_CLK_SET_CLR_F(off, b, idx, f) \ +/* Clocks with fixed source and set/clr register access */ +#define _CLK_SC_FIXED(off, b, idx, f) \ { \ .offset = (off), \ .bit = (b), \ @@ -244,32 +240,20 @@ struct stm32mp1_clk_priv { .set_clr = 1, \ .sel = _UNKNOWN_SEL, \ .fixed = (f), \ - .secure = 0, \ } -#define STM32MP1_CLK_SEC_SET_CLR(off, b, idx, s) \ - { \ - .offset = (off), \ - .bit = (b), \ - .index = (idx), \ - .set_clr = 1, \ - .sel = (s), \ - .fixed = _UNKNOWN_ID, \ - .secure = 1, \ - } - -#define STM32MP1_CLK_PARENT(idx, off, s, m, p) \ +#define _CLK_PARENT(idx, off, s, m, p) \ [(idx)] = { \ .offset = (off), \ .src = (s), \ .msk = (m), \ .parent = (p), \ - .nb_parent = ARRAY_SIZE((p)) \ + .nb_parent = ARRAY_SIZE(p) \ } -#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3, \ - off4, off5, off6, \ - p1, p2, p3, p4) \ +#define _CLK_PLL(idx, type, off1, off2, off3, \ + off4, off5, off6, \ + p1, p2, p3, p4) \ [(idx)] = { \ .plltype = (type), \ .rckxselr = (off1), \ @@ -285,113 +269,176 @@ struct stm32mp1_clk_priv { } static const uint8_t stm32mp1_clks[][2] = { - {CK_PER, _CK_PER}, - {CK_MPU, _CK_MPU}, - {CK_AXI, _ACLK}, - {CK_HSE, _HSE}, - {CK_CSI, _CSI}, - {CK_LSI, _LSI}, - {CK_LSE, _LSE}, - {CK_HSI, _HSI}, - {CK_HSE_DIV2, _HSE_KER_DIV2}, + { CK_PER, _CK_PER }, + { CK_MPU, _CK_MPU }, + { CK_AXI, _ACLK }, + { CK_HSE, _HSE }, + { CK_CSI, _CSI }, + { CK_LSI, _LSI }, + { CK_LSE, _LSE }, + { CK_HSI, _HSI }, + { CK_HSE_DIV2, _HSE_KER_DIV2 }, }; +#define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) + static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { - STM32MP1_CLK(RCC_DDRITFCR, 0, DDRC1, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 1, DDRC1LP, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 2, DDRC2, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 3, DDRC2LP, _UNKNOWN_SEL), - STM32MP1_CLK_F(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), - STM32MP1_CLK(RCC_DDRITFCR, 5, DDRPHYCLP, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 6, DDRCAPB, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 7, DDRCAPBLP, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 8, AXIDCG, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL), + _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK), + _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK), + _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK), + _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK), + _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), + _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), + _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), + _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), + _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK), + _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), + _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), - STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), + _CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), + _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), + _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), + _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), + _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 11, TZC1, _UNKNOWN_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 12, TZC2, _UNKNOWN_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), + _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), + _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), + _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), + _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _USART1_SEL), + _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), + _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), + _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), + _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), + _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), + _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), + _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), + _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), + _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 5, HASH1, _UNKNOWN_SEL), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 6, RNG1_K, _CSI_KER), - STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _UNKNOWN_SEL), + _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), + _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), + _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), + _CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), + _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), + _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), + _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), + _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), + _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), + _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), - STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), + _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), }; -static const uint8_t i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER}; -static const uint8_t uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, - _HSE_KER}; -static const uint8_t uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, - _HSE_KER}; -static const uint8_t uart35_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, - _HSE_KER}; -static const uint8_t uart78_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, - _HSE_KER}; -static const uint8_t sdmmc12_parents[] = {_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER}; -static const uint8_t sdmmc3_parents[] = {_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER}; -static const uint8_t qspi_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER}; -static const uint8_t fmc_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER}; -static const uint8_t usbphy_parents[] = {_HSE_KER, _PLL4_R, _HSE_KER_DIV2}; -static const uint8_t usbo_parents[] = {_PLL4_R, _USB_PHY_48}; -static const uint8_t stgen_parents[] = {_HSI_KER, _HSE_KER}; +static const uint8_t i2c12_parents[] = { + _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER +}; + +static const uint8_t i2c35_parents[] = { + _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER +}; + +static const uint8_t stgen_parents[] = { + _HSI_KER, _HSE_KER +}; + +static const uint8_t i2c46_parents[] = { + _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER +}; + +static const uint8_t spi6_parents[] = { + _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q +}; + +static const uint8_t usart1_parents[] = { + _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER +}; + +static const uint8_t rng1_parents[] = { + _CSI, _PLL4_R, _LSE, _LSI +}; + +static const uint8_t uart6_parents[] = { + _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER +}; + +static const uint8_t uart234578_parents[] = { + _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER +}; + +static const uint8_t sdmmc12_parents[] = { + _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER +}; + +static const uint8_t sdmmc3_parents[] = { + _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER +}; + +static const uint8_t qspi_parents[] = { + _ACLK, _PLL3_R, _PLL4_P, _CK_PER +}; + +static const uint8_t fmc_parents[] = { + _ACLK, _PLL3_R, _PLL4_P, _CK_PER +}; + +static const uint8_t ass_parents[] = { + _HSI, _HSE, _PLL2 +}; + +static const uint8_t usbphy_parents[] = { + _HSE_KER, _PLL4_R, _HSE_KER_DIV2 +}; + +static const uint8_t usbo_parents[] = { + _PLL4_R, _USB_PHY_48 +}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { - STM32MP1_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents), - STM32MP1_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), - STM32MP1_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, - uart24_parents), - STM32MP1_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, - uart35_parents), - STM32MP1_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, - uart78_parents), - STM32MP1_CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, - sdmmc12_parents), - STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, - sdmmc3_parents), - STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), - STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), - STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), - STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), - STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), + _CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), + _CLK_PARENT(_I2C35_SEL, RCC_I2C35CKSELR, 0, 0x7, i2c35_parents), + _CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), + _CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents), + _CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents), + _CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents), + _CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents), + _CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), + _CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, uart234578_parents), + _CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, uart234578_parents), + _CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, uart234578_parents), + _CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, sdmmc12_parents), + _CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents), + _CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), + _CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), + _CLK_PARENT(_ASS_SEL, RCC_ASSCKSELR, 0, 0x3, ass_parents), + _CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), + _CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), }; /* Define characteristic of PLL according type */ @@ -413,26 +460,26 @@ static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { static const uint8_t pllncfgr2[_DIV_NB] = { [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, - [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT + [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, }; static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { - STM32MP1_CLK_PLL(_PLL1, PLL_1600, - RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, - RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, - _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), - STM32MP1_CLK_PLL(_PLL2, PLL_1600, - RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, - RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, - _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), - STM32MP1_CLK_PLL(_PLL3, PLL_800, - RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, - RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, - _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), - STM32MP1_CLK_PLL(_PLL4, PLL_800, - RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, - RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, - _HSI, _HSE, _CSI, _I2S_CKIN), + _CLK_PLL(_PLL1, PLL_1600, + RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, + RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, + _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), + _CLK_PLL(_PLL2, PLL_1600, + RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, + RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, + _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), + _CLK_PLL(_PLL3, PLL_800, + RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, + RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, + _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), + _CLK_PLL(_PLL4, PLL_800, + RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, + RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, + _HSI, _HSE, _CSI, _I2S_CKIN), }; /* Prescaler table lookups for clock computation */ @@ -449,33 +496,84 @@ static const uint8_t stm32mp1_axi_div[8] = { 1, 2, 3, 4, 4, 4, 4, 4 }; -static const struct stm32mp1_clk_data stm32mp1_data = { - .gate = stm32mp1_clk_gate, - .sel = stm32mp1_clk_sel, - .pll = stm32mp1_clk_pll, - .nb_gate = ARRAY_SIZE(stm32mp1_clk_gate), -}; +/* RCC clock device driver private */ +static unsigned long stm32mp1_osc[NB_OSC]; +static struct spinlock reg_lock; +static unsigned int gate_refcounts[NB_GATES]; +static struct spinlock refcount_lock; -static struct stm32mp1_clk_priv stm32mp1_clk_priv_data; +static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) +{ + return &stm32mp1_clk_gate[idx]; +} -static unsigned long stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, - enum stm32mp_osc_id idx) +static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) +{ + return &stm32mp1_clk_sel[idx]; +} + +static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) +{ + return &stm32mp1_clk_pll[idx]; +} + +static int stm32mp1_lock_available(void) +{ + /* The spinlocks are used only when MMU is enabled */ + return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT); +} + +static void stm32mp1_clk_lock(struct spinlock *lock) +{ + if (stm32mp1_lock_available() == 0U) { + return; + } + + /* Assume interrupts are masked */ + spin_lock(lock); +} + +static void stm32mp1_clk_unlock(struct spinlock *lock) +{ + if (stm32mp1_lock_available() == 0U) { + return; + } + + spin_unlock(lock); +} + +bool stm32mp1_rcc_is_secure(void) +{ + uintptr_t rcc_base = stm32mp_rcc_base(); + + return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0; +} + +void stm32mp1_clk_rcc_regs_lock(void) +{ + stm32mp1_clk_lock(®_lock); +} + +void stm32mp1_clk_rcc_regs_unlock(void) +{ + stm32mp1_clk_unlock(®_lock); +} + +static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) { if (idx >= NB_OSC) { return 0; } - return priv->osc[idx]; + return stm32mp1_osc[idx]; } -static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id) +static int stm32mp1_clk_get_gated_id(unsigned long id) { - const struct stm32mp1_clk_gate *gate = priv->data->gate; - int i; - int nb_clks = priv->data->nb_gate; + unsigned int i; - for (i = 0; i < nb_clks; i++) { - if (gate[i].index == id) { + for (i = 0U; i < NB_GATES; i++) { + if (gate_ref(i)->index == id) { return i; } } @@ -485,77 +583,64 @@ static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id) return -EINVAL; } -static enum stm32mp1_parent_sel -stm32mp1_clk_get_sel(struct stm32mp1_clk_priv *priv, int i) +static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) { - const struct stm32mp1_clk_gate *gate = priv->data->gate; - - return gate[i].sel; + return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); } -static enum stm32mp1_parent_id -stm32mp1_clk_get_fixed_parent(struct stm32mp1_clk_priv *priv, int i) +static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) { - const struct stm32mp1_clk_gate *gate = priv->data->gate; - - return gate[i].fixed; + return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); } -static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv, - unsigned long id) +static int stm32mp1_clk_get_parent(unsigned long id) { - const struct stm32mp1_clk_sel *sel = priv->data->sel; + const struct stm32mp1_clk_sel *sel; uint32_t j, p_sel; int i; enum stm32mp1_parent_id p; enum stm32mp1_parent_sel s; + uintptr_t rcc_base = stm32mp_rcc_base(); - for (j = 0; j < ARRAY_SIZE(stm32mp1_clks); j++) { + for (j = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) { if (stm32mp1_clks[j][0] == id) { return (int)stm32mp1_clks[j][1]; } } - i = stm32mp1_clk_get_id(priv, id); + i = stm32mp1_clk_get_gated_id(id); if (i < 0) { - return i; + panic(); } - p = stm32mp1_clk_get_fixed_parent(priv, i); + p = stm32mp1_clk_get_fixed_parent(i); if (p < _PARENT_NB) { return (int)p; } - s = stm32mp1_clk_get_sel(priv, i); - if (s >= _PARENT_SEL_NB) { + s = stm32mp1_clk_get_sel(i); + if (s == _UNKNOWN_SEL) { return -EINVAL; } - - p_sel = (mmio_read_32(priv->base + sel[s].offset) >> sel[s].src) & - sel[s].msk; - - if (p_sel < sel[s].nb_parent) { - return (int)sel[s].parent[p_sel]; + if (s >= _PARENT_SEL_NB) { + panic(); } - ERROR("%s: no parents defined for clk id %ld\n", __func__, id); + sel = clk_sel_ref(s); + p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & sel->msk; + if (p_sel < sel->nb_parent) { + return (int)sel->parent[p_sel]; + } return -EINVAL; } -static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id) +static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; - uint32_t selr, src; - unsigned long refclk; + uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); + uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; - selr = mmio_read_32(priv->base + pll[pll_id].rckxselr); - src = selr & RCC_SELR_REFCLK_SRC_MASK; - - refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]); - - return refclk; + return stm32mp1_clk_get_fixed(pll->refclk[src]); } /* @@ -564,20 +649,19 @@ static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv, * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) */ -static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id) +static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; unsigned long refclk, fvco; uint32_t cfgr1, fracr, divm, divn; + uintptr_t rcc_base = stm32mp_rcc_base(); - cfgr1 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr1); - fracr = mmio_read_32(priv->base + pll[pll_id].pllxfracr); + cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); + fracr = mmio_read_32(rcc_base + pll->pllxfracr); divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; - refclk = stm32mp1_pll_get_fref_ck(priv, pll_id); + refclk = stm32mp1_pll_get_fref(pll); /* * With FRACV : @@ -586,13 +670,13 @@ static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv, * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) */ if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { - uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) - >> RCC_PLLNFRACR_FRACV_SHIFT; + uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> + RCC_PLLNFRACR_FRACV_SHIFT; unsigned long long numerator, denominator; - numerator = ((unsigned long long)divn + 1U) << 13; - numerator = (refclk * numerator) + fracv; - denominator = ((unsigned long long)divm + 1U) << 13; + numerator = (((unsigned long long)divn + 1U) << 13) + fracv; + numerator = refclk * numerator; + denominator = ((unsigned long long)divm + 1U) << 13; fvco = (unsigned long)(numerator / denominator); } else { fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); @@ -601,11 +685,10 @@ static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv, return fvco; } -static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id, +static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, enum stm32mp1_div_id div_id) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); unsigned long dfout; uint32_t cfgr2, divy; @@ -613,42 +696,42 @@ static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, return 0; } - cfgr2 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr2); + cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; - dfout = stm32mp1_pll_get_fvco(priv, pll_id) / (divy + 1U); + dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); return dfout; } -static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) +static unsigned long get_clock_rate(int p) { uint32_t reg, clkdiv; unsigned long clock = 0; + uintptr_t rcc_base = stm32mp_rcc_base(); switch (p) { case _CK_MPU: /* MPU sub system */ - reg = mmio_read_32(priv->base + RCC_MPCKSELR); + reg = mmio_read_32(rcc_base + RCC_MPCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_MPCKSELR_HSI: - clock = stm32mp1_clk_get_fixed(priv, _HSI); + clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_MPCKSELR_HSE: - clock = stm32mp1_clk_get_fixed(priv, _HSE); + clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_MPCKSELR_PLL: - clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); break; case RCC_MPCKSELR_PLL_MPUDIV: - clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); - reg = mmio_read_32(priv->base + RCC_MPCKDIVR); + reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); clkdiv = reg & RCC_MPUDIV_MASK; if (clkdiv != 0U) { clock /= stm32mp1_mpu_div[clkdiv]; } - break; default: break; @@ -660,32 +743,32 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) case _HCLK6: case _PCLK4: case _PCLK5: - reg = mmio_read_32(priv->base + RCC_ASSCKSELR); + reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_ASSCKSELR_HSI: - clock = stm32mp1_clk_get_fixed(priv, _HSI); + clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_ASSCKSELR_HSE: - clock = stm32mp1_clk_get_fixed(priv, _HSE); + clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_ASSCKSELR_PLL: - clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); break; default: break; } /* System clock divider */ - reg = mmio_read_32(priv->base + RCC_AXIDIVR); + reg = mmio_read_32(rcc_base + RCC_AXIDIVR); clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; switch (p) { case _PCLK4: - reg = mmio_read_32(priv->base + RCC_APB4DIVR); + reg = mmio_read_32(rcc_base + RCC_APB4DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; case _PCLK5: - reg = mmio_read_32(priv->base + RCC_APB5DIVR); + reg = mmio_read_32(rcc_base + RCC_APB5DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; default: @@ -693,16 +776,16 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) } break; case _CK_PER: - reg = mmio_read_32(priv->base + RCC_CPERCKSELR); + reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_CPERCKSELR_HSI: - clock = stm32mp1_clk_get_fixed(priv, _HSI); + clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_CPERCKSELR_HSE: - clock = stm32mp1_clk_get_fixed(priv, _HSE); + clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_CPERCKSELR_CSI: - clock = stm32mp1_clk_get_fixed(priv, _CSI); + clock = stm32mp1_clk_get_fixed(_CSI); break; default: break; @@ -710,65 +793,65 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) break; case _HSI: case _HSI_KER: - clock = stm32mp1_clk_get_fixed(priv, _HSI); + clock = stm32mp1_clk_get_fixed(_HSI); break; case _CSI: case _CSI_KER: - clock = stm32mp1_clk_get_fixed(priv, _CSI); + clock = stm32mp1_clk_get_fixed(_CSI); break; case _HSE: case _HSE_KER: - clock = stm32mp1_clk_get_fixed(priv, _HSE); + clock = stm32mp1_clk_get_fixed(_HSE); break; case _HSE_KER_DIV2: - clock = stm32mp1_clk_get_fixed(priv, _HSE) >> 1; + clock = stm32mp1_clk_get_fixed(_HSE) >> 1; break; case _LSI: - clock = stm32mp1_clk_get_fixed(priv, _LSI); + clock = stm32mp1_clk_get_fixed(_LSI); break; case _LSE: - clock = stm32mp1_clk_get_fixed(priv, _LSE); + clock = stm32mp1_clk_get_fixed(_LSE); break; /* PLL */ case _PLL1_P: - clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); break; case _PLL1_Q: - clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_Q); + clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); break; case _PLL1_R: - clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_R); + clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); break; case _PLL2_P: - clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); break; case _PLL2_Q: - clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_Q); + clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); break; case _PLL2_R: - clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_R); + clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); break; case _PLL3_P: - clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); break; case _PLL3_Q: - clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_Q); + clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); break; case _PLL3_R: - clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_R); + clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); break; case _PLL4_P: - clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_P); + clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); break; case _PLL4_Q: - clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_Q); + clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); break; case _PLL4_R: - clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_R); + clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); break; /* Other */ case _USB_PHY_48: - clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48); + clock = USB_PHY_48_MHZ; break; default: break; @@ -777,113 +860,164 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) return clock; } -bool stm32mp1_clk_is_enabled(unsigned long id) +static void __clk_enable(struct stm32mp1_clk_gate const *gate) { - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; - const struct stm32mp1_clk_gate *gate = priv->data->gate; - int i = stm32mp1_clk_get_id(priv, id); + uintptr_t rcc_base = stm32mp_rcc_base(); - if (i < 0) { - return false; - } - - return ((mmio_read_32(priv->base + gate[i].offset) & - BIT(gate[i].bit)) != 0U); -} - -int stm32mp1_clk_enable(unsigned long id) -{ - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; - const struct stm32mp1_clk_gate *gate = priv->data->gate; - int i = stm32mp1_clk_get_id(priv, id); - - if (i < 0) { - return i; - } - - if (gate[i].set_clr != 0U) { - mmio_write_32(priv->base + gate[i].offset, BIT(gate[i].bit)); + if (gate->set_clr != 0U) { + mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); } else { - mmio_setbits_32(priv->base + gate[i].offset, BIT(gate[i].bit)); + mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); } - return 0; + VERBOSE("Clock %d has been enabled", gate->index); } -int stm32mp1_clk_disable(unsigned long id) +static void __clk_disable(struct stm32mp1_clk_gate const *gate) { - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; - const struct stm32mp1_clk_gate *gate = priv->data->gate; - int i = stm32mp1_clk_get_id(priv, id); + uintptr_t rcc_base = stm32mp_rcc_base(); + + if (gate->set_clr != 0U) { + mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, + BIT(gate->bit)); + } else { + mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit)); + } + + VERBOSE("Clock %d has been disabled", gate->index); +} + +static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) +{ + uintptr_t rcc_base = stm32mp_rcc_base(); + + return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); +} + +unsigned int stm32mp1_clk_get_refcount(unsigned long id) +{ + int i = stm32mp1_clk_get_gated_id(id); if (i < 0) { - return i; + panic(); } - if (gate[i].set_clr != 0U) { - mmio_write_32(priv->base + gate[i].offset - + RCC_MP_ENCLRR_OFFSET, - BIT(gate[i].bit)); - } else { - mmio_clrbits_32(priv->base + gate[i].offset, BIT(gate[i].bit)); - } - - return 0; + return gate_refcounts[i]; } -unsigned long stm32mp1_clk_get_rate(unsigned long id) +void __stm32mp1_clk_enable(unsigned long id, bool secure) { - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; - int p = stm32mp1_clk_get_parent(priv, id); - unsigned long rate; + const struct stm32mp1_clk_gate *gate; + int i = stm32mp1_clk_get_gated_id(id); + unsigned int *refcnt; + + if (i < 0) { + ERROR("Clock %d can't be enabled\n", (uint32_t)id); + panic(); + } + + gate = gate_ref(i); + refcnt = &gate_refcounts[i]; + + stm32mp1_clk_lock(&refcount_lock); + + if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) { + __clk_enable(gate); + } + + stm32mp1_clk_unlock(&refcount_lock); +} + +void __stm32mp1_clk_disable(unsigned long id, bool secure) +{ + const struct stm32mp1_clk_gate *gate; + int i = stm32mp1_clk_get_gated_id(id); + unsigned int *refcnt; + + if (i < 0) { + ERROR("Clock %d can't be disabled\n", (uint32_t)id); + panic(); + } + + gate = gate_ref(i); + refcnt = &gate_refcounts[i]; + + stm32mp1_clk_lock(&refcount_lock); + + if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) { + __clk_disable(gate); + } + + stm32mp1_clk_unlock(&refcount_lock); +} + +void stm32mp_clk_enable(unsigned long id) +{ + __stm32mp1_clk_enable(id, true); +} + +void stm32mp_clk_disable(unsigned long id) +{ + __stm32mp1_clk_disable(id, true); +} + +bool stm32mp_clk_is_enabled(unsigned long id) +{ + int i = stm32mp1_clk_get_gated_id(id); + + if (i < 0) { + panic(); + } + + return __clk_is_enabled(gate_ref(i)); +} + +unsigned long stm32mp_clk_get_rate(unsigned long id) +{ + int p = stm32mp1_clk_get_parent(id); if (p < 0) { return 0; } - rate = stm32mp1_clk_get(priv, p); - - return rate; + return get_clock_rate(p); } -static void stm32mp1_ls_osc_set(int enable, uint32_t rcc, uint32_t offset, - uint32_t mask_on) +static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) { - uint32_t address = rcc + offset; + uintptr_t address = stm32mp_rcc_base() + offset; - if (enable != 0) { + if (enable) { mmio_setbits_32(address, mask_on); } else { mmio_clrbits_32(address, mask_on); } } -static void stm32mp1_hs_ocs_set(int enable, uint32_t rcc, uint32_t mask_on) +static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) { - if (enable != 0) { - mmio_setbits_32(rcc + RCC_OCENSETR, mask_on); - } else { - mmio_setbits_32(rcc + RCC_OCENCLRR, mask_on); - } + uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; + uintptr_t address = stm32mp_rcc_base() + offset; + + mmio_write_32(address, mask_on); } -static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset, - uint32_t mask_rdy) +static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) { - unsigned long start; + uint64_t timeout; uint32_t mask_test; - uint32_t address = rcc + offset; + uintptr_t address = stm32mp_rcc_base() + offset; - if (enable != 0) { + if (enable) { mask_test = mask_rdy; } else { mask_test = 0; } - start = get_timer(0); + timeout = timeout_init_us(OSCRDY_TIMEOUT); while ((mmio_read_32(address) & mask_rdy) != mask_test) { - if (get_timer(start) > OSCRDY_TIMEOUT) { - ERROR("OSC %x @ %x timeout for enable=%d : 0x%x\n", + if (timeout_elapsed(timeout)) { + ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", mask_rdy, address, enable, mmio_read_32(address)); return -ETIMEDOUT; } @@ -892,19 +1026,24 @@ static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset, return 0; } -static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv) +static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) { uint32_t value; + uintptr_t rcc_base = stm32mp_rcc_base(); - if (bypass) { - mmio_setbits_32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP); + if (digbyp) { + mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); + } + + if (bypass || digbyp) { + mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); } /* * Warning: not recommended to switch directly from "high drive" * to "medium low drive", and vice-versa. */ - value = (mmio_read_32(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> + value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> RCC_BDCR_LSEDRV_SHIFT; while (value != lsedrv) { @@ -914,78 +1053,82 @@ static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv) value++; } - mmio_clrsetbits_32(rcc + RCC_BDCR, + mmio_clrsetbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEDRV_MASK, value << RCC_BDCR_LSEDRV_SHIFT); } - stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON); + stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); } -static void stm32mp1_lse_wait(uint32_t rcc) +static void stm32mp1_lse_wait(void) { - if (stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { + if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { VERBOSE("%s: failed\n", __func__); } } -static void stm32mp1_lsi_set(uint32_t rcc, int enable) +static void stm32mp1_lsi_set(bool enable) { - stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION); - if (stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != - 0) { + stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); + + if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) { VERBOSE("%s: failed\n", __func__); } } -static void stm32mp1_hse_enable(uint32_t rcc, bool bypass, bool css) +static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) { - if (bypass) { - mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP); + uintptr_t rcc_base = stm32mp_rcc_base(); + + if (digbyp) { + mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); } - stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON); - if (stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != - 0) { + if (bypass || digbyp) { + mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); + } + + stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); + if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { VERBOSE("%s: failed\n", __func__); } if (css) { - mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON); + mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); } } -static void stm32mp1_csi_set(uint32_t rcc, int enable) +static void stm32mp1_csi_set(bool enable) { - stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION); - if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != - 0) { + stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); + if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) { VERBOSE("%s: failed\n", __func__); } } -static void stm32mp1_hsi_set(uint32_t rcc, int enable) +static void stm32mp1_hsi_set(bool enable) { - stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION); - if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != - 0) { + stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); + if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) { VERBOSE("%s: failed\n", __func__); } } -static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv) +static int stm32mp1_set_hsidiv(uint8_t hsidiv) { - unsigned long start; - uint32_t address = rcc + RCC_OCRDYR; + uint64_t timeout; + uintptr_t rcc_base = stm32mp_rcc_base(); + uintptr_t address = rcc_base + RCC_OCRDYR; - mmio_clrsetbits_32(rcc + RCC_HSICFGR, + mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, RCC_HSICFGR_HSIDIV_MASK, RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); - start = get_timer(0); + timeout = timeout_init_us(HSIDIV_TIMEOUT); while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { - if (get_timer(start) > HSIDIV_TIMEOUT) { - ERROR("HSIDIV failed @ 0x%x: 0x%x\n", + if (timeout_elapsed(timeout)) { + ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", address, mmio_read_32(address)); return -ETIMEDOUT; } @@ -994,7 +1137,7 @@ static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv) return 0; } -static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq) +static int stm32mp1_hsidiv(unsigned long hsifreq) { uint8_t hsidiv; uint32_t hsidivfreq = MAX_HSI_HZ; @@ -1013,32 +1156,102 @@ static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq) } if (hsidiv != 0U) { - return stm32mp1_set_hsidiv(rcc, hsidiv); + return stm32mp1_set_hsidiv(hsidiv); } return 0; } -static void stm32mp1_pll_start(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id) +static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, + unsigned int clksrc, + uint32_t *pllcfg, int plloff) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t rcc_base = stm32mp_rcc_base(); + uintptr_t pllxcr = rcc_base + pll->pllxcr; + enum stm32mp1_plltype type = pll->plltype; + uintptr_t clksrc_address = rcc_base + (clksrc >> 4); + unsigned long refclk; + uint32_t ifrge = 0U; + uint32_t src, value, fracv; - mmio_write_32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_PLLON); + /* Check PLL output */ + if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { + return false; + } + + /* Check current clksrc */ + src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK; + if (src != (clksrc & RCC_SELR_SRC_MASK)) { + return false; + } + + /* Check Div */ + src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; + + refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / + (pllcfg[PLLCFG_M] + 1U); + + if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || + (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { + return false; + } + + if ((type == PLL_800) && (refclk >= 8000000U)) { + ifrge = 1U; + } + + value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & + RCC_PLLNCFGR1_DIVN_MASK; + value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & + RCC_PLLNCFGR1_DIVM_MASK; + value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & + RCC_PLLNCFGR1_IFRGE_MASK; + if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { + return false; + } + + /* Fractional configuration */ + fracv = fdt_read_uint32_default(plloff, "frac", 0); + + value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; + value |= RCC_PLLNFRACR_FRACLE; + if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { + return false; + } + + /* Output config */ + value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & + RCC_PLLNCFGR2_DIVP_MASK; + value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & + RCC_PLLNCFGR2_DIVQ_MASK; + value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & + RCC_PLLNCFGR2_DIVR_MASK; + if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { + return false; + } + + return true; } -static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id, uint32_t output) +static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; - uint32_t pllxcr = priv->base + pll[pll_id].pllxcr; - unsigned long start; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; + + mmio_write_32(pllxcr, RCC_PLLNCR_PLLON); +} + +static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; + uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); - start = get_timer(0); /* Wait PLL lock */ while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { - if (get_timer(start) > PLLRDY_TIMEOUT) { - ERROR("PLL%d start failed @ 0x%x: 0x%x\n", + if (timeout_elapsed(timeout)) { + ERROR("PLL%d start failed @ 0x%lx: 0x%x\n", pll_id, pllxcr, mmio_read_32(pllxcr)); return -ETIMEDOUT; } @@ -1050,12 +1263,11 @@ static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv, return 0; } -static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id) +static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; - uint32_t pllxcr = priv->base + pll[pll_id].pllxcr; - unsigned long start; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; + uint64_t timeout; /* Stop all output */ mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | @@ -1064,11 +1276,11 @@ static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, /* Stop PLL */ mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); - start = get_timer(0); + timeout = timeout_init_us(PLLRDY_TIMEOUT); /* Wait PLL stopped */ while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { - if (get_timer(start) > PLLRDY_TIMEOUT) { - ERROR("PLL%d stop failed @ 0x%x: 0x%x\n", + if (timeout_elapsed(timeout)) { + ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n", pll_id, pllxcr, mmio_read_32(pllxcr)); return -ETIMEDOUT; } @@ -1077,12 +1289,11 @@ static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, return 0; } -static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id, +static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, uint32_t *pllcfg) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; - uint32_t rcc = priv->base; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t rcc_base = stm32mp_rcc_base(); uint32_t value; value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & @@ -1091,24 +1302,23 @@ static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv, RCC_PLLNCFGR2_DIVQ_MASK; value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & RCC_PLLNCFGR2_DIVR_MASK; - mmio_write_32(rcc + pll[pll_id].pllxcfgr2, value); + mmio_write_32(rcc_base + pll->pllxcfgr2, value); } -static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id, +static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, uint32_t *pllcfg, uint32_t fracv) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; - uint32_t rcc = priv->base; - enum stm32mp1_plltype type = pll[pll_id].plltype; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t rcc_base = stm32mp_rcc_base(); + enum stm32mp1_plltype type = pll->plltype; unsigned long refclk; uint32_t ifrge = 0; uint32_t src, value; - src = mmio_read_32(priv->base + pll[pll_id].rckxselr) & + src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK; - refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]) / + refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / (pllcfg[PLLCFG_M] + 1U); if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || @@ -1126,28 +1336,26 @@ static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv, RCC_PLLNCFGR1_DIVM_MASK; value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & RCC_PLLNCFGR1_IFRGE_MASK; - mmio_write_32(rcc + pll[pll_id].pllxcfgr1, value); + mmio_write_32(rcc_base + pll->pllxcfgr1, value); /* Fractional configuration */ value = 0; - mmio_write_32(rcc + pll[pll_id].pllxfracr, value); + mmio_write_32(rcc_base + pll->pllxfracr, value); value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; - mmio_write_32(rcc + pll[pll_id].pllxfracr, value); + mmio_write_32(rcc_base + pll->pllxfracr, value); value |= RCC_PLLNFRACR_FRACLE; - mmio_write_32(rcc + pll[pll_id].pllxfracr, value); + mmio_write_32(rcc_base + pll->pllxfracr, value); - stm32mp1_pll_config_output(priv, pll_id, pllcfg); + stm32mp1_pll_config_output(pll_id, pllcfg); return 0; } -static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv, - enum stm32mp1_pll_id pll_id, - uint32_t *csg) +static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) { - const struct stm32mp1_clk_pll *pll = priv->data->pll; + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); uint32_t pllxcsg = 0; pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & @@ -1159,23 +1367,22 @@ static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv, pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & RCC_PLLNCSGR_SSCG_MODE_MASK; - mmio_write_32(priv->base + pll[pll_id].pllxcsgr, pllxcsg); + mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); } -static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv, - unsigned int clksrc) +static int stm32mp1_set_clksrc(unsigned int clksrc) { - uint32_t address = priv->base + (clksrc >> 4); - unsigned long start; + uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); + uint64_t timeout; - mmio_clrsetbits_32(address, RCC_SELR_SRC_MASK, + mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, clksrc & RCC_SELR_SRC_MASK); - start = get_timer(0); - while ((mmio_read_32(address) & RCC_SELR_SRCRDY) == 0U) { - if (get_timer(start) > CLKSRC_TIMEOUT) { - ERROR("CLKSRC %x start failed @ 0x%x: 0x%x\n", - clksrc, address, mmio_read_32(address)); + timeout = timeout_init_us(CLKSRC_TIMEOUT); + while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { + if (timeout_elapsed(timeout)) { + ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, + clksrc_address, mmio_read_32(clksrc_address)); return -ETIMEDOUT; } } @@ -1183,17 +1390,17 @@ static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv, return 0; } -static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address) +static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) { - unsigned long start; + uint64_t timeout; mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, clkdiv & RCC_DIVR_DIV_MASK); - start = get_timer(0); + timeout = timeout_init_us(CLKDIV_TIMEOUT); while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { - if (get_timer(start) > CLKDIV_TIMEOUT) { - ERROR("CLKDIV %x start failed @ 0x%x: 0x%x\n", + if (timeout_elapsed(timeout)) { + ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", clkdiv, address, mmio_read_32(address)); return -ETIMEDOUT; } @@ -1202,10 +1409,9 @@ static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address) return 0; } -static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv, - uint32_t clksrc, uint32_t clkdiv) +static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) { - uint32_t address = priv->base + (clksrc >> 4); + uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); /* * Binding clksrc : @@ -1214,22 +1420,21 @@ static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv, * bit2-0: MCOSEL[2:0] */ if ((clksrc & 0x8U) != 0U) { - mmio_clrbits_32(address, RCC_MCOCFG_MCOON); + mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); } else { - mmio_clrsetbits_32(address, + mmio_clrsetbits_32(clksrc_address, RCC_MCOCFG_MCOSRC_MASK, clksrc & RCC_MCOCFG_MCOSRC_MASK); - mmio_clrsetbits_32(address, + mmio_clrsetbits_32(clksrc_address, RCC_MCOCFG_MCODIV_MASK, clkdiv << RCC_MCOCFG_MCODIV_SHIFT); - mmio_setbits_32(address, RCC_MCOCFG_MCOON); + mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); } } -static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv, - unsigned int clksrc, bool lse_css) +static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) { - uint32_t address = priv->base + RCC_BDCR; + uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || (clksrc != (uint32_t)CLK_RTC_DISABLED)) { @@ -1248,38 +1453,35 @@ static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv, #define CNTCVL_OFF 0x008 #define CNTCVU_OFF 0x00C -static void stm32mp1_stgen_config(struct stm32mp1_clk_priv *priv) +static void stm32mp1_stgen_config(void) { uintptr_t stgen; - int p; uint32_t cntfid0; unsigned long rate; + unsigned long long counter; stgen = fdt_get_stgen_base(); - cntfid0 = mmio_read_32(stgen + CNTFID_OFF); - p = stm32mp1_clk_get_parent(priv, STGEN_K); - rate = stm32mp1_clk_get(priv, p); + rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); - if (cntfid0 != rate) { - unsigned long long counter; - - mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); - counter = (unsigned long long) - mmio_read_32(stgen + CNTCVL_OFF); - counter |= ((unsigned long long) - (mmio_read_32(stgen + CNTCVU_OFF))) << 32; - counter = (counter * rate / cntfid0); - mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter); - mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32)); - mmio_write_32(stgen + CNTFID_OFF, rate); - mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); - - write_cntfrq((u_register_t)rate); - - /* Need to update timer with new frequency */ - generic_delay_timer_init(); + if (cntfid0 == rate) { + return; } + + mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); + counter = (unsigned long long)mmio_read_32(stgen + CNTCVL_OFF); + counter |= ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF)) << 32; + counter = (counter * rate / cntfid0); + + mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter); + mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32)); + mmio_write_32(stgen + CNTFID_OFF, rate); + mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); + + write_cntfrq((u_register_t)rate); + + /* Need to update timer with new frequency */ + generic_delay_timer_init(); } void stm32mp1_stgen_increment(unsigned long long offset_in_ms) @@ -1300,9 +1502,9 @@ void stm32mp1_stgen_increment(unsigned long long offset_in_ms) mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); } -static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs) +static void stm32mp1_pkcs_config(uint32_t pkcs) { - uint32_t address = priv->base + ((pkcs >> 4) & 0xFFFU); + uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); uint32_t value = pkcs & 0xFU; uint32_t mask = 0xFU; @@ -1316,8 +1518,7 @@ static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs) int stm32mp1_clk_init(void) { - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; - uint32_t rcc = priv->base; + uintptr_t rcc_base = stm32mp_rcc_base(); unsigned int clksrc[CLKSRC_NB]; unsigned int clkdiv[CLKDIV_NB]; unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; @@ -1325,11 +1526,14 @@ int stm32mp1_clk_init(void) int ret, len; enum stm32mp1_pll_id i; bool lse_css = false; + bool pll3_preserve = false; + bool pll4_preserve = false; + bool pll4_bootrom = false; const fdt32_t *pkcs_cell; /* Check status field to disable security */ if (!fdt_get_rcc_secure_status()) { - mmio_write_32(rcc + RCC_TZCR, 0); + mmio_write_32(rcc_base + RCC_TZCR, 0); } ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc, @@ -1361,113 +1565,135 @@ int stm32mp1_clk_init(void) } } - stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); - stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); + stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); + stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); /* * Switch ON oscillator found in device-tree. * Note: HSI already ON after BootROM stage. */ - if (priv->osc[_LSI] != 0U) { - stm32mp1_lsi_set(rcc, 1); + if (stm32mp1_osc[_LSI] != 0U) { + stm32mp1_lsi_set(true); } - if (priv->osc[_LSE] != 0U) { - bool bypass; + if (stm32mp1_osc[_LSE] != 0U) { + bool bypass, digbyp; uint32_t lsedrv; bypass = fdt_osc_read_bool(_LSE, "st,bypass"); + digbyp = fdt_osc_read_bool(_LSE, "st,digbypass"); lse_css = fdt_osc_read_bool(_LSE, "st,css"); lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive", LSEDRV_MEDIUM_HIGH); - stm32mp1_lse_enable(rcc, bypass, lsedrv); + stm32mp1_lse_enable(bypass, digbyp, lsedrv); } - if (priv->osc[_HSE] != 0U) { - bool bypass, css; + if (stm32mp1_osc[_HSE] != 0U) { + bool bypass, digbyp, css; - bypass = fdt_osc_read_bool(_LSE, "st,bypass"); - css = fdt_osc_read_bool(_LSE, "st,css"); - stm32mp1_hse_enable(rcc, bypass, css); + bypass = fdt_osc_read_bool(_HSE, "st,bypass"); + digbyp = fdt_osc_read_bool(_HSE, "st,digbypass"); + css = fdt_osc_read_bool(_HSE, "st,css"); + stm32mp1_hse_enable(bypass, digbyp, css); } /* * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) * => switch on CSI even if node is not present in device tree */ - stm32mp1_csi_set(rcc, 1); + stm32mp1_csi_set(true); /* Come back to HSI */ - ret = stm32mp1_set_clksrc(priv, CLK_MPU_HSI); + ret = stm32mp1_set_clksrc(CLK_MPU_HSI); if (ret != 0) { return ret; } - ret = stm32mp1_set_clksrc(priv, CLK_AXI_HSI); + ret = stm32mp1_set_clksrc(CLK_AXI_HSI); if (ret != 0) { return ret; } + if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & + RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { + pll3_preserve = stm32mp1_check_pll_conf(_PLL3, + clksrc[CLKSRC_PLL3], + pllcfg[_PLL3], + plloff[_PLL3]); + pll4_preserve = stm32mp1_check_pll_conf(_PLL4, + clksrc[CLKSRC_PLL4], + pllcfg[_PLL4], + plloff[_PLL4]); + } + for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { - if (i == _PLL4) + if (((i == _PLL3) && pll3_preserve) || + ((i == _PLL4) && pll4_preserve)) { continue; - ret = stm32mp1_pll_stop(priv, i); + } + + ret = stm32mp1_pll_stop(i); if (ret != 0) { return ret; } } /* Configure HSIDIV */ - if (priv->osc[_HSI] != 0U) { - ret = stm32mp1_hsidiv(rcc, priv->osc[_HSI]); + if (stm32mp1_osc[_HSI] != 0U) { + ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); if (ret != 0) { return ret; } - stm32mp1_stgen_config(priv); + stm32mp1_stgen_config(); } /* Select DIV */ /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ - mmio_write_32(rcc + RCC_MPCKDIVR, + mmio_write_32(rcc_base + RCC_MPCKDIVR, clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); - ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR); + ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); if (ret != 0) { return ret; } - ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR); + ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); if (ret != 0) { return ret; } - ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR); + ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); if (ret != 0) { return ret; } - ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR); + ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); if (ret != 0) { return ret; } - ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR); + ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); if (ret != 0) { return ret; } - ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR); + ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); if (ret != 0) { return ret; } /* No ready bit for RTC */ - mmio_write_32(rcc + RCC_RTCDIVR, + mmio_write_32(rcc_base + RCC_RTCDIVR, clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); /* Configure PLLs source */ - ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL12]); - if (ret != 0) { - return ret; - } - ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL3]); + ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); if (ret != 0) { return ret; } - ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL4]); - if (ret != 0) { - return ret; + if (!pll3_preserve) { + ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); + if (ret != 0) { + return ret; + } + } + + if (!pll4_preserve) { + ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); + if (ret != 0) { + return ret; + } } /* Configure and start PLLs */ @@ -1475,25 +1701,36 @@ int stm32mp1_clk_init(void) uint32_t fracv; uint32_t csg[PLLCSG_NB]; + if (((i == _PLL3) && pll3_preserve) || + ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { + continue; + } + if (!fdt_check_node(plloff[i])) { continue; } + if ((i == _PLL4) && pll4_bootrom) { + /* Set output divider if not done by the Bootrom */ + stm32mp1_pll_config_output(i, pllcfg[i]); + continue; + } + fracv = fdt_read_uint32_default(plloff[i], "frac", 0); - ret = stm32mp1_pll_config(priv, i, pllcfg[i], fracv); + ret = stm32mp1_pll_config(i, pllcfg[i], fracv); if (ret != 0) { return ret; } ret = fdt_read_uint32_array(plloff[i], "csg", csg, (uint32_t)PLLCSG_NB); if (ret == 0) { - stm32mp1_pll_csg(priv, i, csg); + stm32mp1_pll_csg(i, csg); } else if (ret != -FDT_ERR_NOTFOUND) { return ret; } - stm32mp1_pll_start(priv, i); + stm32mp1_pll_start(i); } /* Wait and start PLLs ouptut when ready */ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { @@ -1501,26 +1738,26 @@ int stm32mp1_clk_init(void) continue; } - ret = stm32mp1_pll_output(priv, i, pllcfg[i][PLLCFG_O]); + ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); if (ret != 0) { return ret; } } /* Wait LSE ready before to use it */ - if (priv->osc[_LSE] != 0U) { - stm32mp1_lse_wait(rcc); + if (stm32mp1_osc[_LSE] != 0U) { + stm32mp1_lse_wait(); } /* Configure with expected clock source */ - ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_MPU]); + ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); if (ret != 0) { return ret; } - ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_AXI]); + ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); if (ret != 0) { return ret; } - stm32mp1_set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css); + stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); /* Configure PKCK */ pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); @@ -1528,8 +1765,6 @@ int stm32mp1_clk_init(void) bool ckper_disabled = false; uint32_t j; - priv->pkcs_usb_value = 0; - for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); @@ -1537,7 +1772,7 @@ int stm32mp1_clk_init(void) ckper_disabled = true; continue; } - stm32mp1_pkcs_config(priv, pkcs); + stm32mp1_pkcs_config(pkcs); } /* @@ -1547,18 +1782,18 @@ int stm32mp1_clk_init(void) * => deactivated CKPER only after switching clock */ if (ckper_disabled) { - stm32mp1_pkcs_config(priv, CLK_CKPER_DISABLED); + stm32mp1_pkcs_config(CLK_CKPER_DISABLED); } } /* Switch OFF HSI if not found in device-tree */ - if (priv->osc[_HSI] == 0U) { - stm32mp1_hsi_set(rcc, 0); + if (stm32mp1_osc[_HSI] == 0U) { + stm32mp1_hsi_set(false); } - stm32mp1_stgen_config(priv); + stm32mp1_stgen_config(); /* Software Self-Refresh mode (SSR) during DDR initilialization */ - mmio_clrsetbits_32(priv->base + RCC_DDRITFCR, + mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_DDRCKMOD_MASK, RCC_DDRITFCR_DDRCKMOD_SSR << RCC_DDRITFCR_DDRCKMOD_SHIFT); @@ -1567,47 +1802,26 @@ int stm32mp1_clk_init(void) } static void stm32mp1_osc_clk_init(const char *name, - struct stm32mp1_clk_priv *priv, enum stm32mp_osc_id index) { uint32_t frequency; - priv->osc[index] = 0; - - if (fdt_osc_read_freq(name, &frequency) != 0) { - ERROR("%s frequency request failed\n", name); - panic(); - } else { - priv->osc[index] = frequency; + if (fdt_osc_read_freq(name, &frequency) == 0) { + stm32mp1_osc[index] = frequency; } } static void stm32mp1_osc_init(void) { - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; enum stm32mp_osc_id i; for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { - stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], priv, i); + stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); } } int stm32mp1_clk_probe(void) { - struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; - - priv->base = fdt_rcc_read_addr(); - if (priv->base == 0U) { - return -EINVAL; - } - - priv->data = &stm32mp1_data; - - if ((priv->data->gate == NULL) || (priv->data->sel == NULL) || - (priv->data->pll == NULL)) { - return -EINVAL; - } - stm32mp1_osc_init(); return 0; diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c index 19dfe1b25..1aa05bf55 100644 --- a/drivers/st/clk/stm32mp1_clkfunc.c +++ b/drivers/st/clk/stm32mp1_clkfunc.c @@ -10,17 +10,12 @@ #include +#include +#include #include #include #include -#define DT_RCC_NODE_NAME "rcc@50000000" -#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" -#define DT_RCC_COMPAT "syscon" -#define DT_STGEN_COMPAT "st,stm32-stgen" -#define DT_UART_COMPAT "st,stm32h7-uart" -#define DT_USART_COMPAT "st,stm32h7-usart" - const char *stm32mp_osc_node_label[NB_OSC] = { [_LSI] = "clk-lsi", [_LSE] = "clk-lse", @@ -28,23 +23,14 @@ const char *stm32mp_osc_node_label[NB_OSC] = { [_HSE] = "clk-hse", [_CSI] = "clk-csi", [_I2S_CKIN] = "i2s_ckin", - [_USB_PHY_48] = "ck_usbo_48m" }; -/******************************************************************************* - * This function returns the RCC node in the device tree. - ******************************************************************************/ -static int fdt_get_rcc_node(void *fdt) -{ - return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); -} - -/******************************************************************************* - * This function reads the frequency of an oscillator from its name. - * It reads the value indicated inside the device tree. - * Returns 0 on success, and a negative FDT/ERRNO error code on failure. - * On success, value is stored in the second parameter. - ******************************************************************************/ +/* + * Get the frequency of an oscillator from its name in device tree. + * @param name: oscillator name + * @param freq: stores the frequency of the oscillator + * @return: 0 on success, and a negative FDT/ERRNO error code on failure. + */ int fdt_osc_read_freq(const char *name, uint32_t *freq) { int node, subnode; @@ -88,11 +74,12 @@ int fdt_osc_read_freq(const char *name, uint32_t *freq) return 0; } -/******************************************************************************* - * This function checks the presence of an oscillator property from its id. - * The search is done inside the device tree. - * Returns true/false regarding search result. - ******************************************************************************/ +/* + * Check the presence of an oscillator property from its id. + * @param osc_id: oscillator ID + * @param prop_name: property name + * @return: true/false regarding search result. + */ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) { int node, subnode; @@ -133,11 +120,13 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) return false; } -/******************************************************************************* - * This function reads a value of a oscillator property from its id. - * Returns value on success, and a default value if property not found. - * Default value is passed as parameter. - ******************************************************************************/ +/* + * Get the value of a oscillator property from its ID. + * @param osc_id: oscillator ID + * @param prop_name: property name + * @param dflt_value: default value + * @return oscillator value on success, default value if property not found. + */ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, const char *prop_name, uint32_t dflt_value) { @@ -176,201 +165,3 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, return dflt_value; } - -/******************************************************************************* - * This function reads the rcc base address. - * It reads the value indicated inside the device tree. - * Returns address if success, and 0 value else. - ******************************************************************************/ -uint32_t fdt_rcc_read_addr(void) -{ - int node, subnode; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return 0; - } - - node = fdt_path_offset(fdt, "/soc"); - if (node < 0) { - return 0; - } - - fdt_for_each_subnode(subnode, fdt, node) { - const char *cchar; - int ret; - - cchar = fdt_get_name(fdt, subnode, &ret); - if (cchar == NULL) { - return 0; - } - - if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) { - const fdt32_t *cuint; - - cuint = fdt_getprop(fdt, subnode, "reg", NULL); - if (cuint == NULL) { - return 0; - } - - return fdt32_to_cpu(*cuint); - } - } - - return 0; -} - -/******************************************************************************* - * This function reads a series of parameters in rcc-clk section. - * It reads the values indicated inside the device tree, from property name. - * The number of parameters is also indicated as entry parameter. - * Returns 0 if success, and a negative value else. - * If success, values are stored at the second parameter address. - ******************************************************************************/ -int fdt_rcc_read_uint32_array(const char *prop_name, - uint32_t *array, uint32_t count) -{ - int node; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return -ENOENT; - } - - node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); - if (node < 0) { - return -FDT_ERR_NOTFOUND; - } - - return fdt_read_uint32_array(node, prop_name, array, count); -} - -/******************************************************************************* - * This function gets the subnode offset in rcc-clk section from its name. - * It reads the values indicated inside the device tree. - * Returns offset on success, and a negative FDT/ERRNO error code on failure. - ******************************************************************************/ -int fdt_rcc_subnode_offset(const char *name) -{ - int node, subnode; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return -ENOENT; - } - - node = fdt_get_rcc_node(fdt); - if (node < 0) { - return -FDT_ERR_NOTFOUND; - } - - subnode = fdt_subnode_offset(fdt, node, name); - if (subnode <= 0) { - return -FDT_ERR_NOTFOUND; - } - - return subnode; -} - -/******************************************************************************* - * This function gets the pointer to a rcc-clk property from its name. - * It reads the values indicated inside the device tree. - * Length of the property is stored in the second parameter. - * Returns pointer on success, and NULL value on failure. - ******************************************************************************/ -const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) -{ - const fdt32_t *cuint; - int node, len; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return NULL; - } - - node = fdt_get_rcc_node(fdt); - if (node < 0) { - return NULL; - } - - cuint = fdt_getprop(fdt, node, prop_name, &len); - if (cuint == NULL) { - return NULL; - } - - *lenp = len; - return cuint; -} - -/******************************************************************************* - * This function gets the secure status for rcc node. - * It reads secure-status in device tree. - * Returns true if rcc is available from secure world, false if not. - ******************************************************************************/ -bool fdt_get_rcc_secure_status(void) -{ - int node; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return false; - } - - node = fdt_get_rcc_node(fdt); - if (node < 0) { - return false; - } - - return (fdt_get_status(node) & DT_SECURE) != 0U; -} - -/******************************************************************************* - * This function reads the stgen base address. - * It reads the value indicated inside the device tree. - * Returns address on success, and NULL value on failure. - ******************************************************************************/ -uintptr_t fdt_get_stgen_base(void) -{ - int node; - const fdt32_t *cuint; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return 0; - } - - node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); - if (node < 0) { - return 0; - } - - cuint = fdt_getprop(fdt, node, "reg", NULL); - if (cuint == NULL) { - return 0; - } - - return fdt32_to_cpu(*cuint); -} - -/******************************************************************************* - * This function gets the clock ID of the given node. - * It reads the value indicated inside the device tree. - * Returns ID on success, and a negative FDT/ERRNO error code on failure. - ******************************************************************************/ -int fdt_get_clock_id(int node) -{ - const fdt32_t *cuint; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return -ENOENT; - } - - cuint = fdt_getprop(fdt, node, "clocks", NULL); - if (cuint == NULL) { - return -FDT_ERR_NOTFOUND; - } - - cuint++; - return (int)fdt32_to_cpu(*cuint); -} diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c new file mode 100644 index 000000000..16acef07b --- /dev/null +++ b/drivers/st/clk/stm32mp_clkfunc.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include + +#include +#include + +#define DT_STGEN_COMPAT "st,stm32-stgen" + +/* + * Get the RCC node offset from the device tree + * @param fdt: Device tree reference + * @return: Node offset or a negative value on error + */ +int fdt_get_rcc_node(void *fdt) +{ + return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +} + +/* + * Get the RCC base address from the device tree + * @return: RCC address or 0 on error + */ +uint32_t fdt_rcc_read_addr(void) +{ + int node; + void *fdt; + const fdt32_t *cuint; + + if (fdt_get_address(&fdt) == 0) { + return 0; + } + + node = fdt_get_rcc_node(fdt); + if (node < 0) { + return 0; + } + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint == NULL) { + return 0; + } + + return fdt32_to_cpu(*cuint); +} + +/* + * Read a series of parameters in rcc-clk section in device tree + * @param prop_name: Name of the RCC property to be read + * @param array: the array to store the property parameters + * @param count: number of parameters to be read + * @return: 0 on succes or a negative value on error + */ +int fdt_rcc_read_uint32_array(const char *prop_name, + uint32_t *array, uint32_t count) +{ + int node; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + node = fdt_get_rcc_node(fdt); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } + + return fdt_read_uint32_array(node, prop_name, array, count); +} + +/* + * Get the subnode offset in rcc-clk section from its name in device tree + * @param name: name of the RCC property + * @return: offset on success, and a negative FDT/ERRNO error code on failure. + */ +int fdt_rcc_subnode_offset(const char *name) +{ + int node, subnode; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + node = fdt_get_rcc_node(fdt); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } + + subnode = fdt_subnode_offset(fdt, node, name); + if (subnode <= 0) { + return -FDT_ERR_NOTFOUND; + } + + return subnode; +} + +/* + * Get the pointer to a rcc-clk property from its name. + * @param name: name of the RCC property + * @param lenp: stores the length of the property. + * @return: pointer to the property on success, and NULL value on failure. + */ +const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) +{ + const fdt32_t *cuint; + int node, len; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return NULL; + } + + node = fdt_get_rcc_node(fdt); + if (node < 0) { + return NULL; + } + + cuint = fdt_getprop(fdt, node, prop_name, &len); + if (cuint == NULL) { + return NULL; + } + + *lenp = len; + return cuint; +} + +/* + * Get the secure status for rcc node in device tree. + * @return: true if rcc is available from secure world, false if not. + */ +bool fdt_get_rcc_secure_status(void) +{ + int node; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return false; + } + + node = fdt_get_rcc_node(fdt); + if (node < 0) { + return false; + } + + return !!(fdt_get_status(node) & DT_SECURE); +} + +/* + * Get the stgen base address. + * @return: address of stgen on success, and NULL value on failure. + */ +uintptr_t fdt_get_stgen_base(void) +{ + int node; + const fdt32_t *cuint; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return 0; + } + + node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); + if (node < 0) { + return 0; + } + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint == NULL) { + return 0; + } + + return fdt32_to_cpu(*cuint); +} + +/* + * Get the clock ID of the given node in device tree. + * @param node: node offset + * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure. + */ +int fdt_get_clock_id(int node) +{ + const fdt32_t *cuint; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + cuint = fdt_getprop(fdt, node, "clocks", NULL); + if (cuint == NULL) { + return -FDT_ERR_NOTFOUND; + } + + cuint++; + return (int)fdt32_to_cpu(*cuint); +} diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c index 79aff6e73..caf8eefa8 100644 --- a/drivers/st/ddr/stm32mp1_ddr.c +++ b/drivers/st/ddr/stm32mp1_ddr.c @@ -14,13 +14,10 @@ #include #include #include -#include #include #include #include #include -#include -#include #include #include @@ -32,7 +29,7 @@ struct reg_desc { #define INVALID_OFFSET 0xFFU -#define TIMESLOT_1US (plat_get_syscnt_freq2() / 1000000U) +#define TIMEOUT_US_1S 1000000U #define DDRCTL_REG(x, y) \ { \ @@ -327,49 +324,43 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) { uint32_t pgsr; int error = 0; - unsigned long start; - unsigned long time0, time; - - start = get_timer(0); - time0 = start; + uint64_t timeout = timeout_init_us(TIMEOUT_US_1S); do { pgsr = mmio_read_32((uintptr_t)&phy->pgsr); - time = get_timer(start); - if (time != time0) { - VERBOSE(" > [0x%lx] pgsr = 0x%x &\n", - (uintptr_t)&phy->pgsr, pgsr); - VERBOSE(" [0x%lx] pir = 0x%x (time=%lx)\n", - (uintptr_t)&phy->pir, - mmio_read_32((uintptr_t)&phy->pir), - time); - } - time0 = time; - if (time > plat_get_syscnt_freq2()) { + VERBOSE(" > [0x%lx] pgsr = 0x%x &\n", + (uintptr_t)&phy->pgsr, pgsr); + + if (timeout_elapsed(timeout)) { panic(); } + if ((pgsr & DDRPHYC_PGSR_DTERR) != 0U) { VERBOSE("DQS Gate Trainig Error\n"); error++; } + if ((pgsr & DDRPHYC_PGSR_DTIERR) != 0U) { VERBOSE("DQS Gate Trainig Intermittent Error\n"); error++; } + if ((pgsr & DDRPHYC_PGSR_DFTERR) != 0U) { VERBOSE("DQS Drift Error\n"); error++; } + if ((pgsr & DDRPHYC_PGSR_RVERR) != 0U) { VERBOSE("Read Valid Training Error\n"); error++; } + if ((pgsr & DDRPHYC_PGSR_RVEIRR) != 0U) { VERBOSE("Read Valid Training Intermittent Error\n"); error++; } - } while ((pgsr & DDRPHYC_PGSR_IDONE) == 0U && error == 0); + } while (((pgsr & DDRPHYC_PGSR_IDONE) == 0U) && (error == 0)); VERBOSE("\n[0x%lx] pgsr = 0x%x\n", (uintptr_t)&phy->pgsr, pgsr); } @@ -401,21 +392,19 @@ static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl) /* Wait quasi dynamic register update */ static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl) { - unsigned long start; + uint64_t timeout; uint32_t swstat; mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); VERBOSE("[0x%lx] swctl = 0x%x\n", (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); - start = get_timer(0); + timeout = timeout_init_us(TIMEOUT_US_1S); do { swstat = mmio_read_32((uintptr_t)&ctl->swstat); VERBOSE("[0x%lx] swstat = 0x%x ", (uintptr_t)&ctl->swstat, swstat); - VERBOSE("timer in ms 0x%x = start 0x%lx\r", - get_timer(0), start); - if (get_timer(start) > plat_get_syscnt_freq2()) { + if (timeout_elapsed(timeout)) { panic(); } } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); @@ -427,22 +416,21 @@ static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl) /* Wait quasi dynamic register update */ static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode) { - unsigned long start; + uint64_t timeout; uint32_t stat; - uint32_t operating_mode; - uint32_t selref_type; int break_loop = 0; - start = get_timer(0); + timeout = timeout_init_us(TIMEOUT_US_1S); for ( ; ; ) { + uint32_t operating_mode; + uint32_t selref_type; + stat = mmio_read_32((uintptr_t)&priv->ctl->stat); operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; VERBOSE("[0x%lx] stat = 0x%x\n", (uintptr_t)&priv->ctl->stat, stat); - VERBOSE("timer in ms 0x%x = start 0x%lx\r", - get_timer(0), start); - if (get_timer(start) > plat_get_syscnt_freq2()) { + if (timeout_elapsed(timeout)) { panic(); } @@ -639,7 +627,7 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) */ /* Change Bypass Mode Frequency Range */ - if (stm32mp1_clk_get_rate(DDRPHYC) < 100000000U) { + if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) { mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr, DDRPHYC_DLLGCR_BPS200); } else { @@ -712,7 +700,7 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, static int board_ddr_power_init(enum ddr_type ddr_type) { - if (dt_check_pmic()) { + if (dt_pmic_status() > 0) { return pmic_ddr_power_init(ddr_type); } diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c index a8c1b7769..fcb4cfcfd 100644 --- a/drivers/st/ddr/stm32mp1_ddr_helpers.c +++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,15 +7,18 @@ #include #include -#include #include void ddr_enable_clock(void) { - mmio_setbits_32(RCC_BASE + RCC_DDRITFCR, + stm32mp1_clk_rcc_regs_lock(); + + mmio_setbits_32(stm32mp_rcc_base() + RCC_DDRITFCR, RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN | RCC_DDRITFCR_DDRPHYCEN | RCC_DDRITFCR_DDRPHYCAPBEN | RCC_DDRITFCR_DDRCAPBEN); + + stm32mp1_clk_rcc_regs_unlock(); } diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c index e65fbeaa2..4ae55fcc7 100644 --- a/drivers/st/ddr/stm32mp1_ram.c +++ b/drivers/st/ddr/stm32mp1_ram.c @@ -12,12 +12,9 @@ #include #include -#include #include #include #include -#include -#include #include #define DDR_PATTERN 0xAAAAAAAAU @@ -31,7 +28,7 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) ddr_enable_clock(); - ddrphy_clk = stm32mp1_clk_get_rate(DDRPHYC); + ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC); VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n", mem_speed, ddrphy_clk / 1000U); @@ -65,10 +62,10 @@ static uint32_t ddr_test_data_bus(void) uint32_t pattern; for (pattern = 1U; pattern != 0U; pattern <<= 1) { - mmio_write_32(STM32MP1_DDR_BASE, pattern); + mmio_write_32(STM32MP_DDR_BASE, pattern); - if (mmio_read_32(STM32MP1_DDR_BASE) != pattern) { - return (uint32_t)STM32MP1_DDR_BASE; + if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { + return (uint32_t)STM32MP_DDR_BASE; } } @@ -92,44 +89,44 @@ static uint32_t ddr_test_addr_bus(void) /* Write the default pattern at each of the power-of-two offsets. */ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; offset <<= 1) { - mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)offset, + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset, DDR_PATTERN); } /* Check for address bits stuck high. */ - mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_ANTIPATTERN); for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; offset <<= 1) { - if (mmio_read_32(STM32MP1_DDR_BASE + (uint32_t)offset) != + if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != DDR_PATTERN) { - return (uint32_t)(STM32MP1_DDR_BASE + offset); + return (uint32_t)(STM32MP_DDR_BASE + offset); } } - mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); /* Check for address bits stuck low or shorted. */ for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; testoffset <<= 1) { - mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_ANTIPATTERN); - if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) { - return STM32MP1_DDR_BASE; + if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { + return STM32MP_DDR_BASE; } for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; offset <<= 1) { - if ((mmio_read_32(STM32MP1_DDR_BASE + + if ((mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != DDR_PATTERN) && (offset != testoffset)) { - return (uint32_t)(STM32MP1_DDR_BASE + offset); + return (uint32_t)(STM32MP_DDR_BASE + offset); } } - mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); } @@ -147,13 +144,13 @@ static uint32_t ddr_check_size(void) { uint32_t offset = sizeof(uint32_t); - mmio_write_32(STM32MP1_DDR_BASE, DDR_PATTERN); + mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); - while (offset < STM32MP1_DDR_MAX_SIZE) { - mmio_write_32(STM32MP1_DDR_BASE + offset, DDR_ANTIPATTERN); + while (offset < STM32MP_DDR_MAX_SIZE) { + mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); dsb(); - if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) { + if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { break; } @@ -171,7 +168,7 @@ static int stm32mp1_ddr_setup(void) int ret; struct stm32mp1_ddr_config config; int node, len; - uint32_t tamp_clk_off = 0, uret, idx; + uint32_t uret, idx; void *fdt; #define PARAM(x, y) \ @@ -240,19 +237,6 @@ static int stm32mp1_ddr_setup(void) } } - if (!stm32mp1_clk_is_enabled(RTCAPB)) { - tamp_clk_off = 1; - if (stm32mp1_clk_enable(RTCAPB) != 0) { - return -EINVAL; - } - } - - if (tamp_clk_off != 0U) { - if (stm32mp1_clk_disable(RTCAPB) != 0) { - return -EINVAL; - } - } - /* Disable axidcg clock gating during init */ mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); @@ -301,12 +285,12 @@ int stm32mp1_ddr_probe(void) VERBOSE("STM32MP DDR probe\n"); - priv->ctl = (struct stm32mp1_ddrctl *)DDRCTRL_BASE; - priv->phy = (struct stm32mp1_ddrphy *)DDRPHYC_BASE; - priv->pwr = PWR_BASE; - priv->rcc = RCC_BASE; + priv->ctl = (struct stm32mp1_ddrctl *)stm32mp_ddrctrl_base(); + priv->phy = (struct stm32mp1_ddrphy *)stm32mp_ddrphyc_base(); + priv->pwr = stm32mp_pwr_base(); + priv->rcc = stm32mp_rcc_base(); - priv->info.base = STM32MP1_DDR_BASE; + priv->info.base = STM32MP_DDR_BASE; priv->info.size = 0; return stm32mp1_ddr_setup(); diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c index d217c4501..343ad6c1d 100644 --- a/drivers/st/gpio/stm32_gpio.c +++ b/drivers/st/gpio/stm32_gpio.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include @@ -208,7 +207,7 @@ void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, assert(pin <= GPIO_PIN_MAX); - stm32mp1_clk_enable(clock); + stm32mp_clk_enable(clock); mmio_clrbits_32(base + GPIO_MODE_OFFSET, ((uint32_t)GPIO_MODE_MASK << (pin << 1))); @@ -254,17 +253,17 @@ void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank, mmio_read_32(base + GPIO_AFRH_OFFSET)); - stm32mp1_clk_disable((unsigned long)clock); + stm32mp_clk_disable(clock); } void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) { uintptr_t base = stm32_get_gpio_bank_base(bank); - int clock = stm32_get_gpio_bank_clock(bank); + unsigned long clock = stm32_get_gpio_bank_clock(bank); assert(pin <= GPIO_PIN_MAX); - stm32mp1_clk_enable((unsigned long)clock); + stm32mp_clk_enable(clock); if (secure) { mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin)); @@ -272,5 +271,5 @@ void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin)); } - stm32mp1_clk_disable((unsigned long)clock); + stm32mp_clk_disable(clock); } diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c index 2be7afe2d..ed880522b 100644 --- a/drivers/st/i2c/stm32_i2c.c +++ b/drivers/st/i2c/stm32_i2c.c @@ -8,10 +8,16 @@ #include #include -#include +#include + +#include + +#include #include +#include #include #include +#include /* STM32 I2C registers offsets */ #define I2C_CR1 0x00U @@ -26,50 +32,122 @@ #define I2C_RXDR 0x24U #define I2C_TXDR 0x28U -#define MAX_DELAY 0xFFFFFFFFU - -/* I2C TIMING clear register Mask */ -#define TIMING_CLEAR_MASK 0xF0FFFFFFU -/* Timeout 25 ms */ -#define I2C_TIMEOUT_BUSY 25U +#define TIMINGR_CLEAR_MASK 0xF0FFFFFFU #define MAX_NBYTE_SIZE 255U -static int i2c_request_memory_write(struct i2c_handle_s *hi2c, - uint16_t dev_addr, uint16_t mem_addr, - uint16_t mem_add_size, uint32_t timeout, - uint32_t tick_start); -static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, - uint16_t mem_addr, uint16_t mem_add_size, - uint32_t timeout, uint32_t tick_start); +#define I2C_NSEC_PER_SEC 1000000000L -/* Private functions to handle flags during polling transfer */ -static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, - uint8_t awaited_value, uint32_t timeout, - uint32_t tick_start); -static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, - uint32_t tick_start); -static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, - uint32_t tick_start); -static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, - uint32_t tick_start); +/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */ +#define I2C_TIMING 0x10D07DB5 -/* Private function to flush TXDR register */ -static void i2c_flush_txdr(struct i2c_handle_s *hi2c); +static void notif_i2c_timeout(struct i2c_handle_s *hi2c) +{ + hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + hi2c->i2c_mode = I2C_MODE_NONE; + hi2c->i2c_state = I2C_STATE_READY; +} -/* Private function to start, restart or stop a transfer */ -static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, - uint16_t size, uint32_t i2c_mode, - uint32_t request); +/* + * @brief Configure I2C Analog noise filter. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C peripheral. + * @param analog_filter: New state of the Analog filter + * @retval 0 if OK, negative value else + */ +static int i2c_config_analog_filter(struct i2c_handle_s *hi2c, + uint32_t analog_filter) +{ + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return -EBUSY; + } + + hi2c->lock = 1; + + hi2c->i2c_state = I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + + /* Reset I2Cx ANOFF bit */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF); + + /* Set analog filter bit*/ + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter); + + /* Enable the selected I2C peripheral */ + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + + hi2c->i2c_state = I2C_STATE_READY; + + hi2c->lock = 0; + + return 0; +} + +/* + * @brief Get I2C setup information from the device tree and set pinctrl + * configuration. + * @param fdt: Pointer to the device tree + * @param node: I2C node offset + * @param init: Ref to the initialization configuration structure + * @retval 0 if OK, negative value else + */ +int stm32_i2c_get_setup_from_fdt(void *fdt, int node, + struct stm32_i2c_init_s *init) +{ + const fdt32_t *cuint; + + cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL); + if (cuint == NULL) { + init->rise_time = STM32_I2C_RISE_TIME_DEFAULT; + } else { + init->rise_time = fdt32_to_cpu(*cuint); + } + + cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL); + if (cuint == NULL) { + init->fall_time = STM32_I2C_FALL_TIME_DEFAULT; + } else { + init->fall_time = fdt32_to_cpu(*cuint); + } + + cuint = fdt_getprop(fdt, node, "clock-frequency", NULL); + if (cuint == NULL) { + init->speed_mode = STM32_I2C_SPEED_DEFAULT; + } else { + switch (fdt32_to_cpu(*cuint)) { + case STANDARD_RATE: + init->speed_mode = I2C_SPEED_STANDARD; + break; + case FAST_RATE: + init->speed_mode = I2C_SPEED_FAST; + break; + case FAST_PLUS_RATE: + init->speed_mode = I2C_SPEED_FAST_PLUS; + break; + default: + init->speed_mode = STM32_I2C_SPEED_DEFAULT; + break; + } + } + + return dt_set_pinctrl_config(node); +} /* * @brief Initialize the I2C device. * @param hi2c: Pointer to a struct i2c_handle_s structure that contains * the configuration information for the specified I2C. + * @param init_data: Initialization configuration structure * @retval 0 if OK, negative value else */ -int stm32_i2c_init(struct i2c_handle_s *hi2c) +int stm32_i2c_init(struct i2c_handle_s *hi2c, + struct stm32_i2c_init_s *init_data) { + int rc = 0; + uint32_t timing = I2C_TIMING; + if (hi2c == NULL) { return -ENOENT; } @@ -80,34 +158,38 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c) hi2c->i2c_state = I2C_STATE_BUSY; + stm32mp_clk_enable(hi2c->clock); + /* Disable the selected I2C peripheral */ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); /* Configure I2Cx: Frequency range */ mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR, - hi2c->i2c_init.timing & TIMING_CLEAR_MASK); + timing & TIMINGR_CLEAR_MASK); /* Disable Own Address1 before set the Own Address1 configuration */ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN); /* Configure I2Cx: Own Address1 and ack own address1 mode */ - if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { + if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) { mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, - I2C_OAR1_OA1EN | hi2c->i2c_init.own_address1); + I2C_OAR1_OA1EN | init_data->own_address1); } else { /* I2C_ADDRESSINGMODE_10BIT */ mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | - hi2c->i2c_init.own_address1); + init_data->own_address1); } + mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0); + /* Configure I2Cx: Addressing Master mode */ - if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_10BIT) { - mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10); + if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) { + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10); } /* * Enable the AUTOEND by default, and enable NACK - * (should be disable only during Slave process) + * (should be disabled only during Slave process). */ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_AUTOEND | I2C_CR2_NACK); @@ -117,14 +199,14 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c) /* Configure I2Cx: Dual mode and Own Address2 */ mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2, - hi2c->i2c_init.dual_address_mode | - hi2c->i2c_init.own_address2 | - (hi2c->i2c_init.own_address2_masks << 8)); + init_data->dual_address_mode | + init_data->own_address2 | + (init_data->own_address2_masks << 8)); /* Configure I2Cx: Generalcall and NoStretch mode */ mmio_write_32(hi2c->i2c_base_addr + I2C_CR1, - hi2c->i2c_init.general_call_mode | - hi2c->i2c_init.no_stretch_mode); + init_data->general_call_mode | + init_data->no_stretch_mode); /* Enable the selected I2C peripheral */ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); @@ -133,471 +215,23 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c) hi2c->i2c_state = I2C_STATE_READY; hi2c->i2c_mode = I2C_MODE_NONE; - return 0; -} - -/* - * @brief Write an amount of data in blocking mode to a specific memory address - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param dev_addr: Target device address - * @param mem_addr: Internal memory address - * @param mem_add_size: size of internal memory address - * @param p_data: Pointer to data buffer - * @param size: Amount of data to be sent - * @param timeout: timeout duration - * @retval 0 if OK, negative value else - */ -int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, - uint16_t mem_addr, uint16_t mem_add_size, - uint8_t *p_data, uint16_t size, uint32_t timeout) -{ - uint32_t tickstart; - - if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { - return -EBUSY; + rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ? + I2C_ANALOGFILTER_ENABLE : + I2C_ANALOGFILTER_DISABLE); + if (rc != 0) { + ERROR("Cannot initialize I2C analog filter (%d)\n", rc); + stm32mp_clk_disable(hi2c->clock); + return rc; } - if ((p_data == NULL) || (size == 0U)) { - return -EINVAL; - } + stm32mp_clk_disable(hi2c->clock); - hi2c->lock = 1; - - tickstart = (uint32_t)read_cntpct_el0(); - - if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, - tickstart) != 0) { - return -EIO; - } - - hi2c->i2c_state = I2C_STATE_BUSY_TX; - hi2c->i2c_mode = I2C_MODE_MEM; - hi2c->i2c_err = I2C_ERROR_NONE; - - hi2c->p_buff = p_data; - hi2c->xfer_count = size; - - /* Send Slave Address and Memory Address */ - if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, mem_add_size, - timeout, tickstart) != 0) { - hi2c->lock = 0; - return -EIO; - } - - /* - * Set NBYTES to write and reload - * if hi2c->xfer_count > MAX_NBYTE_SIZE - */ - if (hi2c->xfer_count > MAX_NBYTE_SIZE) { - hi2c->xfer_size = MAX_NBYTE_SIZE; - i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, - I2C_RELOAD_MODE, I2C_NO_STARTSTOP); - } else { - hi2c->xfer_size = hi2c->xfer_count; - i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, - I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); - } - - do { - if (i2c_wait_txis(hi2c, timeout, tickstart) != 0) { - return -EIO; - } - - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *hi2c->p_buff); - hi2c->p_buff++; - hi2c->xfer_count--; - hi2c->xfer_size--; - - if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { - /* Wait until TCR flag is set */ - if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, - tickstart) != 0) { - return -EIO; - } - - if (hi2c->xfer_count > MAX_NBYTE_SIZE) { - hi2c->xfer_size = MAX_NBYTE_SIZE; - i2c_transfer_config(hi2c, dev_addr, - hi2c->xfer_size, - I2C_RELOAD_MODE, - I2C_NO_STARTSTOP); - } else { - hi2c->xfer_size = hi2c->xfer_count; - i2c_transfer_config(hi2c, dev_addr, - hi2c->xfer_size, - I2C_AUTOEND_MODE, - I2C_NO_STARTSTOP); - } - } - - } while (hi2c->xfer_count > 0U); - - /* - * No need to Check TC flag, with AUTOEND mode the stop - * is automatically generated. - * Wait until STOPF flag is reset. - */ - if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) { - return -EIO; - } - - mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); - - mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); - - hi2c->i2c_state = I2C_STATE_READY; - hi2c->i2c_mode = I2C_MODE_NONE; - - hi2c->lock = 0; - - return 0; -} - -/* - * @brief Read an amount of data in blocking mode from a specific memory - * address - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param dev_addr: Target device address - * @param mem_addr: Internal memory address - * @param mem_add_size: size of internal memory address - * @param p_data: Pointer to data buffer - * @param size: Amount of data to be sent - * @param timeout: timeout duration - * @retval 0 if OK, negative value else - */ -int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, - uint16_t mem_addr, uint16_t mem_add_size, - uint8_t *p_data, uint16_t size, uint32_t timeout) -{ - uint32_t tickstart; - - if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { - return -EBUSY; - } - - if ((p_data == NULL) || (size == 0U)) { - return -EINVAL; - } - - hi2c->lock = 1; - - tickstart = (uint32_t)read_cntpct_el0(); - - if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, - tickstart) != 0) { - return -EIO; - } - - hi2c->i2c_state = I2C_STATE_BUSY_RX; - hi2c->i2c_mode = I2C_MODE_MEM; - hi2c->i2c_err = I2C_ERROR_NONE; - - hi2c->p_buff = p_data; - hi2c->xfer_count = size; - - /* Send Slave Address and Memory Address */ - if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, mem_add_size, - timeout, tickstart) != 0) { - hi2c->lock = 0; - return -EIO; - } - - /* - * Send Slave Address. - * Set NBYTES to write and reload if hi2c->xfer_count > MAX_NBYTE_SIZE - * and generate RESTART. - */ - if (hi2c->xfer_count > MAX_NBYTE_SIZE) { - hi2c->xfer_size = MAX_NBYTE_SIZE; - i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, - I2C_RELOAD_MODE, I2C_GENERATE_START_READ); - } else { - hi2c->xfer_size = hi2c->xfer_count; - i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, - I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); - } - - do { - if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout, - tickstart) != 0) { - return -EIO; - } - - *hi2c->p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR); - hi2c->p_buff++; - hi2c->xfer_size--; - hi2c->xfer_count--; - - if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { - if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, - tickstart) != 0) { - return -EIO; - } - - if (hi2c->xfer_count > MAX_NBYTE_SIZE) { - hi2c->xfer_size = MAX_NBYTE_SIZE; - i2c_transfer_config(hi2c, dev_addr, - hi2c->xfer_size, - I2C_RELOAD_MODE, - I2C_NO_STARTSTOP); - } else { - hi2c->xfer_size = hi2c->xfer_count; - i2c_transfer_config(hi2c, dev_addr, - hi2c->xfer_size, - I2C_AUTOEND_MODE, - I2C_NO_STARTSTOP); - } - } - } while (hi2c->xfer_count > 0U); - - /* - * No need to Check TC flag, with AUTOEND mode the stop - * is automatically generated - * Wait until STOPF flag is reset - */ - if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) { - return -EIO; - } - - mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); - - mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); - - hi2c->i2c_state = I2C_STATE_READY; - hi2c->i2c_mode = I2C_MODE_NONE; - - hi2c->lock = 0; - - return 0; -} - -/* - * @brief Checks if target device is ready for communication. - * @note This function is used with Memory devices - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param dev_addr: Target device address - * @param trials: Number of trials - * @param timeout: timeout duration - * @retval 0 if OK, negative value else - */ -int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, - uint16_t dev_addr, uint32_t trials, - uint32_t timeout) -{ - uint32_t i2c_trials = 0U; - - if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { - return -EBUSY; - } - - if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) != - 0U) { - return -EBUSY; - } - - hi2c->lock = 1; - - hi2c->i2c_state = I2C_STATE_BUSY; - hi2c->i2c_err = I2C_ERROR_NONE; - - do { - uint32_t tickstart; - - /* Generate Start */ - if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { - mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, - (((uint32_t)dev_addr & I2C_CR2_SADD) | - I2C_CR2_START | I2C_CR2_AUTOEND) & - ~I2C_CR2_RD_WRN); - } else { - mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, - (((uint32_t)dev_addr & I2C_CR2_SADD) | - I2C_CR2_START | I2C_CR2_ADD10) & - ~I2C_CR2_RD_WRN); - } - - /* - * No need to Check TC flag, with AUTOEND mode the stop - * is automatically generated - * Wait until STOPF flag is set or a NACK flag is set - */ - tickstart = (uint32_t)read_cntpct_el0(); - while (((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & - (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0U) && - (hi2c->i2c_state != I2C_STATE_TIMEOUT)) { - if (timeout != MAX_DELAY) { - if ((((uint32_t)read_cntpct_el0() - tickstart) > - timeout) || (timeout == 0U)) { - hi2c->i2c_state = I2C_STATE_READY; - - hi2c->i2c_err |= - I2C_ERROR_TIMEOUT; - - hi2c->lock = 0; - - return -EIO; - } - } - } - - /* Check if the NACKF flag has not been set */ - if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & - I2C_FLAG_AF) == 0U) { - if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, - tickstart) != 0) { - return -EIO; - } - - mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, - I2C_FLAG_STOPF); - - hi2c->i2c_state = I2C_STATE_READY; - - hi2c->lock = 0; - - return 0; - } - - if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, - tickstart) != 0) { - return -EIO; - } - - mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); - - mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); - - if (i2c_trials == trials) { - mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, - I2C_CR2_STOP); - - if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, - tickstart) != 0) { - return -EIO; - } - - mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, - I2C_FLAG_STOPF); - } - - i2c_trials++; - } while (i2c_trials < trials); - - hi2c->i2c_state = I2C_STATE_READY; - - hi2c->i2c_err |= I2C_ERROR_TIMEOUT; - - hi2c->lock = 0; - - return -EIO; -} - -/* - * @brief Master sends target device address followed by internal memory - * address for write request. - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param dev_addr: Target device address - * @param mem_addr: Internal memory address - * @param mem_add_size: size of internal memory address - * @param timeout: timeout duration - * @param tick_start Tick start value - * @retval 0 if OK, negative value else - */ -static int i2c_request_memory_write(struct i2c_handle_s *hi2c, - uint16_t dev_addr, uint16_t mem_addr, - uint16_t mem_add_size, uint32_t timeout, - uint32_t tick_start) -{ - i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, - I2C_GENERATE_START_WRITE); - - if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { - return -EIO; - } - - if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { - /* Send Memory Address */ - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, - (uint8_t)(mem_addr & 0x00FFU)); - } else { - /* Send MSB of Memory Address */ - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, - (uint8_t)((mem_addr & 0xFF00U) >> 8)); - - /* Wait until TXIS flag is set */ - if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { - return -EIO; - } - - /* Send LSB of Memory Address */ - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, - (uint8_t)(mem_addr & 0x00FFU)); - } - - if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, tick_start) != - 0) { - return -EIO; - } - - return 0; -} - -/* - * @brief Master sends target device address followed by internal memory - * address for read request. - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param dev_addr: Target device address - * @param mem_addr: Internal memory address - * @param mem_add_size: size of internal memory address - * @param timeout: timeout duration - * @param tick_start Tick start value - * @retval 0 if OK, negative value else - */ -static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, - uint16_t mem_addr, uint16_t mem_add_size, - uint32_t timeout, uint32_t tick_start) -{ - i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, - I2C_GENERATE_START_WRITE); - - if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { - return -EIO; - } - - if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { - /* Send Memory Address */ - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, - (uint8_t)(mem_addr & 0x00FFU)); - } else { - /* Send MSB of Memory Address */ - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, - (uint8_t)((mem_addr & 0xFF00U) >> 8)); - - /* Wait until TXIS flag is set */ - if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { - return -EIO; - } - - /* Send LSB of Memory Address */ - mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, - (uint8_t)(mem_addr & 0x00FFU)); - } - - if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout, tick_start) != 0) { - return -EIO; - } - - return 0; + return rc; } /* * @brief I2C Tx data register flush process. - * @param hi2c: I2C handle. + * @param hi2c: I2C handle * @retval None */ static void i2c_flush_txdr(struct i2c_handle_s *hi2c) @@ -623,104 +257,28 @@ static void i2c_flush_txdr(struct i2c_handle_s *hi2c) * @brief This function handles I2C Communication timeout. * @param hi2c: Pointer to a struct i2c_handle_s structure that contains * the configuration information for the specified I2C. - * @param flag: Specifies the I2C flag to check. - * @param awaited_value: The awaited bit value for the flag (0 or 1). - * @param timeout: timeout duration - * @param tick_start: Tick start value + * @param flag: Specifies the I2C flag to check + * @param awaited_value: The awaited bit value for the flag (0 or 1) + * @param timeout_ref: Reference to target timeout * @retval 0 if OK, negative value else */ static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, - uint8_t awaited_value, uint32_t timeout, - uint32_t tick_start) + uint8_t awaited_value, uint64_t timeout_ref) { - uint8_t flag_check; + for ( ; ; ) { + uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR); - do { - flag_check = ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & - flag) == flag) ? 1U : 0U; - - if (timeout != MAX_DELAY) { - if ((((uint32_t)read_cntpct_el0() - tick_start) > - timeout) || (timeout == 0U)) { - hi2c->i2c_err |= I2C_ERROR_TIMEOUT; - hi2c->i2c_state = I2C_STATE_READY; - hi2c->i2c_mode = I2C_MODE_NONE; - - hi2c->lock = 0; - return -EIO; - } - } - } while (flag_check == awaited_value); - - return 0; -} - -/* - * @brief This function handles I2C Communication timeout for specific usage - * of TXIS flag. - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param timeout: timeout duration - * @param tick_start: Tick start value - * @retval 0 if OK, negative value else - */ -static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, - uint32_t tick_start) -{ - while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & - I2C_FLAG_TXIS) == 0U) { - if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { - return -EIO; + if (!!(isr & flag) != !!awaited_value) { + return 0; } - if (timeout != MAX_DELAY) { - if ((((uint32_t)read_cntpct_el0() - tick_start) > - timeout) || (timeout == 0U)) { - hi2c->i2c_err |= I2C_ERROR_TIMEOUT; - hi2c->i2c_state = I2C_STATE_READY; - hi2c->i2c_mode = I2C_MODE_NONE; - - hi2c->lock = 0; - - return -EIO; - } - } - } - - return 0; -} - -/* - * @brief This function handles I2C Communication timeout for specific - * usage of STOP flag. - * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2C. - * @param timeout: timeout duration - * @param tick_start: Tick start value - * @retval 0 if OK, negative value else - */ -static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, - uint32_t tick_start) -{ - while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & - I2C_FLAG_STOPF) == 0U) { - if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { - return -EIO; - } - - if ((((uint32_t)read_cntpct_el0() - tick_start) > timeout) || - (timeout == 0U)) { - hi2c->i2c_err |= I2C_ERROR_TIMEOUT; - hi2c->i2c_state = I2C_STATE_READY; - hi2c->i2c_mode = I2C_MODE_NONE; - + if (timeout_elapsed(timeout_ref)) { + notif_i2c_timeout(hi2c); hi2c->lock = 0; return -EIO; } } - - return 0; } /* @@ -728,12 +286,10 @@ static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, * an I2C Communication. * @param hi2c: Pointer to a struct i2c_handle_s structure that contains * the configuration information for the specified I2C. - * @param timeout: timeout duration - * @param tick_start: Tick start value + * @param timeout_ref: Reference to target timeout * @retval 0 if OK, negative value else */ -static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, - uint32_t tick_start) +static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref) { if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) { return 0; @@ -745,17 +301,11 @@ static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, */ while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_STOPF) == 0U) { - if (timeout != MAX_DELAY) { - if ((((uint32_t)read_cntpct_el0() - tick_start) > - timeout) || (timeout == 0U)) { - hi2c->i2c_err |= I2C_ERROR_TIMEOUT; - hi2c->i2c_state = I2C_STATE_READY; - hi2c->i2c_mode = I2C_MODE_NONE; + if (timeout_elapsed(timeout_ref)) { + notif_i2c_timeout(hi2c); + hi2c->lock = 0; - hi2c->lock = 0; - - return -EIO; - } + return -EIO; } } @@ -776,16 +326,70 @@ static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, return -EIO; } +/* + * @brief This function handles I2C Communication timeout for specific usage + * of TXIS flag. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param timeout_ref: Reference to target timeout + * @retval 0 if OK, negative value else + */ +static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t timeout_ref) +{ + while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_TXIS) == 0U) { + if (i2c_ack_failed(hi2c, timeout_ref) != 0) { + return -EIO; + } + + if (timeout_elapsed(timeout_ref)) { + notif_i2c_timeout(hi2c); + hi2c->lock = 0; + + return -EIO; + } + } + + return 0; +} + +/* + * @brief This function handles I2C Communication timeout for specific + * usage of STOP flag. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param timeout_ref: Reference to target timeout + * @retval 0 if OK, negative value else + */ +static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t timeout_ref) +{ + while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_STOPF) == 0U) { + if (i2c_ack_failed(hi2c, timeout_ref) != 0) { + return -EIO; + } + + if (timeout_elapsed(timeout_ref)) { + notif_i2c_timeout(hi2c); + hi2c->lock = 0; + + return -EIO; + } + } + + return 0; +} + /* * @brief Handles I2Cx communication when starting transfer or during transfer * (TC or TCR flag are set). - * @param hi2c: I2C handle. - * @param dev_addr: Specifies the slave address to be programmed. + * @param hi2c: I2C handle + * @param dev_addr: Specifies the slave address to be programmed * @param size: Specifies the number of bytes to be programmed. * This parameter must be a value between 0 and 255. * @param i2c_mode: New state of the I2C START condition generation. * This parameter can be one of the following values: - * @arg @ref I2C_RELOAD_MODE: Enable Reload mode . + * @arg @ref I2C_RELOAD_MODE: Enable Reload mode. * @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode. * @arg @ref I2C_SOFTEND_MODE: Enable Software end mode. * @param request: New state of the I2C START condition generation. @@ -815,38 +419,563 @@ static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, } /* - * @brief Configure I2C Analog noise filter. + * @brief Master sends target device address followed by internal memory + * address for write request. * @param hi2c: Pointer to a struct i2c_handle_s structure that contains - * the configuration information for the specified I2Cx peripheral - * @param analog_filter: New state of the Analog filter. + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: Size of internal memory address + * @param timeout_ref: Reference to target timeout * @retval 0 if OK, negative value else */ -int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, - uint32_t analog_filter) +static int i2c_request_memory_write(struct i2c_handle_s *hi2c, + uint16_t dev_addr, uint16_t mem_addr, + uint16_t mem_add_size, uint64_t timeout_ref) { + i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, + I2C_GENERATE_START_WRITE); + + if (i2c_wait_txis(hi2c, timeout_ref) != 0) { + return -EIO; + } + + if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { + /* Send Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } else { + /* Send MSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)((mem_addr & 0xFF00U) >> 8)); + + if (i2c_wait_txis(hi2c, timeout_ref) != 0) { + return -EIO; + } + + /* Send LSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } + + if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout_ref) != 0) { + return -EIO; + } + + return 0; +} + +/* + * @brief Master sends target device address followed by internal memory + * address for read request. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: Size of internal memory address + * @param timeout_ref: Reference to target timeout + * @retval 0 if OK, negative value else + */ +static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint64_t timeout_ref) +{ + i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, + I2C_GENERATE_START_WRITE); + + if (i2c_wait_txis(hi2c, timeout_ref) != 0) { + return -EIO; + } + + if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { + /* Send Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } else { + /* Send MSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)((mem_addr & 0xFF00U) >> 8)); + + if (i2c_wait_txis(hi2c, timeout_ref) != 0) { + return -EIO; + } + + /* Send LSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } + + if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout_ref) != 0) { + return -EIO; + } + + return 0; +} +/* + * @brief Generic function to write an amount of data in blocking mode + * (for Memory Mode and Master Mode) + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address (if Memory Mode) + * @param mem_add_size: Size of internal memory address (if Memory Mode) + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout_ms: Timeout duration in milliseconds + * @param mode: Communication mode + * @retval 0 if OK, negative value else + */ +static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout_ms, + enum i2c_mode_e mode) +{ + uint64_t timeout_ref; + int rc = -EIO; + uint8_t *p_buff = p_data; + uint32_t xfer_size; + uint32_t xfer_count = size; + + if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) { + return -1; + } + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { return -EBUSY; } + if ((p_data == NULL) || (size == 0U)) { + return -EINVAL; + } + + stm32mp_clk_enable(hi2c->clock); + hi2c->lock = 1; - hi2c->i2c_state = I2C_STATE_BUSY; + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000); + if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) { + goto bail; + } - /* Disable the selected I2C peripheral */ - mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + hi2c->i2c_state = I2C_STATE_BUSY_TX; + hi2c->i2c_mode = mode; + hi2c->i2c_err = I2C_ERROR_NONE; - /* Reset I2Cx ANOFF bit */ - mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF); + timeout_ref = timeout_init_us(timeout_ms * 1000); - /* Set analog filter bit*/ - mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter); + if (mode == I2C_MODE_MEM) { + /* In Memory Mode, Send Slave Address and Memory Address */ + if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, + mem_add_size, timeout_ref) != 0) { + goto bail; + } - /* Enable the selected I2C peripheral */ - mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + if (xfer_count > MAX_NBYTE_SIZE) { + xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, xfer_size, + I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + } else { + xfer_size = xfer_count; + i2c_transfer_config(hi2c, dev_addr, xfer_size, + I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + } + } else { + /* In Master Mode, Send Slave Address */ + if (xfer_count > MAX_NBYTE_SIZE) { + xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, xfer_size, + I2C_RELOAD_MODE, + I2C_GENERATE_START_WRITE); + } else { + xfer_size = xfer_count; + i2c_transfer_config(hi2c, dev_addr, xfer_size, + I2C_AUTOEND_MODE, + I2C_GENERATE_START_WRITE); + } + } + + do { + if (i2c_wait_txis(hi2c, timeout_ref) != 0) { + goto bail; + } + + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *p_buff); + p_buff++; + xfer_count--; + xfer_size--; + + if ((xfer_count != 0U) && (xfer_size == 0U)) { + /* Wait until TCR flag is set */ + if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, + timeout_ref) != 0) { + goto bail; + } + + if (xfer_count > MAX_NBYTE_SIZE) { + xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, + xfer_size, + I2C_RELOAD_MODE, + I2C_NO_STARTSTOP); + } else { + xfer_size = xfer_count; + i2c_transfer_config(hi2c, dev_addr, + xfer_size, + I2C_AUTOEND_MODE, + I2C_NO_STARTSTOP); + } + } + + } while (xfer_count > 0U); + + /* + * No need to Check TC flag, with AUTOEND mode the stop + * is automatically generated. + * Wait until STOPF flag is reset. + */ + if (i2c_wait_stop(hi2c, timeout_ref) != 0) { + goto bail; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + rc = 0; + +bail: hi2c->lock = 0; + stm32mp_clk_disable(hi2c->clock); - return 0; + return rc; } + +/* + * @brief Write an amount of data in blocking mode to a specific memory + * address. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: Size of internal memory address + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout_ms: Timeout duration in milliseconds + * @retval 0 if OK, negative value else + */ +int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout_ms) +{ + return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size, + p_data, size, timeout_ms, I2C_MODE_MEM); +} + +/* + * @brief Transmits in master mode an amount of data in blocking mode. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout_ms: Timeout duration in milliseconds + * @retval 0 if OK, negative value else + */ +int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint8_t *p_data, uint16_t size, + uint32_t timeout_ms) +{ + return i2c_write(hi2c, dev_addr, 0, 0, + p_data, size, timeout_ms, I2C_MODE_MASTER); +} + +/* + * @brief Generic function to read an amount of data in blocking mode + * (for Memory Mode and Master Mode) + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address (if Memory Mode) + * @param mem_add_size: Size of internal memory address (if Memory Mode) + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout_ms: Timeout duration in milliseconds + * @param mode: Communication mode + * @retval 0 if OK, negative value else + */ +static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout_ms, + enum i2c_mode_e mode) +{ + uint64_t timeout_ref; + int rc = -EIO; + uint8_t *p_buff = p_data; + uint32_t xfer_count = size; + uint32_t xfer_size; + + if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) { + return -1; + } + + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return -EBUSY; + } + + if ((p_data == NULL) || (size == 0U)) { + return -EINVAL; + } + + stm32mp_clk_enable(hi2c->clock); + + hi2c->lock = 1; + + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000); + if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) { + goto bail; + } + + hi2c->i2c_state = I2C_STATE_BUSY_RX; + hi2c->i2c_mode = mode; + hi2c->i2c_err = I2C_ERROR_NONE; + + if (mode == I2C_MODE_MEM) { + /* Send Memory Address */ + if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, + mem_add_size, timeout_ref) != 0) { + goto bail; + } + } + + /* + * Send Slave Address. + * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE + * and generate RESTART. + */ + if (xfer_count > MAX_NBYTE_SIZE) { + xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, xfer_size, + I2C_RELOAD_MODE, I2C_GENERATE_START_READ); + } else { + xfer_size = xfer_count; + i2c_transfer_config(hi2c, dev_addr, xfer_size, + I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); + } + + do { + if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout_ref) != 0) { + goto bail; + } + + *p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR); + p_buff++; + xfer_size--; + xfer_count--; + + if ((xfer_count != 0U) && (xfer_size == 0U)) { + if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, + timeout_ref) != 0) { + goto bail; + } + + if (xfer_count > MAX_NBYTE_SIZE) { + xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, + xfer_size, + I2C_RELOAD_MODE, + I2C_NO_STARTSTOP); + } else { + xfer_size = xfer_count; + i2c_transfer_config(hi2c, dev_addr, + xfer_size, + I2C_AUTOEND_MODE, + I2C_NO_STARTSTOP); + } + } + } while (xfer_count > 0U); + + /* + * No need to Check TC flag, with AUTOEND mode the stop + * is automatically generated. + * Wait until STOPF flag is reset. + */ + if (i2c_wait_stop(hi2c, timeout_ref) != 0) { + goto bail; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + rc = 0; + +bail: + hi2c->lock = 0; + stm32mp_clk_disable(hi2c->clock); + + return rc; +} + +/* + * @brief Read an amount of data in blocking mode from a specific memory + * address. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: Size of internal memory address + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout_ms: Timeout duration in milliseconds + * @retval 0 if OK, negative value else + */ +int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout_ms) +{ + return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size, + p_data, size, timeout_ms, I2C_MODE_MEM); +} + +/* + * @brief Receives in master mode an amount of data in blocking mode. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout_ms: Timeout duration in milliseconds + * @retval 0 if OK, negative value else + */ +int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint8_t *p_data, uint16_t size, + uint32_t timeout_ms) +{ + return i2c_read(hi2c, dev_addr, 0, 0, + p_data, size, timeout_ms, I2C_MODE_MASTER); +} + +/* + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param trials: Number of trials + * @param timeout_ms: Timeout duration in milliseconds + * @retval True if device is ready, false else + */ +bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, + uint16_t dev_addr, uint32_t trials, + uint32_t timeout_ms) +{ + uint32_t i2c_trials = 0U; + bool rc = false; + + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return rc; + } + + stm32mp_clk_enable(hi2c->clock); + + hi2c->lock = 1; + hi2c->i2c_mode = I2C_MODE_NONE; + + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) != + 0U) { + goto bail; + } + + hi2c->i2c_state = I2C_STATE_BUSY; + hi2c->i2c_err = I2C_ERROR_NONE; + + do { + uint64_t timeout_ref; + + /* Generate Start */ + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) & + I2C_OAR1_OA1MODE) == 0) { + mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, + (((uint32_t)dev_addr & I2C_CR2_SADD) | + I2C_CR2_START | I2C_CR2_AUTOEND) & + ~I2C_CR2_RD_WRN); + } else { + mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, + (((uint32_t)dev_addr & I2C_CR2_SADD) | + I2C_CR2_START | I2C_CR2_ADD10) & + ~I2C_CR2_RD_WRN); + } + + /* + * No need to Check TC flag, with AUTOEND mode the stop + * is automatically generated. + * Wait until STOPF flag is set or a NACK flag is set. + */ + timeout_ref = timeout_init_us(timeout_ms * 1000); + do { + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) { + break; + } + + if (timeout_elapsed(timeout_ref)) { + notif_i2c_timeout(hi2c); + goto bail; + } + } while (true); + + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_AF) == 0U) { + if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, + timeout_ref) != 0) { + goto bail; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, + I2C_FLAG_STOPF); + + hi2c->i2c_state = I2C_STATE_READY; + + rc = true; + goto bail; + } + + if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout_ref) != 0) { + goto bail; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + if (i2c_trials == trials) { + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, + I2C_CR2_STOP); + + if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, + timeout_ref) != 0) { + goto bail; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, + I2C_FLAG_STOPF); + } + + i2c_trials++; + } while (i2c_trials < trials); + + notif_i2c_timeout(hi2c); + +bail: + hi2c->lock = 0; + stm32mp_clk_disable(hi2c->clock); + + return rc; +} + diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c index 57812d899..06de112e9 100644 --- a/drivers/st/mmc/stm32_sdmmc2.c +++ b/drivers/st/mmc/stm32_sdmmc2.c @@ -19,11 +19,7 @@ #include #include #include -#include -#include -#include -#include -#include +#include #include #include #include @@ -123,8 +119,8 @@ SDMMC_STAR_IDMATE | \ SDMMC_STAR_IDMABTC) -#define TIMEOUT_10_MS (plat_get_syscnt_freq2() / 100U) -#define TIMEOUT_1_S plat_get_syscnt_freq2() +#define TIMEOUT_US_10_MS 10000U +#define TIMEOUT_US_1_S 1000000U #define DT_SDMMC2_COMPAT "st,stm32-sdmmc2" @@ -159,7 +155,7 @@ static void stm32_sdmmc2_init(void) uintptr_t base = sdmmc2_params.reg_base; clock_div = div_round_up(sdmmc2_params.clk_rate, - STM32MP1_MMC_INIT_FREQ * 2); + STM32MP_MMC_INIT_FREQ * 2); mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div | sdmmc2_params.negedge | @@ -185,11 +181,12 @@ static int stm32_sdmmc2_stop_transfer(void) static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) { + uint64_t timeout; uint32_t flags_cmd, status; uint32_t flags_data = 0; int err = 0; uintptr_t base = sdmmc2_params.reg_base; - unsigned int cmd_reg, arg_reg, start; + unsigned int cmd_reg, arg_reg; if (cmd == NULL) { return -EINVAL; @@ -272,10 +269,10 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) status = mmio_read_32(base + SDMMC_STAR); - start = get_timer(0); + timeout = timeout_init_us(TIMEOUT_US_10_MS); while ((status & flags_cmd) == 0U) { - if (get_timer(start) > TIMEOUT_10_MS) { + if (timeout_elapsed(timeout)) { err = -ETIMEDOUT; ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n", __func__, cmd->cmd_idx, status); @@ -339,10 +336,10 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) status = mmio_read_32(base + SDMMC_STAR); - start = get_timer(0); + timeout = timeout_init_us(TIMEOUT_US_10_MS); while ((status & flags_data) == 0U) { - if (get_timer(start) > TIMEOUT_10_MS) { + if (timeout_elapsed(timeout)) { ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n", __func__, cmd->cmd_idx, status); err = -ETIMEDOUT; @@ -364,7 +361,7 @@ err_exit: mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS); mmio_clrbits_32(base + SDMMC_CMDR, SDMMC_CMDR_CMDTRANS); - if (err != 0) { + if ((err != 0) && ((status & SDMMC_STAR_DPSMACT) != 0U)) { int ret_stop = stm32_sdmmc2_stop_transfer(); if (ret_stop != 0) { @@ -429,15 +426,15 @@ static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width) if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) { if (max_bus_freq >= 52000000U) { - max_freq = STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ; + max_freq = STM32MP_EMMC_HIGH_SPEED_MAX_FREQ; } else { - max_freq = STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ; + max_freq = STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ; } } else { if (max_bus_freq >= 50000000U) { - max_freq = STM32MP1_SD_HIGH_SPEED_MAX_FREQ; + max_freq = STM32MP_SD_HIGH_SPEED_MAX_FREQ; } else { - max_freq = STM32MP1_SD_NORMAL_SPEED_MAX_FREQ; + max_freq = STM32MP_SD_NORMAL_SPEED_MAX_FREQ; } } @@ -523,7 +520,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size) uint32_t *buffer; uintptr_t base = sdmmc2_params.reg_base; uintptr_t fifo_reg = base + SDMMC_FIFOR; - unsigned int start; + uint64_t timeout; int ret; /* Assert buf is 4 bytes aligned */ @@ -541,7 +538,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size) flags |= SDMMC_STAR_DBCKEND; } - start = get_timer(0); + timeout = timeout_init_us(TIMEOUT_US_1_S); do { status = mmio_read_32(base + SDMMC_STAR); @@ -563,7 +560,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size) return -EIO; } - if (get_timer(start) > TIMEOUT_1_S) { + if (timeout_elapsed(timeout)) { ERROR("%s: timeout 1s (status = %x)\n", __func__, status); mmio_write_32(base + SDMMC_ICR, @@ -705,8 +702,6 @@ unsigned long long stm32_sdmmc2_mmc_get_device_size(void) int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) { - int ret; - assert((params != NULL) && ((params->reg_base & MMC_BLOCK_MASK) == 0U) && ((params->bus_width == MMC_BUS_WIDTH_1) || @@ -720,19 +715,14 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) return -ENOMEM; } - ret = stm32mp1_clk_enable(sdmmc2_params.clock_id); - if (ret != 0) { - ERROR("%s: clock %d failed\n", __func__, - sdmmc2_params.clock_id); - return ret; - } + stm32mp_clk_enable(sdmmc2_params.clock_id); - stm32mp1_reset_assert(sdmmc2_params.reset_id); + stm32mp_reset_assert(sdmmc2_params.reset_id); udelay(2); - stm32mp1_reset_deassert(sdmmc2_params.reset_id); + stm32mp_reset_deassert(sdmmc2_params.reset_id); mdelay(1); - sdmmc2_params.clk_rate = stm32mp1_clk_get_rate(sdmmc2_params.clock_id); + sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id); return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate, sdmmc2_params.bus_width, sdmmc2_params.flags, diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c index 6beabc153..6fe51f443 100644 --- a/drivers/st/pmic/stm32mp_pmic.c +++ b/drivers/st/pmic/stm32mp_pmic.c @@ -5,7 +5,6 @@ */ #include -#include #include @@ -13,20 +12,12 @@ #include #include +#include #include -#include -#include #include #include #include -/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */ -#define I2C_TIMING 0x10D07DB5 - -#define I2C_TIMEOUT 0xFFFFF - -#define MASK_RESET_BUCK3 BIT(2) - #define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) #define STPMIC1_LDO12356_OUTPUT_SHIFT 2 #define STPMIC1_LDO3_MODE (uint8_t)(BIT(7)) @@ -46,25 +37,29 @@ static int dt_get_pmic_node(void *fdt) return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1"); } -bool dt_check_pmic(void) +int dt_pmic_status(void) { int node; void *fdt; if (fdt_get_address(&fdt) == 0) { - return false; + return -ENOENT; } node = dt_get_pmic_node(fdt); - if (node < 0) { - VERBOSE("%s: No PMIC node found in DT\n", __func__); - return false; + if (node <= 0) { + return -FDT_ERR_NOTFOUND; } return fdt_get_status(node); } -static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) +/* + * Get PMIC and its I2C bus configuration from the device tree. + * Return 0 on success, negative on error, 1 if no PMIC node is found. + */ +static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, + struct stm32_i2c_init_s *init) { int pmic_node, i2c_node; void *fdt; @@ -76,7 +71,7 @@ static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) pmic_node = dt_get_pmic_node(fdt); if (pmic_node < 0) { - return -FDT_ERR_NOTFOUND; + return 1; } cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); @@ -99,10 +94,10 @@ static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) return -FDT_ERR_NOTFOUND; } - return dt_set_pinctrl_config(i2c_node); + return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init); } -int dt_pmic_enable_boot_on_regulators(void) +int dt_pmic_configure_boot_on_regulators(void) { int pmic_node, regulators_node, regulator_node; void *fdt; @@ -120,14 +115,40 @@ int dt_pmic_enable_boot_on_regulators(void) fdt_for_each_subnode(regulator_node, fdt, regulators_node) { const fdt32_t *cuint; - const char *node_name; + const char *node_name = fdt_get_name(fdt, regulator_node, NULL); uint16_t voltage; + int status; +#if defined(IMAGE_BL2) + if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on", + NULL) == NULL) && + (fdt_getprop(fdt, regulator_node, "regulator-always-on", + NULL) == NULL)) { +#else if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", NULL) == NULL) { +#endif continue; } + if (fdt_getprop(fdt, regulator_node, "regulator-pull-down", + NULL) != NULL) { + + status = stpmic1_regulator_pull_down_set(node_name); + if (status != 0) { + return status; + } + } + + if (fdt_getprop(fdt, regulator_node, "st,mask-reset", + NULL) != NULL) { + + status = stpmic1_regulator_mask_reset_set(node_name); + if (status != 0) { + return status; + } + } + cuint = fdt_getprop(fdt, regulator_node, "regulator-min-microvolt", NULL); if (cuint == NULL) { @@ -136,17 +157,13 @@ int dt_pmic_enable_boot_on_regulators(void) /* DT uses microvolts, whereas driver awaits millivolts */ voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); - node_name = fdt_get_name(fdt, regulator_node, NULL); + + status = stpmic1_regulator_voltage_set(node_name, voltage); + if (status != 0) { + return status; + } if (stpmic1_is_regulator_enabled(node_name) == 0U) { - int status; - - status = stpmic1_regulator_voltage_set(node_name, - voltage); - if (status != 0) { - return status; - } - status = stpmic1_regulator_enable(node_name); if (status != 0) { return status; @@ -157,77 +174,77 @@ int dt_pmic_enable_boot_on_regulators(void) return 0; } -void initialize_pmic_i2c(void) +bool initialize_pmic_i2c(void) { int ret; struct dt_node_info i2c_info; + struct i2c_handle_s *i2c = &i2c_handle; + struct stm32_i2c_init_s i2c_init; - if (dt_pmic_i2c_config(&i2c_info) != 0) { - ERROR("I2C configuration failed\n"); + ret = dt_pmic_i2c_config(&i2c_info, &i2c_init); + if (ret < 0) { + ERROR("I2C configuration failed %d\n", ret); panic(); } - if (stm32mp1_clk_enable((uint32_t)i2c_info.clock) < 0) { - ERROR("I2C clock enable failed\n"); - panic(); + if (ret != 0) { + return false; } /* Initialize PMIC I2C */ - i2c_handle.i2c_base_addr = i2c_info.base; - i2c_handle.i2c_init.timing = I2C_TIMING; - i2c_handle.i2c_init.own_address1 = pmic_i2c_addr; - i2c_handle.i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT; - i2c_handle.i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE; - i2c_handle.i2c_init.own_address2 = 0; - i2c_handle.i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK; - i2c_handle.i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE; - i2c_handle.i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE; + i2c->i2c_base_addr = i2c_info.base; + i2c->dt_status = i2c_info.status; + i2c->clock = i2c_info.clock; + i2c_init.own_address1 = pmic_i2c_addr; + i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT; + i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE; + i2c_init.own_address2 = 0; + i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK; + i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE; + i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE; + i2c_init.analog_filter = 1; + i2c_init.digital_filter_coef = 0; - ret = stm32_i2c_init(&i2c_handle); + ret = stm32_i2c_init(i2c, &i2c_init); if (ret != 0) { ERROR("Cannot initialize I2C %x (%d)\n", - i2c_handle.i2c_base_addr, ret); + i2c->i2c_base_addr, ret); panic(); } - ret = stm32_i2c_config_analog_filter(&i2c_handle, - I2C_ANALOGFILTER_ENABLE); - if (ret != 0) { - ERROR("Cannot initialize I2C analog filter (%d)\n", ret); + if (!stm32_i2c_is_device_ready(i2c, pmic_i2c_addr, 1, + I2C_TIMEOUT_BUSY_MS)) { + ERROR("I2C device not ready\n"); panic(); } - ret = stm32_i2c_is_device_ready(&i2c_handle, (uint16_t)pmic_i2c_addr, 1, - I2C_TIMEOUT); - if (ret != 0) { - ERROR("I2C device not ready (%d)\n", ret); - panic(); - } + stpmic1_bind_i2c(i2c, (uint16_t)pmic_i2c_addr); - stpmic1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr); + return true; } void initialize_pmic(void) { - int status; - uint8_t read_val; + unsigned long pmic_version; - initialize_pmic_i2c(); + if (!initialize_pmic_i2c()) { + VERBOSE("No PMIC\n"); + return; + } - status = stpmic1_register_read(VERSION_STATUS_REG, &read_val); - if (status != 0) { + if (stpmic1_get_version(&pmic_version) != 0) { + ERROR("Failed to access PMIC\n"); panic(); } - INFO("PMIC version = 0x%x\n", read_val); + INFO("PMIC version = 0x%02lx\n", pmic_version); + stpmic1_dump_regulators(); - /* Keep VDD on during the reset cycle */ - status = stpmic1_register_update(MASK_RESET_BUCK_REG, - MASK_RESET_BUCK3, - MASK_RESET_BUCK3); - if (status != 0) { +#if defined(IMAGE_BL2) + if (dt_pmic_configure_boot_on_regulators() != 0) { panic(); - } + }; +#endif } int pmic_ddr_power_init(enum ddr_type ddr_type) diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c index 465996da9..999963054 100644 --- a/drivers/st/pmic/stpmic1.c +++ b/drivers/st/pmic/stpmic1.c @@ -8,7 +8,8 @@ #include #include -#include + +#define I2C_TIMEOUT_MS 25 struct regul_struct { const char *dt_node_name; @@ -677,8 +678,9 @@ int stpmic1_regulator_voltage_get(const char *name) int stpmic1_register_read(uint8_t register_id, uint8_t *value) { return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr, - (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT, - value, 1, 100000); + (uint16_t)register_id, + I2C_MEMADD_SIZE_8BIT, value, + 1, I2C_TIMEOUT_MS); } int stpmic1_register_write(uint8_t register_id, uint8_t value) @@ -687,7 +689,8 @@ int stpmic1_register_write(uint8_t register_id, uint8_t value) status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr, (uint16_t)register_id, - I2C_MEMADD_SIZE_8BIT, &value, 1, 100000); + I2C_MEMADD_SIZE_8BIT, &value, + 1, I2C_TIMEOUT_MS); #if ENABLE_ASSERTIONS if (status != 0) { diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c index f58e10b27..fd3f93e01 100644 --- a/drivers/st/reset/stm32mp1_reset.c +++ b/drivers/st/reset/stm32mp1_reset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,32 +10,53 @@ #include #include -#include -#include +#include +#include #include #include -#define RST_CLR_OFFSET 4U +#define RESET_TIMEOUT_US_1MS U(1000) -void stm32mp1_reset_assert(uint32_t id) +static uint32_t id2reg_offset(unsigned int reset_id) { - uint32_t offset = (id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t); - uint32_t bit = id % (uint32_t)__LONG_BIT; + return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t); +} - mmio_write_32(RCC_BASE + offset, BIT(bit)); - while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) == 0U) { - ; +static uint8_t id2reg_bit_pos(unsigned int reset_id) +{ + return (uint8_t)(reset_id & GENMASK(4, 0)); +} + +void stm32mp_reset_assert(uint32_t id) +{ + uint32_t offset = id2reg_offset(id); + uint32_t bitmsk = BIT(id2reg_bit_pos(id)); + uint64_t timeout_ref; + uintptr_t rcc_base = stm32mp_rcc_base(); + + mmio_write_32(rcc_base + offset, bitmsk); + + timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS); + while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) { + if (timeout_elapsed(timeout_ref)) { + panic(); + } } } -void stm32mp1_reset_deassert(uint32_t id) +void stm32mp_reset_deassert(uint32_t id) { - uint32_t offset = ((id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t)) + - RST_CLR_OFFSET; - uint32_t bit = id % (uint32_t)__LONG_BIT; + uint32_t offset = id2reg_offset(id) + RCC_RSTCLRR_OFFSET; + uint32_t bitmsk = BIT(id2reg_bit_pos(id)); + uint64_t timeout_ref; + uintptr_t rcc_base = stm32mp_rcc_base(); - mmio_write_32(RCC_BASE + offset, BIT(bit)); - while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) != 0U) { - ; + mmio_write_32(rcc_base + offset, bitmsk); + + timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS); + while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) { + if (timeout_elapsed(timeout_ref)) { + panic(); + } } } diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi new file mode 100644 index 000000000..16b8cf623 --- /dev/null +++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ +/* STM32MP157C DK1/DK2 BOARD configuration + * 1x DDR3L 4Gb, 16-bit, 533MHz. + * Reference used NT5CC256M16DP-DI from NANYA + * + * DDR type / Platform DDR3/3L + * freq 533MHz + * width 16 + * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G + * DDR density 4 + * timing mode optimized + * Scheduling/QoS options : type = 2 + * address mapping : RBC + * Tc > + 85C : N + */ + +#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.41" +#define DDR_MEM_SPEED 533000 +#define DDR_MEM_SIZE 0x20000000 + +#define DDR_MSTR 0x00041401 +#define DDR_MRCTRL0 0x00000010 +#define DDR_MRCTRL1 0x00000000 +#define DDR_DERATEEN 0x00000000 +#define DDR_DERATEINT 0x00800000 +#define DDR_PWRCTL 0x00000000 +#define DDR_PWRTMG 0x00400010 +#define DDR_HWLPCTL 0x00000000 +#define DDR_RFSHCTL0 0x00210000 +#define DDR_RFSHCTL3 0x00000000 +#define DDR_RFSHTMG 0x0081008B +#define DDR_CRCPARCTL0 0x00000000 +#define DDR_DRAMTMG0 0x121B2414 +#define DDR_DRAMTMG1 0x000A041C +#define DDR_DRAMTMG2 0x0608090F +#define DDR_DRAMTMG3 0x0050400C +#define DDR_DRAMTMG4 0x08040608 +#define DDR_DRAMTMG5 0x06060403 +#define DDR_DRAMTMG6 0x02020002 +#define DDR_DRAMTMG7 0x00000202 +#define DDR_DRAMTMG8 0x00001005 +#define DDR_DRAMTMG14 0x000000A0 +#define DDR_ZQCTL0 0xC2000040 +#define DDR_DFITMG0 0x02060105 +#define DDR_DFITMG1 0x00000202 +#define DDR_DFILPCFG0 0x07000000 +#define DDR_DFIUPD0 0xC0400003 +#define DDR_DFIUPD1 0x00000000 +#define DDR_DFIUPD2 0x00000000 +#define DDR_DFIPHYMSTR 0x00000000 +#define DDR_ADDRMAP1 0x00070707 +#define DDR_ADDRMAP2 0x00000000 +#define DDR_ADDRMAP3 0x1F000000 +#define DDR_ADDRMAP4 0x00001F1F +#define DDR_ADDRMAP5 0x06060606 +#define DDR_ADDRMAP6 0x0F060606 +#define DDR_ADDRMAP9 0x00000000 +#define DDR_ADDRMAP10 0x00000000 +#define DDR_ADDRMAP11 0x00000000 +#define DDR_ODTCFG 0x06000600 +#define DDR_ODTMAP 0x00000001 +#define DDR_SCHED 0x00000C01 +#define DDR_SCHED1 0x00000000 +#define DDR_PERFHPR1 0x01000001 +#define DDR_PERFLPR1 0x08000200 +#define DDR_PERFWR1 0x08000400 +#define DDR_DBG0 0x00000000 +#define DDR_DBG1 0x00000000 +#define DDR_DBGCMD 0x00000000 +#define DDR_POISONCFG 0x00000000 +#define DDR_PCCFG 0x00000010 +#define DDR_PCFGR_0 0x00010000 +#define DDR_PCFGW_0 0x00000000 +#define DDR_PCFGQOS0_0 0x02100C03 +#define DDR_PCFGQOS1_0 0x00800100 +#define DDR_PCFGWQOS0_0 0x01100C03 +#define DDR_PCFGWQOS1_0 0x01000200 +#define DDR_PCFGR_1 0x00010000 +#define DDR_PCFGW_1 0x00000000 +#define DDR_PCFGQOS0_1 0x02100C03 +#define DDR_PCFGQOS1_1 0x00800040 +#define DDR_PCFGWQOS0_1 0x01100C03 +#define DDR_PCFGWQOS1_1 0x01000200 +#define DDR_PGCR 0x01442E02 +#define DDR_PTR0 0x0022AA5B +#define DDR_PTR1 0x04841104 +#define DDR_PTR2 0x042DA068 +#define DDR_ACIOCR 0x10400812 +#define DDR_DXCCR 0x00000C40 +#define DDR_DSGCR 0xF200001F +#define DDR_DCR 0x0000000B +#define DDR_DTPR0 0x38D488D0 +#define DDR_DTPR1 0x098B00D8 +#define DDR_DTPR2 0x10023600 +#define DDR_MR0 0x00000840 +#define DDR_MR1 0x00000000 +#define DDR_MR2 0x00000208 +#define DDR_MR3 0x00000000 +#define DDR_ODTCR 0x00010000 +#define DDR_ZQ0CR1 0x00000038 +#define DDR_DX0GCR 0x0000CE81 +#define DDR_DX0DLLCR 0x40000000 +#define DDR_DX0DQTR 0xFFFFFFFF +#define DDR_DX0DQSTR 0x3DB02000 +#define DDR_DX1GCR 0x0000CE81 +#define DDR_DX1DLLCR 0x40000000 +#define DDR_DX1DQTR 0xFFFFFFFF +#define DDR_DX1DQSTR 0x3DB02000 +#define DDR_DX2GCR 0x0000CE81 +#define DDR_DX2DLLCR 0x40000000 +#define DDR_DX2DQTR 0xFFFFFFFF +#define DDR_DX2DQSTR 0x3DB02000 +#define DDR_DX3GCR 0x0000CE81 +#define DDR_DX3DLLCR 0x40000000 +#define DDR_DX3DQTR 0xFFFFFFFF +#define DDR_DX3DQSTR 0x3DB02000 + +#include "stm32mp15-ddr.dtsi" diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts new file mode 100644 index 000000000..0314171f5 --- /dev/null +++ b/fdts/stm32mp157a-dk1.dts @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018-2019 - All Rights Reserved + * Author: Alexandre Torgue . + */ + +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157cac-pinctrl.dtsi" + +/ { + model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; + compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + +}; + +&clk_hse { + st,digbypass; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; + status = "okay"; + + pmic: stpmic@33 { + compatible = "st,stpmic1"; + reg = <0x33>; + interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; + st,usb-control-register = <0x20>; + + regulators { + compatible = "st,stpmic1-regulators"; + + ldo1-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; + ldo6-supply = <&v3v3>; + + vddcore: buck1 { + regulator-name = "vddcore"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + vdd_ddr: buck2 { + regulator-name = "vdd_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + vdd: buck3 { + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + st,mask-reset; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + v3v3: buck4 { + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-over-current-protection; + regulator-initial-mode = <0>; + }; + + v1v8_audio: ldo1 { + regulator-name = "v1v8_audio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + v3v3_hdmi: ldo2 { + regulator-name = "v3v3_hdmi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <750000>; + regulator-always-on; + regulator-over-current-protection; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vdda: ldo5 { + regulator-name = "vdda"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + regulator-boot-on; + }; + + v1v2_hdmi: ldo6 { + regulator-name = "v1v2_hdmi"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; + regulator-over-current-protection; + }; + }; + }; +}; + +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + +&rng1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&sdmmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + broken-cd; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_a>; + status = "okay"; +}; + +/* ATF Specific */ +#include +#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi" + +/ { + aliases { + gpio0 = &gpioa; + gpio1 = &gpiob; + gpio2 = &gpioc; + gpio3 = &gpiod; + gpio4 = &gpioe; + gpio5 = &gpiof; + gpio6 = &gpiog; + gpio7 = &gpioh; + gpio8 = &gpioi; + gpio25 = &gpioz; + i2c3 = &i2c4; + }; + + soc { + stgen: stgen@5C008000 { + compatible = "st,stm32-stgen"; + reg = <0x5C008000 0x1000>; + status = "okay"; + }; + }; +}; + +/* CLOCK init */ +&rcc { + secure-status = "disabled"; + st,clksrc = < + CLK_MPU_PLL1P + CLK_AXI_PLL2P + CLK_PLL12_HSE + CLK_PLL3_HSE + CLK_PLL4_HSE + CLK_RTC_LSE + CLK_MCO1_DISABLED + CLK_MCO2_DISABLED + >; + + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ + 1 /*APB4*/ + 2 /*APB5*/ + 23 /*RTC*/ + 0 /*MCO1*/ + 0 /*MCO2*/ + >; + + st,pkcs = < + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK + CLK_ETH_DISABLED + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE + CLK_USBPHY_HSE + CLK_SPI2S1_PLL3Q + CLK_SPI2S23_PLL3Q + CLK_SPI45_HSI + CLK_SPI6_HSI + CLK_I2C46_HSI + CLK_SDMMC3_PLL4P + CLK_USBO_USBPHY + CLK_ADC_CKPER + CLK_CEC_LSE + CLK_I2C12_HSI + CLK_I2C35_HSI + CLK_UART1_HSI + CLK_UART24_HSI + CLK_UART35_HSI + CLK_UART6_HSI + CLK_UART78_HSI + CLK_SPDIF_PLL4P + CLK_FDCAN_PLL4Q + CLK_SAI1_PLL3Q + CLK_SAI2_PLL3Q + CLK_SAI3_PLL3Q + CLK_SAI4_PLL3Q + CLK_RNG1_LSI + CLK_RNG2_LSI + CLK_LPTIM1_PCLK1 + CLK_LPTIM23_PCLK3 + CLK_LPTIM45_LSE + >; + + /* VCO = 1300.0 MHz => P = 650 (CPU) */ + pll1: st,pll@0 { + cfg = < 2 80 0 0 0 PQR(1,0,0) >; + frac = < 0x800 >; + }; + + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; + frac = < 0x1400 >; + }; + + /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ + pll3: st,pll@2 { + cfg = < 1 33 1 16 36 PQR(1,1,1) >; + frac = < 0x1a04 >; + }; + + /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ + pll4: st,pll@3 { + cfg = < 3 98 5 7 7 PQR(1,1,1) >; + }; +}; diff --git a/fdts/stm32mp157c-dk2.dts b/fdts/stm32mp157c-dk2.dts new file mode 100644 index 000000000..fdcf4c802 --- /dev/null +++ b/fdts/stm32mp157c-dk2.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue . + */ + +/dts-v1/; + +#include "stm32mp157a-dk1.dts" + +/ { + model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; + compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; + +}; + diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts index a97e8053b..5d8817f69 100644 --- a/fdts/stm32mp157c-ed1.dts +++ b/fdts/stm32mp157c-ed1.dts @@ -55,7 +55,7 @@ vddcore: buck1 { regulator-name = "vddcore"; - regulator-min-microvolt = <800000>; + regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; diff --git a/fdts/stm32mp157cac-pinctrl.dtsi b/fdts/stm32mp157cac-pinctrl.dtsi new file mode 100644 index 000000000..777f9919d --- /dev/null +++ b/fdts/stm32mp157cac-pinctrl.dtsi @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue + */ + +#include "stm32mp157-pinctrl.dtsi" +/ { + soc { + pinctrl: pin-controller@50002000 { + st,package = ; + + gpioa: gpio@50002000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 80 16>; + }; + + gpiog: gpio@50008000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 96 16>; + }; + + gpioh: gpio@50009000 { + status = "okay"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 112 16>; + }; + + gpioi: gpio@5000a000 { + status = "okay"; + ngpios = <12>; + gpio-ranges = <&pinctrl 0 128 12>; + }; + }; + + pinctrl_z: pin-controller-z@54004000 { + st,package = ; + + gpioz: gpio@54004000 { + status = "okay"; + ngpios = <8>; + gpio-ranges = <&pinctrl_z 0 400 8>; + }; + }; + }; +}; diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h index de2ca59c8..170d4cf81 100644 --- a/include/drivers/st/stm32_i2c.h +++ b/include/drivers/st/stm32_i2c.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -111,94 +111,113 @@ #define I2C_ICR_TIMOUTCF BIT(12) #define I2C_ICR_ALERTCF BIT(13) +enum i2c_speed_e { + I2C_SPEED_STANDARD, /* 100 kHz */ + I2C_SPEED_FAST, /* 400 kHz */ + I2C_SPEED_FAST_PLUS, /* 1 MHz */ +}; + +#define STANDARD_RATE 100000 +#define FAST_RATE 400000 +#define FAST_PLUS_RATE 1000000 + struct stm32_i2c_init_s { - uint32_t timing; /* Specifies the I2C_TIMINGR_register value - * This parameter is calculated by referring - * to I2C initialization section in Reference - * manual. - */ + uint32_t own_address1; /* + * Specifies the first device own + * address. This parameter can be a + * 7-bit or 10-bit address. + */ - uint32_t own_address1; /* Specifies the first device own address. - * This parameter can be a 7-bit or 10-bit - * address. - */ + uint32_t addressing_mode; /* + * Specifies if 7-bit or 10-bit + * addressing mode is selected. + * This parameter can be a value of + * @ref I2C_ADDRESSING_MODE. + */ - uint32_t addressing_mode; /* Specifies if 7-bit or 10-bit addressing - * mode is selected. - * This parameter can be a value of @ref - * I2C_ADDRESSING_MODE. - */ + uint32_t dual_address_mode; /* + * Specifies if dual addressing mode is + * selected. + * This parameter can be a value of @ref + * I2C_DUAL_ADDRESSING_MODE. + */ - uint32_t dual_address_mode; /* Specifies if dual addressing mode is - * selected. - * This parameter can be a value of @ref - * I2C_DUAL_ADDRESSING_MODE. - */ + uint32_t own_address2; /* + * Specifies the second device own + * address if dual addressing mode is + * selected. This parameter can be a + * 7-bit address. + */ - uint32_t own_address2; /* Specifies the second device own address - * if dual addressing mode is selected. - * This parameter can be a 7-bit address. - */ + uint32_t own_address2_masks; /* + * Specifies the acknowledge mask + * address second device own address + * if dual addressing mode is selected + * This parameter can be a value of @ref + * I2C_OWN_ADDRESS2_MASKS. + */ - uint32_t own_address2_masks; /* Specifies the acknowledge mask address - * second device own address if dual - * addressing mode is selected. - * This parameter can be a value of @ref - * I2C_OWN_ADDRESS2_MASKS. - */ + uint32_t general_call_mode; /* + * Specifies if general call mode is + * selected. + * This parameter can be a value of @ref + * I2C_GENERAL_CALL_ADDRESSING_MODE. + */ - uint32_t general_call_mode; /* Specifies if general call mode is - * selected. - * This parameter can be a value of @ref - * I2C_GENERAL_CALL_ADDRESSING_MODE. - */ + uint32_t no_stretch_mode; /* + * Specifies if nostretch mode is + * selected. + * This parameter can be a value of @ref + * I2C_NOSTRETCH_MODE. + */ - uint32_t no_stretch_mode; /* Specifies if nostretch mode is - * selected. - * This parameter can be a value of @ref - * I2C_NOSTRETCH_MODE. - */ + uint32_t rise_time; /* + * Specifies the SCL clock pin rising + * time in nanoseconds. + */ + uint32_t fall_time; /* + * Specifies the SCL clock pin falling + * time in nanoseconds. + */ + + enum i2c_speed_e speed_mode; /* + * Specifies the I2C clock source + * frequency mode. + * This parameter can be a value of @ref + * i2c_speed_mode_e. + */ + + int analog_filter; /* + * Specifies if the I2C analog noise + * filter is selected. + * This parameter can be 0 (filter + * off), all other values mean filter + * on. + */ + + uint8_t digital_filter_coef; /* + * Specifies the I2C digital noise + * filter coefficient. + * This parameter can be a value + * between 0 and + * STM32_I2C_DIGITAL_FILTER_MAX. + */ }; enum i2c_state_e { - I2C_STATE_RESET = 0x00U, /* Peripheral is not yet - * initialized. - */ - I2C_STATE_READY = 0x20U, /* Peripheral Initialized - * and ready for use. - */ - I2C_STATE_BUSY = 0x24U, /* An internal process is - * ongoing. - */ - I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission process - * is ongoing. - */ - I2C_STATE_BUSY_RX = 0x22U, /* Data Reception process - * is ongoing. - */ - I2C_STATE_LISTEN = 0x28U, /* Address Listen Mode is - * ongoing. - */ - I2C_STATE_BUSY_TX_LISTEN = 0x29U, /* Address Listen Mode - * and Data Transmission - * process is ongoing. - */ - I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /* Address Listen Mode - * and Data Reception - * process is ongoing. - */ - I2C_STATE_ABORT = 0x60U, /* Abort user request ongoing. */ - I2C_STATE_TIMEOUT = 0xA0U, /* Timeout state. */ - I2C_STATE_ERROR = 0xE0U /* Error. */ - + I2C_STATE_RESET = 0x00U, /* Not yet initialized */ + I2C_STATE_READY = 0x20U, /* Ready for use */ + I2C_STATE_BUSY = 0x24U, /* Internal process ongoing */ + I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission ongoing */ + I2C_STATE_BUSY_RX = 0x22U, /* Data Reception ongoing */ }; enum i2c_mode_e { - I2C_MODE_NONE = 0x00U, /* No I2C communication on going. */ - I2C_MODE_MASTER = 0x10U, /* I2C communication is in Master Mode. */ - I2C_MODE_SLAVE = 0x20U, /* I2C communication is in Slave Mode. */ - I2C_MODE_MEM = 0x40U /* I2C communication is in Memory Mode. */ + I2C_MODE_NONE = 0x00U, /* No active communication */ + I2C_MODE_MASTER = 0x10U, /* Communication in Master Mode */ + I2C_MODE_SLAVE = 0x20U, /* Communication in Slave Mode */ + I2C_MODE_MEM = 0x40U /* Communication in Memory Mode */ }; @@ -213,26 +232,12 @@ enum i2c_mode_e { struct i2c_handle_s { uint32_t i2c_base_addr; /* Registers base address */ - - struct stm32_i2c_init_s i2c_init; /* Communication parameters */ - - uint8_t *p_buff; /* Pointer to transfer buffer */ - - uint16_t xfer_size; /* Transfer size */ - - uint16_t xfer_count; /* Transfer counter */ - - uint32_t prev_state; /* Communication previous - * state - */ - - uint8_t lock; /* Locking object */ - - enum i2c_state_e i2c_state; /* Communication state */ - - enum i2c_mode_e i2c_mode; /* Communication mode */ - - uint32_t i2c_err; /* Error code */ + unsigned int dt_status; /* DT nsec/sec status */ + unsigned int clock; /* Clock reference */ + uint8_t lock; /* Locking object */ + enum i2c_state_e i2c_state; /* Communication state */ + enum i2c_mode_e i2c_mode; /* Communication mode */ + uint32_t i2c_err; /* Error code */ }; #define I2C_ADDRESSINGMODE_7BIT 0x00000001U @@ -250,15 +255,15 @@ struct i2c_handle_s { #define I2C_MEMADD_SIZE_8BIT 0x00000001U #define I2C_MEMADD_SIZE_16BIT 0x00000002U -#define I2C_RELOAD_MODE I2C_CR2_RELOAD -#define I2C_AUTOEND_MODE I2C_CR2_AUTOEND -#define I2C_SOFTEND_MODE 0x00000000U +#define I2C_RELOAD_MODE I2C_CR2_RELOAD +#define I2C_AUTOEND_MODE I2C_CR2_AUTOEND +#define I2C_SOFTEND_MODE 0x00000000U -#define I2C_NO_STARTSTOP 0x00000000U -#define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP) -#define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \ +#define I2C_NO_STARTSTOP 0x00000000U +#define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP) +#define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \ I2C_CR2_RD_WRN) -#define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START) +#define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START) #define I2C_FLAG_TXE I2C_ISR_TXE #define I2C_FLAG_TXIS I2C_ISR_TXIS @@ -281,21 +286,36 @@ struct i2c_handle_s { I2C_CR2_NBYTES | I2C_CR2_RELOAD | \ I2C_CR2_RD_WRN) -#define I2C_ANALOGFILTER_ENABLE ((uint32_t)0x00000000U) +#define I2C_TIMEOUT_BUSY_MS 25U + +#define I2C_ANALOGFILTER_ENABLE 0x00000000U #define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF -int stm32_i2c_init(struct i2c_handle_s *hi2c); +/* STM32 specific defines */ +#define STM32_I2C_RISE_TIME_DEFAULT 25 /* ns */ +#define STM32_I2C_FALL_TIME_DEFAULT 10 /* ns */ +#define STM32_I2C_SPEED_DEFAULT I2C_SPEED_STANDARD +#define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ +#define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ +#define STM32_I2C_DIGITAL_FILTER_MAX 16 +int stm32_i2c_get_setup_from_fdt(void *fdt, int node, + struct stm32_i2c_init_s *init); +int stm32_i2c_init(struct i2c_handle_s *hi2c, + struct stm32_i2c_init_s *init_data); int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint16_t mem_addr, uint16_t mem_add_size, - uint8_t *p_data, uint16_t size, uint32_t timeout); + uint8_t *p_data, uint16_t size, uint32_t timeout_ms); int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint16_t mem_addr, uint16_t mem_add_size, - uint8_t *p_data, uint16_t size, uint32_t timeout); -int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, - uint32_t trials, uint32_t timeout); - -int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, - uint32_t analog_filter); + uint8_t *p_data, uint16_t size, uint32_t timeout_ms); +int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint8_t *p_data, uint16_t size, + uint32_t timeout_ms); +int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint8_t *p_data, uint16_t size, + uint32_t timeout_ms); +bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint32_t trials, uint32_t timeout_ms); #endif /* STM32_I2C_H */ diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h index 5594e2327..1e0d949ac 100644 --- a/include/drivers/st/stm32mp1_clk.h +++ b/include/drivers/st/stm32mp1_clk.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,25 +7,42 @@ #ifndef STM32MP1_CLK_H #define STM32MP1_CLK_H -#include - #include int stm32mp1_clk_probe(void); int stm32mp1_clk_init(void); -bool stm32mp1_clk_is_enabled(unsigned long id); -int stm32mp1_clk_enable(unsigned long id); -int stm32mp1_clk_disable(unsigned long id); -unsigned long stm32mp1_clk_get_rate(unsigned long id); -void stm32mp1_stgen_increment(unsigned long long offset_in_ms); -static inline uint32_t get_timer(uint32_t base) +bool stm32mp1_rcc_is_secure(void); + +void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure); +void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure); + +static inline void stm32mp1_clk_enable_non_secure(unsigned long id) { - if (base == 0U) { - return (uint32_t)(~read_cntpct_el0()); - } - - return base - (uint32_t)(~read_cntpct_el0()); + __stm32mp1_clk_enable(id, false); } +static inline void stm32mp1_clk_enable_secure(unsigned long id) +{ + __stm32mp1_clk_enable(id, true); +} + +static inline void stm32mp1_clk_disable_non_secure(unsigned long id) +{ + __stm32mp1_clk_disable(id, false); +} + +static inline void stm32mp1_clk_disable_secure(unsigned long id) +{ + __stm32mp1_clk_disable(id, true); +} + +unsigned int stm32mp1_clk_get_refcount(unsigned long id); + +/* SMP protection on RCC registers access */ +void stm32mp1_clk_rcc_regs_lock(void); +void stm32mp1_clk_rcc_regs_unlock(void); + +void stm32mp1_stgen_increment(unsigned long long offset_in_ms); + #endif /* STM32MP1_CLK_H */ diff --git a/include/drivers/st/stm32mp1_clkfunc.h b/include/drivers/st/stm32mp1_clkfunc.h index 106dcae01..f30393734 100644 --- a/include/drivers/st/stm32mp1_clkfunc.h +++ b/include/drivers/st/stm32mp1_clkfunc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,7 +18,6 @@ enum stm32mp_osc_id { _LSI, _LSE, _I2S_CKIN, - _USB_PHY_48, NB_OSC, _UNKNOWN_OSC_ID = 0xFF }; @@ -31,14 +30,4 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, const char *prop_name, uint32_t dflt_value); -uint32_t fdt_rcc_read_addr(void); -int fdt_rcc_read_uint32_array(const char *prop_name, - uint32_t *array, uint32_t count); -int fdt_rcc_subnode_offset(const char *name); -const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp); -bool fdt_get_rcc_secure_status(void); - -uintptr_t fdt_get_stgen_base(void); -int fdt_get_clock_id(int node); - #endif /* STM32MP1_CLKFUNC_H */ diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h index 2f29e84d5..1922c4815 100644 --- a/include/drivers/st/stm32mp1_rcc.h +++ b/include/drivers/st/stm32mp1_rcc.h @@ -280,6 +280,9 @@ /* Offset between RCC_MP_xxxENSETR and RCC_MP_xxxENCLRR registers */ #define RCC_MP_ENCLRR_OFFSET U(4) +/* Offset between RCC_xxxRSTSETR and RCC_xxxRSTCLRR registers */ +#define RCC_RSTCLRR_OFFSET U(4) + /* Fields of RCC_BDCR register */ #define RCC_BDCR_LSEON BIT(0) #define RCC_BDCR_LSEBYP BIT(1) diff --git a/include/drivers/st/stm32mp1_reset.h b/include/drivers/st/stm32mp1_reset.h deleted file mode 100644 index cd488cc33..000000000 --- a/include/drivers/st/stm32mp1_reset.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018, STMicroelectronics - All Rights Reserved - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef STM32MP1_RESET_H -#define STM32MP1_RESET_H - -#include - -void stm32mp1_reset_assert(uint32_t reset_id); -void stm32mp1_reset_deassert(uint32_t reset_id); - -#endif /* STM32MP1_RESET_H */ diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h new file mode 100644 index 000000000..5beb06bb2 --- /dev/null +++ b/include/drivers/st/stm32mp_clkfunc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_CLKFUNC_H +#define STM32MP_CLKFUNC_H + +#include + +#include + +int fdt_get_rcc_node(void *fdt); +uint32_t fdt_rcc_read_addr(void); +int fdt_rcc_read_uint32_array(const char *prop_name, + uint32_t *array, uint32_t count); +int fdt_rcc_subnode_offset(const char *name); +const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp); +bool fdt_get_rcc_secure_status(void); + +uintptr_t fdt_get_stgen_base(void); +int fdt_get_clock_id(int node); + +#endif /* STM32MP_CLKFUNC_H */ diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h index 700039b26..984cd6014 100644 --- a/include/drivers/st/stm32mp_pmic.h +++ b/include/drivers/st/stm32mp_pmic.h @@ -11,10 +11,41 @@ #include -bool dt_check_pmic(void); -int dt_pmic_enable_boot_on_regulators(void); -void initialize_pmic_i2c(void); +/* + * dt_pmic_status - Check PMIC status from device tree + * + * Returns the status of the PMIC (secure, non-secure), or a negative value on + * error + */ +int dt_pmic_status(void); + +/* + * dt_pmic_configure_boot_on_regulators - Configure boot-on and always-on + * regulators from device tree configuration + * + * Returns 0 on success, and negative values on errors + */ +int dt_pmic_configure_boot_on_regulators(void); + +/* + * initialize_pmic_i2c - Initialize I2C for the PMIC control + * + * Returns true if PMIC is available, false if not found, panics on errors + */ +bool initialize_pmic_i2c(void); + +/* + * initialize_pmic - Main PMIC initialization function, called at platform init + * + * Panics on errors + */ void initialize_pmic(void); + +/* + * pmic_ddr_power_init - Initialize regulators required for DDR + * + * Returns 0 on success, and negative values on errors + */ int pmic_ddr_power_init(enum ddr_type ddr_type); #endif /* STM32MP_PMIC_H */ diff --git a/include/drivers/st/stm32mp_reset.h b/include/drivers/st/stm32mp_reset.h new file mode 100644 index 000000000..2da5adf44 --- /dev/null +++ b/include/drivers/st/stm32mp_reset.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_RESET_H +#define STM32MP_RESET_H + +#include + +void stm32mp_reset_assert(uint32_t reset_id); +void stm32mp_reset_deassert(uint32_t reset_id); + +#endif /* STM32MP_RESET_H */ diff --git a/plat/st/stm32mp1/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c similarity index 93% rename from plat/st/stm32mp1/bl2_io_storage.c rename to plat/st/common/bl2_io_storage.c index 8ccbc246c..c8bb559f4 100644 --- a/plat/st/stm32mp1/bl2_io_storage.c +++ b/plat/st/common/bl2_io_storage.c @@ -20,14 +20,10 @@ #include #include #include -#include #include #include #include -#include -#include - /* IO devices */ static const io_dev_connector_t *dummy_dev_con; static uintptr_t dummy_dev_handle; @@ -60,12 +56,12 @@ static const io_dev_connector_t *mmc_dev_con; static const io_block_spec_t bl32_block_spec = { .offset = BL32_BASE, - .length = STM32MP1_BL32_SIZE + .length = STM32MP_BL32_SIZE }; static const io_block_spec_t bl2_block_spec = { .offset = BL2_BASE, - .length = STM32MP1_BL2_SIZE, + .length = STM32MP_BL2_SIZE, }; static const struct stm32image_part_info bl33_partition_spec = { @@ -166,7 +162,7 @@ static void print_boot_device(boot_api_context_t *boot_context) } } -void stm32mp1_io_setup(void) +void stm32mp_io_setup(void) { int io_result __unused; uint8_t idx; @@ -176,7 +172,7 @@ void stm32mp1_io_setup(void) uintptr_t mmc_default_instance; const partition_entry_t *entry; boot_api_context_t *boot_context = - (boot_api_context_t *)stm32mp1_get_boot_ctx_address(); + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); print_boot_device(boot_context); @@ -203,21 +199,21 @@ void stm32mp1_io_setup(void) if (boot_context->boot_interface_selected == BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC) { device_info.mmc_dev_type = MMC_IS_EMMC; - mmc_default_instance = STM32MP1_SDMMC2_BASE; + mmc_default_instance = STM32MP_SDMMC2_BASE; } else { device_info.mmc_dev_type = MMC_IS_SD; - mmc_default_instance = STM32MP1_SDMMC1_BASE; + mmc_default_instance = STM32MP_SDMMC1_BASE; } switch (boot_context->boot_interface_instance) { case 1: - params.reg_base = STM32MP1_SDMMC1_BASE; + params.reg_base = STM32MP_SDMMC1_BASE; break; case 2: - params.reg_base = STM32MP1_SDMMC2_BASE; + params.reg_base = STM32MP_SDMMC2_BASE; break; case 3: - params.reg_base = STM32MP1_SDMMC3_BASE; + params.reg_base = STM32MP_SDMMC3_BASE; break; default: WARN("SDMMC instance not found, using default\n"); diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h new file mode 100644 index 000000000..4bbc4dba5 --- /dev/null +++ b/plat/st/common/include/stm32mp_common.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2018-2019, Linaro Limited + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_COMMON_H +#define STM32MP_COMMON_H + +#include + +#include + +/* Functions to save and get boot context address given by ROM code */ +void stm32mp_save_boot_ctx_address(uintptr_t address); +uintptr_t stm32mp_get_boot_ctx_address(void); + +/* Return the base address of the DDR controller */ +uintptr_t stm32mp_ddrctrl_base(void); + +/* Return the base address of the DDR PHY */ +uintptr_t stm32mp_ddrphyc_base(void); + +/* Return the base address of the PWR peripheral */ +uintptr_t stm32mp_pwr_base(void); + +/* Return the base address of the RCC peripheral */ +uintptr_t stm32mp_rcc_base(void); + +/* + * Platform util functions for the GPIO driver + * @bank: Target GPIO bank ID as per DT bindings + * + * Platform shall implement these functions to provide to stm32_gpio + * driver the resource reference for a target GPIO bank. That are + * memory mapped interface base address, interface offset (see below) + * and clock identifier. + * + * stm32_get_gpio_bank_offset() returns a bank offset that is used to + * check DT configuration matches platform implementation of the banks + * description. + */ +uintptr_t stm32_get_gpio_bank_base(unsigned int bank); +unsigned long stm32_get_gpio_bank_clock(unsigned int bank); +uint32_t stm32_get_gpio_bank_offset(unsigned int bank); + +/* + * Util for clock gating and to get clock rate for stm32 and platform drivers + * @id: Target clock ID, ID used in clock DT bindings + */ +bool stm32mp_clk_is_enabled(unsigned long id); +void stm32mp_clk_enable(unsigned long id); +void stm32mp_clk_disable(unsigned long id); +unsigned long stm32mp_clk_get_rate(unsigned long id); + +/* Initialise the IO layer and register platform IO devices */ +void stm32mp_io_setup(void); + +static inline uint64_t arm_cnt_us2cnt(uint32_t us) +{ + return ((uint64_t)us * (uint64_t)read_cntfrq()) / 1000000ULL; +} + +static inline uint64_t timeout_init_us(uint32_t us) +{ + return read_cntpct_el0() + arm_cnt_us2cnt(us); +} + +static inline bool timeout_elapsed(uint64_t expire) +{ + return read_cntpct_el0() > expire; +} + +#endif /* STM32MP_COMMON_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_dt.h b/plat/st/common/include/stm32mp_dt.h similarity index 85% rename from plat/st/stm32mp1/include/stm32mp1_dt.h rename to plat/st/common/include/stm32mp_dt.h index d5640c1fd..3415b051d 100644 --- a/plat/st/stm32mp1/include/stm32mp1_dt.h +++ b/plat/st/common/include/stm32mp_dt.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef STM32MP1_DT_H -#define STM32MP1_DT_H +#ifndef STM32MP_DT_H +#define STM32MP_DT_H #include @@ -27,7 +27,7 @@ struct dt_node_info { int dt_open_and_check(void); int fdt_get_address(void **fdt_addr); bool fdt_check_node(int node); -uint32_t fdt_get_status(int node); +uint8_t fdt_get_status(int node); uint32_t fdt_read_uint32_default(int node, const char *prop_name, uint32_t dflt_value); int fdt_read_uint32_array(int node, const char *prop_name, @@ -38,6 +38,9 @@ int dt_get_node(struct dt_node_info *info, int offset, const char *compat); int dt_get_stdout_uart_info(struct dt_node_info *info); int dt_get_stdout_node_offset(void); uint32_t dt_get_ddr_size(void); +uintptr_t dt_get_ddrctrl_base(void); +uintptr_t dt_get_ddrphyc_base(void); +uintptr_t dt_get_pwr_base(void); const char *dt_get_board_model(void); -#endif /* STM32MP1_DT_H */ +#endif /* STM32MP_DT_H */ diff --git a/plat/st/common/include/stm32mp_shres_helpers.h b/plat/st/common/include/stm32mp_shres_helpers.h new file mode 100644 index 000000000..8b786cc04 --- /dev/null +++ b/plat/st/common/include/stm32mp_shres_helpers.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_SHRES_HELPERS_H +#define STM32MP_SHRES_HELPERS_H + +#include + +#include + +/* + * Shared reference counter: increments by 2 on secure increment + * request, decrements by 2 on secure decrement request. Bit #0 + * is set to 1 on non-secure increment request and reset to 0 on + * non-secure decrement request. The counter initializes to + * either 0, 1 or 2 upon their expect default state. + * Counters saturates once above UINT_MAX / 2. + */ +#define SHREFCNT_NONSECURE_FLAG 0x1UL +#define SHREFCNT_SECURE_STEP 0x2UL +#define SHREFCNT_MAX (UINT32_MAX / 2) + +/* Return 1 if refcnt increments from 0, else return 0 */ +static inline int stm32mp_incr_shrefcnt(unsigned int *refcnt, bool secure) +{ + int rc = !*refcnt; + + if (secure) { + *refcnt += SHREFCNT_SECURE_STEP; + if (*refcnt >= SHREFCNT_MAX) { + panic(); + } + } else { + *refcnt |= SHREFCNT_NONSECURE_FLAG; + } + + return rc; +} + +/* Return 1 if refcnt decrements to 0, else return 0 */ +static inline int stm32mp_decr_shrefcnt(unsigned int *refcnt, bool secure) +{ + int rc = 0; + + if (secure) { + if (*refcnt < SHREFCNT_MAX) { + if (*refcnt < SHREFCNT_SECURE_STEP) { + panic(); + } + *refcnt -= SHREFCNT_SECURE_STEP; + rc = !*refcnt; + } + } else { + rc = (*refcnt == SHREFCNT_NONSECURE_FLAG) ? 1 : 0; + *refcnt &= ~SHREFCNT_NONSECURE_FLAG; + } + + return rc; +} + +static inline int stm32mp_incr_refcnt(unsigned int *refcnt) +{ + return stm32mp_incr_shrefcnt(refcnt, true); +} + +static inline int stm32mp_decr_refcnt(unsigned int *refcnt) +{ + return stm32mp_decr_shrefcnt(refcnt, true); +} + +#endif /* STM32MP_SHRES_HELPERS_H */ diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c new file mode 100644 index 000000000..2aba41e54 --- /dev/null +++ b/plat/st/common/stm32mp_common.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include +#include +#include +#include + +uintptr_t plat_get_ns_image_entrypoint(void) +{ + return BL33_BASE; +} + +unsigned int plat_get_syscnt_freq2(void) +{ + return read_cntfrq_el0(); +} + +static uintptr_t boot_ctx_address; + +void stm32mp_save_boot_ctx_address(uintptr_t address) +{ + boot_ctx_address = address; +} + +uintptr_t stm32mp_get_boot_ctx_address(void) +{ + return boot_ctx_address; +} + +uintptr_t stm32mp_ddrctrl_base(void) +{ + static uintptr_t ddrctrl_base; + + if (ddrctrl_base == 0) { + ddrctrl_base = dt_get_ddrctrl_base(); + + assert(ddrctrl_base == DDRCTRL_BASE); + } + + return ddrctrl_base; +} + +uintptr_t stm32mp_ddrphyc_base(void) +{ + static uintptr_t ddrphyc_base; + + if (ddrphyc_base == 0) { + ddrphyc_base = dt_get_ddrphyc_base(); + + assert(ddrphyc_base == DDRPHYC_BASE); + } + + return ddrphyc_base; +} + +uintptr_t stm32mp_pwr_base(void) +{ + static uintptr_t pwr_base; + + if (pwr_base == 0) { + pwr_base = dt_get_pwr_base(); + + assert(pwr_base == PWR_BASE); + } + + return pwr_base; +} + +uintptr_t stm32mp_rcc_base(void) +{ + static uintptr_t rcc_base; + + if (rcc_base == 0) { + rcc_base = fdt_rcc_read_addr(); + + assert(rcc_base == RCC_BASE); + } + + return rcc_base; +} + +uintptr_t stm32_get_gpio_bank_base(unsigned int bank) +{ + if (bank == GPIO_BANK_Z) { + return GPIOZ_BASE; + } + + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); + + return GPIOA_BASE + (bank * GPIO_BANK_OFFSET); +} + +unsigned long stm32_get_gpio_bank_clock(unsigned int bank) +{ + if (bank == GPIO_BANK_Z) { + return GPIOZ; + } + + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); + + return GPIOA + (bank - GPIO_BANK_A); +} + +uint32_t stm32_get_gpio_bank_offset(unsigned int bank) +{ + if (bank == GPIO_BANK_Z) { + return 0; + } + + assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); + + return bank * GPIO_BANK_OFFSET; +} diff --git a/plat/st/stm32mp1/stm32mp1_dt.c b/plat/st/common/stm32mp_dt.c similarity index 80% rename from plat/st/stm32mp1/stm32mp1_dt.c rename to plat/st/common/stm32mp_dt.c index 8493b8786..e64433bc8 100644 --- a/plat/st/stm32mp1/stm32mp1_dt.c +++ b/plat/st/common/stm32mp_dt.c @@ -13,14 +13,14 @@ #include #include -#include -#include #include #include +#include + static int fdt_checked; -static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE; +static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE; /******************************************************************************* * This function checks device tree file with its header. @@ -68,9 +68,9 @@ bool fdt_check_node(int node) /******************************************************************************* * This function return global node status (generic use of fdt library). ******************************************************************************/ -uint32_t fdt_get_status(int node) +uint8_t fdt_get_status(int node) { - uint32_t status = DT_DISABLED; + uint8_t status = DT_DISABLED; int len; const char *cchar; @@ -291,6 +291,73 @@ uint32_t dt_get_ddr_size(void) return fdt_read_uint32_default(node, "st,mem-size", 0); } +/******************************************************************************* + * This function gets DDRCTRL base address information from the DT. + * Returns value on success, and 0 on failure. + ******************************************************************************/ +uintptr_t dt_get_ddrctrl_base(void) +{ + int node; + uint32_t array[4]; + + node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); + if (node < 0) { + INFO("%s: Cannot read DDR node in DT\n", __func__); + return 0; + } + + if (fdt_read_uint32_array(node, "reg", array, 4) < 0) { + return 0; + } + + return array[0]; +} + +/******************************************************************************* + * This function gets DDRPHYC base address information from the DT. + * Returns value on success, and 0 on failure. + ******************************************************************************/ +uintptr_t dt_get_ddrphyc_base(void) +{ + int node; + uint32_t array[4]; + + node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); + if (node < 0) { + INFO("%s: Cannot read DDR node in DT\n", __func__); + return 0; + } + + if (fdt_read_uint32_array(node, "reg", array, 4) < 0) { + return 0; + } + + return array[2]; +} + +/******************************************************************************* + * This function gets PWR base address information from the DT. + * Returns value on success, and 0 on failure. + ******************************************************************************/ +uintptr_t dt_get_pwr_base(void) +{ + int node; + const fdt32_t *cuint; + + node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); + if (node < 0) { + INFO("%s: Cannot read PWR node in DT\n", __func__); + return 0; + } + + cuint = fdt_getprop(fdt, node, "reg", NULL); + if (cuint == NULL) { + return 0; + } + + return fdt32_to_cpu(*cuint); +} + /******************************************************************************* * This function retrieves board model from DT * Returns string taken from model node, NULL otherwise diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c index a1ffd5a9d..c7bc39f4e 100644 --- a/plat/st/stm32mp1/bl2_plat_setup.c +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -17,25 +17,21 @@ #include #include #include +#include #include #include #include -#include -#include #include #include #include -#include #include -#include -#include static struct console_stm32 console; static void print_reset_reason(void) { - uint32_t rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR); + uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR); if (rstsr == 0U) { WARN("Reset reason unknown\n"); @@ -123,14 +119,14 @@ void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg2 __unused, u_register_t arg3 __unused) { - stm32mp1_save_boot_ctx_address(arg0); + stm32mp_save_boot_ctx_address(arg0); } void bl2_platform_setup(void) { int ret; - if (dt_check_pmic()) { + if (dt_pmic_status() > 0) { initialize_pmic(); } @@ -149,8 +145,10 @@ void bl2_el3_plat_arch_setup(void) struct dt_node_info dt_uart_info; const char *board_model; boot_api_context_t *boot_context = - (boot_api_context_t *)stm32mp1_get_boot_ctx_address(); + (boot_api_context_t *)stm32mp_get_boot_ctx_address(); uint32_t clk_rate; + uintptr_t pwr_base; + uintptr_t rcc_base; mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, @@ -162,9 +160,9 @@ void bl2_el3_plat_arch_setup(void) MT_MEMORY | MT_RO | MT_SECURE); /* Map non secure DDR for BL33 load and DDR training area restore */ - mmap_add_region(STM32MP1_DDR_BASE, - STM32MP1_DDR_BASE, - STM32MP1_DDR_MAX_SIZE, + mmap_add_region(STM32MP_DDR_BASE, + STM32MP_DDR_BASE, + STM32MP_DDR_MAX_SIZE, MT_MEMORY | MT_RW | MT_NS); /* Prevent corruption of preloaded Device Tree */ @@ -178,27 +176,30 @@ void bl2_el3_plat_arch_setup(void) panic(); } + pwr_base = stm32mp_pwr_base(); + rcc_base = stm32mp_rcc_base(); + /* * Disable the backup domain write protection. * The protection is enable at each reset by hardware * and must be disabled by software. */ - mmio_setbits_32(PWR_BASE + PWR_CR1, PWR_CR1_DBP); + mmio_setbits_32(pwr_base + PWR_CR1, PWR_CR1_DBP); - while ((mmio_read_32(PWR_BASE + PWR_CR1) & PWR_CR1_DBP) == 0U) { + while ((mmio_read_32(pwr_base + PWR_CR1) & PWR_CR1_DBP) == 0U) { ; } /* Reset backup domain on cold boot cases */ - if ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { - mmio_setbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST); + if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { + mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); - while ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_VSWRST) == + while ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_VSWRST) == 0U) { ; } - mmio_clrbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST); + mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); } generic_delay_timer_init(); @@ -224,19 +225,17 @@ void bl2_el3_plat_arch_setup(void) goto skip_console_init; } - if (stm32mp1_clk_enable((unsigned long)dt_uart_info.clock) != 0) { - goto skip_console_init; - } + stm32mp_clk_enable((unsigned long)dt_uart_info.clock); - stm32mp1_reset_assert((uint32_t)dt_uart_info.reset); + stm32mp_reset_assert((uint32_t)dt_uart_info.reset); udelay(2); - stm32mp1_reset_deassert((uint32_t)dt_uart_info.reset); + stm32mp_reset_deassert((uint32_t)dt_uart_info.reset); mdelay(1); - clk_rate = stm32mp1_clk_get_rate((unsigned long)dt_uart_info.clock); + clk_rate = stm32mp_clk_get_rate((unsigned long)dt_uart_info.clock); if (console_stm32_register(dt_uart_info.base, clk_rate, - STM32MP1_UART_BAUDRATE, &console) == 0) { + STM32MP_UART_BAUDRATE, &console) == 0) { panic(); } @@ -257,5 +256,5 @@ skip_console_init: print_reset_reason(); - stm32mp1_io_setup(); + stm32mp_io_setup(); } diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h index 6d3d36dba..5019b1a3b 100644 --- a/plat/st/stm32mp1/include/platform_def.h +++ b/plat/st/stm32mp1/include/platform_def.h @@ -29,8 +29,8 @@ #define BL33_IMAGE_NAME "ssbl" #define BL33_BINARY_TYPE U(0x0) -#define STM32MP1_PRIMARY_CPU U(0x0) -#define STM32MP1_SECONDARY_CPU U(0x1) +#define STM32MP_PRIMARY_CPU U(0x0) +#define STM32MP_SECONDARY_CPU U(0x1) #define PLATFORM_CLUSTER_COUNT ULL(1) #define PLATFORM_CLUSTER0_CORE_COUNT U(2) @@ -50,33 +50,33 @@ * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug * size plus a little space for growth. */ -#define BL2_BASE STM32MP1_BL2_BASE -#define BL2_LIMIT (STM32MP1_BL2_BASE + \ - STM32MP1_BL2_SIZE) +#define BL2_BASE STM32MP_BL2_BASE +#define BL2_LIMIT (STM32MP_BL2_BASE + \ + STM32MP_BL2_SIZE) /******************************************************************************* * BL32 specific defines. ******************************************************************************/ -#define BL32_BASE STM32MP1_BL32_BASE -#define BL32_LIMIT (STM32MP1_BL32_BASE + \ - STM32MP1_BL32_SIZE) +#define BL32_BASE STM32MP_BL32_BASE +#define BL32_LIMIT (STM32MP_BL32_BASE + \ + STM32MP_BL32_SIZE) /******************************************************************************* * BL33 specific defines. ******************************************************************************/ -#define BL33_BASE STM32MP1_BL33_BASE +#define BL33_BASE STM32MP_BL33_BASE /* * Load address of BL33 for this platform port */ -#define PLAT_STM32MP1_NS_IMAGE_OFFSET BL33_BASE +#define PLAT_STM32MP_NS_IMAGE_OFFSET BL33_BASE /******************************************************************************* * DTB specific defines. ******************************************************************************/ -#define DTB_BASE STM32MP1_DTB_BASE -#define DTB_LIMIT (STM32MP1_DTB_BASE + \ - STM32MP1_DTB_SIZE) +#define DTB_BASE STM32MP_DTB_BASE +#define DTB_LIMIT (STM32MP_DTB_BASE + \ + STM32MP_DTB_SIZE) /******************************************************************************* * Platform specific page table and MMU setup constants diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h index 04c9a9ad5..49a2bdf41 100644 --- a/plat/st/stm32mp1/include/stm32mp1_private.h +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -9,20 +9,12 @@ #include -void stm32mp1_io_setup(void); void configure_mmu(void); void stm32mp1_arch_security_setup(void); void stm32mp1_security_setup(void); -void stm32mp1_save_boot_ctx_address(uintptr_t address); -uintptr_t stm32mp1_get_boot_ctx_address(void); - void stm32mp1_gic_pcpu_init(void); void stm32mp1_gic_init(void); -uintptr_t stm32_get_gpio_bank_base(unsigned int bank); -unsigned long stm32_get_gpio_bank_clock(unsigned int bank); -uint32_t stm32_get_gpio_bank_offset(unsigned int bank); - #endif /* STM32MP1_PRIVATE_H */ diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c index 621419439..0da93e4fa 100644 --- a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c +++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -50,7 +50,7 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), - .ep_info.pc = PLAT_STM32MP1_NS_IMAGE_OFFSET, + .ep_info.pc = PLAT_STM32MP_NS_IMAGE_OFFSET, .ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS), @@ -58,9 +58,9 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), - .image_info.image_base = PLAT_STM32MP1_NS_IMAGE_OFFSET, - .image_info.image_max_size = STM32MP1_DDR_MAX_SIZE - - (PLAT_STM32MP1_NS_IMAGE_OFFSET - STM32MP1_DDR_BASE), + .image_info.image_base = PLAT_STM32MP_NS_IMAGE_OFFSET, + .image_info.image_max_size = STM32MP_DDR_MAX_SIZE - + (PLAT_STM32MP_NS_IMAGE_OFFSET - STM32MP_DDR_BASE), .next_handoff_image_id = INVALID_IMAGE_ID, } diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index 4288f23d9..3e3460189 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -21,7 +21,8 @@ $(eval $(call add_define,STM32_TF_A_COPIES)) PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 1))) $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES)) -PLAT_INCLUDES := -Iplat/st/stm32mp1/include/ +PLAT_INCLUDES := -Iplat/st/common/include/ +PLAT_INCLUDES += -Iplat/st/stm32mp1/include/ # Device tree DTB_FILE_NAME ?= stm32mp157c-ev1.dtb @@ -30,7 +31,8 @@ DTC_FLAGS += -Wno-unit_address_vs_reg include lib/libfdt/libfdt.mk -PLAT_BL_COMMON_SOURCES := plat/st/stm32mp1/stm32mp1_common.c +PLAT_BL_COMMON_SOURCES := plat/st/common/stm32mp_common.c \ + plat/st/stm32mp1/stm32mp1_private.c PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S @@ -48,6 +50,7 @@ PLAT_BL_COMMON_SOURCES += ${LIBFDT_SRCS} \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/st/bsec/bsec.c \ + drivers/st/clk/stm32mp_clkfunc.c \ drivers/st/clk/stm32mp1_clk.c \ drivers/st/clk/stm32mp1_clkfunc.c \ drivers/st/ddr/stm32mp1_ddr_helpers.c \ @@ -56,8 +59,8 @@ PLAT_BL_COMMON_SOURCES += ${LIBFDT_SRCS} \ drivers/st/pmic/stm32mp_pmic.c \ drivers/st/pmic/stpmic1.c \ drivers/st/reset/stm32mp1_reset.c \ + plat/st/common/stm32mp_dt.c \ plat/st/stm32mp1/stm32mp1_context.c \ - plat/st/stm32mp1/stm32mp1_dt.c \ plat/st/stm32mp1/stm32mp1_helper.S \ plat/st/stm32mp1/stm32mp1_security.c @@ -65,7 +68,7 @@ BL2_SOURCES += drivers/io/io_block.c \ drivers/io/io_dummy.c \ drivers/io/io_storage.c \ drivers/st/io/io_stm32image.c \ - plat/st/stm32mp1/bl2_io_storage.c \ + plat/st/common/bl2_io_storage.c \ plat/st/stm32mp1/bl2_plat_setup.c BL2_SOURCES += drivers/mmc/mmc.c \ diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c index 0d76fb7e3..329ff688a 100644 --- a/plat/st/stm32mp1/sp_min/sp_min_setup.c +++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c @@ -27,8 +27,6 @@ #include #include -#include -#include /****************************************************************************** * Placeholder variables for copying the arguments that have been passed to @@ -125,7 +123,7 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, if ((result > 0) && (dt_uart_info.status != 0U)) { if (console_stm32_register(dt_uart_info.base, 0, - STM32MP1_UART_BAUDRATE, &console) == + STM32MP_UART_BAUDRATE, &console) == 0) { panic(); } diff --git a/plat/st/stm32mp1/stm32mp1.ld.S b/plat/st/stm32mp1/stm32mp1.ld.S index a8e822063..c041fb67d 100644 --- a/plat/st/stm32mp1/stm32mp1.ld.S +++ b/plat/st/stm32mp1/stm32mp1.ld.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -17,7 +17,7 @@ ENTRY(__BL2_IMAGE_START__) MEMORY { HEADER (rw) : ORIGIN = 0x00000000, LENGTH = 0x3000 - RAM (rwx) : ORIGIN = STM32MP1_BINARY_BASE, LENGTH = STM32MP1_BINARY_SIZE + RAM (rwx) : ORIGIN = STM32MP_BINARY_BASE, LENGTH = STM32MP_BINARY_SIZE } SECTIONS @@ -32,7 +32,7 @@ SECTIONS __HEADER_END__ = .; } >HEADER - . = STM32MP1_BINARY_BASE; + . = STM32MP_BINARY_BASE; .data . : { . = ALIGN(PAGE_SIZE); __DATA_START__ = .; @@ -43,7 +43,7 @@ SECTIONS * The strongest and only alignment contraint is MMU 4K page. * Indeed as images below will be removed, 4K pages will be re-used. */ - . = ( STM32MP1_DTB_BASE - STM32MP1_BINARY_BASE ); + . = ( STM32MP_DTB_BASE - STM32MP_BINARY_BASE ); __DTB_IMAGE_START__ = .; *(.dtb_image*) __DTB_IMAGE_END__ = .; @@ -53,7 +53,7 @@ SECTIONS * The strongest and only alignment contraint is MMU 4K page. * Indeed as images below will be removed, 4K pages will be re-used. */ - . = ( STM32MP1_BL2_BASE - STM32MP1_BINARY_BASE ); + . = ( STM32MP_BL2_BASE - STM32MP_BINARY_BASE ); __BL2_IMAGE_START__ = .; *(.bl2_image*) __BL2_IMAGE_END__ = .; @@ -63,7 +63,7 @@ SECTIONS * The strongest and only alignment constraint is 8 words to simplify * memraise8 assembly code. */ - . = ( STM32MP1_BL32_BASE - STM32MP1_BINARY_BASE ); + . = ( STM32MP_BL32_BASE - STM32MP_BINARY_BASE ); __BL32_IMAGE_START__ = .; *(.bl32_image*) __BL32_IMAGE_END__ = .; diff --git a/plat/st/stm32mp1/stm32mp1_common.c b/plat/st/stm32mp1/stm32mp1_common.c deleted file mode 100644 index cd93d2eef..000000000 --- a/plat/st/stm32mp1/stm32mp1_common.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAP_SRAM MAP_REGION_FLAT(STM32MP1_SRAM_BASE, \ - STM32MP1_SRAM_SIZE, \ - MT_MEMORY | \ - MT_RW | \ - MT_SECURE | \ - MT_EXECUTE_NEVER) - -#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ - STM32MP1_DEVICE1_SIZE, \ - MT_DEVICE | \ - MT_RW | \ - MT_SECURE | \ - MT_EXECUTE_NEVER) - -#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \ - STM32MP1_DEVICE2_SIZE, \ - MT_DEVICE | \ - MT_RW | \ - MT_SECURE | \ - MT_EXECUTE_NEVER) - -#if defined(IMAGE_BL2) -static const mmap_region_t stm32mp1_mmap[] = { - MAP_SRAM, - MAP_DEVICE1, - MAP_DEVICE2, - {0} -}; -#endif -#if defined(IMAGE_BL32) -static const mmap_region_t stm32mp1_mmap[] = { - MAP_SRAM, - MAP_DEVICE1, - MAP_DEVICE2, - {0} -}; -#endif - -void configure_mmu(void) -{ - mmap_add(stm32mp1_mmap); - init_xlat_tables(); - - enable_mmu_svc_mon(0); -} - -uintptr_t plat_get_ns_image_entrypoint(void) -{ - return BL33_BASE; -} - -unsigned int plat_get_syscnt_freq2(void) -{ - return read_cntfrq_el0(); -} - -/* Functions to save and get boot context address given by ROM code */ -static uintptr_t boot_ctx_address; - -void stm32mp1_save_boot_ctx_address(uintptr_t address) -{ - boot_ctx_address = address; -} - -uintptr_t stm32mp1_get_boot_ctx_address(void) -{ - return boot_ctx_address; -} - -uintptr_t stm32_get_gpio_bank_base(unsigned int bank) -{ - switch (bank) { - case GPIO_BANK_A ... GPIO_BANK_K: - return GPIOA_BASE + (bank * GPIO_BANK_OFFSET); - case GPIO_BANK_Z: - return GPIOZ_BASE; - default: - panic(); - } -} - -/* Return clock ID on success, negative value on error */ -unsigned long stm32_get_gpio_bank_clock(unsigned int bank) -{ - switch (bank) { - case GPIO_BANK_A ... GPIO_BANK_K: - return GPIOA + (bank - GPIO_BANK_A); - case GPIO_BANK_Z: - return GPIOZ; - default: - panic(); - } -} - -uint32_t stm32_get_gpio_bank_offset(unsigned int bank) -{ - if (bank == GPIO_BANK_Z) { - return 0; - } else { - return bank * GPIO_BANK_OFFSET; - } -} diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c index a8f9bf46d..cf8a91eb4 100644 --- a/plat/st/stm32mp1/stm32mp1_context.c +++ b/plat/st/stm32mp1/stm32mp1_context.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -20,26 +20,16 @@ int stm32_save_boot_interface(uint32_t interface, uint32_t instance) { - uint32_t tamp_clk_off = 0; uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID); - if (!stm32mp1_clk_is_enabled(RTCAPB)) { - tamp_clk_off = 1; - if (stm32mp1_clk_enable(RTCAPB) != 0) { - return -EINVAL; - } - } + stm32mp_clk_enable(RTCAPB); mmio_clrsetbits_32(bkpr_itf_idx, TAMP_BOOT_ITF_MASK, ((interface << 4) | (instance & 0xFU)) << TAMP_BOOT_ITF_SHIFT); - if (tamp_clk_off != 0U) { - if (stm32mp1_clk_disable(RTCAPB) != 0) { - return -EINVAL; - } - } + stm32mp_clk_disable(RTCAPB); return 0; } diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index 8cd5aeb26..f0dc575e2 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -8,12 +8,19 @@ #define STM32MP1_DEF_H #include +#include +#include +#include #include #include #ifndef __ASSEMBLY__ +#include + #include -#include +#include +#include +#include #include #endif @@ -21,14 +28,13 @@ * STM32MP1 memory map related constants ******************************************************************************/ -#define STM32MP1_SRAM_BASE U(0x2FFC0000) -#define STM32MP1_SRAM_SIZE U(0x00040000) +#define STM32MP_SYSRAM_BASE U(0x2FFC0000) +#define STM32MP_SYSRAM_SIZE U(0x00040000) /* DDR configuration */ -#define STM32MP1_DDR_BASE U(0xC0000000) -#define STM32MP1_DDR_SIZE_DFLT U(0x20000000) /* 512 MB */ -#define STM32MP1_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ -#define STM32MP1_DDR_SPEED_DFLT 528 +#define STM32MP_DDR_BASE U(0xC0000000) +#define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ +#define STM32MP_DDR_SPEED_DFLT 528 /* DDR power initializations */ #ifndef __ASSEMBLY__ @@ -39,36 +45,36 @@ enum ddr_type { #endif /* Section used inside TF binaries */ -#define STM32MP1_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */ +#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */ /* 256 Octets reserved for header */ -#define STM32MP1_HEADER_SIZE U(0x00000100) +#define STM32MP_HEADER_SIZE U(0x00000100) -#define STM32MP1_BINARY_BASE (STM32MP1_SRAM_BASE + \ - STM32MP1_PARAM_LOAD_SIZE + \ - STM32MP1_HEADER_SIZE) +#define STM32MP_BINARY_BASE (STM32MP_SYSRAM_BASE + \ + STM32MP_PARAM_LOAD_SIZE + \ + STM32MP_HEADER_SIZE) -#define STM32MP1_BINARY_SIZE (STM32MP1_SRAM_SIZE - \ - (STM32MP1_PARAM_LOAD_SIZE + \ - STM32MP1_HEADER_SIZE)) +#define STM32MP_BINARY_SIZE (STM32MP_SYSRAM_SIZE - \ + (STM32MP_PARAM_LOAD_SIZE + \ + STM32MP_HEADER_SIZE)) #if STACK_PROTECTOR_ENABLED -#define STM32MP1_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */ +#define STM32MP_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */ #else -#define STM32MP1_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ +#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ #endif -#define STM32MP1_BL32_BASE (STM32MP1_SRAM_BASE + \ - STM32MP1_SRAM_SIZE - \ - STM32MP1_BL32_SIZE) +#define STM32MP_BL32_BASE (STM32MP_SYSRAM_BASE + \ + STM32MP_SYSRAM_SIZE - \ + STM32MP_BL32_SIZE) #if STACK_PROTECTOR_ENABLED -#define STM32MP1_BL2_SIZE U(0x00015000) /* 84 Ko for BL2 */ +#define STM32MP_BL2_SIZE U(0x00015000) /* 84 Ko for BL2 */ #else -#define STM32MP1_BL2_SIZE U(0x00013000) /* 76 Ko for BL2 */ +#define STM32MP_BL2_SIZE U(0x00013000) /* 76 Ko for BL2 */ #endif -#define STM32MP1_BL2_BASE (STM32MP1_BL32_BASE - \ - STM32MP1_BL2_SIZE) +#define STM32MP_BL2_BASE (STM32MP_BL32_BASE - \ + STM32MP_BL2_SIZE) /* BL2 and BL32/sp_min require 5 tables */ #define MAX_XLAT_TABLES 5 @@ -85,12 +91,12 @@ enum ddr_type { #endif /* DTB initialization value */ -#define STM32MP1_DTB_SIZE U(0x00004000) /* 16Ko for DTB */ +#define STM32MP_DTB_SIZE U(0x00004000) /* 16Ko for DTB */ -#define STM32MP1_DTB_BASE (STM32MP1_BL2_BASE - \ - STM32MP1_DTB_SIZE) +#define STM32MP_DTB_BASE (STM32MP_BL2_BASE - \ + STM32MP_DTB_SIZE) -#define STM32MP1_BL33_BASE (STM32MP1_DDR_BASE + U(0x100000)) +#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000)) /******************************************************************************* * STM32MP1 device/io map related constants (used for MMU) @@ -155,12 +161,12 @@ enum ddr_type { #define USART6_BASE U(0x44003000) #define UART7_BASE U(0x40018000) #define UART8_BASE U(0x40019000) -#define STM32MP1_UART_BAUDRATE U(115200) +#define STM32MP_UART_BAUDRATE U(115200) /* For UART crash console */ -#define STM32MP1_DEBUG_USART_BASE UART4_BASE +#define STM32MP_DEBUG_USART_BASE UART4_BASE /* UART4 on HSI@64MHz, TX on GPIOG11 Alternate 6 */ -#define STM32MP1_DEBUG_USART_CLK_FRQ 64000000 +#define STM32MP_DEBUG_USART_CLK_FRQ 64000000 #define DEBUG_UART_TX_GPIO_BANK_ADDRESS GPIOG_BASE #define DEBUG_UART_TX_GPIO_BANK_CLK_REG RCC_MP_AHB4ENSETR #define DEBUG_UART_TX_GPIO_BANK_CLK_EN RCC_MP_AHB4ENSETR_GPIOGEN @@ -192,15 +198,15 @@ enum ddr_type { /******************************************************************************* * STM32MP1 SDMMC ******************************************************************************/ -#define STM32MP1_SDMMC1_BASE U(0x58005000) -#define STM32MP1_SDMMC2_BASE U(0x58007000) -#define STM32MP1_SDMMC3_BASE U(0x48004000) +#define STM32MP_SDMMC1_BASE U(0x58005000) +#define STM32MP_SDMMC2_BASE U(0x58007000) +#define STM32MP_SDMMC3_BASE U(0x48004000) -#define STM32MP1_MMC_INIT_FREQ 400000 /*400 KHz*/ -#define STM32MP1_SD_NORMAL_SPEED_MAX_FREQ 25000000 /*25 MHz*/ -#define STM32MP1_SD_HIGH_SPEED_MAX_FREQ 50000000 /*50 MHz*/ -#define STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ 26000000 /*26 MHz*/ -#define STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ 52000000 /*52 MHz*/ +#define STM32MP_MMC_INIT_FREQ 400000 /*400 KHz*/ +#define STM32MP_SD_NORMAL_SPEED_MAX_FREQ 25000000 /*25 MHz*/ +#define STM32MP_SD_HIGH_SPEED_MAX_FREQ 50000000 /*50 MHz*/ +#define STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ 26000000 /*26 MHz*/ +#define STM32MP_EMMC_HIGH_SPEED_MAX_FREQ 52000000 /*52 MHz*/ /******************************************************************************* * STM32MP1 BSEC / OTP @@ -245,4 +251,10 @@ static inline uint32_t tamp_bkpr(uint32_t idx) ******************************************************************************/ #define I2C4_BASE U(0x5C002000) +/******************************************************************************* + * Device Tree defines + ******************************************************************************/ +#define DT_PWR_COMPAT "st,stm32mp1-pwr" +#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" + #endif /* STM32MP1_DEF_H */ diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c index becb925c2..851a9cf0c 100644 --- a/plat/st/stm32mp1/stm32mp1_gic.c +++ b/plat/st/stm32mp1/stm32mp1_gic.c @@ -15,9 +15,6 @@ #include #include -#include -#include - struct stm32_gic_instance { uint32_t cells; uint32_t phandle_node; diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S index 8c2e1b6ea..bfcd991a3 100644 --- a/plat/st/stm32mp1/stm32mp1_helper.S +++ b/plat/st/stm32mp1/stm32mp1_helper.S @@ -10,7 +10,6 @@ #include #include #include -#include #define GPIO_TX_SHIFT (DEBUG_UART_TX_GPIO_PORT << 1) #define GPIO_TX_ALT_SHIFT ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2) @@ -74,7 +73,7 @@ func plat_is_my_cpu_primary ldcopr r0, MPIDR ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) and r0, r1 - cmp r0, #STM32MP1_PRIMARY_CPU + cmp r0, #STM32MP_PRIMARY_CPU moveq r0, #1 movne r0, #0 bx lr @@ -143,9 +142,9 @@ func plat_crash_console_init orr r2, r2, #DEBUG_UART_TX_EN str r2, [r1] - ldr r0, =STM32MP1_DEBUG_USART_BASE - ldr r1, =STM32MP1_DEBUG_USART_CLK_FRQ - ldr r2, =STM32MP1_UART_BAUDRATE + ldr r0, =STM32MP_DEBUG_USART_BASE + ldr r1, =STM32MP_DEBUG_USART_CLK_FRQ + ldr r2, =STM32MP_UART_BAUDRATE b console_stm32_core_init endfunc plat_crash_console_init @@ -156,7 +155,7 @@ endfunc plat_crash_console_init * --------------------------------------------- */ func plat_crash_console_flush - ldr r1, =STM32MP1_DEBUG_USART_BASE + ldr r1, =STM32MP_DEBUG_USART_BASE b console_stm32_core_flush endfunc plat_crash_console_flush @@ -172,6 +171,6 @@ endfunc plat_crash_console_flush * --------------------------------------------- */ func plat_crash_console_putc - ldr r1, =STM32MP1_DEBUG_USART_BASE + ldr r1, =STM32MP_DEBUG_USART_BASE b console_stm32_core_putc endfunc plat_crash_console_putc diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c index c0e9c4eb8..cf9fa8e69 100644 --- a/plat/st/stm32mp1/stm32mp1_pm.c +++ b/plat/st/stm32mp1/stm32mp1_pm.c @@ -14,15 +14,11 @@ #include #include #include -#include #include #include #include #include -#include -#include - static uintptr_t stm32_sec_entrypoint; static uint32_t cntfrq_core0; @@ -63,7 +59,6 @@ static void stm32_cpu_standby(plat_local_state_t cpu_state) static int stm32_pwr_domain_on(u_register_t mpidr) { unsigned long current_cpu_mpidr = read_mpidr_el1(); - uint32_t tamp_clk_off = 0; uint32_t bkpr_core1_addr = tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); uint32_t bkpr_core1_magic = @@ -73,18 +68,13 @@ static int stm32_pwr_domain_on(u_register_t mpidr) return PSCI_E_INVALID_PARAMS; } - if ((stm32_sec_entrypoint < STM32MP1_SRAM_BASE) || - (stm32_sec_entrypoint > (STM32MP1_SRAM_BASE + - (STM32MP1_SRAM_SIZE - 1)))) { + if ((stm32_sec_entrypoint < STM32MP_SYSRAM_BASE) || + (stm32_sec_entrypoint > (STM32MP_SYSRAM_BASE + + (STM32MP_SYSRAM_SIZE - 1)))) { return PSCI_E_INVALID_ADDRESS; } - if (!stm32mp1_clk_is_enabled(RTCAPB)) { - tamp_clk_off = 1; - if (stm32mp1_clk_enable(RTCAPB) != 0) { - panic(); - } - } + stm32mp_clk_enable(RTCAPB); cntfrq_core0 = read_cntfrq_el0(); @@ -94,14 +84,10 @@ static int stm32_pwr_domain_on(u_register_t mpidr) /* Write magic number in backup register */ mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER); - if (tamp_clk_off != 0U) { - if (stm32mp1_clk_disable(RTCAPB) != 0) { - panic(); - } - } + stm32mp_clk_disable(RTCAPB); /* Generate an IT to core 1 */ - gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, STM32MP1_SECONDARY_CPU); + gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, STM32MP_SECONDARY_CPU); return PSCI_E_SUCCESS; } @@ -163,7 +149,8 @@ static void __dead2 stm32_system_off(void) static void __dead2 stm32_system_reset(void) { - mmio_setbits_32(RCC_BASE + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); + mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, + RCC_MP_GRSTCSETR_MPSYSRST); /* Loop in case system reset is not immediately caught */ for ( ; ; ) { @@ -197,7 +184,7 @@ static int stm32_validate_power_state(unsigned int power_state, static int stm32_validate_ns_entrypoint(uintptr_t entrypoint) { /* The non-secure entry point must be in DDR */ - if (entrypoint < STM32MP1_DDR_BASE) { + if (entrypoint < STM32MP_DDR_BASE) { return PSCI_E_INVALID_ADDRESS; } diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c new file mode 100644 index 000000000..20eb88e72 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#define MAP_SRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \ + STM32MP_SYSRAM_SIZE, \ + MT_MEMORY | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) + +#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ + STM32MP1_DEVICE1_SIZE, \ + MT_DEVICE | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) + +#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \ + STM32MP1_DEVICE2_SIZE, \ + MT_DEVICE | \ + MT_RW | \ + MT_SECURE | \ + MT_EXECUTE_NEVER) + +#if defined(IMAGE_BL2) +static const mmap_region_t stm32mp1_mmap[] = { + MAP_SRAM, + MAP_DEVICE1, + MAP_DEVICE2, + {0} +}; +#endif +#if defined(IMAGE_BL32) +static const mmap_region_t stm32mp1_mmap[] = { + MAP_SRAM, + MAP_DEVICE1, + MAP_DEVICE2, + {0} +}; +#endif + +void configure_mmu(void) +{ + mmap_add(stm32mp1_mmap); + init_xlat_tables(); + + enable_mmu_svc_mon(0); +} diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c index cfdbf3185..ebf1587a6 100644 --- a/plat/st/stm32mp1/stm32mp1_security.c +++ b/plat/st/stm32mp1/stm32mp1_security.c @@ -11,13 +11,9 @@ #include #include #include -#include #include #include -#include -#include - /******************************************************************************* * Initialize the TrustZone Controller. Configure Region 0 with Secure RW access * and allow Non-Secure masters full access. @@ -25,7 +21,7 @@ static void init_tzc400(void) { unsigned long long region_base, region_top; - unsigned long long ddr_base = STM32MP1_DDR_BASE; + unsigned long long ddr_base = STM32MP_DDR_BASE; unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size(); tzc400_init(STM32MP1_TZC_BASE); @@ -65,14 +61,8 @@ static void init_tzc400(void) ******************************************************************************/ static void early_init_tzc400(void) { - if (stm32mp1_clk_enable(TZC1) != 0) { - ERROR("Cannot enable TZC1 clock\n"); - panic(); - } - if (stm32mp1_clk_enable(TZC2) != 0) { - ERROR("Cannot enable TZC2 clock\n"); - panic(); - } + stm32mp_clk_enable(TZC1); + stm32mp_clk_enable(TZC2); tzc400_init(STM32MP1_TZC_BASE); @@ -83,9 +73,9 @@ static void early_init_tzc400(void) * same configuration to all filters in the TZC. */ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, - STM32MP1_DDR_BASE, - STM32MP1_DDR_BASE + - (STM32MP1_DDR_MAX_SIZE - 1U), + STM32MP_DDR_BASE, + STM32MP_DDR_BASE + + (STM32MP_DDR_MAX_SIZE - 1U), TZC_REGION_S_RDWR, TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID));