siemens: add ddr full memory test
authorEnrico Leto <enrico.leto@siemens.com>
Sat, 23 Nov 2024 16:53:02 +0000 (17:53 +0100)
committerFabio Estevam <festevam@gmail.com>
Tue, 26 Nov 2024 02:07:37 +0000 (23:07 -0300)
Add siemens specific memory test. Enable it through Kconfig option
SPL_CMT. The test is required from our HW team. It runs over
temperature during many days:
* must run indefinitively through the *whole* DDR area,
  so we cannot use linux memtest for example.
* must write/read/check all values

Signed-off-by: Enrico Leto <enrico.leto@siemens.com>
Signed-off-by: Heiko Schocher <hs@denx.de>
board/siemens/capricorn/Kconfig
board/siemens/capricorn/Makefile
board/siemens/capricorn/spl.c
board/siemens/capricorn/spl_memory_test.c [new file with mode: 0644]
board/siemens/capricorn/spl_memory_test.h [new file with mode: 0644]

index 371eca3..03a433d 100644 (file)
@@ -14,3 +14,10 @@ config IMX_CONFIG
        default "board/siemens/capricorn/imximage.cfg"
 
 endif
+
+
+config SPL_CMT
+       bool "Enable Siemens SPL RAM test"
+       depends on SPL
+       help
+         Enable SIemens SPL RAM test.
index e8a24c4..b8350d9 100644 (file)
@@ -8,6 +8,7 @@ obj-y += ../common/eeprom.o
 
 ifdef CONFIG_XPL_BUILD
 obj-y += spl.o
+obj-$(CONFIG_SPL_CMT) += spl_memory_test.o
 else
 obj-y += ../common/factoryset.o
 endif
index 7ee2895..5865cde 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/arch/iomux.h>
 #include <asm/gpio.h>
 #include <asm/arch/sys_proto.h>
+#include "spl_memory_test.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -58,6 +59,10 @@ void spl_board_init(void)
        preloader_console_init();
 
        puts("Normal Boot\n");
+
+#if IS_ENABLED(CONFIG_SPL_CMT)
+       spl_siemens_memory_full_test();
+#endif
 }
 
 void spl_board_prepare_for_boot(void)
