diff options
Diffstat (limited to 'drivers/st')
-rw-r--r-- | drivers/st/clk/stm32mp1_clk.c | 437 | ||||
-rw-r--r-- | drivers/st/clk/stm32mp_clkfunc.c | 68 | ||||
-rw-r--r-- | drivers/st/crypto/stm32_hash.c | 17 | ||||
-rw-r--r-- | drivers/st/ddr/stm32mp1_ram.c | 26 | ||||
-rw-r--r-- | drivers/st/etzpc/etzpc.c | 258 | ||||
-rw-r--r-- | drivers/st/fmc/stm32_fmc2_nand.c | 112 | ||||
-rw-r--r-- | drivers/st/gpio/stm32_gpio.c | 14 | ||||
-rw-r--r-- | drivers/st/io/io_mmc.c | 21 | ||||
-rw-r--r-- | drivers/st/io/io_stm32image.c | 3 | ||||
-rw-r--r-- | drivers/st/iwdg/stm32_iwdg.c | 6 | ||||
-rw-r--r-- | drivers/st/mmc/stm32_sdmmc2.c | 43 | ||||
-rw-r--r-- | drivers/st/pmic/stm32mp_pmic.c | 24 | ||||
-rw-r--r-- | drivers/st/reset/stm32mp1_reset.c | 35 | ||||
-rw-r--r-- | drivers/st/spi/stm32_qspi.c | 27 | ||||
-rw-r--r-- | drivers/st/uart/aarch32/stm32_console.S | 30 |
15 files changed, 903 insertions, 218 deletions
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c index 0cc87cc71..564bd8798 100644 --- a/drivers/st/clk/stm32mp1_clk.c +++ b/drivers/st/clk/stm32mp1_clk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -16,6 +16,7 @@ #include <arch.h> #include <arch_helpers.h> #include <common/debug.h> +#include <common/fdt_wrappers.h> #include <drivers/delay_timer.h> #include <drivers/generic_delay_timer.h> #include <drivers/st/stm32mp_clkfunc.h> @@ -105,10 +106,62 @@ enum stm32mp1_parent_sel { _MCUS_SEL, _USBPHY_SEL, _USBO_SEL, + _MPU_SEL, + _PER_SEL, + _RTC_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; +/* State the parent clock ID straight related to a clock */ +static const uint8_t parent_id_clock_id[_PARENT_NB] = { + [_HSE] = CK_HSE, + [_HSI] = CK_HSI, + [_CSI] = CK_CSI, + [_LSE] = CK_LSE, + [_LSI] = CK_LSI, + [_I2S_CKIN] = _UNKNOWN_ID, + [_USB_PHY_48] = _UNKNOWN_ID, + [_HSI_KER] = CK_HSI, + [_HSE_KER] = CK_HSE, + [_HSE_KER_DIV2] = CK_HSE_DIV2, + [_CSI_KER] = CK_CSI, + [_PLL1_P] = PLL1_P, + [_PLL1_Q] = PLL1_Q, + [_PLL1_R] = PLL1_R, + [_PLL2_P] = PLL2_P, + [_PLL2_Q] = PLL2_Q, + [_PLL2_R] = PLL2_R, + [_PLL3_P] = PLL3_P, + [_PLL3_Q] = PLL3_Q, + [_PLL3_R] = PLL3_R, + [_PLL4_P] = PLL4_P, + [_PLL4_Q] = PLL4_Q, + [_PLL4_R] = PLL4_R, + [_ACLK] = CK_AXI, + [_PCLK1] = CK_AXI, + [_PCLK2] = CK_AXI, + [_PCLK3] = CK_AXI, + [_PCLK4] = CK_AXI, + [_PCLK5] = CK_AXI, + [_CK_PER] = CK_PER, + [_CK_MPU] = CK_MPU, + [_CK_MCU] = CK_MCU, +}; + +static unsigned int clock_id2parent_id(unsigned long id) +{ + unsigned int n; + + for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) { + if (parent_id_clock_id[n] == id) { + return n; + } + } + + return _UNKNOWN_ID; +} + enum stm32mp1_pll_id { _PLL1, _PLL2, @@ -258,7 +311,8 @@ struct stm32mp1_clk_pll { [_ ## _label ## _SEL] = { \ .offset = _rcc_selr, \ .src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \ - .msk = _rcc_selr ## _ ## _label ## SRC_MASK, \ + .msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \ + (_rcc_selr ## _ ## _label ## SRC_SHIFT), \ .parent = (_parents), \ .nb_parent = ARRAY_SIZE(_parents) \ } @@ -280,19 +334,6 @@ struct stm32mp1_clk_pll { .refclk[3] = (p4), \ } -static const uint8_t stm32mp1_clks[][2] = { - { CK_PER, _CK_PER }, - { CK_MPU, _CK_MPU }, - { CK_AXI, _ACLK }, - { CK_MCU, _CK_MCU }, - { 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[] = { @@ -368,6 +409,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), + _CLK_SELEC(RCC_BDCR, 20, RTC, _RTC_SEL), _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), }; @@ -439,6 +481,18 @@ static const uint8_t usbo_parents[] = { _PLL4_R, _USB_PHY_48 }; +static const uint8_t mpu_parents[] = { + _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ +}; + +static const uint8_t per_parents[] = { + _HSI, _HSE, _CSI, +}; + +static const uint8_t rtc_parents[] = { + _UNKNOWN_ID, _LSE, _LSI, _HSE +}; + static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), @@ -447,6 +501,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), + _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents), + _CLK_PARENT_SEL(PER, RCC_CPERCKSELR, per_parents), + _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents), _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), @@ -520,6 +577,43 @@ static const uint8_t stm32mp1_axi_div[8] = { 1, 2, 3, 4, 4, 4, 4, 4 }; +static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { + [_HSI] = "HSI", + [_HSE] = "HSE", + [_CSI] = "CSI", + [_LSI] = "LSI", + [_LSE] = "LSE", + [_I2S_CKIN] = "I2S_CKIN", + [_HSI_KER] = "HSI_KER", + [_HSE_KER] = "HSE_KER", + [_HSE_KER_DIV2] = "HSE_KER_DIV2", + [_CSI_KER] = "CSI_KER", + [_PLL1_P] = "PLL1_P", + [_PLL1_Q] = "PLL1_Q", + [_PLL1_R] = "PLL1_R", + [_PLL2_P] = "PLL2_P", + [_PLL2_Q] = "PLL2_Q", + [_PLL2_R] = "PLL2_R", + [_PLL3_P] = "PLL3_P", + [_PLL3_Q] = "PLL3_Q", + [_PLL3_R] = "PLL3_R", + [_PLL4_P] = "PLL4_P", + [_PLL4_Q] = "PLL4_Q", + [_PLL4_R] = "PLL4_R", + [_ACLK] = "ACLK", + [_PCLK1] = "PCLK1", + [_PCLK2] = "PCLK2", + [_PCLK3] = "PCLK3", + [_PCLK4] = "PCLK4", + [_PCLK5] = "PCLK5", + [_HCLK6] = "KCLK6", + [_HCLK2] = "HCLK2", + [_CK_PER] = "CK_PER", + [_CK_MPU] = "CK_MPU", + [_CK_MCU] = "CK_MCU", + [_USB_PHY_48] = "USB_PHY_48", +}; + /* RCC clock device driver private */ static unsigned long stm32mp1_osc[NB_OSC]; static struct spinlock reg_lock; @@ -559,15 +653,17 @@ static void stm32mp1_clk_unlock(struct spinlock *lock) bool stm32mp1_rcc_is_secure(void) { uintptr_t rcc_base = stm32mp_rcc_base(); + uint32_t mask = RCC_TZCR_TZEN; - return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0; + return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; } bool stm32mp1_rcc_is_mckprot(void) { uintptr_t rcc_base = stm32mp_rcc_base(); + uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; - return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_MCKPROT) != 0; + return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask; } void stm32mp1_clk_rcc_regs_lock(void) @@ -617,16 +713,16 @@ static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) static int stm32mp1_clk_get_parent(unsigned long id) { const struct stm32mp1_clk_sel *sel; - uint32_t j, p_sel; + uint32_t p_sel; int i; enum stm32mp1_parent_id p; enum stm32mp1_parent_sel s; uintptr_t rcc_base = stm32mp_rcc_base(); - for (j = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) { - if (stm32mp1_clks[j][0] == id) { - return (int)stm32mp1_clks[j][1]; - } + /* Few non gateable clock have a static parent ID, find them */ + i = (int)clock_id2parent_id(id); + if (i != _UNKNOWN_ID) { + return i; } i = stm32mp1_clk_get_gated_id(id); @@ -648,7 +744,8 @@ static int stm32mp1_clk_get_parent(unsigned long id) } sel = clk_sel_ref(s); - p_sel = (mmio_read_32(rcc_base + sel->offset) & sel->msk) >> sel->src; + p_sel = (mmio_read_32(rcc_base + sel->offset) & + (sel->msk << sel->src)) >> sel->src; if (p_sel < sel->nb_parent) { return (int)sel->parent[p_sel]; } @@ -930,27 +1027,27 @@ static void __clk_enable(struct stm32mp1_clk_gate const *gate) { uintptr_t rcc_base = stm32mp_rcc_base(); + VERBOSE("Enable clock %u\n", gate->index); + if (gate->set_clr != 0U) { mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); } else { mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit)); } - - VERBOSE("Clock %d has been enabled", gate->index); } static void __clk_disable(struct stm32mp1_clk_gate const *gate) { uintptr_t rcc_base = stm32mp_rcc_base(); + VERBOSE("Disable clock %u\n", gate->index); + 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) @@ -971,12 +1068,41 @@ unsigned int stm32mp1_clk_get_refcount(unsigned long id) return gate_refcounts[i]; } +/* Oscillators and PLLs are not gated at runtime */ +static bool clock_is_always_on(unsigned long id) +{ + switch (id) { + case CK_HSE: + case CK_CSI: + case CK_LSI: + case CK_LSE: + case CK_HSI: + case CK_HSE_DIV2: + case PLL1_Q: + case PLL1_R: + case PLL2_P: + case PLL2_Q: + case PLL2_R: + case PLL3_P: + case PLL3_Q: + case PLL3_R: + return true; + default: + return false; + } +} + void __stm32mp1_clk_enable(unsigned long id, bool secure) { const struct stm32mp1_clk_gate *gate; - int i = stm32mp1_clk_get_gated_id(id); + int i; unsigned int *refcnt; + if (clock_is_always_on(id)) { + return; + } + + i = stm32mp1_clk_get_gated_id(id); if (i < 0) { ERROR("Clock %d can't be enabled\n", (uint32_t)id); panic(); @@ -997,9 +1123,14 @@ void __stm32mp1_clk_enable(unsigned long id, bool secure) void __stm32mp1_clk_disable(unsigned long id, bool secure) { const struct stm32mp1_clk_gate *gate; - int i = stm32mp1_clk_get_gated_id(id); + int i; unsigned int *refcnt; + if (clock_is_always_on(id)) { + return; + } + + i = stm32mp1_clk_get_gated_id(id); if (i < 0) { ERROR("Clock %d can't be disabled\n", (uint32_t)id); panic(); @@ -1029,8 +1160,13 @@ void stm32mp_clk_disable(unsigned long id) bool stm32mp_clk_is_enabled(unsigned long id) { - int i = stm32mp1_clk_get_gated_id(id); + int i; + + if (clock_is_always_on(id)) { + return true; + } + i = stm32mp1_clk_get_gated_id(id); if (i < 0) { panic(); } @@ -1239,7 +1375,8 @@ static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, uintptr_t clksrc_address = rcc_base + (clksrc >> 4); unsigned long refclk; uint32_t ifrge = 0U; - uint32_t src, value, fracv; + uint32_t src, value, fracv = 0; + void *fdt; /* Check PLL output */ if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { @@ -1278,7 +1415,9 @@ static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, } /* Fractional configuration */ - fracv = fdt_read_uint32_default(plloff, "frac", 0); + if (fdt_get_address(&fdt) == 1) { + fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0); + } value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; value |= RCC_PLLNFRACR_FRACLE; @@ -1525,28 +1664,26 @@ static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) static void stm32mp1_stgen_config(void) { - uintptr_t stgen; uint32_t cntfid0; unsigned long rate; unsigned long long counter; - stgen = fdt_get_stgen_base(); - cntfid0 = mmio_read_32(stgen + CNTFID_OFF); + cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF); rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); 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; + mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); + counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF); + counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + 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); + mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter); + mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32)); + mmio_write_32(STGEN_BASE + CNTFID_OFF, rate); + mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); write_cntfrq((u_register_t)rate); @@ -1556,20 +1693,17 @@ static void stm32mp1_stgen_config(void) void stm32mp1_stgen_increment(unsigned long long offset_in_ms) { - uintptr_t stgen; unsigned long long cnt; - stgen = fdt_get_stgen_base(); + cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) | + mmio_read_32(STGEN_BASE + CNTCVL_OFF); - cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) | - mmio_read_32(stgen + CNTCVL_OFF); + cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U; - cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U; - - mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); - mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt); - mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(cnt >> 32)); - mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); + mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); + mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt); + mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32)); + mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN); } static void stm32mp1_pkcs_config(uint32_t pkcs) @@ -1600,20 +1734,25 @@ int stm32mp1_clk_init(void) bool pll4_preserve = false; bool pll4_bootrom = false; const fdt32_t *pkcs_cell; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return false; + } /* Check status field to disable security */ if (!fdt_get_rcc_secure_status()) { mmio_write_32(rcc_base + RCC_TZCR, 0); } - ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc, - (uint32_t)CLKSRC_NB); + ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB, + clksrc); if (ret < 0) { return -FDT_ERR_NOTFOUND; } - ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv, - (uint32_t)CLKDIV_NB); + ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB, + clkdiv); if (ret < 0) { return -FDT_ERR_NOTFOUND; } @@ -1628,8 +1767,8 @@ int stm32mp1_clk_init(void) continue; } - ret = fdt_read_uint32_array(plloff[i], "cfg", - pllcfg[i], (int)PLLCFG_NB); + ret = fdt_read_uint32_array(fdt, plloff[i], "cfg", + (int)PLLCFG_NB, pllcfg[i]); if (ret < 0) { return -FDT_ERR_NOTFOUND; } @@ -1794,14 +1933,14 @@ int stm32mp1_clk_init(void) continue; } - fracv = fdt_read_uint32_default(plloff[i], "frac", 0); + fracv = fdt_read_uint32_default(fdt, plloff[i], "frac", 0); 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); + ret = fdt_read_uint32_array(fdt, plloff[i], "csg", + (uint32_t)PLLCSG_NB, csg); if (ret == 0) { stm32mp1_pll_csg(i, csg); } else if (ret != -FDT_ERR_NOTFOUND) { @@ -1902,8 +2041,184 @@ static void stm32mp1_osc_init(void) } } +#ifdef STM32MP_SHARED_RESOURCES +/* + * Get the parent ID of the target parent clock, for tagging as secure + * shared clock dependencies. + */ +static int get_parent_id_parent(unsigned int parent_id) +{ + enum stm32mp1_parent_sel s = _UNKNOWN_SEL; + enum stm32mp1_pll_id pll_id; + uint32_t p_sel; + uintptr_t rcc_base = stm32mp_rcc_base(); + + switch (parent_id) { + case _ACLK: + case _PCLK4: + case _PCLK5: + s = _AXIS_SEL; + break; + case _PLL1_P: + case _PLL1_Q: + case _PLL1_R: + pll_id = _PLL1; + break; + case _PLL2_P: + case _PLL2_Q: + case _PLL2_R: + pll_id = _PLL2; + break; + case _PLL3_P: + case _PLL3_Q: + case _PLL3_R: + pll_id = _PLL3; + break; + case _PLL4_P: + case _PLL4_Q: + case _PLL4_R: + pll_id = _PLL4; + break; + case _PCLK1: + case _PCLK2: + case _HCLK2: + case _HCLK6: + case _CK_PER: + case _CK_MPU: + case _CK_MCU: + case _USB_PHY_48: + /* We do not expect to access these */ + panic(); + break; + default: + /* Other parents have no parent */ + return -1; + } + + if (s != _UNKNOWN_SEL) { + const struct stm32mp1_clk_sel *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]; + } + } else { + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + + p_sel = mmio_read_32(rcc_base + pll->rckxselr) & + RCC_SELR_REFCLK_SRC_MASK; + + if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { + return (int)pll->refclk[p_sel]; + } + } + + VERBOSE("No parent selected for %s\n", + stm32mp1_clk_parent_name[parent_id]); + + return -1; +} + +static void secure_parent_clocks(unsigned long parent_id) +{ + int grandparent_id; + + switch (parent_id) { + case _PLL3_P: + case _PLL3_Q: + case _PLL3_R: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); + break; + + /* These clocks are always secure when RCC is secure */ + case _ACLK: + case _HCLK2: + case _HCLK6: + case _PCLK4: + case _PCLK5: + case _PLL1_P: + case _PLL1_Q: + case _PLL1_R: + case _PLL2_P: + case _PLL2_Q: + case _PLL2_R: + case _HSI: + case _HSI_KER: + case _LSI: + case _CSI: + case _CSI_KER: + case _HSE: + case _HSE_KER: + case _HSE_KER_DIV2: + case _LSE: + break; + + default: + VERBOSE("Cannot secure parent clock %s\n", + stm32mp1_clk_parent_name[parent_id]); + panic(); + } + + grandparent_id = get_parent_id_parent(parent_id); + if (grandparent_id >= 0) { + secure_parent_clocks(grandparent_id); + } +} + +void stm32mp1_register_clock_parents_secure(unsigned long clock_id) +{ + int parent_id; + + if (!stm32mp1_rcc_is_secure()) { + return; + } + + switch (clock_id) { + case PLL1: + case PLL2: + /* PLL1/PLL2 are always secure: nothing to do */ + break; + case PLL3: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3); + break; + case PLL4: + ERROR("PLL4 cannot be secured\n"); + panic(); + break; + default: + /* Others are expected gateable clock */ + parent_id = stm32mp1_clk_get_parent(clock_id); + if (parent_id < 0) { + INFO("No parent found for clock %lu\n", clock_id); + } else { + secure_parent_clocks(parent_id); + } + break; + } +} +#endif /* STM32MP_SHARED_RESOURCES */ + static void sync_earlyboot_clocks_state(void) { + unsigned int idx; + const unsigned long secure_enable[] = { + AXIDCG, + BSEC, + DDRC1, DDRC1LP, + DDRC2, DDRC2LP, + DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP, + DDRPHYC, DDRPHYCLP, + TZC1, TZC2, + TZPC, + STGEN_K, + }; + + for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) { + stm32mp_clk_enable(secure_enable[idx]); + } + if (!stm32mp_is_single_core()) { stm32mp1_clk_enable_secure(RTCAPB); } diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c index 87c8e2b84..8333f6dfb 100644 --- a/drivers/st/clk/stm32mp_clkfunc.c +++ b/drivers/st/clk/stm32mp_clkfunc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,11 +10,10 @@ #include <platform_def.h> +#include <common/fdt_wrappers.h> #include <drivers/st/stm32_gpio.h> #include <drivers/st/stm32mp_clkfunc.h> -#define DT_STGEN_COMPAT "st,stm32-stgen" - /* * Get the frequency of an oscillator from its name in device tree. * @param name: oscillator name @@ -150,7 +149,8 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, continue; } - return fdt_read_uint32_default(subnode, prop_name, dflt_value); + return fdt_read_uint32_default(fdt, subnode, prop_name, + dflt_value); } return dflt_value; @@ -167,41 +167,14 @@ int fdt_get_rcc_node(void *fdt) } /* - * 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 fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count, + uint32_t *array) { int node; void *fdt; @@ -215,7 +188,7 @@ int fdt_rcc_read_uint32_array(const char *prop_name, return -FDT_ERR_NOTFOUND; } - return fdt_read_uint32_array(node, prop_name, array, count); + return fdt_read_uint32_array(fdt, node, prop_name, count, array); } /* @@ -297,33 +270,6 @@ bool fdt_get_rcc_secure_status(void) } /* - * 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. diff --git a/drivers/st/crypto/stm32_hash.c b/drivers/st/crypto/stm32_hash.c index f72787d33..317fd9eb8 100644 --- a/drivers/st/crypto/stm32_hash.c +++ b/drivers/st/crypto/stm32_hash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -51,6 +51,7 @@ #define SHA224_DIGEST_SIZE 28U #define SHA256_DIGEST_SIZE 32U +#define RESET_TIMEOUT_US_1MS 1000U #define HASH_TIMEOUT_US 10000U enum stm32_hash_data_format { @@ -251,6 +252,8 @@ int stm32_hash_final(uint8_t *digest) mmio_clrsetbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK, 8U * stm32_remain.length); zeromem(&stm32_remain, sizeof(stm32_remain)); + } else { + mmio_clrbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK); } mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL); @@ -299,7 +302,9 @@ int stm32_hash_register(void) break; } #else + /* BL32 uses hash if it is assigned only to secure world */ if (hash_info.status == DT_SECURE) { + stm32mp_register_secure_periph_iomem(hash_info.base); break; } #endif @@ -319,9 +324,15 @@ int stm32_hash_register(void) stm32mp_clk_enable(stm32_hash.clock); if (hash_info.reset >= 0) { - stm32mp_reset_assert((unsigned long)hash_info.reset); + uint32_t id = (uint32_t)hash_info.reset; + + if (stm32mp_reset_assert(id, RESET_TIMEOUT_US_1MS) != 0) { + panic(); + } udelay(20); - stm32mp_reset_deassert((unsigned long)hash_info.reset); + if (stm32mp_reset_deassert(id, RESET_TIMEOUT_US_1MS) != 0) { + panic(); + } } stm32mp_clk_disable(stm32_hash.clock); diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c index 4ae55fcc7..b21c8949f 100644 --- a/drivers/st/ddr/stm32mp1_ram.c +++ b/drivers/st/ddr/stm32mp1_ram.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -12,6 +12,7 @@ #include <arch_helpers.h> #include <common/debug.h> +#include <common/fdt_wrappers.h> #include <drivers/st/stm32mp1_ddr.h> #include <drivers/st/stm32mp1_ddr_helpers.h> #include <drivers/st/stm32mp1_ram.h> @@ -205,13 +206,13 @@ static int stm32mp1_ddr_setup(void) return -EINVAL; } - config.info.speed = fdt_read_uint32_default(node, "st,mem-speed", 0); - if (!config.info.speed) { + ret = fdt_read_uint32(fdt, node, "st,mem-speed", &config.info.speed); + if (ret < 0) { VERBOSE("%s: no st,mem-speed\n", __func__); return -EINVAL; } - config.info.size = fdt_read_uint32_default(node, "st,mem-size", 0); - if (!config.info.size) { + ret = fdt_read_uint32(fdt, node, "st,mem-size", &config.info.size); + if (ret < 0) { VERBOSE("%s: no st,mem-size\n", __func__); return -EINVAL; } @@ -223,10 +224,10 @@ static int stm32mp1_ddr_setup(void) INFO("RAM: %s\n", config.info.name); for (idx = 0; idx < ARRAY_SIZE(param); idx++) { - ret = fdt_read_uint32_array(node, param[idx].name, + ret = fdt_read_uint32_array(fdt, node, param[idx].name, + param[idx].size, (void *)((uintptr_t)&config + - param[idx].offset), - param[idx].size); + param[idx].offset)); VERBOSE("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret); @@ -250,8 +251,9 @@ static int stm32mp1_ddr_setup(void) VERBOSE("%s : ram size(%x, %x)\n", __func__, (uint32_t)priv->info.base, (uint32_t)priv->info.size); - write_sctlr(read_sctlr() & ~SCTLR_C_BIT); - dcsw_op_all(DC_OP_CISW); + if (stm32mp_map_ddr_non_cacheable() != 0) { + panic(); + } uret = ddr_test_data_bus(); if (uret != 0U) { @@ -274,7 +276,9 @@ static int stm32mp1_ddr_setup(void) panic(); } - write_sctlr(read_sctlr() | SCTLR_C_BIT); + if (stm32mp_unmap_ddr() != 0) { + panic(); + } return 0; } diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c new file mode 100644 index 000000000..ff52a22d9 --- /dev/null +++ b/drivers/st/etzpc/etzpc.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <stdint.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/st/etzpc.h> +#include <dt-bindings/soc/st,stm32-etzpc.h> +#include <lib/mmio.h> +#include <lib/utils_def.h> +#include <libfdt.h> + +#include <platform_def.h> + +/* Device Tree related definitions */ +#define ETZPC_COMPAT "st,stm32-etzpc" +#define ETZPC_LOCK_MASK 0x1U +#define ETZPC_MODE_SHIFT 8 +#define ETZPC_MODE_MASK GENMASK(1, 0) +#define ETZPC_ID_SHIFT 16 +#define ETZPC_ID_MASK GENMASK(7, 0) + +/* ID Registers */ +#define ETZPC_TZMA0_SIZE 0x000U +#define ETZPC_DECPROT0 0x010U +#define ETZPC_DECPROT_LOCK0 0x030U +#define ETZPC_HWCFGR 0x3F0U +#define ETZPC_VERR 0x3F4U + +/* ID Registers fields */ +#define ETZPC_TZMA0_SIZE_LOCK BIT(31) +#define ETZPC_DECPROT0_MASK GENMASK(1, 0) +#define ETZPC_HWCFGR_NUM_TZMA_SHIFT 0 +#define ETZPC_HWCFGR_NUM_PER_SEC_SHIFT 8 +#define ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT 16 +#define ETZPC_HWCFGR_CHUNCKS1N4_SHIFT 24 + +#define DECPROT_SHIFT 1 +#define IDS_PER_DECPROT_REGS 16U +#define IDS_PER_DECPROT_LOCK_REGS 32U + +/* + * etzpc_instance. + * base : register base address set during init given by user + * chunk_size : supported TZMA size steps + * num_tzma: number of TZMA zone read from register at init + * num_ahb_sec : number of securable AHB master zone read from register + * num_per_sec : number of securable AHB & APB Peripherals read from register + * revision : IP revision read from register at init + */ +struct etzpc_instance { + uintptr_t base; + uint8_t chunck_size; + uint8_t num_tzma; + uint8_t num_per_sec; + uint8_t num_ahb_sec; + uint8_t revision; +}; + +/* Only 1 instance of the ETZPC is expected per platform */ +static struct etzpc_instance etzpc_dev; + +/* + * Implementation uses uint8_t to store each securable DECPROT configuration. + * When resuming from deep suspend, the DECPROT configurations are restored. + */ +#define PERIPH_LOCK_BIT BIT(7) +#define PERIPH_ATTR_MASK GENMASK(2, 0) + +#if ENABLE_ASSERTIONS +static bool valid_decprot_id(unsigned int id) +{ + return id < (unsigned int)etzpc_dev.num_per_sec; +} + +static bool valid_tzma_id(unsigned int id) +{ + return id < (unsigned int)etzpc_dev.num_tzma; +} +#endif + +/* + * etzpc_configure_decprot : Load a DECPROT configuration + * decprot_id : ID of the IP + * decprot_attr : Restriction access attribute + */ +void etzpc_configure_decprot(uint32_t decprot_id, + enum etzpc_decprot_attributes decprot_attr) +{ + uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_REGS); + uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT; + uint32_t masked_decprot = (uint32_t)decprot_attr & ETZPC_DECPROT0_MASK; + + assert(valid_decprot_id(decprot_id)); + + mmio_clrsetbits_32(etzpc_dev.base + ETZPC_DECPROT0 + offset, + (uint32_t)ETZPC_DECPROT0_MASK << shift, + masked_decprot << shift); +} + +/* + * etzpc_get_decprot : Get the DECPROT attribute + * decprot_id : ID of the IP + * return : Attribute of this DECPROT + */ +enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id) +{ + uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_REGS); + uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT; + uintptr_t base_decprot = etzpc_dev.base + offset; + uint32_t value; + + assert(valid_decprot_id(decprot_id)); + + value = (mmio_read_32(base_decprot + ETZPC_DECPROT0) >> shift) & + ETZPC_DECPROT0_MASK; + + return (enum etzpc_decprot_attributes)value; +} + +/* + * etzpc_lock_decprot : Lock access to the DECPROT attribute + * decprot_id : ID of the IP + */ +void etzpc_lock_decprot(uint32_t decprot_id) +{ + uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_LOCK_REGS); + uint32_t shift = BIT(decprot_id % IDS_PER_DECPROT_LOCK_REGS); + uintptr_t base_decprot = etzpc_dev.base + offset; + + assert(valid_decprot_id(decprot_id)); + + mmio_write_32(base_decprot + ETZPC_DECPROT_LOCK0, shift); +} + +/* + * etzpc_configure_tzma : Configure the target TZMA read only size + * tzma_id : ID of the memory + * tzma_value : read-only size + */ +void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value) +{ + assert(valid_tzma_id(tzma_id)); + + mmio_write_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + + (sizeof(uint32_t) * tzma_id), tzma_value); +} + +/* + * etzpc_get_tzma : Get the target TZMA read only size + * tzma_id : TZMA ID + * return : Size of read only size + */ +uint16_t etzpc_get_tzma(uint32_t tzma_id) +{ + assert(valid_tzma_id(tzma_id)); + + return (uint16_t)mmio_read_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + + (sizeof(uint32_t) * tzma_id)); +} + +/* + * etzpc_lock_tzma : Lock the target TZMA + * tzma_id : TZMA ID + */ +void etzpc_lock_tzma(uint32_t tzma_id) +{ + assert(valid_tzma_id(tzma_id)); + + mmio_setbits_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + + (sizeof(uint32_t) * tzma_id), ETZPC_TZMA0_SIZE_LOCK); +} + +/* + * etzpc_get_lock_tzma : Return the lock status of the target TZMA + * tzma_id : TZMA ID + * return : True if TZMA is locked, false otherwise + */ +bool etzpc_get_lock_tzma(uint32_t tzma_id) +{ + uint32_t tzma_size; + + assert(valid_tzma_id(tzma_id)); + + tzma_size = mmio_read_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + + (sizeof(uint32_t) * tzma_id)); + + return (tzma_size & ETZPC_TZMA0_SIZE_LOCK) != 0; +} + +/* + * etzpc_get_num_per_sec : Return the DECPROT ID limit value + */ +uint8_t etzpc_get_num_per_sec(void) +{ + return etzpc_dev.num_per_sec; +} + +/* + * etzpc_get_revision : Return the ETZPC IP revision + */ +uint8_t etzpc_get_revision(void) +{ + return etzpc_dev.revision; +} + +/* + * etzpc_get_base_address : Return the ETZPC IP base address + */ +uintptr_t etzpc_get_base_address(void) +{ + return etzpc_dev.base; +} + +/* + * etzpc_init : Initialize the ETZPC driver + * Return 0 on success and a negative errno on failure + */ +int etzpc_init(void) +{ + uint32_t hwcfg; + int node; + struct dt_node_info etzpc_info; + + node = dt_get_node(&etzpc_info, -1, ETZPC_COMPAT); + if (node < 0) { + return -EIO; + } + + /* Check ETZPC is secure only */ + if (etzpc_info.status != DT_SECURE) { + return -EACCES; + } + + etzpc_dev.base = etzpc_info.base; + + hwcfg = mmio_read_32(etzpc_dev.base + ETZPC_HWCFGR); + + etzpc_dev.num_tzma = (uint8_t)(hwcfg >> ETZPC_HWCFGR_NUM_TZMA_SHIFT); + etzpc_dev.num_per_sec = (uint8_t)(hwcfg >> + ETZPC_HWCFGR_NUM_PER_SEC_SHIFT); + etzpc_dev.num_ahb_sec = (uint8_t)(hwcfg >> + ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT); + etzpc_dev.chunck_size = (uint8_t)(hwcfg >> + ETZPC_HWCFGR_CHUNCKS1N4_SHIFT); + + etzpc_dev.revision = mmio_read_8(etzpc_dev.base + ETZPC_VERR); + + VERBOSE("ETZPC version 0x%x", etzpc_dev.revision); + + return 0; +} diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c index b694fff6b..a58a243ad 100644 --- a/drivers/st/fmc/stm32_fmc2_nand.c +++ b/drivers/st/fmc/stm32_fmc2_nand.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -22,9 +22,14 @@ #include <lib/mmio.h> #include <lib/utils_def.h> +/* Timeout for device interface reset */ +#define TIMEOUT_US_1_MS 1000U + /* FMC2 Compatibility */ -#define DT_FMC2_COMPAT "st,stm32mp15-fmc2" +#define DT_FMC2_EBI_COMPAT "st,stm32mp1-fmc2-ebi" +#define DT_FMC2_NFC_COMPAT "st,stm32mp1-fmc2-nfc" #define MAX_CS 2U +#define MAX_BANK 5U /* FMC2 Controller Registers */ #define FMC2_BCR1 0x00U @@ -34,6 +39,7 @@ #define FMC2_PATT 0x8CU #define FMC2_HECCR 0x94U #define FMC2_BCHISR 0x254U +#define FMC2_BCHICR 0x258U #define FMC2_BCHDSR0 0x27CU #define FMC2_BCHDSR1 0x280U #define FMC2_BCHDSR2 0x284U @@ -79,6 +85,8 @@ #define FMC2_PATT_DEFAULT 0x0A0A0A0AU /* FMC2_BCHISR register */ #define FMC2_BCHISR_DERF BIT(1) +/* FMC2_BCHICR register */ +#define FMC2_BCHICR_CLEAR_IRQ GENMASK_32(4, 0) /* FMC2_BCHDSR0 register */ #define FMC2_BCHDSR0_DUE BIT(0) #define FMC2_BCHDSR0_DEF BIT(1) @@ -365,7 +373,7 @@ static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer, xor_ecc_2b = ecc[1] ^ eccbuffer[1]; xor_ecc_3b = ecc[2] ^ eccbuffer[2]; - xor_ecc.val = 0L; + xor_ecc.val = 0U; xor_ecc.bytes[2] = xor_ecc_3b; xor_ecc.bytes[1] = xor_ecc_2b; xor_ecc.bytes[0] = xor_ecc_1b; @@ -497,6 +505,7 @@ static void stm32_fmc2_hwctl(struct nand_device *nand) if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) { mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN); + mmio_write_32(fmc2_base() + FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ); } stm32_fmc2_set_ecc(true); @@ -786,22 +795,26 @@ static const struct nand_ctrl_ops ctrl_ops = { int stm32_fmc2_init(void) { - int fmc_node; - int fmc_subnode = 0; + int fmc_ebi_node; + int fmc_nfc_node; + int fmc_flash_node = 0; int nchips = 0; unsigned int i; void *fdt = NULL; const fdt32_t *cuint; struct dt_node_info info; + uintptr_t bank_address[MAX_BANK] = { 0, 0, 0, 0, 0 }; + uint8_t bank_assigned = 0; + uint8_t bank; + int ret; if (fdt_get_address(&fdt) == 0) { return -FDT_ERR_NOTFOUND; } - fmc_node = dt_get_node(&info, -1, DT_FMC2_COMPAT); - if (fmc_node == -FDT_ERR_NOTFOUND) { - WARN("No FMC2 node found\n"); - return fmc_node; + fmc_ebi_node = dt_get_node(&info, -1, DT_FMC2_EBI_COMPAT); + if (fmc_ebi_node < 0) { + return fmc_ebi_node; } if (info.status == DT_DISABLED) { @@ -817,27 +830,69 @@ int stm32_fmc2_init(void) stm32_fmc2.clock_id = (unsigned long)info.clock; stm32_fmc2.reset_id = (unsigned int)info.reset; - cuint = fdt_getprop(fdt, fmc_node, "reg", NULL); + cuint = fdt_getprop(fdt, fmc_ebi_node, "ranges", NULL); if (cuint == NULL) { return -FDT_ERR_BADVALUE; } - cuint += 2; - - for (i = 0U; i < MAX_CS; i++) { - stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*cuint); - stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 2)); - stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 4)); - cuint += 6; + for (i = 0U; i < MAX_BANK; i++) { + bank = fdt32_to_cpu(*cuint); + if ((bank >= MAX_BANK) || ((bank_assigned & BIT(bank)) != 0U)) { + return -FDT_ERR_BADVALUE; + } + bank_assigned |= BIT(bank); + bank_address[bank] = fdt32_to_cpu(*(cuint + 2)); + cuint += 4; } /* Pinctrl initialization */ - if (dt_set_pinctrl_config(fmc_node) != 0) { + if (dt_set_pinctrl_config(fmc_ebi_node) != 0) { + return -FDT_ERR_BADVALUE; + } + + /* Parse NFC controller node */ + fmc_nfc_node = fdt_node_offset_by_compatible(fdt, fmc_ebi_node, + DT_FMC2_NFC_COMPAT); + if (fmc_nfc_node < 0) { + return fmc_nfc_node; + } + + if (fdt_get_status(fmc_nfc_node) == DT_DISABLED) { + return -FDT_ERR_NOTFOUND; + } + + cuint = fdt_getprop(fdt, fmc_nfc_node, "reg", NULL); + if (cuint == NULL) { return -FDT_ERR_BADVALUE; } + for (i = 0U; i < MAX_CS; i++) { + bank = fdt32_to_cpu(*cuint); + if (bank >= MAX_BANK) { + return -FDT_ERR_BADVALUE; + } + stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*(cuint + 1)) + + bank_address[bank]; + + bank = fdt32_to_cpu(*(cuint + 3)); + if (bank >= MAX_BANK) { + return -FDT_ERR_BADVALUE; + } + stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 4)) + + bank_address[bank]; + + bank = fdt32_to_cpu(*(cuint + 6)); + if (bank >= MAX_BANK) { + return -FDT_ERR_BADVALUE; + } + stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 7)) + + bank_address[bank]; + + cuint += 9; + } + /* Parse flash nodes */ - fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) { + fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) { nchips++; } @@ -846,14 +901,19 @@ int stm32_fmc2_init(void) return -FDT_ERR_BADVALUE; } - fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) { + fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) { /* Get chip select */ - cuint = fdt_getprop(fdt, fmc_subnode, "reg", NULL); + cuint = fdt_getprop(fdt, fmc_flash_node, "reg", NULL); if (cuint == NULL) { WARN("Chip select not well defined\n"); return -FDT_ERR_BADVALUE; } + stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint); + if (stm32_fmc2.cs_sel >= MAX_CS) { + return -FDT_ERR_BADVALUE; + } + VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel); } @@ -861,8 +921,14 @@ int stm32_fmc2_init(void) stm32mp_clk_enable(stm32_fmc2.clock_id); /* Reset IP */ - stm32mp_reset_assert(stm32_fmc2.reset_id); - stm32mp_reset_deassert(stm32_fmc2.reset_id); + ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS); + if (ret != 0) { + panic(); + } + ret = stm32mp_reset_deassert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS); + if (ret != 0) { + panic(); + } /* Setup default IP registers */ stm32_fmc2_ctrl_init(); diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c index a13c341a8..7d63262d7 100644 --- a/drivers/st/gpio/stm32_gpio.c +++ b/drivers/st/gpio/stm32_gpio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -161,13 +161,14 @@ int dt_set_pinctrl_config(int node) const fdt32_t *cuint; int lenp = 0; uint32_t i; - uint8_t status = fdt_get_status(node); + uint8_t status; void *fdt; if (fdt_get_address(&fdt) == 0) { return -FDT_ERR_NOTFOUND; } + status = fdt_get_status(node); if (status == DT_DISABLED) { return -FDT_ERR_NOTFOUND; } @@ -254,6 +255,15 @@ void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, mmio_read_32(base + GPIO_AFRH_OFFSET)); stm32mp_clk_disable(clock); + + if (status == DT_SECURE) { + stm32mp_register_secure_gpio(bank, pin); + set_gpio_secure_cfg(bank, pin, true); + + } else { + stm32mp_register_non_secure_gpio(bank, pin); + set_gpio_secure_cfg(bank, pin, false); + } } void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c index 44b7d1907..0ed71540c 100644 --- a/drivers/st/io/io_mmc.c +++ b/drivers/st/io/io_mmc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -97,14 +97,21 @@ static int mmc_block_seek(io_entity_t *entity, int mode, static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { - *length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE, - buffer, length); - - if (*length_read != length) { - return -EIO; + uint8_t retries; + + for (retries = 0U; retries < 3U; retries++) { + *length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE, + buffer, length); + + if (*length_read == length) { + return 0; + } + WARN("%s: length_read = %lu (!= %lu), retry %u\n", __func__, + (unsigned long)*length_read, (unsigned long)length, + retries + 1U); } - return 0; + return -EIO; } /* Close a file on the mmc device */ diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c index 413521b1e..3e377cd48 100644 --- a/drivers/st/io/io_stm32image.c +++ b/drivers/st/io/io_stm32image.c @@ -247,7 +247,7 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { int result; - uint8_t *local_buffer = (uint8_t *)buffer; + uint8_t *local_buffer; boot_api_image_header_t *header = (boot_api_image_header_t *)first_lba_buffer; @@ -255,6 +255,7 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer, assert(buffer != 0U); assert(length_read != NULL); + local_buffer = (uint8_t *)buffer; *length_read = 0U; while (*length_read == 0U) { diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c index ea6fbb2b9..c052b4dfb 100644 --- a/drivers/st/iwdg/stm32_iwdg.c +++ b/drivers/st/iwdg/stm32_iwdg.c @@ -137,6 +137,12 @@ int stm32_iwdg_init(void) ((dt_info.status & DT_NON_SECURE) != 0) ? "non-" : ""); + if ((dt_info.status & DT_NON_SECURE) != 0) { + stm32mp_register_non_secure_periph_iomem(iwdg->base); + } else { + stm32mp_register_secure_periph_iomem(iwdg->base); + } + #if defined(IMAGE_BL2) if (stm32_iwdg_shadow_update(idx, iwdg->flags) != BSEC_OK) { return -1; diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c index 24e6efe98..cff3a344f 100644 --- a/drivers/st/mmc/stm32_sdmmc2.c +++ b/drivers/st/mmc/stm32_sdmmc2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -113,6 +113,7 @@ SDMMC_STAR_IDMATE | \ SDMMC_STAR_IDMABTC) +#define TIMEOUT_US_1_MS 1000U #define TIMEOUT_US_10_MS 10000U #define TIMEOUT_US_1_S 1000000U @@ -257,6 +258,18 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) break; } + mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS); + + /* + * Clear the SDMMC_DCTRLR if the command does not await data. + * Skip CMD55 as the next command could be data related, and + * the register could have been set in prepare function. + */ + if (((cmd_reg & SDMMC_CMDR_CMDTRANS) == 0U) && + (cmd->cmd_idx != MMC_CMD(55))) { + mmio_write_32(base + SDMMC_DCTRLR, 0U); + } + if ((cmd->resp_type & MMC_RSP_BUSY) != 0U) { mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX); } @@ -372,15 +385,15 @@ err_exit: static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd) { - int8_t retry; - int err = 0; + uint8_t retry; + int err; assert(cmd != NULL); - for (retry = 0; retry <= 3; retry++) { + for (retry = 0U; retry < 3U; retry++) { err = stm32_sdmmc2_send_cmd_req(cmd); if (err == 0) { - return err; + return 0; } if ((cmd->cmd_idx == MMC_CMD(1)) || @@ -389,12 +402,12 @@ static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd) } /* Command 8 is expected to fail for eMMC */ - if (!(cmd->cmd_idx == MMC_CMD(8))) { - WARN(" CMD%d, Retry: %d, Error: %d\n", - cmd->cmd_idx, retry, err); + if (cmd->cmd_idx != MMC_CMD(8)) { + WARN(" CMD%u, Retry: %u, Error: %d\n", + cmd->cmd_idx, retry + 1U, err); } - udelay(10); + udelay(10U); } return err; @@ -711,6 +724,8 @@ unsigned long long stm32_sdmmc2_mmc_get_device_size(void) int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) { + int rc; + assert((params != NULL) && ((params->reg_base & MMC_BLOCK_MASK) == 0U) && ((params->bus_width == MMC_BUS_WIDTH_1) || @@ -726,9 +741,15 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) stm32mp_clk_enable(sdmmc2_params.clock_id); - stm32mp_reset_assert(sdmmc2_params.reset_id); + rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS); + if (rc != 0) { + panic(); + } udelay(2); - stm32mp_reset_deassert(sdmmc2_params.reset_id); + rc = stm32mp_reset_deassert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS); + if (rc != 0) { + panic(); + } mdelay(1); sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id); diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c index 9e9dddc4d..b2bb482f9 100644 --- a/drivers/st/pmic/stm32mp_pmic.c +++ b/drivers/st/pmic/stm32mp_pmic.c @@ -54,6 +54,15 @@ int dt_pmic_status(void) return fdt_get_status(node); } +static bool dt_pmic_is_secure(void) +{ + int status = dt_pmic_status(); + + return (status >= 0) && + (status == DT_SECURE) && + (i2c_handle.dt_status == DT_SECURE); +} + /* * 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. @@ -223,6 +232,19 @@ bool initialize_pmic_i2c(void) return true; } +static void register_pmic_shared_peripherals(void) +{ + uintptr_t i2c_base = i2c_handle.i2c_base_addr; + + if (dt_pmic_is_secure()) { + stm32mp_register_secure_periph_iomem(i2c_base); + } else { + if (i2c_base != 0U) { + stm32mp_register_non_secure_periph_iomem(i2c_base); + } + } +} + void initialize_pmic(void) { unsigned long pmic_version; @@ -232,6 +254,8 @@ void initialize_pmic(void) return; } + register_pmic_shared_peripherals(); + if (stpmic1_get_version(&pmic_version) != 0) { ERROR("Failed to access PMIC\n"); panic(); diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c index fd3f93e01..98c8dcf71 100644 --- a/drivers/st/reset/stm32mp1_reset.c +++ b/drivers/st/reset/stm32mp1_reset.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include <errno.h> #include <limits.h> #include <platform_def.h> @@ -15,8 +16,6 @@ #include <lib/mmio.h> #include <lib/utils_def.h> -#define RESET_TIMEOUT_US_1MS U(1000) - static uint32_t id2reg_offset(unsigned int reset_id) { return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t); @@ -27,36 +26,44 @@ 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) +int stm32mp_reset_assert(uint32_t id, unsigned int to_us) { 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(); + if (to_us != 0U) { + uint64_t timeout_ref = timeout_init_us(to_us); + + while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) { + if (timeout_elapsed(timeout_ref)) { + return -ETIMEDOUT; + } } } + + return 0; } -void stm32mp_reset_deassert(uint32_t id) +int stm32mp_reset_deassert(uint32_t id, unsigned int to_us) { 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, 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(); + if (to_us != 0U) { + uint64_t timeout_ref = timeout_init_us(to_us); + + while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) { + if (timeout_elapsed(timeout_ref)) { + return -ETIMEDOUT; + } } } + + return 0; } diff --git a/drivers/st/spi/stm32_qspi.c b/drivers/st/spi/stm32_qspi.c index 188d2ff80..d67f8313f 100644 --- a/drivers/st/spi/stm32_qspi.c +++ b/drivers/st/spi/stm32_qspi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -9,13 +9,18 @@ #include <platform_def.h> #include <common/debug.h> +#include <common/fdt_wrappers.h> #include <drivers/delay_timer.h> #include <drivers/spi_mem.h> #include <drivers/st/stm32_gpio.h> +#include <drivers/st/stm32_qspi.h> #include <drivers/st/stm32mp_reset.h> #include <lib/mmio.h> #include <lib/utils_def.h> +/* Timeout for device interface reset */ +#define TIMEOUT_US_1_MS 1000U + /* QUADSPI registers */ #define QSPI_CR 0x00U #define QSPI_DCR 0x04U @@ -172,9 +177,8 @@ static void stm32_qspi_write_fifo(uint8_t *val, uintptr_t addr) static int stm32_qspi_poll(const struct spi_mem_op *op) { void (*fifo)(uint8_t *val, uintptr_t addr); - uint32_t len = op->data.nbytes; + uint32_t len; uint8_t *buf; - uint64_t timeout; if (op->data.dir == SPI_MEM_DATA_IN) { fifo = stm32_qspi_read_fifo; @@ -185,7 +189,8 @@ static int stm32_qspi_poll(const struct spi_mem_op *op) buf = (uint8_t *)op->data.buf; for (len = op->data.nbytes; len != 0U; len--) { - timeout = timeout_init_us(QSPI_FIFO_TIMEOUT_US); + uint64_t timeout = timeout_init_us(QSPI_FIFO_TIMEOUT_US); + while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_FTF) == 0U) { if (timeout_elapsed(timeout)) { @@ -464,13 +469,13 @@ int stm32_qspi_init(void) return -FDT_ERR_NOTFOUND; } - ret = fdt_get_reg_props_by_name(qspi_node, "qspi", + ret = fdt_get_reg_props_by_name(fdt, qspi_node, "qspi", &stm32_qspi.reg_base, &size); if (ret != 0) { return ret; } - ret = fdt_get_reg_props_by_name(qspi_node, "qspi_mm", + ret = fdt_get_reg_props_by_name(fdt, qspi_node, "qspi_mm", &stm32_qspi.mm_base, &stm32_qspi.mm_size); if (ret != 0) { @@ -490,8 +495,14 @@ int stm32_qspi_init(void) stm32mp_clk_enable(stm32_qspi.clock_id); - stm32mp_reset_assert(stm32_qspi.reset_id); - stm32mp_reset_deassert(stm32_qspi.reset_id); + ret = stm32mp_reset_assert(stm32_qspi.reset_id, TIMEOUT_US_1_MS); + if (ret != 0) { + panic(); + } + ret = stm32mp_reset_deassert(stm32_qspi.reset_id, TIMEOUT_US_1_MS); + if (ret != 0) { + panic(); + } mmio_write_32(qspi_base() + QSPI_CR, QSPI_CR_SSHIFT); mmio_write_32(qspi_base() + QSPI_DCR, QSPI_DCR_FSIZE_MASK); diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S index ca3c1f618..686b18b96 100644 --- a/drivers/st/uart/aarch32/stm32_console.S +++ b/drivers/st/uart/aarch32/stm32_console.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -91,14 +91,14 @@ endfunc console_stm32_core_init /* ------------------------------------------------------- * int console_stm32_register(uintptr_t baseaddr, * uint32_t clock, uint32_t baud, - * struct console_stm32 *console); + * console_t *console); * Function to initialize and register a new STM32 * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: r0 - UART register base address * r1 - UART clock in Hz * r2 - Baud rate - * r3 - pointer to empty console_stm32 struct + * r3 - pointer to empty console_t struct * Out: return 1 on success, 0 on error * Clobber list : r0, r1, r2 * ------------------------------------------------------- @@ -108,7 +108,7 @@ func console_stm32_register mov r4, r3 cmp r4, #0 beq register_fail - str r0, [r4, #CONSOLE_T_STM32_BASE] + str r0, [r4, #CONSOLE_T_BASE] bl console_stm32_core_init cmp r0, #0 @@ -157,7 +157,7 @@ putc_error: endfunc console_stm32_core_putc /* ------------------------------------------------------------ - * int console_stm32_putc(int c, struct console_stm32 *console) + * int console_stm32_putc(int c, console_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In: r0 - character to be printed @@ -171,7 +171,7 @@ func console_stm32_putc cmp r1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ - ldr r1, [r1, #CONSOLE_T_STM32_BASE] + ldr r1, [r1, #CONSOLE_T_BASE] b console_stm32_core_putc endfunc console_stm32_putc @@ -193,37 +193,35 @@ func console_stm32_core_getc endfunc console_stm32_core_getc /* --------------------------------------------------------------- - * int console_core_flush(uintptr_t base_addr) + * void console_core_flush(uintptr_t base_addr) * * Function to force a write of all buffered data that hasn't been * output. * * In : r0 - console base address - * Out : return -1 on error else return 0. + * Out : void. * Clobber list : r0, r1 * --------------------------------------------------------------- */ func console_stm32_core_flush +#if ENABLE_ASSERTIONS cmp r0, #0 - beq flush_error + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ /* Check Transmit Data Register Empty */ txe_loop_3: ldr r1, [r0, #USART_ISR] tst r1, #USART_ISR_TXE beq txe_loop_3 - mov r0, #0 - bx lr -flush_error: - mov r0, #-1 bx lr endfunc console_stm32_core_flush /* ------------------------------------------------------ - * int console_stm32_flush(struct console_stm32 *console) + * void console_stm32_flush(console_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : r0 - pointer to console_t structure - * Out : return -1 on error else return 0. + * Out : void. * Clobber list: r0, r1 * ------------------------------------------------------ */ @@ -232,6 +230,6 @@ func console_stm32_flush cmp r0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ - ldr r0, [r0, #CONSOLE_T_STM32_BASE] + ldr r0, [r0, #CONSOLE_T_BASE] b console_stm32_core_flush endfunc console_stm32_flush |