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