f8472b49567a2d84d02ae26b64d71a402ba12593
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / mtd / nand / bcm_umi_bch.c
1 /*****************************************************************************
2 * Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
3 *
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").
8 *
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
12 * consent.
13 *****************************************************************************/
14
15 /* ---- Include Files ---------------------------------------------------- */
16 #include "nand_bcm_umi.h"
17
18 /* ---- External Variable Declarations ----------------------------------- */
19 /* ---- External Function Prototypes ------------------------------------- */
20 /* ---- Public Variables ------------------------------------------------- */
21 /* ---- Private Constants and Types -------------------------------------- */
22
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);
28
29 /* ---- Private Variables ------------------------------------------------ */
30
31 /*
32 ** nand_hw_eccoob
33 ** New oob placement block for use with hardware ecc generation.
34 */
35 static struct nand_ecclayout nand_hw_eccoob_512 = {
36 /* Reserve 5 for BI indicator */
37 .oobfree = {
38 #if (NAND_ECC_NUM_BYTES > 3)
39 {.offset = 0, .length = 2}
40 #else
41 {.offset = 0, .length = 5},
42 {.offset = 6, .length = 7}
43 #endif
44 }
45 };
46
47 /*
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.
50 */
51 static struct nand_ecclayout nand_hw_eccoob_2048 = {
52 /* Reserve 0 as BI indicator */
53 .oobfree = {
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}
61 #else
62 {.offset = 1, .length = 8},
63 {.offset = 16, .length = 9},
64 {.offset = 32, .length = 9},
65 {.offset = 48, .length = 9}
66 #endif
67 }
68 };
69
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 */
74 .oobfree = {
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}
84 #else
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}
93 #endif
94 }
95 };
96
97 /* ---- Private Functions ------------------------------------------------ */
98 /* ==== Public Functions ================================================= */
99
100 /****************************************************************************
101 *
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 *
107 ***************************************************************************/
108 static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
109 struct nand_chip *chip, uint8_t * buf,
110 int page)
111 {
112 int sectorIdx = 0;
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;
118 int stat;
119 unsigned int max_bitflips = 0;
120
121 for (sectorIdx = 0; sectorIdx < eccsteps;
122 sectorIdx++, datap += eccsize) {
123 if (sectorIdx > 0) {
124 /* Seek to page location within sector */
125 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
126 -1);
127 }
128
129 /* Enable hardware ECC before reading the buf */
130 nand_bcm_umi_bch_enable_read_hwecc();
131
132 /* Read in data */
133 bcm_umi_nand_read_buf(mtd, datap, eccsize);
134
135 /* Pause hardware ECC after reading the buf */
136 nand_bcm_umi_bch_pause_read_ecc_calc();
137
138 /* Read the OOB ECC */
139 chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
140 mtd->writesize + sectorIdx * sectorOobSize, -1);
141 nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
142 NAND_ECC_NUM_BYTES,
143 chip->oob_poi +
144 sectorIdx * sectorOobSize);
145
146 /* Correct any ECC detected errors */
147 stat =
148 nand_bcm_umi_bch_correct_page(datap, eccCalc,
149 NAND_ECC_NUM_BYTES);
150
151 /* Update Stats */
152 if (stat < 0) {
153 #if defined(NAND_BCM_UMI_DEBUG)
154 printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
155 __func__, sectorIdx);
156 printk(KERN_WARNING
157 "%s data %02x %02x %02x %02x "
158 "%02x %02x %02x %02x\n",
159 __func__, datap[0], datap[1], datap[2], datap[3],
160 datap[4], datap[5], datap[6], datap[7]);
161 printk(KERN_WARNING
162 "%s ecc %02x %02x %02x %02x "
163 "%02x %02x %02x %02x %02x %02x "
164 "%02x %02x %02x\n",
165 __func__, eccCalc[0], eccCalc[1], eccCalc[2],
166 eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
167 eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
168 eccCalc[11], eccCalc[12]);
169 BUG();
170 #endif
171 mtd->ecc_stats.failed++;
172 } else {
173 #if defined(NAND_BCM_UMI_DEBUG)
174 if (stat > 0) {
175 printk(KERN_INFO
176 "%s %d correctable_errors detected\n",
177 __func__, stat);
178 }
179 #endif
180 mtd->ecc_stats.corrected += stat;
181 max_bitflips = max_t(unsigned int, max_bitflips, stat);
182 }
183 }
184 return max_bitflips;
185 }
186
187 /****************************************************************************
188 *
189 * bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
190 * @mtd: mtd info structure
191 * @chip: nand chip info structure
192 * @buf: data buffer
193 *
194 ***************************************************************************/
195 static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
196 struct nand_chip *chip, const uint8_t *buf)
197 {
198 int sectorIdx = 0;
199 int eccsize = chip->ecc.size;
200 int eccsteps = chip->ecc.steps;
201 const uint8_t *datap = buf;
202 uint8_t *oobp = chip->oob_poi;
203 int sectorOobSize = mtd->oobsize / eccsteps;
204
205 for (sectorIdx = 0; sectorIdx < eccsteps;
206 sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
207 /* Enable hardware ECC before writing the buf */
208 nand_bcm_umi_bch_enable_write_hwecc();
209 bcm_umi_nand_write_buf(mtd, datap, eccsize);
210 nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
211 NAND_ECC_NUM_BYTES);
212 }
213
214 bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
215 }