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