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