Commit 2313d48445e59f063ec9a3b4940fe8252737db76

Authored by Tom Rini

Merge git://git.denx.de/u-boot-nand-flash

Showing 12 changed files Side-by-side Diff

... ... @@ -647,6 +647,9 @@
647 647  
648 648 #ifdef CONFIG_CMD_NAND_TORTURE
649 649 if (strcmp(cmd, "torture") == 0) {
  650 + loff_t endoff;
  651 + unsigned int failed = 0, passed = 0;
  652 +
650 653 if (argc < 3)
651 654 goto usage;
652 655  
653 656  
... ... @@ -655,12 +658,37 @@
655 658 return 1;
656 659 }
657 660  
658   - printf("\nNAND torture: device %d offset 0x%llx size 0x%x\n",
659   - dev, off, mtd->erasesize);
660   - ret = nand_torture(mtd, off);
661   - printf(" %s\n", ret ? "Failed" : "Passed");
  661 + size = mtd->erasesize;
  662 + if (argc > 3) {
  663 + if (!str2off(argv[3], &size)) {
  664 + puts("Size is not a valid number\n");
  665 + return 1;
  666 + }
  667 + }
662 668  
663   - return ret == 0 ? 0 : 1;
  669 + endoff = off + size;
  670 + if (endoff > mtd->size) {
  671 + puts("Arguments beyond end of NAND\n");
  672 + return 1;
  673 + }
  674 +
  675 + off = round_down(off, mtd->erasesize);
  676 + endoff = round_up(endoff, mtd->erasesize);
  677 + size = endoff - off;
  678 + printf("\nNAND torture: device %d offset 0x%llx size 0x%llx (block size 0x%x)\n",
  679 + dev, off, size, mtd->erasesize);
  680 + while (off < endoff) {
  681 + ret = nand_torture(mtd, off);
  682 + if (ret) {
  683 + failed++;
  684 + printf(" block at 0x%llx failed\n", off);
  685 + } else {
  686 + passed++;
  687 + }
  688 + off += mtd->erasesize;
  689 + }
  690 + printf(" Passed: %u, failed: %u\n", passed, failed);
  691 + return failed != 0;
664 692 }
665 693 #endif
666 694  
... ... @@ -775,7 +803,8 @@
775 803 "nand bad - show bad blocks\n"
776 804 "nand dump[.oob] off - dump page\n"
777 805 #ifdef CONFIG_CMD_NAND_TORTURE
778   - "nand torture off - torture block at offset\n"
  806 + "nand torture off - torture one block at offset\n"
  807 + "nand torture off [size] - torture blocks from off to off+size\n"
779 808 #endif
780 809 "nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
781 810 " really clean NAND erasing bad blocks (UNSAFE)\n"
... ... @@ -34,7 +34,7 @@
34 34 }
35 35  
36 36 static int fb_nand_lookup(const char *partname, char *response,
37   - struct mtd_info **nand,
  37 + struct mtd_info **mtd,
38 38 struct part_info **part)
39 39 {
40 40 struct mtd_device *dev;
common/spl/spl_nand.c
... ... @@ -134,6 +134,13 @@
134 134 #endif
135 135 /* Load u-boot */
136 136 err = spl_nand_load_element(CONFIG_SYS_NAND_U_BOOT_OFFS, header);
  137 +#ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
  138 +#if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
  139 + if (err)
  140 + err = spl_nand_load_element(CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
  141 + header);
  142 +#endif
  143 +#endif
137 144 nand_deselect();
138 145 return err;
139 146 }
... ... @@ -137,7 +137,7 @@
137 137 init:
138 138  
139 139 /* chip is struct nand_chip, and is now provided by the driver. */
140   - mtd = &chip.mtd;
  140 + mtd = nand_to_mtd(&chip);
