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 oob_required
, int page
);
26 static void bcm_umi_bch_write_page_hwecc(struct mtd_info
*mtd
,
27 struct nand_chip
*chip
, const uint8_t *buf
, int oob_required
);
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
106 * @oob_required: caller expects OOB data read to chip->oob_poi
108 ***************************************************************************/
109 static int bcm_umi_bch_read_page_hwecc(struct mtd_info
*mtd
,
110 struct nand_chip
*chip
, uint8_t * buf
,
111 int oob_required
, int page
)
114 int eccsize
= chip
->ecc
.size
;
115 int eccsteps
= chip
->ecc
.steps
;
116 uint8_t *datap
= buf
;
117 uint8_t eccCalc
[NAND_ECC_NUM_BYTES
];
118 int sectorOobSize
= mtd
->oobsize
/ eccsteps
;
120 unsigned int max_bitflips
= 0;
122 for (sectorIdx
= 0; sectorIdx
< eccsteps
;
123 sectorIdx
++, datap
+= eccsize
) {
125 /* Seek to page location within sector */
126 chip
->cmdfunc(mtd
, NAND_CMD_RNDOUT
, sectorIdx
* eccsize
,
130 /* Enable hardware ECC before reading the buf */
131 nand_bcm_umi_bch_enable_read_hwecc();
134 bcm_umi_nand_read_buf(mtd
, datap
, eccsize
);
136 /* Pause hardware ECC after reading the buf */
137 nand_bcm_umi_bch_pause_read_ecc_calc();
139 /* Read the OOB ECC */
140 chip
->cmdfunc(mtd
, NAND_CMD_RNDOUT
,
141 mtd
->writesize
+ sectorIdx
* sectorOobSize
, -1);
142 nand_bcm_umi_bch_read_oobEcc(mtd
->writesize
, eccCalc
,
145 sectorIdx
* sectorOobSize
);
147 /* Correct any ECC detected errors */
149 nand_bcm_umi_bch_correct_page(datap
, eccCalc
,
154 #if defined(NAND_BCM_UMI_DEBUG)
155 printk(KERN_WARNING
"%s uncorr_err sectorIdx=%d\n",
156 __func__
, sectorIdx
);
158 "%s data %02x %02x %02x %02x "
159 "%02x %02x %02x %02x\n",
160 __func__
, datap
[0], datap
[1], datap
[2], datap
[3],
161 datap
[4], datap
[5], datap
[6], datap
[7]);
163 "%s ecc %02x %02x %02x %02x "
164 "%02x %02x %02x %02x %02x %02x "
166 __func__
, eccCalc
[0], eccCalc
[1], eccCalc
[2],
167 eccCalc
[3], eccCalc
[4], eccCalc
[5], eccCalc
[6],
168 eccCalc
[7], eccCalc
[8], eccCalc
[9], eccCalc
[10],
169 eccCalc
[11], eccCalc
[12]);
172 mtd
->ecc_stats
.failed
++;
174 #if defined(NAND_BCM_UMI_DEBUG)
177 "%s %d correctable_errors detected\n",
181 mtd
->ecc_stats
.corrected
+= stat
;
182 max_bitflips
= max_t(unsigned int, max_bitflips
, stat
);
188 /****************************************************************************
190 * bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
191 * @mtd: mtd info structure
192 * @chip: nand chip info structure
194 * @oob_required: must write chip->oob_poi to OOB
196 ***************************************************************************/
197 static void bcm_umi_bch_write_page_hwecc(struct mtd_info
*mtd
,
198 struct nand_chip
*chip
, const uint8_t *buf
, int oob_required
)
201 int eccsize
= chip
->ecc
.size
;
202 int eccsteps
= chip
->ecc
.steps
;
203 const uint8_t *datap
= buf
;
204 uint8_t *oobp
= chip
->oob_poi
;
205 int sectorOobSize
= mtd
->oobsize
/ eccsteps
;
207 for (sectorIdx
= 0; sectorIdx
< eccsteps
;
208 sectorIdx
++, datap
+= eccsize
, oobp
+= sectorOobSize
) {
209 /* Enable hardware ECC before writing the buf */
210 nand_bcm_umi_bch_enable_write_hwecc();
211 bcm_umi_nand_write_buf(mtd
, datap
, eccsize
);
212 nand_bcm_umi_bch_write_oobEcc(mtd
->writesize
, oobp
,
216 bcm_umi_nand_write_buf(mtd
, chip
->oob_poi
, mtd
->oobsize
);