2 * Broadcom chipcommon NAND flash interface
4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved.
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.
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: nflash.c 300516 2011-12-04 17:39:44Z $
34 #define NFL_MSG(args) printf args
39 #define NF_RETRIES 1000000
41 #define NF_SMALL_BADBLOCK_POS 5
42 #define NF_LARGE_BADBLOCK_POS 0
44 /* Private global state */
45 static struct nflash nflash
;
47 /* Private variables used for BCM4706 only */
48 static uint32 nflash_col_mask
;
49 static uint32 nflash_row_shift
;
52 void nflash_enable(si_t
*sih
, int enable
)
54 if (sih
->ccrev
== 38) {
55 /* BCM5357 NAND boot */
56 if ((sih
->chipst
& (1 << 4)) != 0)
60 si_pmu_chipcontrol(sih
, 1, CCTRL5357_NFLASH
, CCTRL5357_NFLASH
);
62 si_pmu_chipcontrol(sih
, 1, CCTRL5357_NFLASH
, 0);
66 /* Issue a nand flash control command; this is used for BCM4706 */
68 nflash_ctrlcmd(osl_t
*osh
, chipcregs_t
*cc
, uint ctrlcode
)
72 W_REG(osh
, &cc
->nflashctrl
, ctrlcode
| NFC_START
);
74 while ((R_REG(osh
, &cc
->nflashctrl
) & NFC_START
) != 0) {
75 if (++cnt
> NF_RETRIES
) {
76 printf("nflash_ctrlcmd: not ready\n");
84 /* Issue a nand flash command */
86 nflash_cmd(osl_t
*osh
, chipcregs_t
*cc
, uint opcode
)
88 W_REG(osh
, &cc
->nand_cmd_start
, opcode
);
89 /* read after write to flush the command */
90 R_REG(osh
, &cc
->nand_cmd_start
);
93 static bool firsttime
= TRUE
;
95 static char *nflash_check_id(uint8
*id
)
98 char *value
; /* J++ */
105 case NFL_VENDOR_NUMONYX
:
108 case NFL_VENDOR_MICRON
:
111 case NFL_VENDOR_TOSHIBA
:
114 case NFL_VENDOR_HYNIX
:
117 case NFL_VENDOR_SAMSUNG
:
122 printf("No NAND flash type found\n");
124 value
= nvram_get("bootflags");
125 if (!value
|| (int) bcm_atoi(value
) != 1)
129 value
= nvram_get("ntype");
133 ntype
= (int) bcm_atoi(value
);
136 // printf("NAND type: %d\n", ntype);
158 printf("No NAND flash type found\n");
168 /* Initialize nand flash access */
170 nflash_init(si_t
*sih
, chipcregs_t
*cc
)
180 /* Only support chipcommon revision == 38 and BCM4706 for now */
181 if ((CHIPID(sih
->chip
) != BCM4706_CHIP_ID
) && (sih
->ccrev
!= 38))
184 /* Check if nand flash is mounted */
185 if ((sih
->cccaps
& CC_CAP_NFLASH
) != CC_CAP_NFLASH
)
188 if (!firsttime
&& nflash
.size
)
192 bzero(&nflash
, sizeof(nflash
));
194 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
195 uint32 cpu_freq
, clk
;
196 uint32 w0
, w1
, w2
, w3
, w4
;
197 uint32 ctrlcode
, val
;
198 uint32 totbits
= 0, colbits
= 0, rowbits
;
199 uint32 colbsize
, rowbsize
;
200 uint32 oobsz_per_sector
, plane_sz
, plane_num
;
202 /* Enable nand flash interface of BCM4706 (usign CS1) */
203 val
= R_REG(osh
, &cc
->eci
.flashconf
.flashstrconfig
) | FLSTRCF4706_NF1
;
204 W_REG(osh
, &cc
->eci
.flashconf
.flashstrconfig
, val
);
206 /* Configure nand flash bus timing */
207 if (R_REG(osh
, &cc
->chipstatus
) & CST4706_PKG_OPTION
) {
208 cpu_freq
= (400000000 / 4);
210 /* Get N divider to determine CPU clock */
211 W_REG(osh
, &cc
->pllcontrol_addr
, 4);
212 val
= (R_REG(osh
, &cc
->pllcontrol_data
) & 0xfff) >> 3;
214 /* Fixed reference clock 25MHz and m = 2 */
215 cpu_freq
= (val
* 25000000 / 2) / 4;
218 clk
= cpu_freq
/ 1000000;
222 w2
= NFLASH_T_CS
- NFLASH_T_WP
;
226 w0
= nflash_ns_to_cycle(w0
, clk
);
227 w1
= nflash_ns_to_cycle(w1
, clk
);
228 w2
= nflash_ns_to_cycle(w2
, clk
);
229 w3
= nflash_ns_to_cycle(w3
, clk
);
230 w4
= nflash_ns_to_cycle(w4
, clk
) - 1;
232 val
= (w4
<< NFLASH_WAITCOUNT_W4_SHIFT
) | (w3
<< NFLASH_WAITCOUNT_W3_SHIFT
)
233 | (w2
<< NFLASH_WAITCOUNT_W2_SHIFT
)
234 | (w1
<< NFLASH_WAITCOUNT_W1_SHIFT
) | w0
;
235 W_REG(osh
, &cc
->nflashwaitcnt0
, val
);
237 /* Read nand flash ID */
238 ctrlcode
= NFC_CSA
| NFC_SPECADDR
| NFC_CMD1W
| NFC_CMD0
| NFCTRL_ID
;
240 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
243 for (i
= 0; i
< 5; i
++) {
245 ctrlcode
= (NFC_CSA
| NFC_1BYTE
| NFC_DREAD
);
247 ctrlcode
= (NFC_1BYTE
| NFC_DREAD
);
249 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
252 nflash
.id
[i
] = R_REG(osh
, &cc
->nflashdata
) & 0xff;
255 name
= nflash_check_id(nflash
.id
);
257 /* Disable nand flash interface of BCM4706 (usign CS1) */
258 val
= R_REG(osh
, &cc
->eci
.flashconf
.flashstrconfig
) & ~FLSTRCF4706_NF1
;
259 W_REG(osh
, &cc
->eci
.flashconf
.flashstrconfig
, val
);
263 nflash
.type
= nflash
.id
[0];
265 /* In unit of bytes */
266 nflash
.pagesize
= 1024 << (nflash
.id
[3] & 0x3);
267 nflash
.blocksize
= (64 * 1024) << ((nflash
.id
[3] >> 4) & 0x3);
269 oobsz_per_sector
= (8 << ((nflash
.id
[3] >> 2) & 0x1));
270 nflash
.oobsize
= oobsz_per_sector
* (nflash
.pagesize
/ NFL_SECTOR_SIZE
);
272 /* In unit of MBytes */
273 plane_sz
= (8 << ((nflash
.id
[4] >> 4) & 0x7));
274 plane_num
= (1 << ((nflash
.id
[4] >> 2) & 0x3));
275 nflash
.size
= plane_sz
* plane_num
;
277 for (i
= 0; i
< 32; i
++) {
278 if ((0x1 << i
) == nflash
.size
) {
286 NFL_MSG(("nflash_init: failed to find nflash total bits\n"));
291 for (i
= 0; i
< 32; i
++) {
292 if ((0x1 << i
) == nflash
.pagesize
) {
293 colbits
= i
+ 1; /* including spare oob bytes */
300 NFL_MSG(("nflash_init: failed to find nflash column address bits\n"));
305 nflash_col_mask
= (0x1 << colbits
) - 1;
306 nflash_row_shift
= colbits
;
308 colbsize
= (colbits
+ 7) / 8;
310 rowbits
= totbits
- colbits
+ 1;
311 rowbsize
= (rowbits
+ 7) / 8;
313 val
= ((rowbsize
- 1) << NFCF_ROWSZ_SHIFT
) | ((colbsize
- 1) << NFCF_COLSZ_SHIFT
)
314 | NFCF_DS_8
| NFCF_WE
;
316 W_REG(osh
, &cc
->nflashconf
, val
);
318 nflash_enable(sih
, 1);
319 nflash_cmd(osh
, cc
, NCMD_ID_RD
);
320 if (nflash_poll(sih
, cc
) < 0) {
321 nflash_enable(sih
, 0);
324 nflash_enable(sih
, 0);
325 id
= R_REG(osh
, &cc
->nand_devid
);
326 id2
= R_REG(osh
, &cc
->nand_devid_x
);
327 for (i
= 0; i
< 5; i
++) {
329 nflash
.id
[i
] = (id
>> (8*i
)) & 0xff;
331 nflash
.id
[i
] = id2
& 0xff;
334 name
= nflash_check_id(nflash
.id
);
337 nflash
.type
= nflash
.id
[0];
339 ncf
= R_REG(osh
, &cc
->nand_config
);
340 /* Page size (# of bytes) */
341 val
= (ncf
& NCF_PAGE_SIZE_MASK
) >> NCF_PAGE_SIZE_SHIFT
;
344 nflash
.pagesize
= 512;
347 nflash
.pagesize
= (1 << 10) * 2;
350 nflash
.pagesize
= (1 << 10) * 4;
353 nflash
.pagesize
= (1 << 10) * 8;
356 /* Block size (# of bytes) */
357 val
= (ncf
& NCF_BLOCK_SIZE_MASK
) >> NCF_BLOCK_SIZE_SHIFT
;
360 nflash
.blocksize
= (1 << 10) * 16;
363 nflash
.blocksize
= (1 << 10) * 128;
366 nflash
.blocksize
= (1 << 10) * 8;
369 nflash
.blocksize
= (1 << 10) * 512;
372 nflash
.blocksize
= (1 << 10) * 256;
375 printf("Unknown block size\n");
378 /* NAND flash size in MBytes */
379 val
= (ncf
& NCF_DEVICE_SIZE_MASK
) >> NCF_DEVICE_SIZE_SHIFT
;
381 printf("Unknown flash size\n");
384 nflash
.size
= (1 << (val
- 1)) * 8;
386 /* More attribues for ECC functions */
387 acc_control
= R_REG(osh
, &cc
->nand_acc_control
);
388 nflash
.ecclevel
= (acc_control
& NAC_ECC_LEVEL_MASK
) >> NAC_ECC_LEVEL_SHIFT
;
389 nflash
.ecclevel0
= (acc_control
& NAC_ECC_LEVEL0_MASK
) >> NAC_ECC_LEVEL0_SHIFT
;
390 /* make sure that block-0 and block-n use the same ECC level */
391 if (nflash
.ecclevel
!= nflash
.ecclevel0
) {
392 acc_control
&= ~(NAC_ECC_LEVEL_MASK
| NAC_ECC_LEVEL0_MASK
);
394 (nflash
.ecclevel0
<< NAC_ECC_LEVEL0_SHIFT
) |
395 (nflash
.ecclevel0
<< NAC_ECC_LEVEL_SHIFT
);
396 W_REG(osh
, &cc
->nand_acc_control
, acc_control
);
397 nflash
.ecclevel
= nflash
.ecclevel0
;
401 nflash
.numblocks
= (nflash
.size
* (1 << 10)) / (nflash
.blocksize
>> 10);
403 printf("Found a %s NAND flash with %uB pages or %dKB blocks; total size %dMB\n",
404 name
, nflash
.pagesize
, (nflash
.blocksize
>> 10), nflash
.size
);
406 return nflash
.size
? &nflash
: NULL
;
409 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
411 nflash_read(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
421 mask
= NFL_SECTOR_SIZE
- 1;
422 if ((offset
& mask
) != 0 || (len
& mask
) != 0)
424 if ((((offset
+ len
) >> 20) > nflash
.size
) ||
425 ((((offset
+ len
) >> 20) == nflash
.size
) &&
426 (((offset
+ len
) & ((1 << 20) - 1)) != 0)))
432 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
433 uint32 page_addr
, page_offset
;
437 page_offset
= offset
& (nflash
.pagesize
- 1);
438 page_addr
= (offset
& ~(nflash
.pagesize
- 1)) * 2;
439 page_addr
+= page_offset
;
441 W_REG(osh
, &cc
->nflashcoladdr
, page_addr
& nflash_col_mask
);
442 W_REG(osh
, &cc
->nflashrowaddr
, page_addr
>> nflash_row_shift
);
444 ctrlcode
= NFC_CSA
| NFC_CMD1W
| NFC_ROW
| NFC_COL
| NFC_CMD0
| NFCTRL_READ
;
446 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
449 if (nflash_poll(sih
, cc
) < 0)
452 for (i
= 0; i
< NFL_SECTOR_SIZE
; i
+= 4, to
++) {
453 if (i
< NFL_SECTOR_SIZE
- 4)
454 ctrlcode
= (NFC_CSA
| NFC_4BYTES
| NFC_DREAD
);
456 ctrlcode
= (NFC_4BYTES
| NFC_DREAD
);
458 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
461 *to
= R_REG(osh
, &cc
->nflashdata
);
464 res
-= NFL_SECTOR_SIZE
;
465 offset
+= NFL_SECTOR_SIZE
;
468 nflash_enable(sih
, 1);
470 W_REG(osh
, &cc
->nand_cmd_addr
, offset
);
471 nflash_cmd(osh
, cc
, NCMD_PAGE_RD
);
472 if (nflash_poll(sih
, cc
) < 0)
474 if (((val
= R_REG(osh
, &cc
->nand_intfc_status
)) & NIST_CACHE_VALID
) == 0)
476 W_REG(osh
, &cc
->nand_cache_addr
, 0);
477 for (i
= 0; i
< NFL_SECTOR_SIZE
; i
+= 4, to
++) {
478 *to
= R_REG(osh
, &cc
->nand_cache_data
);
481 res
-= NFL_SECTOR_SIZE
;
482 offset
+= NFL_SECTOR_SIZE
;
484 nflash_enable(sih
, 0);
490 /* Poll for command completion. Returns zero when complete. */
492 nflash_poll(si_t
*sih
, chipcregs_t
*cc
)
501 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
502 for (i
= 0; i
< NF_RETRIES
; i
++) {
503 if ((R_REG(osh
, &cc
->nflashctrl
) & NFC_RDYBUSY
) == NFC_RDYBUSY
) {
504 if ((R_REG(osh
, &cc
->nflashctrl
) & NFC_ERROR
) == NFC_ERROR
) {
505 printf("nflash_poll: error occurred\n");
513 pollmask
= NIST_CTRL_READY
|NIST_FLASH_READY
;
514 for (i
= 0; i
< NF_RETRIES
; i
++) {
515 if ((R_REG(osh
, &cc
->nand_intfc_status
) & pollmask
) == pollmask
) {
521 printf("nflash_poll: not ready\n");
525 /* Write len bytes starting at offset into buf. Returns number of bytes
529 nflash_write(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
541 mask
= nflash
.pagesize
- 1;
542 /* Check offset and length */
543 if ((offset
& mask
) != 0 || (len
& mask
) != 0)
545 if ((((offset
+ len
) >> 20) > nflash
.size
) ||
546 ((((offset
+ len
) >> 20) == nflash
.size
) &&
547 (((offset
+ len
) & ((1 << 20) - 1)) != 0)))
551 from
= (uint32
*)buf
;
554 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
559 page_addr
= (offset
& ~(nflash
.pagesize
- 1)) * 2;
561 W_REG(osh
, &cc
->nflashcoladdr
, page_addr
& nflash_col_mask
);
562 W_REG(osh
, &cc
->nflashrowaddr
, page_addr
>> nflash_row_shift
);
564 ctrlcode
= NFC_CSA
| NFC_ROW
| NFC_COL
| NFC_CMD0
| NFCTRL_PAGEPROG
;
566 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
569 for (i
= 0; i
< nflash
.pagesize
; i
+= 4, from
++) {
570 W_REG(osh
, &cc
->nflashdata
, *from
);
572 if (i
< nflash
.pagesize
- 4)
573 ctrlcode
= (NFC_CSA
| NFC_4BYTES
| NFC_DWRITE
);
575 ctrlcode
= (NFC_4BYTES
| NFC_DWRITE
);
577 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
581 if (nflash_ctrlcmd(osh
, cc
, (NFC_CMD0
| NFCTRL_PROGSTART
)) != 0)
584 if (nflash_poll(sih
, cc
) < 0)
587 if (nflash_readst(sih
, cc
, &status
) != 0)
591 printf("nflash_write: failed with status 0x%02x\n", status
);
595 res
-= nflash
.pagesize
;
596 offset
+= nflash
.pagesize
;
599 nflash_enable(sih
, 1);
600 /* disable partial page enable */
601 reg
= R_REG(osh
, &cc
->nand_acc_control
);
602 reg
&= ~NAC_PARTIAL_PAGE_EN
;
603 W_REG(osh
, &cc
->nand_acc_control
, reg
);
606 W_REG(osh
, &cc
->nand_cache_addr
, 0);
607 for (i
= 0; i
< nflash
.pagesize
; i
+= 4, from
++) {
609 W_REG(osh
, &cc
->nand_cmd_addr
, i
);
610 W_REG(osh
, &cc
->nand_cache_data
, *from
);
612 W_REG(osh
, &cc
->nand_cmd_addr
, offset
+ nflash
.pagesize
- 512);
613 nflash_cmd(osh
, cc
, NCMD_PAGE_PROG
);
614 if (nflash_poll(sih
, cc
) < 0)
618 W_REG(osh
, &cc
->nand_cmd_start
, NCMD_STATUS_RD
);
619 if (nflash_poll(sih
, cc
) < 0)
621 status
= R_REG(osh
, &cc
->nand_intfc_status
) & NIST_STATUS
;
626 res
-= nflash
.pagesize
;
627 offset
+= nflash
.pagesize
;
630 nflash_enable(sih
, 0);
638 /* Erase a region. Returns number of bytes scheduled for erasure.
639 * Caller should poll for completion.
642 nflash_erase(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
651 if ((offset
>> 20) >= nflash
.size
)
653 if ((offset
& (nflash
.blocksize
- 1)) != 0) {
657 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
661 row_addr
= (offset
& ~(nflash
.blocksize
- 1)) * 2;
663 W_REG(osh
, &cc
->nflashrowaddr
, row_addr
>> nflash_row_shift
);
665 ctrlcode
= (NFC_CMD1W
| NFC_ROW
| NFC_CMD0
| NFCTRL_ERASE
);
667 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
670 if (nflash_poll(sih
, cc
) < 0)
673 if (nflash_readst(sih
, cc
, &status
) != 0)
677 printf("nflash_erase: failed with status 0x%02x\n", status
);
681 nflash_enable(sih
, 1);
682 W_REG(osh
, &cc
->nand_cmd_addr
, offset
);
683 nflash_cmd(osh
, cc
, NCMD_BLOCK_ERASE
);
684 if (nflash_poll(sih
, cc
) < 0) {
689 W_REG(osh
, &cc
->nand_cmd_start
, NCMD_STATUS_RD
);
690 if (nflash_poll(sih
, cc
) < 0) {
694 status
= R_REG(osh
, &cc
->nand_intfc_status
) & NIST_STATUS
;
698 nflash_enable(sih
, 0);
705 nflash_checkbadb(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
710 uint32 nand_intfc_status
;
716 if ((offset
>> 20) >= nflash
.size
)
718 if ((offset
& (nflash
.blocksize
- 1)) != 0) {
722 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
723 uint8 oob_buf1
[8], oob_buf2
[8];
724 uint sec_page_offset
;
725 int status1
, status2
, badblk_pos
;
727 status1
= nflash_readoob(sih
, cc
, offset
, sizeof(oob_buf1
), oob_buf1
);
729 sec_page_offset
= offset
+ nflash
.pagesize
;
730 status2
= nflash_readoob(sih
, cc
, sec_page_offset
, sizeof(oob_buf2
), oob_buf2
);
732 if (status1
<= 0 || status2
<= 0)
735 /* Set the bad block position */
736 if (nflash
.pagesize
> 512)
737 badblk_pos
= NF_LARGE_BADBLOCK_POS
;
739 badblk_pos
= NF_SMALL_BADBLOCK_POS
;
741 if (oob_buf1
[badblk_pos
] != 0xff || oob_buf2
[badblk_pos
] != 0xff)
746 nflash_enable(sih
, 1);
747 for (i
= 0; i
< 2; i
++) {
748 off
= offset
+ (nflash
.pagesize
* i
);
749 W_REG(osh
, &cc
->nand_cmd_addr
, off
);
750 nflash_cmd(osh
, cc
, NCMD_SPARE_RD
);
751 if (nflash_poll(sih
, cc
) < 0) {
755 nand_intfc_status
= R_REG(osh
, &cc
->nand_intfc_status
) & NIST_SPARE_VALID
;
756 if (nand_intfc_status
!= NIST_SPARE_VALID
) {
760 if ((R_REG(osh
, &cc
->nand_spare_rd0
) & 0xff) != 0xff) {
766 nflash_enable(sih
, 0);
772 nflash_mark_badb(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
782 if ((offset
>> 20) >= nflash
.size
)
784 if ((offset
& (nflash
.blocksize
- 1)) != 0) {
788 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
789 unsigned char oob_buf
[128];
791 /* Force OOB write even nflash_erase return failure */
792 nflash_erase(sih
, cc
, offset
);
794 memset((void *)oob_buf
, 0, nflash
.oobsize
);
796 if (nflash_writeoob(sih
, cc
, offset
, nflash
.oobsize
, oob_buf
) < 0)
799 if (nflash_writeoob(sih
, cc
, offset
+ nflash
.pagesize
, nflash
.oobsize
, oob_buf
) < 0)
802 nflash_enable(sih
, 1);
804 W_REG(osh
, &cc
->nand_cmd_addr
, offset
);
805 nflash_cmd(osh
, cc
, NCMD_BLOCK_ERASE
);
806 if (nflash_poll(sih
, cc
) < 0) {
812 * Enable partial page programming and disable ECC checkbit generation
813 * for PROGRAM_SPARE_AREA
815 reg
= R_REG(osh
, &cc
->nand_acc_control
);
816 reg
|= NAC_PARTIAL_PAGE_EN
;
817 reg
&= ~NAC_WR_ECC_EN
;
818 W_REG(osh
, &cc
->nand_acc_control
, reg
);
820 for (i
= 0; i
< 2; i
++) {
821 off
= offset
+ (nflash
.pagesize
* i
);
822 W_REG(osh
, &cc
->nand_cmd_addr
, off
);
824 W_REG(osh
, &cc
->nand_spare_wr0
, 0);
825 W_REG(osh
, &cc
->nand_spare_wr4
, 0);
826 W_REG(osh
, &cc
->nand_spare_wr8
, 0);
827 W_REG(osh
, &cc
->nand_spare_wr12
, 0);
829 nflash_cmd(osh
, cc
, NCMD_SPARE_PROG
);
830 if (nflash_poll(sih
, cc
) < 0) {
836 /* Restore the default value for spare area write registers */
837 W_REG(osh
, &cc
->nand_spare_wr0
, 0xffffffff);
838 W_REG(osh
, &cc
->nand_spare_wr4
, 0xffffffff);
839 W_REG(osh
, &cc
->nand_spare_wr8
, 0xffffffff);
840 W_REG(osh
, &cc
->nand_spare_wr12
, 0xffffffff);
843 * Disable partial page programming and enable ECC checkbit generation
844 * for PROGRAM_SPARE_AREA
846 reg
= R_REG(osh
, &cc
->nand_acc_control
);
847 reg
&= ~NAC_PARTIAL_PAGE_EN
;
848 reg
|= NAC_WR_ECC_EN
;
849 W_REG(osh
, &cc
->nand_acc_control
, reg
);
851 nflash_enable(sih
, 0);
857 nflash_readst(si_t
*sih
, chipcregs_t
*cc
, uint8
*status
)
866 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
869 ctrlcode
= (NFC_CSA
| NFC_CMD0
| NFCTRL_STATUS
);
871 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
874 ctrlcode
= (NFC_1BYTE
| NFC_DREAD
);
876 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
879 *status
= (uint8
)(R_REG(osh
, &cc
->nflashdata
) & 0xff);
883 nflash_enable(sih
, 1);
884 W_REG(osh
, &cc
->nand_cmd_start
, NCMD_STATUS_RD
);
886 if (nflash_poll(sih
, cc
) < 0)
890 *status
= (uint8
)(R_REG(osh
, &cc
->nand_intfc_status
) & NIST_STATUS
);
892 nflash_enable(sih
, 0);
897 /* To read len bytes of oob data in the page specified in the page address offset */
899 nflash_readoob(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
909 mask
= nflash
.pagesize
- 1;
910 if ((offset
& mask
) != 0 || (len
> nflash
.oobsize
) || (len
& 0x3) != 0)
917 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
918 uint32 page_addr
, page_offset
;
921 page_addr
= (offset
& ~(nflash
.pagesize
- 1)) * 2;
922 page_offset
= nflash
.pagesize
;
923 page_addr
+= page_offset
;
925 W_REG(osh
, &cc
->nflashcoladdr
, page_addr
& nflash_col_mask
);
926 W_REG(osh
, &cc
->nflashrowaddr
, page_addr
>> nflash_row_shift
);
928 ctrlcode
= (NFC_CSA
| NFC_CMD1W
| NFC_ROW
| NFC_COL
| NFC_CMD0
| NFCTRL_READ
);
930 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
933 if (nflash_poll(sih
, cc
) < 0)
936 for (i
= 0; i
< len
; i
+= 4, to
++) {
938 ctrlcode
= (NFC_CSA
| NFC_4BYTES
| NFC_DREAD
);
940 ctrlcode
= (NFC_4BYTES
| NFC_DREAD
);
942 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
945 *to
= R_REG(osh
, &cc
->nflashdata
);
955 /* To write len bytes of oob data in the page specified in the page address offset */
957 nflash_writeoob(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
967 mask
= nflash
.pagesize
- 1;
968 if ((offset
& mask
) != 0 || (len
> nflash
.oobsize
) || (len
& 0x3) != 0)
972 from
= (uint32
*)buf
;
975 if (CHIPID(sih
->chip
) == BCM4706_CHIP_ID
) {
976 uint32 page_addr
, page_offset
;
980 page_addr
= (offset
& ~(nflash
.pagesize
- 1)) * 2;
981 page_offset
= nflash
.pagesize
;
982 page_addr
+= page_offset
;
984 W_REG(osh
, &cc
->nflashcoladdr
, page_addr
& nflash_col_mask
);
985 W_REG(osh
, &cc
->nflashrowaddr
, page_addr
>> nflash_row_shift
);
987 ctrlcode
= (NFC_CSA
| NFC_ROW
| NFC_COL
| NFC_CMD0
| NFCTRL_PAGEPROG
);
989 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
992 for (i
= 0; i
< len
; i
+= 4, from
++) {
993 W_REG(osh
, &cc
->nflashdata
, *from
);
996 ctrlcode
= (NFC_CSA
| NFC_4BYTES
| NFC_DWRITE
);
998 ctrlcode
= (NFC_4BYTES
| NFC_DWRITE
);
1000 if (nflash_ctrlcmd(osh
, cc
, ctrlcode
) != 0)
1006 if (nflash_ctrlcmd(osh
, cc
, (NFC_CMD0
| NFCTRL_PROGSTART
)) != 0)
1009 if (nflash_poll(sih
, cc
) < 0)
1012 if (nflash_readst(sih
, cc
, &status
) != 0)
1016 printf("nflash_writeoob: failed with status 0x%02x\n", status
);