Merge git://git.denx.de/u-boot-nand-flash
This commit is contained in:
@@ -25,7 +25,7 @@ static int nand_block_op(enum dfu_op op, struct dfu_entity *dfu,
|
||||
loff_t start, lim;
|
||||
size_t count, actual;
|
||||
int ret;
|
||||
nand_info_t *nand;
|
||||
struct mtd_info *mtd;
|
||||
|
||||
/* if buf == NULL return total size of the area */
|
||||
if (buf == NULL) {
|
||||
@@ -39,16 +39,16 @@ static int nand_block_op(enum dfu_op op, struct dfu_entity *dfu,
|
||||
|
||||
if (nand_curr_device < 0 ||
|
||||
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
|
||||
!nand_info[nand_curr_device].name) {
|
||||
!nand_info[nand_curr_device]->name) {
|
||||
printf("%s: invalid nand device\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nand = &nand_info[nand_curr_device];
|
||||
mtd = nand_info[nand_curr_device];
|
||||
|
||||
if (op == DFU_OP_READ) {
|
||||
ret = nand_read_skip_bad(nand, start, &count, &actual,
|
||||
lim, buf);
|
||||
ret = nand_read_skip_bad(mtd, start, &count, &actual,
|
||||
lim, buf);
|
||||
} else {
|
||||
nand_erase_options_t opts;
|
||||
|
||||
@@ -59,12 +59,12 @@ static int nand_block_op(enum dfu_op op, struct dfu_entity *dfu,
|
||||
opts.quiet = 1;
|
||||
opts.lim = lim;
|
||||
/* first erase */
|
||||
ret = nand_erase_opts(nand, &opts);
|
||||
ret = nand_erase_opts(mtd, &opts);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* then write */
|
||||
ret = nand_write_skip_bad(nand, start, &count, &actual,
|
||||
lim, buf, WITH_WR_VERIFY);
|
||||
ret = nand_write_skip_bad(mtd, start, &count, &actual,
|
||||
lim, buf, WITH_WR_VERIFY);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
@@ -142,24 +142,24 @@ static int dfu_flush_medium_nand(struct dfu_entity *dfu)
|
||||
|
||||
/* in case of ubi partition, erase rest of the partition */
|
||||
if (dfu->data.nand.ubi) {
|
||||
nand_info_t *nand;
|
||||
struct mtd_info *mtd;
|
||||
nand_erase_options_t opts;
|
||||
|
||||
if (nand_curr_device < 0 ||
|
||||
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
|
||||
!nand_info[nand_curr_device].name) {
|
||||
!nand_info[nand_curr_device]->name) {
|
||||
printf("%s: invalid nand device\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nand = &nand_info[nand_curr_device];
|
||||
mtd = nand_info[nand_curr_device];
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.offset = dfu->data.nand.start + dfu->offset +
|
||||
dfu->bad_skip;
|
||||
opts.length = dfu->data.nand.start +
|
||||
dfu->data.nand.size - opts.offset;
|
||||
ret = nand_erase_opts(nand, &opts);
|
||||
ret = nand_erase_opts(mtd, &opts);
|
||||
if (ret != 0)
|
||||
printf("Failure erase: %d\n", ret);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ endif
|
||||
|
||||
obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
|
||||
obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
|
||||
obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
|
||||
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
|
||||
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
|
||||
obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
|
||||
@@ -50,7 +49,6 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
|
||||
obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
|
||||
obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
|
||||
obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o
|
||||
obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
|
||||
obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
|
||||
obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
|
||||
obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
|
||||
@@ -68,7 +66,6 @@ obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
|
||||
obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
|
||||
obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
|
||||
obj-$(CONFIG_NAND_PLAT) += nand_plat.o
|
||||
obj-$(CONFIG_NAND_DOCG4) += docg4.o
|
||||
|
||||
else # minimal SPL drivers
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
|
||||
static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
|
||||
nand_info_t nand_info[1];
|
||||
static struct mtd_info *mtd;
|
||||
static struct nand_chip nand_chip;
|
||||
|
||||
#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \
|
||||
@@ -30,12 +30,12 @@ static struct nand_chip nand_chip;
|
||||
static int nand_command(int block, int page, uint32_t offs,
|
||||
u8 cmd)
|
||||
{
|
||||
struct nand_chip *this = nand_info[0].priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
||||
void (*hwctrl)(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl) = this->cmd_ctrl;
|
||||
|
||||
while (!this->dev_ready(&nand_info[0]))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
/* Emulate NAND_CMD_READOOB */
|
||||
@@ -45,11 +45,11 @@ static int nand_command(int block, int page, uint32_t offs,
|
||||
}
|
||||
|
||||
/* Begin command latch cycle */
|
||||
hwctrl(&nand_info[0], cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
|
||||
if (cmd == NAND_CMD_RESET) {
|
||||
hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
while (!this->dev_ready(&nand_info[0]))
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
@@ -60,39 +60,39 @@ static int nand_command(int block, int page, uint32_t offs,
|
||||
|
||||
/* Set ALE and clear CLE to start address cycle */
|
||||
/* Column address */
|
||||
hwctrl(&nand_info[0], offs & 0xff,
|
||||
hwctrl(mtd, offs & 0xff,
|
||||
NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
|
||||
hwctrl(&nand_info[0], (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
|
||||
hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
|
||||
/* Row address */
|
||||
if (cmd != NAND_CMD_RNDOUT) {
|
||||
hwctrl(&nand_info[0], (page_addr & 0xff),
|
||||
hwctrl(mtd, (page_addr & 0xff),
|
||||
NAND_CTRL_ALE); /* A[19:12] */
|
||||
hwctrl(&nand_info[0], ((page_addr >> 8) & 0xff),
|
||||
hwctrl(mtd, ((page_addr >> 8) & 0xff),
|
||||
NAND_CTRL_ALE); /* A[27:20] */
|
||||
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
|
||||
/* One more address cycle for devices > 128MiB */
|
||||
hwctrl(&nand_info[0], (page_addr >> 16) & 0x0f,
|
||||
hwctrl(mtd, (page_addr >> 16) & 0x0f,
|
||||
NAND_CTRL_ALE); /* A[31:28] */
|
||||
#endif
|
||||
}
|
||||
|
||||
hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
if (cmd == NAND_CMD_READ0) {
|
||||
/* Latch in address */
|
||||
hwctrl(&nand_info[0], NAND_CMD_READSTART,
|
||||
hwctrl(mtd, NAND_CMD_READSTART,
|
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/*
|
||||
* Wait a while for the data to be ready
|
||||
*/
|
||||
while (!this->dev_ready(&nand_info[0]))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
} else if (cmd == NAND_CMD_RNDOUT) {
|
||||
hwctrl(&nand_info[0], NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE |
|
||||
hwctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE |
|
||||
NAND_CTRL_CHANGE);
|
||||
hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -100,7 +100,7 @@ static int nand_command(int block, int page, uint32_t offs,
|
||||
|
||||
static int nand_is_bad_block(int block)
|
||||
{
|
||||
struct nand_chip *this = nand_info[0].priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS,
|
||||
NAND_CMD_READOOB);
|
||||
@@ -121,7 +121,7 @@ static int nand_is_bad_block(int block)
|
||||
|
||||
static int nand_read_page(int block, int page, void *dst)
|
||||
{
|
||||
struct nand_chip *this = nand_info[0].priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char ecc_calc[ECCTOTAL];
|
||||
u_char ecc_code[ECCTOTAL];
|
||||
u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
|
||||
@@ -137,15 +137,15 @@ static int nand_read_page(int block, int page, void *dst)
|
||||
nand_command(block, page, 0, NAND_CMD_READ0);
|
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||
this->ecc.hwctl(&nand_info[0], NAND_ECC_READ);
|
||||
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||
nand_command(block, page, data_pos, NAND_CMD_RNDOUT);
|
||||
|
||||
this->read_buf(&nand_info[0], p, eccsize);
|
||||
this->read_buf(mtd, p, eccsize);
|
||||
|
||||
nand_command(block, page, oob_pos, NAND_CMD_RNDOUT);
|
||||
|
||||
this->read_buf(&nand_info[0], oob, eccbytes);
|
||||
this->ecc.calculate(&nand_info[0], p, &ecc_calc[i]);
|
||||
this->read_buf(mtd, oob, eccbytes);
|
||||
this->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
|
||||
data_pos += eccsize;
|
||||
oob_pos += eccbytes;
|
||||
@@ -164,7 +164,7 @@ static int nand_read_page(int block, int page, void *dst)
|
||||
* from correct_data(). We just hope that all possible errors
|
||||
* are corrected by this routine.
|
||||
*/
|
||||
this->ecc.correct(&nand_info[0], p, &ecc_code[i], &ecc_calc[i]);
|
||||
this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -223,13 +223,13 @@ void nand_init(void)
|
||||
/*
|
||||
* Init board specific nand support
|
||||
*/
|
||||
nand_info[0].priv = &nand_chip;
|
||||
mtd = &nand_chip.mtd;
|
||||
nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
|
||||
(void __iomem *)CONFIG_SYS_NAND_BASE;
|
||||
board_nand_init(&nand_chip);
|
||||
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&nand_info[0], 0);
|
||||
nand_chip.select_chip(mtd, 0);
|
||||
|
||||
/* NAND chip may require reset after power-on */
|
||||
nand_command(0, 0, 0, NAND_CMD_RESET);
|
||||
@@ -239,5 +239,5 @@ void nand_init(void)
|
||||
void nand_deselect(void)
|
||||
{
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&nand_info[0], -1);
|
||||
nand_chip.select_chip(mtd, -1);
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ static void arasan_nand_enable_ecc(void)
|
||||
static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd)
|
||||
{
|
||||
u8 addrcycles;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
switch (curr_cmd->addr_cycles) {
|
||||
case NAND_ADDR_CYCL_NONE:
|
||||
@@ -264,7 +264,7 @@ static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd)
|
||||
|
||||
static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 reg_val, i, pktsize, pktnum;
|
||||
u32 *bufptr = (u32 *)buf;
|
||||
u32 timeout;
|
||||
@@ -433,7 +433,8 @@ static void arasan_nand_fill_tx(const u8 *buf, int len)
|
||||
}
|
||||
|
||||
static int arasan_nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const u8 *buf, int oob_required)
|
||||
struct nand_chip *chip, const u8 *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
u32 reg_val, i, pktsize, pktnum;
|
||||
const u32 *bufptr = (const u32 *)buf;
|
||||
@@ -441,7 +442,7 @@ static int arasan_nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
u32 size = mtd->writesize;
|
||||
u32 rdcount = 0;
|
||||
u8 column_addr_cycles;
|
||||
struct arasan_nand_info *nand = chip->priv;
|
||||
struct arasan_nand_info *nand = nand_get_controller_data(chip);
|
||||
|
||||
if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
|
||||
pktsize = ARASAN_NAND_PKTSIZE_1K;
|
||||
@@ -944,7 +945,7 @@ static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size)
|
||||
|
||||
static u8 arasan_nand_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 size;
|
||||
u8 val;
|
||||
struct nand_onfi_params *p;
|
||||
@@ -976,8 +977,8 @@ static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
u32 i, ret = 0;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct arasan_nand_info *nand = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct arasan_nand_info *nand = nand_get_controller_data(chip);
|
||||
|
||||
curr_cmd = NULL;
|
||||
writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
|
||||
@@ -1033,7 +1034,7 @@ static int arasan_nand_ecc_init(struct mtd_info *mtd)
|
||||
{
|
||||
int found = -1;
|
||||
u32 regval, eccpos_start, i;
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.hwctl = NULL;
|
||||
@@ -1058,20 +1059,20 @@ static int arasan_nand_ecc_init(struct mtd_info *mtd)
|
||||
if (found < 0)
|
||||
return 1;
|
||||
|
||||
regval = ecc_matrix[i].eccaddr |
|
||||
(ecc_matrix[i].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
|
||||
(ecc_matrix[i].bch << ARASAN_NAND_ECC_BCH_SHIFT);
|
||||
regval = ecc_matrix[found].eccaddr |
|
||||
(ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
|
||||
(ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT);
|
||||
writel(regval, &arasan_nand_base->ecc_reg);
|
||||
|
||||
if (ecc_matrix[i].bch) {
|
||||
if (ecc_matrix[found].bch) {
|
||||
regval = readl(&arasan_nand_base->memadr_reg2);
|
||||
regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK;
|
||||
regval |= (ecc_matrix[i].bchval <<
|
||||
regval |= (ecc_matrix[found].bchval <<
|
||||
ARASAN_NAND_MEM_ADDR2_BCH_SHIFT);
|
||||
writel(regval, &arasan_nand_base->memadr_reg2);
|
||||
}
|
||||
|
||||
nand_oob.eccbytes = ecc_matrix[i].eccsize;
|
||||
nand_oob.eccbytes = ecc_matrix[found].eccsize;
|
||||
eccpos_start = mtd->oobsize - nand_oob.eccbytes;
|
||||
|
||||
for (i = 0; i < nand_oob.eccbytes; i++)
|
||||
@@ -1080,9 +1081,9 @@ static int arasan_nand_ecc_init(struct mtd_info *mtd)
|
||||
nand_oob.oobfree[0].offset = 2;
|
||||
nand_oob.oobfree[0].length = eccpos_start - 2;
|
||||
|
||||
nand_chip->ecc.size = ecc_matrix[i].ecc_codeword_size;
|
||||
nand_chip->ecc.strength = ecc_matrix[i].eccbits;
|
||||
nand_chip->ecc.bytes = ecc_matrix[i].eccsize;
|
||||
nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size;
|
||||
nand_chip->ecc.strength = ecc_matrix[found].eccbits;
|
||||
nand_chip->ecc.bytes = ecc_matrix[found].eccsize;
|
||||
nand_chip->ecc.layout = &nand_oob;
|
||||
|
||||
return 0;
|
||||
@@ -1101,9 +1102,8 @@ static int arasan_nand_init(struct nand_chip *nand_chip, int devnum)
|
||||
}
|
||||
|
||||
nand->nand_base = arasan_nand_base;
|
||||
mtd = &nand_info[0];
|
||||
nand_chip->priv = nand;
|
||||
mtd->priv = nand_chip;
|
||||
mtd = nand_to_mtd(nand_chip);
|
||||
nand_set_controller_data(nand_chip, nand);
|
||||
|
||||
/* Set the driver entry points for MTD */
|
||||
nand_chip->cmdfunc = arasan_nand_cmd_function;
|
||||
@@ -1134,7 +1134,7 @@ static int arasan_nand_init(struct nand_chip *nand_chip, int devnum)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (nand_register(devnum)) {
|
||||
if (nand_register(devnum, mtd)) {
|
||||
printf("Nand Register Fail\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -160,8 +160,8 @@ static int pmecc_data_alloc(struct atmel_nand_host *host)
|
||||
|
||||
static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
int i;
|
||||
uint32_t value;
|
||||
|
||||
@@ -177,8 +177,8 @@ static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
|
||||
|
||||
static void pmecc_substitute(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
int16_t __iomem *alpha_to = host->pmecc_alpha_to;
|
||||
int16_t __iomem *index_of = host->pmecc_index_of;
|
||||
int16_t *partial_syn = host->pmecc_partial_syn;
|
||||
@@ -227,8 +227,8 @@ static void pmecc_substitute(struct mtd_info *mtd)
|
||||
*/
|
||||
static void pmecc_get_sigma(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
int16_t *lmu = host->pmecc_lmu;
|
||||
int16_t *si = host->pmecc_si;
|
||||
@@ -383,8 +383,8 @@ static void pmecc_get_sigma(struct mtd_info *mtd)
|
||||
|
||||
static int pmecc_err_location(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
const int cap = host->pmecc_corr_cap;
|
||||
const int num = 2 * cap + 1;
|
||||
int sector_size = host->pmecc_sector_size;
|
||||
@@ -437,8 +437,8 @@ static int pmecc_err_location(struct mtd_info *mtd)
|
||||
static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
||||
int sector_num, int extra_bytes, int err_nbr)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
int i = 0;
|
||||
int byte_pos, bit_pos, sector_size, pos;
|
||||
uint32_t tmp;
|
||||
@@ -483,8 +483,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
||||
static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
|
||||
u8 *ecc)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
int i, err_nbr, eccbytes;
|
||||
uint8_t *buf_pos;
|
||||
|
||||
@@ -513,7 +513,7 @@ normal_check:
|
||||
if (err_nbr == -1) {
|
||||
dev_err(host->dev, "PMECC: Too many errors\n");
|
||||
mtd->ecc_stats.failed++;
|
||||
return -EIO;
|
||||
return -EBADMSG;
|
||||
} else {
|
||||
pmecc_correct_data(mtd, buf_pos, ecc, i,
|
||||
host->pmecc_bytes_per_sector, err_nbr);
|
||||
@@ -529,7 +529,7 @@ normal_check:
|
||||
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct atmel_nand_host *host = chip->priv;
|
||||
struct atmel_nand_host *host = nand_get_controller_data(chip);
|
||||
int eccsize = chip->ecc.size;
|
||||
uint8_t *oob = chip->oob_poi;
|
||||
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
||||
@@ -562,16 +562,16 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
stat = pmecc_readl(host->pmecc, isr);
|
||||
if (stat != 0)
|
||||
if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
|
||||
return -EIO;
|
||||
return -EBADMSG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required)
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct atmel_nand_host *host = chip->priv;
|
||||
struct atmel_nand_host *host = nand_get_controller_data(chip);
|
||||
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
||||
int i, j;
|
||||
int timeout = PMECC_MAX_TIMEOUT_US;
|
||||
@@ -615,8 +615,8 @@ out:
|
||||
|
||||
static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct atmel_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint32_t val = 0;
|
||||
struct nand_ecclayout *ecc_layout;
|
||||
|
||||
@@ -808,7 +808,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
|
||||
struct atmel_nand_host *host;
|
||||
int cap, sector_size;
|
||||
|
||||
host = nand->priv = &pmecc_host;
|
||||
host = &pmecc_host;
|
||||
nand_set_controller_data(nand, host);
|
||||
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.calculate = NULL;
|
||||
@@ -1080,7 +1081,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
|
||||
u_char *read_ecc, u_char *isnull)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
unsigned int ecc_status;
|
||||
unsigned int ecc_word, ecc_bit;
|
||||
|
||||
@@ -1111,7 +1112,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
|
||||
* We can't correct so many errors */
|
||||
dev_warn(host->dev, "atmel_nand : multiple errors detected."
|
||||
" Unable to correct.\n");
|
||||
return -EIO;
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* if there's a single bit error : we can correct it */
|
||||
@@ -1207,7 +1208,7 @@ int atmel_hwecc_nand_init_param(struct nand_chip *nand, struct mtd_info *mtd)
|
||||
static void at91_nand_hwcontrol(struct mtd_info *mtd,
|
||||
int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
|
||||
@@ -1238,17 +1239,17 @@ static int at91_nand_ready(struct mtd_info *mtd)
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
/* The following code is for SPL */
|
||||
static nand_info_t mtd;
|
||||
static struct mtd_info *mtd;
|
||||
static struct nand_chip nand_chip;
|
||||
|
||||
static int nand_command(int block, int page, uint32_t offs, u8 cmd)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
||||
void (*hwctrl)(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl) = this->cmd_ctrl;
|
||||
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
if (cmd == NAND_CMD_READOOB) {
|
||||
@@ -1256,24 +1257,24 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd)
|
||||
cmd = NAND_CMD_READ0;
|
||||
}
|
||||
|
||||
hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
|
||||
if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd))
|
||||
offs >>= 1;
|
||||
|
||||
hwctrl(&mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE);
|
||||
hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE);
|
||||
hwctrl(&mtd, ((page_addr >> 8) & 0xff), NAND_CTRL_ALE);
|
||||
hwctrl(mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE);
|
||||
hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE);
|
||||
hwctrl(mtd, ((page_addr >> 8) & 0xff), NAND_CTRL_ALE);
|
||||
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
|
||||
hwctrl(&mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE);
|
||||
hwctrl(mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE);
|
||||
#endif
|
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
hwctrl(&mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
return 0;
|
||||
@@ -1281,7 +1282,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd)
|
||||
|
||||
static int nand_is_bad_block(int block)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB);
|
||||
|
||||
@@ -1304,7 +1305,7 @@ static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
|
||||
|
||||
static int nand_read_page(int block, int page, void *dst)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char ecc_calc[ECCTOTAL];
|
||||
u_char ecc_code[ECCTOTAL];
|
||||
u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
|
||||
@@ -1317,11 +1318,11 @@ static int nand_read_page(int block, int page, void *dst)
|
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||
if (this->ecc.mode != NAND_ECC_SOFT)
|
||||
this->ecc.hwctl(&mtd, NAND_ECC_READ);
|
||||
this->read_buf(&mtd, p, eccsize);
|
||||
this->ecc.calculate(&mtd, p, &ecc_calc[i]);
|
||||
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||
this->read_buf(mtd, p, eccsize);
|
||||
this->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
}
|
||||
this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||
this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||
|
||||
for (i = 0; i < ECCTOTAL; i++)
|
||||
ecc_code[i] = oob_data[nand_ecc_pos[i]];
|
||||
@@ -1330,35 +1331,35 @@ static int nand_read_page(int block, int page, void *dst)
|
||||
p = dst;
|
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
||||
this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spl_nand_erase_one(int block, int page)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void (*hwctrl)(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl) = this->cmd_ctrl;
|
||||
int page_addr;
|
||||
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&mtd, 0);
|
||||
nand_chip.select_chip(mtd, 0);
|
||||
|
||||
page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
||||
hwctrl(&mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
/* Row address */
|
||||
hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
hwctrl(&mtd, ((page_addr >> 8) & 0xff),
|
||||
hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, ((page_addr >> 8) & 0xff),
|
||||
NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
|
||||
/* One more address cycle for devices > 128MiB */
|
||||
hwctrl(&mtd, (page_addr >> 16) & 0x0f,
|
||||
hwctrl(mtd, (page_addr >> 16) & 0x0f,
|
||||
NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
#endif
|
||||
hwctrl(&mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
nand_deselect();
|
||||
@@ -1368,10 +1369,10 @@ int spl_nand_erase_one(int block, int page)
|
||||
#else
|
||||
static int nand_read_page(int block, int page, void *dst)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
nand_command(block, page, 0, NAND_CMD_READ0);
|
||||
atmel_nand_pmecc_read_page(&mtd, this, dst, 0, page);
|
||||
atmel_nand_pmecc_read_page(mtd, this, dst, 0, page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1407,7 +1408,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
|
||||
|
||||
int at91_nand_wait_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
udelay(this->chip_delay);
|
||||
|
||||
@@ -1438,7 +1439,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
|
||||
#ifdef CONFIG_ATMEL_NAND_HWECC
|
||||
#ifdef CONFIG_ATMEL_NAND_HW_PMECC
|
||||
ret = atmel_pmecc_nand_init_params(nand, &mtd);
|
||||
ret = atmel_pmecc_nand_init_params(nand, mtd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1447,9 +1448,9 @@ int board_nand_init(struct nand_chip *nand)
|
||||
|
||||
void nand_init(void)
|
||||
{
|
||||
mtd.writesize = CONFIG_SYS_NAND_PAGE_SIZE;
|
||||
mtd.oobsize = CONFIG_SYS_NAND_OOBSIZE;
|
||||
mtd.priv = &nand_chip;
|
||||
mtd = &nand_chip.mtd;
|
||||
mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE;
|
||||
mtd->oobsize = CONFIG_SYS_NAND_OOBSIZE;
|
||||
nand_chip.IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE;
|
||||
nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE;
|
||||
board_nand_init(&nand_chip);
|
||||
@@ -1462,13 +1463,13 @@ void nand_init(void)
|
||||
#endif
|
||||
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&mtd, 0);
|
||||
nand_chip.select_chip(mtd, 0);
|
||||
}
|
||||
|
||||
void nand_deselect(void)
|
||||
{
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&mtd, -1);
|
||||
nand_chip.select_chip(mtd, -1);
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -1482,10 +1483,9 @@ static ulong base_addr[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
|
||||
int atmel_nand_chip_init(int devnum, ulong base_addr)
|
||||
{
|
||||
int ret;
|
||||
struct mtd_info *mtd = &nand_info[devnum];
|
||||
struct nand_chip *nand = &nand_chip[devnum];
|
||||
struct mtd_info *mtd = nand_to_mtd(nand);
|
||||
|
||||
mtd->priv = nand;
|
||||
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
|
||||
|
||||
#ifdef CONFIG_NAND_ECC_BCH
|
||||
@@ -1521,7 +1521,7 @@ int atmel_nand_chip_init(int devnum, ulong base_addr)
|
||||
|
||||
ret = nand_scan_tail(mtd);
|
||||
if (!ret)
|
||||
nand_register(devnum);
|
||||
nand_register(devnum, mtd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
*/
|
||||
static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
const u32 *nand = chip->IO_ADDR_R;
|
||||
|
||||
/* Make sure that buf is 32 bit aligned */
|
||||
@@ -99,7 +99,7 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
const u32 *nand = chip->IO_ADDR_W;
|
||||
|
||||
/* Make sure that buf is 32 bit aligned */
|
||||
@@ -144,7 +144,7 @@ static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
||||
static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
@@ -223,7 +223,7 @@ static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) |
|
||||
(read_ecc[2] << 16);
|
||||
u_int32_t ecc_calc = calc_ecc[0] | (calc_ecc[1] << 8) |
|
||||
@@ -243,7 +243,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
"%d\n", find_byte, find_bit);
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
} else if (!(diff & (diff - 1))) {
|
||||
/* Single bit ECC error in the ECC itself,
|
||||
@@ -254,7 +254,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
} else {
|
||||
/* Uncorrectable error */
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -380,10 +380,13 @@ static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
||||
|
||||
if (unlikely(raw))
|
||||
status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
|
||||
else
|
||||
status = chip->ecc.write_page(mtd, chip, buf, oob_required);
|
||||
if (unlikely(raw)) {
|
||||
status = chip->ecc.write_page_raw(mtd, chip, buf,
|
||||
oob_required, page);
|
||||
} else {
|
||||
status = chip->ecc.write_page(mtd, chip, buf,
|
||||
oob_required, page);
|
||||
}
|
||||
|
||||
if (status < 0) {
|
||||
ret = status;
|
||||
@@ -698,7 +701,7 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
|
||||
return 0;
|
||||
} else if (iserror == ECC_STATE_TOO_MANY_ERRS) {
|
||||
val = __raw_readl(&davinci_emif_regs->nanderrval1);
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16)
|
||||
|
||||
@@ -48,7 +48,10 @@ static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
|
||||
* this macro allows us to convert from an MTD structure to our own
|
||||
* device context (denali) structure.
|
||||
*/
|
||||
#define mtd_to_denali(m) container_of(m->priv, struct denali_nand_info, nand)
|
||||
static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
|
||||
{
|
||||
return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
|
||||
}
|
||||
|
||||
/*
|
||||
* These constants are defined by the driver to enable common driver
|
||||
@@ -865,7 +868,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* by write_page above.
|
||||
*/
|
||||
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
|
||||
@@ -889,7 +892,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* write_page() function above.
|
||||
*/
|
||||
static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
|
||||
@@ -988,7 +992,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
debug(" ECC error cause by erased block\n");
|
||||
/* false alarm, return the 0xFF */
|
||||
} else {
|
||||
return -EIO;
|
||||
return -EBADMSG;
|
||||
}
|
||||
}
|
||||
memcpy(buf, denali->buf.dma_buf, mtd->writesize);
|
||||
@@ -1173,13 +1177,13 @@ static struct nand_ecclayout nand_oob;
|
||||
|
||||
static int denali_init(struct denali_nand_info *denali)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(&denali->nand);
|
||||
int ret;
|
||||
|
||||
denali_hw_init(denali);
|
||||
|
||||
denali->mtd->name = "denali-nand";
|
||||
denali->mtd->owner = THIS_MODULE;
|
||||
denali->mtd->priv = &denali->nand;
|
||||
mtd->name = "denali-nand";
|
||||
mtd->owner = THIS_MODULE;
|
||||
|
||||
/* register the driver with the NAND core subsystem */
|
||||
denali->nand.select_chip = denali_select_chip;
|
||||
@@ -1193,7 +1197,7 @@ static int denali_init(struct denali_nand_info *denali)
|
||||
* this is the first stage in a two step process to register
|
||||
* with the nand subsystem
|
||||
*/
|
||||
if (nand_scan_ident(denali->mtd, denali->max_banks, NULL)) {
|
||||
if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
|
||||
ret = -ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1239,13 +1243,13 @@ static int denali_init(struct denali_nand_info *denali)
|
||||
nand_oob.eccbytes = denali->nand.ecc.bytes;
|
||||
denali->nand.ecc.layout = &nand_oob;
|
||||
|
||||
writel(denali->mtd->erasesize / denali->mtd->writesize,
|
||||
writel(mtd->erasesize / mtd->writesize,
|
||||
denali->flash_reg + PAGES_PER_BLOCK);
|
||||
writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
|
||||
denali->flash_reg + DEVICE_WIDTH);
|
||||
writel(denali->mtd->writesize,
|
||||
writel(mtd->writesize,
|
||||
denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
|
||||
writel(denali->mtd->oobsize,
|
||||
writel(mtd->oobsize,
|
||||
denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
|
||||
if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0)
|
||||
writel(1, denali->flash_reg + DEVICES_CONNECTED);
|
||||
@@ -1258,12 +1262,12 @@ static int denali_init(struct denali_nand_info *denali)
|
||||
denali->nand.ecc.read_oob = denali_read_oob;
|
||||
denali->nand.ecc.write_oob = denali_write_oob;
|
||||
|
||||
if (nand_scan_tail(denali->mtd)) {
|
||||
if (nand_scan_tail(mtd)) {
|
||||
ret = -ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = nand_register(0);
|
||||
ret = nand_register(0, mtd);
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
@@ -1277,13 +1281,6 @@ static int __board_nand_init(void)
|
||||
if (!denali)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* If CONFIG_SYS_NAND_SELF_INIT is defined, each driver is responsible
|
||||
* for instantiating struct nand_chip, while drivers/mtd/nand/nand.c
|
||||
* still provides a "struct mtd_info nand_info" instance.
|
||||
*/
|
||||
denali->mtd = &nand_info[0];
|
||||
|
||||
/*
|
||||
* In the future, these base addresses should be taken from
|
||||
* Device Tree or platform data.
|
||||
|
||||
@@ -436,7 +436,6 @@ struct nand_buf {
|
||||
#define DT 3
|
||||
|
||||
struct denali_nand_info {
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip nand;
|
||||
int flash_bank; /* currently selected chip */
|
||||
int status;
|
||||
|
||||
@@ -41,7 +41,7 @@ static int wait_for_irq(uint32_t irq_mask)
|
||||
|
||||
if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
|
||||
debug("Uncorrected ECC detected\n");
|
||||
return -EIO;
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
if (intr_status & irq_mask)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* SPL driver for Diskonchip G4 nand flash
|
||||
*
|
||||
* Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This driver basically mimics the load functionality of a typical IPL (initial
|
||||
* program loader) resident in the 2k NOR-like region of the docg4 that is
|
||||
* mapped to the reset vector. It allows the u-boot SPL to continue loading if
|
||||
* the IPL loads a fixed number of flash blocks that is insufficient to contain
|
||||
* the entire u-boot image. In this case, a concatenated spl + u-boot image is
|
||||
* written at the flash offset from which the IPL loads an image, and when the
|
||||
* IPL jumps to the SPL, the SPL resumes loading where the IPL left off. See
|
||||
* the palmtreo680 for an example.
|
||||
*
|
||||
* This driver assumes that the data was written to the flash using the device's
|
||||
* "reliable" mode, and also assumes that each 512 byte page is stored
|
||||
* redundantly in the subsequent page. This storage format is likely to be used
|
||||
* by all boards that boot from the docg4. The format compensates for the lack
|
||||
* of ecc in the IPL.
|
||||
*
|
||||
* Reliable mode reduces the capacity of a block by half, and the redundant
|
||||
* pages reduce it by half again. As a result, the normal 256k capacity of a
|
||||
* block is reduced to 64k for the purposes of the IPL/SPL.
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/mtd/docg4.h>
|
||||
|
||||
/* forward declarations */
|
||||
static inline void write_nop(void __iomem *docptr);
|
||||
static int poll_status(void __iomem *docptr);
|
||||
static void write_addr(void __iomem *docptr, uint32_t docg4_addr);
|
||||
static void address_sequence(unsigned int g4_page, unsigned int g4_index,
|
||||
void __iomem *docptr);
|
||||
static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr);
|
||||
|
||||
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
|
||||
{
|
||||
void *load_addr = dst;
|
||||
uint32_t flash_offset = offs;
|
||||
const unsigned int block_count =
|
||||
(size + DOCG4_BLOCK_CAPACITY_SPL - 1)
|
||||
/ DOCG4_BLOCK_CAPACITY_SPL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < block_count; i++) {
|
||||
int ret = docg4_load_block_reliable(flash_offset, load_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
load_addr += DOCG4_BLOCK_CAPACITY_SPL;
|
||||
flash_offset += DOCG4_BLOCK_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void write_nop(void __iomem *docptr)
|
||||
{
|
||||
writew(0, docptr + DOC_NOP);
|
||||
}
|
||||
|
||||
static int poll_status(void __iomem *docptr)
|
||||
{
|
||||
/*
|
||||
* Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
|
||||
* register. Operations known to take a long time (e.g., block erase)
|
||||
* should sleep for a while before calling this.
|
||||
*/
|
||||
|
||||
uint8_t flash_status;
|
||||
|
||||
/* hardware quirk requires reading twice initially */
|
||||
flash_status = readb(docptr + DOC_FLASHCONTROL);
|
||||
|
||||
do {
|
||||
flash_status = readb(docptr + DOC_FLASHCONTROL);
|
||||
} while (!(flash_status & DOC_CTRL_FLASHREADY));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void write_addr(void __iomem *docptr, uint32_t docg4_addr)
|
||||
{
|
||||
/* write the four address bytes packed in docg4_addr to the device */
|
||||
|
||||
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
|
||||
docg4_addr >>= 8;
|
||||
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
|
||||
docg4_addr >>= 8;
|
||||
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
|
||||
docg4_addr >>= 8;
|
||||
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
|
||||
}
|
||||
|
||||
static void address_sequence(unsigned int g4_page, unsigned int g4_index,
|
||||
void __iomem *docptr)
|
||||
{
|
||||
writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
|
||||
writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
|
||||
write_nop(docptr);
|
||||
write_addr(docptr, ((uint32_t)g4_page << 16) | g4_index);
|
||||
write_nop(docptr);
|
||||
}
|
||||
|
||||
static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr)
|
||||
{
|
||||
void __iomem *docptr = (void *)CONFIG_SYS_NAND_BASE;
|
||||
unsigned int g4_page = flash_offset >> 11; /* 2k page */
|
||||
const unsigned int last_g4_page = g4_page + 0x80; /* last in block */
|
||||
int g4_index = 0;
|
||||
uint16_t flash_status;
|
||||
uint16_t *buf;
|
||||
|
||||
/* flash_offset must be aligned to the start of a block */
|
||||
if (flash_offset & 0x3ffff)
|
||||
return -1;
|
||||
|
||||
writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
|
||||
writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
poll_status(docptr);
|
||||
write_nop(docptr);
|
||||
writew(0x45, docptr + DOC_FLASHSEQUENCE);
|
||||
writew(0xa3, docptr + DOC_FLASHCOMMAND);
|
||||
write_nop(docptr);
|
||||
writew(0x22, docptr + DOC_FLASHCOMMAND);
|
||||
write_nop(docptr);
|
||||
|
||||
/* read 1st 4 oob bytes of first subpage of block */
|
||||
address_sequence(g4_page, 0x0100, docptr); /* index at oob */
|
||||
write_nop(docptr);
|
||||
flash_status = readw(docptr + DOC_FLASHCONTROL);
|
||||
flash_status = readw(docptr + DOC_FLASHCONTROL);
|
||||
if (flash_status & 0x06) /* sequence or protection errors */
|
||||
return -1;
|
||||
writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
poll_status(docptr);
|
||||
writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
|
||||
/*
|
||||
* Here we read the first four oob bytes of the first page of the block.
|
||||
* The IPL on the palmtreo680 requires that this contain a 32 bit magic
|
||||
* number, or the load aborts. We'll ignore it.
|
||||
*/
|
||||
readw(docptr + 0x103c); /* hw quirk; 1st read discarded */
|
||||
readw(docptr + 0x103c); /* lower 16 bits of magic number */
|
||||
readw(docptr + DOCG4_MYSTERY_REG); /* upper 16 bits of magic number */
|
||||
writew(0, docptr + DOC_DATAEND);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
|
||||
/* load contents of block to memory */
|
||||
buf = (uint16_t *)dest_addr;
|
||||
do {
|
||||
int i;
|
||||
|
||||
address_sequence(g4_page, g4_index, docptr);
|
||||
writew(DOCG4_CMD_READ2,
|
||||
docptr + DOC_FLASHCOMMAND);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
poll_status(docptr);
|
||||
writew(DOC_ECCCONF0_READ_MODE |
|
||||
DOC_ECCCONF0_ECC_ENABLE |
|
||||
DOCG4_BCH_SIZE,
|
||||
docptr + DOC_ECCCONF0);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
|
||||
/* read the 512 bytes of page data, 2 bytes at a time */
|
||||
readw(docptr + 0x103c); /* hw quirk */
|
||||
for (i = 0; i < 256; i++)
|
||||
*buf++ = readw(docptr + 0x103c);
|
||||
|
||||
/* read oob, but discard it */
|
||||
for (i = 0; i < 7; i++)
|
||||
readw(docptr + 0x103c);
|
||||
readw(docptr + DOCG4_OOB_6_7);
|
||||
readw(docptr + DOCG4_OOB_6_7);
|
||||
|
||||
writew(0, docptr + DOC_DATAEND);
|
||||
write_nop(docptr);
|
||||
write_nop(docptr);
|
||||
|
||||
if (!(g4_index & 0x100)) {
|
||||
/* not redundant subpage read; check for ecc error */
|
||||
write_nop(docptr);
|
||||
flash_status = readw(docptr + DOC_ECCCONF1);
|
||||
flash_status = readw(docptr + DOC_ECCCONF1);
|
||||
if (flash_status & 0x80) { /* ecc error */
|
||||
g4_index += 0x108; /* read redundant subpage */
|
||||
buf -= 256; /* back up ram ptr */
|
||||
continue;
|
||||
} else /* no ecc error */
|
||||
g4_index += 0x210; /* skip redundant subpage */
|
||||
} else /* redundant page was just read; skip ecc error check */
|
||||
g4_index += 0x108;
|
||||
|
||||
if (g4_index == 0x420) { /* finished with 2k page */
|
||||
g4_index = 0;
|
||||
g4_page += 2; /* odd-numbered 2k pages skipped */
|
||||
}
|
||||
|
||||
} while (g4_page != last_g4_page); /* while still on same block */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -154,8 +154,8 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
||||
*/
|
||||
static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
fsl_lbc_t *lbc = ctrl->regs;
|
||||
int buf_num;
|
||||
@@ -194,8 +194,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
|
||||
*/
|
||||
static int fsl_elbc_run_command(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
fsl_lbc_t *lbc = ctrl->regs;
|
||||
u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
|
||||
@@ -246,7 +246,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
|
||||
|
||||
static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
fsl_lbc_t *lbc = ctrl->regs;
|
||||
|
||||
@@ -279,8 +279,8 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
|
||||
static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
fsl_lbc_t *lbc = ctrl->regs;
|
||||
|
||||
@@ -489,8 +489,8 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
|
||||
*/
|
||||
static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
unsigned int bufsize = mtd->writesize + mtd->oobsize;
|
||||
|
||||
@@ -526,8 +526,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
*/
|
||||
static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
|
||||
/* If there are still bytes in the FCM, then use the next byte. */
|
||||
@@ -543,8 +543,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
|
||||
*/
|
||||
static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
int avail;
|
||||
|
||||
@@ -566,7 +566,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
*/
|
||||
static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv = chip->priv;
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
||||
fsl_lbc_t *lbc = ctrl->regs;
|
||||
|
||||
@@ -611,7 +611,8 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* waitfunc.
|
||||
*/
|
||||
static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
@@ -626,7 +627,7 @@ static struct fsl_elbc_ctrl *elbc_ctrl;
|
||||
*/
|
||||
static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint32_t offset, uint32_t data_len,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
@@ -656,7 +657,7 @@ static void fsl_elbc_ctrl_init(void)
|
||||
|
||||
static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
{
|
||||
struct mtd_info *mtd = &nand_info[devnum];
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *nand;
|
||||
struct fsl_elbc_mtd *priv;
|
||||
uint32_t br = 0, or = 0;
|
||||
@@ -697,7 +698,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
}
|
||||
|
||||
nand = &priv->chip;
|
||||
mtd->priv = nand;
|
||||
mtd = nand_to_mtd(nand);
|
||||
|
||||
elbc_ctrl->chips[priv->bank] = priv;
|
||||
|
||||
@@ -719,7 +720,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||
|
||||
nand->controller = &elbc_ctrl->controller;
|
||||
nand->priv = priv;
|
||||
nand_set_controller_data(nand, priv);
|
||||
|
||||
nand->ecc.read_page = fsl_elbc_read_page;
|
||||
nand->ecc.write_page = fsl_elbc_write_page;
|
||||
@@ -787,7 +788,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_register(devnum);
|
||||
ret = nand_register(devnum, mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -222,8 +222,8 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
||||
*/
|
||||
static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
|
||||
int buf_num;
|
||||
@@ -247,8 +247,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
|
||||
static int is_blank(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
|
||||
unsigned int bufnum)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
|
||||
u32 __iomem *main = (u32 *)addr;
|
||||
u8 __iomem *oob = addr + mtd->writesize;
|
||||
@@ -286,8 +286,8 @@ static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
|
||||
*/
|
||||
static int fsl_ifc_run_command(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
|
||||
u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
|
||||
@@ -367,7 +367,7 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
|
||||
int oob,
|
||||
struct mtd_info *mtd)
|
||||
{
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
|
||||
|
||||
@@ -404,8 +404,8 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
|
||||
static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
|
||||
|
||||
@@ -607,8 +607,8 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
*/
|
||||
static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
unsigned int bufsize = mtd->writesize + mtd->oobsize;
|
||||
|
||||
@@ -635,8 +635,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
*/
|
||||
static u8 fsl_ifc_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
unsigned int offset;
|
||||
|
||||
@@ -659,8 +659,8 @@ static u8 fsl_ifc_read_byte(struct mtd_info *mtd)
|
||||
*/
|
||||
static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
uint16_t data;
|
||||
|
||||
@@ -683,8 +683,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
|
||||
*/
|
||||
static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
int avail;
|
||||
|
||||
@@ -706,7 +706,7 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
*/
|
||||
static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
|
||||
u32 nand_fsr;
|
||||
@@ -739,7 +739,7 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
|
||||
fsl_ifc_read_buf(mtd, buf, mtd->writesize);
|
||||
@@ -755,7 +755,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* waitfunc.
|
||||
*/
|
||||
static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
fsl_ifc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
@@ -880,7 +880,7 @@ static int fsl_ifc_sram_init(uint32_t ver)
|
||||
|
||||
static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||
{
|
||||
struct mtd_info *mtd = &nand_info[devnum];
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *nand;
|
||||
struct fsl_ifc_mtd *priv;
|
||||
struct nand_ecclayout *layout;
|
||||
@@ -925,7 +925,7 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||
}
|
||||
|
||||
nand = &priv->chip;
|
||||
mtd->priv = nand;
|
||||
mtd = nand_to_mtd(nand);
|
||||
|
||||
ifc_ctrl->chips[priv->bank] = priv;
|
||||
|
||||
@@ -954,7 +954,7 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||
}
|
||||
|
||||
nand->controller = &ifc_ctrl->controller;
|
||||
nand->priv = priv;
|
||||
nand_set_controller_data(nand, priv);
|
||||
|
||||
nand->ecc.read_page = fsl_ifc_read_page;
|
||||
nand->ecc.write_page = fsl_ifc_write_page;
|
||||
@@ -1044,7 +1044,7 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_register(devnum);
|
||||
ret = nand_register(devnum, mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
@@ -64,8 +64,8 @@ static void fun_wait(struct fsl_upm_nand *fun)
|
||||
#if CONFIG_SYS_NAND_MAX_CHIPS > 1
|
||||
static void fun_select_chip(struct mtd_info *mtd, int chip_nr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_upm_nand *fun = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_upm_nand *fun = nand_get_controller_data(chip);
|
||||
|
||||
if (chip_nr >= 0) {
|
||||
fun->chip_nr = chip_nr;
|
||||
@@ -79,8 +79,8 @@ static void fun_select_chip(struct mtd_info *mtd, int chip_nr)
|
||||
|
||||
static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_upm_nand *fun = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_upm_nand *fun = nand_get_controller_data(chip);
|
||||
void __iomem *io_addr;
|
||||
u32 mar;
|
||||
|
||||
@@ -123,7 +123,7 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
|
||||
static u8 upm_nand_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
return in_8(chip->IO_ADDR_R);
|
||||
}
|
||||
@@ -131,8 +131,8 @@ static u8 upm_nand_read_byte(struct mtd_info *mtd)
|
||||
static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_upm_nand *fun = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_upm_nand *fun = nand_get_controller_data(chip);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
out_8(chip->IO_ADDR_W, buf[i]);
|
||||
@@ -147,7 +147,7 @@ static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = in_8(chip->IO_ADDR_R);
|
||||
@@ -155,8 +155,8 @@ static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
|
||||
static int nand_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct fsl_upm_nand *fun = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_upm_nand *fun = nand_get_controller_data(chip);
|
||||
|
||||
return fun->dev_ready(fun->chip_nr);
|
||||
}
|
||||
@@ -168,7 +168,7 @@ int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun)
|
||||
|
||||
fun->last_ctrl = NAND_CLE;
|
||||
|
||||
chip->priv = fun;
|
||||
nand_set_controller_data(chip, fun);
|
||||
chip->chip_delay = fun->chip_delay;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->cmd_ctrl = fun_cmd_ctrl;
|
||||
|
||||
@@ -165,7 +165,7 @@ static int count_written_bits(uint8_t *buff, int size, int max_bits)
|
||||
|
||||
static void fsmc_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
ulong IO_ADDR_W;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
@@ -409,8 +409,8 @@ int fsmc_nand_switch_ecc(uint32_t eccstrength)
|
||||
* Nomadik SoC is currently supporting this fsmc_nand_switch_ecc()
|
||||
* function, as it doesn't need to switch to a different ECC layout.
|
||||
*/
|
||||
mtd = &nand_info[nand_curr_device];
|
||||
nand = mtd->priv;
|
||||
mtd = nand_info[nand_curr_device];
|
||||
nand = mtd_to_nand(mtd);
|
||||
|
||||
/* Setup the ecc configurations again */
|
||||
if (eccstrength == 1) {
|
||||
@@ -443,7 +443,6 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
static int chip_nr;
|
||||
struct mtd_info *mtd;
|
||||
int i;
|
||||
u32 peripid2 = readl(&fsmc_regs_p->peripid2);
|
||||
|
||||
fsmc_version = (peripid2 >> FSMC_REVISION_SHFT) &
|
||||
@@ -480,8 +479,7 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||
(void __iomem *)CONFIG_SYS_NAND_BASE;
|
||||
nand->badblockbits = 7;
|
||||
|
||||
mtd = &nand_info[chip_nr++];
|
||||
mtd->priv = nand;
|
||||
mtd = nand_to_mtd(nand);
|
||||
|
||||
switch (fsmc_version) {
|
||||
case FSMC_VER8:
|
||||
@@ -514,9 +512,8 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||
if (nand_scan_tail(mtd))
|
||||
return -ENXIO;
|
||||
|
||||
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
|
||||
if (nand_register(i))
|
||||
return -ENXIO;
|
||||
if (nand_register(chip_nr++, mtd))
|
||||
return -ENXIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Platform independend driver for JZ4740.
|
||||
*
|
||||
* Copyright (c) 2007 Ingenic Semiconductor Inc.
|
||||
* Author: <jlwei@ingenic.cn>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
|
||||
#include <nand.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/jz4740.h>
|
||||
|
||||
#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000)
|
||||
#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
|
||||
#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000)
|
||||
|
||||
#define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
|
||||
#define JZ_NAND_ECC_CTRL_RS BIT(2)
|
||||
#define JZ_NAND_ECC_CTRL_RESET BIT(1)
|
||||
#define JZ_NAND_ECC_CTRL_ENABLE BIT(0)
|
||||
|
||||
#define EMC_SMCR1_OPT_NAND 0x094c4400
|
||||
/* Optimize the timing of nand */
|
||||
|
||||
static struct jz4740_emc * emc = (struct jz4740_emc *)JZ4740_EMC_BASE;
|
||||
|
||||
static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
|
||||
.eccbytes = 72,
|
||||
.eccpos = {
|
||||
12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 73, 74, 75,
|
||||
76, 77, 78, 79, 80, 81, 82, 83 },
|
||||
.oobfree = {
|
||||
{.offset = 2,
|
||||
.length = 10 },
|
||||
{.offset = 84,
|
||||
.length = 44 } }
|
||||
};
|
||||
|
||||
static int is_reading;
|
||||
|
||||
static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
uint32_t reg;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if (ctrl & NAND_ALE)
|
||||
this->IO_ADDR_W = JZ_NAND_ADDR_ADDR;
|
||||
else if (ctrl & NAND_CLE)
|
||||
this->IO_ADDR_W = JZ_NAND_CMD_ADDR;
|
||||
else
|
||||
this->IO_ADDR_W = JZ_NAND_DATA_ADDR;
|
||||
|
||||
reg = readl(&emc->nfcsr);
|
||||
if (ctrl & NAND_NCE)
|
||||
reg |= EMC_NFCSR_NFCE1;
|
||||
else
|
||||
reg &= ~EMC_NFCSR_NFCE1;
|
||||
writel(reg, &emc->nfcsr);
|
||||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int jz_nand_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return (readl(GPIO_PXPIN(2)) & 0x40000000) ? 1 : 0;
|
||||
}
|
||||
|
||||
void board_nand_select_device(struct nand_chip *nand, int chip)
|
||||
{
|
||||
/*
|
||||
* Don't use "chip" to address the NAND device,
|
||||
* generate the cs from the address where it is encoded.
|
||||
*/
|
||||
}
|
||||
|
||||
static int jz_nand_rs_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
{
|
||||
uint32_t status;
|
||||
int i;
|
||||
|
||||
if (is_reading)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
status = readl(&emc->nfints);
|
||||
} while (!(status & EMC_NFINTS_ENCF));
|
||||
|
||||
/* disable ecc */
|
||||
writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr);
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
ecc_code[i] = readb(&emc->nfpar[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
writel(0, &emc->nfints);
|
||||
reg = readl(&emc->nfecr);
|
||||
reg |= JZ_NAND_ECC_CTRL_RESET;
|
||||
reg |= JZ_NAND_ECC_CTRL_ENABLE;
|
||||
reg |= JZ_NAND_ECC_CTRL_RS;
|
||||
|
||||
switch (mode) {
|
||||
case NAND_ECC_READ:
|
||||
reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
|
||||
is_reading = 1;
|
||||
break;
|
||||
case NAND_ECC_WRITE:
|
||||
reg |= JZ_NAND_ECC_CTRL_ENCODING;
|
||||
is_reading = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
writel(reg, &emc->nfecr);
|
||||
}
|
||||
|
||||
/* Correct 1~9-bit errors in 512-bytes data */
|
||||
static void jz_rs_correct(unsigned char *dat, int idx, int mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
idx--;
|
||||
|
||||
i = idx + (idx >> 3);
|
||||
if (i >= 512)
|
||||
return;
|
||||
|
||||
mask <<= (idx & 0x7);
|
||||
|
||||
dat[i] ^= mask & 0xff;
|
||||
if (i < 511)
|
||||
dat[i + 1] ^= (mask >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
int k;
|
||||
uint32_t errcnt, index, mask, status;
|
||||
|
||||
/* Set PAR values */
|
||||
const uint8_t all_ff_ecc[] = {
|
||||
0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f };
|
||||
|
||||
if (read_ecc[0] == 0xff && read_ecc[1] == 0xff &&
|
||||
read_ecc[2] == 0xff && read_ecc[3] == 0xff &&
|
||||
read_ecc[4] == 0xff && read_ecc[5] == 0xff &&
|
||||
read_ecc[6] == 0xff && read_ecc[7] == 0xff &&
|
||||
read_ecc[8] == 0xff) {
|
||||
for (k = 0; k < 9; k++)
|
||||
writeb(all_ff_ecc[k], &emc->nfpar[k]);
|
||||
} else {
|
||||
for (k = 0; k < 9; k++)
|
||||
writeb(read_ecc[k], &emc->nfpar[k]);
|
||||
}
|
||||
/* Set PRDY */
|
||||
writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr);
|
||||
|
||||
/* Wait for completion */
|
||||
do {
|
||||
status = readl(&emc->nfints);
|
||||
} while (!(status & EMC_NFINTS_DECF));
|
||||
|
||||
/* disable ecc */
|
||||
writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr);
|
||||
|
||||
/* Check decoding */
|
||||
if (!(status & EMC_NFINTS_ERR))
|
||||
return 0;
|
||||
|
||||
if (status & EMC_NFINTS_UNCOR) {
|
||||
printf("uncorrectable ecc\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
errcnt = (status & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
|
||||
|
||||
switch (errcnt) {
|
||||
case 4:
|
||||
index = (readl(&emc->nferr[3]) & EMC_NFERR_INDEX_MASK) >>
|
||||
EMC_NFERR_INDEX_BIT;
|
||||
mask = (readl(&emc->nferr[3]) & EMC_NFERR_MASK_MASK) >>
|
||||
EMC_NFERR_MASK_BIT;
|
||||
jz_rs_correct(dat, index, mask);
|
||||
case 3:
|
||||
index = (readl(&emc->nferr[2]) & EMC_NFERR_INDEX_MASK) >>
|
||||
EMC_NFERR_INDEX_BIT;
|
||||
mask = (readl(&emc->nferr[2]) & EMC_NFERR_MASK_MASK) >>
|
||||
EMC_NFERR_MASK_BIT;
|
||||
jz_rs_correct(dat, index, mask);
|
||||
case 2:
|
||||
index = (readl(&emc->nferr[1]) & EMC_NFERR_INDEX_MASK) >>
|
||||
EMC_NFERR_INDEX_BIT;
|
||||
mask = (readl(&emc->nferr[1]) & EMC_NFERR_MASK_MASK) >>
|
||||
EMC_NFERR_MASK_BIT;
|
||||
jz_rs_correct(dat, index, mask);
|
||||
case 1:
|
||||
index = (readl(&emc->nferr[0]) & EMC_NFERR_INDEX_MASK) >>
|
||||
EMC_NFERR_INDEX_BIT;
|
||||
mask = (readl(&emc->nferr[0]) & EMC_NFERR_MASK_MASK) >>
|
||||
EMC_NFERR_MASK_BIT;
|
||||
jz_rs_correct(dat, index, mask);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return errcnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main initialization routine
|
||||
*/
|
||||
int board_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = readl(&emc->nfcsr);
|
||||
reg |= EMC_NFCSR_NFE1; /* EMC setup, Set NFE bit */
|
||||
writel(reg, &emc->nfcsr);
|
||||
|
||||
writel(EMC_SMCR1_OPT_NAND, &emc->smcr[1]);
|
||||
|
||||
nand->IO_ADDR_R = JZ_NAND_DATA_ADDR;
|
||||
nand->IO_ADDR_W = JZ_NAND_DATA_ADDR;
|
||||
nand->cmd_ctrl = jz_nand_cmd_ctrl;
|
||||
nand->dev_ready = jz_nand_device_ready;
|
||||
nand->ecc.hwctl = jz_nand_hwctl;
|
||||
nand->ecc.correct = jz_nand_rs_correct_data;
|
||||
nand->ecc.calculate = jz_nand_rs_calculate_ecc;
|
||||
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||
nand->ecc.strength = 4;
|
||||
nand->ecc.layout = &qi_lb60_ecclayout_2gb;
|
||||
nand->chip_delay = 50;
|
||||
nand->bbt_options |= NAND_BBT_USE_FLASH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -35,7 +35,7 @@
|
||||
*/
|
||||
static void kb9202_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
|
||||
|
||||
@@ -33,7 +33,7 @@ static u32 nand_mpp_backup[9] = { 0 };
|
||||
static void kw_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nc = mtd->priv;
|
||||
struct nand_chip *nc = mtd_to_nand(mtd);
|
||||
u32 offs;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
|
||||
@@ -378,7 +378,8 @@ static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
*/
|
||||
|
||||
static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
unsigned int i, status, timeout;
|
||||
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
|
||||
@@ -435,7 +436,8 @@ static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
|
||||
*/
|
||||
|
||||
static int lpc32xx_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
unsigned int i;
|
||||
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
|
||||
@@ -539,11 +541,7 @@ static struct nand_chip lpc32xx_chip;
|
||||
|
||||
void board_nand_init(void)
|
||||
{
|
||||
/* we have only one device anyway */
|
||||
struct mtd_info *mtd = &nand_info[0];
|
||||
/* chip is struct nand_chip, and is now provided by the driver. */
|
||||
mtd->priv = &lpc32xx_chip;
|
||||
/* to store return status in case we need to print it */
|
||||
struct mtd_info *mtd = &lpc32xx_chip.mtd;
|
||||
int ret;
|
||||
|
||||
/* Set all BOARDSPECIFIC (actually core-specific) fields */
|
||||
@@ -597,7 +595,7 @@ void board_nand_init(void)
|
||||
}
|
||||
|
||||
/* chip is good, register it */
|
||||
ret = nand_register(0);
|
||||
ret = nand_register(0, mtd);
|
||||
if (ret)
|
||||
error("nand_register returned %i", ret);
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ static void lpc32xx_nand_dma_configure(struct nand_chip *chip,
|
||||
static void lpc32xx_nand_xfer(struct mtd_info *mtd, const u8 *buf,
|
||||
int len, int read)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 config;
|
||||
int ret;
|
||||
|
||||
@@ -486,7 +486,8 @@ static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
/* Reuse the logic from "nand_write_page_hwecc()" */
|
||||
static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
int i;
|
||||
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
#define NFC_WPC_UNLOCK (1 << 2)
|
||||
|
||||
struct mpc5121_nfc_prv {
|
||||
struct mtd_info mtd;
|
||||
struct nand_chip chip;
|
||||
int irq;
|
||||
void __iomem *regs;
|
||||
@@ -117,8 +116,8 @@ static void mpc5121_nfc_done(struct mtd_info *mtd);
|
||||
/* Read NFC register */
|
||||
static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mpc5121_nfc_prv *prv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
|
||||
|
||||
return in_be16(prv->regs + reg);
|
||||
}
|
||||
@@ -126,8 +125,8 @@ static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
|
||||
/* Write NFC register */
|
||||
static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mpc5121_nfc_prv *prv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
|
||||
|
||||
out_be16(prv->regs + reg, val);
|
||||
}
|
||||
@@ -211,7 +210,7 @@ static void mpc5121_nfc_done(struct mtd_info *mtd)
|
||||
/* Do address cycle(s) */
|
||||
static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 pagemask = chip->pagemask;
|
||||
|
||||
if (column != -1) {
|
||||
@@ -283,8 +282,8 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
|
||||
static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
|
||||
int column, int page)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mpc5121_nfc_prv *prv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
|
||||
|
||||
prv->column = (column >= 0) ? column : 0;
|
||||
prv->spareonly = 0;
|
||||
@@ -357,8 +356,8 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
|
||||
static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
|
||||
u8 * buffer, uint size, int wr)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct mpc5121_nfc_prv *prv = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
|
||||
uint o, s, sbsize, blksize;
|
||||
|
||||
/*
|
||||
@@ -410,8 +409,8 @@ static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
|
||||
static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char * buf, int len,
|
||||
int wr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mpc5121_nfc_prv *prv = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
|
||||
uint c = prv->column;
|
||||
uint l;
|
||||
|
||||
@@ -489,7 +488,7 @@ static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
|
||||
static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
|
||||
{
|
||||
immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
uint rcw_pagesize = 0;
|
||||
uint rcw_sparesize = 0;
|
||||
uint rcw_width;
|
||||
@@ -549,7 +548,6 @@ int board_nand_init(struct nand_chip *chip)
|
||||
int resettime = 0;
|
||||
int retval = 0;
|
||||
int rev;
|
||||
static int chip_nr = 0;
|
||||
|
||||
/*
|
||||
* Check SoC revision. This driver supports only NFC
|
||||
@@ -568,9 +566,8 @@ int board_nand_init(struct nand_chip *chip)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mtd = &nand_info[chip_nr++];
|
||||
mtd->priv = chip;
|
||||
chip->priv = prv;
|
||||
mtd = &chip->mtd;
|
||||
nand_set_controller_data(chip, prv);
|
||||
|
||||
/* Read NFC configuration from Reset Config Word */
|
||||
retval = mpc5121_nfc_read_hw_config(mtd);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#define DRIVER_NAME "mxc_nand"
|
||||
|
||||
struct mxc_nand_host {
|
||||
struct mtd_info mtd;
|
||||
struct nand_chip *nand;
|
||||
|
||||
struct mxc_nand_regs __iomem *regs;
|
||||
@@ -351,8 +350,8 @@ static int mxc_nand_dev_ready(struct mtd_info *mtd)
|
||||
|
||||
static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
|
||||
uint16_t tmp = readnfc(&host->regs->config1);
|
||||
|
||||
@@ -386,7 +385,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
uint8_t *buf = chip->oob_poi;
|
||||
int length = mtd->oobsize;
|
||||
int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
@@ -441,7 +440,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
||||
int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
@@ -486,7 +485,7 @@ static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,
|
||||
int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int n, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
@@ -550,7 +549,7 @@ static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
int length = mtd->oobsize;
|
||||
int i, len, status, steps = chip->ecc.steps;
|
||||
@@ -576,9 +575,9 @@ static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf,
|
||||
int oob_required)
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
@@ -616,9 +615,9 @@ static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf,
|
||||
int oob_required)
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int i, n, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
@@ -661,8 +660,8 @@ static int mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint32_t ecc_status = readl(&host->regs->ecc_status_result);
|
||||
int subpages = mtd->writesize / nand_chip->subpagesize;
|
||||
int pg2blk_shift = nand_chip->phys_erase_shift -
|
||||
@@ -681,7 +680,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
mtd->writesize / nand_chip->subpagesize
|
||||
- subpages);
|
||||
}
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
ecc_status >>= 4;
|
||||
subpages--;
|
||||
@@ -700,8 +699,8 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
/*
|
||||
* 1-Bit errors are automatically corrected in HW. No need for
|
||||
@@ -713,7 +712,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL0,
|
||||
"MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -729,8 +728,8 @@ static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
|
||||
static u_char mxc_nand_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint8_t ret = 0;
|
||||
uint16_t col;
|
||||
uint16_t __iomem *main_buf =
|
||||
@@ -769,8 +768,8 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
|
||||
|
||||
static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint16_t col, ret;
|
||||
uint16_t __iomem *p;
|
||||
|
||||
@@ -821,8 +820,8 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
|
||||
static void mxc_nand_write_buf(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
int n, col, i = 0;
|
||||
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL3,
|
||||
@@ -895,8 +894,8 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
|
||||
*/
|
||||
static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
int n, col, i = 0;
|
||||
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL3,
|
||||
@@ -955,8 +954,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
*/
|
||||
static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
switch (chip) {
|
||||
case -1:
|
||||
@@ -982,8 +981,8 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct mxc_nand_host *host = nand_chip->priv;
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL3,
|
||||
"mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
|
||||
@@ -1164,14 +1163,13 @@ int board_nand_init(struct nand_chip *this)
|
||||
#endif
|
||||
|
||||
/* structures must be linked */
|
||||
mtd = &host->mtd;
|
||||
mtd->priv = this;
|
||||
mtd = &this->mtd;
|
||||
host->nand = this;
|
||||
|
||||
/* 5 us command delay time */
|
||||
this->chip_delay = 5;
|
||||
|
||||
this->priv = host;
|
||||
nand_set_controller_data(this, host);
|
||||
this->dev_ready = mxc_nand_dev_ready;
|
||||
this->cmdfunc = mxc_nand_command;
|
||||
this->select_chip = mxc_nand_select_chip;
|
||||
|
||||
@@ -232,7 +232,7 @@ static int nfc_read_page(unsigned int page_address, unsigned char *buf)
|
||||
nfc_nand_read_page(page_address);
|
||||
|
||||
if (nfc_nand_check_ecc())
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
|
||||
src = (u32 *)&nfc->main_area[0][0];
|
||||
dst = (u32 *)buf;
|
||||
|
||||
@@ -264,8 +264,8 @@ static int mxs_nand_wait_for_bch_complete(void)
|
||||
*/
|
||||
static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
struct mxs_dma_desc *d;
|
||||
uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
|
||||
int ret;
|
||||
@@ -343,8 +343,8 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
|
||||
*/
|
||||
static int mxs_nand_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
|
||||
struct mxs_gpmi_regs *gpmi_regs =
|
||||
(struct mxs_gpmi_regs *)MXS_GPMI_BASE;
|
||||
uint32_t tmp;
|
||||
@@ -360,8 +360,8 @@ static int mxs_nand_device_ready(struct mtd_info *mtd)
|
||||
*/
|
||||
static void mxs_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
|
||||
nand_info->cur_chip = chip;
|
||||
}
|
||||
@@ -410,8 +410,8 @@ static void mxs_nand_swap_block_mark(struct mtd_info *mtd,
|
||||
*/
|
||||
static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
struct mxs_dma_desc *d;
|
||||
uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
|
||||
int ret;
|
||||
@@ -494,8 +494,8 @@ rtn:
|
||||
static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
||||
int length)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
struct mxs_dma_desc *d;
|
||||
uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
|
||||
int ret;
|
||||
@@ -559,7 +559,7 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
struct mxs_dma_desc *d;
|
||||
uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
|
||||
uint32_t corrected = 0, failed = 0;
|
||||
@@ -707,9 +707,9 @@ rtn:
|
||||
*/
|
||||
static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *nand, const uint8_t *buf,
|
||||
int oob_required)
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
struct mxs_dma_desc *d;
|
||||
uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
|
||||
int ret;
|
||||
@@ -775,8 +775,8 @@ rtn:
|
||||
static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
if (ops->mode == MTD_OPS_RAW)
|
||||
@@ -800,8 +800,8 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
if (ops->mode == MTD_OPS_RAW)
|
||||
@@ -824,8 +824,8 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
*/
|
||||
static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
nand_info->marking_block_bad = 1;
|
||||
@@ -884,7 +884,7 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
int page)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
|
||||
/*
|
||||
* First, fill in the OOB buffer. If we're doing a raw read, we need to
|
||||
@@ -919,7 +919,7 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
int page)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
uint8_t block_mark = 0;
|
||||
|
||||
/*
|
||||
@@ -961,7 +961,7 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
* Thus, this function is only called when we want *all* blocks to look good,
|
||||
* so it *always* return success.
|
||||
*/
|
||||
static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -982,8 +982,8 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
*/
|
||||
static int mxs_nand_scan_bbt(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
|
||||
struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
|
||||
uint32_t tmp;
|
||||
|
||||
@@ -1175,7 +1175,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
|
||||
memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout));
|
||||
|
||||
nand->priv = nand_info;
|
||||
nand_set_controller_data(nand, nand_info);
|
||||
nand->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
|
||||
nand->cmd_ctrl = mxs_nand_cmd_ctrl;
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#include <nand.h>
|
||||
#include <malloc.h>
|
||||
|
||||
static nand_info_t mtd;
|
||||
static struct mtd_info *mtd;
|
||||
static struct nand_chip nand_chip;
|
||||
|
||||
static void mxs_nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 timeo, time_start;
|
||||
|
||||
/* write out the command to the device */
|
||||
@@ -51,7 +51,7 @@ static void mxs_nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
|
||||
static int mxs_flash_ident(struct mtd_info *mtd)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int i;
|
||||
u8 mfg_id, dev_id;
|
||||
u8 id_data[8];
|
||||
@@ -111,7 +111,7 @@ static int mxs_flash_ident(struct mtd_info *mtd)
|
||||
|
||||
static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int ret;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page);
|
||||
@@ -125,7 +125,7 @@ static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page)
|
||||
|
||||
static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
unsigned int block = offs >> chip->phys_erase_shift;
|
||||
unsigned int page = offs >> chip->page_shift;
|
||||
|
||||
@@ -147,14 +147,14 @@ static int mxs_nand_init(void)
|
||||
|
||||
/* init mxs nand driver */
|
||||
board_nand_init(&nand_chip);
|
||||
mtd.priv = &nand_chip;
|
||||
mtd = &nand_chip.mtd;
|
||||
/* set mtd functions */
|
||||
nand_chip.cmdfunc = mxs_nand_command;
|
||||
nand_chip.numchips = 1;
|
||||
|
||||
/* identify flash device */
|
||||
puts("NAND : ");
|
||||
if (mxs_flash_ident(&mtd)) {
|
||||
if (mxs_flash_ident(mtd)) {
|
||||
printf("Failed to identify\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -162,12 +162,12 @@ static int mxs_nand_init(void)
|
||||
/* allocate and initialize buffers */
|
||||
nand_chip.buffers = memalign(ARCH_DMA_MINALIGN,
|
||||
sizeof(*nand_chip.buffers));
|
||||
nand_chip.oob_poi = nand_chip.buffers->databuf + mtd.writesize;
|
||||
nand_chip.oob_poi = nand_chip.buffers->databuf + mtd->writesize;
|
||||
/* setup flash layout (does not scan as we override that) */
|
||||
mtd.size = nand_chip.chipsize;
|
||||
nand_chip.scan_bbt(&mtd);
|
||||
mtd->size = nand_chip.chipsize;
|
||||
nand_chip.scan_bbt(mtd);
|
||||
|
||||
printf("%llu MiB\n", (mtd.size / (1024 * 1024)));
|
||||
printf("%llu MiB\n", (mtd->size / (1024 * 1024)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -180,20 +180,20 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
|
||||
|
||||
if (mxs_nand_init())
|
||||
return -ENODEV;
|
||||
chip = mtd.priv;
|
||||
chip = mtd_to_nand(mtd);
|
||||
page = offs >> chip->page_shift;
|
||||
nand_page_per_block = mtd.erasesize / mtd.writesize;
|
||||
nand_page_per_block = mtd->erasesize / mtd->writesize;
|
||||
|
||||
debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page);
|
||||
|
||||
size = roundup(size, mtd.writesize);
|
||||
size = roundup(size, mtd->writesize);
|
||||
while (sz < size) {
|
||||
if (mxs_read_page_ecc(&mtd, buf, page) < 0)
|
||||
if (mxs_read_page_ecc(mtd, buf, page) < 0)
|
||||
return -1;
|
||||
sz += mtd.writesize;
|
||||
offs += mtd.writesize;
|
||||
sz += mtd->writesize;
|
||||
offs += mtd->writesize;
|
||||
page++;
|
||||
buf += mtd.writesize;
|
||||
buf += mtd->writesize;
|
||||
|
||||
/*
|
||||
* Check if we have crossed a block boundary, and if so
|
||||
@@ -204,10 +204,10 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
|
||||
* Yes, new block. See if this block is good. If not,
|
||||
* loop until we find a good block.
|
||||
*/
|
||||
while (is_badblock(&mtd, offs, 1)) {
|
||||
while (is_badblock(mtd, offs, 1)) {
|
||||
page = page + nand_page_per_block;
|
||||
/* Check i we've reached the end of flash. */
|
||||
if (page >= mtd.size >> chip->page_shift)
|
||||
if (page >= mtd->size >> chip->page_shift)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
int nand_curr_device = -1;
|
||||
|
||||
|
||||
nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
|
||||
struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
|
||||
|
||||
#ifndef CONFIG_SYS_NAND_SELF_INIT
|
||||
static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
|
||||
@@ -30,15 +30,25 @@ static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
|
||||
|
||||
static unsigned long total_nand_size; /* in kiB */
|
||||
|
||||
/* Register an initialized NAND mtd device with the U-Boot NAND command. */
|
||||
int nand_register(int devnum)
|
||||
int nand_mtd_to_devnum(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *mtd;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nand_info); i++) {
|
||||
if (mtd && nand_info[i] == mtd)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Register an initialized NAND mtd device with the U-Boot NAND command. */
|
||||
int nand_register(int devnum, struct mtd_info *mtd)
|
||||
{
|
||||
if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE)
|
||||
return -EINVAL;
|
||||
|
||||
mtd = &nand_info[devnum];
|
||||
nand_info[devnum] = mtd;
|
||||
|
||||
sprintf(dev_name[devnum], "nand%d", devnum);
|
||||
mtd->name = dev_name[devnum];
|
||||
@@ -62,15 +72,14 @@ int nand_register(int devnum)
|
||||
#ifndef CONFIG_SYS_NAND_SELF_INIT
|
||||
static void nand_init_chip(int i)
|
||||
{
|
||||
struct mtd_info *mtd = &nand_info[i];
|
||||
struct nand_chip *nand = &nand_chip[i];
|
||||
struct mtd_info *mtd = nand_to_mtd(nand);
|
||||
ulong base_addr = base_address[i];
|
||||
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
|
||||
|
||||
if (maxchips < 1)
|
||||
maxchips = 1;
|
||||
|
||||
mtd->priv = nand;
|
||||
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
|
||||
|
||||
if (board_nand_init(nand))
|
||||
@@ -79,7 +88,7 @@ static void nand_init_chip(int i)
|
||||
if (nand_scan(mtd, maxchips))
|
||||
return;
|
||||
|
||||
nand_register(i);
|
||||
nand_register(i, mtd);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -100,6 +109,7 @@ void nand_init(void)
|
||||
/*
|
||||
* Select the chip in the board/cpu specific driver
|
||||
*/
|
||||
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
|
||||
board_nand_select_device(mtd_to_nand(nand_info[nand_curr_device]),
|
||||
nand_curr_device);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/*
|
||||
* drivers/mtd/nand.c
|
||||
*
|
||||
* Overview:
|
||||
* This is the generic MTD driver for NAND flash devices. It should be
|
||||
* capable of working with almost all NAND chips currently available.
|
||||
@@ -45,8 +43,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
static bool is_module_text_address(unsigned long addr) {return 0;}
|
||||
|
||||
/* Define default oob placement schemes for large and small page devices */
|
||||
static struct nand_ecclayout nand_oob_8 = {
|
||||
.eccbytes = 3,
|
||||
@@ -105,7 +101,7 @@ DEFINE_LED_TRIGGER(nand_led_trigger);
|
||||
static int check_offs_len(struct mtd_info *mtd,
|
||||
loff_t ofs, uint64_t len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int ret = 0;
|
||||
|
||||
/* Start address must align on block boundary */
|
||||
@@ -131,7 +127,7 @@ static int check_offs_len(struct mtd_info *mtd,
|
||||
*/
|
||||
static void nand_release_device(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/* De-select the NAND device */
|
||||
chip->select_chip(mtd, -1);
|
||||
@@ -145,7 +141,7 @@ static void nand_release_device(struct mtd_info *mtd)
|
||||
*/
|
||||
uint8_t nand_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
return readb(chip->IO_ADDR_R);
|
||||
}
|
||||
|
||||
@@ -158,7 +154,7 @@ uint8_t nand_read_byte(struct mtd_info *mtd)
|
||||
*/
|
||||
static uint8_t nand_read_byte16(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
|
||||
}
|
||||
|
||||
@@ -170,7 +166,7 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)
|
||||
*/
|
||||
static u16 nand_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
return readw(chip->IO_ADDR_R);
|
||||
}
|
||||
|
||||
@@ -183,7 +179,7 @@ static u16 nand_read_word(struct mtd_info *mtd)
|
||||
*/
|
||||
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
switch (chipnr) {
|
||||
case -1:
|
||||
@@ -206,7 +202,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
*/
|
||||
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
chip->write_buf(mtd, &byte, 1);
|
||||
}
|
||||
@@ -220,7 +216,7 @@ static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
|
||||
*/
|
||||
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
uint16_t word = byte;
|
||||
|
||||
/*
|
||||
@@ -287,7 +283,7 @@ static void iowrite16_rep(void *addr, void *buf, int len)
|
||||
*/
|
||||
void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
iowrite8_rep(chip->IO_ADDR_W, buf, len);
|
||||
}
|
||||
@@ -302,7 +298,7 @@ void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
*/
|
||||
void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
ioread8_rep(chip->IO_ADDR_R, buf, len);
|
||||
}
|
||||
@@ -317,7 +313,7 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
*/
|
||||
void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u16 *p = (u16 *) buf;
|
||||
|
||||
iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
|
||||
@@ -333,7 +329,7 @@ void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
*/
|
||||
void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u16 *p = (u16 *) buf;
|
||||
|
||||
ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
|
||||
@@ -343,14 +339,13 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
|
||||
* @mtd: MTD device structure
|
||||
* @ofs: offset from device start
|
||||
* @getchip: 0, if the chip is already selected
|
||||
*
|
||||
* Check, if the block is bad.
|
||||
*/
|
||||
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
int page, chipnr, res = 0, i = 0;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
int page, res = 0, i = 0;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u16 bad;
|
||||
|
||||
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
||||
@@ -358,15 +353,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
|
||||
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
||||
|
||||
if (getchip) {
|
||||
chipnr = (int)(ofs >> chip->chip_shift);
|
||||
|
||||
nand_get_device(mtd, FL_READING);
|
||||
|
||||
/* Select the NAND device */
|
||||
chip->select_chip(mtd, chipnr);
|
||||
}
|
||||
|
||||
do {
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
chip->cmdfunc(mtd, NAND_CMD_READOOB,
|
||||
@@ -391,11 +377,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
i++;
|
||||
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
|
||||
|
||||
if (getchip) {
|
||||
chip->select_chip(mtd, -1);
|
||||
nand_release_device(mtd);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -410,7 +391,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
*/
|
||||
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_oob_ops ops;
|
||||
uint8_t buf[2] = { 0, 0 };
|
||||
int ret = 0, res, i = 0;
|
||||
@@ -460,7 +441,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
*/
|
||||
static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int res, ret = 0;
|
||||
|
||||
if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
|
||||
@@ -501,7 +482,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
|
||||
*/
|
||||
static int nand_check_wp(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/* Broken xD cards report WP despite being writable */
|
||||
if (chip->options & NAND_BROKEN_XD)
|
||||
@@ -521,7 +502,7 @@ static int nand_check_wp(struct mtd_info *mtd)
|
||||
*/
|
||||
static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if (!chip->bbt)
|
||||
return 0;
|
||||
@@ -533,16 +514,14 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
|
||||
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
||||
* @mtd: MTD device structure
|
||||
* @ofs: offset from device start
|
||||
* @getchip: 0, if the chip is already selected
|
||||
* @allowbbt: 1, if its allowed to access the bbt area
|
||||
*
|
||||
* Check, if the block is bad. Either by reading the bad block table or
|
||||
* calling of the scan function.
|
||||
*/
|
||||
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
||||
int allowbbt)
|
||||
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if (!(chip->options & NAND_SKIP_BBTSCAN) &&
|
||||
!(chip->options & NAND_BBT_SCANNED)) {
|
||||
@@ -551,17 +530,22 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
||||
}
|
||||
|
||||
if (!chip->bbt)
|
||||
return chip->block_bad(mtd, ofs, getchip);
|
||||
return chip->block_bad(mtd, ofs);
|
||||
|
||||
/* Return info from the table */
|
||||
return nand_isbad_bbt(mtd, ofs, allowbbt);
|
||||
}
|
||||
|
||||
/* Wait for the ready pin, after a command. The timeout is caught later. */
|
||||
/**
|
||||
* nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
|
||||
* @mtd: MTD device structure
|
||||
*
|
||||
* Wait for the ready pin after a command, and warn if a timeout occurs.
|
||||
*/
|
||||
void nand_wait_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 timeo = (CONFIG_SYS_HZ * 400) / 1000;
|
||||
u32 time_start;
|
||||
|
||||
time_start = get_timer(0);
|
||||
@@ -571,6 +555,9 @@ void nand_wait_ready(struct mtd_info *mtd)
|
||||
if (chip->dev_ready(mtd))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!chip->dev_ready(mtd))
|
||||
pr_warn("timeout while waiting for chip to become ready\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nand_wait_ready);
|
||||
|
||||
@@ -583,7 +570,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
|
||||
*/
|
||||
static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 time_start;
|
||||
|
||||
timeo = (CONFIG_SYS_HZ * timeo) / 1000;
|
||||
@@ -608,7 +595,7 @@ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
|
||||
static void nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
|
||||
|
||||
/* Write out the command to the device */
|
||||
@@ -711,7 +698,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
register struct nand_chip *chip = mtd->priv;
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/* Emulate NAND_CMD_READOOB */
|
||||
if (command == NAND_CMD_READOOB) {
|
||||
@@ -835,7 +822,7 @@ static void panic_nand_get_device(struct nand_chip *chip,
|
||||
static int
|
||||
nand_get_device(struct mtd_info *mtd, int new_state)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
chip->state = new_state;
|
||||
return 0;
|
||||
}
|
||||
@@ -871,15 +858,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip structure
|
||||
*
|
||||
* Wait for command done. This applies to erase and program only. Erase can
|
||||
* take up to 400ms and program up to 20ms according to general NAND and
|
||||
* SmartMedia specs.
|
||||
* Wait for command done. This applies to erase and program only.
|
||||
*/
|
||||
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
|
||||
int status, state = chip->state;
|
||||
unsigned long timeo = (state == FL_ERASING ? 400 : 20);
|
||||
int status;
|
||||
unsigned long timeo = 400;
|
||||
|
||||
led_trigger_event(nand_led_trigger, LED_FULL);
|
||||
|
||||
@@ -912,6 +897,135 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
return status;
|
||||
}
|
||||
|
||||
#define BITS_PER_BYTE 8
|
||||
|
||||
/**
|
||||
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
|
||||
* @buf: buffer to test
|
||||
* @len: buffer length
|
||||
* @bitflips_threshold: maximum number of bitflips
|
||||
*
|
||||
* Check if a buffer contains only 0xff, which means the underlying region
|
||||
* has been erased and is ready to be programmed.
|
||||
* The bitflips_threshold specify the maximum number of bitflips before
|
||||
* considering the region is not erased.
|
||||
* Note: The logic of this function has been extracted from the memweight
|
||||
* implementation, except that nand_check_erased_buf function exit before
|
||||
* testing the whole buffer if the number of bitflips exceed the
|
||||
* bitflips_threshold value.
|
||||
*
|
||||
* Returns a positive number of bitflips less than or equal to
|
||||
* bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
|
||||
* threshold.
|
||||
*/
|
||||
static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
|
||||
{
|
||||
const unsigned char *bitmap = buf;
|
||||
int bitflips = 0;
|
||||
int weight;
|
||||
|
||||
for (; len && ((uintptr_t)bitmap) % sizeof(long);
|
||||
len--, bitmap++) {
|
||||
weight = hweight8(*bitmap);
|
||||
bitflips += BITS_PER_BYTE - weight;
|
||||
if (unlikely(bitflips > bitflips_threshold))
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
for (; len >= 4; len -= 4, bitmap += 4) {
|
||||
weight = hweight32(*((u32 *)bitmap));
|
||||
bitflips += 32 - weight;
|
||||
if (unlikely(bitflips > bitflips_threshold))
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
for (; len > 0; len--, bitmap++) {
|
||||
weight = hweight8(*bitmap);
|
||||
bitflips += BITS_PER_BYTE - weight;
|
||||
if (unlikely(bitflips > bitflips_threshold))
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
return bitflips;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
|
||||
* 0xff data
|
||||
* @data: data buffer to test
|
||||
* @datalen: data length
|
||||
* @ecc: ECC buffer
|
||||
* @ecclen: ECC length
|
||||
* @extraoob: extra OOB buffer
|
||||
* @extraooblen: extra OOB length
|
||||
* @bitflips_threshold: maximum number of bitflips
|
||||
*
|
||||
* Check if a data buffer and its associated ECC and OOB data contains only
|
||||
* 0xff pattern, which means the underlying region has been erased and is
|
||||
* ready to be programmed.
|
||||
* The bitflips_threshold specify the maximum number of bitflips before
|
||||
* considering the region as not erased.
|
||||
*
|
||||
* Note:
|
||||
* 1/ ECC algorithms are working on pre-defined block sizes which are usually
|
||||
* different from the NAND page size. When fixing bitflips, ECC engines will
|
||||
* report the number of errors per chunk, and the NAND core infrastructure
|
||||
* expect you to return the maximum number of bitflips for the whole page.
|
||||
* This is why you should always use this function on a single chunk and
|
||||
* not on the whole page. After checking each chunk you should update your
|
||||
* max_bitflips value accordingly.
|
||||
* 2/ When checking for bitflips in erased pages you should not only check
|
||||
* the payload data but also their associated ECC data, because a user might
|
||||
* have programmed almost all bits to 1 but a few. In this case, we
|
||||
* shouldn't consider the chunk as erased, and checking ECC bytes prevent
|
||||
* this case.
|
||||
* 3/ The extraoob argument is optional, and should be used if some of your OOB
|
||||
* data are protected by the ECC engine.
|
||||
* It could also be used if you support subpages and want to attach some
|
||||
* extra OOB data to an ECC chunk.
|
||||
*
|
||||
* Returns a positive number of bitflips less than or equal to
|
||||
* bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
|
||||
* threshold. In case of success, the passed buffers are filled with 0xff.
|
||||
*/
|
||||
int nand_check_erased_ecc_chunk(void *data, int datalen,
|
||||
void *ecc, int ecclen,
|
||||
void *extraoob, int extraooblen,
|
||||
int bitflips_threshold)
|
||||
{
|
||||
int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
|
||||
|
||||
data_bitflips = nand_check_erased_buf(data, datalen,
|
||||
bitflips_threshold);
|
||||
if (data_bitflips < 0)
|
||||
return data_bitflips;
|
||||
|
||||
bitflips_threshold -= data_bitflips;
|
||||
|
||||
ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
|
||||
if (ecc_bitflips < 0)
|
||||
return ecc_bitflips;
|
||||
|
||||
bitflips_threshold -= ecc_bitflips;
|
||||
|
||||
extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
|
||||
bitflips_threshold);
|
||||
if (extraoob_bitflips < 0)
|
||||
return extraoob_bitflips;
|
||||
|
||||
if (data_bitflips)
|
||||
memset(data, 0xff, datalen);
|
||||
|
||||
if (ecc_bitflips)
|
||||
memset(ecc, 0xff, ecclen);
|
||||
|
||||
if (extraoob_bitflips)
|
||||
memset(extraoob, 0xff, extraooblen);
|
||||
|
||||
return data_bitflips + ecc_bitflips + extraoob_bitflips;
|
||||
}
|
||||
EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
|
||||
|
||||
/**
|
||||
* nand_read_page_raw - [INTERN] read raw page data without ecc
|
||||
* @mtd: mtd info structure
|
||||
@@ -1103,6 +1217,16 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
stat = chip->ecc.correct(mtd, p,
|
||||
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
||||
if (stat == -EBADMSG &&
|
||||
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||
/* check for empty pages with bitflips */
|
||||
stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
|
||||
&chip->buffers->ecccode[i],
|
||||
chip->ecc.bytes,
|
||||
NULL, 0,
|
||||
chip->ecc.strength);
|
||||
}
|
||||
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
@@ -1152,6 +1276,15 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int stat;
|
||||
|
||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
if (stat == -EBADMSG &&
|
||||
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||
/* check for empty pages with bitflips */
|
||||
stat = nand_check_erased_ecc_chunk(p, eccsize,
|
||||
&ecc_code[i], eccbytes,
|
||||
NULL, 0,
|
||||
chip->ecc.strength);
|
||||
}
|
||||
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
@@ -1204,6 +1337,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
||||
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
|
||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
||||
if (stat == -EBADMSG &&
|
||||
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||
/* check for empty pages with bitflips */
|
||||
stat = nand_check_erased_ecc_chunk(p, eccsize,
|
||||
&ecc_code[i], eccbytes,
|
||||
NULL, 0,
|
||||
chip->ecc.strength);
|
||||
}
|
||||
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
@@ -1231,6 +1373,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int i, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
int eccsteps = chip->ecc.steps;
|
||||
int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||
uint8_t *p = buf;
|
||||
uint8_t *oob = chip->oob_poi;
|
||||
unsigned int max_bitflips = 0;
|
||||
@@ -1250,19 +1393,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
chip->read_buf(mtd, oob, eccbytes);
|
||||
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
||||
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
mtd->ecc_stats.corrected += stat;
|
||||
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
||||
}
|
||||
|
||||
oob += eccbytes;
|
||||
|
||||
if (chip->ecc.postpad) {
|
||||
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
||||
oob += chip->ecc.postpad;
|
||||
}
|
||||
|
||||
if (stat == -EBADMSG &&
|
||||
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||
/* check for empty pages with bitflips */
|
||||
stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
|
||||
oob - eccpadbytes,
|
||||
eccpadbytes,
|
||||
NULL, 0,
|
||||
chip->ecc.strength);
|
||||
}
|
||||
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
mtd->ecc_stats.corrected += stat;
|
||||
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate remaining oob bytes */
|
||||
@@ -1332,7 +1485,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
|
||||
*/
|
||||
static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
pr_debug("setting READ RETRY mode %d\n", retry_mode);
|
||||
|
||||
@@ -1357,12 +1510,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
int chipnr, page, realpage, col, bytes, aligned, oob_required;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int ret = 0;
|
||||
uint32_t readlen = ops->len;
|
||||
uint32_t oobreadlen = ops->ooblen;
|
||||
uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
|
||||
mtd->oobavail : mtd->oobsize;
|
||||
uint32_t max_oobsize = mtd_oobavail(mtd, ops);
|
||||
|
||||
uint8_t *bufpoi, *oob, *buf;
|
||||
int use_bufpoi;
|
||||
@@ -1700,7 +1852,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
int page, realpage, chipnr;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_ecc_stats stats;
|
||||
int readlen = ops->ooblen;
|
||||
int len;
|
||||
@@ -1712,10 +1864,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
|
||||
stats = mtd->ecc_stats;
|
||||
|
||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||
len = chip->ecc.layout->oobavail;
|
||||
else
|
||||
len = mtd->oobsize;
|
||||
len = mtd_oobavail(mtd, ops);
|
||||
|
||||
if (unlikely(ops->ooboffs >= len)) {
|
||||
pr_debug("%s: attempt to start read outside oob\n",
|
||||
@@ -1840,11 +1989,12 @@ out:
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
* @page: page number to write
|
||||
*
|
||||
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
||||
*/
|
||||
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
chip->write_buf(mtd, buf, mtd->writesize);
|
||||
if (oob_required)
|
||||
@@ -1859,12 +2009,14 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
* @page: page number to write
|
||||
*
|
||||
* We need a special oob layout and handling even when ECC isn't checked.
|
||||
*/
|
||||
static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
int eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
@@ -1901,9 +2053,11 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
* @page: page number to write
|
||||
*/
|
||||
static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
int i, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
@@ -1919,7 +2073,7 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
for (i = 0; i < chip->ecc.total; i++)
|
||||
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
||||
|
||||
return chip->ecc.write_page_raw(mtd, chip, buf, 1);
|
||||
return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1928,9 +2082,11 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
* @page: page number to write
|
||||
*/
|
||||
static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
int i, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
@@ -1962,11 +2118,12 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* @data_len: data length
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
* @page: page number to write
|
||||
*/
|
||||
static int nand_write_subpage_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint32_t offset,
|
||||
uint32_t data_len, const uint8_t *buf,
|
||||
int oob_required)
|
||||
int oob_required, int page)
|
||||
{
|
||||
uint8_t *oob_buf = chip->oob_poi;
|
||||
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
||||
@@ -2021,13 +2178,15 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
* @page: page number to write
|
||||
*
|
||||
* The hw generator calculates the error syndrome automatically. Therefore we
|
||||
* need a special oob layout and handling.
|
||||
*/
|
||||
static int nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
int i, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
@@ -2091,12 +2250,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
if (unlikely(raw))
|
||||
status = chip->ecc.write_page_raw(mtd, chip, buf,
|
||||
oob_required);
|
||||
oob_required, page);
|
||||
else if (subpage)
|
||||
status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
|
||||
buf, oob_required);
|
||||
buf, oob_required, page);
|
||||
else
|
||||
status = chip->ecc.write_page(mtd, chip, buf, oob_required);
|
||||
status = chip->ecc.write_page(mtd, chip, buf, oob_required,
|
||||
page);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
@@ -2139,7 +2299,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/*
|
||||
* Initialise to all 0xFF, to avoid the possibility of left over OOB
|
||||
@@ -2199,12 +2359,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
int chipnr, realpage, page, blockmask, column;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
uint32_t writelen = ops->len;
|
||||
|
||||
uint32_t oobwritelen = ops->ooblen;
|
||||
uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
|
||||
mtd->oobavail : mtd->oobsize;
|
||||
uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
|
||||
|
||||
uint8_t *oob = ops->oobbuf;
|
||||
uint8_t *buf = ops->datbuf;
|
||||
@@ -2328,7 +2487,7 @@ err_out:
|
||||
static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const uint8_t *buf)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_oob_ops ops;
|
||||
int ret;
|
||||
|
||||
@@ -2388,15 +2547,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
int chipnr, page, status, len;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
pr_debug("%s: to = 0x%08x, len = %i\n",
|
||||
__func__, (unsigned int)to, (int)ops->ooblen);
|
||||
|
||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||
len = chip->ecc.layout->oobavail;
|
||||
else
|
||||
len = mtd->oobsize;
|
||||
len = mtd_oobavail(mtd, ops);
|
||||
|
||||
/* Do not allow write past end of page */
|
||||
if ((ops->ooboffs + ops->ooblen) > len) {
|
||||
@@ -2513,7 +2669,7 @@ out:
|
||||
*/
|
||||
static int single_erase(struct mtd_info *mtd, int page)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
/* Send commands to erase a block */
|
||||
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
|
||||
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
|
||||
@@ -2545,7 +2701,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
||||
int allowbbt)
|
||||
{
|
||||
int page, status, pages_per_block, ret, chipnr;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
loff_t len;
|
||||
|
||||
pr_debug("%s: start = 0x%012llx, len = %llu\n",
|
||||
@@ -2586,7 +2742,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
||||
|
||||
/* Check if we have a bad block, we do not erase bad blocks! */
|
||||
if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
|
||||
chip->page_shift, 0, allowbbt)) {
|
||||
chip->page_shift, allowbbt)) {
|
||||
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
|
||||
__func__, page);
|
||||
instr->state = MTD_ERASE_FAILED;
|
||||
@@ -2673,7 +2829,20 @@ static void nand_sync(struct mtd_info *mtd)
|
||||
*/
|
||||
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
||||
{
|
||||
return nand_block_checkbad(mtd, offs, 1, 0);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int chipnr = (int)(offs >> chip->chip_shift);
|
||||
int ret;
|
||||
|
||||
/* Select the NAND device */
|
||||
nand_get_device(mtd, FL_READING);
|
||||
chip->select_chip(mtd, chipnr);
|
||||
|
||||
ret = nand_block_checkbad(mtd, offs, 0);
|
||||
|
||||
chip->select_chip(mtd, -1);
|
||||
nand_release_device(mtd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2745,9 +2914,6 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
/* clear the sub feature parameters */
|
||||
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
|
||||
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
||||
*subfeature_param++ = chip->read_byte(mtd);
|
||||
@@ -2908,7 +3074,7 @@ ext_out:
|
||||
|
||||
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
|
||||
|
||||
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
|
||||
@@ -3480,7 +3646,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
|
||||
goto ident_done;
|
||||
} else if (*dev_id == type->dev_id) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3503,10 +3669,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
|
||||
chip->chipsize = (uint64_t)type->chipsize << 20;
|
||||
|
||||
if (!type->pagesize && chip->init_size) {
|
||||
/* Set the pagesize, oobsize, erasesize by the driver */
|
||||
busw = chip->init_size(mtd, chip, id_data);
|
||||
} else if (!type->pagesize) {
|
||||
if (!type->pagesize) {
|
||||
/* Decode parameters from extended ID */
|
||||
nand_decode_ext_id(mtd, chip, id_data, &busw);
|
||||
} else {
|
||||
@@ -3610,13 +3773,12 @@ ident_done:
|
||||
* This is the first phase of the normal nand_scan() function. It reads the
|
||||
* flash ID and sets up MTD fields accordingly.
|
||||
*
|
||||
* The mtd->owner field must be set to the module of the caller.
|
||||
*/
|
||||
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||
struct nand_flash_dev *table)
|
||||
{
|
||||
int i, nand_maf_id, nand_dev_id;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_flash_dev *type;
|
||||
|
||||
/* Set the default functions */
|
||||
@@ -3680,7 +3842,7 @@ EXPORT_SYMBOL(nand_scan_ident);
|
||||
*/
|
||||
static bool nand_ecc_strength_good(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
int corr, ds_corr;
|
||||
|
||||
@@ -3709,7 +3871,7 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
|
||||
int nand_scan_tail(struct mtd_info *mtd)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
struct nand_buffers *nbuf;
|
||||
|
||||
@@ -3786,7 +3948,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
ecc->write_oob = nand_write_oob_std;
|
||||
if (!ecc->read_subpage)
|
||||
ecc->read_subpage = nand_read_subpage;
|
||||
if (!ecc->write_subpage)
|
||||
if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
|
||||
ecc->write_subpage = nand_write_subpage_hwecc;
|
||||
|
||||
case NAND_ECC_HW_SYNDROME:
|
||||
@@ -3864,10 +4026,8 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
/* See nand_bch_init() for details. */
|
||||
ecc->bytes = DIV_ROUND_UP(
|
||||
ecc->strength * fls(8 * ecc->size), 8);
|
||||
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
|
||||
&ecc->layout);
|
||||
ecc->bytes = 0;
|
||||
ecc->priv = nand_bch_init(mtd);
|
||||
if (!ecc->priv) {
|
||||
pr_warn("BCH ECC initialization failed!\n");
|
||||
BUG();
|
||||
@@ -3902,11 +4062,11 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
* The number of bytes available for a client to place data into
|
||||
* the out of band area.
|
||||
*/
|
||||
ecc->layout->oobavail = 0;
|
||||
for (i = 0; ecc->layout->oobfree[i].length
|
||||
&& i < ARRAY_SIZE(ecc->layout->oobfree); i++)
|
||||
ecc->layout->oobavail += ecc->layout->oobfree[i].length;
|
||||
mtd->oobavail = ecc->layout->oobavail;
|
||||
mtd->oobavail = 0;
|
||||
if (ecc->layout) {
|
||||
for (i = 0; ecc->layout->oobfree[i].length; i++)
|
||||
mtd->oobavail += ecc->layout->oobfree[i].length;
|
||||
}
|
||||
|
||||
/* ECC sanity check: warn if it's too weak */
|
||||
if (!nand_ecc_strength_good(mtd))
|
||||
@@ -3991,18 +4151,6 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
}
|
||||
EXPORT_SYMBOL(nand_scan_tail);
|
||||
|
||||
/*
|
||||
* is_module_text_address() isn't exported, and it's mostly a pointless
|
||||
* test if this is a module _anyway_ -- they'd have to try _really_ hard
|
||||
* to call us from in-kernel code if the core NAND support is modular.
|
||||
*/
|
||||
#ifdef MODULE
|
||||
#define caller_is_module() (1)
|
||||
#else
|
||||
#define caller_is_module() \
|
||||
is_module_text_address((unsigned long)__builtin_return_address(0))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* nand_scan - [NAND Interface] Scan for the NAND device
|
||||
* @mtd: MTD device structure
|
||||
@@ -4010,19 +4158,12 @@ EXPORT_SYMBOL(nand_scan_tail);
|
||||
*
|
||||
* This fills out all the uninitialized function pointers with the defaults.
|
||||
* The flash ID is read and the mtd/chip structures are filled with the
|
||||
* appropriate values. The mtd->owner field must be set to the module of the
|
||||
* caller.
|
||||
* appropriate values.
|
||||
*/
|
||||
int nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Many callers got this wrong, so check for it for a while... */
|
||||
if (!mtd->owner && caller_is_module()) {
|
||||
pr_crit("%s called with NULL mtd->owner!\n", __func__);
|
||||
BUG();
|
||||
}
|
||||
|
||||
ret = nand_scan_ident(mtd, maxchips, NULL);
|
||||
if (!ret)
|
||||
ret = nand_scan_tail(mtd);
|
||||
@@ -4030,9 +4171,6 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
}
|
||||
EXPORT_SYMBOL(nand_scan);
|
||||
|
||||
module_init(nand_base_init);
|
||||
module_exit(nand_base_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
|
||||
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/*
|
||||
* drivers/mtd/nand_bbt.c
|
||||
*
|
||||
* Overview:
|
||||
* Bad block table support for the NAND driver
|
||||
*
|
||||
@@ -65,7 +63,6 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/bbm.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
@@ -173,7 +170,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||
struct nand_bbt_descr *td, int offs)
|
||||
{
|
||||
int res, ret = 0, i, j, act = 0;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
size_t retlen, len, totlen;
|
||||
loff_t from;
|
||||
int bits = td->options & NAND_BBT_NRBITS_MSK;
|
||||
@@ -264,7 +261,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||
*/
|
||||
static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int res = 0, i;
|
||||
|
||||
if (td->options & NAND_BBT_PERCHIP) {
|
||||
@@ -389,7 +386,7 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
|
||||
static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
|
||||
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
/* Read the primary version, if available */
|
||||
if (td->options & NAND_BBT_VERSION) {
|
||||
@@ -455,7 +452,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
|
||||
static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
struct nand_bbt_descr *bd, int chip)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int i, numblocks, numpages;
|
||||
int startblock;
|
||||
loff_t from;
|
||||
@@ -524,7 +521,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
*/
|
||||
static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int i, chips;
|
||||
int startblock, block, dir;
|
||||
int scanlen = mtd->writesize + mtd->oobsize;
|
||||
@@ -619,7 +616,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
|
||||
int chipsel)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct erase_info einfo;
|
||||
int i, res, chip = 0;
|
||||
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
|
||||
@@ -718,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
/* Must we save the block contents? */
|
||||
if (td->options & NAND_BBT_SAVECONTENT) {
|
||||
/* Make it block aligned */
|
||||
to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
|
||||
to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
|
||||
len = 1 << this->bbt_erase_shift;
|
||||
res = mtd_read(mtd, to, len, &retlen, buf);
|
||||
if (res < 0) {
|
||||
@@ -820,7 +817,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
*/
|
||||
static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
return create_bbt(mtd, this->buffers->databuf, bd, -1);
|
||||
}
|
||||
@@ -839,7 +836,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
|
||||
static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
|
||||
{
|
||||
int i, chips, writeops, create, chipsel, res, res2;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct nand_bbt_descr *td = this->bbt_td;
|
||||
struct nand_bbt_descr *md = this->bbt_md;
|
||||
struct nand_bbt_descr *rd, *rd2;
|
||||
@@ -963,7 +960,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
|
||||
*/
|
||||
static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int i, j, chips, block, nrblocks, update;
|
||||
uint8_t oldval;
|
||||
|
||||
@@ -1023,7 +1020,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
|
||||
*/
|
||||
static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u32 pattern_len;
|
||||
u32 bits;
|
||||
u32 table_size;
|
||||
@@ -1073,15 +1070,15 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
* The bad block table memory is allocated here. It must be freed by calling
|
||||
* the nand_free_bbt function.
|
||||
*/
|
||||
int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
int len, res = 0;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int len, res;
|
||||
uint8_t *buf;
|
||||
struct nand_bbt_descr *td = this->bbt_td;
|
||||
struct nand_bbt_descr *md = this->bbt_md;
|
||||
|
||||
len = mtd->size >> (this->bbt_erase_shift + 2);
|
||||
len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
|
||||
/*
|
||||
* Allocate memory (2bit per block) and clear the memory bad block
|
||||
* table.
|
||||
@@ -1097,10 +1094,9 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
if (!td) {
|
||||
if ((res = nand_memory_bbt(mtd, bd))) {
|
||||
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
|
||||
kfree(this->bbt);
|
||||
this->bbt = NULL;
|
||||
goto err;
|
||||
}
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
verify_bbt_descr(mtd, td);
|
||||
verify_bbt_descr(mtd, md);
|
||||
@@ -1110,9 +1106,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
len += (len >> this->page_shift) * mtd->oobsize;
|
||||
buf = vmalloc(len);
|
||||
if (!buf) {
|
||||
kfree(this->bbt);
|
||||
this->bbt = NULL;
|
||||
return -ENOMEM;
|
||||
res = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Is the bbt at a given page? */
|
||||
@@ -1124,6 +1119,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
}
|
||||
|
||||
res = check_create(mtd, buf, bd);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
/* Prevent the bbt regions from erasing / writing */
|
||||
mark_bbt_region(mtd, td);
|
||||
@@ -1131,6 +1128,11 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
mark_bbt_region(mtd, md);
|
||||
|
||||
vfree(buf);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(this->bbt);
|
||||
this->bbt = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1143,7 +1145,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
*/
|
||||
static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int len, res = 0;
|
||||
int chip, chipsel;
|
||||
uint8_t *buf;
|
||||
@@ -1277,7 +1279,7 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
|
||||
*/
|
||||
int nand_default_bbt(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int ret;
|
||||
|
||||
/* Is a flash based bad block table requested? */
|
||||
@@ -1313,7 +1315,7 @@ int nand_default_bbt(struct mtd_info *mtd)
|
||||
*/
|
||||
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int block;
|
||||
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
@@ -1328,7 +1330,7 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
*/
|
||||
int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int block, res;
|
||||
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
@@ -1355,7 +1357,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
*/
|
||||
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int block, ret = 0;
|
||||
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
@@ -1369,5 +1371,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(nand_scan_bbt);
|
||||
|
||||
@@ -41,7 +41,7 @@ struct nand_bch_control {
|
||||
int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
|
||||
unsigned char *code)
|
||||
{
|
||||
const struct nand_chip *chip = mtd->priv;
|
||||
const struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_bch_control *nbc = chip->ecc.priv;
|
||||
unsigned int i;
|
||||
|
||||
@@ -67,7 +67,7 @@ int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
|
||||
int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc)
|
||||
{
|
||||
const struct nand_chip *chip = mtd->priv;
|
||||
const struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_bch_control *nbc = chip->ecc.priv;
|
||||
unsigned int *errloc = nbc->errloc;
|
||||
int i, count;
|
||||
@@ -86,7 +86,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
}
|
||||
} else if (count < 0) {
|
||||
printk(KERN_ERR "ecc unrecoverable error\n");
|
||||
count = -1;
|
||||
count = -EBADMSG;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -94,9 +94,6 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
/**
|
||||
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
|
||||
* @mtd: MTD block structure
|
||||
* @eccsize: ecc block size in bytes
|
||||
* @eccbytes: ecc length in bytes
|
||||
* @ecclayout: output default layout
|
||||
*
|
||||
* Returns:
|
||||
* a pointer to a new NAND BCH control structure, or NULL upon failure
|
||||
@@ -110,14 +107,21 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
|
||||
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
|
||||
*/
|
||||
struct nand_bch_control *
|
||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||
struct nand_ecclayout **ecclayout)
|
||||
struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
unsigned int m, t, eccsteps, i;
|
||||
struct nand_ecclayout *layout;
|
||||
struct nand_ecclayout *layout = nand->ecc.layout;
|
||||
struct nand_bch_control *nbc = NULL;
|
||||
unsigned char *erased_page;
|
||||
unsigned int eccsize = nand->ecc.size;
|
||||
unsigned int eccbytes = nand->ecc.bytes;
|
||||
unsigned int eccstrength = nand->ecc.strength;
|
||||
|
||||
if (!eccbytes && eccstrength) {
|
||||
eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
|
||||
nand->ecc.bytes = eccbytes;
|
||||
}
|
||||
|
||||
if (!eccsize || !eccbytes) {
|
||||
printk(KERN_WARNING "ecc parameters not supplied\n");
|
||||
@@ -145,7 +149,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||
eccsteps = mtd->writesize/eccsize;
|
||||
|
||||
/* if no ecc placement scheme was provided, build one */
|
||||
if (!*ecclayout) {
|
||||
if (!layout) {
|
||||
|
||||
/* handle large page devices only */
|
||||
if (mtd->oobsize < 64) {
|
||||
@@ -171,7 +175,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||
layout->oobfree[0].offset = 2;
|
||||
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
|
||||
|
||||
*ecclayout = layout;
|
||||
nand->ecc.layout = layout;
|
||||
}
|
||||
|
||||
/* sanity checks */
|
||||
@@ -179,7 +183,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
|
||||
goto fail;
|
||||
}
|
||||
if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
|
||||
if (layout->eccbytes != (eccsteps*eccbytes)) {
|
||||
printk(KERN_WARNING "invalid ecc layout\n");
|
||||
goto fail;
|
||||
}
|
||||
@@ -203,6 +207,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||
for (i = 0; i < eccbytes; i++)
|
||||
nbc->eccmask[i] ^= 0xff;
|
||||
|
||||
if (!eccstrength)
|
||||
nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
|
||||
|
||||
return nbc;
|
||||
fail:
|
||||
nand_bch_free(nbc);
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/*
|
||||
* drivers/mtd/nandids.c
|
||||
*
|
||||
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -41,6 +39,10 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||
* listed by full ID. We list them first so that we can easily identify
|
||||
* the most specific match.
|
||||
*/
|
||||
{"TC58NVG0S3E 1G 3.3V 8-bit",
|
||||
{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
|
||||
SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
|
||||
2 },
|
||||
{"TC58NVG2S0F 4G 3.3V 8-bit",
|
||||
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
|
||||
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
|
||||
@@ -58,8 +60,8 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
|
||||
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
|
||||
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
||||
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
|
||||
4 },
|
||||
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
|
||||
NAND_ECC_INFO(40, SZ_1K), 4 },
|
||||
|
||||
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
static void plat_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
@@ -39,7 +39,7 @@ static void plat_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
#ifdef NAND_PLAT_DEV_READY
|
||||
static int plat_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return NAND_PLAT_DEV_READY((struct nand_chip *)mtd->priv);
|
||||
return NAND_PLAT_DEV_READY((struct nand_chip *)mtd_to_nand(mtd));
|
||||
}
|
||||
#else
|
||||
# define plat_dev_ready NULL
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
|
||||
static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
|
||||
static nand_info_t mtd;
|
||||
static struct mtd_info *mtd;
|
||||
static struct nand_chip nand_chip;
|
||||
|
||||
#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \
|
||||
@@ -26,32 +26,32 @@ static struct nand_chip nand_chip;
|
||||
static int nand_command(int block, int page, uint32_t offs,
|
||||
u8 cmd)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
||||
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
/* Begin command latch cycle */
|
||||
this->cmd_ctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
/* Set ALE and clear CLE to start address cycle */
|
||||
/* Column address */
|
||||
this->cmd_ctrl(&mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
this->cmd_ctrl(&mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */
|
||||
this->cmd_ctrl(&mtd, (page_addr >> 8) & 0xff,
|
||||
this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */
|
||||
this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff,
|
||||
NAND_CTRL_ALE); /* A[24:17] */
|
||||
#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE
|
||||
/* One more address cycle for devices > 32MiB */
|
||||
this->cmd_ctrl(&mtd, (page_addr >> 16) & 0x0f,
|
||||
this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f,
|
||||
NAND_CTRL_ALE); /* A[28:25] */
|
||||
#endif
|
||||
/* Latch in address */
|
||||
this->cmd_ctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/*
|
||||
* Wait a while for the data to be ready
|
||||
*/
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
return 0;
|
||||
@@ -63,12 +63,12 @@ static int nand_command(int block, int page, uint32_t offs,
|
||||
static int nand_command(int block, int page, uint32_t offs,
|
||||
u8 cmd)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
|
||||
void (*hwctrl)(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl) = this->cmd_ctrl;
|
||||
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
/* Emulate NAND_CMD_READOOB */
|
||||
@@ -82,30 +82,30 @@ static int nand_command(int block, int page, uint32_t offs,
|
||||
offs >>= 1;
|
||||
|
||||
/* Begin command latch cycle */
|
||||
hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
/* Set ALE and clear CLE to start address cycle */
|
||||
/* Column address */
|
||||
hwctrl(&mtd, offs & 0xff,
|
||||
NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
|
||||
hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
|
||||
hwctrl(mtd, offs & 0xff,
|
||||
NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
|
||||
hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
|
||||
/* Row address */
|
||||
hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
|
||||
hwctrl(&mtd, ((page_addr >> 8) & 0xff),
|
||||
NAND_CTRL_ALE); /* A[27:20] */
|
||||
hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
|
||||
hwctrl(mtd, ((page_addr >> 8) & 0xff),
|
||||
NAND_CTRL_ALE); /* A[27:20] */
|
||||
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
|
||||
/* One more address cycle for devices > 128MiB */
|
||||
hwctrl(&mtd, (page_addr >> 16) & 0x0f,
|
||||
hwctrl(mtd, (page_addr >> 16) & 0x0f,
|
||||
NAND_CTRL_ALE); /* A[31:28] */
|
||||
#endif
|
||||
/* Latch in address */
|
||||
hwctrl(&mtd, NAND_CMD_READSTART,
|
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_READSTART,
|
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/*
|
||||
* Wait a while for the data to be ready
|
||||
*/
|
||||
while (!this->dev_ready(&mtd))
|
||||
while (!this->dev_ready(mtd))
|
||||
;
|
||||
|
||||
return 0;
|
||||
@@ -114,7 +114,7 @@ static int nand_command(int block, int page, uint32_t offs,
|
||||
|
||||
static int nand_is_bad_block(int block)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char bb_data[2];
|
||||
|
||||
nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS,
|
||||
@@ -124,11 +124,11 @@ static int nand_is_bad_block(int block)
|
||||
* Read one byte (or two if it's a 16 bit chip).
|
||||
*/
|
||||
if (this->options & NAND_BUSWIDTH_16) {
|
||||
this->read_buf(&mtd, bb_data, 2);
|
||||
this->read_buf(mtd, bb_data, 2);
|
||||
if (bb_data[0] != 0xff || bb_data[1] != 0xff)
|
||||
return 1;
|
||||
} else {
|
||||
this->read_buf(&mtd, bb_data, 1);
|
||||
this->read_buf(mtd, bb_data, 1);
|
||||
if (bb_data[0] != 0xff)
|
||||
return 1;
|
||||
}
|
||||
@@ -139,7 +139,7 @@ static int nand_is_bad_block(int block)
|
||||
#if defined(CONFIG_SYS_NAND_HW_ECC_OOBFIRST)
|
||||
static int nand_read_page(int block, int page, uchar *dst)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char ecc_calc[ECCTOTAL];
|
||||
u_char ecc_code[ECCTOTAL];
|
||||
u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
|
||||
@@ -150,7 +150,7 @@ static int nand_read_page(int block, int page, uchar *dst)
|
||||
uint8_t *p = dst;
|
||||
|
||||
nand_command(block, page, 0, NAND_CMD_READOOB);
|
||||
this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||
this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||
nand_command(block, page, 0, NAND_CMD_READ0);
|
||||
|
||||
/* Pick the ECC bytes out of the oob data */
|
||||
@@ -159,10 +159,10 @@ static int nand_read_page(int block, int page, uchar *dst)
|
||||
|
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||
this->ecc.hwctl(&mtd, NAND_ECC_READ);
|
||||
this->read_buf(&mtd, p, eccsize);
|
||||
this->ecc.calculate(&mtd, p, &ecc_calc[i]);
|
||||
this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||
this->read_buf(mtd, p, eccsize);
|
||||
this->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -170,7 +170,7 @@ static int nand_read_page(int block, int page, uchar *dst)
|
||||
#else
|
||||
static int nand_read_page(int block, int page, void *dst)
|
||||
{
|
||||
struct nand_chip *this = mtd.priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char ecc_calc[ECCTOTAL];
|
||||
u_char ecc_code[ECCTOTAL];
|
||||
u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
|
||||
@@ -184,11 +184,11 @@ static int nand_read_page(int block, int page, void *dst)
|
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||
if (this->ecc.mode != NAND_ECC_SOFT)
|
||||
this->ecc.hwctl(&mtd, NAND_ECC_READ);
|
||||
this->read_buf(&mtd, p, eccsize);
|
||||
this->ecc.calculate(&mtd, p, &ecc_calc[i]);
|
||||
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||
this->read_buf(mtd, p, eccsize);
|
||||
this->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
}
|
||||
this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||
this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||
|
||||
/* Pick the ECC bytes out of the oob data */
|
||||
for (i = 0; i < ECCTOTAL; i++)
|
||||
@@ -202,7 +202,7 @@ static int nand_read_page(int block, int page, void *dst)
|
||||
* from correct_data(). We just hope that all possible errors
|
||||
* are corrected by this routine.
|
||||
*/
|
||||
this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -249,7 +249,7 @@ void nand_init(void)
|
||||
/*
|
||||
* Init board specific nand support
|
||||
*/
|
||||
mtd.priv = &nand_chip;
|
||||
mtd = &nand_chip.mtd;
|
||||
nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
|
||||
(void __iomem *)CONFIG_SYS_NAND_BASE;
|
||||
board_nand_init(&nand_chip);
|
||||
@@ -262,12 +262,12 @@ void nand_init(void)
|
||||
#endif
|
||||
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&mtd, 0);
|
||||
nand_chip.select_chip(mtd, 0);
|
||||
}
|
||||
|
||||
/* Unselect after operation */
|
||||
void nand_deselect(void)
|
||||
{
|
||||
if (nand_chip.select_chip)
|
||||
nand_chip.select_chip(&mtd, -1);
|
||||
nand_chip.select_chip(mtd, -1);
|
||||
}
|
||||
|
||||
@@ -42,25 +42,26 @@ typedef struct mtd_info mtd_info_t;
|
||||
* nand_erase_opts: - erase NAND flash with support for various options
|
||||
* (jffs2 formatting)
|
||||
*
|
||||
* @param meminfo NAND device to erase
|
||||
* @param mtd nand mtd instance to erase
|
||||
* @param opts options, @see struct nand_erase_options
|
||||
* @return 0 in case of success
|
||||
*
|
||||
* This code is ported from flash_eraseall.c from Linux mtd utils by
|
||||
* Arcom Control System Ltd.
|
||||
*/
|
||||
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
int nand_erase_opts(struct mtd_info *mtd,
|
||||
const nand_erase_options_t *opts)
|
||||
{
|
||||
struct jffs2_unknown_node cleanmarker;
|
||||
erase_info_t erase;
|
||||
unsigned long erase_length, erased_length; /* in blocks */
|
||||
int result;
|
||||
int percent_complete = -1;
|
||||
const char *mtd_device = meminfo->name;
|
||||
const char *mtd_device = mtd->name;
|
||||
struct mtd_oob_ops oob_opts;
|
||||
struct nand_chip *chip = meminfo->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if ((opts->offset & (meminfo->erasesize - 1)) != 0) {
|
||||
if ((opts->offset & (mtd->erasesize - 1)) != 0) {
|
||||
printf("Attempt to erase non block-aligned data\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -68,11 +69,11 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
memset(&erase, 0, sizeof(erase));
|
||||
memset(&oob_opts, 0, sizeof(oob_opts));
|
||||
|
||||
erase.mtd = meminfo;
|
||||
erase.len = meminfo->erasesize;
|
||||
erase.mtd = mtd;
|
||||
erase.len = mtd->erasesize;
|
||||
erase.addr = opts->offset;
|
||||
erase_length = lldiv(opts->length + meminfo->erasesize - 1,
|
||||
meminfo->erasesize);
|
||||
erase_length = lldiv(opts->length + mtd->erasesize - 1,
|
||||
mtd->erasesize);
|
||||
|
||||
cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
|
||||
@@ -97,7 +98,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
|
||||
for (erased_length = 0;
|
||||
erased_length < erase_length;
|
||||
erase.addr += meminfo->erasesize) {
|
||||
erase.addr += mtd->erasesize) {
|
||||
|
||||
WATCHDOG_RESET();
|
||||
|
||||
@@ -106,7 +107,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
return -EFBIG;
|
||||
}
|
||||
if (!opts->scrub) {
|
||||
int ret = mtd_block_isbad(meminfo, erase.addr);
|
||||
int ret = mtd_block_isbad(mtd, erase.addr);
|
||||
if (ret > 0) {
|
||||
if (!opts->quiet)
|
||||
printf("\rSkipping bad block at "
|
||||
@@ -129,7 +130,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
|
||||
erased_length++;
|
||||
|
||||
result = mtd_erase(meminfo, &erase);
|
||||
result = mtd_erase(mtd, &erase);
|
||||
if (result != 0) {
|
||||
printf("\n%s: MTD Erase failure: %d\n",
|
||||
mtd_device, result);
|
||||
@@ -145,9 +146,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
ops.ooboffs = 0;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
|
||||
result = mtd_write_oob(meminfo,
|
||||
erase.addr,
|
||||
&ops);
|
||||
result = mtd_write_oob(mtd, erase.addr, &ops);
|
||||
if (result != 0) {
|
||||
printf("\n%s: MTD writeoob failure: %d\n",
|
||||
mtd_device, result);
|
||||
@@ -218,7 +217,7 @@ int nand_lock(struct mtd_info *mtd, int tight)
|
||||
{
|
||||
int ret = 0;
|
||||
int status;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/* select the NAND device */
|
||||
chip->select_chip(mtd, 0);
|
||||
@@ -268,7 +267,7 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
|
||||
int ret = 0;
|
||||
int chipnr;
|
||||
int page;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/* select the NAND device */
|
||||
chipnr = (int)(offset >> chip->chip_shift);
|
||||
@@ -303,7 +302,7 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
|
||||
* @param mtd nand mtd instance
|
||||
* @param start start byte address
|
||||
* @param length number of bytes to unlock (must be a multiple of
|
||||
* page size nand->writesize)
|
||||
* page size mtd->writesize)
|
||||
* @param allexcept if set, unlock everything not selected
|
||||
*
|
||||
* @return 0 on success, -1 in case of error
|
||||
@@ -315,7 +314,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length,
|
||||
int chipnr;
|
||||
int status;
|
||||
int page;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
debug("nand_unlock%s: start: %08llx, length: %zd!\n",
|
||||
allexcept ? " (allexcept)" : "", start, length);
|
||||
@@ -399,7 +398,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length,
|
||||
* Check if there are any bad blocks, and whether length including bad
|
||||
* blocks fits into device
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param mtd nand mtd instance
|
||||
* @param offset offset in flash
|
||||
* @param length image length
|
||||
* @param used length of flash needed for the requested length
|
||||
@@ -407,8 +406,8 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length,
|
||||
* 1 if the image fits, but there are bad blocks
|
||||
* -1 if the image does not fit
|
||||
*/
|
||||
static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length,
|
||||
size_t *used)
|
||||
static int check_skip_len(struct mtd_info *mtd, loff_t offset, size_t length,
|
||||
size_t *used)
|
||||
{
|
||||
size_t len_excl_bad = 0;
|
||||
int ret = 0;
|
||||
@@ -417,14 +416,14 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length,
|
||||
size_t block_len, block_off;
|
||||
loff_t block_start;
|
||||
|
||||
if (offset >= nand->size)
|
||||
if (offset >= mtd->size)
|
||||
return -1;
|
||||
|
||||
block_start = offset & ~(loff_t)(nand->erasesize - 1);
|
||||
block_off = offset & (nand->erasesize - 1);
|
||||
block_len = nand->erasesize - block_off;
|
||||
block_start = offset & ~(loff_t)(mtd->erasesize - 1);
|
||||
block_off = offset & (mtd->erasesize - 1);
|
||||
block_len = mtd->erasesize - block_off;
|
||||
|
||||
if (!nand_block_isbad(nand, block_start))
|
||||
if (!nand_block_isbad(mtd, block_start))
|
||||
len_excl_bad += block_len;
|
||||
else
|
||||
ret = 1;
|
||||
@@ -441,7 +440,7 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_TRIMFFS
|
||||
static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
|
||||
static size_t drop_ffs(const struct mtd_info *mtd, const u_char *buf,
|
||||
const size_t *len)
|
||||
{
|
||||
size_t l = *len;
|
||||
@@ -453,8 +452,8 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
|
||||
|
||||
/* The resulting length must be aligned to the minimum flash I/O size */
|
||||
l = i + 1;
|
||||
l = (l + nand->writesize - 1) / nand->writesize;
|
||||
l *= nand->writesize;
|
||||
l = (l + mtd->writesize - 1) / mtd->writesize;
|
||||
l *= mtd->writesize;
|
||||
|
||||
/*
|
||||
* since the input length may be unaligned, prevent access past the end
|
||||
@@ -471,16 +470,17 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
|
||||
* Reads page of NAND and verifies the contents and OOB against the
|
||||
* values in ops.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param mtd nand mtd instance
|
||||
* @param ops MTD operations, including data to verify
|
||||
* @param ofs offset in flash
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs)
|
||||
int nand_verify_page_oob(struct mtd_info *mtd, struct mtd_oob_ops *ops,
|
||||
loff_t ofs)
|
||||
{
|
||||
int rval;
|
||||
struct mtd_oob_ops vops;
|
||||
size_t verlen = nand->writesize + nand->oobsize;
|
||||
size_t verlen = mtd->writesize + mtd->oobsize;
|
||||
|
||||
memcpy(&vops, ops, sizeof(vops));
|
||||
|
||||
@@ -489,9 +489,9 @@ int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs)
|
||||
if (!vops.datbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
vops.oobbuf = vops.datbuf + nand->writesize;
|
||||
vops.oobbuf = vops.datbuf + mtd->writesize;
|
||||
|
||||
rval = mtd_read_oob(nand, ofs, &vops);
|
||||
rval = mtd_read_oob(mtd, ofs, &vops);
|
||||
if (!rval)
|
||||
rval = memcmp(ops->datbuf, vops.datbuf, vops.len);
|
||||
if (!rval)
|
||||
@@ -510,17 +510,17 @@ int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs)
|
||||
* the contents of a buffer. The offset into the NAND must be
|
||||
* page-aligned, and the function doesn't handle skipping bad blocks.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param mtd nand mtd instance
|
||||
* @param ofs offset in flash
|
||||
* @param len buffer length
|
||||
* @param buf buffer to read from
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
|
||||
int nand_verify(struct mtd_info *mtd, loff_t ofs, size_t len, u_char *buf)
|
||||
{
|
||||
int rval = 0;
|
||||
size_t verofs;
|
||||
size_t verlen = nand->writesize;
|
||||
size_t verlen = mtd->writesize;
|
||||
uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen);
|
||||
|
||||
if (!verbuf)
|
||||
@@ -529,8 +529,8 @@ int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
|
||||
/* Read the NAND back in page-size groups to limit malloc size */
|
||||
for (verofs = ofs; verofs < ofs + len;
|
||||
verofs += verlen, buf += verlen) {
|
||||
verlen = min(nand->writesize, (uint32_t)(ofs + len - verofs));
|
||||
rval = nand_read(nand, verofs, &verlen, verbuf);
|
||||
verlen = min(mtd->writesize, (uint32_t)(ofs + len - verofs));
|
||||
rval = nand_read(mtd, verofs, &verlen, verbuf);
|
||||
if (!rval || (rval == -EUCLEAN))
|
||||
rval = memcmp(buf, verbuf, verlen);
|
||||
|
||||
@@ -558,7 +558,7 @@ int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
|
||||
* beyond the limit we are passed, length is set to 0 and actual is set
|
||||
* to the required length.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param mtd nand mtd instance
|
||||
* @param offset offset in flash
|
||||
* @param length buffer length
|
||||
* @param actual set to size required to write length worth of
|
||||
@@ -569,8 +569,8 @@ int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
|
||||
* @param flags flags modifying the behaviour of the write to NAND
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
size_t *actual, loff_t lim, u_char *buffer, int flags)
|
||||
int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,
|
||||
size_t *actual, loff_t lim, u_char *buffer, int flags)
|
||||
{
|
||||
int rval = 0, blocksize;
|
||||
size_t left_to_write = *length;
|
||||
@@ -581,7 +581,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
if (actual)
|
||||
*actual = 0;
|
||||
|
||||
blocksize = nand->erasesize;
|
||||
blocksize = mtd->erasesize;
|
||||
|
||||
/*
|
||||
* nand_write() handles unaligned, partial page writes.
|
||||
@@ -594,13 +594,13 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
* you should only start a block skipping access at a
|
||||
* partition boundary). So don't try to handle that.
|
||||
*/
|
||||
if ((offset & (nand->writesize - 1)) != 0) {
|
||||
if ((offset & (mtd->writesize - 1)) != 0) {
|
||||
printf("Attempt to write non page-aligned data\n");
|
||||
*length = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
need_skip = check_skip_len(nand, offset, *length, &used_for_write);
|
||||
need_skip = check_skip_len(mtd, offset, *length, &used_for_write);
|
||||
|
||||
if (actual)
|
||||
*actual = used_for_write;
|
||||
@@ -618,10 +618,10 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
}
|
||||
|
||||
if (!need_skip && !(flags & WITH_DROP_FFS)) {
|
||||
rval = nand_write(nand, offset, length, buffer);
|
||||
rval = nand_write(mtd, offset, length, buffer);
|
||||
|
||||
if ((flags & WITH_WR_VERIFY) && !rval)
|
||||
rval = nand_verify(nand, offset, *length, buffer);
|
||||
rval = nand_verify(mtd, offset, *length, buffer);
|
||||
|
||||
if (rval == 0)
|
||||
return 0;
|
||||
@@ -633,15 +633,15 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
}
|
||||
|
||||
while (left_to_write > 0) {
|
||||
size_t block_offset = offset & (nand->erasesize - 1);
|
||||
size_t block_offset = offset & (mtd->erasesize - 1);
|
||||
size_t write_size, truncated_write_size;
|
||||
|
||||
WATCHDOG_RESET();
|
||||
|
||||
if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) {
|
||||
if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) {
|
||||
printf("Skip bad block 0x%08llx\n",
|
||||
offset & ~(nand->erasesize - 1));
|
||||
offset += nand->erasesize - block_offset;
|
||||
offset & ~(mtd->erasesize - 1));
|
||||
offset += mtd->erasesize - block_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -653,15 +653,15 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
truncated_write_size = write_size;
|
||||
#ifdef CONFIG_CMD_NAND_TRIMFFS
|
||||
if (flags & WITH_DROP_FFS)
|
||||
truncated_write_size = drop_ffs(nand, p_buffer,
|
||||
truncated_write_size = drop_ffs(mtd, p_buffer,
|
||||
&write_size);
|
||||
#endif
|
||||
|
||||
rval = nand_write(nand, offset, &truncated_write_size,
|
||||
rval = nand_write(mtd, offset, &truncated_write_size,
|
||||
p_buffer);
|
||||
|
||||
if ((flags & WITH_WR_VERIFY) && !rval)
|
||||
rval = nand_verify(nand, offset,
|
||||
rval = nand_verify(mtd, offset,
|
||||
truncated_write_size, p_buffer);
|
||||
|
||||
offset += write_size;
|
||||
@@ -693,7 +693,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
* the limit we are passed, length is set to 0 and actual is set to the
|
||||
* required length.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param mtd nand mtd instance
|
||||
* @param offset offset in flash
|
||||
* @param length buffer length, on return holds number of read bytes
|
||||
* @param actual set to size required to read length worth of buffer or 0
|
||||
@@ -703,8 +703,8 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
* @param buffer buffer to write to
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
size_t *actual, loff_t lim, u_char *buffer)
|
||||
int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,
|
||||
size_t *actual, loff_t lim, u_char *buffer)
|
||||
{
|
||||
int rval;
|
||||
size_t left_to_read = *length;
|
||||
@@ -712,7 +712,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
u_char *p_buffer = buffer;
|
||||
int need_skip;
|
||||
|
||||
if ((offset & (nand->writesize - 1)) != 0) {
|
||||
if ((offset & (mtd->writesize - 1)) != 0) {
|
||||
printf("Attempt to read non page-aligned data\n");
|
||||
*length = 0;
|
||||
if (actual)
|
||||
@@ -720,7 +720,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
need_skip = check_skip_len(nand, offset, *length, &used_for_read);
|
||||
need_skip = check_skip_len(mtd, offset, *length, &used_for_read);
|
||||
|
||||
if (actual)
|
||||
*actual = used_for_read;
|
||||
@@ -738,7 +738,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
}
|
||||
|
||||
if (!need_skip) {
|
||||
rval = nand_read(nand, offset, length, buffer);
|
||||
rval = nand_read(mtd, offset, length, buffer);
|
||||
if (!rval || rval == -EUCLEAN)
|
||||
return 0;
|
||||
|
||||
@@ -749,24 +749,24 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
}
|
||||
|
||||
while (left_to_read > 0) {
|
||||
size_t block_offset = offset & (nand->erasesize - 1);
|
||||
size_t block_offset = offset & (mtd->erasesize - 1);
|
||||
size_t read_length;
|
||||
|
||||
WATCHDOG_RESET();
|
||||
|
||||
if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) {
|
||||
if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) {
|
||||
printf("Skipping bad block 0x%08llx\n",
|
||||
offset & ~(nand->erasesize - 1));
|
||||
offset += nand->erasesize - block_offset;
|
||||
offset & ~(mtd->erasesize - 1));
|
||||
offset += mtd->erasesize - block_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (left_to_read < (nand->erasesize - block_offset))
|
||||
if (left_to_read < (mtd->erasesize - block_offset))
|
||||
read_length = left_to_read;
|
||||
else
|
||||
read_length = nand->erasesize - block_offset;
|
||||
read_length = mtd->erasesize - block_offset;
|
||||
|
||||
rval = nand_read(nand, offset, &read_length, p_buffer);
|
||||
rval = nand_read(mtd, offset, &read_length, p_buffer);
|
||||
if (rval && rval != -EUCLEAN) {
|
||||
printf("NAND read from offset %llx failed %d\n",
|
||||
offset, rval);
|
||||
@@ -812,57 +812,57 @@ static int check_pattern(const u_char *buf, u_char patt, int size)
|
||||
* This is useful to determine if a block that caused a write error is still
|
||||
* good or should be marked as bad.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param mtd nand mtd instance
|
||||
* @param offset offset in flash
|
||||
* @return 0 if the block is still good
|
||||
*/
|
||||
int nand_torture(nand_info_t *nand, loff_t offset)
|
||||
int nand_torture(struct mtd_info *mtd, loff_t offset)
|
||||
{
|
||||
u_char patterns[] = {0xa5, 0x5a, 0x00};
|
||||
struct erase_info instr = {
|
||||
.mtd = nand,
|
||||
.addr = offset,
|
||||
.len = nand->erasesize,
|
||||
.len = mtd->erasesize,
|
||||
};
|
||||
size_t retlen;
|
||||
int err, ret = -1, i, patt_count;
|
||||
u_char *buf;
|
||||
|
||||
if ((offset & (nand->erasesize - 1)) != 0) {
|
||||
if ((offset & (mtd->erasesize - 1)) != 0) {
|
||||
puts("Attempt to torture a block at a non block-aligned offset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (offset + nand->erasesize > nand->size) {
|
||||
if (offset + mtd->erasesize > mtd->size) {
|
||||
puts("Attempt to torture a block outside the flash area\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
patt_count = ARRAY_SIZE(patterns);
|
||||
|
||||
buf = malloc_cache_aligned(nand->erasesize);
|
||||
buf = malloc_cache_aligned(mtd->erasesize);
|
||||
if (buf == NULL) {
|
||||
puts("Out of memory for erase block buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < patt_count; i++) {
|
||||
err = nand->erase(nand, &instr);
|
||||
err = mtd_erase(mtd, &instr);
|
||||
if (err) {
|
||||
printf("%s: erase() failed for block at 0x%llx: %d\n",
|
||||
nand->name, instr.addr, err);
|
||||
mtd->name, instr.addr, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Make sure the block contains only 0xff bytes */
|
||||
err = nand->read(nand, offset, nand->erasesize, &retlen, buf);
|
||||
if ((err && err != -EUCLEAN) || retlen != nand->erasesize) {
|
||||
err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf);
|
||||
if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) {
|
||||
printf("%s: read() failed for block at 0x%llx: %d\n",
|
||||
nand->name, instr.addr, err);
|
||||
mtd->name, instr.addr, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = check_pattern(buf, 0xff, nand->erasesize);
|
||||
err = check_pattern(buf, 0xff, mtd->erasesize);
|
||||
if (!err) {
|
||||
printf("Erased block at 0x%llx, but a non-0xff byte was found\n",
|
||||
offset);
|
||||
@@ -871,22 +871,22 @@ int nand_torture(nand_info_t *nand, loff_t offset)
|
||||
}
|
||||
|
||||
/* Write a pattern and check it */
|
||||
memset(buf, patterns[i], nand->erasesize);
|
||||
err = nand->write(nand, offset, nand->erasesize, &retlen, buf);
|
||||
if (err || retlen != nand->erasesize) {
|
||||
memset(buf, patterns[i], mtd->erasesize);
|
||||
err = mtd_write(mtd, offset, mtd->erasesize, &retlen, buf);
|
||||
if (err || retlen != mtd->erasesize) {
|
||||
printf("%s: write() failed for block at 0x%llx: %d\n",
|
||||
nand->name, instr.addr, err);
|
||||
mtd->name, instr.addr, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nand->read(nand, offset, nand->erasesize, &retlen, buf);
|
||||
if ((err && err != -EUCLEAN) || retlen != nand->erasesize) {
|
||||
err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf);
|
||||
if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) {
|
||||
printf("%s: read() failed for block at 0x%llx: %d\n",
|
||||
nand->name, instr.addr, err);
|
||||
mtd->name, instr.addr, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = check_pattern(buf, patterns[i], nand->erasesize);
|
||||
err = check_pattern(buf, patterns[i], mtd->erasesize);
|
||||
if (!err) {
|
||||
printf("Pattern 0x%.2x checking failed for block at "
|
||||
"0x%llx\n", patterns[i], offset);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Overview:
|
||||
* Platform independend driver for NDFC (NanD Flash Controller)
|
||||
* Platform independent driver for NDFC (NanD Flash Controller)
|
||||
* integrated into IBM/AMCC PPC4xx cores
|
||||
*
|
||||
* (C) Copyright 2006-2009
|
||||
@@ -37,7 +37,7 @@ static int ndfc_cs[NDFC_MAX_BANKS];
|
||||
|
||||
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
@@ -51,7 +51,7 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
|
||||
static int ndfc_dev_ready(struct mtd_info *mtdinfo)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtdinfo);
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
|
||||
return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY);
|
||||
@@ -59,7 +59,7 @@ static int ndfc_dev_ready(struct mtd_info *mtdinfo)
|
||||
|
||||
static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtdinfo);
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
u32 ccr;
|
||||
|
||||
@@ -71,7 +71,7 @@ static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode)
|
||||
static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtdinfo);
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
u32 ecc;
|
||||
u8 *p = (u8 *)&ecc;
|
||||
@@ -96,7 +96,7 @@ static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
|
||||
*/
|
||||
static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtdinfo);
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
@@ -110,7 +110,7 @@ static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
|
||||
*/
|
||||
static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtdinfo->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtdinfo);
|
||||
ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
@@ -124,7 +124,7 @@ static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len
|
||||
static uint8_t ndfc_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
|
||||
return (uint8_t) readw(chip->IO_ADDR_R);
|
||||
|
||||
@@ -58,8 +58,8 @@ static struct omap_nand_info omap_nand_info[GPMC_MAX_CS];
|
||||
static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
|
||||
uint32_t ctrl)
|
||||
{
|
||||
register struct nand_chip *this = mtd->priv;
|
||||
struct omap_nand_info *info = this->priv;
|
||||
register struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(this);
|
||||
int cs = info->cs;
|
||||
|
||||
/*
|
||||
@@ -85,8 +85,8 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
|
||||
/* Check wait pin as dev ready indicator */
|
||||
static int omap_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
register struct nand_chip *this = mtd->priv;
|
||||
struct omap_nand_info *info = this->priv;
|
||||
register struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(this);
|
||||
return gpmc_cfg->status & (1 << (8 + info->ws));
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
|
||||
return 0;
|
||||
printf("Error: Bad compare! failed\n");
|
||||
/* detected 2 bit error */
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -177,8 +177,8 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
|
||||
__maybe_unused
|
||||
static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct omap_nand_info *info = nand->priv;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(nand);
|
||||
unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
|
||||
unsigned int ecc_algo = 0;
|
||||
unsigned int bch_type = 0;
|
||||
@@ -262,8 +262,8 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
|
||||
static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
|
||||
uint8_t *ecc_code)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct omap_nand_info *info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(chip);
|
||||
uint32_t *ptr, val = 0;
|
||||
int8_t i = 0, j;
|
||||
|
||||
@@ -392,7 +392,7 @@ static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int le
|
||||
{
|
||||
int ret;
|
||||
uint32_t cnt;
|
||||
struct omap_nand_info *info = chip->priv;
|
||||
struct omap_nand_info *info = nand_get_controller_data(chip);
|
||||
|
||||
ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs);
|
||||
if (ret < 0)
|
||||
@@ -417,7 +417,7 @@ static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int le
|
||||
|
||||
static inline void omap_nand_read(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if (chip->options & NAND_BUSWIDTH_16)
|
||||
nand_read_buf16(mtd, buf, len);
|
||||
@@ -429,7 +429,7 @@ static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
uint32_t head, tail;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
/*
|
||||
* If the destination buffer is unaligned, start with reading
|
||||
@@ -491,8 +491,8 @@ static void omap_reverse_list(u8 *list, unsigned int length)
|
||||
static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
|
||||
uint8_t *read_ecc, uint8_t *calc_ecc)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct omap_nand_info *info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
uint32_t error_count = 0, error_max;
|
||||
uint32_t error_loc[ELM_MAX_ERROR_COUNT];
|
||||
@@ -652,8 +652,8 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
|
||||
int i, count;
|
||||
/* cannot correct more than 8 errors */
|
||||
unsigned int errloc[8];
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct omap_nand_info *info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(chip);
|
||||
|
||||
count = decode_bch(info->control, NULL, 512, read_ecc, calc_ecc,
|
||||
NULL, errloc);
|
||||
@@ -691,8 +691,8 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
|
||||
*/
|
||||
static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct omap_nand_info *info = chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = nand_get_controller_data(chip);
|
||||
|
||||
if (info->control) {
|
||||
free_bch(info->control);
|
||||
@@ -710,7 +710,7 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
|
||||
*/
|
||||
static int omap_select_ecc_scheme(struct nand_chip *nand,
|
||||
enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
|
||||
struct omap_nand_info *info = nand->priv;
|
||||
struct omap_nand_info *info = nand_get_controller_data(nand);
|
||||
struct nand_ecclayout *ecclayout = &omap_ecclayout;
|
||||
int eccsteps = pagesize / SECTOR_BYTES;
|
||||
int i;
|
||||
@@ -898,13 +898,13 @@ int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
|
||||
|
||||
if (nand_curr_device < 0 ||
|
||||
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
|
||||
!nand_info[nand_curr_device].name) {
|
||||
!nand_info[nand_curr_device]->name) {
|
||||
printf("nand: error: no NAND devices found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mtd = &nand_info[nand_curr_device];
|
||||
nand = mtd->priv;
|
||||
mtd = nand_info[nand_curr_device];
|
||||
nand = mtd_to_nand(mtd);
|
||||
nand->options |= NAND_OWN_BUFFERS;
|
||||
nand->options &= ~NAND_SUBPAGE_READ;
|
||||
/* Setup the ecc configurations again */
|
||||
@@ -994,7 +994,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
omap_nand_info[cs].control = NULL;
|
||||
omap_nand_info[cs].cs = cs;
|
||||
omap_nand_info[cs].ws = wscfg[cs];
|
||||
nand->priv = &omap_nand_info[cs];
|
||||
nand_set_controller_data(nand, &omap_nand_info[cs]);
|
||||
nand->cmd_ctrl = omap_nand_hwcontrol;
|
||||
nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
|
||||
nand->chip_delay = 100;
|
||||
|
||||
@@ -900,7 +900,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
|
||||
static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
int exec_cmd;
|
||||
|
||||
@@ -960,7 +961,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
|
||||
const unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
int exec_cmd, ext_cmd_type;
|
||||
|
||||
@@ -1079,7 +1081,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
|
||||
}
|
||||
|
||||
static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
chip->write_buf(mtd, buf, mtd->writesize);
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
@@ -1091,7 +1094,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
|
||||
chip->read_buf(mtd, buf, mtd->writesize);
|
||||
@@ -1117,7 +1120,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
|
||||
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
char retval = 0xFF;
|
||||
|
||||
@@ -1130,7 +1134,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
|
||||
|
||||
static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
u16 retval = 0xFFFF;
|
||||
|
||||
@@ -1143,7 +1148,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
|
||||
|
||||
static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
|
||||
|
||||
@@ -1154,7 +1160,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
|
||||
|
||||
@@ -1169,7 +1176,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
|
||||
static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
|
||||
if (info->need_wait) {
|
||||
@@ -1210,7 +1218,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = info->host[info->cs];
|
||||
struct mtd_info *mtd = host->mtd;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
|
||||
info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
|
||||
@@ -1262,7 +1270,7 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host)
|
||||
int ret;
|
||||
|
||||
mtd = info->host[info->cs]->mtd;
|
||||
chip = mtd->priv;
|
||||
chip = mtd_to_nand(mtd);
|
||||
|
||||
/* configure default flash values */
|
||||
info->reg_ndcr = 0x0; /* enable all interrupts */
|
||||
@@ -1354,10 +1362,10 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
|
||||
|
||||
static int pxa3xx_nand_scan(struct mtd_info *mtd)
|
||||
{
|
||||
struct pxa3xx_nand_host *host = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct pxa3xx_nand_info *info = host->info_data;
|
||||
struct pxa3xx_nand_platform_data *pdata = info->pdata;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
int ret;
|
||||
uint16_t ecc_strength, ecc_step;
|
||||
|
||||
@@ -1477,16 +1485,15 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info)
|
||||
|
||||
info->variant = pxa3xx_nand_get_variant();
|
||||
for (cs = 0; cs < pdata->num_cs; cs++) {
|
||||
mtd = &nand_info[cs];
|
||||
chip = (struct nand_chip *)
|
||||
((u8 *)&info[1] + sizeof(*host) * cs);
|
||||
mtd = nand_to_mtd(chip);
|
||||
host = (struct pxa3xx_nand_host *)chip;
|
||||
info->host[cs] = host;
|
||||
host->mtd = mtd;
|
||||
host->cs = cs;
|
||||
host->info_data = info;
|
||||
host->read_id_bytes = 4;
|
||||
mtd->priv = host;
|
||||
mtd->owner = THIS_MODULE;
|
||||
|
||||
chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
|
||||
@@ -1573,8 +1580,10 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
probe_success = 1;
|
||||
if (nand_register(cs, mtd))
|
||||
continue;
|
||||
|
||||
probe_success = 1;
|
||||
}
|
||||
|
||||
if (!probe_success)
|
||||
@@ -1601,6 +1610,4 @@ void board_nand_init(void)
|
||||
ret = pxa3xx_nand_probe(info);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
nand_register(0);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = readb(this->IO_ADDR_R);
|
||||
@@ -40,7 +40,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
|
||||
static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
|
||||
|
||||
debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
|
||||
@@ -104,7 +104,7 @@ static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
return 0;
|
||||
|
||||
printf("s3c24x0_nand_correct_data: not implemented\n");
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -143,10 +143,10 @@ static int nand_waitfor_cmd_completion(struct nand_ctlr *reg)
|
||||
*/
|
||||
static uint8_t read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_drv *info;
|
||||
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
|
||||
writel(CMD_GO | CMD_PIO | CMD_RX | CMD_CE0 | CMD_A_VALID,
|
||||
&info->reg->command);
|
||||
@@ -169,8 +169,8 @@ static void read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
int i, s;
|
||||
unsigned int reg;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_drv *info = (struct nand_drv *)chip->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_drv *info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
s = (len - i) > 4 ? 4 : len - i;
|
||||
@@ -194,11 +194,11 @@ static void read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
*/
|
||||
static int nand_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int reg_val;
|
||||
struct nand_drv *info;
|
||||
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
|
||||
reg_val = readl(&info->reg->status);
|
||||
if (reg_val & STATUS_RBSY0)
|
||||
@@ -245,10 +245,10 @@ static void nand_clear_interrupt_status(struct nand_ctlr *reg)
|
||||
static void nand_command(struct mtd_info *mtd, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_drv *info;
|
||||
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
|
||||
/*
|
||||
* Write out the command to the device.
|
||||
@@ -512,7 +512,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
config = &info->config;
|
||||
if (set_bus_width_page_size(config, ®_val))
|
||||
return -EINVAL;
|
||||
@@ -657,16 +657,9 @@ static int nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
* @param buf data buffer
|
||||
*/
|
||||
static int nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
int page;
|
||||
struct nand_drv *info;
|
||||
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
|
||||
page = (readl(&info->reg->addr_reg1) >> 16) |
|
||||
(readl(&info->reg->addr_reg2) << 16);
|
||||
|
||||
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
@@ -697,15 +690,9 @@ static int nand_read_page_raw(struct mtd_info *mtd,
|
||||
* @param buf data buffer
|
||||
*/
|
||||
static int nand_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
int page;
|
||||
struct nand_drv *info;
|
||||
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
page = (readl(&info->reg->addr_reg1) >> 16) |
|
||||
(readl(&info->reg->addr_reg2) << 16);
|
||||
|
||||
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1);
|
||||
return 0;
|
||||
}
|
||||
@@ -734,7 +721,7 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
if (((int)chip->oob_poi) & 0x03)
|
||||
return -EINVAL;
|
||||
info = (struct nand_drv *)chip->priv;
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
if (set_bus_width_page_size(&info->config, ®_val))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -963,7 +950,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
||||
nand->ecc.strength = 1;
|
||||
nand->select_chip = nand_select_chip;
|
||||
nand->dev_ready = nand_dev_ready;
|
||||
nand->priv = &nand_ctrl;
|
||||
nand_set_controller_data(nand, &nand_ctrl);
|
||||
|
||||
/* Disable subpage writes as we do not provide ecc->hwctl */
|
||||
nand->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
@@ -976,8 +963,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
||||
|
||||
dm_gpio_set_value(&config->wp_gpio, 1);
|
||||
|
||||
our_mtd = &nand_info[devnum];
|
||||
our_mtd->priv = nand;
|
||||
our_mtd = nand_to_mtd(nand);
|
||||
ret = nand_scan_ident(our_mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -989,7 +975,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_register(devnum);
|
||||
ret = nand_register(devnum, our_mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -146,7 +146,6 @@ enum vf610_nfc_alt_buf {
|
||||
};
|
||||
|
||||
struct vf610_nfc {
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip chip;
|
||||
void __iomem *regs;
|
||||
uint buf_offset;
|
||||
@@ -155,8 +154,7 @@ struct vf610_nfc {
|
||||
enum vf610_nfc_alt_buf alt_buf;
|
||||
};
|
||||
|
||||
#define mtd_to_nfc(_mtd) \
|
||||
(struct vf610_nfc *)((struct nand_chip *)_mtd->priv)->priv
|
||||
#define mtd_to_nfc(_mtd) nand_get_controller_data(mtd_to_nand(_mtd))
|
||||
|
||||
#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES)
|
||||
#define ECC_HW_MODE ECC_45_BYTE
|
||||
@@ -608,7 +606,7 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* ECC will be calculated automatically
|
||||
*/
|
||||
static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
|
||||
|
||||
@@ -630,7 +628,7 @@ struct vf610_nfc_config {
|
||||
|
||||
static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
||||
{
|
||||
struct mtd_info *mtd = &nand_info[devnum];
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *chip;
|
||||
struct vf610_nfc *nfc;
|
||||
int err = 0;
|
||||
@@ -653,8 +651,8 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
||||
chip = &nfc->chip;
|
||||
nfc->regs = addr;
|
||||
|
||||
mtd->priv = chip;
|
||||
chip->priv = nfc;
|
||||
mtd = nand_to_mtd(chip);
|
||||
nand_set_controller_data(chip, nfc);
|
||||
|
||||
if (cfg.width == 16)
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
@@ -753,7 +751,7 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nand_register(devnum);
|
||||
err = nand_register(devnum, mtd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ int fm_init_common(int index, struct ccsr_fman *reg)
|
||||
size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
|
||||
void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
|
||||
|
||||
rc = nand_read(&nand_info[0], (loff_t)CONFIG_SYS_FMAN_FW_ADDR,
|
||||
rc = nand_read(nand_info[0], (loff_t)CONFIG_SYS_FMAN_FW_ADDR,
|
||||
&fw_length, (u_char *)addr);
|
||||
if (rc == -EUCLEAN) {
|
||||
printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
|
||||
|
||||
@@ -139,8 +139,8 @@ void cs4340_upload_firmware(struct phy_device *phydev)
|
||||
size_t fw_length = CONFIG_CORTINA_FW_LENGTH;
|
||||
|
||||
addr = malloc(CONFIG_CORTINA_FW_LENGTH);
|
||||
ret = nand_read(&nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR,
|
||||
&fw_length, (u_char *)addr);
|
||||
ret = nand_read(nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR,
|
||||
&fw_length, (u_char *)addr);
|
||||
if (ret == -EUCLEAN) {
|
||||
printf("NAND read of Cortina firmware at 0x%x failed %d\n",
|
||||
CONFIG_CORTINA_FW_ADDR, ret);
|
||||
|
||||
Reference in New Issue
Block a user