
Some platforms read the nand type to make configuration choices. For example, some versions of OMAP3 Beagle use the NAND type as a hint of the DRAM type.
Turn readid support on with CONFIG_SYS_NAND_BOOT_READID
Add 16-bit nand support. Turn it on with CONFIG_SYS_NAND_BUSWIDTH_16
Signed-off-by: John Rigby john.rigby@linaro.org CC: Scott Wood scootwood@freescale.com --- include/nand.h | 3 + nand_spl/nand_boot.c | 134 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 112 insertions(+), 25 deletions(-)
diff --git a/include/nand.h b/include/nand.h index a452411..3c6237a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -130,6 +130,9 @@ int nand_get_lock_status(nand_info_t *meminfo, loff_t offset); void board_nand_select_device(struct nand_chip *nand, int chip); #endif
+#ifdef CONFIG_SYS_NAND_BOOT_READID +int nand_boot_readid(int *manf_id, int *dev_id); +#endif __attribute__((noreturn)) void nand_boot(void);
#endif diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 76b8566..1ae2cd0 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -27,6 +27,15 @@
static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
+static uint8_t nand_read_byte(struct nand_chip *chip) +{ +#ifndef CONFIG_SYS_NAND_BUSWIDTH_16 + return readb(chip->IO_ADDR_R); +#else + return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); +#endif +} + #if (CONFIG_SYS_NAND_PAGE_SIZE <= 512) /* * NAND command for small page NAND devices (512) @@ -46,6 +55,9 @@ static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); /* Set ALE and clear CLE to start address cycle */ /* Column address */ +#ifdef CONFIG_SYS_NAND_BUSWIDTH_16 + offs >>= 1; +#endif 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, @@ -94,6 +106,9 @@ static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); /* Set ALE and clear CLE to start address cycle */ /* Column address */ +#ifdef CONFIG_SYS_NAND_BUSWIDTH_16 + offs >>= 1; +#endif this->cmd_ctrl(mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ this->cmd_ctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ @@ -128,17 +143,27 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block) { struct nand_chip *this = mtd->priv;
+#ifndef CONFIG_SYS_NAND_BUSWIDTH_16 + bad = 0; nand_command(mtd, block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB); - - /* - * Read one byte - */ if (readb(this->IO_ADDR_R) != 0xff) return 1; - +#else + u16 bad; + nand_command(mtd, block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS & 0xFE, NAND_CMD_READOOB); + bad = cpu_to_le16(readw(this->IO_ADDR_R)); + if (CONFIG_SYS_NAND_BAD_BLOCK_POS & 0x1) + bad >> 8; + if ((bad & 0xff) != 0xff) + return 1; +#endif return 0; }
+#ifndef CONFIG_SYS_NAND_BOOT_ECC_SCRATCH +#define CONFIG_SYS_NAND_BOOT_ECC_SCRATCH 0x10000 +#endif + static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst) { struct nand_chip *this = mtd->priv; @@ -222,47 +247,54 @@ static int nand_load(struct mtd_info *mtd, unsigned int offs, }
/* + * Get ready for booting from NAND. This is for platforms + * that need to read nand data or nand chip id's before initializing + * SDRAM. + */ +void nand_boot_init(struct nand_chip *nand_chip, nand_info_t (*nand_info)) +{ + /* + * Init board specific nand support + */ + nand_chip->select_chip = NULL; + nand_info->priv = nand_chip; + nand_chip->IO_ADDR_R = nand_chip->IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE; + 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); + +} + +/* * The main entry for NAND booting. It's necessary that SDRAM is already * configured and available since this code loads the main U-Boot image * from NAND into SDRAM and starts it from there. */ -void nand_boot(void) +void nand_boot_tail(struct nand_chip *nand_chip, nand_info_t *nand_info) { - struct nand_chip nand_chip; - nand_info_t nand_info; int ret; __attribute__((noreturn)) void (*uboot)(void);
/* - * Init board specific nand support - */ - nand_chip.select_chip = NULL; - nand_info.priv = &nand_chip; - nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE; - 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, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE, + ret = nand_load(nand_info, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE, (uchar *)CONFIG_SYS_NAND_U_BOOT_DST);
#ifdef CONFIG_NAND_ENV_DST - nand_load(&nand_info, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, + nand_load(nand_info, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, (uchar *)CONFIG_NAND_ENV_DST);
#ifdef CONFIG_ENV_OFFSET_REDUND - nand_load(&nand_info, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, + nand_load(nand_info, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); #endif #endif
- if (nand_chip.select_chip) - nand_chip.select_chip(&nand_info, -1); + if (nand_chip->select_chip) + nand_chip->select_chip(nand_info, -1);
/* * Jump to U-Boot image @@ -270,3 +302,55 @@ void nand_boot(void) uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; (*uboot)(); } + +#ifdef CONFIG_SYS_NAND_BOOT_READID +int nand_boot_readid(int *manf_id, int *dev_id) +{ + struct nand_chip nand_chip; + nand_info_t nand_info; + + nand_boot_init(&nand_chip, &nand_info); + + /* + * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) + * after power-up + */ + nand_chip.cmd_ctrl(&nand_info, NAND_CMD_RESET, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + + if (!nand_chip.dev_ready) { + CONFIG_SYS_NAND_READ_DELAY; + nand_chip.cmd_ctrl(&nand_info, NAND_CMD_STATUS, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + nand_chip.cmd_ctrl(&nand_info, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + while (!(nand_read_byte(&nand_chip) & NAND_STATUS_READY)) + CONFIG_SYS_NAND_READ_DELAY; + } + + /* Send the command for reading device ID */ + nand_chip.cmd_ctrl(&nand_info, NAND_CMD_READID, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + nand_chip.cmd_ctrl(&nand_info, 0x0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + nand_chip.cmd_ctrl(&nand_info, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + + /* Read manufacturer and device IDs */ + *manf_id = nand_read_byte(&nand_chip); + *dev_id = nand_read_byte(&nand_chip); + + if (nand_chip.select_chip) + nand_chip.select_chip(&nand_info, -1); + + return 0; +} +#endif + + +/* + * Init the nand subsystem and boot. + */ +void nand_boot(void) +{ + struct nand_chip nand_chip; + nand_info_t nand_info; + + nand_boot_init(&nand_chip, &nand_info); + nand_boot_tail(&nand_chip, &nand_info); +}