blob: c7e09850503eab63ade5488e3f1e5aa62f58eca3 [file] [log] [blame]
Sean Anderson326422b2023-11-04 16:37:52 -04001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
4 */
5
6#include <nand.h>
7#include <part.h>
8#include <rand.h>
9#include <dm/test.h>
10#include <test/test.h>
11#include <test/ut.h>
12#include <linux/mtd/mtd.h>
13#include <linux/mtd/rawnand.h>
14
Simon Glass12439ed2024-08-22 07:57:52 -060015static int run_test_nand(struct unit_test_state *uts, int dev, bool end)
Sean Anderson326422b2023-11-04 16:37:52 -040016{
17 nand_erase_options_t opts = { };
18 struct mtd_info *mtd;
19 size_t length;
20 loff_t size;
21 char *buf;
22 int *gold;
23 u8 oob[NAND_MAX_OOBSIZE];
24 int i;
25 loff_t off = 0;
26 mtd_oob_ops_t ops = { };
27
28 /* Seed RNG for bit errors */
29 srand((off >> 32) ^ off ^ ~dev);
30
31 mtd = get_nand_dev_by_index(dev);
32 ut_assertnonnull(mtd);
33 size = mtd->erasesize * 4;
34 length = size;
35
36 buf = malloc(size);
37 ut_assertnonnull(buf);
38 gold = malloc(size);
39 ut_assertnonnull(gold);
40
41 /* Mark a block as bad */
42 ut_assertok(mtd_block_markbad(mtd, off + mtd->erasesize));
43
44 /* Erase some stuff */
45 if (end)
46 off = mtd->size - size - mtd->erasesize;
47 opts.offset = off;
48 opts.length = size;
49 opts.spread = 1;
50 opts.lim = U32_MAX;
51 ut_assertok(nand_erase_opts(mtd, &opts));
52
53 /* Make sure everything is erased */
54 memset(gold, 0xff, size);
55 ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf));
56 ut_asserteq(size, length);
57 ut_asserteq_mem(gold, buf, size);
58
59 /* ...but our bad block marker is still there */
60 ops.oobbuf = oob;
61 ops.ooblen = mtd->oobsize;
62 ut_assertok(mtd_read_oob(mtd, mtd->erasesize, &ops));
63 ut_asserteq(0, oob[mtd_to_nand(mtd)->badblockpos]);
64
65 /* Generate some data and write it */
66 for (i = 0; i < size / sizeof(int); i++)
67 gold[i] = rand();
68 ut_assertok(nand_write_skip_bad(mtd, off, &length, NULL, U64_MAX,
69 (void *)gold, 0));
70 ut_asserteq(size, length);
71
72 /* Verify */
73 ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf));
74 ut_asserteq(size, length);
75 ut_asserteq_mem(gold, buf, size);
76
77 /* Erase some blocks */
78 memset(((char *)gold) + mtd->erasesize, 0xff, mtd->erasesize * 2);
79 opts.offset = off + mtd->erasesize;
80 opts.length = mtd->erasesize * 2;
81 ut_assertok(nand_erase_opts(mtd, &opts));
82
83 /* Verify */
84 ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf));
85 ut_asserteq(size, length);
86 ut_asserteq_mem(gold, buf, size);
87
88 return 0;
89}
90
Simon Glass12439ed2024-08-22 07:57:52 -060091static int dm_test_nand0_start(struct unit_test_state *uts)
92{
93 ut_assertok(run_test_nand(uts, 0, false));
94
95 return 0;
96}
97DM_TEST(dm_test_nand0_start, UTF_SCAN_FDT);
98
99static int dm_test_nand1_start(struct unit_test_state *uts)
100{
101 ut_assertok(run_test_nand(uts, 1, false));
102
103 return 0;
104}
105DM_TEST(dm_test_nand1_start, UTF_SCAN_FDT);
Sean Anderson326422b2023-11-04 16:37:52 -0400106
Simon Glass12439ed2024-08-22 07:57:52 -0600107static int dm_test_nand0_end(struct unit_test_state *uts)
108{
109 ut_assertok(run_test_nand(uts, 0, true));
110
111 return 0;
112}
113DM_TEST(dm_test_nand0_end, UTF_SCAN_FDT);
114
115static int dm_test_nand1_end(struct unit_test_state *uts)
116{
117 ut_assertok(run_test_nand(uts, 1, true));
118
119 return 0;
120}
121DM_TEST(dm_test_nand1_end, UTF_SCAN_FDT);