stm32mp1: ram: add tests in DDR interactive mode

Add command tests for DDR interactive mode, used during
board bring-up or with CubeMX DDR tools to verify the
DDR configuration.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
index 1a31948..62d61ac 100644
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
@@ -11,6 +11,7 @@
 #include <ram.h>
 #include <reset.h>
 #include "stm32mp1_ddr.h"
+#include "stm32mp1_tests.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -51,6 +52,9 @@
 		[DDR_CMD_STEP] = "step",
 		[DDR_CMD_NEXT] = "next",
 		[DDR_CMD_GO] = "go",
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+		[DDR_CMD_TEST] = "test",
+#endif
 	};
 	/* min and max number of argument */
 	const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
@@ -64,6 +68,9 @@
 		[DDR_CMD_STEP] = { 0, 1 },
 		[DDR_CMD_NEXT] = { 0, 0 },
 		[DDR_CMD_GO] = { 0, 0 },
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+		[DDR_CMD_TEST] = { 0, 255 },
+#endif
 	};
 	int i;
 
@@ -105,6 +112,9 @@
 		"next                       goes to the next step\n"
 		"go                         continues the U-Boot SPL execution\n"
 		"reset                      reboots machine\n"
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+		"test [help] | <n> [...]    lists (with help) or executes test <n>\n"
+#endif
 		"\nwith for [type|reg]:\n"
 		"  all registers if absent\n"
 		"  <type> = ctl, phy\n"
@@ -287,6 +297,63 @@
 	return step;
 }
 
+#if defined(CONFIG_STM32MP1_DDR_TESTS)
+static const char * const s_result[] = {
+		[TEST_PASSED] = "Pass",
+		[TEST_FAILED] = "Failed",
+		[TEST_ERROR] = "Error"
+};
+
+static void stm32mp1_ddr_subcmd(struct ddr_info *priv,
+				int argc, char *argv[],
+				const struct test_desc array[],
+				const int array_nb)
+{
+	int i;
+	unsigned long value;
+	int result;
+	char string[50] = "";
+
+	if (argc == 1) {
+		printf("%s:%d\n", argv[0], array_nb);
+		for (i = 0; i < array_nb; i++)
+			printf("%d:%s:%s\n",
+			       i, array[i].name, array[i].usage);
+		return;
+	}
+	if (argc > 1 && !strcmp(argv[1], "help")) {
+		printf("%s:%d\n", argv[0], array_nb);
+		for (i = 0; i < array_nb; i++)
+			printf("%d:%s:%s:%s\n", i,
+			       array[i].name, array[i].usage, array[i].help);
+		return;
+	}
+
+	if ((strict_strtoul(argv[1], 0, &value) <  0) ||
+	    value >= array_nb) {
+		sprintf(string, "invalid argument %s",
+			argv[1]);
+		result = TEST_FAILED;
+		goto end;
+	}
+
+	if (argc > (array[value].max_args + 2)) {
+		sprintf(string, "invalid nb of args %d, max %d",
+			argc - 2, array[value].max_args);
+		result = TEST_FAILED;
+		goto end;
+	}
+
+	printf("execute %d:%s\n", (int)value, array[value].name);
+	clear_ctrlc();
+	result = array[value].fct(priv->ctl, priv->phy,
+				  string, argc - 2, &argv[2]);
+
+end:
+	printf("Result: %s [%s]\n", s_result[result], string);
+}
+#endif
+
 bool stm32mp1_ddr_interactive(void *priv,
 			      enum stm32mp1_ddr_interact_step step,
 			      const struct stm32mp1_ddr_config *config)
@@ -382,6 +449,14 @@
 			next_step = stm32mp1_do_step(step, argc, argv);
 			break;
 
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+		case DDR_CMD_TEST:
+			if (!stm32mp1_check_step(step, STEP_DDR_READY))
+				continue;
+			stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
+			break;
+#endif
+
 		default:
 			break;
 		}