141 141  
142 142 /*
143 143 * Fill in appropriate values if this driver uses these fields,
... ... @@ -271,7 +271,7 @@
271 271  
272 272 However, for 4K pagesize NAND
273 273 NAND_PAGESIZE = 4096
274   - NAND_OOBSIZE = 64
  274 + NAND_OOBSIZE = 224
275 275 ECC_BYTES = 26
276 276 2 + (4096 / 512) * 26 = 210 < NAND_OOBSIZE
277 277 Thus BCH16 can be supported on 4K page NAND.
... ... @@ -307,7 +307,7 @@
307 307 DANGEROUS!!! Factory set bad blocks will be lost. Use only
308 308 to remove artificial bad blocks created with the "markbad" command.
309 309  
310   - "torture offset"
  310 + "torture offset [size]"
311 311 Torture block to determine if it is still reliable.
312 312 Enabled by the CONFIG_CMD_NAND_TORTURE configuration option.
313 313 This command returns 0 if the block is still reliable, else 1.
... ... @@ -324,6 +324,10 @@
324 324 automate actions following a nand->write() error. This would e.g. be required
325 325 in order to program or update safely firmware to NAND, especially for the UBI
326 326 part of such firmware.
  327 + Optionally, a second parameter size can be given to test multiple blocks with
  328 + one call. If size is not a multiple of the NAND's erase size, then the block
  329 + that contains offset + size will be tested in full. If used with size, this
  330 + command returns 0 if all tested blocks have been found reliable, else 1.
327 331  
328 332  
329 333 NAND locking command (for chips with active LOCKPRE pin)
drivers/mtd/nand/Kconfig
... ... @@ -99,16 +99,31 @@
99 99 not available while configuring controller. So a static CONFIG_NAND_xx
100 100 is needed to know the device's bus-width in advance.
101 101  
102   -# Enhance depends when converting drivers to Kconfig which use this config
  102 +if SPL
  103 +
  104 +config SYS_NAND_U_BOOT_LOCATIONS
  105 + bool "Define U-boot binaries locations in NAND"
  106 + help
  107 + Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
  108 + This option should not be enabled when compiling U-boot for boards
  109 + defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
  110 + file.
  111 +
103 112 config SYS_NAND_U_BOOT_OFFS
104 113 hex "Location in NAND to read U-Boot from"
105 114 default 0x8000 if NAND_SUNXI
106   - depends on NAND_SUNXI
  115 + depends on SYS_NAND_U_BOOT_LOCATIONS
107 116 help
108 117 Set the offset from the start of the nand where u-boot should be
109 118 loaded from.
110 119  
111   -if SPL
  120 +config SYS_NAND_U_BOOT_OFFS_REDUND
  121 + hex "Location in NAND to read U-Boot from"
  122 + default SYS_NAND_U_BOOT_OFFS
  123 + depends on SYS_NAND_U_BOOT_LOCATIONS
  124 + help
  125 + Set the offset from the start of the nand where the redundant u-boot
  126 + should be loaded from.
112 127  
113 128 config SPL_NAND_DENALI
114 129 bool "Support Denali NAND controller for SPL"
drivers/mtd/nand/am335x_spl_bch.c
... ... @@ -223,7 +223,7 @@
223 223 /*
224 224 * Init board specific nand support
225 225 */
226   - mtd = &nand_chip.mtd;
  226 + mtd = nand_to_mtd(&nand_chip);