diff --git a/board/siemens/capricorn/spl_memory_test.c b/board/siemens/capricorn/spl_memory_test.c
new file mode 100644 (file)
index 0000000..84c97e7
--- /dev/null
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright Siemens AG 2020
+ *
+ * SPL Full Memory Test
+ * - memory test through the full DDR area
+ * - refresh over temperature torture (write all, read all)
+ *
+ * Remark:
+ * This test has ran properly with the definition of the RAM sizes in board
+ * headers. Since these headers are removed it's necessary to set the correct
+ * values to PHYS_SDRAM_1_SIZE & PHYS_SDRAM_2_SIZE before to recompile.
+ *
+ * An alternative is to refactor the code to get the size info from system
+ * controller
+ */
+
+#include <init.h>
+#include <log.h>
+
+/* ----- Defines ----- */
+#define CHECK_LOWER_UPPER
+
+#define LEVEL2_PRINT    0x0FFFFFFF
+
+/* use 0x7FFF0000 for shorter loop test */
+#define BASE_OFFSET    0x00000000
+
+/* ----- Types ----- */
+struct ct_t {
+       unsigned long *start;
+       unsigned long *end;
+};
+
+/* ----- Variables ----- */
+static struct ct_t ct;
+static unsigned long error_counter;
+
+static void print_parameters(void)
+{
+       printf("\nstart addr: %p\n", ct.start);
+       printf("end addr  : %p\n", ct.end);
+}
+
+static void run_test(void)
+{
+       /* moved full test in one void */
+       unsigned long *address; /* 512 */
+       unsigned long ebyte1;
+       unsigned long ebyte2;
+       unsigned int i;
+       unsigned long rpattern;
+
+       for (i = 0; i <= 255; i++) {
+               memset(&ebyte1, i, sizeof(ebyte1));
+               ebyte2 = ~ebyte1;
+               printf("LWord: %016lx  #LWord: %016lx\n", ebyte1, ebyte2);
+
+               /* write  all bytes -> duration ~ 150 s */
+               for (address = ct.start; address <= ct.end; address++) {
+#ifdef LEVEL2_PRINT
+                       if (((unsigned long)address & LEVEL2_PRINT) == 0)
+                               printf("write to %p - %p\n", address,
+                                      (void *)((unsigned long)address +
+                                      LEVEL2_PRINT));
+#endif
+                       *address = ebyte1;
+                       address++;
+                       *address = ebyte2;
+               }
+
+               /* check all bytes */
+               for (address = ct.start; address <= ct.end; address++) {
+#ifdef LEVEL2_PRINT
+                       if (((unsigned long)address & LEVEL2_PRINT) == 0)
+                               printf("check from %p - %p\n", address,
+                                      (void *)((unsigned long)address +
+                                      LEVEL2_PRINT));
+#endif
+
+                       rpattern = *address;
+                       if (rpattern != ebyte1) {
+                               error_counter++;
+                               printf("Error! Read: %016lX Wrote: %016lX Address: %p\n",
+                                      rpattern, ebyte1, address);
+                       }
+
+                       address++;
+                       rpattern = *address;
+                       if (rpattern != ebyte2) {
+                               error_counter++;
+                               printf("Error! Read: %016lX Wrote: %016lX Address: %p\n",
+                                      rpattern, ebyte2, address);
+                       }
+               }
+       }
+}
+
+#ifdef CHECK_LOWER_UPPER
+void test_lower_upper(void)
+{
+       /*
+        * write different values at the same address of both memory areas
+        * and check them
+        */
+#define TEST_ADDRESS    0x12345670UL
+#define LOWER_ADDRESS  (PHYS_SDRAM_1 + TEST_ADDRESS)
+#define UPPER_ADDRESS  (PHYS_SDRAM_2 + TEST_ADDRESS)
+#define LOWER_VALUE    0x0011223344556677
+#define UPPER_VALUE    0x89ab89abffeeddcc
+
+       *(unsigned long *)LOWER_ADDRESS = LOWER_VALUE;
+       *(unsigned long *)UPPER_ADDRESS = UPPER_VALUE;
+
+       puts("\nlower-upper memory area test\n");
+       printf("write %016lx to   lower address %010lx\n", LOWER_VALUE,
+              LOWER_ADDRESS);
+       printf("write %016lx to   upper address %010lx\n", UPPER_VALUE,
+              UPPER_ADDRESS);
+       printf("read  %016lx from lower address %010lx\n",
+              *(unsigned long *)LOWER_ADDRESS, LOWER_ADDRESS);
+       printf("read  %016lx from upper address %010lx\n",
+              *(unsigned long *)UPPER_ADDRESS, UPPER_ADDRESS);
+}
+#endif
+
+void spl_siemens_memory_full_test(void)
+{
+       unsigned long loopc = 0;
+
+       puts("\nSPL: memory cell test\n");
+
+#ifdef CHECK_LOWER_UPPER
+       if (PHYS_SDRAM_2_SIZE != 0)
+               test_lower_upper();
+#endif
+
+       while (true) {
+               /* imx8x has 2 memory areas up to 2 GB */
+
+               /* 1st memory area @ 0x80000000 */
+               ct.start = (unsigned long *)(PHYS_SDRAM_1 + BASE_OFFSET);
+               ct.end = (unsigned long *)(PHYS_SDRAM_1 + PHYS_SDRAM_1_SIZE - 1);
+               print_parameters();
+               run_test();
+
+               /* 2nd memory area @ 0x880000000 */
+               if (PHYS_SDRAM_2_SIZE != 0) {
+                       ct.start = (unsigned long *)(PHYS_SDRAM_2 + BASE_OFFSET);
+                       ct.end = (unsigned long *)(PHYS_SDRAM_2 + PHYS_SDRAM_2_SIZE - 1);
+                       print_parameters();
+                       run_test();
+               }
+
+               loopc++;
+               printf("loop: %ld, errors: %ld\n\n", loopc, error_counter);
+       };
+}
diff --git a/board/siemens/capricorn/spl_memory_test.h b/board/siemens/capricorn/spl_memory_test.h
new file mode 100644 (file)
index 0000000..28df284
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright Siemens AG 2020
+ *
+ */
+
+void spl_siemens_memory_full_test(void);