• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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