227 227 nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
228 228 (void __iomem *)CONFIG_SYS_NAND_BASE;
229 229 board_nand_init(&nand_chip);
drivers/mtd/nand/atmel_nand.c
... ... @@ -1449,7 +1449,7 @@
1449 1449  
1450 1450 void nand_init(void)
1451 1451 {
1452   - mtd = &nand_chip.mtd;
  1452 + mtd = nand_to_mtd(&nand_chip);
1453 1453 mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE;
1454 1454 mtd->oobsize = CONFIG_SYS_NAND_OOBSIZE;
1455 1455 nand_chip.IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE;
drivers/mtd/nand/lpc32xx_nand_mlc.c
... ... @@ -541,7 +541,7 @@
541 541  
542 542 void board_nand_init(void)
543 543 {
544   - struct mtd_info *mtd = &lpc32xx_chip.mtd;
  544 + struct mtd_info *mtd = nand_to_mtd(&lpc32xx_chip);
545 545 int ret;
546 546  
547 547 /* Set all BOARDSPECIFIC (actually core-specific) fields */
drivers/mtd/nand/mxs_nand_spl.c
... ... @@ -147,7 +147,7 @@
147 147  
148 148 /* init mxs nand driver */
149 149 board_nand_init(&nand_chip);
150   - mtd = &nand_chip.mtd;
  150 + mtd = nand_to_mtd(&nand_chip);
151 151 /* set mtd functions */
152 152 nand_chip.cmdfunc = mxs_nand_command;
153 153 nand_chip.numchips = 1;
drivers/mtd/nand/nand_spl_simple.c
... ... @@ -249,7 +249,7 @@
249 249 /*
250 250 * Init board specific nand support
251 251 */
252   - mtd = &nand_chip.mtd;
  252 + mtd = nand_to_mtd(&nand_chip);
253 253 nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
254 254 (void __iomem *)CONFIG_SYS_NAND_BASE;
255 255 board_nand_init(&nand_chip);
drivers/mtd/nand/nand_util.c
... ... @@ -820,7 +820,7 @@
820 820 {
821 821 u_char patterns[] = {0xa5, 0x5a, 0x00};
822 822 struct erase_info instr = {
823   - .mtd = nand,
  823 + .mtd = mtd,
824 824 .addr = offset,
825 825 .len = mtd->erasesize,
826 826 };
drivers/mtd/nand/sunxi_nand_spl.c
... ... @@ -66,6 +66,8 @@
66 66 #define NFC_ROW_AUTO_INC (1 << 27)
67 67 #define NFC_SEND_CMD3 (1 << 28)
68 68 #define NFC_SEND_CMD4 (1 << 29)
  69 +#define NFC_RAW_CMD (0 << 30)
  70 +#define NFC_PAGE_CMD (2 << 30)
69 71  
70 72 #define NFC_ST_CMD_INT_FLAG (1 << 1)
71 73 #define NFC_ST_DMA_INT_FLAG (1 << 2)
... ... @@ -78,9 +80,6 @@
78 80 #define NFC_CMD_RNDOUT 0x05
79 81 #define NFC_CMD_READSTART 0x30
80 82  
81   -
82   -#define NFC_PAGE_CMD (2 << 30)
83   -
84 83 #define SUNXI_DMA_CFG_REG0 0x300
85 84 #define SUNXI_DMA_SRC_START_ADDR_REG0 0x304
86 85 #define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308
... ... @@ -97,6 +96,16 @@
97 96 #define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0)
98 97 #define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8)
99 98  
  99 +struct nfc_config {
  100 + int page_size;
  101 + int ecc_strength;
  102 + int ecc_size;
  103 + int addr_cycles;
  104 + int nseeds;
  105 + bool randomize;
  106 + bool valid;
  107 +};
  108 +
100 109 /* minimal "boot0" style NAND support for Allwinner A20 */
101 110  
102 111 /* random seed used by linux */
103 112  
104 113  
105 114  
106 115  
107 116  
108 117  
109 118  
110 119  
... ... @@ -119,38 +128,31 @@
119 128 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
120 129 };
121 130  
122   -/* random seed used for syndrome calls */
123   -const uint16_t random_seed_syndrome = 0x4a80;
  131 +#define DEFAULT_TIMEOUT_US 100000
124 132  
125   -#define MAX_RETRIES 10
126   -
127 133 static int check_value_inner(int offset, int expected_bits,
128   - int max_number_of_retries, int negation)
  134 + int timeout_us, int negation)
129 135 {
130   - int retries = 0;
131 136 do {
132 137 int val = readl(offset) & expected_bits;
133 138 if (negation ? !val : val)
134 139 return 1;
135   - mdelay(1);
136   - retries++;
137   - } while (retries < max_number_of_retries);
  140 + udelay(1);
  141 + } while (--timeout_us);
138 142  
139 143 return 0;
140 144 }
141 145  
142 146 static inline int check_value(int offset, int expected_bits,
143   - int max_number_of_retries)
  147 + int timeout_us)
