blob: 45178a7e235a3b3a655adee9d70dd680fc0854d0 [file] [log] [blame]
Patrick Georgid0835952010-10-05 09:07:10 +00001#include <stdint.h>
Elyes HAOUAS3b3d0852021-02-01 10:09:40 +01002#include <lib.h>
Patrick Georgid0835952010-10-05 09:07:10 +00003#include <console/console.h>
Kyösti Mälkki321bce42019-03-20 19:53:44 +02004#include <device/mmio.h>
Myles Watson34261952010-03-19 02:33:40 +00005
Kyösti Mälkki7336f972020-06-08 06:05:03 +03006#if ENV_X86 && CONFIG(SSE2)
Kyösti Mälkki321bce42019-03-20 19:53:44 +02007/* Assembler in lib/ is ugly. */
8static void write_phys(uintptr_t addr, u32 value)
Eric Biederman8ca8d762003-04-22 19:02:15 +00009{
Kyösti Mälkki321bce42019-03-20 19:53:44 +020010 asm volatile (
Eric Biederman8d9c1232003-06-17 08:42:17 +000011 "movnti %1, (%0)"
12 : /* outputs */
13 : "r" (addr), "r" (value) /* inputs */
Kyösti Mälkki321bce42019-03-20 19:53:44 +020014 );
Eric Biederman8ca8d762003-04-22 19:02:15 +000015}
16
Stefan Reinauere0d607a2010-03-28 21:31:30 +000017static void phys_memory_barrier(void)
18{
Stefan Reinauere0d607a2010-03-28 21:31:30 +000019 // Needed for movnti
Kyösti Mälkki321bce42019-03-20 19:53:44 +020020 asm volatile ("sfence" ::: "memory");
21}
Stefan Reinauere0d607a2010-03-28 21:31:30 +000022#else
Kyösti Mälkki321bce42019-03-20 19:53:44 +020023static void write_phys(uintptr_t addr, u32 value)
24{
25 write32((void *)addr, value);
26}
27
28static void phys_memory_barrier(void)
29{
Stefan Reinauere0d607a2010-03-28 21:31:30 +000030 asm volatile ("" ::: "memory");
Kyösti Mälkki321bce42019-03-20 19:53:44 +020031}
Stefan Reinauere0d607a2010-03-28 21:31:30 +000032#endif
Kyösti Mälkki321bce42019-03-20 19:53:44 +020033
34static u32 read_phys(uintptr_t addr)
35{
36 return read32((void *)addr);
Stefan Reinauere0d607a2010-03-28 21:31:30 +000037}
38
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010039/**
40 * Rotate ones test pattern that access every bit on a 128bit wide
41 * memory bus. To test most address lines, addresses are scattered
42 * using 256B, 4kB and 64kB increments.
43 *
Martin Roth5f066b22015-01-04 16:47:39 -070044 * @param idx Index to test pattern (0=<idx<0x400)
45 * @param addr Memory to access on idx
46 * @param value Value to write or read at addr
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010047 */
48static inline void test_pattern(unsigned short int idx,
49 unsigned long *addr, unsigned long *value)
Eric Biederman8ca8d762003-04-22 19:02:15 +000050{
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010051 uint8_t j, k;
52
53 k = (idx >> 8) + 1;
54 j = (idx >> 4) & 0x0f;
55 *addr = idx & 0x0f;
56 *addr |= j << (4*k);
57 *value = 0x01010101 << (j & 7);
58 if (j & 8)
59 *value = ~(*value);
Eric Biederman8ca8d762003-04-22 19:02:15 +000060}
61
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010062/**
63 * Simple write-read-verify memory test. See console debug output for
64 * any dislocated bytes.
65 *
Patrick Rudolph3dbd2842017-10-27 11:49:29 +020066 * Tests 1MiB of memory starting from start.
67 *
Martin Roth5f066b22015-01-04 16:47:39 -070068 * @param start System memory offset, aligned to 128bytes
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010069 */
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +020070static int ram_bitset_nodie(uintptr_t start)
Eric Biederman8ca8d762003-04-22 19:02:15 +000071{
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010072 unsigned long addr, value, value2;
73 unsigned short int idx;
74 unsigned char failed, failures;
75 uint8_t verbose = 0;
76
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010077 printk(BIOS_DEBUG, "DRAM bitset write: 0x%08lx\n", start);
Lee Leahy35af5c42017-03-09 17:35:28 -080078 for (idx = 0; idx < 0x400; idx += 4) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010079 test_pattern(idx, &addr, &value);
80 write_phys(start + addr, value);
81 }
82
83 /* Make sure we don't read before we wrote */
84 phys_memory_barrier();
85
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010086 printk(BIOS_DEBUG, "DRAM bitset verify: 0x%08lx\n", start);
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010087 failures = 0;
Lee Leahy35af5c42017-03-09 17:35:28 -080088 for (idx = 0; idx < 0x400; idx += 4) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010089 test_pattern(idx, &addr, &value);
90 value2 = read_phys(start + addr);
91
92 failed = (value2 != value);
93 failures |= failed;
Elyes HAOUAS1943f372018-05-04 16:30:39 +020094 if (failed && !verbose) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010095 printk(BIOS_ERR, "0x%08lx wr: 0x%08lx rd: 0x%08lx FAIL\n",
96 start + addr, value, value2);
Eric Biederman8ca8d762003-04-22 19:02:15 +000097 }
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010098 if (verbose) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010099 if ((addr & 0x0f) == 0)
100 printk(BIOS_DEBUG, "%08lx wr: %08lx rd:",
101 start + addr, value);
102 if (failed)
103 printk(BIOS_DEBUG, " %08lx!", value2);
104 else
105 printk(BIOS_DEBUG, " %08lx ", value2);
106 if ((addr & 0x0f) == 0xc)
107 printk(BIOS_DEBUG, "\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000108 }
109 }
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100110 if (failures) {
111 post_code(0xea);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000112 printk(BIOS_DEBUG, "\nDRAM did _NOT_ verify!\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100113 return 1;
Richard Smithffb7d8a2006-04-01 04:10:44 +0000114 }
Lee Leahy3e1cab42017-03-10 17:48:31 -0800115 printk(BIOS_DEBUG, "\nDRAM range verified.\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100116 return 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000117}
118
119
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +0200120void ram_check(uintptr_t start)
Eric Biederman8ca8d762003-04-22 19:02:15 +0000121{
Eric Biederman8ca8d762003-04-22 19:02:15 +0000122 /*
123 * This is much more of a "Is my DRAM properly configured?"
124 * test than a "Is my DRAM faulty?" test. Not all bits
125 * are tested. -Tyson
126 */
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100127 printk(BIOS_DEBUG, "Testing DRAM at: %08lx\n", start);
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100128 if (ram_bitset_nodie(start))
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100129 die("DRAM ERROR");
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000130 printk(BIOS_DEBUG, "Done.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000131}
132
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100133
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +0200134int ram_check_nodie(uintptr_t start)
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100135{
136 int ret;
137 /*
138 * This is much more of a "Is my DRAM properly configured?"
139 * test than a "Is my DRAM faulty?" test. Not all bits
140 * are tested. -Tyson
141 */
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100142 printk(BIOS_DEBUG, "Testing DRAM at : %08lx\n", start);
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100143
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100144 ret = ram_bitset_nodie(start);
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100145 printk(BIOS_DEBUG, "Done.\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100146 return ret;
147}
148
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +0200149int ram_check_noprint_nodie(uintptr_t start)
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500150{
151 unsigned long addr, value, value2;
152 unsigned short int idx;
153 unsigned char failed, failures;
154
Lee Leahy35af5c42017-03-09 17:35:28 -0800155 for (idx = 0; idx < 0x400; idx += 4) {
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500156 test_pattern(idx, &addr, &value);
157 write_phys(start + addr, value);
158 }
159
160 /* Make sure we don't read before we wrote */
161 phys_memory_barrier();
162
163 failures = 0;
Lee Leahy35af5c42017-03-09 17:35:28 -0800164 for (idx = 0; idx < 0x400; idx += 4) {
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500165 test_pattern(idx, &addr, &value);
166 value2 = read_phys(start + addr);
167
168 failed = (value2 != value);
169 failures |= failed;
170 }
171 return failures;
172}
173
Kyösti Mälkkif5cf60f2019-03-18 15:26:48 +0200174/* Assumption is 32-bit addressable UC memory at dst. This also executes
175 * on S3 resume path so target memory must be restored.
176 */
177void quick_ram_check_or_die(uintptr_t dst)
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000178{
179 int fail = 0;
180 u32 backup;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300181 backup = read_phys(dst);
182 write_phys(dst, 0x55555555);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000183 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300184 if (read_phys(dst) != 0x55555555)
Lee Leahy35af5c42017-03-09 17:35:28 -0800185 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300186 write_phys(dst, 0xaaaaaaaa);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000187 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300188 if (read_phys(dst) != 0xaaaaaaaa)
Lee Leahy35af5c42017-03-09 17:35:28 -0800189 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300190 write_phys(dst, 0x00000000);
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) != 0x00000000)
Lee Leahy35af5c42017-03-09 17:35:28 -0800193 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300194 write_phys(dst, 0xffffffff);
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) != 0xffffffff)
Lee Leahy35af5c42017-03-09 17:35:28 -0800197 fail = 1;
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000198
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300199 write_phys(dst, backup);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000200 if (fail) {
201 post_code(0xea);
202 die("RAM INIT FAILURE!\n");
203 }
204 phys_memory_barrier();
205}