1 /*
2 * Copyright (C) 2022-2024, 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 mmio_write_pattern(STM32MP_DDR_BASE, saved_value);
55
56 return 0UL;
57 }
58
59 /*******************************************************************************
60 * This function tests the DDR data bus wiring.
61 * This is inspired from the Data Bus Test algorithm written by Michael Barr
62 * in "Programming Embedded Systems in C and C++" book.
63 * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
64 * File: memtest.c - This source code belongs to Public Domain.
65 * Returns 0 if success, and address value else.
66 ******************************************************************************/
stm32mp_ddr_test_data_bus(void)67 uintptr_t stm32mp_ddr_test_data_bus(void)
68 {
69 u_register_t pattern;
70
71 for (pattern = 1U; pattern != 0U; pattern <<= 1U) {
72 mmio_write_pattern(STM32MP_DDR_BASE, pattern);
73
74 if (mmio_read_pattern(STM32MP_DDR_BASE) != pattern) {
75 return STM32MP_DDR_BASE;
76 }
77 }
78
79 return 0UL;
80 }
81
82 /*******************************************************************************
83 * This function tests the DDR address bus wiring.
84 * This is inspired from the Data Bus Test algorithm written by Michael Barr
85 * in "Programming Embedded Systems in C and C++" book.
86 * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
87 * File: memtest.c - This source code belongs to Public Domain.
88 * size: size in bytes of the DDR memory device.
89 * Returns 0 if success, and address value else.
90 ******************************************************************************/
stm32mp_ddr_test_addr_bus(size_t size)91 uintptr_t stm32mp_ddr_test_addr_bus(size_t size)
92 {
93 size_t addressmask = size - 1U;
94 size_t offset;
95 size_t testoffset = 0U;
96
97 /* Write the default pattern at each of the power-of-two offsets. */
98 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
99 offset <<= 1U) {
100 mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_PATTERN);
101 }
102
103 /* Check for address bits stuck high. */
104 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
105
106 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
107 offset <<= 1U) {
108 if (mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) {
109 return STM32MP_DDR_BASE + offset;
110 }
111 }
112
113 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
114
115 /* Check for address bits stuck low or shorted. */
116 for (testoffset = sizeof(u_register_t); (testoffset & addressmask) != 0U;
117 testoffset <<= 1U) {
118 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
119
120 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
121 return STM32MP_DDR_BASE;
122 }
123
124 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
125 offset <<= 1U) {
126 if ((mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) &&
127 (offset != testoffset)) {
128 return STM32MP_DDR_BASE + offset;
129 }
130 }
131
132 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
133 }
134
135 return 0UL;
136 }
137
138 /*******************************************************************************
139 * This function checks the DDR size. It has to be run with Data Cache off.
140 * This test is run before data have been put in DDR, and is only done for
141 * cold boot. The DDR data can then be overwritten, and it is not useful to
142 * restore its content.
143 * Returns DDR computed size.
144 ******************************************************************************/
stm32mp_ddr_check_size(void)145 size_t stm32mp_ddr_check_size(void)
146 {
147 size_t offset = sizeof(u_register_t);
148
149 mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN);
150
151 while (offset < STM32MP_DDR_MAX_SIZE) {
152 mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
153 dsb();
154
155 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
156 break;
157 }
158
159 offset <<= 1U;
160 }
161
162 return offset;
163 }
164