blob: 90fc777a25acd11b5360a22431b5d1b81555a82d [file] [log] [blame]
Martin Rothfb8876d2022-08-07 15:12:12 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
Patrick Georgid0835952010-10-05 09:07:10 +00003#include <stdint.h>
Elyes HAOUAS3b3d0852021-02-01 10:09:40 +01004#include <lib.h>
Patrick Georgid0835952010-10-05 09:07:10 +00005#include <console/console.h>
Kyösti Mälkki321bce42019-03-20 19:53:44 +02006#include <device/mmio.h>
Myles Watson34261952010-03-19 02:33:40 +00007
Kyösti Mälkki7336f972020-06-08 06:05:03 +03008#if ENV_X86 && CONFIG(SSE2)
Kyösti Mälkki321bce42019-03-20 19:53:44 +02009/* Assembler in lib/ is ugly. */
10static void write_phys(uintptr_t addr, u32 value)
Eric Biederman8ca8d762003-04-22 19:02:15 +000011{
Kyösti Mälkki321bce42019-03-20 19:53:44 +020012 asm volatile (
Eric Biederman8d9c1232003-06-17 08:42:17 +000013 "movnti %1, (%0)"
14 : /* outputs */
15 : "r" (addr), "r" (value) /* inputs */
Kyösti Mälkki321bce42019-03-20 19:53:44 +020016 );
Eric Biederman8ca8d762003-04-22 19:02:15 +000017}
18
Stefan Reinauere0d607a2010-03-28 21:31:30 +000019static void phys_memory_barrier(void)
20{
Stefan Reinauere0d607a2010-03-28 21:31:30 +000021 // Needed for movnti
Kyösti Mälkki321bce42019-03-20 19:53:44 +020022 asm volatile ("sfence" ::: "memory");
23}
Stefan Reinauere0d607a2010-03-28 21:31:30 +000024#else
Kyösti Mälkki321bce42019-03-20 19:53:44 +020025static void write_phys(uintptr_t addr, u32 value)
26{
Elyes Haouas793403c2022-12-08 08:50:21 +010027 write32p(addr, value);
Kyösti Mälkki321bce42019-03-20 19:53:44 +020028}
29
30static void phys_memory_barrier(void)
31{
Stefan Reinauere0d607a2010-03-28 21:31:30 +000032 asm volatile ("" ::: "memory");
Kyösti Mälkki321bce42019-03-20 19:53:44 +020033}
Stefan Reinauere0d607a2010-03-28 21:31:30 +000034#endif
Kyösti Mälkki321bce42019-03-20 19:53:44 +020035
36static u32 read_phys(uintptr_t addr)
37{
Elyes Haouas793403c2022-12-08 08:50:21 +010038 return read32p(addr);
Stefan Reinauere0d607a2010-03-28 21:31:30 +000039}
40
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010041/**
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 *
Martin Roth5f066b22015-01-04 16:47:39 -070046 * @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
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010049 */
50static inline void test_pattern(unsigned short int idx,
51 unsigned long *addr, unsigned long *value)
Eric Biederman8ca8d762003-04-22 19:02:15 +000052{
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010053 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);
Eric Biederman8ca8d762003-04-22 19:02:15 +000062}
63
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010064/**
65 * Simple write-read-verify memory test. See console debug output for
66 * any dislocated bytes.
67 *
Patrick Rudolph3dbd2842017-10-27 11:49:29 +020068 * Tests 1MiB of memory starting from start.
69 *
Martin Roth5f066b22015-01-04 16:47:39 -070070 * @param start System memory offset, aligned to 128bytes
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010071 */
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +020072static int ram_bitset_nodie(uintptr_t start)
Eric Biederman8ca8d762003-04-22 19:02:15 +000073{
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010074 unsigned long addr, value, value2;
75 unsigned short int idx;
76 unsigned char failed, failures;
77 uint8_t verbose = 0;
78
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010079 printk(BIOS_DEBUG, "DRAM bitset write: 0x%08lx\n", start);
Lee Leahy35af5c42017-03-09 17:35:28 -080080 for (idx = 0; idx < 0x400; idx += 4) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010081 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
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010088 printk(BIOS_DEBUG, "DRAM bitset verify: 0x%08lx\n", start);
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010089 failures = 0;
Lee Leahy35af5c42017-03-09 17:35:28 -080090 for (idx = 0; idx < 0x400; idx += 4) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010091 test_pattern(idx, &addr, &value);
92 value2 = read_phys(start + addr);
93
94 failed = (value2 != value);
95 failures |= failed;
Elyes HAOUAS1943f372018-05-04 16:30:39 +020096 if (failed && !verbose) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +010097 printk(BIOS_ERR, "0x%08lx wr: 0x%08lx rd: 0x%08lx FAIL\n",
98 start + addr, value, value2);
Eric Biederman8ca8d762003-04-22 19:02:15 +000099 }
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100100 if (verbose) {
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100101 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");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000110 }
111 }
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100112 if (failures) {
lilacious40cb3fe2023-06-21 23:24:14 +0200113 post_code(POSTCODE_RAM_FAILURE);
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000114 printk(BIOS_DEBUG, "\nDRAM did _NOT_ verify!\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100115 return 1;
Richard Smithffb7d8a2006-04-01 04:10:44 +0000116 }
Lee Leahy3e1cab42017-03-10 17:48:31 -0800117 printk(BIOS_DEBUG, "\nDRAM range verified.\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100118 return 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000119}
120
121
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +0200122void ram_check(uintptr_t start)
Eric Biederman8ca8d762003-04-22 19:02:15 +0000123{
Eric Biederman8ca8d762003-04-22 19:02:15 +0000124 /*
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 */
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100129 printk(BIOS_DEBUG, "Testing DRAM at: %08lx\n", start);
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100130 if (ram_bitset_nodie(start))
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100131 die("DRAM ERROR");
Stefan Reinauer64ed2b72010-03-31 14:47:43 +0000132 printk(BIOS_DEBUG, "Done.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +0000133}
134
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100135
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +0200136int ram_check_nodie(uintptr_t start)
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100137{
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 */
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100144 printk(BIOS_DEBUG, "Testing DRAM at : %08lx\n", start);
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100145
Kyösti Mälkkie77b9a02012-03-17 08:09:14 +0100146 ret = ram_bitset_nodie(start);
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100147 printk(BIOS_DEBUG, "Done.\n");
Sven Schnelle3ad8c542011-12-02 16:23:06 +0100148 return ret;
149}
150
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +0200151int ram_check_noprint_nodie(uintptr_t start)
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500152{
153 unsigned long addr, value, value2;
154 unsigned short int idx;
155 unsigned char failed, failures;
156
Lee Leahy35af5c42017-03-09 17:35:28 -0800157 for (idx = 0; idx < 0x400; idx += 4) {
Alexandru Gagniuc5239ba22013-06-08 11:32:36 -0500158 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;
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 value2 = read_phys(start + addr);
169
170 failed = (value2 != value);
171 failures |= failed;
172 }
173 return failures;
174}
175
Kyösti Mälkkif5cf60f2019-03-18 15:26:48 +0200176/* Assumption is 32-bit addressable UC memory at dst. This also executes
177 * on S3 resume path so target memory must be restored.
178 */
179void quick_ram_check_or_die(uintptr_t dst)
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000180{
181 int fail = 0;
182 u32 backup;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300183 backup = read_phys(dst);
184 write_phys(dst, 0x55555555);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000185 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300186 if (read_phys(dst) != 0x55555555)
Lee Leahy35af5c42017-03-09 17:35:28 -0800187 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300188 write_phys(dst, 0xaaaaaaaa);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000189 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300190 if (read_phys(dst) != 0xaaaaaaaa)
Lee Leahy35af5c42017-03-09 17:35:28 -0800191 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300192 write_phys(dst, 0x00000000);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000193 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300194 if (read_phys(dst) != 0x00000000)
Lee Leahy35af5c42017-03-09 17:35:28 -0800195 fail = 1;
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300196 write_phys(dst, 0xffffffff);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000197 phys_memory_barrier();
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300198 if (read_phys(dst) != 0xffffffff)
Lee Leahy35af5c42017-03-09 17:35:28 -0800199 fail = 1;
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000200
Kyösti Mälkki19652e62016-06-17 23:31:42 +0300201 write_phys(dst, backup);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000202 if (fail) {
lilacious40cb3fe2023-06-21 23:24:14 +0200203 post_code(POSTCODE_RAM_FAILURE);
Stefan Reinauere0d607a2010-03-28 21:31:30 +0000204 die("RAM INIT FAILURE!\n");
205 }
206 phys_memory_barrier();
207}