blob: 90e82acda7a57e2a83ce91babd8a9e2f86a536d4 [file] [log] [blame]
Patrick Delaunay0d447522019-04-10 14:09:28 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4 */
5#include <common.h>
6#include <console.h>
Simon Glass9b4a2052019-12-28 10:45:05 -07007#include <init.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06008#include <log.h>
Simon Glass90526e92020-05-10 11:39:56 -06009#include <rand.h>
Patrick Delaunay25331ae2019-07-30 19:16:51 +020010#include <watchdog.h>
Patrick Delaunay0d447522019-04-10 14:09:28 +020011#include <asm/io.h>
12#include <linux/log2.h>
13#include "stm32mp1_tests.h"
14
15#define ADDR_INVALID 0xFFFFFFFF
16
17DECLARE_GLOBAL_DATA_PTR;
18
19static int get_bufsize(char *string, int argc, char *argv[], int arg_nb,
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +020020 size_t *bufsize, size_t default_size, size_t min_size)
Patrick Delaunay0d447522019-04-10 14:09:28 +020021{
22 unsigned long value;
23
24 if (argc > arg_nb) {
25 if (strict_strtoul(argv[arg_nb], 0, &value) < 0) {
26 sprintf(string, "invalid %d parameter %s",
27 arg_nb, argv[arg_nb]);
28 return -1;
29 }
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +020030 if (value > STM32_DDR_SIZE || value < min_size) {
31 sprintf(string, "invalid size %s (min=%d)",
32 argv[arg_nb], min_size);
Patrick Delaunay0d447522019-04-10 14:09:28 +020033 return -1;
34 }
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +020035 if (value & (min_size - 1)) {
36 sprintf(string, "unaligned size %s (min=%d)",
37 argv[arg_nb], min_size);
Patrick Delaunay0d447522019-04-10 14:09:28 +020038 return -1;
39 }
40 *bufsize = value;
41 } else {
42 if (default_size != STM32_DDR_SIZE)
43 *bufsize = default_size;
44 else
45 *bufsize = get_ram_size((long *)STM32_DDR_BASE,
46 STM32_DDR_SIZE);
47 }
48 return 0;
49}
50
51static int get_nb_loop(char *string, int argc, char *argv[], int arg_nb,
52 u32 *nb_loop, u32 default_nb_loop)
53{
54 unsigned long value;
55
56 if (argc > arg_nb) {
57 if (strict_strtoul(argv[arg_nb], 0, &value) < 0) {
58 sprintf(string, "invalid %d parameter %s",
59 arg_nb, argv[arg_nb]);
60 return -1;
61 }
62 if (value == 0)
63 printf("WARNING: infinite loop requested\n");
64 *nb_loop = value;
65 } else {
66 *nb_loop = default_nb_loop;
67 }
68
69 return 0;
70}
71
72static int get_addr(char *string, int argc, char *argv[], int arg_nb,
73 u32 *addr)
74{
75 unsigned long value;
76
77 if (argc > arg_nb) {
78 if (strict_strtoul(argv[arg_nb], 16, &value) < 0) {
79 sprintf(string, "invalid %d parameter %s",
80 arg_nb, argv[arg_nb]);
81 return -1;
82 }
83 if (value < STM32_DDR_BASE) {
84 sprintf(string, "too low address %s", argv[arg_nb]);
85 return -1;
86 }
87 if (value & 0x3 && value != ADDR_INVALID) {
88 sprintf(string, "unaligned address %s",
89 argv[arg_nb]);
90 return -1;
91 }
92 *addr = value;
93 } else {
94 *addr = STM32_DDR_BASE;
95 }
96
97 return 0;
98}
99
100static int get_pattern(char *string, int argc, char *argv[], int arg_nb,
101 u32 *pattern, u32 default_pattern)
102{
103 unsigned long value;
104
105 if (argc > arg_nb) {
106 if (strict_strtoul(argv[arg_nb], 16, &value) < 0) {
107 sprintf(string, "invalid %d parameter %s",
108 arg_nb, argv[arg_nb]);
109 return -1;
110 }
111 *pattern = value;
112 } else {
113 *pattern = default_pattern;
114 }
115
116 return 0;
117}
118
119static u32 check_addr(u32 addr, u32 value)
120{
121 u32 data = readl(addr);
122
123 if (value != data) {
124 printf("0x%08x: 0x%08x <=> 0x%08x", addr, data, value);
125 data = readl(addr);
126 printf("(2nd read: 0x%08x)", data);
127 if (value == data)
128 printf("- read error");
129 else
130 printf("- write error");
131 printf("\n");
132 return -1;
133 }
134 return 0;
135}
136
137static int progress(u32 offset)
138{
139 if (!(offset & 0xFFFFFF)) {
140 putc('.');
141 if (ctrlc()) {
142 printf("\ntest interrupted!\n");
143 return 1;
144 }
145 }
146 return 0;
147}
148
149static int test_loop_end(u32 *loop, u32 nb_loop, u32 progress)
150{
151 (*loop)++;
152 if (nb_loop && *loop >= nb_loop)
153 return 1;
154 if ((*loop) % progress)
155 return 0;
156 /* allow to interrupt the test only for progress step */
157 if (ctrlc()) {
158 printf("test interrupted!\n");
159 return 1;
160 }
161 printf("loop #%d\n", *loop);
Patrick Delaunay25331ae2019-07-30 19:16:51 +0200162 WATCHDOG_RESET();
163
Patrick Delaunay0d447522019-04-10 14:09:28 +0200164 return 0;
165}
166
167/**********************************************************************
168 *
169 * Function: memTestDataBus()
170 *
171 * Description: Test the data bus wiring in a memory region by
172 * performing a walking 1's test at a fixed address
173 * within that region. The address is selected
174 * by the caller.
175 *
176 * Notes:
177 *
178 * Returns: 0 if the test succeeds.
179 * A non-zero result is the first pattern that failed.
180 *
181 **********************************************************************/
182static u32 databus(u32 *address)
183{
184 u32 pattern;
185 u32 read_value;
186
187 /* Perform a walking 1's test at the given address. */
188 for (pattern = 1; pattern != 0; pattern <<= 1) {
189 /* Write the test pattern. */
190 writel(pattern, address);
191
192 /* Read it back (immediately is okay for this test). */
193 read_value = readl(address);
194 debug("%x: %x <=> %x\n",
195 (u32)address, read_value, pattern);
196
197 if (read_value != pattern)
198 return pattern;
199 }
200
201 return 0;
202}
203
204/**********************************************************************
205 *
206 * Function: memTestAddressBus()
207 *
208 * Description: Test the address bus wiring in a memory region by
209 * performing a walking 1's test on the relevant bits
210 * of the address and checking for aliasing. This test
211 * will find single-bit address failures such as stuck
212 * -high, stuck-low, and shorted pins. The base address
213 * and size of the region are selected by the caller.
214 *
215 * Notes: For best results, the selected base address should
216 * have enough LSB 0's to guarantee single address bit
217 * changes. For example, to test a 64-Kbyte region,
218 * select a base address on a 64-Kbyte boundary. Also,
219 * select the region size as a power-of-two--if at all
220 * possible.
221 *
222 * Returns: NULL if the test succeeds.
223 * A non-zero result is the first address at which an
224 * aliasing problem was uncovered. By examining the
225 * contents of memory, it may be possible to gather
226 * additional information about the problem.
227 *
228 **********************************************************************/
229static u32 *addressbus(u32 *address, u32 nb_bytes)
230{
231 u32 mask = (nb_bytes / sizeof(u32) - 1);
232 u32 offset;
233 u32 test_offset;
234 u32 read_value;
235
236 u32 pattern = 0xAAAAAAAA;
237 u32 antipattern = 0x55555555;
238
239 /* Write the default pattern at each of the power-of-two offsets. */
240 for (offset = 1; (offset & mask) != 0; offset <<= 1)
241 writel(pattern, &address[offset]);
242
243 /* Check for address bits stuck high. */
244 test_offset = 0;
245 writel(antipattern, &address[test_offset]);
246
247 for (offset = 1; (offset & mask) != 0; offset <<= 1) {
248 read_value = readl(&address[offset]);
249 debug("%x: %x <=> %x\n",
250 (u32)&address[offset], read_value, pattern);
251 if (read_value != pattern)
252 return &address[offset];
253 }
254
255 writel(pattern, &address[test_offset]);
256
257 /* Check for address bits stuck low or shorted. */
258 for (test_offset = 1; (test_offset & mask) != 0; test_offset <<= 1) {
259 writel(antipattern, &address[test_offset]);
260 if (readl(&address[0]) != pattern)
261 return &address[test_offset];
262
263 for (offset = 1; (offset & mask) != 0; offset <<= 1) {
264 if (readl(&address[offset]) != pattern &&
265 offset != test_offset)
266 return &address[test_offset];
267 }
268 writel(pattern, &address[test_offset]);
269 }
270
271 return NULL;
272}
273
274/**********************************************************************
275 *
276 * Function: memTestDevice()
277 *
278 * Description: Test the integrity of a physical memory device by
279 * performing an increment/decrement test over the
280 * entire region. In the process every storage bit
281 * in the device is tested as a zero and a one. The
282 * base address and the size of the region are
283 * selected by the caller.
284 *
285 * Notes:
286 *
287 * Returns: NULL if the test succeeds.
288 *
289 * A non-zero result is the first address at which an
290 * incorrect value was read back. By examining the
291 * contents of memory, it may be possible to gather
292 * additional information about the problem.
293 *
294 **********************************************************************/
295static u32 *memdevice(u32 *address, u32 nb_bytes)
296{
297 u32 offset;
298 u32 nb_words = nb_bytes / sizeof(u32);
299
300 u32 pattern;
301 u32 antipattern;
302
303 puts("Fill with pattern");
304 /* Fill memory with a known pattern. */
305 for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) {
306 writel(pattern, &address[offset]);
307 if (progress(offset))
308 return NULL;
309 }
310
311 puts("\nCheck and invert pattern");
312 /* Check each location and invert it for the second pass. */
313 for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) {
314 if (readl(&address[offset]) != pattern)
315 return &address[offset];
316
317 antipattern = ~pattern;
318 writel(antipattern, &address[offset]);
319 if (progress(offset))
320 return NULL;
321 }
322
323 puts("\nCheck inverted pattern");
324 /* Check each location for the inverted pattern and zero it. */
325 for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) {
326 antipattern = ~pattern;
327 if (readl(&address[offset]) != antipattern)
328 return &address[offset];
329 if (progress(offset))
330 return NULL;
331 }
332 printf("\n");
333
334 return NULL;
335}
336
337static enum test_result databuswalk0(struct stm32mp1_ddrctl *ctl,
338 struct stm32mp1_ddrphy *phy,
339 char *string, int argc, char *argv[])
340{
341 int i;
342 u32 loop = 0, nb_loop;
343 u32 addr;
344 u32 error = 0;
345 u32 data;
346
347 if (get_nb_loop(string, argc, argv, 0, &nb_loop, 100))
348 return TEST_ERROR;
349 if (get_addr(string, argc, argv, 1, &addr))
350 return TEST_ERROR;
351
352 printf("running %d loops at 0x%x\n", nb_loop, addr);
353 while (!error) {
354 for (i = 0; i < 32; i++)
355 writel(~(1 << i), addr + 4 * i);
356 for (i = 0; i < 32; i++) {
357 data = readl(addr + 4 * i);
358 if (~(1 << i) != data) {
359 error |= 1 << i;
360 debug("%x: error %x expected %x => error:%x\n",
361 addr + 4 * i, data, ~(1 << i), error);
362 }
363 }
364 if (test_loop_end(&loop, nb_loop, 1000))
365 break;
366 for (i = 0; i < 32; i++)
367 writel(0, addr + 4 * i);
368 }
369 if (error) {
370 sprintf(string, "loop %d: error for bits 0x%x",
371 loop, error);
372 return TEST_FAILED;
373 }
374 sprintf(string, "no error for %d loops", loop);
375 return TEST_PASSED;
376}
377
378static enum test_result databuswalk1(struct stm32mp1_ddrctl *ctl,
379 struct stm32mp1_ddrphy *phy,
380 char *string, int argc, char *argv[])
381{
382 int i;
383 u32 loop = 0, nb_loop;
384 u32 addr;
385 u32 error = 0;
386 u32 data;
387
388 if (get_nb_loop(string, argc, argv, 0, &nb_loop, 100))
389 return TEST_ERROR;
390 if (get_addr(string, argc, argv, 1, &addr))
391 return TEST_ERROR;
392 printf("running %d loops at 0x%x\n", nb_loop, addr);
393 while (!error) {
394 for (i = 0; i < 32; i++)
395 writel(1 << i, addr + 4 * i);
396 for (i = 0; i < 32; i++) {
397 data = readl(addr + 4 * i);
398 if ((1 << i) != data) {
399 error |= 1 << i;
400 debug("%x: error %x expected %x => error:%x\n",
401 addr + 4 * i, data, (1 << i), error);
402 }
403 }
404 if (test_loop_end(&loop, nb_loop, 1000))
405 break;
406 for (i = 0; i < 32; i++)
407 writel(0, addr + 4 * i);
408 }
409 if (error) {
410 sprintf(string, "loop %d: error for bits 0x%x",
411 loop, error);
412 return TEST_FAILED;
413 }
414 sprintf(string, "no error for %d loops", loop);
415 return TEST_PASSED;
416}
417
418static enum test_result test_databus(struct stm32mp1_ddrctl *ctl,
419 struct stm32mp1_ddrphy *phy,
420 char *string, int argc, char *argv[])
421{
422 u32 addr;
423 u32 error;
424
425 if (get_addr(string, argc, argv, 0, &addr))
426 return TEST_ERROR;
427 error = databus((u32 *)addr);
428 if (error) {
429 sprintf(string, "0x%x: error for bits 0x%x",
430 addr, error);
431 return TEST_FAILED;
432 }
433 sprintf(string, "address 0x%x", addr);
434 return TEST_PASSED;
435}
436
437static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl,
438 struct stm32mp1_ddrphy *phy,
439 char *string, int argc, char *argv[])
440{
441 u32 addr;
442 u32 bufsize;
443 u32 error;
444
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +0200445 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
Patrick Delaunay0d447522019-04-10 14:09:28 +0200446 return TEST_ERROR;
447 if (!is_power_of_2(bufsize)) {
448 sprintf(string, "size 0x%x is not a power of 2",
449 (u32)bufsize);
450 return TEST_ERROR;
451 }
452 if (get_addr(string, argc, argv, 1, &addr))
453 return TEST_ERROR;
454
455 error = (u32)addressbus((u32 *)addr, bufsize);
456 if (error) {
457 sprintf(string, "0x%x: error for address 0x%x",
458 addr, error);
459 return TEST_FAILED;
460 }
461 sprintf(string, "address 0x%x, size 0x%x",
462 addr, bufsize);
463 return TEST_PASSED;
464}
465
466static enum test_result test_memdevice(struct stm32mp1_ddrctl *ctl,
467 struct stm32mp1_ddrphy *phy,
468 char *string, int argc, char *argv[])
469{
470 u32 addr;
471 size_t bufsize;
472 u32 error;
473
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +0200474 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
Patrick Delaunay0d447522019-04-10 14:09:28 +0200475 return TEST_ERROR;
476 if (get_addr(string, argc, argv, 1, &addr))
477 return TEST_ERROR;
478 error = (u32)memdevice((u32 *)addr, (unsigned long)bufsize);
479 if (error) {
480 sprintf(string, "0x%x: error for address 0x%x",
481 addr, error);
482 return TEST_FAILED;
483 }
484 sprintf(string, "address 0x%x, size 0x%x",
485 addr, bufsize);
486 return TEST_PASSED;
487}
488
489/**********************************************************************
490 *
491 * Function: sso
492 *
493 * Description: Test the Simultaneous Switching Output.
494 * Verifies succes sive reads and writes to the same memory word,
495 * holding one bit constant while toggling all other data bits
496 * simultaneously
497 * => stress the data bus over an address range
498 *
499 * The CPU writes to each address in the given range.
500 * For each bit, first the CPU holds the bit at 1 while
501 * toggling the other bits, and then the CPU holds the bit at 0
502 * while toggling the other bits.
503 * After each write, the CPU reads the address that was written
504 * to verify that it contains the correct data
505 *
506 **********************************************************************/
507static enum test_result test_sso(struct stm32mp1_ddrctl *ctl,
508 struct stm32mp1_ddrphy *phy,
509 char *string, int argc, char *argv[])
510{
511 int i, j;
512 u32 addr, bufsize, remaining, offset;
513 u32 error = 0;
514 u32 data;
515
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +0200516 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
Patrick Delaunay0d447522019-04-10 14:09:28 +0200517 return TEST_ERROR;
518 if (get_addr(string, argc, argv, 1, &addr))
519 return TEST_ERROR;
520
521 printf("running sso at 0x%x length 0x%x", addr, bufsize);
522 offset = addr;
523 remaining = bufsize;
524 while (remaining) {
525 for (i = 0; i < 32; i++) {
526 /* write pattern. */
527 for (j = 0; j < 6; j++) {
528 switch (j) {
529 case 0:
530 case 2:
531 data = 1 << i;
532 break;
533 case 3:
534 case 5:
535 data = ~(1 << i);
536 break;
537 case 1:
538 data = ~0x0;
539 break;
540 case 4:
541 data = 0x0;
542 break;
543 }
544
545 writel(data, offset);
546 error = check_addr(offset, data);
547 if (error)
548 goto end;
549 }
550 }
551 offset += 4;
552 remaining -= 4;
553 if (progress(offset << 7))
554 goto end;
555 }
556 puts("\n");
557
558end:
559 if (error) {
560 sprintf(string, "error for pattern 0x%x @0x%x",
561 data, offset);
562 return TEST_FAILED;
563 }
564 sprintf(string, "no error for sso at 0x%x length 0x%x", addr, bufsize);
565 return TEST_PASSED;
566}
567
568/**********************************************************************
569 *
570 * Function: Random
571 *
572 * Description: Verifies r/w with pseudo-ramdom value on one region
573 * + write the region (individual access)
574 * + memcopy to the 2nd region (try to use burst)
575 * + verify the 2 regions
576 *
577 **********************************************************************/
578static enum test_result test_random(struct stm32mp1_ddrctl *ctl,
579 struct stm32mp1_ddrphy *phy,
580 char *string, int argc, char *argv[])
581{
582 u32 addr, offset, value = 0;
583 size_t bufsize;
584 u32 loop = 0, nb_loop;
585 u32 error = 0;
586 unsigned int seed;
587
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +0200588 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 8))
Patrick Delaunay0d447522019-04-10 14:09:28 +0200589 return TEST_ERROR;
590 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
591 return TEST_ERROR;
592 if (get_addr(string, argc, argv, 2, &addr))
593 return TEST_ERROR;
594
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200595 bufsize /= 2;
596 printf("running %d loops copy from 0x%x to 0x%x (buffer size=0x%x)\n",
597 nb_loop, addr, addr + bufsize, bufsize);
Patrick Delaunay0d447522019-04-10 14:09:28 +0200598 while (!error) {
599 seed = rand();
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200600 for (offset = 0; offset < bufsize; offset += 4)
601 writel(rand(), addr + offset);
Patrick Delaunay0d447522019-04-10 14:09:28 +0200602
603 memcpy((void *)addr + bufsize, (void *)addr, bufsize);
604
605 srand(seed);
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200606 for (offset = 0; offset < 2 * bufsize; offset += 4) {
607 if (offset == bufsize)
Patrick Delaunay0d447522019-04-10 14:09:28 +0200608 srand(seed);
609 value = rand();
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200610 error = check_addr(addr + offset, value);
Patrick Delaunay0d447522019-04-10 14:09:28 +0200611 if (error)
612 break;
613 if (progress(offset))
614 return TEST_FAILED;
615 }
616 if (test_loop_end(&loop, nb_loop, 100))
617 break;
618 }
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200619 putc('\n');
Patrick Delaunay0d447522019-04-10 14:09:28 +0200620
621 if (error) {
622 sprintf(string,
623 "loop %d: error for address 0x%x: 0x%x expected 0x%x",
624 loop, offset, readl(offset), value);
625 return TEST_FAILED;
626 }
627 sprintf(string, "no error for %d loops, size 0x%x",
628 loop, bufsize);
629 return TEST_PASSED;
630}
631
632/**********************************************************************
633 *
634 * Function: noise
635 *
636 * Description: Verifies r/w while forcing switching of all data bus lines.
637 * optimised 4 iteration write/read/write/read cycles...
638 * for pattern and inversed pattern
639 *
640 **********************************************************************/
641void do_noise(u32 addr, u32 pattern, u32 *result)
642{
643 __asm__("push {R0-R11}");
644 __asm__("mov r0, %0" : : "r" (addr));
645 __asm__("mov r1, %0" : : "r" (pattern));
646 __asm__("mov r11, %0" : : "r" (result));
647
648 __asm__("mvn r2, r1");
649
650 __asm__("str r1, [r0]");
651 __asm__("ldr r3, [r0]");
652 __asm__("str r2, [r0]");
653 __asm__("ldr r4, [r0]");
654
655 __asm__("str r1, [r0]");
656 __asm__("ldr r5, [r0]");
657 __asm__("str r2, [r0]");
658 __asm__("ldr r6, [r0]");
659
660 __asm__("str r1, [r0]");
661 __asm__("ldr r7, [r0]");
662 __asm__("str r2, [r0]");
663 __asm__("ldr r8, [r0]");
664
665 __asm__("str r1, [r0]");
666 __asm__("ldr r9, [r0]");
667 __asm__("str r2, [r0]");
668 __asm__("ldr r10, [r0]");
669
670 __asm__("stmia R11!, {R3-R10}");
671
672 __asm__("pop {R0-R11}");
673}
674
675static enum test_result test_noise(struct stm32mp1_ddrctl *ctl,
676 struct stm32mp1_ddrphy *phy,
677 char *string, int argc, char *argv[])
678{
679 u32 addr, pattern;
680 u32 result[8];
681 int i;
682 enum test_result res = TEST_PASSED;
683
684 if (get_pattern(string, argc, argv, 0, &pattern, 0xFFFFFFFF))
685 return TEST_ERROR;
686 if (get_addr(string, argc, argv, 1, &addr))
687 return TEST_ERROR;
688
689 printf("running noise for 0x%x at 0x%x\n", pattern, addr);
690
691 do_noise(addr, pattern, result);
692
693 for (i = 0; i < 0x8;) {
694 if (check_addr((u32)&result[i++], pattern))
695 res = TEST_FAILED;
696 if (check_addr((u32)&result[i++], ~pattern))
697 res = TEST_FAILED;
698 }
699
700 return res;
701}
702
703/**********************************************************************
704 *
705 * Function: noise_burst
706 *
707 * Description: Verifies r/w while forcing switching of all data bus lines.
708 * optimised write loop witrh store multiple to use burst
709 * for pattern and inversed pattern
710 *
711 **********************************************************************/
712void do_noise_burst(u32 addr, u32 pattern, size_t bufsize)
713{
714 __asm__("push {R0-R9}");
715 __asm__("mov r0, %0" : : "r" (addr));
716 __asm__("mov r1, %0" : : "r" (pattern));
717 __asm__("mov r9, %0" : : "r" (bufsize));
718
719 __asm__("mvn r2, r1");
720 __asm__("mov r3, r1");
721 __asm__("mov r4, r2");
722 __asm__("mov r5, r1");
723 __asm__("mov r6, r2");
724 __asm__("mov r7, r1");
725 __asm__("mov r8, r2");
726
727 __asm__("loop1:");
728 __asm__("stmia R0!, {R1-R8}");
729 __asm__("stmia R0!, {R1-R8}");
730 __asm__("stmia R0!, {R1-R8}");
731 __asm__("stmia R0!, {R1-R8}");
732 __asm__("subs r9, r9, #128");
733 __asm__("bge loop1");
734 __asm__("pop {R0-R9}");
735}
736
737/* chunk size enough to allow interruption with Ctrl-C*/
738#define CHUNK_SIZE 0x8000000
739static enum test_result test_noise_burst(struct stm32mp1_ddrctl *ctl,
740 struct stm32mp1_ddrphy *phy,
741 char *string, int argc, char *argv[])
742{
743 u32 addr, offset, pattern;
744 size_t bufsize, remaining, size;
745 int i;
746 enum test_result res = TEST_PASSED;
747
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +0200748 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128))
Patrick Delaunay0d447522019-04-10 14:09:28 +0200749 return TEST_ERROR;
750 if (get_pattern(string, argc, argv, 1, &pattern, 0xFFFFFFFF))
751 return TEST_ERROR;
752 if (get_addr(string, argc, argv, 2, &addr))
753 return TEST_ERROR;
754
755 printf("running noise burst for 0x%x at 0x%x + 0x%x",
756 pattern, addr, bufsize);
757
758 offset = addr;
759 remaining = bufsize;
760 size = CHUNK_SIZE;
761 while (remaining) {
762 if (remaining < size)
763 size = remaining;
764 do_noise_burst(offset, pattern, size);
765 remaining -= size;
766 offset += size;
767 if (progress(offset)) {
768 res = TEST_FAILED;
769 goto end;
770 }
771 }
772 puts("\ncheck buffer");
773 for (i = 0; i < bufsize;) {
774 if (check_addr(addr + i, pattern))
775 res = TEST_FAILED;
776 i += 4;
777 if (check_addr(addr + i, ~pattern))
778 res = TEST_FAILED;
779 i += 4;
780 if (progress(i)) {
781 res = TEST_FAILED;
782 goto end;
783 }
784 }
785end:
786 puts("\n");
787 return res;
788}
789
790/**********************************************************************
791 *
792 * Function: pattern test
793 *
794 * Description: optimized loop for read/write pattern (array of 8 u32)
795 *
796 **********************************************************************/
797#define PATTERN_SIZE 8
798static enum test_result test_loop(const u32 *pattern, u32 *address,
799 const u32 bufsize)
800{
801 int i;
802 int j;
803 enum test_result res = TEST_PASSED;
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200804 u32 offset, testsize, remaining;
Patrick Delaunay0d447522019-04-10 14:09:28 +0200805
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200806 offset = (u32)address;
Patrick Delaunay0d447522019-04-10 14:09:28 +0200807 remaining = bufsize;
808 while (remaining) {
809 testsize = bufsize > 0x1000000 ? 0x1000000 : bufsize;
810
811 __asm__("push {R0-R10}");
812 __asm__("mov r0, %0" : : "r" (pattern));
813 __asm__("mov r1, %0" : : "r" (offset));
814 __asm__("mov r2, %0" : : "r" (testsize));
815 __asm__("ldmia r0!, {R3-R10}");
816
817 __asm__("loop2:");
818 __asm__("stmia r1!, {R3-R10}");
819 __asm__("stmia r1!, {R3-R10}");
820 __asm__("stmia r1!, {R3-R10}");
821 __asm__("stmia r1!, {R3-R10}");
Patrick Delaunay4b0496f2019-07-30 19:16:49 +0200822 __asm__("subs r2, r2, #128");
Patrick Delaunay0d447522019-04-10 14:09:28 +0200823 __asm__("bge loop2");
824 __asm__("pop {R0-R10}");
825
826 offset += testsize;
827 remaining -= testsize;
828 if (progress((u32)offset)) {
829 res = TEST_FAILED;
830 goto end;
831 }
832 }
833
834 puts("\ncheck buffer");
835 for (i = 0; i < bufsize; i += PATTERN_SIZE * 4) {
836 for (j = 0; j < PATTERN_SIZE; j++, address++)
837 if (check_addr((u32)address, pattern[j])) {
838 res = TEST_FAILED;
839 goto end;
840 }
841 if (progress(i)) {
842 res = TEST_FAILED;
843 goto end;
844 }
845 }
846
847end:
848 puts("\n");
849 return res;
850}
851
852const u32 pattern_div1_x16[PATTERN_SIZE] = {
853 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,
854 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF
855};
856
857const u32 pattern_div2_x16[PATTERN_SIZE] = {
858 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
859 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000
860};
861
862const u32 pattern_div4_x16[PATTERN_SIZE] = {
863 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
864 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000
865};
866
867const u32 pattern_div4_x32[PATTERN_SIZE] = {
868 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
869 0x00000000, 0x00000000, 0x00000000, 0x00000000
870};
871
872const u32 pattern_mostly_zero_x16[PATTERN_SIZE] = {
873 0x00000000, 0x00000000, 0x00000000, 0x0000FFFF,
874 0x00000000, 0x00000000, 0x00000000, 0x00000000
875};
876
877const u32 pattern_mostly_zero_x32[PATTERN_SIZE] = {
878 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,
879 0x00000000, 0x00000000, 0x00000000, 0x00000000
880};
881
882const u32 pattern_mostly_one_x16[PATTERN_SIZE] = {
883 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF,
884 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
885};
886
887const u32 pattern_mostly_one_x32[PATTERN_SIZE] = {
888 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
889 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
890};
891
892#define NB_PATTERN 5
893static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl,
894 struct stm32mp1_ddrphy *phy,
895 char *string, int argc, char *argv[])
896{
897 const u32 * const patterns_x16[NB_PATTERN] = {
898 pattern_div1_x16,
899 pattern_div2_x16,
900 pattern_div4_x16,
901 pattern_mostly_zero_x16,
902 pattern_mostly_one_x16,
903 };
904 const u32 * const patterns_x32[NB_PATTERN] = {
905 pattern_div2_x16,
906 pattern_div4_x16,
907 pattern_div4_x32,
908 pattern_mostly_zero_x32,
909 pattern_mostly_one_x32
910 };
911 const char *patterns_comments[NB_PATTERN] = {
912 "switching at frequency F/1",
913 "switching at frequency F/2",
914 "switching at frequency F/4",
915 "mostly zero",
916 "mostly one"
917 };
918
919 enum test_result res = TEST_PASSED, pattern_res;
920 int i, bus_width;
921 const u32 **patterns;
922 u32 bufsize;
923
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +0200924 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 128))
Patrick Delaunay0d447522019-04-10 14:09:28 +0200925 return TEST_ERROR;
926
927 switch (readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) {
928 case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
929 case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
930 bus_width = 16;
931 break;
932 default:
933 bus_width = 32;
934 break;
935 }
936
937 printf("running test pattern at 0x%08x length 0x%x width = %d\n",
938 STM32_DDR_BASE, bufsize, bus_width);
939
940 patterns =
941 (const u32 **)(bus_width == 16 ? patterns_x16 : patterns_x32);
942
943 for (i = 0; i < NB_PATTERN; i++) {
944 printf("test data pattern %s:", patterns_comments[i]);
945 pattern_res = test_loop(patterns[i], (u32 *)STM32_DDR_BASE,
946 bufsize);
947 if (pattern_res != TEST_PASSED) {
948 printf("Failed\n");
949 return pattern_res;
950 }
951 printf("Passed\n");
952 }
953
954 return res;
955}
956
957/**********************************************************************
958 *
959 * Function: pattern test with size
960 *
961 * Description: loop for write pattern
962 *
963 **********************************************************************/
964
965static enum test_result test_loop_size(const u32 *pattern, u32 size,
966 u32 *address,
967 const u32 bufsize)
968{
969 int i, j;
970 enum test_result res = TEST_PASSED;
971 u32 *p = address;
972
973 for (i = 0; i < bufsize; i += size * 4) {
974 for (j = 0; j < size ; j++, p++)
975 *p = pattern[j];
976 if (progress(i)) {
977 res = TEST_FAILED;
978 goto end;
979 }
980 }
981
982 puts("\ncheck buffer");
983 p = address;
984 for (i = 0; i < bufsize; i += size * 4) {
985 for (j = 0; j < size; j++, p++)
986 if (check_addr((u32)p, pattern[j])) {
987 res = TEST_FAILED;
988 goto end;
989 }
990 if (progress(i)) {
991 res = TEST_FAILED;
992 goto end;
993 }
994 }
995
996end:
997 puts("\n");
998 return res;
999}
1000
1001static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl,
1002 struct stm32mp1_ddrphy *phy,
1003 char *string, int argc, char *argv[])
1004{
1005 enum test_result res = TEST_PASSED;
1006 u32 bufsize, nb_loop, loop = 0, addr;
1007 int i;
1008
1009 u32 checkboard[2] = {0x55555555, 0xAAAAAAAA};
1010
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +02001011 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 8))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001012 return TEST_ERROR;
1013 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
1014 return TEST_ERROR;
1015 if (get_addr(string, argc, argv, 2, &addr))
1016 return TEST_ERROR;
1017
1018 printf("running %d loops at 0x%08x length 0x%x\n",
1019 nb_loop, addr, bufsize);
1020 while (1) {
1021 for (i = 0; i < 2; i++) {
1022 res = test_loop_size(checkboard, 2, (u32 *)addr,
1023 bufsize);
1024 if (res)
1025 return res;
1026 checkboard[0] = ~checkboard[0];
1027 checkboard[1] = ~checkboard[1];
1028 }
1029 if (test_loop_end(&loop, nb_loop, 1))
1030 break;
1031 }
1032 sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
1033 loop, addr, bufsize);
1034
1035 return res;
1036}
1037
1038static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl,
1039 struct stm32mp1_ddrphy *phy,
1040 char *string, int argc, char *argv[])
1041{
1042 enum test_result res = TEST_PASSED;
1043 u32 bufsize, nb_loop, loop = 0, addr, value;
1044 int i;
1045
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +02001046 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001047 return TEST_ERROR;
1048 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
1049 return TEST_ERROR;
1050 if (get_addr(string, argc, argv, 2, &addr))
1051 return TEST_ERROR;
1052
1053 printf("running %d loops at 0x%08x length 0x%x\n",
1054 nb_loop, addr, bufsize);
1055 while (1) {
1056 for (i = 0; i < 256; i++) {
1057 value = i | i << 8 | i << 16 | i << 24;
1058 printf("pattern = %08x", value);
1059 res = test_loop_size(&value, 1, (u32 *)addr, bufsize);
1060 if (res != TEST_PASSED)
1061 return res;
1062 }
1063 if (test_loop_end(&loop, nb_loop, 1))
1064 break;
1065 }
1066 sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
1067 loop, addr, bufsize);
1068
1069 return res;
1070}
1071
1072static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl,
1073 struct stm32mp1_ddrphy *phy,
1074 char *string, int argc, char *argv[])
1075{
1076 enum test_result res = TEST_PASSED;
1077 u32 bufsize, nb_loop, loop = 0, addr, value;
1078 int i;
1079
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +02001080 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001081 return TEST_ERROR;
1082 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
1083 return TEST_ERROR;
1084 if (get_addr(string, argc, argv, 2, &addr))
1085 return TEST_ERROR;
1086
1087 printf("running %d loops at 0x%08x length 0x%x\n",
1088 nb_loop, addr, bufsize);
1089 while (1) {
1090 for (i = 0; i < 64; i++) {
1091 if (i < 32)
1092 value = 1 << i;
1093 else
1094 value = 1 << (63 - i);
1095
1096 printf("pattern = %08x", value);
1097 res = test_loop_size(&value, 1, (u32 *)addr, bufsize);
1098 if (res != TEST_PASSED)
1099 return res;
1100 }
1101 if (test_loop_end(&loop, nb_loop, 1))
1102 break;
1103 }
1104 sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
1105 loop, addr, bufsize);
1106
1107 return res;
1108}
1109
1110static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl,
1111 struct stm32mp1_ddrphy *phy,
1112 char *string, int argc, char *argv[])
1113{
1114 enum test_result res = TEST_PASSED;
1115 u32 bufsize, nb_loop, loop = 0, addr, value;
1116 int i;
1117
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +02001118 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 4))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001119 return TEST_ERROR;
1120 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
1121 return TEST_ERROR;
1122 if (get_addr(string, argc, argv, 2, &addr))
1123 return TEST_ERROR;
1124
1125 printf("running %d loops at 0x%08x length 0x%x\n",
1126 nb_loop, addr, bufsize);
1127 while (1) {
1128 for (i = 0; i < 64; i++) {
1129 if (i < 32)
1130 value = ~(1 << i);
1131 else
1132 value = ~(1 << (63 - i));
1133
1134 printf("pattern = %08x", value);
1135 res = test_loop_size(&value, 1, (u32 *)addr, bufsize);
1136 if (res != TEST_PASSED)
1137 return res;
1138 }
1139 if (test_loop_end(&loop, nb_loop, 1))
1140 break;
1141 }
1142 sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
1143 loop, addr, bufsize);
1144
1145 return res;
1146}
1147
1148/*
1149 * try to catch bad bits which are dependent on the current values of
1150 * surrounding bits in either the same word32
1151 */
1152static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl,
1153 struct stm32mp1_ddrphy *phy,
1154 char *string, int argc, char *argv[])
1155{
1156 enum test_result res = TEST_PASSED;
1157 u32 bufsize, nb_loop, loop = 0, addr, bitspread[4];
1158 int i, j;
1159
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +02001160 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 32))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001161 return TEST_ERROR;
1162 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
1163 return TEST_ERROR;
1164 if (get_addr(string, argc, argv, 2, &addr))
1165 return TEST_ERROR;
1166
1167 printf("running %d loops at 0x%08x length 0x%x\n",
1168 nb_loop, addr, bufsize);
1169 while (1) {
1170 for (i = 1; i < 32; i++) {
1171 for (j = 0; j < i; j++) {
1172 if (i < 32)
1173 bitspread[0] = (1 << i) | (1 << j);
1174 else
1175 bitspread[0] = (1 << (63 - i)) |
1176 (1 << (63 - j));
1177 bitspread[1] = bitspread[0];
1178 bitspread[2] = ~bitspread[0];
1179 bitspread[3] = ~bitspread[0];
1180 printf("pattern = %08x", bitspread[0]);
1181
1182 res = test_loop_size(bitspread, 4, (u32 *)addr,
1183 bufsize);
1184 if (res != TEST_PASSED)
1185 return res;
1186 }
1187 }
1188 if (test_loop_end(&loop, nb_loop, 1))
1189 break;
1190 }
1191 sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
1192 loop, addr, bufsize);
1193
1194 return res;
1195}
1196
1197static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl,
1198 struct stm32mp1_ddrphy *phy,
1199 char *string, int argc, char *argv[])
1200{
1201 enum test_result res = TEST_PASSED;
1202 u32 bufsize, nb_loop, loop = 0, addr;
1203 int i;
1204
1205 u32 bitflip[4];
1206
Patrick Delaunay1a5be5a2020-07-02 19:56:34 +02001207 if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024, 32))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001208 return TEST_ERROR;
1209 if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
1210 return TEST_ERROR;
1211 if (get_addr(string, argc, argv, 2, &addr))
1212 return TEST_ERROR;
1213
1214 printf("running %d loops at 0x%08x length 0x%x\n",
1215 nb_loop, addr, bufsize);
1216 while (1) {
1217 for (i = 0; i < 32; i++) {
1218 bitflip[0] = 1 << i;
1219 bitflip[1] = bitflip[0];
1220 bitflip[2] = ~bitflip[0];
1221 bitflip[3] = bitflip[2];
1222 printf("pattern = %08x", bitflip[0]);
1223
1224 res = test_loop_size(bitflip, 4, (u32 *)addr, bufsize);
1225 if (res != TEST_PASSED)
1226 return res;
1227 }
1228 if (test_loop_end(&loop, nb_loop, 1))
1229 break;
1230 }
1231 sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
1232 loop, addr, bufsize);
1233
1234 return res;
1235}
1236
1237/**********************************************************************
1238 *
1239 * Function: infinite read access to DDR
1240 *
1241 * Description: continuous read the same pattern at the same address
1242 *
1243 **********************************************************************/
1244static enum test_result test_read(struct stm32mp1_ddrctl *ctl,
1245 struct stm32mp1_ddrphy *phy,
1246 char *string, int argc, char *argv[])
1247{
1248 u32 *addr;
1249 u32 data;
1250 u32 loop = 0;
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001251 int i, size = 1024 * 1024;
Patrick Delaunay0d447522019-04-10 14:09:28 +02001252 bool random = false;
1253
1254 if (get_addr(string, argc, argv, 0, (u32 *)&addr))
1255 return TEST_ERROR;
1256
Patrick Delaunay757bca82019-07-30 19:16:52 +02001257 if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55))
1258 return TEST_ERROR;
Patrick Delaunay0d447522019-04-10 14:09:28 +02001259
Patrick Delaunay757bca82019-07-30 19:16:52 +02001260 if ((u32)addr == ADDR_INVALID) {
1261 printf("running random\n");
1262 random = true;
1263 } else {
1264 printf("running at 0x%08x with pattern=0x%08x\n",
1265 (u32)addr, data);
1266 writel(data, addr);
1267 }
Patrick Delaunay0d447522019-04-10 14:09:28 +02001268
1269 while (1) {
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001270 for (i = 0; i < size; i++) {
1271 if (random)
1272 addr = (u32 *)(STM32_DDR_BASE +
1273 (rand() & (STM32_DDR_SIZE - 1) & ~0x3));
1274 data = readl(addr);
1275 }
1276 if (test_loop_end(&loop, 0, 1))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001277 break;
1278 }
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001279 if (random)
1280 sprintf(string, "%d loops random", loop);
1281 else
1282 sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data);
Patrick Delaunay0d447522019-04-10 14:09:28 +02001283
1284 return TEST_PASSED;
1285}
1286
1287/**********************************************************************
1288 *
1289 * Function: infinite write access to DDR
1290 *
1291 * Description: continuous write the same pattern at the same address
1292 *
1293 **********************************************************************/
1294static enum test_result test_write(struct stm32mp1_ddrctl *ctl,
1295 struct stm32mp1_ddrphy *phy,
1296 char *string, int argc, char *argv[])
1297{
1298 u32 *addr;
Patrick Delaunay757bca82019-07-30 19:16:52 +02001299 u32 data;
Patrick Delaunay0d447522019-04-10 14:09:28 +02001300 u32 loop = 0;
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001301 int i, size = 1024 * 1024;
Patrick Delaunay0d447522019-04-10 14:09:28 +02001302 bool random = false;
1303
1304 if (get_addr(string, argc, argv, 0, (u32 *)&addr))
1305 return TEST_ERROR;
1306
Patrick Delaunay757bca82019-07-30 19:16:52 +02001307 if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55))
1308 return TEST_ERROR;
Patrick Delaunay0d447522019-04-10 14:09:28 +02001309
Patrick Delaunay757bca82019-07-30 19:16:52 +02001310 if ((u32)addr == ADDR_INVALID) {
1311 printf("running random\n");
1312 random = true;
1313 } else {
1314 printf("running at 0x%08x with pattern 0x%08x\n",
1315 (u32)addr, data);
1316 }
Patrick Delaunay0d447522019-04-10 14:09:28 +02001317
1318 while (1) {
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001319 for (i = 0; i < size; i++) {
1320 if (random) {
1321 addr = (u32 *)(STM32_DDR_BASE +
1322 (rand() & (STM32_DDR_SIZE - 1) & ~0x3));
1323 data = rand();
1324 }
1325 writel(data, addr);
Patrick Delaunay0d447522019-04-10 14:09:28 +02001326 }
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001327 if (test_loop_end(&loop, 0, 1))
Patrick Delaunay0d447522019-04-10 14:09:28 +02001328 break;
1329 }
Patrick Delaunay37f41ae2019-07-30 19:16:50 +02001330 if (random)
1331 sprintf(string, "%d loops random", loop);
1332 else
1333 sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data);
Patrick Delaunay0d447522019-04-10 14:09:28 +02001334
1335 return TEST_PASSED;
1336}
1337
1338#define NB_TEST_INFINITE 2
1339static enum test_result test_all(struct stm32mp1_ddrctl *ctl,
1340 struct stm32mp1_ddrphy *phy,
1341 char *string, int argc, char *argv[])
1342{
1343 enum test_result res = TEST_PASSED, result;
1344 int i, nb_error = 0;
1345 u32 loop = 0, nb_loop;
1346
1347 if (get_nb_loop(string, argc, argv, 0, &nb_loop, 1))
1348 return TEST_ERROR;
1349
1350 while (!nb_error) {
1351 /* execute all the test except the lasts which are infinite */
1352 for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) {
1353 printf("execute %d:%s\n", (int)i, test[i].name);
1354 result = test[i].fct(ctl, phy, string, 0, NULL);
1355 printf("result %d:%s = ", (int)i, test[i].name);
1356 if (result != TEST_PASSED) {
1357 nb_error++;
1358 res = TEST_FAILED;
1359 puts("Failed");
1360 } else {
1361 puts("Passed");
1362 }
1363 puts("\n\n");
1364 }
1365 printf("loop %d: %d/%d test failed\n\n\n",
1366 loop + 1, nb_error, test_nb - NB_TEST_INFINITE);
1367 if (test_loop_end(&loop, nb_loop, 1))
1368 break;
1369 }
1370 if (res != TEST_PASSED) {
1371 sprintf(string, "loop %d: %d/%d test failed", loop, nb_error,
1372 test_nb - NB_TEST_INFINITE);
1373 } else {
1374 sprintf(string, "loop %d: %d tests passed", loop,
1375 test_nb - NB_TEST_INFINITE);
1376 }
1377 return res;
1378}
1379
1380/****************************************************************
1381 * TEST Description
1382 ****************************************************************/
1383
1384const struct test_desc test[] = {
1385 {test_all, "All", "[loop]", "Execute all tests", 1 },
1386 {test_databus, "Simple DataBus", "[addr]",
1387 "Verifies each data line by walking 1 on fixed address",
1388 1
1389 },
1390 {databuswalk0, "DataBusWalking0", "[loop] [addr]",
1391 "Verifies each data bus signal can be driven low (32 word burst)",
1392 2
1393 },
1394 {databuswalk1, "DataBusWalking1", "[loop] [addr]",
1395 "Verifies each data bus signal can be driven high (32 word burst)",
1396 2
1397 },
1398 {test_addressbus, "AddressBus", "[size] [addr]",
1399 "Verifies each relevant bits of the address and checking for aliasing",
1400 2
1401 },
1402 {test_memdevice, "MemDevice", "[size] [addr]",
1403 "Test the integrity of a physical memory (test every storage bit in the region)",
1404 2
1405 },
1406 {test_sso, "SimultaneousSwitchingOutput", "[size] [addr] ",
1407 "Stress the data bus over an address range",
1408 2
1409 },
1410 {test_noise, "Noise", "[pattern] [addr]",
1411 "Verifies r/w while forcing switching of all data bus lines.",
1412 3
1413 },
1414 {test_noise_burst, "NoiseBurst", "[size] [pattern] [addr]",
1415 "burst transfers while forcing switching of the data bus lines",
1416 3
1417 },
1418 {test_random, "Random", "[size] [loop] [addr]",
1419 "Verifies r/w and memcopy(burst for pseudo random value.",
1420 3
1421 },
Patrick Delaunay4b0496f2019-07-30 19:16:49 +02001422 {test_freq_pattern, "FrequencySelectivePattern", "[size]",
Patrick Delaunay0d447522019-04-10 14:09:28 +02001423 "write & test patterns: Mostly Zero, Mostly One and F/n",
1424 1
1425 },
1426 {test_blockseq, "BlockSequential", "[size] [loop] [addr]",
1427 "test incremental pattern",
1428 3
1429 },
1430 {test_checkboard, "Checkerboard", "[size] [loop] [addr]",
1431 "test checker pattern",
1432 3
1433 },
1434 {test_bitspread, "BitSpread", "[size] [loop] [addr]",
1435 "test Bit Spread pattern",
1436 3
1437 },
1438 {test_bitflip, "BitFlip", "[size] [loop] [addr]",
1439 "test Bit Flip pattern",
1440 3
1441 },
1442 {test_walkbit0, "WalkingOnes", "[size] [loop] [addr]",
1443 "test Walking Ones pattern",
1444 3
1445 },
1446 {test_walkbit1, "WalkingZeroes", "[size] [loop] [addr]",
1447 "test Walking Zeroes pattern",
1448 3
1449 },
1450 /* need to the the 2 last one (infinite) : skipped for test all */
Patrick Delaunay757bca82019-07-30 19:16:52 +02001451 {test_read, "infinite read", "[addr] [pattern]",
1452 "basic test : infinite read access (random: addr=0xFFFFFFFF)", 2},
1453 {test_write, "infinite write", "[addr] [pattern]",
1454 "basic test : infinite write access (random: addr=0xFFFFFFFF)", 2},
Patrick Delaunay0d447522019-04-10 14:09:28 +02001455};
1456
1457const int test_nb = ARRAY_SIZE(test);