From c568f77acdf896fc3dd6413ce53205b17ba809a3 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Sat, 5 Jan 2008 16:49:37 +0100 Subject: NAND: Update nand_spl driver to match updated nand subsystem This patch changes the NAND booting driver nand_spl/nand_boot.c to match the new infrastructure from the updated NAND subsystem. This NAND subsystem was recently synced again with the Linux 2.6.22 MTD/NAND subsystem. Signed-off-by: Stefan Roese --- nand_spl/nand_boot.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'nand_spl/nand_boot.c') diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 563a80b9537..5914d040343 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -20,6 +20,7 @@ #include #include +#include #define CFG_NAND_READ_DELAY \ { volatile int dummy; int i; for (i=0; i<10000; i++) dummy = i; } @@ -36,34 +37,37 @@ static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 { struct nand_chip *this = mtd->priv; int page_addr = page + block * CFG_NAND_PAGE_COUNT; + int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; if (this->dev_ready) - this->dev_ready(mtd); + while (!this->dev_ready(mtd)) + ; else CFG_NAND_READ_DELAY; /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, cmd); + this->cmd_ctrl(mtd, cmd, ctrl); /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - this->hwcontrol(mtd, NAND_CTL_SETALE); + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; /* Column address */ - this->write_byte(mtd, offs); /* A[7:0] */ - this->write_byte(mtd, (uchar)(page_addr & 0xff)); /* A[16:9] */ - this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff)); /* A[24:17] */ + this->cmd_ctrl(mtd, offs, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + this->cmd_ctrl(mtd, (u8)(page_addr & 0xff), ctrl); /* A[16:9] */ + ctrl &= ~NAND_CTRL_CHANGE; + this->cmd_ctrl(mtd, (u8)((page_addr >> 8) & 0xff), ctrl); /* A[24:17] */ #ifdef CFG_NAND_4_ADDR_CYCLE /* One more address cycle for devices > 32MiB */ - this->write_byte(mtd, (uchar)((page_addr >> 16) & 0x0f)); /* A[xx:25] */ + this->cmd_ctrl(mtd, (u8)((page_addr >> 16) & 0x0f), ctrl); /* A[xx:25] */ #endif /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* * Wait a while for the data to be ready */ if (this->dev_ready) - this->dev_ready(mtd); + while (!this->dev_ready(mtd)) + ; else CFG_NAND_READ_DELAY; @@ -137,7 +141,7 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block) /* * Read one byte */ - if (this->read_byte(mtd) != 0xff) + if (in_8(this->IO_ADDR_R) != 0xff) return 1; return 0; @@ -166,9 +170,9 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst) oob_data = ecc_calc + 0x200; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - this->enable_hwecc(mtd, NAND_ECC_READ); + this->ecc.hwctl(mtd, NAND_ECC_READ); this->read_buf(mtd, p, eccsize); - this->calculate_ecc(mtd, p, &ecc_calc[i]); + this->ecc.calculate(mtd, p, &ecc_calc[i]); } this->read_buf(mtd, oob_data, CFG_NAND_OOBSIZE); @@ -184,7 +188,7 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst) * from correct_data(). We just hope that all possible errors * are corrected by this routine. */ - stat = this->correct_data(mtd, p, &ecc_code[i], &ecc_calc[i]); + stat = this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); } return 0; -- cgit v1.2.3 From e4c09508545d1c45617ba45391c03c03cbc360b9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 30 Jun 2008 14:13:28 -0500 Subject: NAND boot: MPC8313ERDB support Note that with older board revisions, NAND boot may only work after a power-on reset, and not after a warm reset. I don't have a newer board to test on; if you have a board with a 33MHz crystal, please let me know if it works after a warm reset. Signed-off-by: Scott Wood --- nand_spl/nand_boot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nand_spl/nand_boot.c') diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 5914d040343..0f56ba52020 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -235,7 +235,7 @@ void nand_boot(void) struct nand_chip nand_chip; nand_info_t nand_info; int ret; - void (*uboot)(void); + __attribute__((noreturn)) void (*uboot)(void); /* * Init board specific nand support @@ -254,6 +254,6 @@ void nand_boot(void) /* * Jump to U-Boot image */ - uboot = (void (*)(void))CFG_NAND_U_BOOT_START; + uboot = (void *)CFG_NAND_U_BOOT_START; (*uboot)(); } -- cgit v1.2.3 From 4f32d7760a58fe73981b6edc0b0751565d2daa4c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 5 Aug 2008 11:15:59 -0500 Subject: NAND boot: Update large page support for current API. Also, remove the ctrl variable in favor of passing the constants directly, and remove redundant (u8) casts. Signed-off-by: Scott Wood --- nand_spl/nand_boot.c | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) (limited to 'nand_spl/nand_boot.c') diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 0f56ba52020..81b4dfc5414 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -37,7 +37,6 @@ static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 { struct nand_chip *this = mtd->priv; int page_addr = page + block * CFG_NAND_PAGE_COUNT; - int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; if (this->dev_ready) while (!this->dev_ready(mtd)) @@ -46,18 +45,15 @@ static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 CFG_NAND_READ_DELAY; /* Begin command latch cycle */ - this->cmd_ctrl(mtd, cmd, ctrl); + this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); /* Set ALE and clear CLE to start address cycle */ - ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; /* Column address */ - this->cmd_ctrl(mtd, offs, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - this->cmd_ctrl(mtd, (u8)(page_addr & 0xff), ctrl); /* A[16:9] */ - ctrl &= ~NAND_CTRL_CHANGE; - this->cmd_ctrl(mtd, (u8)((page_addr >> 8) & 0xff), ctrl); /* A[24:17] */ + this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + this->cmd_ctrl(mtd, page_addr & 0xff, 0); /* A[16:9] */ + this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff, 0); /* A[24:17] */ #ifdef CFG_NAND_4_ADDR_CYCLE /* One more address cycle for devices > 32MiB */ - this->cmd_ctrl(mtd, (u8)((page_addr >> 16) & 0x0f), ctrl); /* A[xx:25] */ + this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f, 0); /* A[28:25] */ #endif /* Latch in address */ this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); @@ -80,51 +76,45 @@ static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd) { struct nand_chip *this = mtd->priv; - int page_offs = offs; int page_addr = page + block * CFG_NAND_PAGE_COUNT; if (this->dev_ready) - this->dev_ready(mtd); + while (!this->dev_ready(mtd)) + ; else CFG_NAND_READ_DELAY; /* Emulate NAND_CMD_READOOB */ if (cmd == NAND_CMD_READOOB) { - page_offs += CFG_NAND_PAGE_SIZE; + offs += CFG_NAND_PAGE_SIZE; cmd = NAND_CMD_READ0; } /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, cmd); + this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - this->hwcontrol(mtd, NAND_CTL_SETALE); /* Column address */ - this->write_byte(mtd, page_offs & 0xff); /* A[7:0] */ - this->write_byte(mtd, (uchar)((page_offs >> 8) & 0xff)); /* A[11:9] */ + this->cmd_ctrl(mtd, offs & 0xff, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ + this->cmd_ctrl(mtd, (offs >> 8) & 0xff, 0); /* A[11:9] */ /* Row address */ - this->write_byte(mtd, (uchar)(page_addr & 0xff)); /* A[19:12] */ - this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff)); /* A[27:20] */ + this->cmd_ctrl(mtd, (page_addr & 0xff), 0); /* A[19:12] */ + this->cmd_ctrl(mtd, ((page_addr >> 8) & 0xff), 0); /* A[27:20] */ #ifdef CFG_NAND_5_ADDR_CYCLE /* One more address cycle for devices > 128MiB */ - this->write_byte(mtd, (uchar)((page_addr >> 16) & 0x0f)); /* A[xx:28] */ + this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f, 0); /* A[31:28] */ #endif /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); - - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - /* Write out the start read command */ - this->write_byte(mtd, NAND_CMD_READSTART); - /* End command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + this->cmd_ctrl(mtd, NAND_CMD_READSTART, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* * Wait a while for the data to be ready */ if (this->dev_ready) - this->dev_ready(mtd); + while (!this->dev_ready(mtd)) + ; else CFG_NAND_READ_DELAY; -- cgit v1.2.3 From aa646643b6bc250cb3a4966bf728876e0c10d329 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 6 Aug 2008 21:42:07 +0200 Subject: nand_spl: Support page-aligned read in nand_load, use chipselect Supporting page-aligned reads doesn't incure any sinificant overhead, just a small change in the algorithm. Also replace in_8 with readb, since there is no in_8 on ARM. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Scott Wood --- nand_spl/nand_boot.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'nand_spl/nand_boot.c') diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 81b4dfc5414..16d128fc836 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -131,7 +131,7 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block) /* * Read one byte */ - if (in_8(this->IO_ADDR_R) != 0xff) + if (readb(this->IO_ADDR_R) != 0xff) return 1; return 0; @@ -184,29 +184,33 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst) return 0; } -static int nand_load(struct mtd_info *mtd, int offs, int uboot_size, uchar *dst) +static int nand_load(struct mtd_info *mtd, unsigned int offs, + unsigned int uboot_size, uchar *dst) { - int block; - int blockcopy_count; - int page; + unsigned int block, lastblock; + unsigned int page; /* - * offs has to be aligned to a block address! + * offs has to be aligned to a page address! */ block = offs / CFG_NAND_BLOCK_SIZE; - blockcopy_count = 0; + lastblock = (offs + uboot_size - 1) / CFG_NAND_BLOCK_SIZE; + page = (offs % CFG_NAND_BLOCK_SIZE) / CFG_NAND_PAGE_SIZE; - while (blockcopy_count < (uboot_size / CFG_NAND_BLOCK_SIZE)) { + while (block <= lastblock) { if (!nand_is_bad_block(mtd, block)) { /* * Skip bad blocks */ - for (page = 0; page < CFG_NAND_PAGE_COUNT; page++) { + while (page < CFG_NAND_PAGE_COUNT) { nand_read_page(mtd, block, page, dst); dst += CFG_NAND_PAGE_SIZE; + page++; } - blockcopy_count++; + page = 0; + } else { + lastblock++; } block++; @@ -235,12 +239,18 @@ void nand_boot(void) nand_chip.dev_ready = NULL; /* preset to NULL */ board_nand_init(&nand_chip); + if (nand_chip.select_chip) + nand_chip.select_chip(&nand_info, 0); + /* * Load U-Boot image from NAND into RAM */ ret = nand_load(&nand_info, CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE, (uchar *)CFG_NAND_U_BOOT_DST); + if (nand_chip.select_chip) + nand_chip.select_chip(&nand_info, -1); + /* * Jump to U-Boot image */ -- cgit v1.2.3