feat(stm32mp1): manage HSLV on STM32MP13

On STM32MP13, the high speed mode for pads in low voltage is different
from STM32MP15. Each peripheral supporting the feature has its own
register.
Special care is taken for SDMMC peripherals. The HSLV mode is enabled
only if the max voltage for the pads is lower or equal to 1.8V.

Change-Id: Id94d2cca17dd4aca4d764230a643b2bb9a5f3342
Signed-off-by: Yann Gautier <yann.gautier@st.com>
diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c
index 8edf338..39ad90b 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 <assert.h>
+#include <errno.h>
+
 #include <common/debug.h>
 #include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/st/stpmic1.h>
 #include <lib/mmio.h>
 #include <lib/utils_def.h>
+#include <libfdt.h>
 
 #include <platform_def.h>
 #include <stm32mp_common.h>
@@ -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
 
@@ -81,6 +86,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
  */
 #define SYSCFG_IDC_DEV_ID_MASK			GENMASK(11, 0)
@@ -126,8 +150,99 @@
 	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", &regu_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 |