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