1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <stdint.h>
4 #include <lib.h>
5 #include <console/console.h>
6 #include <device/mmio.h>
7
8 #if ENV_X86 && CONFIG(SSE2)
9 /* Assembler in lib/ is ugly. */
write_phys(uintptr_t addr,u32 value)10 static void write_phys(uintptr_t addr, u32 value)
11 {
12 asm volatile (
13 "movnti %1, (%0)"
14 : /* outputs */
15 : "r" (addr), "r" (value) /* inputs */
16 );
17 }
18
phys_memory_barrier(void)19 static void phys_memory_barrier(void)
20 {
21 // Needed for movnti
22 asm volatile ("sfence" ::: "memory");
23 }
24 #else
write_phys(uintptr_t addr,u32 value)25 static void write_phys(uintptr_t addr, u32 value)
26 {
27 write32p(addr, value);
28 }
29
phys_memory_barrier(void)30 static void phys_memory_barrier(void)
31 {
32 asm volatile ("" ::: "memory");
33 }
34 #endif
35
read_phys(uintptr_t addr)36 static u32 read_phys(uintptr_t addr)
37 {
38 return read32p(addr);
39 }
40
41 /**
42 * Rotate ones test pattern that access every bit on a 128bit wide
43 * memory bus. To test most address lines, addresses are scattered
44 * using 256B, 4kB and 64kB increments.
45 *
46 * @param idx Index to test pattern (0=<idx<0x400)
47 * @param addr Memory to access on idx
48 * @param value Value to write or read at addr
49 */
test_pattern(unsigned short int idx,unsigned long * addr,unsigned long * value)50 static inline void test_pattern(unsigned short int idx,
51 unsigned long *addr, unsigned long *value)
52 {
53 uint8_t j, k;
54
55 k = (idx >> 8) + 1;
56 j = (idx >> 4) & 0x0f;
57 *addr = idx & 0x0f;
58 *addr |= j << (4*k);
59 *value = 0x01010101 << (j & 7);
60 if (j & 8)
61 *value = ~(*value);
62 }
63
64 /**
65 * Simple write-read-verify memory test. See console debug output for
66 * any dislocated bytes.
67 *
68 * Tests 1MiB of memory starting from start.
69 *
70 * @param start System memory offset, aligned to 128bytes
71 */
ram_bitset_nodie(uintptr_t start)72 static int ram_bitset_nodie(uintptr_t start)
73 {
74 unsigned long addr, value, value2;
75 unsigned short int idx;
76 unsigned char failed, failures;
77 uint8_t verbose = 0;
78
79 printk(BIOS_DEBUG, "DRAM bitset write: 0x%08lx\n", start);
80 for (idx = 0; idx < 0x400; idx += 4) {
81 test_pattern(idx, &addr, &value);
82 write_phys(start + addr, value);
83 }
84
85 /* Make sure we don't read before we wrote */
86 phys_memory_barrier();
87
88 printk(BIOS_DEBUG, "DRAM bitset verify: 0x%08lx\n", start);
89 failures = 0;
90 for (idx = 0; idx < 0x400; idx += 4) {
91 test_pattern(idx, &addr, &value);
92 value2 = read_phys(start + addr);
93
94 failed = (value2 != value);
95 failures |= failed;
96 if (failed && !verbose) {
97 printk(BIOS_ERR, "0x%08lx wr: 0x%08lx rd: 0x%08lx FAIL\n",
98 start + addr, value, value2);
99 }
100 if (verbose) {
101 if ((addr & 0x0f) == 0)
102 printk(BIOS_DEBUG, "%08lx wr: %08lx rd:",
103 start + addr, value);
104 if (failed)
105 printk(BIOS_DEBUG, " %08lx!", value2);
106 else
107 printk(BIOS_DEBUG, " %08lx ", value2);
108 if ((addr & 0x0f) == 0xc)
109 printk(BIOS_DEBUG, "\n");
110 }
111 }
112 if (failures) {
113 post_code(POSTCODE_RAM_FAILURE);
114 printk(BIOS_DEBUG, "\nDRAM did _NOT_ verify!\n");
115 return 1;
116 }
117 printk(BIOS_DEBUG, "\nDRAM range verified.\n");
118 return 0;
119 }
120
121
ram_check(uintptr_t start)122 void ram_check(uintptr_t start)
123 {
124 /*
125 * This is much more of a "Is my DRAM properly configured?"
126 * test than a "Is my DRAM faulty?" test. Not all bits
127 * are tested. -Tyson
128 */
129 printk(BIOS_DEBUG, "Testing DRAM at: %08lx\n", start);
130 if (ram_bitset_nodie(start))
131 die("DRAM ERROR");
132 printk(BIOS_DEBUG, "Done.\n");
133 }
134
135
ram_check_nodie(uintptr_t start)136 int ram_check_nodie(uintptr_t start)
137 {
138 int ret;
139 /*
140 * This is much more of a "Is my DRAM properly configured?"
141 * test than a "Is my DRAM faulty?" test. Not all bits
142 * are tested. -Tyson
143 */
144 printk(BIOS_DEBUG, "Testing DRAM at : %08lx\n", start);
145
146 ret = ram_bitset_nodie(start);
147 printk(BIOS_DEBUG, "Done.\n");
148 return ret;
149 }
150
ram_check_noprint_nodie(uintptr_t start)151 int ram_check_noprint_nodie(uintptr_t start)
152 {
153 unsigned long addr, value, value2;
154 unsigned short int idx;
155 unsigned char failed, failures;
156
157 for (idx = 0; idx < 0x400; idx += 4) {
158 test_pattern(idx, &addr, &value);
159 write_phys(start + addr, value);
160 }
161
162 /* Make sure we don't read before we wrote */
163 phys_memory_barrier();
164
165 failures = 0;
166 for (idx = 0; idx < 0x400; idx += 4) {
167 test_pattern(idx, &addr, &value);
168 value2 = read_phys(start + addr);
169
170 failed = (value2 != value);
171 failures |= failed;
172 }
173 return failures;
174 }
175
176 /* Assumption is 32-bit addressable UC memory at dst. This also executes
177 * on S3 resume path so target memory must be restored.
178 */
quick_ram_check_or_die(uintptr_t dst)179 void quick_ram_check_or_die(uintptr_t dst)
180 {
181 int fail = 0;
182 u32 backup;
183 backup = read_phys(dst);
184 write_phys(dst, 0x55555555);
185 phys_memory_barrier();
186 if (read_phys(dst) != 0x55555555)
187 fail = 1;
188 write_phys(dst, 0xaaaaaaaa);
189 phys_memory_barrier();
190 if (read_phys(dst) != 0xaaaaaaaa)
191 fail = 1;
192 write_phys(dst, 0x00000000);
193 phys_memory_barrier();
194 if (read_phys(dst) != 0x00000000)
195 fail = 1;
196 write_phys(dst, 0xffffffff);
197 phys_memory_barrier();
198 if (read_phys(dst) != 0xffffffff)
199 fail = 1;
200
201 write_phys(dst, backup);
202 if (fail) {
203 post_code(POSTCODE_RAM_FAILURE);
204 die("RAM INIT FAILURE!\n");
205 }
206 phys_memory_barrier();
207 }
208