feat(stm32mp2): handle DDR power supplies

Modify platform driver to handle the DDR power supplies when
a PMIC is present.

Signed-off-by: Pascal Paillet <p.paillet@st.com>
Change-Id: I98df132a63c2ad351d4dae949f5dbb831cc40637
diff --git a/plat/st/stm32mp2/plat_ddr.c b/plat/st/stm32mp2/plat_ddr.c
new file mode 100644
index 0000000..b665062
--- /dev/null
+++ b/plat/st/stm32mp2/plat_ddr.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2023-2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <common/fdt_wrappers.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/regulator.h>
+#include <drivers/st/stm32mp_ddr.h>
+
+#include <libfdt.h>
+#include <platform_def.h>
+
+#if STM32MP_DDR3_TYPE
+struct ddr3_supply {
+	struct rdev *vdd;
+	struct rdev *vref;
+	struct rdev *vtt;
+};
+
+static void ddr3_supply_read(void *fdt, int node, struct ddr3_supply *supply)
+{
+	supply->vdd = regulator_get_by_supply_name(fdt, node, "vdd");
+	supply->vref = regulator_get_by_supply_name(fdt, node, "vref");
+	supply->vtt = regulator_get_by_supply_name(fdt, node, "vtt");
+}
+
+static int ddr_power_init(void *fdt, int node)
+{
+	int status;
+	struct ddr3_supply supply;
+
+	ddr3_supply_read(fdt, node, &supply);
+	if ((supply.vdd == NULL) || (supply.vref == NULL) || (supply.vtt == NULL)) {
+		return -ENOENT;
+	}
+
+	/*
+	 * DDR3 power on sequence is:
+	 * enable VREF_DDR, VTT_DDR, VPP_DDR
+	 */
+	status = regulator_set_min_voltage(supply.vdd);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vdd);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vref);
+	if (status != 0) {
+		return status;
+	}
+
+	return regulator_enable(supply.vtt);
+}
+#endif /* STM32MP_DDR3_TYPE */
+
+#if STM32MP_DDR4_TYPE
+struct ddr4_supply {
+	struct rdev *vdd;
+	struct rdev *vref;
+	struct rdev *vtt;
+	struct rdev *vpp;
+};
+
+static void ddr4_supply_read(void *fdt, int node, struct ddr4_supply *supply)
+{
+	supply->vpp = regulator_get_by_supply_name(fdt, node, "vpp");
+	supply->vdd = regulator_get_by_supply_name(fdt, node, "vdd");
+	supply->vref = regulator_get_by_supply_name(fdt, node, "vref");
+	supply->vtt = regulator_get_by_supply_name(fdt, node, "vtt");
+}
+
+static int ddr_power_init(void *fdt, int node)
+{
+	int status;
+	struct ddr4_supply supply;
+
+	ddr4_supply_read(fdt, node, &supply);
+	if ((supply.vpp == NULL) || (supply.vdd == NULL) || (supply.vref == NULL) ||
+	    (supply.vtt == NULL)) {
+		return -ENOENT;
+	}
+
+	/*
+	 * DDR4 power on sequence is:
+	 * enable VPP_DDR
+	 * enable VREF_DDR, VTT_DDR, VPP_DDR
+	 */
+	status = regulator_set_min_voltage(supply.vpp);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_set_min_voltage(supply.vdd);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vpp);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vdd);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vref);
+	if (status != 0) {
+		return status;
+	}
+
+	return regulator_enable(supply.vtt);
+}
+#endif /* STM32MP_DDR4_TYPE */
+
+#if STM32MP_LPDDR4_TYPE
+struct lpddr4_supply {
+	struct rdev *vdd1;
+	struct rdev *vdd2;
+	struct rdev *vddq;
+};
+
+static void lpddr4_supply_read(void *fdt, int node, struct lpddr4_supply *supply)
+{
+	supply->vdd1 = regulator_get_by_supply_name(fdt, node, "vdd1");
+	supply->vdd2 = regulator_get_by_supply_name(fdt, node, "vdd2");
+	supply->vddq = regulator_get_by_supply_name(fdt, node, "vddq");
+}
+
+static int ddr_power_init(void *fdt, int node)
+{
+	int status;
+	struct lpddr4_supply supply;
+
+	lpddr4_supply_read(fdt, node, &supply);
+	if ((supply.vdd1 == NULL) || (supply.vdd2 == NULL) || (supply.vddq == NULL)) {
+		return -ENOENT;
+	}
+
+	/*
+	 * LPDDR4 power on sequence is:
+	 * enable VDD1_DDR
+	 * enable VDD2_DDR
+	 * enable VDDQ_DDR
+	 */
+	status = regulator_set_min_voltage(supply.vdd1);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_set_min_voltage(supply.vdd2);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_set_min_voltage(supply.vddq);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vdd1);
+	if (status != 0) {
+		return status;
+	}
+
+	status = regulator_enable(supply.vdd2);
+	if (status != 0) {
+		return status;
+	}
+
+	return regulator_enable(supply.vddq);
+}
+#endif /* STM32MP_LPDDR4_TYPE */
+
+int stm32mp_board_ddr_power_init(enum ddr_type ddr_type)
+{
+	void *fdt = NULL;
+	int node;
+
+	VERBOSE("DDR power init, ddr_type = %u\n", ddr_type);
+
+#if STM32MP_DDR3_TYPE
+	assert(ddr_type == STM32MP_DDR3);
+#elif STM32MP_DDR4_TYPE
+	assert(ddr_type == STM32MP_DDR4);
+#elif STM32MP_LPDDR4_TYPE
+	assert(ddr_type == STM32MP_LPDDR4);
+#else
+	ERROR("DDR type (%u) not supported\n", ddr_type);
+	panic();
+#endif
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
+	if (node < 0) {
+		ERROR("%s: Cannot read DDR node in DT\n", __func__);
+		return -EINVAL;
+	}
+
+	return ddr_power_init(fdt, node);
+}