X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fam335x_spl_bch.c;h=e68b4a5b19612ab5fee44f57b1270afef5cb73de;hb=6f84b26b53afa207092a8906fa08f4c78d65afb6;hp=c84851bab58ea193cdeff3cd51f352f76230a5c4;hpb=326ea986ac150acdc7656d57fca647db80b50158;p=oweals%2Fu-boot.git diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/am335x_spl_bch.c index c84851bab5..e68b4a5b19 100644 --- a/drivers/mtd/nand/am335x_spl_bch.c +++ b/drivers/mtd/nand/am335x_spl_bch.c @@ -16,7 +16,7 @@ #include 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 / \ @@ -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 = 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 */ @@ -45,58 +45,90 @@ static int nand_command(int block, int page, uint32_t offs, } /* Begin command latch cycle */ - hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); if (cmd == NAND_CMD_RESET) { - hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!this->dev_ready(&mtd)) + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Apply this short delay always to ensure that we do wait + * tWB in any case on any machine. + */ + ndelay(150); + + while (!this->dev_ready(mtd)) ; return 0; } /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; /* Set ALE and clear CLE to start address cycle */ /* Column address */ - hwctrl(&mtd, offs & 0xff, + 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 >> 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), + if (cmd != NAND_CMD_RNDOUT) { + 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, + /* One more address cycle for devices > 128MiB */ + hwctrl(mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE); /* A[31:28] */ #endif - hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + } - if (cmd == NAND_CMD_READ0) { - /* 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_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* - * Wait a while for the data to be ready - */ - while (!this->dev_ready(&mtd)) - ; - } else if (cmd == NAND_CMD_RNDOUT) { - hwctrl(&mtd, NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE | - NAND_CTRL_CHANGE); - hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status, sequential + * in and status need no delay. + */ + switch (cmd) { + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_RNDIN: + case NAND_CMD_STATUS: + return 0; + + case NAND_CMD_RNDOUT: + /* No ready / busy check necessary */ + hwctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE | + NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + return 0; + + case NAND_CMD_READ0: + /* Latch in address */ + hwctrl(mtd, NAND_CMD_READSTART, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); } + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(150); + + while (!this->dev_ready(mtd)) + ; + return 0; } 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); @@ -117,7 +149,7 @@ static int nand_is_bad_block(int block) 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]; @@ -133,15 +165,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(&mtd, NAND_ECC_READ); + this->ecc.hwctl(mtd, NAND_ECC_READ); nand_command(block, page, data_pos, NAND_CMD_RNDOUT); - this->read_buf(&mtd, p, eccsize); + this->read_buf(mtd, p, eccsize); nand_command(block, page, oob_pos, NAND_CMD_RNDOUT); - this->read_buf(&mtd, oob, eccbytes); - this->ecc.calculate(&mtd, p, &ecc_calc[i]); + this->read_buf(mtd, oob, eccbytes); + this->ecc.calculate(mtd, p, &ecc_calc[i]); data_pos += eccsize; oob_pos += eccbytes; @@ -160,41 +192,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]); - } - - return 0; -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page; - - /* - * offs has to be aligned to a page address! - */ - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - /* - * Skip bad blocks - */ - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; + this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); } return 0; @@ -206,13 +204,13 @@ void nand_init(void) /* * Init board specific nand support */ - mtd.priv = &nand_chip; + mtd = nand_to_mtd(&nand_chip); 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(&mtd, 0); + nand_chip.select_chip(mtd, 0); /* NAND chip may require reset after power-on */ nand_command(0, 0, 0, NAND_CMD_RESET); @@ -222,5 +220,7 @@ void nand_init(void) void nand_deselect(void) { if (nand_chip.select_chip) - nand_chip.select_chip(&mtd, -1); + nand_chip.select_chip(mtd, -1); } + +#include "nand_spl_loaders.c"