1 /*
2  * Copyright (C) 2022-2023, 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 uintptr_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 STM32MP_DDR_BASE;
29 	}
30 
31 	mmio_write_32(STM32MP_DDR_BASE, saved_value);
32 
33 	return 0UL;
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 uintptr_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 STM32MP_DDR_BASE;
53 		}
54 	}
55 
56 	return 0UL;
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(size_t size)68 uintptr_t stm32mp_ddr_test_addr_bus(size_t size)
69 {
70 	size_t addressmask = size - 1U;
71 	size_t offset;
72 	size_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 + offset, DDR_PATTERN);
78 	}
79 
80 	/* Check for address bits stuck high. */
81 	mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
82 
83 	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
84 	     offset <<= 1U) {
85 		if (mmio_read_32(STM32MP_DDR_BASE + offset) != DDR_PATTERN) {
86 			return STM32MP_DDR_BASE + offset;
87 		}
88 	}
89 
90 	mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
91 
92 	/* Check for address bits stuck low or shorted. */
93 	for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
94 	     testoffset <<= 1U) {
95 		mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
96 
97 		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
98 			return STM32MP_DDR_BASE;
99 		}
100 
101 		for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
102 		     offset <<= 1) {
103 			if ((mmio_read_32(STM32MP_DDR_BASE + offset) != DDR_PATTERN) &&
104 			    (offset != testoffset)) {
105 				return STM32MP_DDR_BASE + offset;
106 			}
107 		}
108 
109 		mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
110 	}
111 
112 	return 0UL;
113 }
114 
115 /*******************************************************************************
116  * This function checks the DDR size. It has to be run with Data Cache off.
117  * This test is run before data have been put in DDR, and is only done for
118  * cold boot. The DDR data can then be overwritten, and it is not useful to
119  * restore its content.
120  * Returns DDR computed size.
121  ******************************************************************************/
stm32mp_ddr_check_size(void)122 size_t stm32mp_ddr_check_size(void)
123 {
124 	size_t offset = sizeof(uint32_t);
125 
126 	mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
127 
128 	while (offset < STM32MP_DDR_MAX_SIZE) {
129 		mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
130 		dsb();
131 
132 		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
133 			break;
134 		}
135 
136 		offset <<= 1U;
137 	}
138 
139 	return offset;
140 }
141