xref: /openbmc/u-boot/post/drivers/memory.c (revision e8f80a5a)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2ad5bb451SWolfgang Denk /*
3ad5bb451SWolfgang Denk  * (C) Copyright 2002
4ad5bb451SWolfgang Denk  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5ad5bb451SWolfgang Denk  */
6ad5bb451SWolfgang Denk 
7ad5bb451SWolfgang Denk #include <common.h>
8ad5bb451SWolfgang Denk 
9ad5bb451SWolfgang Denk /* Memory test
10ad5bb451SWolfgang Denk  *
11ad5bb451SWolfgang Denk  * General observations:
12ad5bb451SWolfgang Denk  * o The recommended test sequence is to test the data lines: if they are
13ad5bb451SWolfgang Denk  *   broken, nothing else will work properly.  Then test the address
14ad5bb451SWolfgang Denk  *   lines.  Finally, test the cells in the memory now that the test
15ad5bb451SWolfgang Denk  *   program knows that the address and data lines work properly.
16ad5bb451SWolfgang Denk  *   This sequence also helps isolate and identify what is faulty.
17ad5bb451SWolfgang Denk  *
18ad5bb451SWolfgang Denk  * o For the address line test, it is a good idea to use the base
19ad5bb451SWolfgang Denk  *   address of the lowest memory location, which causes a '1' bit to
20ad5bb451SWolfgang Denk  *   walk through a field of zeros on the address lines and the highest
21ad5bb451SWolfgang Denk  *   memory location, which causes a '0' bit to walk through a field of
22ad5bb451SWolfgang Denk  *   '1's on the address line.
23ad5bb451SWolfgang Denk  *
24ad5bb451SWolfgang Denk  * o Floating buses can fool memory tests if the test routine writes
25ad5bb451SWolfgang Denk  *   a value and then reads it back immediately.  The problem is, the
26ad5bb451SWolfgang Denk  *   write will charge the residual capacitance on the data bus so the
27ad5bb451SWolfgang Denk  *   bus retains its state briefely.  When the test program reads the
28ad5bb451SWolfgang Denk  *   value back immediately, the capacitance of the bus can allow it
29ad5bb451SWolfgang Denk  *   to read back what was written, even though the memory circuitry
30ad5bb451SWolfgang Denk  *   is broken.  To avoid this, the test program should write a test
31ad5bb451SWolfgang Denk  *   pattern to the target location, write a different pattern elsewhere
32ad5bb451SWolfgang Denk  *   to charge the residual capacitance in a differnt manner, then read
33ad5bb451SWolfgang Denk  *   the target location back.
34ad5bb451SWolfgang Denk  *
35ad5bb451SWolfgang Denk  * o Always read the target location EXACTLY ONCE and save it in a local
36ad5bb451SWolfgang Denk  *   variable.  The problem with reading the target location more than
37ad5bb451SWolfgang Denk  *   once is that the second and subsequent reads may work properly,
38ad5bb451SWolfgang Denk  *   resulting in a failed test that tells the poor technician that
39ad5bb451SWolfgang Denk  *   "Memory error at 00000000, wrote aaaaaaaa, read aaaaaaaa" which
40ad5bb451SWolfgang Denk  *   doesn't help him one bit and causes puzzled phone calls.  Been there,
41ad5bb451SWolfgang Denk  *   done that.
42ad5bb451SWolfgang Denk  *
43ad5bb451SWolfgang Denk  * Data line test:
44ad5bb451SWolfgang Denk  * ---------------
45ad5bb451SWolfgang Denk  * This tests data lines for shorts and opens by forcing adjacent data
46ad5bb451SWolfgang Denk  * to opposite states. Because the data lines could be routed in an
47ad5bb451SWolfgang Denk  * arbitrary manner the must ensure test patterns ensure that every case
48ad5bb451SWolfgang Denk  * is tested. By using the following series of binary patterns every
49ad5bb451SWolfgang Denk  * combination of adjacent bits is test regardless of routing.
50ad5bb451SWolfgang Denk  *
51ad5bb451SWolfgang Denk  *     ...101010101010101010101010
52ad5bb451SWolfgang Denk  *     ...110011001100110011001100
53ad5bb451SWolfgang Denk  *     ...111100001111000011110000
54ad5bb451SWolfgang Denk  *     ...111111110000000011111111
55ad5bb451SWolfgang Denk  *
56ad5bb451SWolfgang Denk  * Carrying this out, gives us six hex patterns as follows:
57ad5bb451SWolfgang Denk  *
58ad5bb451SWolfgang Denk  *     0xaaaaaaaaaaaaaaaa
59ad5bb451SWolfgang Denk  *     0xcccccccccccccccc
60ad5bb451SWolfgang Denk  *     0xf0f0f0f0f0f0f0f0
61ad5bb451SWolfgang Denk  *     0xff00ff00ff00ff00
62ad5bb451SWolfgang Denk  *     0xffff0000ffff0000
63ad5bb451SWolfgang Denk  *     0xffffffff00000000
64ad5bb451SWolfgang Denk  *
65ad5bb451SWolfgang Denk  * To test for short and opens to other signals on our boards, we
66ad5bb451SWolfgang Denk  * simply test with the 1's complemnt of the paterns as well, resulting
67ad5bb451SWolfgang Denk  * in twelve patterns total.
68ad5bb451SWolfgang Denk  *
69ad5bb451SWolfgang Denk  * After writing a test pattern. a special pattern 0x0123456789ABCDEF is
70ad5bb451SWolfgang Denk  * written to a different address in case the data lines are floating.
71ad5bb451SWolfgang Denk  * Thus, if a byte lane fails, you will see part of the special
72ad5bb451SWolfgang Denk  * pattern in that byte lane when the test runs.  For example, if the
73ad5bb451SWolfgang Denk  * xx__xxxxxxxxxxxx byte line fails, you will see aa23aaaaaaaaaaaa
74ad5bb451SWolfgang Denk  * (for the 'a' test pattern).
75ad5bb451SWolfgang Denk  *
76ad5bb451SWolfgang Denk  * Address line test:
77ad5bb451SWolfgang Denk  * ------------------
78ad5bb451SWolfgang Denk  *  This function performs a test to verify that all the address lines
79ad5bb451SWolfgang Denk  *  hooked up to the RAM work properly.  If there is an address line
80ad5bb451SWolfgang Denk  *  fault, it usually shows up as two different locations in the address
81ad5bb451SWolfgang Denk  *  map (related by the faulty address line) mapping to one physical
82ad5bb451SWolfgang Denk  *  memory storage location.  The artifact that shows up is writing to
83ad5bb451SWolfgang Denk  *  the first location "changes" the second location.
84ad5bb451SWolfgang Denk  *
85ad5bb451SWolfgang Denk  * To test all address lines, we start with the given base address and
86ad5bb451SWolfgang Denk  * xor the address with a '1' bit to flip one address line.  For each
87ad5bb451SWolfgang Denk  * test, we shift the '1' bit left to test the next address line.
88ad5bb451SWolfgang Denk  *
89ad5bb451SWolfgang Denk  * In the actual code, we start with address sizeof(ulong) since our
90ad5bb451SWolfgang Denk  * test pattern we use is a ulong and thus, if we tried to test lower
91ad5bb451SWolfgang Denk  * order address bits, it wouldn't work because our pattern would
92ad5bb451SWolfgang Denk  * overwrite itself.
93ad5bb451SWolfgang Denk  *
94ad5bb451SWolfgang Denk  * Example for a 4 bit address space with the base at 0000:
95ad5bb451SWolfgang Denk  *   0000 <- base
96ad5bb451SWolfgang Denk  *   0001 <- test 1
97ad5bb451SWolfgang Denk  *   0010 <- test 2
98ad5bb451SWolfgang Denk  *   0100 <- test 3
99ad5bb451SWolfgang Denk  *   1000 <- test 4
100ad5bb451SWolfgang Denk  * Example for a 4 bit address space with the base at 0010:
101ad5bb451SWolfgang Denk  *   0010 <- base
102ad5bb451SWolfgang Denk  *   0011 <- test 1
103ad5bb451SWolfgang Denk  *   0000 <- (below the base address, skipped)
104ad5bb451SWolfgang Denk  *   0110 <- test 2
105ad5bb451SWolfgang Denk  *   1010 <- test 3
106ad5bb451SWolfgang Denk  *
107ad5bb451SWolfgang Denk  * The test locations are successively tested to make sure that they are
108ad5bb451SWolfgang Denk  * not "mirrored" onto the base address due to a faulty address line.
109ad5bb451SWolfgang Denk  * Note that the base and each test location are related by one address
110ad5bb451SWolfgang Denk  * line flipped.  Note that the base address need not be all zeros.
111ad5bb451SWolfgang Denk  *
112ad5bb451SWolfgang Denk  * Memory tests 1-4:
113ad5bb451SWolfgang Denk  * -----------------
114ad5bb451SWolfgang Denk  * These tests verify RAM using sequential writes and reads
115ad5bb451SWolfgang Denk  * to/from RAM. There are several test cases that use different patterns to
116ad5bb451SWolfgang Denk  * verify RAM. Each test case fills a region of RAM with one pattern and
117ad5bb451SWolfgang Denk  * then reads the region back and compares its contents with the pattern.
118ad5bb451SWolfgang Denk  * The following patterns are used:
119ad5bb451SWolfgang Denk  *
120ad5bb451SWolfgang Denk  *  1a) zero pattern (0x00000000)
121ad5bb451SWolfgang Denk  *  1b) negative pattern (0xffffffff)
122ad5bb451SWolfgang Denk  *  1c) checkerboard pattern (0x55555555)
123ad5bb451SWolfgang Denk  *  1d) checkerboard pattern (0xaaaaaaaa)
124ad5bb451SWolfgang Denk  *  2)  bit-flip pattern ((1 << (offset % 32))
125ad5bb451SWolfgang Denk  *  3)  address pattern (offset)
126ad5bb451SWolfgang Denk  *  4)  address pattern (~offset)
127ad5bb451SWolfgang Denk  *
128ad5bb451SWolfgang Denk  * Being run in normal mode, the test verifies only small 4Kb
129ad5bb451SWolfgang Denk  * regions of RAM around each 1Mb boundary. For example, for 64Mb
130ad5bb451SWolfgang Denk  * RAM the following areas are verified: 0x00000000-0x00000800,
131ad5bb451SWolfgang Denk  * 0x000ff800-0x00100800, 0x001ff800-0x00200800, ..., 0x03fff800-
132ad5bb451SWolfgang Denk  * 0x04000000. If the test is run in slow-test mode, it verifies
133ad5bb451SWolfgang Denk  * the whole RAM.
134ad5bb451SWolfgang Denk  */
135ad5bb451SWolfgang Denk 
136ad5bb451SWolfgang Denk #include <post.h>
137ad5bb451SWolfgang Denk #include <watchdog.h>
138ad5bb451SWolfgang Denk 
1398d3fcb5eSValentin Longchamp #if CONFIG_POST & (CONFIG_SYS_POST_MEMORY | CONFIG_SYS_POST_MEM_REGIONS)
140ad5bb451SWolfgang Denk 
141ad5bb451SWolfgang Denk DECLARE_GLOBAL_DATA_PTR;
142ad5bb451SWolfgang Denk 
143ad5bb451SWolfgang Denk /*
144ad5bb451SWolfgang Denk  * Define INJECT_*_ERRORS for testing error detection in the presence of
145ad5bb451SWolfgang Denk  * _good_ hardware.
146ad5bb451SWolfgang Denk  */
147ad5bb451SWolfgang Denk #undef  INJECT_DATA_ERRORS
148ad5bb451SWolfgang Denk #undef  INJECT_ADDRESS_ERRORS
149ad5bb451SWolfgang Denk 
150ad5bb451SWolfgang Denk #ifdef INJECT_DATA_ERRORS
151ad5bb451SWolfgang Denk #warning "Injecting data line errors for testing purposes"
152ad5bb451SWolfgang Denk #endif
153ad5bb451SWolfgang Denk 
154ad5bb451SWolfgang Denk #ifdef INJECT_ADDRESS_ERRORS
155ad5bb451SWolfgang Denk #warning "Injecting address line errors for testing purposes"
156ad5bb451SWolfgang Denk #endif
157ad5bb451SWolfgang Denk 
158ad5bb451SWolfgang Denk 
159ad5bb451SWolfgang Denk /*
160ad5bb451SWolfgang Denk  * This function performs a double word move from the data at
161ad5bb451SWolfgang Denk  * the source pointer to the location at the destination pointer.
162ad5bb451SWolfgang Denk  * This is helpful for testing memory on processors which have a 64 bit
163ad5bb451SWolfgang Denk  * wide data bus.
164ad5bb451SWolfgang Denk  *
165ad5bb451SWolfgang Denk  * On those PowerPC with FPU, use assembly and a floating point move:
166ad5bb451SWolfgang Denk  * this does a 64 bit move.
167ad5bb451SWolfgang Denk  *
168ad5bb451SWolfgang Denk  * For other processors, let the compiler generate the best code it can.
169ad5bb451SWolfgang Denk  */
move64(const unsigned long long * src,unsigned long long * dest)17044b4dbedSAnatolij Gustschin static void move64(const unsigned long long *src, unsigned long long *dest)
171ad5bb451SWolfgang Denk {
172ad5bb451SWolfgang Denk 	*dest = *src;
173ad5bb451SWolfgang Denk }
174ad5bb451SWolfgang Denk 
175ad5bb451SWolfgang Denk /*
176ad5bb451SWolfgang Denk  * This is 64 bit wide test patterns.  Note that they reside in ROM
177ad5bb451SWolfgang Denk  * (which presumably works) and the tests write them to RAM which may
178ad5bb451SWolfgang Denk  * not work.
179ad5bb451SWolfgang Denk  *
180ad5bb451SWolfgang Denk  * The "otherpattern" is written to drive the data bus to values other
181ad5bb451SWolfgang Denk  * than the test pattern.  This is for detecting floating bus lines.
182ad5bb451SWolfgang Denk  *
183ad5bb451SWolfgang Denk  */
184ad5bb451SWolfgang Denk const static unsigned long long pattern[] = {
185ad5bb451SWolfgang Denk 	0xaaaaaaaaaaaaaaaaULL,
186ad5bb451SWolfgang Denk 	0xccccccccccccccccULL,
187ad5bb451SWolfgang Denk 	0xf0f0f0f0f0f0f0f0ULL,
188ad5bb451SWolfgang Denk 	0xff00ff00ff00ff00ULL,
189ad5bb451SWolfgang Denk 	0xffff0000ffff0000ULL,
190ad5bb451SWolfgang Denk 	0xffffffff00000000ULL,
191ad5bb451SWolfgang Denk 	0x00000000ffffffffULL,
192ad5bb451SWolfgang Denk 	0x0000ffff0000ffffULL,
193ad5bb451SWolfgang Denk 	0x00ff00ff00ff00ffULL,
194ad5bb451SWolfgang Denk 	0x0f0f0f0f0f0f0f0fULL,
195ad5bb451SWolfgang Denk 	0x3333333333333333ULL,
196ad5bb451SWolfgang Denk 	0x5555555555555555ULL
197ad5bb451SWolfgang Denk };
198ad5bb451SWolfgang Denk const unsigned long long otherpattern = 0x0123456789abcdefULL;
199ad5bb451SWolfgang Denk 
200ad5bb451SWolfgang Denk 
memory_post_dataline(unsigned long long * pmem)201ad5bb451SWolfgang Denk static int memory_post_dataline(unsigned long long * pmem)
202ad5bb451SWolfgang Denk {
203ad5bb451SWolfgang Denk 	unsigned long long temp64 = 0;
204d2397817SMike Frysinger 	int num_patterns = ARRAY_SIZE(pattern);
205ad5bb451SWolfgang Denk 	int i;
206ad5bb451SWolfgang Denk 	unsigned int hi, lo, pathi, patlo;
207ad5bb451SWolfgang Denk 	int ret = 0;
208ad5bb451SWolfgang Denk 
209ad5bb451SWolfgang Denk 	for ( i = 0; i < num_patterns; i++) {
21044b4dbedSAnatolij Gustschin 		move64(&(pattern[i]), pmem++);
211ad5bb451SWolfgang Denk 		/*
212ad5bb451SWolfgang Denk 		 * Put a different pattern on the data lines: otherwise they
213ad5bb451SWolfgang Denk 		 * may float long enough to read back what we wrote.
214ad5bb451SWolfgang Denk 		 */
21544b4dbedSAnatolij Gustschin 		move64(&otherpattern, pmem--);
216ad5bb451SWolfgang Denk 		move64(pmem, &temp64);
217ad5bb451SWolfgang Denk 
218ad5bb451SWolfgang Denk #ifdef INJECT_DATA_ERRORS
219ad5bb451SWolfgang Denk 		temp64 ^= 0x00008000;
220ad5bb451SWolfgang Denk #endif
221ad5bb451SWolfgang Denk 
222ad5bb451SWolfgang Denk 		if (temp64 != pattern[i]){
223ad5bb451SWolfgang Denk 			pathi = (pattern[i]>>32) & 0xffffffff;
224ad5bb451SWolfgang Denk 			patlo = pattern[i] & 0xffffffff;
225ad5bb451SWolfgang Denk 
226ad5bb451SWolfgang Denk 			hi = (temp64>>32) & 0xffffffff;
227ad5bb451SWolfgang Denk 			lo = temp64 & 0xffffffff;
228ad5bb451SWolfgang Denk 
229e2ee3014SNiko Mauno 			post_log("Memory (data line) error at %08x, "
230ad5bb451SWolfgang Denk 				  "wrote %08x%08x, read %08x%08x !\n",
231ad5bb451SWolfgang Denk 					  pmem, pathi, patlo, hi, lo);
232ad5bb451SWolfgang Denk 			ret = -1;
233ad5bb451SWolfgang Denk 		}
234ad5bb451SWolfgang Denk 	}
235ad5bb451SWolfgang Denk 	return ret;
236ad5bb451SWolfgang Denk }
237ad5bb451SWolfgang Denk 
memory_post_addrline(ulong * testaddr,ulong * base,ulong size)238ad5bb451SWolfgang Denk static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size)
239ad5bb451SWolfgang Denk {
240ad5bb451SWolfgang Denk 	ulong *target;
241ad5bb451SWolfgang Denk 	ulong *end;
242ad5bb451SWolfgang Denk 	ulong readback;
243ad5bb451SWolfgang Denk 	ulong xor;
244ad5bb451SWolfgang Denk 	int   ret = 0;
245ad5bb451SWolfgang Denk 
246ad5bb451SWolfgang Denk 	end = (ulong *)((ulong)base + size);	/* pointer arith! */
247ad5bb451SWolfgang Denk 	xor = 0;
248ad5bb451SWolfgang Denk 	for(xor = sizeof(ulong); xor > 0; xor <<= 1) {
249ad5bb451SWolfgang Denk 		target = (ulong *)((ulong)testaddr ^ xor);
250ad5bb451SWolfgang Denk 		if((target >= base) && (target < end)) {
251ad5bb451SWolfgang Denk 			*testaddr = ~*target;
252ad5bb451SWolfgang Denk 			readback  = *target;
253ad5bb451SWolfgang Denk 
254ad5bb451SWolfgang Denk #ifdef INJECT_ADDRESS_ERRORS
255ad5bb451SWolfgang Denk 			if(xor == 0x00008000) {
256ad5bb451SWolfgang Denk 				readback = *testaddr;
257ad5bb451SWolfgang Denk 			}
258ad5bb451SWolfgang Denk #endif
259ad5bb451SWolfgang Denk 			if(readback == *testaddr) {
260ad5bb451SWolfgang Denk 				post_log("Memory (address line) error at %08x<->%08x, "
261ad5bb451SWolfgang Denk 					"XOR value %08x !\n",
262ad5bb451SWolfgang Denk 					testaddr, target, xor);
263ad5bb451SWolfgang Denk 				ret = -1;
264ad5bb451SWolfgang Denk 			}
265ad5bb451SWolfgang Denk 		}
266ad5bb451SWolfgang Denk 	}
267ad5bb451SWolfgang Denk 	return ret;
268ad5bb451SWolfgang Denk }
269ad5bb451SWolfgang Denk 
memory_post_test1(unsigned long start,unsigned long size,unsigned long val)270ad5bb451SWolfgang Denk static int memory_post_test1(unsigned long start,
271ad5bb451SWolfgang Denk 			      unsigned long size,
272ad5bb451SWolfgang Denk 			      unsigned long val)
273ad5bb451SWolfgang Denk {
274ad5bb451SWolfgang Denk 	unsigned long i;
275ad5bb451SWolfgang Denk 	ulong *mem = (ulong *) start;
276ad5bb451SWolfgang Denk 	ulong readback;
277ad5bb451SWolfgang Denk 	int ret = 0;
278ad5bb451SWolfgang Denk 
279ad5bb451SWolfgang Denk 	for (i = 0; i < size / sizeof (ulong); i++) {
280ad5bb451SWolfgang Denk 		mem[i] = val;
281ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
282ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
283ad5bb451SWolfgang Denk 	}
284ad5bb451SWolfgang Denk 
285ca51d057SValentin Longchamp 	for (i = 0; i < size / sizeof (ulong) && !ret; i++) {
286ad5bb451SWolfgang Denk 		readback = mem[i];
287ad5bb451SWolfgang Denk 		if (readback != val) {
288ad5bb451SWolfgang Denk 			post_log("Memory error at %08x, "
289ad5bb451SWolfgang Denk 				  "wrote %08x, read %08x !\n",
290ad5bb451SWolfgang Denk 					  mem + i, val, readback);
291ad5bb451SWolfgang Denk 
292ad5bb451SWolfgang Denk 			ret = -1;
293ad5bb451SWolfgang Denk 			break;
294ad5bb451SWolfgang Denk 		}
295ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
296ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
297ad5bb451SWolfgang Denk 	}
298ad5bb451SWolfgang Denk 
299ad5bb451SWolfgang Denk 	return ret;
300ad5bb451SWolfgang Denk }
301ad5bb451SWolfgang Denk 
memory_post_test2(unsigned long start,unsigned long size)302ad5bb451SWolfgang Denk static int memory_post_test2(unsigned long start, unsigned long size)
303ad5bb451SWolfgang Denk {
304ad5bb451SWolfgang Denk 	unsigned long i;
305ad5bb451SWolfgang Denk 	ulong *mem = (ulong *) start;
306ad5bb451SWolfgang Denk 	ulong readback;
307ad5bb451SWolfgang Denk 	int ret = 0;
308ad5bb451SWolfgang Denk 
309ad5bb451SWolfgang Denk 	for (i = 0; i < size / sizeof (ulong); i++) {
310ad5bb451SWolfgang Denk 		mem[i] = 1 << (i % 32);
311ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
312ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
313ad5bb451SWolfgang Denk 	}
314ad5bb451SWolfgang Denk 
315ca51d057SValentin Longchamp 	for (i = 0; i < size / sizeof (ulong) && !ret; i++) {
316ad5bb451SWolfgang Denk 		readback = mem[i];
317ad5bb451SWolfgang Denk 		if (readback != (1 << (i % 32))) {
318ad5bb451SWolfgang Denk 			post_log("Memory error at %08x, "
319ad5bb451SWolfgang Denk 				  "wrote %08x, read %08x !\n",
320ad5bb451SWolfgang Denk 					  mem + i, 1 << (i % 32), readback);
321ad5bb451SWolfgang Denk 
322ad5bb451SWolfgang Denk 			ret = -1;
323ad5bb451SWolfgang Denk 			break;
324ad5bb451SWolfgang Denk 		}
325ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
326ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
327ad5bb451SWolfgang Denk 	}
328ad5bb451SWolfgang Denk 
329ad5bb451SWolfgang Denk 	return ret;
330ad5bb451SWolfgang Denk }
331ad5bb451SWolfgang Denk 
memory_post_test3(unsigned long start,unsigned long size)332ad5bb451SWolfgang Denk static int memory_post_test3(unsigned long start, unsigned long size)
333ad5bb451SWolfgang Denk {
334ad5bb451SWolfgang Denk 	unsigned long i;
335ad5bb451SWolfgang Denk 	ulong *mem = (ulong *) start;
336ad5bb451SWolfgang Denk 	ulong readback;
337ad5bb451SWolfgang Denk 	int ret = 0;
338ad5bb451SWolfgang Denk 
339ad5bb451SWolfgang Denk 	for (i = 0; i < size / sizeof (ulong); i++) {
340ad5bb451SWolfgang Denk 		mem[i] = i;
341ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
342ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
343ad5bb451SWolfgang Denk 	}
344ad5bb451SWolfgang Denk 
345ca51d057SValentin Longchamp 	for (i = 0; i < size / sizeof (ulong) && !ret; i++) {
346ad5bb451SWolfgang Denk 		readback = mem[i];
347ad5bb451SWolfgang Denk 		if (readback != i) {
348ad5bb451SWolfgang Denk 			post_log("Memory error at %08x, "
349ad5bb451SWolfgang Denk 				  "wrote %08x, read %08x !\n",
350ad5bb451SWolfgang Denk 					  mem + i, i, readback);
351ad5bb451SWolfgang Denk 
352ad5bb451SWolfgang Denk 			ret = -1;
353ad5bb451SWolfgang Denk 			break;
354ad5bb451SWolfgang Denk 		}
355ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
356ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
357ad5bb451SWolfgang Denk 	}
358ad5bb451SWolfgang Denk 
359ad5bb451SWolfgang Denk 	return ret;
360ad5bb451SWolfgang Denk }
361ad5bb451SWolfgang Denk 
memory_post_test4(unsigned long start,unsigned long size)362ad5bb451SWolfgang Denk static int memory_post_test4(unsigned long start, unsigned long size)
363ad5bb451SWolfgang Denk {
364ad5bb451SWolfgang Denk 	unsigned long i;
365ad5bb451SWolfgang Denk 	ulong *mem = (ulong *) start;
366ad5bb451SWolfgang Denk 	ulong readback;
367ad5bb451SWolfgang Denk 	int ret = 0;
368ad5bb451SWolfgang Denk 
369ad5bb451SWolfgang Denk 	for (i = 0; i < size / sizeof (ulong); i++) {
370ad5bb451SWolfgang Denk 		mem[i] = ~i;
371ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
372ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
373ad5bb451SWolfgang Denk 	}
374ad5bb451SWolfgang Denk 
375ca51d057SValentin Longchamp 	for (i = 0; i < size / sizeof (ulong) && !ret; i++) {
376ad5bb451SWolfgang Denk 		readback = mem[i];
377ad5bb451SWolfgang Denk 		if (readback != ~i) {
378ad5bb451SWolfgang Denk 			post_log("Memory error at %08x, "
379ad5bb451SWolfgang Denk 				  "wrote %08x, read %08x !\n",
380ad5bb451SWolfgang Denk 					  mem + i, ~i, readback);
381ad5bb451SWolfgang Denk 
382ad5bb451SWolfgang Denk 			ret = -1;
383ad5bb451SWolfgang Denk 			break;
384ad5bb451SWolfgang Denk 		}
385ad5bb451SWolfgang Denk 		if (i % 1024 == 0)
386ad5bb451SWolfgang Denk 			WATCHDOG_RESET();
387ad5bb451SWolfgang Denk 	}
388ad5bb451SWolfgang Denk 
389ad5bb451SWolfgang Denk 	return ret;
390ad5bb451SWolfgang Denk }
391ad5bb451SWolfgang Denk 
memory_post_test_lines(unsigned long start,unsigned long size)3928d3fcb5eSValentin Longchamp static int memory_post_test_lines(unsigned long start, unsigned long size)
393ad5bb451SWolfgang Denk {
394ad5bb451SWolfgang Denk 	int ret = 0;
395ad5bb451SWolfgang Denk 
396ad5bb451SWolfgang Denk 	ret = memory_post_dataline((unsigned long long *)start);
397ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
398ca51d057SValentin Longchamp 	if (!ret)
399ca51d057SValentin Longchamp 		ret = memory_post_addrline((ulong *)start, (ulong *)start,
400ca51d057SValentin Longchamp 				size);
401ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
402ca51d057SValentin Longchamp 	if (!ret)
403ad5bb451SWolfgang Denk 		ret = memory_post_addrline((ulong *)(start+size-8),
404ad5bb451SWolfgang Denk 				(ulong *)start, size);
405ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
4068d3fcb5eSValentin Longchamp 
4078d3fcb5eSValentin Longchamp 	return ret;
4088d3fcb5eSValentin Longchamp }
4098d3fcb5eSValentin Longchamp 
memory_post_test_patterns(unsigned long start,unsigned long size)4108d3fcb5eSValentin Longchamp static int memory_post_test_patterns(unsigned long start, unsigned long size)
4118d3fcb5eSValentin Longchamp {
4128d3fcb5eSValentin Longchamp 	int ret = 0;
4138d3fcb5eSValentin Longchamp 
414ad5bb451SWolfgang Denk 	ret = memory_post_test1(start, size, 0x00000000);
415ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
416ca51d057SValentin Longchamp 	if (!ret)
417ad5bb451SWolfgang Denk 		ret = memory_post_test1(start, size, 0xffffffff);
418ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
419ca51d057SValentin Longchamp 	if (!ret)
420ad5bb451SWolfgang Denk 		ret = memory_post_test1(start, size, 0x55555555);
421ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
422ca51d057SValentin Longchamp 	if (!ret)
423ad5bb451SWolfgang Denk 		ret = memory_post_test1(start, size, 0xaaaaaaaa);
424ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
425ca51d057SValentin Longchamp 	if (!ret)
426ad5bb451SWolfgang Denk 		ret = memory_post_test2(start, size);
427ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
428ca51d057SValentin Longchamp 	if (!ret)
429ad5bb451SWolfgang Denk 		ret = memory_post_test3(start, size);
430ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
431ca51d057SValentin Longchamp 	if (!ret)
432ad5bb451SWolfgang Denk 		ret = memory_post_test4(start, size);
433ad5bb451SWolfgang Denk 	WATCHDOG_RESET();
434ad5bb451SWolfgang Denk 
435ad5bb451SWolfgang Denk 	return ret;
436ad5bb451SWolfgang Denk }
437ad5bb451SWolfgang Denk 
memory_post_test_regions(unsigned long start,unsigned long size)4388d3fcb5eSValentin Longchamp static int memory_post_test_regions(unsigned long start, unsigned long size)
4398d3fcb5eSValentin Longchamp {
4408d3fcb5eSValentin Longchamp 	unsigned long i;
4418d3fcb5eSValentin Longchamp 	int ret = 0;
4428d3fcb5eSValentin Longchamp 
4438d3fcb5eSValentin Longchamp 	for (i = 0; i < (size >> 20) && (!ret); i++) {
4448d3fcb5eSValentin Longchamp 		if (!ret)
4457b5d61b5SHeiko Schocher 			ret = memory_post_test_patterns(start + (i << 20),
4468d3fcb5eSValentin Longchamp 				0x800);
4477b5d61b5SHeiko Schocher 		if (!ret)
4487b5d61b5SHeiko Schocher 			ret = memory_post_test_patterns(start + (i << 20) +
4497b5d61b5SHeiko Schocher 				0xff800, 0x800);
4508d3fcb5eSValentin Longchamp 	}
4518d3fcb5eSValentin Longchamp 
4528d3fcb5eSValentin Longchamp 	return ret;
4538d3fcb5eSValentin Longchamp }
4548d3fcb5eSValentin Longchamp 
memory_post_tests(unsigned long start,unsigned long size)4558d3fcb5eSValentin Longchamp static int memory_post_tests(unsigned long start, unsigned long size)
4568d3fcb5eSValentin Longchamp {
4578d3fcb5eSValentin Longchamp 	int ret = 0;
4588d3fcb5eSValentin Longchamp 
4598d3fcb5eSValentin Longchamp 	ret = memory_post_test_lines(start, size);
4608d3fcb5eSValentin Longchamp 	if (!ret)
4618d3fcb5eSValentin Longchamp 		ret = memory_post_test_patterns(start, size);
4628d3fcb5eSValentin Longchamp 
4638d3fcb5eSValentin Longchamp 	return ret;
4648d3fcb5eSValentin Longchamp }
4658d3fcb5eSValentin Longchamp 
4664204298dSHeiko Schocher /*
4674204298dSHeiko Schocher  * !! this is only valid, if you have contiguous memory banks !!
4684204298dSHeiko Schocher  */
46928417030SYork Sun __attribute__((weak))
arch_memory_test_prepare(u32 * vstart,u32 * size,phys_addr_t * phys_offset)47028417030SYork Sun int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
471ad5bb451SWolfgang Denk {
472ad5bb451SWolfgang Denk 	bd_t *bd = gd->bd;
4734204298dSHeiko Schocher 
47428417030SYork Sun 	*vstart = CONFIG_SYS_SDRAM_BASE;
4754204298dSHeiko Schocher 	*size = (gd->ram_size >= 256 << 20 ?
4764204298dSHeiko Schocher 			256 << 20 : gd->ram_size) - (1 << 20);
477ad5bb451SWolfgang Denk 
4789c02defcSYuri Tikhonov 	/* Limit area to be tested with the board info struct */
47928417030SYork Sun 	if ((*vstart) + (*size) > (ulong)bd)
48028417030SYork Sun 		*size = (ulong)bd - *vstart;
481ad5bb451SWolfgang Denk 
48228417030SYork Sun 	return 0;
48328417030SYork Sun }
48428417030SYork Sun 
48528417030SYork Sun __attribute__((weak))
arch_memory_test_advance(u32 * vstart,u32 * size,phys_addr_t * phys_offset)48628417030SYork Sun int arch_memory_test_advance(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
48728417030SYork Sun {
48828417030SYork Sun 	return 1;
48928417030SYork Sun }
49028417030SYork Sun 
49128417030SYork Sun __attribute__((weak))
arch_memory_test_cleanup(u32 * vstart,u32 * size,phys_addr_t * phys_offset)49228417030SYork Sun int arch_memory_test_cleanup(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
49328417030SYork Sun {
49428417030SYork Sun 	return 0;
49528417030SYork Sun }
49628417030SYork Sun 
49728417030SYork Sun __attribute__((weak))
arch_memory_failure_handle(void)49828417030SYork Sun void arch_memory_failure_handle(void)
49928417030SYork Sun {
50028417030SYork Sun 	return;
50128417030SYork Sun }
50228417030SYork Sun 
memory_regions_post_test(int flags)5038d3fcb5eSValentin Longchamp int memory_regions_post_test(int flags)
5048d3fcb5eSValentin Longchamp {
5058d3fcb5eSValentin Longchamp 	int ret = 0;
5068d3fcb5eSValentin Longchamp 	phys_addr_t phys_offset = 0;
5078d3fcb5eSValentin Longchamp 	u32 memsize, vstart;
5088d3fcb5eSValentin Longchamp 
5098d3fcb5eSValentin Longchamp 	arch_memory_test_prepare(&vstart, &memsize, &phys_offset);
5108d3fcb5eSValentin Longchamp 
5118d3fcb5eSValentin Longchamp 	ret = memory_post_test_lines(vstart, memsize);
5128d3fcb5eSValentin Longchamp 	if (!ret)
5138d3fcb5eSValentin Longchamp 		ret = memory_post_test_regions(vstart, memsize);
5148d3fcb5eSValentin Longchamp 
5158d3fcb5eSValentin Longchamp 	return ret;
5168d3fcb5eSValentin Longchamp }
5178d3fcb5eSValentin Longchamp 
memory_post_test(int flags)51828417030SYork Sun int memory_post_test(int flags)
51928417030SYork Sun {
52028417030SYork Sun 	int ret = 0;
52128417030SYork Sun 	phys_addr_t phys_offset = 0;
52228417030SYork Sun 	u32 memsize, vstart;
52328417030SYork Sun 
52428417030SYork Sun 	arch_memory_test_prepare(&vstart, &memsize, &phys_offset);
52528417030SYork Sun 
52628417030SYork Sun 	do {
527ad5bb451SWolfgang Denk 		if (flags & POST_SLOWTEST) {
52828417030SYork Sun 			ret = memory_post_tests(vstart, memsize);
529ad5bb451SWolfgang Denk 		} else {			/* POST_NORMAL */
5308d3fcb5eSValentin Longchamp 			ret = memory_post_test_regions(vstart, memsize);
531ad5bb451SWolfgang Denk 		}
53228417030SYork Sun 	} while (!ret &&
53328417030SYork Sun 		!arch_memory_test_advance(&vstart, &memsize, &phys_offset));
53428417030SYork Sun 
53528417030SYork Sun 	arch_memory_test_cleanup(&vstart, &memsize, &phys_offset);
53628417030SYork Sun 	if (ret)
53728417030SYork Sun 		arch_memory_failure_handle();
538ad5bb451SWolfgang Denk 
539ad5bb451SWolfgang Denk 	return ret;
540ad5bb451SWolfgang Denk }
541ad5bb451SWolfgang Denk 
5428d3fcb5eSValentin Longchamp #endif /* CONFIG_POST&(CONFIG_SYS_POST_MEMORY|CONFIG_SYS_POST_MEM_REGIONS) */
543