blob: 9adcafdd301a62285033c97cb74e84c160158e27 [file] [log] [blame]
Patrick Georgid0835952010-10-05 09:07:10 +00001#include <stdint.h>
Myles Watson34261952010-03-19 02:33:40 +00002#include <lib.h> /* Prototypes */
Patrick Georgid0835952010-10-05 09:07:10 +00003#include <console/console.h>
Myles Watson34261952010-03-19 02:33:40 +00004
Stefan Reinauere0d607a2010-03-28 21:31:30 +00005static void write_phys(unsigned long addr, u32 value)
Eric Biederman8ca8d762003-04-22 19:02:15 +00006{
Stefan Reinauera7acc512010-02-25 13:40:49 +00007 // Assembler in lib/ is very ugly. But we properly guarded
8 // it so let's obey this one for now
Martin Roth1bf55b42017-06-24 14:16:38 -06009#if IS_ENABLED(CONFIG_SSE2)
Eric Biederman8d9c1232003-06-17 08:42:17 +000010 asm volatile(
11 "movnti %1, (%0)"
12 : /* outputs */
13 : "r" (addr), "r" (value) /* inputs */
Stefan Reinauere0d607a2010-03-28 21:31:30 +000014#ifndef __GNUC__ /* GCC does not like empty clobbers? */
Eric Biederman8d9c1232003-06-17 08:42:17 +000015 : /* clobbers */
Stefan Reinauer76712932004-05-27 11:13:24 +000016#endif
Eric Biederman8d9c1232003-06-17 08:42:17 +000017 );
18#else
Eric Biederman52685572003-05-19 19:16:21 +000019 volatile unsigned long *ptr;
Eric Biederman8ca8d762003-04-22 19:02:15 +000020 ptr = (void *)addr;
21 *ptr = value;
Eric Biederman8d9c1232003-06-17 08:42:17 +000022#endif
Eric Biederman8ca8d762003-04-22 19:02:15 +000023}
24
Stefan Reinauere0d607a2010-03-28 21:31:30 +000025static u32 read_phys(unsigned long addr)
Eric Biederman8ca8d762003-04-22 19:02:15 +000026{
Eric Biederman52685572003-05-19 19:16:21 +000027 volatile unsigned long *ptr;
Eric Biederman8ca8d762003-04-22 19:02:15 +000028 ptr = (void *)addr;
29 return *ptr;
30}
31
Stefan Reinauere0d607a2010-03-28 21:31:30 +000032static void phys_memory_barrier(void)
33{
Martin Roth1bf55b42017-06-24 14:16:38 -060034#if IS_ENABLED(CONFIG_SSE2)
Stefan Reinauere0d607a2010-03-28 21:31:30 +000035 // Needed for movnti
36 asm volatile (
37 "sfence"
38 ::
39#ifdef __GNUC__ /* ROMCC does not like memory clobbers */
40 : "memory"
41#endif
42 );
43#else
44#ifdef __GNUC__ /* ROMCC does not like empty asm statements */
45 asm volatile ("" ::: "memory");
46#endif
47#endif
48}
49
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010050/**
51 * Rotate ones test pattern that access every bit on a 128bit wide
52 * memory bus. To test most address lines, addresses are scattered
53 * using 256B, 4kB and 64kB increments.
54 *
Martin Roth5f066b22015-01-04 16:47:39 -070055 * @param idx Index to test pattern (0=<idx<0x400)
56 * @param addr Memory to access on idx
57 * @param value Value to write or read at addr
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010058 */
59static inline void test_pattern(unsigned short int idx,
60 unsigned long *addr, unsigned long *value)
Eric Biederman8ca8d762003-04-22 19:02:15 +000061{
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010062 uint8_t j, k;
63
64 k = (idx >> 8) + 1;
65 j = (idx >> 4) & 0x0f;
66 *addr = idx & 0x0f;
67 *addr |= j << (4*k);
68 *value = 0x01010101 << (j & 7);
69 if (j & 8)
70 *value = ~(*value);
Eric Biederman8ca8d762003-04-22 19:02:15 +000071}
72
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010073/**
74 * Simple write-read-verify memory test. See console debug output for
75 * any dislocated bytes.
76 *
Patrick Rudolph3dbd2842017-10-27 11:49:29 +020077 * Tests 1MiB of memory starting from start.
78 *
Martin Roth5f066b22015-01-04 16:47:39 -070079 * @param start System memory offset, aligned to 128bytes
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010080 */
81static int ram_bitset_nodie(unsigned long start)
Eric Biederman8ca8d762003-04-22 19:02:15 +000082{
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010083 unsigned long addr, value, value2;
84 unsigned short int idx;
85 unsigned char failed, failures;
86 uint8_t verbose = 0;
87
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010088 printk(BIOS_DEBUG, "DRAM bitset write: 0x%08lx\n", start);
Lee Leahy35af5c42017-03-09 17:35:28 -080089 for (idx = 0; idx < 0x400; idx += 4) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010090 test_pattern(idx, &addr, &value);
91 write_phys(start + addr, value);
92 }
93
94 /* Make sure we don't read before we wrote */
95 phys_memory_barrier();
96
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010097 printk(BIOS_DEBUG, "DRAM bitset verify: 0x%08lx\n", start);
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010098 failures = 0;
Lee Leahy35af5c42017-03-09 17:35:28 -080099 for (idx = 0; idx < 0x400; idx += 4) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100100 test_pattern(idx, &addr, &value);
101 value2 = read_phys(start + addr);
102
103 failed = (value2 != value);
104 failures |= failed;
105 if (failed && !verbose) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100106 printk(BIOS_ERR, "0x%08lx wr: 0x%08lx rd: 0x%08lx FAIL\n",
107 start + addr, value, value2);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000108 }
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100109 if (verbose) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100110 if ((addr & 0x0f) == 0)
111 printk(BIOS_DEBUG, "%08lx wr: %08lx rd:",
112 start + addr, value);
113 if (failed)
114 printk(BIOS_DEBUG, " %08lx!", value2);
115 else
116 printk(BIOS_DEBUG, " %08lx ", value2);
117 if ((addr & 0x0f) == 0xc)
118 printk(BIOS_DEBUG, "\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000119 }
120 }
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100121 if (failures) {
122 post_code(0xea);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000123 printk(BIOS_DEBUG, "\nDRAM did _NOT_ verify!\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100124 return 1;
Richard Smithffb7d8a2006-04-01 04:10:44 +0000125 }
Lee Leahy3e1cab42017-03-10 17:48:31 -0800126 printk(BIOS_DEBUG, "\nDRAM range verified.\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100127 return 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000128}
129
130
Eric Biederman8d9c1232003-06-17 08:42:17 +0000131void ram_check(unsigned long start, unsigned long stop)
Eric Biederman8ca8d762003-04-22 19:02:15 +0000132{
Eric Biederman8ca8d762003-04-22 19:02:15 +0000133 /*
134 * This is much more of a "Is my DRAM properly configured?"
135 * test than a "Is my DRAM faulty?" test. Not all bits
136 * are tested. -Tyson
137 */
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100138 printk(BIOS_DEBUG, "Testing DRAM at: %08lx\n", start);
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100139 if (ram_bitset_nodie(start))
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100140 die("DRAM ERROR");
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000141 printk(BIOS_DEBUG, "Done.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000142}
143
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100144
145int ram_check_nodie(unsigned long start, unsigned long stop)
146{
147 int ret;
148 /*
149 * This is much more of a "Is my DRAM properly configured?"
150 * test than a "Is my DRAM faulty?" test. Not all bits
151 * are tested. -Tyson
152 */
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100153 printk(BIOS_DEBUG, "Testing DRAM at : %08lx\n", start);
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100154
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100155 ret = ram_bitset_nodie(start);
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100156 printk(BIOS_DEBUG, "Done.\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100157 return ret;
158}
159
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500160int ram_check_noprint_nodie(unsigned long start, unsigned long stop)
161{
162 unsigned long addr, value, value2;
163 unsigned short int idx;
164 unsigned char failed, failures;
165
Lee Leahy35af5c42017-03-09 17:35:28 -0800166 for (idx = 0; idx < 0x400; idx += 4) {
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500167 test_pattern(idx, &addr, &value);
168 write_phys(start + addr, value);
169 }
170
171 /* Make sure we don't read before we wrote */
172 phys_memory_barrier();
173
174 failures = 0;
Lee Leahy35af5c42017-03-09 17:35:28 -0800175 for (idx = 0; idx < 0x400; idx += 4) {
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500176 test_pattern(idx, &addr, &value);
177 value2 = read_phys(start + addr);
178
179 failed = (value2 != value);
180 failures |= failed;
181 }
182 return failures;
183}
184
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300185static void __quick_ram_check(uintptr_t dst)
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000186{
187 int fail = 0;
188 u32 backup;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300189 backup = read_phys(dst);
190 write_phys(dst, 0x55555555);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000191 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300192 if (read_phys(dst) != 0x55555555)
Lee Leahy35af5c42017-03-09 17:35:28 -0800193 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300194 write_phys(dst, 0xaaaaaaaa);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000195 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300196 if (read_phys(dst) != 0xaaaaaaaa)
Lee Leahy35af5c42017-03-09 17:35:28 -0800197 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300198 write_phys(dst, 0x00000000);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000199 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300200 if (read_phys(dst) != 0x00000000)
Lee Leahy35af5c42017-03-09 17:35:28 -0800201 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300202 write_phys(dst, 0xffffffff);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000203 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300204 if (read_phys(dst) != 0xffffffff)
Lee Leahy35af5c42017-03-09 17:35:28 -0800205 fail = 1;
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000206
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300207 write_phys(dst, backup);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000208 if (fail) {
209 post_code(0xea);
210 die("RAM INIT FAILURE!\n");
211 }
212 phys_memory_barrier();
213}
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300214
215void quick_ram_check(void)
216{
217 __quick_ram_check(0x100000);
218}