diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/txx9ndfmc.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 488088eff2ca..73af8324d0d0 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c | |||
@@ -189,18 +189,43 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, | |||
189 | uint8_t *ecc_code) | 189 | uint8_t *ecc_code) |
190 | { | 190 | { |
191 | struct platform_device *dev = mtd_to_platdev(mtd); | 191 | struct platform_device *dev = mtd_to_platdev(mtd); |
192 | struct nand_chip *chip = mtd->priv; | ||
193 | int eccbytes; | ||
192 | u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); | 194 | u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); |
193 | 195 | ||
194 | mcr &= ~TXX9_NDFMCR_ECC_ALL; | 196 | mcr &= ~TXX9_NDFMCR_ECC_ALL; |
195 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); | 197 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); |
196 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR); | 198 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR); |
197 | ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR); | 199 | for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) { |
198 | ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR); | 200 | ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR); |
199 | ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR); | 201 | ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR); |
202 | ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR); | ||
203 | ecc_code += 3; | ||
204 | } | ||
200 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); | 205 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); |
201 | return 0; | 206 | return 0; |
202 | } | 207 | } |
203 | 208 | ||
209 | static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf, | ||
210 | unsigned char *read_ecc, unsigned char *calc_ecc) | ||
211 | { | ||
212 | struct nand_chip *chip = mtd->priv; | ||
213 | int eccsize; | ||
214 | int corrected = 0; | ||
215 | int stat; | ||
216 | |||
217 | for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) { | ||
218 | stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256); | ||
219 | if (stat < 0) | ||
220 | return stat; | ||
221 | corrected += stat; | ||
222 | buf += 256; | ||
223 | read_ecc += 3; | ||
224 | calc_ecc += 3; | ||
225 | } | ||
226 | return corrected; | ||
227 | } | ||
228 | |||
204 | static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) | 229 | static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) |
205 | { | 230 | { |
206 | struct platform_device *dev = mtd_to_platdev(mtd); | 231 | struct platform_device *dev = mtd_to_platdev(mtd); |
@@ -244,6 +269,22 @@ static void txx9ndfmc_initialize(struct platform_device *dev) | |||
244 | #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \ | 269 | #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \ |
245 | DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000) | 270 | DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000) |
246 | 271 | ||
272 | static int txx9ndfmc_nand_scan(struct mtd_info *mtd) | ||
273 | { | ||
274 | struct nand_chip *chip = mtd->priv; | ||
275 | int ret; | ||
276 | |||
277 | ret = nand_scan_ident(mtd, 1); | ||
278 | if (!ret) { | ||
279 | if (mtd->writesize >= 512) { | ||
280 | chip->ecc.size = mtd->writesize; | ||
281 | chip->ecc.bytes = 3 * (mtd->writesize / 256); | ||
282 | } | ||
283 | ret = nand_scan_tail(mtd); | ||
284 | } | ||
285 | return ret; | ||
286 | } | ||
287 | |||
247 | static int __init txx9ndfmc_probe(struct platform_device *dev) | 288 | static int __init txx9ndfmc_probe(struct platform_device *dev) |
248 | { | 289 | { |
249 | struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; | 290 | struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; |
@@ -321,9 +362,10 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) | |||
321 | chip->cmd_ctrl = txx9ndfmc_cmd_ctrl; | 362 | chip->cmd_ctrl = txx9ndfmc_cmd_ctrl; |
322 | chip->dev_ready = txx9ndfmc_dev_ready; | 363 | chip->dev_ready = txx9ndfmc_dev_ready; |
323 | chip->ecc.calculate = txx9ndfmc_calculate_ecc; | 364 | chip->ecc.calculate = txx9ndfmc_calculate_ecc; |
324 | chip->ecc.correct = nand_correct_data; | 365 | chip->ecc.correct = txx9ndfmc_correct_data; |
325 | chip->ecc.hwctl = txx9ndfmc_enable_hwecc; | 366 | chip->ecc.hwctl = txx9ndfmc_enable_hwecc; |
326 | chip->ecc.mode = NAND_ECC_HW; | 367 | chip->ecc.mode = NAND_ECC_HW; |
368 | /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */ | ||
327 | chip->ecc.size = 256; | 369 | chip->ecc.size = 256; |
328 | chip->ecc.bytes = 3; | 370 | chip->ecc.bytes = 3; |
329 | chip->chip_delay = 100; | 371 | chip->chip_delay = 100; |
@@ -349,7 +391,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) | |||
349 | if (plat->wide_mask & (1 << i)) | 391 | if (plat->wide_mask & (1 << i)) |
350 | chip->options |= NAND_BUSWIDTH_16; | 392 | chip->options |= NAND_BUSWIDTH_16; |
351 | 393 | ||
352 | if (nand_scan(mtd, 1)) { | 394 | if (txx9ndfmc_nand_scan(mtd)) { |
353 | kfree(txx9_priv->mtdname); | 395 | kfree(txx9_priv->mtdname); |
354 | kfree(txx9_priv); | 396 | kfree(txx9_priv); |
355 | continue; | 397 | continue; |