1 /*
2 * Copyright (C) 2022-2026, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <common/debug.h>
8 #include <drivers/st/stm32mp_ddr_test.h>
9 #include <lib/mmio.h>
10
11 #include <platform_def.h>
12
13 #ifdef __aarch64__
14 #define DDR_PATTERN 0xAAAAAAAAAAAAAAAAUL
15 #define DDR_ANTIPATTERN 0x5555555555555555UL
16 #else /* !__aarch64__ */
17 #define DDR_PATTERN 0xAAAAAAAAU
18 #define DDR_ANTIPATTERN 0x55555555U
19 #endif /* __aarch64__ */
20
mmio_write_pattern(uintptr_t addr,u_register_t value)21 static void mmio_write_pattern(uintptr_t addr, u_register_t value)
22 {
23 #ifdef __aarch64__
24 mmio_write_64(addr, (uint64_t)value);
25 #else /* !__aarch64__ */
26 mmio_write_32(addr, (uint32_t)value);
27 #endif /* __aarch64__ */
28 }
29
mmio_read_pattern(uintptr_t addr)30 static u_register_t mmio_read_pattern(uintptr_t addr)
31 {
32 #ifdef __aarch64__
33 return (u_register_t)mmio_read_64(addr);
34 #else /* !__aarch64__ */
35 return (u_register_t)mmio_read_32(addr);
36 #endif /* __aarch64__ */
37 }
38
39 /*******************************************************************************
40 * This function tests a simple read/write access to the DDR.
41 * Note that the previous content is restored after test.
42 * Returns 0 if success, and address value else.
43 ******************************************************************************/
stm32mp_ddr_test_rw_access(void)44 uintptr_t stm32mp_ddr_test_rw_access(void)
45 {
46 u_register_t saved_value = mmio_read_pattern(STM32MP_DDR_BASE);
47
48 mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN);
49
50 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
51 return STM32MP_DDR_BASE;
52 }
53
54 if (saved_value != DDR_PATTERN) {
55 mmio_write_pattern(STM32MP_DDR_BASE, saved_value);
56 }
57
58 return 0UL;
59 }
60
61 /*******************************************************************************
62 * This function tests the DDR data bus wiring.
63 * This is inspired from the Data Bus Test algorithm written by Michael Barr
64 * in "Programming Embedded Systems in C and C++" book.
65 * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
66 * File: memtest.c - This source code belongs to Public Domain.
67 * Returns 0 if success, and address value else.
68 ******************************************************************************/
stm32mp_ddr_test_data_bus(void)69 uintptr_t stm32mp_ddr_test_data_bus(void)
70 {
71 u_register_t pattern;
72
73 for (pattern = 1U; pattern != 0U; pattern <<= 1U) {
74 mmio_write_pattern(STM32MP_DDR_BASE, pattern);
75
76 if (mmio_read_pattern(STM32MP_DDR_BASE) != pattern) {
77 return STM32MP_DDR_BASE;
78 }
79 }
80
81 return 0UL;
82 }
83
84 /*******************************************************************************
85 * This function tests the DDR address bus wiring.
86 * This is inspired from the Data Bus Test algorithm written by Michael Barr
87 * in "Programming Embedded Systems in C and C++" book.
88 * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
89 * File: memtest.c - This source code belongs to Public Domain.
90 * size: size in bytes of the DDR memory device.
91 * Returns 0 if success, and address value else.
92 ******************************************************************************/
stm32mp_ddr_test_addr_bus(size_t size)93 uintptr_t stm32mp_ddr_test_addr_bus(size_t size)
94 {
95 size_t addressmask = size - 1U;
96 size_t offset;
97 size_t testoffset = 0U;
98
99 /* Write the default pattern at each of the power-of-two offsets. */
100 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
101 offset <<= 1U) {
102 mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_PATTERN);
103 }
104
105 /* Check for address bits stuck high. */
106 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
107
108 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
109 offset <<= 1U) {
110 if (mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) {
111 return STM32MP_DDR_BASE + offset;
112 }
113 }
114
115 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
116
117 /* Check for address bits stuck low or shorted. */
118 for (testoffset = sizeof(u_register_t); (testoffset & addressmask) != 0U;
119 testoffset <<= 1U) {
120 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
121
122 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
123 return STM32MP_DDR_BASE;
124 }
125
126 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
127 offset <<= 1U) {
128 if ((mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) &&
129 (offset != testoffset)) {
130 return STM32MP_DDR_BASE + offset;
131 }
132 }
133
134 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
135 }
136
137 return 0UL;
138 }
139
140 /*******************************************************************************
141 * This function checks the DDR size. It has to be run with Data Cache off.
142 * This test is run before data have been put in DDR, and is only done for
143 * cold boot. The DDR data can then be overwritten, and it is not useful to
144 * restore its content.
145 * Returns DDR computed size.
146 ******************************************************************************/
stm32mp_ddr_check_size(void)147 size_t stm32mp_ddr_check_size(void)
148 {
149 size_t offset = sizeof(u_register_t);
150
151 mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN);
152
153 while (offset < STM32MP_DDR_MAX_SIZE) {
154 mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
155 dsb();
156
157 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
158 break;
159 }
160
161 offset <<= 1U;
162 }
163
164 return offset;
165 }
166