1 /*****************************************************************************
2 * Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
13 *****************************************************************************/
15 /* ---- Include Files ---------------------------------------------------- */
16 #include "nand_bcm_umi.h"
18 /* ---- External Variable Declarations ----------------------------------- */
19 /* ---- External Function Prototypes ------------------------------------- */
20 /* ---- Public Variables ------------------------------------------------- */
21 /* ---- Private Constants and Types -------------------------------------- */
23 /* ---- Private Function Prototypes -------------------------------------- */
24 static int bcm_umi_bch_read_page_hwecc(struct mtd_info
*mtd
,
25 struct nand_chip
*chip
, uint8_t *buf
, int page
);
26 static void bcm_umi_bch_write_page_hwecc(struct mtd_info
*mtd
,
27 struct nand_chip
*chip
, const uint8_t *buf
);
29 /* ---- Private Variables ------------------------------------------------ */
33 ** New oob placement block for use with hardware ecc generation.
35 static struct nand_ecclayout nand_hw_eccoob_512
= {
36 /* Reserve 5 for BI indicator */
38 #if (NAND_ECC_NUM_BYTES > 3)
39 {.offset
= 0, .length
= 2}
41 {.offset
= 0, .length
= 5},
42 {.offset
= 6, .length
= 7}
48 ** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
49 ** except the BI is at byte 0.
51 static struct nand_ecclayout nand_hw_eccoob_2048
= {
52 /* Reserve 0 as BI indicator */
54 #if (NAND_ECC_NUM_BYTES > 10)
55 {.offset
= 1, .length
= 2},
56 #elif (NAND_ECC_NUM_BYTES > 7)
57 {.offset
= 1, .length
= 5},
58 {.offset
= 16, .length
= 6},
59 {.offset
= 32, .length
= 6},
60 {.offset
= 48, .length
= 6}
62 {.offset
= 1, .length
= 8},
63 {.offset
= 16, .length
= 9},
64 {.offset
= 32, .length
= 9},
65 {.offset
= 48, .length
= 9}
70 /* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
71 * except the BI is at byte 0. */
72 static struct nand_ecclayout nand_hw_eccoob_4096
= {
73 /* Reserve 0 as BI indicator */
75 #if (NAND_ECC_NUM_BYTES > 10)
76 {.offset
= 1, .length
= 2},
77 {.offset
= 16, .length
= 3},
78 {.offset
= 32, .length
= 3},
79 {.offset
= 48, .length
= 3},
80 {.offset
= 64, .length
= 3},
81 {.offset
= 80, .length
= 3},
82 {.offset
= 96, .length
= 3},
83 {.offset
= 112, .length
= 3}
85 {.offset
= 1, .length
= 5},
86 {.offset
= 16, .length
= 6},
87 {.offset
= 32, .length
= 6},
88 {.offset
= 48, .length
= 6},
89 {.offset
= 64, .length
= 6},
90 {.offset
= 80, .length
= 6},
91 {.offset
= 96, .length
= 6},
92 {.offset
= 112, .length
= 6}
97 /* ---- Private Functions ------------------------------------------------ */
98 /* ==== Public Functions ================================================= */
100 /****************************************************************************
102 * bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
103 * @mtd: mtd info structure
104 * @chip: nand chip info structure
105 * @buf: buffer to store read data
107 ***************************************************************************/
108 static int bcm_umi_bch_read_page_hwecc(struct mtd_info
*mtd
,
109 struct nand_chip
*chip
, uint8_t * buf
,
113 int eccsize
= chip
->ecc
.size
;
114 int eccsteps
= chip
->ecc
.steps
;
115 uint8_t *datap
= buf
;
116 uint8_t eccCalc
[NAND_ECC_NUM_BYTES
];
117 int sectorOobSize
= mtd
->oobsize
/ eccsteps
;
120 for (sectorIdx
= 0; sectorIdx
< eccsteps
;
121 sectorIdx
++, datap
+= eccsize
) {
123 /* Seek to page location within sector */
124 chip
->cmdfunc(mtd
, NAND_CMD_RNDOUT
, sectorIdx
* eccsize
,
128 /* Enable hardware ECC before reading the buf */
129 nand_bcm_umi_bch_enable_read_hwecc();
132 bcm_umi_nand_read_buf(mtd
, datap
, eccsize
);
134 /* Pause hardware ECC after reading the buf */
135 nand_bcm_umi_bch_pause_read_ecc_calc();
137 /* Read the OOB ECC */
138 chip
->cmdfunc(mtd
, NAND_CMD_RNDOUT
,
139 mtd
->writesize
+ sectorIdx
* sectorOobSize
, -1);
140 nand_bcm_umi_bch_read_oobEcc(mtd
->writesize
, eccCalc
,
143 sectorIdx
* sectorOobSize
);
145 /* Correct any ECC detected errors */
147 nand_bcm_umi_bch_correct_page(datap
, eccCalc
,
152 #if defined(NAND_BCM_UMI_DEBUG)
153 printk(KERN_WARNING
"%s uncorr_err sectorIdx=%d\n",
154 __func__
, sectorIdx
);
156 "%s data %02x %02x %02x %02x "
157 "%02x %02x %02x %02x\n",
158 __func__
, datap
[0], datap
[1], datap
[2], datap
[3],
159 datap
[4], datap
[5], datap
[6], datap
[7]);
161 "%s ecc %02x %02x %02x %02x "
162 "%02x %02x %02x %02x %02x %02x "
164 __func__
, eccCalc
[0], eccCalc
[1], eccCalc
[2],
165 eccCalc
[3], eccCalc
[4], eccCalc
[5], eccCalc
[6],
166 eccCalc
[7], eccCalc
[8], eccCalc
[9], eccCalc
[10],
167 eccCalc
[11], eccCalc
[12]);
170 mtd
->ecc_stats
.failed
++;
172 #if defined(NAND_BCM_UMI_DEBUG)
175 "%s %d correctable_errors detected\n",
179 mtd
->ecc_stats
.corrected
+= stat
;
185 /****************************************************************************
187 * bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
188 * @mtd: mtd info structure
189 * @chip: nand chip info structure
192 ***************************************************************************/
193 static void bcm_umi_bch_write_page_hwecc(struct mtd_info
*mtd
,
194 struct nand_chip
*chip
, const uint8_t *buf
)
197 int eccsize
= chip
->ecc
.size
;
198 int eccsteps
= chip
->ecc
.steps
;
199 const uint8_t *datap
= buf
;
200 uint8_t *oobp
= chip
->oob_poi
;
201 int sectorOobSize
= mtd
->oobsize
/ eccsteps
;
203 for (sectorIdx
= 0; sectorIdx
< eccsteps
;
204 sectorIdx
++, datap
+= eccsize
, oobp
+= sectorOobSize
) {
205 /* Enable hardware ECC before writing the buf */
206 nand_bcm_umi_bch_enable_write_hwecc();
207 bcm_umi_nand_write_buf(mtd
, datap
, eccsize
);
208 nand_bcm_umi_bch_write_oobEcc(mtd
->writesize
, oobp
,
212 bcm_umi_nand_write_buf(mtd
, chip
->oob_poi
, mtd
->oobsize
);