144 148 {
145   - return check_value_inner(offset, expected_bits,
146   - max_number_of_retries, 0);
  149 + return check_value_inner(offset, expected_bits, timeout_us, 0);
147 150 }
148 151  
149 152 static inline int check_value_negated(int offset, int unexpected_bits,
150   - int max_number_of_retries)
  153 + int timeout_us)
151 154 {
152   - return check_value_inner(offset, unexpected_bits,
153   - max_number_of_retries, 1);
  155 + return check_value_inner(offset, unexpected_bits, timeout_us, 1);
154 156 }
155 157  
156 158 void nand_init(void)
... ... @@ -165,7 +167,7 @@
165 167 SUNXI_NFC_BASE + NFC_CTL);
166 168  
167 169 if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL,
168   - NFC_CTL_RESET, MAX_RETRIES)) {
  170 + NFC_CTL_RESET, DEFAULT_TIMEOUT_US)) {
169 171 printf("Couldn't initialize nand\n");
170 172 }
171 173  
172 174  
173 175  
174 176  
175 177  
176 178  
177 179  
178 180  
179 181  
180 182  
181 183  
182 184  
... ... @@ -175,65 +177,98 @@
175 177 SUNXI_NFC_BASE + NFC_CMD);
176 178  
177 179 if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
178   - MAX_RETRIES)) {
  180 + DEFAULT_TIMEOUT_US)) {
179 181 printf("Error timeout waiting for nand reset\n");
180 182 return;
181 183 }
182 184 writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
183 185 }
184 186  
185   -static int nand_read_page(int page_size, int ecc_strength, int ecc_page_size,
186   - int addr_cycles, uint32_t real_addr, dma_addr_t dst, int syndrome)
  187 +static void nand_apply_config(const struct nfc_config *conf)
187 188 {
188   - uint32_t val;
189   - int i, ecc_off = 0;
190   - uint16_t ecc_mode = 0;
191   - uint16_t rand_seed;
192   - uint32_t page;
193   - uint16_t column;
194   - static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
  189 + u32 val;
195 190  
196   - for (i = 0; i < ARRAY_SIZE(strengths); i++) {
197   - if (ecc_strength == strengths[i]) {
198   - ecc_mode = i;
199   - break;
200   - }
  191 + val = readl(SUNXI_NFC_BASE + NFC_CTL);
  192 + val &= ~NFC_CTL_PAGE_SIZE_MASK;
  193 + writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size),
  194 + SUNXI_NFC_BASE + NFC_CTL);
  195 + writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
  196 + writel(conf->page_size, SUNXI_NFC_BASE + NFC_SPARE_AREA);
  197 +}
  198 +
  199 +static int nand_load_page(const struct nfc_config *conf, u32 offs)
  200 +{
  201 + int page = offs / conf->page_size;
  202 +
  203 + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
  204 + (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
  205 + (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET),
  206 + SUNXI_NFC_BASE + NFC_RCMD_SET);
  207 + writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW);
  208 + writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
  209 + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
  210 + writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | NFC_WAIT_FLAG |
  211 + ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR,
  212 + SUNXI_NFC_BASE + NFC_CMD);
  213 +
  214 + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
  215 + DEFAULT_TIMEOUT_US)) {
  216 + printf("Error while initializing dma interrupt\n");
  217 + return -EIO;
201 218 }
202 219  
203   - /* HW ECC always request ECC bytes for 1024 bytes blocks */
204   - ecc_off = DIV_ROUND_UP(ecc_strength * fls(8 * 1024), 8);
205   - /* HW ECC always work with even numbers of ECC bytes */
206   - ecc_off += (ecc_off & 1);
207   - ecc_off += 4; /* prepad */
  220 + return 0;
  221 +}
208 222  
209   - page = real_addr / page_size;
210   - column = real_addr % page_size;
  223 +static int nand_reset_column(void)
  224 +{
  225 + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
  226 + (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
  227 + (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET),
  228 + SUNXI_NFC_BASE + NFC_RCMD_SET);
  229 + writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW);
  230 + writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
  231 + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR | NFC_CMD_RNDOUT,
  232 + SUNXI_NFC_BASE + NFC_CMD);
