shared ARM updates
[tomato.git] / release / src-rt-6.x.4708 / shared / nandcore.c
bloba34decb7294d3a87bbbc51c6ec53f855e5bd17eb
1 /*
2 * Broadcom NAND core interface
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: $
21 #include <typedefs.h>
22 #include <osl.h>
23 #include <bcmutils.h>
24 #include <siutils.h>
25 #include <hndsoc.h>
26 #include <sbhndcpu.h>
27 #include <sbchipc.h>
28 #include <bcmdevs.h>
29 #include <nand_core.h>
30 #include <hndnand.h>
31 #include <hndpmu.h>
33 #ifdef BCMDBG
34 #define NANDFL_MSG(args) printf args
35 #else
36 #define NANDFL_MSG(args)
37 #endif /* BCMDBG */
39 #define NANDF_RETRIES 1000000
41 #define NANDF_SMALL_BADBLOCK_POS 5
42 #define NANDF_LARGE_BADBLOCK_POS 0
44 /* Private global state */
45 static hndnand_t nandcore;
47 /* Prototype */
48 static int nandcore_poll(si_t *sih, nandregs_t *nc);
50 hndnand_t *nandcore_init(si_t *sih);
51 static int nandcore_read(hndnand_t *nfl, uint64 offset, uint len, uchar *buf);
52 static int nandcore_write(hndnand_t *nfl, uint64 offset, uint len, const uchar *buf);
53 static int nandcore_erase(hndnand_t *nfl, uint64 offset);
54 static int nandcore_checkbadb(hndnand_t *nfl, uint64 offset);
55 static int nandcore_mark_badb(hndnand_t *nfl, uint64 offset);
57 static int nandcore_read_oob(hndnand_t *nfl, uint64 addr, uint8 *oob);
58 #ifndef _CFE_
59 static int nandcore_dev_ready(hndnand_t *nfl);
60 static int nandcore_select_chip(hndnand_t *nfl, int chip);
61 static int nandcore_cmdfunc(hndnand_t *nfl, uint64 addr, int cmd);
62 static int nandcore_waitfunc(hndnand_t *nfl, int *status);
63 static int nandcore_write_oob(hndnand_t *nfl, uint64 addr, uint8 *oob);
64 static int nandcore_read_page(hndnand_t *nfl, uint64 addr, uint8 *buf, uint8 *oob, bool ecc,
65 uint32 *herr, uint32 *serr);
66 static int nandcore_write_page(hndnand_t *nfl, uint64 addr, const uint8 *buf, uint8 *oob, bool ecc);
67 static int nandcore_cmd_read_byte(hndnand_t *nfl, int cmd, int arg);
68 #endif /* !_CFE_ */
70 /* Issue a nand flash command */
71 static INLINE void
72 nandcore_cmd(osl_t *osh, nandregs_t *nc, uint opcode)
74 W_REG(osh, &nc->cmd_start, opcode);
77 static int
78 _nandcore_ffs(int i)
80 int j;
82 if (i != 0)
83 for (j = 0; j < 32; j++)
84 if (i & (1 << j))
85 return j + 1;
86 return 0;
89 static bool
90 _nandcore_buf_erased(const void *buf, unsigned len)
92 unsigned i;
93 const uint32 *p = buf;
95 for (i = 0; i < (len >> 2); i++) {
96 if (p[i] != 0xffffffff)
97 return FALSE;
100 return TRUE;
103 static int
104 _nandcore_read_page(hndnand_t *nfl, uint64 offset, uint8 *buf, uint8 *oob, bool ecc,
105 uint32 *herr, uint32 *serr)
107 osl_t *osh;
108 nandregs_t *nc = (nandregs_t *)nfl->core;
109 aidmp_t *ai = (aidmp_t *)nfl->wrap;
110 unsigned data_bytes;
111 unsigned spare_per_sec;
112 unsigned sector;
113 unsigned hard_err_count = 0;
114 uint32 mask, reg, *to;
115 uint32 err_soft_reg, err_hard_reg;
116 int i, ret, sectorsize_shift, sec_per_page_shift;
118 ASSERT(nfl->sih);
120 mask = nfl->pagesize - 1;
121 /* Check offset and length */
122 if ((offset & mask) != 0)
123 return 0;
125 if ((((offset + nfl->pagesize) >> 20) > nfl->size) ||
126 ((((offset + nfl->pagesize) >> 20) == nfl->size) &&
127 (((offset + nfl->pagesize) & ((1 << 20) - 1)) != 0)))
128 return 0;
130 osh = si_osh(nfl->sih);
132 /* Reset ECC error stats */
133 err_hard_reg = R_REG(osh, &nc->uncorr_error_count);
134 err_soft_reg = R_REG(osh, &nc->read_error_count);
136 /* Cal shift */
137 sectorsize_shift = _nandcore_ffs(nfl->sectorsize) - 1;
138 sec_per_page_shift = _nandcore_ffs(nfl->pagesize) - 1 - sectorsize_shift;
140 spare_per_sec = nfl->oobsize >> sec_per_page_shift;
142 /* Set the page address for the following commands */
143 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
144 W_REG(osh, &nc->cmd_ext_address, (reg | (offset >> 32)));
146 /* Enable ECC validation for ecc page reads */
147 if (ecc)
148 OR_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0,
149 NANDAC_CS0_RD_ECC_EN);
150 else
151 AND_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0,
152 ~NANDAC_CS0_RD_ECC_EN);
154 /* Loop all sectors in page */
155 for (sector = 0; sector < (1 << sec_per_page_shift); sector ++) {
156 data_bytes = 0;
158 /* Copy partial sectors sized by cache reg */
159 while (data_bytes < (1 << sectorsize_shift)) {
160 unsigned col;
162 col = data_bytes + (sector << sectorsize_shift);
164 W_REG(osh, &nc->cmd_address, offset + col);
166 /* Issue command to read partial page */
167 nandcore_cmd(osh, nc, NANDCMD_PAGE_RD);
169 /* Wait for the command to complete */
170 if ((ret = nandcore_poll(nfl->sih, nc)) < 0)
171 return ret;
173 /* Set controller to Little Endian mode for copying */
174 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
176 if (data_bytes == 0 && oob) {
177 to = (uint32 *)(oob + sector * spare_per_sec);
178 for (i = 0; i < spare_per_sec; i += 4, to++)
179 *to = R_REG(osh, &nc->spare_area_read_ofs[i/4]);
182 /* oob per sector */
183 to = (uint32 *)(buf + col);
184 for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++)
185 *to = R_REG(osh, &nc->flash_cache[i/4]);
187 data_bytes += NFL_SECTOR_SIZE;
189 /* Return to Big Endian mode for commands etc */
190 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
192 /* capture hard errors for each partial */
193 if (err_hard_reg != R_REG(osh, &nc->uncorr_error_count)) {
194 int era = (R_REG(osh, &nc->intfc_status) & NANDIST_ERASED);
195 if ((!era) && (!_nandcore_buf_erased(buf+col, NFL_SECTOR_SIZE)))
196 hard_err_count ++;
198 err_hard_reg = R_REG(osh, &nc->uncorr_error_count);
200 } /* while FlashCache buffer */
201 } /* for sector */
203 if (!ecc)
204 return 0;
206 /* Report hard ECC errors */
207 if (herr)
208 *herr = hard_err_count;
210 /* Get ECC soft error stats */
211 if (serr)
212 *serr = R_REG(osh, &nc->read_error_count) - err_soft_reg;
214 return 0;
217 static int
218 _nandcore_write_page(hndnand_t *nfl, uint64 offset, const uint8 *buf, uint8 *oob, bool ecc)
220 osl_t *osh;
221 nandregs_t *nc = (nandregs_t *)nfl->core;
222 aidmp_t *ai = (aidmp_t *)nfl->wrap;
223 unsigned data_bytes, spare_bytes;
224 unsigned spare_per_sec, sector, num_sec;
225 uint32 mask, reg, *from;
226 int i, ret = 0, sectorsize_shift, sec_per_page_shift;
228 ASSERT(nfl->sih);
230 mask = nfl->pagesize - 1;
231 /* Check offset and length */
232 if ((offset & mask) != 0)
233 return 0;
235 if ((((offset + nfl->pagesize) >> 20) > nfl->size) ||
236 ((((offset + nfl->pagesize) >> 20) == nfl->size) &&
237 (((offset + nfl->pagesize) & ((1 << 20) - 1)) != 0)))
238 return 0;
240 osh = si_osh(nfl->sih);
242 /* Cal shift */
243 sectorsize_shift = _nandcore_ffs(nfl->sectorsize) - 1;
244 sec_per_page_shift = _nandcore_ffs(nfl->pagesize) - 1 - sectorsize_shift;
246 spare_per_sec = nfl->oobsize >> sec_per_page_shift;
248 /* Disable WP */
249 AND_REG(osh, &nc->cs_nand_select, ~NANDCSEL_NAND_WP);
251 /* Set the page address for the following commands */
252 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
253 W_REG(osh, &nc->cmd_ext_address, (reg | (offset >> 32)));
255 /* Enable ECC generation for ecc page write, if requested */
256 if (ecc)
257 OR_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0,
258 NANDAC_CS0_WR_ECC_EN);
259 else
260 AND_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0,
261 ~NANDAC_CS0_WR_ECC_EN);
263 spare_bytes = 0;
264 num_sec = 1 << sec_per_page_shift;
266 /* Loop all sectors in page */
267 for (sector = 0; sector < num_sec; sector++) {
268 data_bytes = 0;
270 /* Copy partial sectors sized by cache reg */
271 while (data_bytes < (1 << sectorsize_shift)) {
272 unsigned col;
274 col = data_bytes + (sector << sectorsize_shift);
276 /* Set address of 512-byte sub-page */
277 W_REG(osh, &nc->cmd_address, offset + col);
279 /* Set controller to Little Endian mode for copying */
280 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
282 /* Set spare area is written at each sector start */
283 if (data_bytes == 0) {
284 if (oob) {
285 from = (uint32 *)(oob + spare_bytes);
286 for (i = 0; i < spare_per_sec; i += 4, from++)
287 W_REG(osh, &nc->spare_area_write_ofs[i/4], *from);
289 else {
290 /* Write 0xffffffff to spare_area_write_ofs register
291 * to prevent old spare_area_write_ofs vale write
292 * when we issue NANDCMD_PAGE_PROG.
294 for (i = 0; i < spare_per_sec; i += 4)
295 W_REG(osh, &nc->spare_area_write_ofs[i/4],
296 0xffffffff);
299 spare_bytes += spare_per_sec;
302 /* Copy sub-page data */
303 from = (uint32 *)(buf + col);
304 for (i = 0; i < NFL_SECTOR_SIZE; i += 4, from++)
305 W_REG(osh, &nc->flash_cache[i/4], *from);
307 data_bytes += NFL_SECTOR_SIZE;
309 /* Return to Big Endian mode for commands etc */
310 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
312 /* Push data into internal cache */
313 nandcore_cmd(osh, nc, NANDCMD_PAGE_PROG);
315 ret = nandcore_poll(nfl->sih, nc);
316 if (ret < 0)
317 goto err;
321 err:
322 /* Enable WP */
323 OR_REG(osh, &nc->cs_nand_select, NANDCSEL_NAND_WP);
325 return ret;
328 static bool firsttime = TRUE;
330 static char *
331 nandcore_check_id(uint8 *id)
333 char *name = NULL;
335 switch (id[0]) {
336 case NFL_VENDOR_AMD:
337 name = "AMD";
338 break;
339 case NFL_VENDOR_NUMONYX:
340 name = "Numonyx";
341 break;
342 case NFL_VENDOR_MICRON:
343 name = "Micron";
344 break;
345 case NFL_VENDOR_TOSHIBA:
346 name = "Toshiba";
347 break;
348 case NFL_VENDOR_HYNIX:
349 name = "Hynix";
350 break;
351 case NFL_VENDOR_SAMSUNG:
352 name = "Samsung";
353 break;
354 case NFL_VENDOR_ESMT:
355 name = "Esmt";
356 break;
357 case NFL_VENDOR_MXIC:
358 name = "Mxic";
359 break;
360 case NFL_VENDOR_ZENTEL:
361 name = "Zentel";
362 break;
363 default:
364 printf("No NAND flash type found\n");
365 break;
368 return name;
371 /* Initialize nand flash access */
372 hndnand_t *
373 nandcore_init(si_t *sih)
375 nandregs_t *nc;
376 aidmp_t *ai;
377 uint32 id, id2;
378 char *name = "";
379 osl_t *osh;
380 int i;
381 uint32 ncf, val;
382 uint32 acc_control;
384 ASSERT(sih);
386 /* Only support chipcommon revision == 42 for now */
387 if (sih->ccrev != 42)
388 return NULL;
390 if ((nc = (nandregs_t *)si_setcore(sih, NS_NAND_CORE_ID, 0)) == NULL)
391 return NULL;
393 if (R_REG(NULL, &nc->flash_device_id) == 0)
394 return NULL;
396 if (!firsttime && nandcore.size)
397 return &nandcore;
399 osh = si_osh(sih);
400 bzero(&nandcore, sizeof(nandcore));
402 nandcore.sih = sih;
403 nandcore.core = (void *)nc;
404 nandcore.wrap = si_wrapperregs(sih);
405 nandcore.read = nandcore_read;
406 nandcore.write = nandcore_write;
407 nandcore.erase = nandcore_erase;
408 nandcore.checkbadb = nandcore_checkbadb;
409 nandcore.markbadb = nandcore_mark_badb;
411 nandcore.read_oob = nandcore_read_oob;
412 #ifndef _CFE_
413 nandcore.dev_ready = nandcore_dev_ready;
414 nandcore.select_chip = nandcore_select_chip;
415 nandcore.cmdfunc = nandcore_cmdfunc;
416 nandcore.waitfunc = nandcore_waitfunc;
417 nandcore.write_oob = nandcore_write_oob;
418 nandcore.read_page = nandcore_read_page;
419 nandcore.write_page = nandcore_write_page;
420 nandcore.cmd_read_byte = nandcore_cmd_read_byte;
421 #endif
423 nandcore_cmd(osh, nc, NANDCMD_ID_RD);
424 if (nandcore_poll(sih, nc) < 0) {
425 return NULL;
428 ai = (aidmp_t *)nandcore.wrap;
430 /* Toggle as little endian */
431 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
433 id = R_REG(osh, &nc->flash_device_id);
434 id2 = R_REG(osh, &nc->flash_device_id_ext);
436 /* Toggle as big endian */
437 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
439 for (i = 0; i < 5; i++) {
440 if (i < 4)
441 nandcore.id[i] = (id >> (8*i)) & 0xff;
442 else
443 nandcore.id[i] = id2 & 0xff;
446 name = nandcore_check_id(nandcore.id);
447 if (name == NULL)
448 return NULL;
449 nandcore.type = nandcore.id[0];
451 ncf = R_REG(osh, &nc->config_cs0);
452 /* Page size (# of bytes) */
453 val = (ncf & NANDCF_CS0_PAGE_SIZE_MASK) >> NANDCF_CS0_PAGE_SIZE_SHIFT;
454 switch (val) {
455 case 0:
456 nandcore.pagesize = 512;
457 break;
458 case 1:
459 nandcore.pagesize = (1 << 10) * 2;
460 break;
461 case 2:
462 nandcore.pagesize = (1 << 10) * 4;
463 break;
464 case 3:
465 nandcore.pagesize = (1 << 10) * 8;
466 break;
468 /* Block size (# of bytes) */
469 val = (ncf & NANDCF_CS0_BLOCK_SIZE_MASK) >> NANDCF_CS0_BLOCK_SIZE_SHIFT;
470 switch (val) {
471 case 0:
472 nandcore.blocksize = (1 << 10) * 8;
473 break;
474 case 1:
475 nandcore.blocksize = (1 << 10) * 16;
476 break;
477 case 2:
478 nandcore.blocksize = (1 << 10) * 128;
479 break;
480 case 3:
481 nandcore.blocksize = (1 << 10) * 256;
482 break;
483 case 4:
484 nandcore.blocksize = (1 << 10) * 512;
485 break;
486 case 5:
487 nandcore.blocksize = (1 << 10) * 1024;
488 break;
489 case 6:
490 nandcore.blocksize = (1 << 10) * 2048;
491 break;
492 default:
493 printf("Unknown block size\n");
494 return NULL;
496 /* NAND flash size in MBytes */
497 val = (ncf & NANDCF_CS0_DEVICE_SIZE_MASK) >> NANDCF_CS0_DEVICE_SIZE_SHIFT;
498 nandcore.size = (1 << val) * 4;
500 /* Get Device I/O data bus width */
501 if (ncf & NANDCF_CS0_DEVICE_WIDTH)
502 nandcore.width = 1;
504 /* Spare size and Spare per sector (# of bytes) */
505 acc_control = R_REG(osh, &nc->acc_control_cs0);
506 if (acc_control & NANDAC_CS0_SECTOR_SIZE_1K) {
507 printf("Pin strapping error. Sector size 1K hasn't supported yet\n");
508 return NULL;
511 /* Check conflict between 1K sector and page size */
512 if (acc_control & NANDAC_CS0_SECTOR_SIZE_1K) {
513 /* NOTE: 1K sector is not yet supported. */
514 nandcore.sectorsize = 1024;
516 else
517 nandcore.sectorsize = 512;
519 if (nandcore.sectorsize == 1024 && nandcore.pagesize == 512) {
520 printf("Pin strapping error. Page size is 512, but sector size is 1024\n");
521 return NULL;
524 /* Get Spare size */
525 nandcore.sparesize = acc_control & NANDAC_CS0_SPARE_AREA_SIZE;
527 /* Get oob size, */
528 nandcore.oobsize = nandcore.sparesize * (nandcore.pagesize / NFL_SECTOR_SIZE);
530 /* Get ECC level */
531 nandcore.ecclevel = (acc_control & NANDAC_CS0_ECC_LEVEL_MASK) >> NANDAC_CS0_ECC_LEVEL_SHIFT;
532 if (nandcore.sectorsize == 1024)
533 nandcore.ecclevel *= 2;
535 nandcore.numblocks = (nandcore.size * (1 << 10)) / (nandcore.blocksize >> 10);
536 if (firsttime) {
537 printf("Found a %s NAND flash:\n", name);
538 printf("Total size: %uMB\n", nandcore.size);
539 printf("Block size: %uKB\n", (nandcore.blocksize >> 10));
540 printf("Page Size: %uB\n", nandcore.pagesize);
541 printf("OOB Size: %uB\n", nandcore.oobsize);
542 printf("Sector size: %uB\n", nandcore.sectorsize);
543 printf("Spare size: %uB\n", nandcore.sparesize);
544 printf("ECC level: %u-bit\n", nandcore.ecclevel);
545 printf("Device ID: 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x\n",
546 nandcore.id[0], nandcore.id[1], nandcore.id[2],
547 nandcore.id[3], nandcore.id[4]);
549 firsttime = FALSE;
551 /* Memory mapping */
552 nandcore.phybase = SI_NS_NANDFLASH;
553 nandcore.base = (uint32)REG_MAP(SI_NS_NANDFLASH, SI_FLASH_WINDOW);
555 #ifdef BCMDBG
556 /* Configuration readback */
557 printf("R_REG(cs_nand_select) = 0x%08x\n", R_REG(osh, &nc->cs_nand_select));
558 printf("R_REG(config_cs0) = 0x%08x\n", R_REG(osh, &nc->config_cs0));
559 printf("R_REG(acc_control_cs0) = 0x%08x\n", R_REG(osh, &nc->acc_control_cs0));
560 #endif /* BCMDBG */
562 return nandcore.size ? &nandcore : NULL;
565 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
566 static int
567 nandcore_read(hndnand_t *nfl, uint64 offset, uint len, uchar *buf)
569 osl_t *osh;
570 uint8 *to;
571 uint res;
572 uint32 herr = 0, serr = 0;
574 ASSERT(nfl->sih);
575 osh = si_osh(nfl->sih);
577 to = buf;
578 res = len;
580 while (res > 0) {
581 _nandcore_read_page(nfl, offset, to, NULL, TRUE, &herr, &serr);
583 res -= nfl->pagesize;
584 offset += nfl->pagesize;
585 to += nfl->pagesize;
588 return (len - res);
591 /* Poll for command completion. Returns zero when complete. */
592 static int
593 nandcore_poll(si_t *sih, nandregs_t *nc)
595 osl_t *osh;
596 int i;
597 uint32 pollmask;
599 ASSERT(sih);
600 osh = si_osh(sih);
602 pollmask = NANDIST_CTRL_READY | NANDIST_FLASH_READY;
603 for (i = 0; i < NANDF_RETRIES; i++) {
604 if ((R_REG(osh, &nc->intfc_status) & pollmask) == pollmask) {
605 return 0;
609 printf("%s: not ready\n", __FUNCTION__);
610 return -1;
613 /* Write len bytes starting at offset into buf. Returns number of bytes
614 * written.
616 static int
617 nandcore_write(hndnand_t *nfl, uint64 offset, uint len, const uchar *buf)
619 int ret = 0;
620 osl_t *osh;
621 uint res;
622 uint8 *from;
624 ASSERT(nfl->sih);
625 osh = si_osh(nfl->sih);
627 from = (uint8 *)buf;
628 res = len;
630 while (res > 0) {
631 ret = _nandcore_write_page(nfl, offset, from, NULL, TRUE);
632 if (ret < 0)
633 return ret;
635 res -= nfl->pagesize;
636 offset += nfl->pagesize;
637 from += nfl->pagesize;
640 if (ret)
641 return ret;
643 return (len - res);
646 /* Erase a region. Returns number of bytes scheduled for erasure.
647 * Caller should poll for completion.
649 static int
650 nandcore_erase(hndnand_t *nfl, uint64 offset)
652 si_t *sih = nfl->sih;
653 nandregs_t *nc = (nandregs_t *)nfl->core;
654 osl_t *osh;
655 int ret = -1;
656 uint8 status = 0;
657 uint32 reg;
659 ASSERT(sih);
661 osh = si_osh(sih);
662 if ((offset >> 20) >= nfl->size)
663 return -1;
664 if ((offset & (nfl->blocksize - 1)) != 0) {
665 return -1;
668 /* Disable WP */
669 AND_REG(osh, &nc->cs_nand_select, ~NANDCSEL_NAND_WP);
671 /* Set the block address for the following commands */
672 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
673 W_REG(osh, &nc->cmd_ext_address, (reg | (offset >> 32)));
675 W_REG(osh, &nc->cmd_address, offset);
676 nandcore_cmd(osh, nc, NANDCMD_BLOCK_ERASE);
677 if (nandcore_poll(sih, nc) < 0)
678 goto exit;
680 /* Check status */
681 W_REG(osh, &nc->cmd_start, NANDCMD_STATUS_RD);
682 if (nandcore_poll(sih, nc) < 0)
683 goto exit;
685 status = R_REG(osh, &nc->intfc_status) & NANDIST_STATUS;
686 if (status & 1)
687 goto exit;
689 ret = 0;
690 exit:
691 /* Enable WP */
692 OR_REG(osh, &nc->cs_nand_select, NANDCSEL_NAND_WP);
694 return ret;
697 static int
698 nandcore_checkbadb(hndnand_t *nfl, uint64 offset)
700 si_t *sih = nfl->sih;
701 nandregs_t *nc = (nandregs_t *)nfl->core;
702 aidmp_t *ai = (aidmp_t *)nfl->wrap;
703 osl_t *osh;
704 int i;
705 uint off;
706 uint32 nand_intfc_status;
707 int ret = 0;
708 uint32 reg;
710 ASSERT(sih);
712 osh = si_osh(sih);
713 if ((offset >> 20) >= nfl->size)
714 return -1;
715 if ((offset & (nfl->blocksize - 1)) != 0) {
716 return -1;
719 /* Set the block address for the following commands */
720 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
721 W_REG(osh, &nc->cmd_ext_address, (reg | (offset >> 32)));
723 for (i = 0; i < 2; i++) {
724 off = offset + (nfl->pagesize * i);
725 W_REG(osh, &nc->cmd_address, off);
726 nandcore_cmd(osh, nc, NANDCMD_SPARE_RD);
727 if (nandcore_poll(sih, nc) < 0) {
728 ret = -1;
729 goto exit;
731 nand_intfc_status = R_REG(osh, &nc->intfc_status) & NANDIST_SPARE_VALID;
732 if (nand_intfc_status != NANDIST_SPARE_VALID) {
733 ret = -1;
734 #ifdef BCMDBG
735 printf("%s: Spare is not valid\n", __FUNCTION__);
736 #endif
737 goto exit;
740 /* Toggle as little endian */
741 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
743 if ((R_REG(osh, &nc->spare_area_read_ofs[0]) & 0xff) != 0xff) {
744 ret = -1;
745 #ifdef BCMDBG
746 printf("%s: Bad Block (0x%llx)\n", __FUNCTION__, offset);
747 #endif
750 /* Toggle as big endian */
751 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
753 if (ret == -1)
754 break;
757 exit:
758 return ret;
761 static int
762 nandcore_mark_badb(hndnand_t *nfl, uint64 offset)
764 si_t *sih = nfl->sih;
765 nandregs_t *nc = (nandregs_t *)nfl->core;
766 aidmp_t *ai = (aidmp_t *)nfl->wrap;
767 osl_t *osh;
768 uint off;
769 int i, ret = 0;
770 uint32 reg;
772 ASSERT(sih);
774 osh = si_osh(sih);
775 if ((offset >> 20) >= nfl->size)
776 return -1;
777 if ((offset & (nfl->blocksize - 1)) != 0) {
778 return -1;
781 /* Disable WP */
782 AND_REG(osh, &nc->cs_nand_select, ~NANDCSEL_NAND_WP);
784 /* Set the block address for the following commands */
785 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
786 W_REG(osh, &nc->cmd_ext_address, (reg | (offset >> 32)));
788 /* Erase block */
789 W_REG(osh, &nc->cmd_address, offset);
790 nandcore_cmd(osh, nc, NANDCMD_BLOCK_ERASE);
791 if (nandcore_poll(sih, nc) < 0) {
792 ret = -1;
793 /* Still go through the spare area write */
794 /* goto err; */
798 * Enable partial page programming and disable ECC checkbit generation
799 * for PROGRAM_SPARE_AREA
801 reg = R_REG(osh, &nc->acc_control_cs0);
802 reg |= NANDAC_CS0_PARTIAL_PAGE_EN;
803 reg |= NANDAC_CS0_FAST_PGM_RDIN;
804 reg &= ~NANDAC_CS0_WR_ECC_EN;
805 W_REG(osh, &nc->acc_control_cs0, reg);
807 for (i = 0; i < 2; i++) {
808 off = offset + (nfl->pagesize * i);
809 W_REG(osh, &nc->cmd_address, off);
811 /* Toggle as little endian */
812 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
814 W_REG(osh, &nc->spare_area_write_ofs[0], 0);
815 W_REG(osh, &nc->spare_area_write_ofs[1], 0);
816 W_REG(osh, &nc->spare_area_write_ofs[2], 0);
817 W_REG(osh, &nc->spare_area_write_ofs[3], 0);
819 /* Toggle as big endian */
820 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
822 nandcore_cmd(osh, nc, NANDCMD_SPARE_PROG);
823 if (nandcore_poll(sih, nc) < 0) {
824 ret = -1;
825 #if BCMDBG
826 printf("%s: Spare program is not ready\n", __FUNCTION__);
827 #endif
828 goto err;
832 err:
833 /* Restore the default value for spare area write registers */
834 W_REG(osh, &nc->spare_area_write_ofs[0], 0xffffffff);
835 W_REG(osh, &nc->spare_area_write_ofs[1], 0xffffffff);
836 W_REG(osh, &nc->spare_area_write_ofs[2], 0xffffffff);
837 W_REG(osh, &nc->spare_area_write_ofs[3], 0xffffffff);
840 * Disable partial page programming and enable ECC checkbit generation
841 * for PROGRAM_SPARE_AREA
843 reg = R_REG(osh, &nc->acc_control_cs0);
844 reg &= ~NANDAC_CS0_PARTIAL_PAGE_EN;
845 reg &= ~NANDAC_CS0_FAST_PGM_RDIN;
846 reg |= NANDAC_CS0_WR_ECC_EN;
847 W_REG(osh, &nc->acc_control_cs0, reg);
849 /* Enable WP */
850 OR_REG(osh, &nc->cs_nand_select, NANDCSEL_NAND_WP);
852 return ret;
856 #ifndef _CFE_
857 /* Functions support brcmnand driver */
858 static void
859 _nandcore_set_cmd_address(hndnand_t *nfl, uint64 addr)
861 uint32 reg;
862 osl_t *osh;
863 si_t *sih = nfl->sih;
864 nandregs_t *nc = (nandregs_t *)nfl->core;
866 ASSERT(sih);
867 osh = si_osh(sih);
869 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
870 W_REG(osh, &nc->cmd_ext_address, (reg | (addr >> 32)));
871 W_REG(osh, &nc->cmd_address, addr);
874 static int
875 nandcore_dev_ready(hndnand_t *nfl)
877 aidmp_t *ai = (aidmp_t *)nfl->wrap;
879 ASSERT(nfl->sih);
881 return (R_REG(si_osh(nfl->sih), &ai->iostatus) & NAND_RO_CTRL_READY);
884 static int
885 nandcore_select_chip(hndnand_t *nfl, int chip)
887 uint32 reg;
888 osl_t *osh;
889 si_t *sih = nfl->sih;
890 nandregs_t *nc = (nandregs_t *)nfl->core;
892 ASSERT(sih);
893 osh = si_osh(sih);
895 reg = R_REG(osh, &nc->cmd_ext_address);
896 reg &= ~NANDCMD_CS_SEL_MASK;
897 reg |= (chip << NANDCMD_CS_SEL_SHIFT);
898 W_REG(osh, &nc->cmd_ext_address, reg);
900 /* Set active chip index */
901 nfl->chipidx = chip;
903 return 0;
906 static int
907 nandcore_cmdfunc(hndnand_t *nfl, uint64 addr, int cmd)
909 int ret = 0;
910 osl_t *osh;
911 nandregs_t *nc = (nandregs_t *)nfl->core;
913 ASSERT(nfl->sih);
914 osh = si_osh(nfl->sih);
916 switch (cmd) {
917 case CMDFUNC_ERASE1:
918 _nandcore_set_cmd_address(nfl, addr);
919 break;
920 case CMDFUNC_ERASE2:
921 /* Disable WP */
922 AND_REG(osh, &nc->cs_nand_select, ~NANDCSEL_NAND_WP);
923 nandcore_cmd(osh, nc, NANDCMD_BLOCK_ERASE);
924 ret = nandcore_waitfunc(nfl, NULL);
925 /* Enable WP */
926 OR_REG(osh, &nc->cs_nand_select, NANDCSEL_NAND_WP);
927 break;
928 case CMDFUNC_SEQIN:
929 _nandcore_set_cmd_address(nfl, addr);
930 break;
931 case CMDFUNC_READ:
932 _nandcore_set_cmd_address(nfl, addr);
933 nandcore_cmd(osh, nc, NANDCMD_PAGE_RD);
934 ret = nandcore_waitfunc(nfl, NULL);
935 break;
936 case CMDFUNC_RESET:
937 nandcore_cmd(osh, nc, NANDCMD_FLASH_RESET);
938 ret = nandcore_waitfunc(nfl, NULL);
939 break;
940 case CMDFUNC_READID:
941 nandcore_cmd(osh, nc, NANDCMD_ID_RD);
942 ret = nandcore_waitfunc(nfl, NULL);
943 break;
944 case CMDFUNC_STATUS:
945 /* Disable WP */
946 AND_REG(osh, &nc->cs_nand_select, ~NANDCSEL_NAND_WP);
947 nandcore_cmd(osh, nc, NANDCMD_STATUS_RD);
948 ret = nandcore_waitfunc(nfl, NULL);
949 /* Enable WP */
950 OR_REG(osh, &nc->cs_nand_select, NANDCSEL_NAND_WP);
951 break;
952 case CMDFUNC_READOOB:
953 break;
954 default:
955 #ifdef BCMDBG
956 printf("%s: Unknow command 0x%x\n", __FUNCTION__, cmd);
957 #endif
958 ret = -1;
959 break;
962 return ret;
965 /* Return intfc_status FLASH_STATUS if CTRL/FLASH is ready otherwise -1 */
966 static int
967 nandcore_waitfunc(hndnand_t *nfl, int *status)
969 int ret;
970 osl_t *osh;
971 nandregs_t *nc = (nandregs_t *)nfl->core;
973 ASSERT(nfl->sih);
974 osh = si_osh(nfl->sih);
976 ret = nandcore_poll(nfl->sih, nc);
977 if (ret == 0 && status)
978 *status = R_REG(osh, &nc->intfc_status) & NANDIST_STATUS;
980 return ret;
983 #endif
985 #ifdef _CFE_
986 static int
987 ffs(int i)
989 int j;
991 if (i != 0)
992 for (j = 0; j < 32; j++)
993 if (i & (1 << j))
994 return j + 1;
995 return 0;
997 #endif
999 static int
1000 nandcore_read_oob(hndnand_t *nfl, uint64 addr, uint8 *oob)
1002 osl_t *osh;
1003 si_t *sih = nfl->sih;
1004 nandregs_t *nc = (nandregs_t *)nfl->core;
1005 aidmp_t *ai = (aidmp_t *)nfl->wrap;
1006 uint32 reg, *to;
1007 unsigned spare_per_sec, sector;
1008 int i, sectorsize_shift, sec_per_page_shift;
1010 ASSERT(sih);
1011 osh = si_osh(sih);
1013 /* Set the page address for the following commands */
1014 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
1015 W_REG(osh, &nc->cmd_ext_address, (reg | (addr >> 32)));
1017 /* Cal shift */
1018 sectorsize_shift = ffs(nfl->sectorsize) - 1;
1019 sec_per_page_shift = ffs(nfl->pagesize) - 1 - sectorsize_shift;
1021 spare_per_sec = nfl->oobsize >> sec_per_page_shift;
1023 /* Disable ECC validation for spare area reads */
1024 AND_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0,
1025 ~NANDAC_CS0_RD_ECC_EN);
1027 /* Loop all sectors in page */
1028 for (sector = 0; sector < (1 << sec_per_page_shift); sector ++) {
1029 unsigned col;
1031 col = (sector << sectorsize_shift);
1033 /* Issue command to read partial page */
1034 W_REG(osh, &nc->cmd_address, addr + col);
1036 nandcore_cmd(osh, nc, NANDCMD_SPARE_RD);
1038 /* Wait for the command to complete */
1039 if (nandcore_poll(sih, nc))
1040 return -1;
1042 if (!(R_REG(osh, &nc->intfc_status) & NANDIST_SPARE_VALID)) {
1043 printf("%s: data not valid\n", __FUNCTION__);
1044 return -1;
1047 /* Set controller to Little Endian mode for copying */
1048 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
1050 to = (uint32 *)(oob + sector * spare_per_sec);
1051 for (i = 0; i < spare_per_sec; i += 4, to++)
1052 *to = R_REG(osh, &nc->spare_area_read_ofs[i/4]);
1054 /* Return to Big Endian mode for commands etc */
1055 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
1058 return 0;
1061 #ifndef _CFE_
1062 static int
1063 nandcore_write_oob(hndnand_t *nfl, uint64 addr, uint8 *oob)
1065 osl_t *osh;
1066 si_t *sih = nfl->sih;
1067 nandregs_t *nc = (nandregs_t *)nfl->core;
1068 aidmp_t *ai = (aidmp_t *)nfl->wrap;
1069 uint32 reg, *from;
1070 unsigned spare_per_sec, sector, num_sec;
1071 int i, sectorsize_shift, sec_per_page_shift;
1072 int ret = 0;
1074 ASSERT(sih);
1075 osh = si_osh(sih);
1077 /* Disable WP */
1078 AND_REG(osh, &nc->cs_nand_select, ~NANDCSEL_NAND_WP);
1081 * Enable partial page programming and disable ECC checkbit generation
1082 * for PROGRAM_SPARE_AREA
1084 reg = R_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0);
1085 reg |= NANDAC_CS0_PARTIAL_PAGE_EN;
1086 reg |= NANDAC_CS0_FAST_PGM_RDIN;
1087 reg &= ~NANDAC_CS0_WR_ECC_EN;
1088 W_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0, reg);
1090 /* Cal shift */
1091 sectorsize_shift = _nandcore_ffs(nfl->sectorsize) - 1;
1092 sec_per_page_shift = _nandcore_ffs(nfl->pagesize) - 1 - sectorsize_shift;
1094 spare_per_sec = nfl->oobsize >> sec_per_page_shift;
1096 /* Set the page address for the following commands */
1097 reg = (R_REG(osh, &nc->cmd_ext_address) & ~NANDCMD_EXT_ADDR_MASK);
1098 W_REG(osh, &nc->cmd_ext_address, (reg | (addr >> 32)));
1100 num_sec = 1 << sec_per_page_shift;
1102 /* Loop all sectors in page */
1103 for (sector = 0; sector < num_sec; sector ++) {
1104 unsigned col;
1106 /* Spare area accessed by the data sector offset */
1107 col = (sector << sectorsize_shift);
1109 W_REG(osh, &nc->cmd_address, addr + col);
1111 /* Set controller to Little Endian mode for copying */
1112 OR_REG(osh, &ai->ioctrl, NAND_APB_LITTLE_ENDIAN);
1114 from = (uint32 *)(oob + sector * spare_per_sec);
1115 for (i = 0; i < spare_per_sec; i += 4, from++)
1116 W_REG(osh, &nc->spare_area_write_ofs[i/4], *from);
1118 /* Return to Big Endian mode for commands etc */
1119 AND_REG(osh, &ai->ioctrl, ~NAND_APB_LITTLE_ENDIAN);
1121 /* Push spare bytes into internal buffer, last goes to flash */
1122 nandcore_cmd(osh, nc, NANDCMD_SPARE_PROG);
1124 if (nandcore_poll(sih, nc)) {
1125 ret = -1;
1126 goto err;
1130 err:
1132 * Disable partial page programming and enable ECC checkbit generation
1133 * for PROGRAM_SPARE_AREA
1135 reg = R_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0);
1136 reg &= ~NANDAC_CS0_PARTIAL_PAGE_EN;
1137 reg &= ~NANDAC_CS0_FAST_PGM_RDIN;
1138 reg |= NANDAC_CS0_WR_ECC_EN;
1139 W_REG(osh, nfl->chipidx ? &nc->acc_control_cs1 : &nc->acc_control_cs0, reg);
1141 /* Enable WP */
1142 OR_REG(osh, &nc->cs_nand_select, NANDCSEL_NAND_WP);
1144 return ret;
1147 static int
1148 nandcore_read_page(hndnand_t *nfl, uint64 addr, uint8 *buf, uint8 *oob, bool ecc,
1149 uint32 *herr, uint32 *serr)
1151 return _nandcore_read_page(nfl, addr, buf, oob, ecc, herr, serr);
1154 static int
1155 nandcore_write_page(hndnand_t *nfl, uint64 addr, const uint8 *buf, uint8 *oob, bool ecc)
1157 return _nandcore_write_page(nfl, addr, buf, oob, ecc);
1160 static int
1161 nandcore_cmd_read_byte(hndnand_t *nfl, int cmd, int arg)
1163 int id_ext = arg;
1164 osl_t *osh;
1165 nandregs_t *nc = (nandregs_t *)nfl->core;
1167 ASSERT(nfl->sih);
1168 osh = si_osh(nfl->sih);
1170 switch (cmd) {
1171 case CMDFUNC_READID:
1172 return R_REG(osh, id_ext ? &nc->flash_device_id_ext : &nc->flash_device_id);
1173 case CMDFUNC_STATUS:
1174 return (R_REG(osh, &nc->intfc_status) & NANDIST_STATUS);
1175 default:
1176 #ifdef BCMDBG
1177 printf("%s: Unknow command 0x%x\n", __FUNCTION__, cmd);
1178 #endif
1179 break;
1182 return 0;
1184 #endif /* !_CFE_ */