95 lines
2.4 KiB
C
95 lines
2.4 KiB
C
#include <common.h>
|
|
#include <errno.h>
|
|
#include <clock.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/nand.h>
|
|
#include <linux/err.h>
|
|
#include <linux/mtd/nand_ecc.h>
|
|
#include <asm/byteorder.h>
|
|
#include <io.h>
|
|
#include <malloc.h>
|
|
|
|
#include "nand.h"
|
|
|
|
/**
|
|
* nand_read_page_swecc - [REPLACABLE] software ecc based page read function
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: buffer to store read data
|
|
*/
|
|
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
uint8_t *buf)
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccsteps = chip->ecc.steps;
|
|
uint8_t *p = buf;
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
chip->ecc.read_page_raw(mtd, chip, buf);
|
|
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
|
|
|
eccsteps = chip->ecc.steps;
|
|
p = buf;
|
|
|
|
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
|
int stat;
|
|
|
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
|
if (stat < 0)
|
|
mtd->ecc_stats.failed++;
|
|
else
|
|
mtd->ecc_stats.corrected += stat;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* nand_write_page_swecc - [REPLACABLE] software ecc based page write function
|
|
* @mtd: mtd info structure
|
|
* @chip: nand chip info structure
|
|
* @buf: data buffer
|
|
*/
|
|
#ifdef CONFIG_MTD_WRITE
|
|
static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|
const uint8_t *buf)
|
|
{
|
|
int i, eccsize = chip->ecc.size;
|
|
int eccbytes = chip->ecc.bytes;
|
|
int eccsteps = chip->ecc.steps;
|
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
|
const uint8_t *p = buf;
|
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
|
|
|
/* Software ecc calculation */
|
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
|
|
|
for (i = 0; i < chip->ecc.total; i++)
|
|
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
|
|
|
chip->ecc.write_page_raw(mtd, chip, buf);
|
|
}
|
|
#endif
|
|
|
|
void nand_init_ecc_soft(struct nand_chip *chip)
|
|
{
|
|
chip->ecc.calculate = nand_calculate_ecc;
|
|
chip->ecc.correct = nand_correct_data;
|
|
chip->ecc.read_page = nand_read_page_swecc;
|
|
chip->ecc.read_oob = nand_read_oob_std;
|
|
#ifdef CONFIG_MTD_WRITE
|
|
chip->ecc.write_page = nand_write_page_swecc;
|
|
chip->ecc.write_oob = nand_write_oob_std;
|
|
#endif
|
|
chip->ecc.size = 256;
|
|
chip->ecc.bytes = 3;
|
|
}
|