diff options
author | Richard Genoud <richard.genoud@gmail.com> | 2008-10-12 02:42:28 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-14 06:07:57 -0400 |
commit | 3fc2389847a84d06263c13a3b6dfe1f1d6eea935 (patch) | |
tree | c63f13a5b79950a390538c34132416f2d3b894c3 /drivers/mtd/nand/atmel_nand.c | |
parent | 08d790432906b3815a1dc91a826ca85ff2a73b6c (diff) |
[MTD] [NAND] Bug on atmel_nand HW ECC : OOB info not correctly written
The functions that write the OOB info (on hardware ECC only) use the
HW_SYNDROME method.
This is not correct : the start position is "pos = eccsize + chunk" and
should be eccsize. So, the standard (nand_write_oob_std) function should
be used. This patch corrects this by using NAND_ECC_HW instead of
NAND_ECC_HW_SYNDROME.
This has only been tested on small pages nand flash.
(if anyone can test it on large pages that would be great).
kernel version : 2.6.27-rc2 (current git mtd-2.6)
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/atmel_nand.c')
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 58 |
1 files changed, 6 insertions, 52 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 3387e0d5076b..c98c1570a40b 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -174,48 +174,6 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) | |||
174 | } | 174 | } |
175 | 175 | ||
176 | /* | 176 | /* |
177 | * write oob for small pages | ||
178 | */ | ||
179 | static int atmel_nand_write_oob_512(struct mtd_info *mtd, | ||
180 | struct nand_chip *chip, int page) | ||
181 | { | ||
182 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | ||
183 | int eccsize = chip->ecc.size, length = mtd->oobsize; | ||
184 | int len, pos, status = 0; | ||
185 | const uint8_t *bufpoi = chip->oob_poi; | ||
186 | |||
187 | pos = eccsize + chunk; | ||
188 | |||
189 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); | ||
190 | len = min_t(int, length, chunk); | ||
191 | chip->write_buf(mtd, bufpoi, len); | ||
192 | bufpoi += len; | ||
193 | length -= len; | ||
194 | if (length > 0) | ||
195 | chip->write_buf(mtd, bufpoi, length); | ||
196 | |||
197 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
198 | status = chip->waitfunc(mtd, chip); | ||
199 | |||
200 | return status & NAND_STATUS_FAIL ? -EIO : 0; | ||
201 | |||
202 | } | ||
203 | |||
204 | /* | ||
205 | * read oob for small pages | ||
206 | */ | ||
207 | static int atmel_nand_read_oob_512(struct mtd_info *mtd, | ||
208 | struct nand_chip *chip, int page, int sndcmd) | ||
209 | { | ||
210 | if (sndcmd) { | ||
211 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
212 | sndcmd = 0; | ||
213 | } | ||
214 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
215 | return sndcmd; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Calculate HW ECC | 177 | * Calculate HW ECC |
220 | * | 178 | * |
221 | * function called after a write | 179 | * function called after a write |
@@ -235,14 +193,14 @@ static int atmel_nand_calculate(struct mtd_info *mtd, | |||
235 | /* get the first 2 ECC bytes */ | 193 | /* get the first 2 ECC bytes */ |
236 | ecc_value = ecc_readl(host->ecc, PR); | 194 | ecc_value = ecc_readl(host->ecc, PR); |
237 | 195 | ||
238 | ecc_code[eccpos[0]] = ecc_value & 0xFF; | 196 | ecc_code[0] = ecc_value & 0xFF; |
239 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; | 197 | ecc_code[1] = (ecc_value >> 8) & 0xFF; |
240 | 198 | ||
241 | /* get the last 2 ECC bytes */ | 199 | /* get the last 2 ECC bytes */ |
242 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; | 200 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; |
243 | 201 | ||
244 | ecc_code[eccpos[2]] = ecc_value & 0xFF; | 202 | ecc_code[2] = ecc_value & 0xFF; |
245 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; | 203 | ecc_code[3] = (ecc_value >> 8) & 0xFF; |
246 | 204 | ||
247 | return 0; | 205 | return 0; |
248 | } | 206 | } |
@@ -476,14 +434,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
476 | res = -EIO; | 434 | res = -EIO; |
477 | goto err_ecc_ioremap; | 435 | goto err_ecc_ioremap; |
478 | } | 436 | } |
479 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; | 437 | nand_chip->ecc.mode = NAND_ECC_HW; |
480 | nand_chip->ecc.calculate = atmel_nand_calculate; | 438 | nand_chip->ecc.calculate = atmel_nand_calculate; |
481 | nand_chip->ecc.correct = atmel_nand_correct; | 439 | nand_chip->ecc.correct = atmel_nand_correct; |
482 | nand_chip->ecc.hwctl = atmel_nand_hwctl; | 440 | nand_chip->ecc.hwctl = atmel_nand_hwctl; |
483 | nand_chip->ecc.read_page = atmel_nand_read_page; | 441 | nand_chip->ecc.read_page = atmel_nand_read_page; |
484 | nand_chip->ecc.bytes = 4; | 442 | nand_chip->ecc.bytes = 4; |
485 | nand_chip->ecc.prepad = 0; | ||
486 | nand_chip->ecc.postpad = 0; | ||
487 | } | 443 | } |
488 | 444 | ||
489 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 445 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
@@ -514,7 +470,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
514 | goto err_scan_ident; | 470 | goto err_scan_ident; |
515 | } | 471 | } |
516 | 472 | ||
517 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { | 473 | if (nand_chip->ecc.mode == NAND_ECC_HW) { |
518 | /* ECC is calculated for the whole page (1 step) */ | 474 | /* ECC is calculated for the whole page (1 step) */ |
519 | nand_chip->ecc.size = mtd->writesize; | 475 | nand_chip->ecc.size = mtd->writesize; |
520 | 476 | ||
@@ -522,8 +478,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
522 | switch (mtd->writesize) { | 478 | switch (mtd->writesize) { |
523 | case 512: | 479 | case 512: |
524 | nand_chip->ecc.layout = &atmel_oobinfo_small; | 480 | nand_chip->ecc.layout = &atmel_oobinfo_small; |
525 | nand_chip->ecc.read_oob = atmel_nand_read_oob_512; | ||
526 | nand_chip->ecc.write_oob = atmel_nand_write_oob_512; | ||
527 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); | 481 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); |
528 | break; | 482 | break; |
529 | case 1024: | 483 | case 1024: |