211 233  
212   - if (syndrome)
213   - column += (column / ecc_page_size) * ecc_off;
  234 + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
  235 + DEFAULT_TIMEOUT_US)) {
  236 + printf("Error while initializing dma interrupt\n");
  237 + return -1;
  238 + }
214 239  
  240 + return 0;
  241 +}
  242 +
  243 +static int nand_read_page(const struct nfc_config *conf, u32 offs,
  244 + void *dest, int len)
  245 +{
  246 + dma_addr_t dst = (dma_addr_t)dest;
  247 + int nsectors = len / conf->ecc_size;
  248 + u16 rand_seed;
  249 + u32 val;
  250 + int page;
  251 +
  252 + page = offs / conf->page_size;
  253 +
  254 + if (offs % conf->page_size || len % conf->ecc_size ||
  255 + len > conf->page_size || len < 0)
  256 + return -EINVAL;
  257 +
215 258 /* clear ecc status */
216 259 writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
217 260  
218 261 /* Choose correct seed */
219   - if (syndrome)
220   - rand_seed = random_seed_syndrome;
221   - else
222   - rand_seed = random_seed[page % 128];
  262 + rand_seed = random_seed[page % conf->nseeds];
223 263  
224   - writel((rand_seed << 16) | NFC_ECC_RANDOM_EN | NFC_ECC_EN
225   - | NFC_ECC_PIPELINE | (ecc_mode << 12),
  264 + writel((rand_seed << 16) | (conf->ecc_strength << 12) |
  265 + (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
  266 + (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
  267 + NFC_ECC_EN | NFC_ECC_PIPELINE | NFC_ECC_EXCEPTION,
226 268 SUNXI_NFC_BASE + NFC_ECC_CTL);
227 269  
228   - val = readl(SUNXI_NFC_BASE + NFC_CTL);
229   - writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL);
  270 + flush_dcache_range(dst, ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
230 271  
231   - if (!syndrome)
232   - writel(page_size + (column / ecc_page_size) * ecc_off,
233   - SUNXI_NFC_BASE + NFC_SPARE_AREA);
234   -
235   - flush_dcache_range(dst, ALIGN(dst + ecc_page_size, ARCH_DMA_MINALIGN));
236   -
237 272 /* SUNXI_DMA */
238 273 writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
239 274 /* read from REG_IO_DATA */
240 275  
241 276  
242 277  
243 278  
244 279  
245 280  
246 281  
247 282  
248 283  
249 284  
250 285  
251 286  
252 287  
253 288  
254 289  
255 290  
256 291  
257 292  
258 293  
259 294  
260 295  
261 296  
262 297  
263 298  
264 299  
265 300  
266 301  
267 302  
268 303  
... ... @@ -241,158 +276,261 @@
241 276 SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
242 277 /* read to RAM */
243 278 writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
244   - writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC
245   - | SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
246   - SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
247   - writel(ecc_page_size,
248   - SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */
249   - writel(SUNXI_DMA_DDMA_CFG_REG_LOADING
250   - | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32
251   - | SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM
252   - | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32
253   - | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO
254   - | SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
255   - SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
  279 + writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC |
  280 + SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
  281 + SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
  282 + writel(len, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0);
  283 + writel(SUNXI_DMA_DDMA_CFG_REG_LOADING |
  284 + SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 |
  285 + SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM |
  286 + SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 |
  287 + SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO |
  288 + SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
  289 + SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
256 290  
257   - writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET)
258   - | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET)
259   - | (NFC_CMD_READSTART | NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE
260   - + NFC_RCMD_SET);
261   - writel(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
262   - writel(((page & 0xFFFF) << 16) | column,
263   - SUNXI_NFC_BASE + NFC_ADDR_LOW);
264   - writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
  291 + writel(nsectors, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
265 292 writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
266   - writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS |
267   - NFC_PAGE_CMD | NFC_WAIT_FLAG |
268   - ((addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) |
269   - NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0),
270   - SUNXI_NFC_BASE + NFC_CMD);
  293 + writel(NFC_DATA_TRANS | NFC_PAGE_CMD | NFC_DATA_SWAP_METHOD,
  294 + SUNXI_NFC_BASE + NFC_CMD);
271 295  
272 296 if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_DMA_INT_FLAG,
273   - MAX_RETRIES)) {
  297 + DEFAULT_TIMEOUT_US)) {
274 298 printf("Error while initializing dma interrupt\n");
275   - return -1;
  299 + return -EIO;
276 300 }
277 301 writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
278 302  
279 303 if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
280   - SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) {
  304 + SUNXI_DMA_DDMA_CFG_REG_LOADING,
  305 + DEFAULT_TIMEOUT_US)) {
281 306 printf("Error while waiting for dma transfer to finish\n");
282   - return -1;
  307 + return -EIO;
283 308 }
284 309  
285 310 invalidate_dcache_range(dst,
286   - ALIGN(dst + ecc_page_size, ARCH_DMA_MINALIGN));
  311 + ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
287 312  
288   - if (readl(SUNXI_NFC_BASE + NFC_ECC_ST))
289   - return -1;
  313 + val = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
290 314  
291   - return 0;
  315 + /* ECC error detected. */
  316 + if (val & 0xffff)
  317 + return -EIO;
  318 +
  319 + /*
  320 + * Return 1 if the page is empty.
  321 + * We consider the page as empty if the first ECC block is marked
  322 + * empty.
  323 + */
  324 + return (val & 0x10000) ? 1 : 0;
292 325 }
293 326  
294   -static int nand_read_ecc(int page_size, int ecc_strength, int ecc_page_size,
295   - int addr_cycles, uint32_t offs, uint32_t size, void *dest, int syndrome)
  327 +static int nand_max_ecc_strength(struct nfc_config *conf)
