diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c index 8edf3389e..39ad90b7e 100644 --- a/plat/st/stm32mp1/stm32mp1_syscfg.c +++ b/plat/st/stm32mp1/stm32mp1_syscfg.c @@ -4,12 +4,16 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include + #include #include #include #include #include #include +#include #include #include @@ -34,6 +38,7 @@ #define SYSCFG_CMPSD2CR 0x40U #define SYSCFG_CMPSD2ENSETR 0x44U #define SYSCFG_CMPSD2ENCLRR 0x48U +#define SYSCFG_HSLVEN0R 0x50U #endif #define SYSCFG_IDC 0x380U @@ -80,6 +85,25 @@ */ #define SYSCFG_CMPENSETR_MPU_EN BIT(0) +/* + * HSLV definitions + */ +#define HSLV_IDX_TPIU 0U +#define HSLV_IDX_QSPI 1U +#define HSLV_IDX_ETH1 2U +#define HSLV_IDX_ETH2 3U +#define HSLV_IDX_SDMMC1 4U +#define HSLV_IDX_SDMMC2 5U +#define HSLV_IDX_SPI1 6U +#define HSLV_IDX_SPI2 7U +#define HSLV_IDX_SPI3 8U +#define HSLV_IDX_SPI4 9U +#define HSLV_IDX_SPI5 10U +#define HSLV_IDX_LTDC 11U +#define HSLV_NB_IDX 12U + +#define HSLV_KEY 0x1018U + /* * SYSCFG_IDC Register */ @@ -126,8 +150,99 @@ static void disable_io_comp_cell(uintptr_t cmpcr_off) mmio_setbits_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENCLRR_OFFSET, SYSCFG_CMPENSETR_MPU_EN); } +#if STM32MP13 +static int get_regu_max_voltage(void *fdt, int sdmmc_node, + const char *regu_name, uint32_t *regu_val) +{ + int node; + const fdt32_t *cuint; + + cuint = fdt_getprop(fdt, sdmmc_node, regu_name, NULL); + if (cuint == NULL) { + return -ENODEV; + } + + node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); + if (node < 0) { + return -ENODEV; + } + + cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); + if (cuint == NULL) { + return -ENODEV; + } + + *regu_val = fdt32_to_cpu(*cuint); + + return 0; +} + +static bool sdmmc_is_low_voltage(uintptr_t sdmmc_base) +{ + int ret; + int node; + void *fdt = NULL; + uint32_t regu_max_val; + + if (fdt_get_address(&fdt) == 0) { + return false; + } + + if (fdt == NULL) { + return false; + } + + node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT, sdmmc_base); + if (node < 0) { + /* No SD or eMMC device on this instance, enable HSLV */ + return true; + } + + ret = get_regu_max_voltage(fdt, node, "vqmmc-supply", ®u_max_val); + if ((ret < 0) || (regu_max_val > 1800000U)) { + /* + * The vqmmc-supply property should always be present for eMMC. + * For SD-card, if it is not, then the card only supports 3.3V. + */ + return false; + } + + return true; +} + +static void enable_hslv_by_index(uint32_t index) +{ + bool apply_hslv; + + assert(index < HSLV_NB_IDX); + + switch (index) { + case HSLV_IDX_SDMMC1: + apply_hslv = sdmmc_is_low_voltage(STM32MP_SDMMC1_BASE); + break; + case HSLV_IDX_SDMMC2: + apply_hslv = sdmmc_is_low_voltage(STM32MP_SDMMC2_BASE); + break; + default: + apply_hslv = true; + break; + } + + if (apply_hslv) { + mmio_write_32(SYSCFG_BASE + SYSCFG_HSLVEN0R + index * sizeof(uint32_t), HSLV_KEY); + } +} +#endif + static void enable_high_speed_mode_low_voltage(void) { +#if STM32MP13 + uint32_t idx; + + for (idx = 0U; idx < HSLV_NB_IDX; idx++) { + enable_hslv_by_index(idx); + } +#endif #if STM32MP15 mmio_write_32(SYSCFG_BASE + SYSCFG_IOCTRLSETR, SYSCFG_IOCTRLSETR_HSLVEN_TRACE |