xref: /rk3399_ARM-atf/drivers/st/ddr/stm32mp_ddr_test.c (revision 681296444e508e722565c6713effd2cf346a4dcf)
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