1 /*
2  * Copyright (C) 2022, 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 #define DDR_PATTERN	0xAAAAAAAAU
14 #define DDR_ANTIPATTERN	0x55555555U
15 
16 /*******************************************************************************
17  * This function tests a simple read/write access to the DDR.
18  * Note that the previous content is restored after test.
19  * Returns 0 if success, and address value else.
20  ******************************************************************************/
stm32mp_ddr_test_rw_access(void)21 uint32_t stm32mp_ddr_test_rw_access(void)
22 {
23 	uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE);
24 
25 	mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
26 
27 	if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
28 		return (uint32_t)STM32MP_DDR_BASE;
29 	}
30 
31 	mmio_write_32(STM32MP_DDR_BASE, saved_value);
32 
33 	return 0U;
34 }
35 
36 /*******************************************************************************
37  * This function tests the DDR data bus wiring.
38  * This is inspired from the Data Bus Test algorithm written by Michael Barr
39  * in "Programming Embedded Systems in C and C++" book.
40  * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
41  * File: memtest.c - This source code belongs to Public Domain.
42  * Returns 0 if success, and address value else.
43  ******************************************************************************/
stm32mp_ddr_test_data_bus(void)44 uint32_t stm32mp_ddr_test_data_bus(void)
45 {
46 	uint32_t pattern;
47 
48 	for (pattern = 1U; pattern != 0U; pattern <<= 1U) {
49 		mmio_write_32(STM32MP_DDR_BASE, pattern);
50 
51 		if (mmio_read_32(STM32MP_DDR_BASE) != pattern) {
52 			return (uint32_t)STM32MP_DDR_BASE;
53 		}
54 	}
55 
56 	return 0;
57 }
58 
59 /*******************************************************************************
60  * This function tests the DDR address 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  * size: size in bytes of the DDR memory device.
66  * Returns 0 if success, and address value else.
67  ******************************************************************************/
stm32mp_ddr_test_addr_bus(uint64_t size)68 uint32_t stm32mp_ddr_test_addr_bus(uint64_t size)
69 {
70 	uint64_t addressmask = size - 1U;
71 	uint64_t offset;
72 	uint64_t testoffset = 0U;
73 
74 	/* Write the default pattern at each of the power-of-two offsets. */
75 	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
76 	     offset <<= 1U) {
77 		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset,
78 			      DDR_PATTERN);
79 	}
80 
81 	/* Check for address bits stuck high. */
82 	mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
83 		      DDR_ANTIPATTERN);
84 
85 	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
86 	     offset <<= 1U) {
87 		if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) !=
88 		    DDR_PATTERN) {
89 			return (uint32_t)(STM32MP_DDR_BASE + offset);
90 		}
91 	}
92 
93 	mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN);
94 
95 	/* Check for address bits stuck low or shorted. */
96 	for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
97 	     testoffset <<= 1U) {
98 		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
99 			      DDR_ANTIPATTERN);
100 
101 		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
102 			return STM32MP_DDR_BASE;
103 		}
104 
105 		for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
106 		     offset <<= 1) {
107 			if ((mmio_read_32(STM32MP_DDR_BASE +
108 					  (uint32_t)offset) != DDR_PATTERN) &&
109 			    (offset != testoffset)) {
110 				return (uint32_t)(STM32MP_DDR_BASE + offset);
111 			}
112 		}
113 
114 		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
115 			      DDR_PATTERN);
116 	}
117 
118 	return 0U;
119 }
120 
121 /*******************************************************************************
122  * This function checks the DDR size. It has to be run with Data Cache off.
123  * This test is run before data have been put in DDR, and is only done for
124  * cold boot. The DDR data can then be overwritten, and it is not useful to
125  * restore its content.
126  * Returns DDR computed size.
127  ******************************************************************************/
stm32mp_ddr_check_size(void)128 uint32_t stm32mp_ddr_check_size(void)
129 {
130 	uint32_t offset = sizeof(uint32_t);
131 
132 	mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
133 
134 	while (offset < STM32MP_DDR_MAX_SIZE) {
135 		mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
136 		dsb();
137 
138 		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
139 			break;
140 		}
141 
142 		offset <<= 1U;
143 	}
144 
145 	INFO("Memory size = 0x%x (%u MB)\n", offset, offset / (1024U * 1024U));
146 
147 	return offset;
148 }
149