296 328 {
297   - void *end = dest + size;
  329 + static const int ecc_bytes[] = { 32, 46, 54, 60, 74, 88, 102, 110, 116 };
  330 + int max_oobsize, max_ecc_bytes;
  331 + int nsectors = conf->page_size / conf->ecc_size;
  332 + int i;
298 333  
299   - clrsetbits_le32(SUNXI_NFC_BASE + NFC_CTL, NFC_CTL_PAGE_SIZE_MASK,
300   - NFC_CTL_PAGE_SIZE(page_size));
  334 + /*
  335 + * ECC strength is limited by the size of the OOB area which is
  336 + * correlated with the page size.
  337 + */
  338 + switch (conf->page_size) {
  339 + case 2048:
  340 + max_oobsize = 64;
  341 + break;
  342 + case 4096:
  343 + max_oobsize = 256;
  344 + break;
  345 + case 8192:
  346 + max_oobsize = 640;
  347 + break;
  348 + case 16384:
  349 + max_oobsize = 1664;
  350 + break;
  351 + default:
  352 + return -EINVAL;
  353 + }
301 354  
302   - for ( ;dest < end; dest += ecc_page_size, offs += ecc_page_size) {
303   - if (nand_read_page(page_size, ecc_strength, ecc_page_size,
304   - addr_cycles, offs, (dma_addr_t)dest,
305   - syndrome))
306   - return -1;
  355 + max_ecc_bytes = max_oobsize / nsectors;
  356 +
  357 + for (i = 0; i < ARRAY_SIZE(ecc_bytes); i++) {
  358 + if (ecc_bytes[i] > max_ecc_bytes)
  359 + break;
307 360 }
308 361  
309   - return 0;
  362 + if (!i)
  363 + return -EINVAL;
  364 +
  365 + return i - 1;
310 366 }
311 367  
312   -static int nand_read_buffer(uint32_t offs, unsigned int size, void *dest,
313   - int syndrome)
  368 +static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs,
  369 + void *dest)
314 370 {
315   - const struct {
316   - int page_size;
317   - int ecc_strength;
318   - int ecc_page_size;
319   - int addr_cycles;
320   - } nand_configs[] = {
321   - { 8192, 40, 1024, 5 },
322   - { 16384, 56, 1024, 5 },
323   - { 8192, 24, 1024, 5 },
324   - { 4096, 24, 1024, 5 },
325   - };
326   - static int nand_config = -1;
327   - int i;
  371 + /* NAND with pages > 4k will likely require 1k sector size. */
  372 + int min_ecc_size = conf->page_size > 4096 ? 1024 : 512;
  373 + int page = offs / conf->page_size;
  374 + int ret;
328 375  
329   - if (nand_config == -1) {
330   - for (i = 0; i < ARRAY_SIZE(nand_configs); i++) {
331   - debug("nand: trying page %d ecc %d / %d addr %d: ",
332   - nand_configs[i].page_size,
333   - nand_configs[i].ecc_strength,
334   - nand_configs[i].ecc_page_size,
335   - nand_configs[i].addr_cycles);
336   - if (nand_read_ecc(nand_configs[i].page_size,
337   - nand_configs[i].ecc_strength,
338   - nand_configs[i].ecc_page_size,
339   - nand_configs[i].addr_cycles,
340   - offs, size, dest, syndrome) == 0) {
341   - debug("success\n");
342   - nand_config = i;
  376 + /*
  377 + * In most cases, 1k sectors are preferred over 512b ones, start
  378 + * testing this config first.
  379 + */
  380 + for (conf->ecc_size = 1024; conf->ecc_size >= min_ecc_size;
  381 + conf->ecc_size >>= 1) {
  382 + int max_ecc_strength = nand_max_ecc_strength(conf);
  383 +
  384 + nand_apply_config(conf);
  385 +
  386 + /*
  387 + * We are starting from the maximum ECC strength because
  388 + * most of the time NAND vendors provide an OOB area that
  389 + * barely meets the ECC requirements.
  390 + */
  391 + for (conf->ecc_strength = max_ecc_strength;
  392 + conf->ecc_strength >= 0;
  393 + conf->ecc_strength--) {
  394 + conf->randomize = false;
  395 + if (nand_reset_column())
  396 + return -EIO;
  397 +
  398 + /*
  399 + * Only read the first sector to speedup detection.
  400 + */
  401 + ret = nand_read_page(conf, offs, dest, conf->ecc_size);
  402 + if (!ret) {
343 403 return 0;
  404 + } else if (ret > 0) {
  405 + /*
  406 + * If page is empty we can't deduce anything
  407 + * about the ECC config => stop the detection.
  408 + */
  409 + return -EINVAL;
344 410 }
345   - debug("failed\n");
  411 +
  412 + conf->randomize = true;
  413 + conf->nseeds = ARRAY_SIZE(random_seed);
  414 + do {
  415 + if (nand_reset_column())
  416 + return -EIO;
  417 +
  418 + if (!nand_read_page(conf, offs, dest,
  419 + conf->ecc_size))
  420 + return 0;
  421 +
  422 + /*
  423 + * Find the next ->nseeds value that would
  424 + * change the randomizer seed for the page
  425 + * we're trying to read.
  426 + */
  427 + while (conf->nseeds >= 16) {
  428 + int seed = page % conf->nseeds;
  429 +
  430 + conf->nseeds >>= 1;
  431 + if (seed != page % conf->nseeds)
  432 + break;
  433 + }
  434 + } while (conf->nseeds >= 16);
346 435 }
347   - return -1;
348 436 }
349 437  
350   - return nand_read_ecc(nand_configs[nand_config].page_size,
351   - nand_configs[nand_config].ecc_strength,
352   - nand_configs[nand_config].ecc_page_size,
353   - nand_configs[nand_config].addr_cycles,
354   - offs, size, dest, syndrome);
  438 + return -EINVAL;
355 439 }
356 440  
357   -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
  441 +static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest)
358 442 {
359   -#if CONFIG_SYS_NAND_U_BOOT_OFFS == CONFIG_SPL_PAD_TO
  443 + if (conf->valid)
  444 + return 0;
  445 +
360 446 /*
361   - * u-boot-dtb.bin appended to SPL, use syndrome (like the BROM does)
362   - * and try different erase block sizes to find the backup.
  447 + * Modern NANDs are more likely than legacy ones, so we start testing
  448 + * with 5 address cycles.
363 449 */
364   - const uint32_t boot_offsets[] = {
365   - 0 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS,
366   - 1 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS,
367   - 2 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS,
368   - 4 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS,
369   - };
370   - const int syndrome = 1;
371   -#else
372   - /*
373   - * u-boot-dtb.bin on its own partition, do not use syndrome, u-boot
374   - * partition sits after 2 eraseblocks (spl, spl-backup), look for
375   - * backup u-boot 1 erase block further.
376   - */
377   - const uint32_t eraseblock_size = CONFIG_SYS_NAND_U_BOOT_OFFS / 2;
378   - const uint32_t boot_offsets[] = {
379   - CONFIG_SYS_NAND_U_BOOT_OFFS,
380   - CONFIG_SYS_NAND_U_BOOT_OFFS + eraseblock_size,
381   - };
382   - const int syndrome = 0;
383   -#endif
384   - int i;
  450 + for (conf->addr_cycles = 5;
  451 + conf->addr_cycles >= 4;
  452 + conf->addr_cycles--) {
  453 + int max_page_size = conf->addr_cycles == 4 ? 2048 : 16384;
385 454  
386   - if (offs == CONFIG_SYS_NAND_U_BOOT_OFFS) {
387   - for (i = 0; i < ARRAY_SIZE(boot_offsets); i++) {
388   - if (nand_read_buffer(boot_offsets[i], size,
389   - dest, syndrome) == 0)
  455 + /*
  456 + * Ignoring 1k pages cause I'm not even sure this case exist
  457 + * in the real world.
  458 + */
  459 + for (conf->page_size = 2048; conf->page_size <= max_page_size;
  460 + conf->page_size <<= 1) {
  461 + if (nand_load_page(conf, offs))
  462 + return -1;
  463 +
  464 + if (!nand_detect_ecc_config(conf, offs, dest)) {
  465 + conf->valid = true;
390 466 return 0;
  467 + }
391 468 }
392   - return -1;
393 469 }
394 470  
395   - return nand_read_buffer(offs, size, dest, syndrome);
  471 + return -EINVAL;
  472 +}
  473 +
  474 +static int nand_read_buffer(struct nfc_config *conf, uint32_t offs,
  475 + unsigned int size, void *dest)
  476 +{
  477 + int first_seed, page, ret;
  478 +
  479 + size = ALIGN(size, conf->page_size);
  480 + page = offs / conf->page_size;
  481 + first_seed = page % conf->nseeds;
  482 +
  483 + for (; size; size -= conf->page_size) {
  484 + if (nand_load_page(conf, offs))
  485 + return -1;
  486 +
  487 + ret = nand_read_page(conf, offs, dest, conf->page_size);
  488 + /*
  489 + * The ->nseeds value should be equal to the number of pages
  490 + * in an eraseblock. Since we don't know this information in
  491 + * advance we might have picked a wrong value.
  492 + */
  493 + if (ret < 0 && conf->randomize) {
  494 + int cur_seed = page % conf->nseeds;
  495 +
  496 + /*
  497 + * We already tried all the seed values => we are
  498 + * facing a real corruption.
  499 + */
  500 + if (cur_seed < first_seed)
  501 + return -EIO;
  502 +
  503 + /* Try to adjust ->nseeds and read the page again... */
  504 + conf->nseeds = cur_seed;
  505 +
  506 + if (nand_reset_column())
  507 + return -EIO;
  508 +
  509 + /* ... it still fails => it's a real corruption. */
  510 + if (nand_read_page(conf, offs, dest, conf->page_size))
  511 + return -EIO;
  512 + } else if (ret && conf->randomize) {
  513 + memset(dest, 0xff, conf->page_size);
  514 + }
  515 +
  516 + page++;
  517 + offs += conf->page_size;
  518 + dest += conf->page_size;
  519 + }
  520 +
  521 + return 0;
  522 +}
  523 +
  524 +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
  525 +{
  526 + static struct nfc_config conf = { };
  527 + int ret;
  528 +
  529 + ret = nand_detect_config(&conf, offs, dest);
  530 + if (ret)
  531 + return ret;
  532 +
  533 + return nand_read_buffer(&conf, offs, size, dest);
396 534 }
397 535  
398 536 void nand_deselect(void)