[U-Boot] [RFC] omap3: single binary supporting all flash types

Hi there!
currently it is not possible to build single working OMAP3 binary which enables more than one of these: CONFIG_NOR CONFIG_NAND CONFIG_CMD_ONENAND first problem lies in gpmc_init which configures CS[0] to one flash type determined at compile time. Another is that identify_nand_chip hang when trying to indentify chip which is not present. The same issue is with OneNAND mtd driver. And finally omap_gpmc:board_nand_init() searches for NAND specific configuration in gpmc config1 register - but that value is forced earlier from gpmc_init, making test completely pointless. Most of these issues are fixed with patches sent as reply to this message, but:
As we might want to use single binary also to boot from MMC or other sources, we cannot use boot_device to get a glue about used flash type. Also U-Boot should not count on being loaded by its own SPL. So, to make things easier to begin with, do we all agree that omap_gpmc:board_nand_init as well as its OneNAND counterpart should expect gpmc config1 register properly set and fail if something unexpected is found? That basically means if we should rely on CS0 config provided by first stage loader or try to rediscover flash devices (this problem does not exist when flash itself is boot source)
Thank you for your attention, ladis

identify_nand_chip hangs forever in loop when NAND is not present. As IGEPv2 comes either with NAND or OneNAND flash, add reset timeout to let function fail gracefully allowing caller to know NAND is not present. On NAND equipped board, reset succeeds on first read, so 1000 loops seems to be a safe timeout.
Signed-off-by: Ladislav Michl ladis@linux-mips.org --- arch/arm/cpu/armv7/omap3/spl_id_nand.c | 32 +++++++++++++---------------- arch/arm/include/asm/arch-omap3/sys_proto.h | 2 +- 2 files changed, 15 insertions(+), 19 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap3/spl_id_nand.c b/arch/arm/cpu/armv7/omap3/spl_id_nand.c index db6de09..26d3aa4 100644 --- a/arch/arm/cpu/armv7/omap3/spl_id_nand.c +++ b/arch/arm/cpu/armv7/omap3/spl_id_nand.c @@ -20,29 +20,16 @@
static struct gpmc *gpmc_config = (struct gpmc *)GPMC_BASE;
-/* nand_command: Send a flash command to the flash chip */ -static void nand_command(u8 command) -{ - writeb(command, &gpmc_config->cs[0].nand_cmd); - - if (command == NAND_CMD_RESET) { - unsigned char ret_val; - writeb(NAND_CMD_STATUS, &gpmc_config->cs[0].nand_cmd); - do { - /* Wait until ready */ - ret_val = readl(&gpmc_config->cs[0].nand_dat); - } while ((ret_val & NAND_STATUS_READY) != NAND_STATUS_READY); - } -} - /* * Many boards will want to know the results of the NAND_CMD_READID command * in order to decide what to do about DDR initialization. This function * allows us to do that very early and to pass those results back to the * board so it can make whatever decisions need to be made. */ -void identify_nand_chip(int *mfr, int *id) +int identify_nand_chip(int *mfr, int *id) { + int loops = 1000; + /* Make sure that we have setup GPMC for NAND correctly. */ writel(M_NAND_GPMC_CONFIG1, &gpmc_config->cs[0].config1); writel(M_NAND_GPMC_CONFIG2, &gpmc_config->cs[0].config2); @@ -62,8 +49,15 @@ void identify_nand_chip(int *mfr, int *id) sdelay(2000);
/* Issue a RESET and then READID */ - nand_command(NAND_CMD_RESET); - nand_command(NAND_CMD_READID); + writeb(NAND_CMD_RESET, &gpmc_config->cs[0].nand_cmd); + writeb(NAND_CMD_STATUS, &gpmc_config->cs[0].nand_cmd); + while ((readl(&gpmc_config->cs[0].nand_dat) & NAND_STATUS_READY) + != NAND_STATUS_READY) { + sdelay(100); + if (--loops == 0) + return 1; + } + writeb(NAND_CMD_READID, &gpmc_config->cs[0].nand_cmd);
/* Set the address to read to 0x0 */ writeb(0x0, &gpmc_config->cs[0].nand_adr); @@ -71,4 +65,6 @@ void identify_nand_chip(int *mfr, int *id) /* Read off the manufacturer and device id. */ *mfr = readb(&gpmc_config->cs[0].nand_dat); *id = readb(&gpmc_config->cs[0].nand_dat); + + return 0; } diff --git a/arch/arm/include/asm/arch-omap3/sys_proto.h b/arch/arm/include/asm/arch-omap3/sys_proto.h index 24563c0..1be2b15 100644 --- a/arch/arm/include/asm/arch-omap3/sys_proto.h +++ b/arch/arm/include/asm/arch-omap3/sys_proto.h @@ -40,7 +40,7 @@ void sdrc_init(void); void do_sdrc_init(u32, u32);
void get_board_mem_timings(struct board_sdrc_timings *timings); -void identify_nand_chip(int *mfr, int *id); +int identify_nand_chip(int *mfr, int *id); void emif4_init(void); void gpmc_init(void); void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base,

Signed-off-by: Ladislav Michl ladis@linux-mips.org --- arch/arm/cpu/armv7/omap-common/mem-common.c | 8 +++----- arch/arm/include/asm/arch-omap3/sys_proto.h | 4 ++-- include/linux/mtd/omap_gpmc.h | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap-common/mem-common.c b/arch/arm/cpu/armv7/omap-common/mem-common.c index fc4290c..136a032 100644 --- a/arch/arm/cpu/armv7/omap-common/mem-common.c +++ b/arch/arm/cpu/armv7/omap-common/mem-common.c @@ -21,7 +21,7 @@ #include <command.h> #include <linux/mtd/omap_gpmc.h>
-struct gpmc *gpmc_cfg; +const struct gpmc *gpmc_cfg = (struct gpmc *)GPMC_BASE;
#if defined(CONFIG_OMAP34XX) /******************************************************** @@ -50,8 +50,8 @@ u32 mem_ok(u32 cs) } #endif
-void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, - u32 size) +void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, + u32 base, u32 size) { writel(0, &cs->config7); sdelay(1000); @@ -75,8 +75,6 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, *****************************************************/ void gpmc_init(void) { - /* putting a blanket check on GPMC based on ZeBu for now */ - gpmc_cfg = (struct gpmc *)GPMC_BASE; #if defined(CONFIG_NOR) /* configure GPMC for NOR */ const u32 gpmc_regs[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1, diff --git a/arch/arm/include/asm/arch-omap3/sys_proto.h b/arch/arm/include/asm/arch-omap3/sys_proto.h index 1be2b15..4c5aa99 100644 --- a/arch/arm/include/asm/arch-omap3/sys_proto.h +++ b/arch/arm/include/asm/arch-omap3/sys_proto.h @@ -43,8 +43,8 @@ void get_board_mem_timings(struct board_sdrc_timings *timings); int identify_nand_chip(int *mfr, int *id); void emif4_init(void); void gpmc_init(void); -void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, - u32 size); +void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, + u32 base, u32 size);
void watchdog_init(void); void set_muxconf_regs(void); diff --git a/include/linux/mtd/omap_gpmc.h b/include/linux/mtd/omap_gpmc.h index 3a75674..f49ea3d 100644 --- a/include/linux/mtd/omap_gpmc.h +++ b/include/linux/mtd/omap_gpmc.h @@ -92,6 +92,6 @@ struct gpmc { };
/* Used for board specific gpmc initialization */ -extern struct gpmc *gpmc_cfg; +extern const struct gpmc *gpmc_cfg;
#endif /* __ASM_OMAP_GPMC_H */

for now gpmc_init keeps original init logic... Also see FIXME and TODO below --- arch/arm/cpu/armv7/omap-common/mem-common.c | 134 +++++++++++++++++----------- arch/arm/include/asm/arch-omap3/sys_proto.h | 1 + 2 files changed, 84 insertions(+), 51 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap-common/mem-common.c b/arch/arm/cpu/armv7/omap-common/mem-common.c index 136a032..3953ca3 100644 --- a/arch/arm/cpu/armv7/omap-common/mem-common.c +++ b/arch/arm/cpu/armv7/omap-common/mem-common.c @@ -68,6 +68,79 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, sdelay(2000); }
+/* TODO: reuse MTD_DEV_TYPE_ from <jffs2/load_kernel.h> ? */ +void set_gpmc_cs0(int flash_type) +{ + const u32 *gpmc_regs; + u32 base, size; +#if defined(CONFIG_NOR) + const u32 gpmc_regs_nor[GPMC_MAX_REG] = { + STNOR_GPMC_CONFIG1, + STNOR_GPMC_CONFIG2, + STNOR_GPMC_CONFIG3, + STNOR_GPMC_CONFIG4, + STNOR_GPMC_CONFIG5, + STNOR_GPMC_CONFIG6, + STNOR_GPMC_CONFIG7 + }; +#endif +#if defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) + const u32 gpmc_regs_nand[GPMC_MAX_REG] = { + M_NAND_GPMC_CONFIG1, + M_NAND_GPMC_CONFIG2, + M_NAND_GPMC_CONFIG3, + M_NAND_GPMC_CONFIG4, + M_NAND_GPMC_CONFIG5, + M_NAND_GPMC_CONFIG6, + 0 + }; +#endif +#if defined(CONFIG_CMD_ONENAND) + const u32 gpmc_regs_onenand[GPMC_MAX_REG] = { + ONENAND_GPMC_CONFIG1, + ONENAND_GPMC_CONFIG2, + ONENAND_GPMC_CONFIG3, + ONENAND_GPMC_CONFIG4, + ONENAND_GPMC_CONFIG5, + ONENAND_GPMC_CONFIG6, + 0 + }; +#endif + + switch (flash_type) { +#if defined(CONFIG_NOR) + case 0: + gpmc_regs = gpmc_regs_nor; + base = CONFIG_SYS_FLASH_BASE; + size = (CONFIG_SYS_FLASH_SIZE > 0x08000000) ? GPMC_SIZE_256M : + ((CONFIG_SYS_FLASH_SIZE > 0x04000000) ? GPMC_SIZE_128M : + ((CONFIG_SYS_FLASH_SIZE > 0x02000000) ? GPMC_SIZE_64M : + ((CONFIG_SYS_FLASH_SIZE > 0x01000000) ? GPMC_SIZE_32M : + GPMC_SIZE_16M))); + break; +#endif +#if defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) + case 1: + gpmc_regs = gpmc_regs_nand; + base = CONFIG_SYS_NAND_BASE; + size = GPMC_SIZE_16M; + break; +#endif +#if defined(CONFIG_CMD_ONENAND) + case 2: + gpmc_regs = gpmc_regs_onenand; + base = CONFIG_SYS_ONENAND_BASE; + size = GPMC_SIZE_128M; + break; +#endif + default: + return; + } + + /* enable chip-select specific configurations */ + enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size); +} + /***************************************************** * gpmc_init(): init gpmc bus * Init GPMC for x16, MuxMode (SDRAM in x32). @@ -75,51 +148,6 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, *****************************************************/ void gpmc_init(void) { -#if defined(CONFIG_NOR) -/* configure GPMC for NOR */ - const u32 gpmc_regs[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1, - STNOR_GPMC_CONFIG2, - STNOR_GPMC_CONFIG3, - STNOR_GPMC_CONFIG4, - STNOR_GPMC_CONFIG5, - STNOR_GPMC_CONFIG6, - STNOR_GPMC_CONFIG7 - }; - u32 base = CONFIG_SYS_FLASH_BASE; - u32 size = (CONFIG_SYS_FLASH_SIZE > 0x08000000) ? GPMC_SIZE_256M : - /* > 64MB */ ((CONFIG_SYS_FLASH_SIZE > 0x04000000) ? GPMC_SIZE_128M : - /* > 32MB */ ((CONFIG_SYS_FLASH_SIZE > 0x02000000) ? GPMC_SIZE_64M : - /* > 16MB */ ((CONFIG_SYS_FLASH_SIZE > 0x01000000) ? GPMC_SIZE_32M : - /* min 16MB */ GPMC_SIZE_16M))); -#elif defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) -/* configure GPMC for NAND */ - const u32 gpmc_regs[GPMC_MAX_REG] = { M_NAND_GPMC_CONFIG1, - M_NAND_GPMC_CONFIG2, - M_NAND_GPMC_CONFIG3, - M_NAND_GPMC_CONFIG4, - M_NAND_GPMC_CONFIG5, - M_NAND_GPMC_CONFIG6, - 0 - }; - u32 base = CONFIG_SYS_NAND_BASE; - u32 size = GPMC_SIZE_16M; - -#elif defined(CONFIG_CMD_ONENAND) - const u32 gpmc_regs[GPMC_MAX_REG] = { ONENAND_GPMC_CONFIG1, - ONENAND_GPMC_CONFIG2, - ONENAND_GPMC_CONFIG3, - ONENAND_GPMC_CONFIG4, - ONENAND_GPMC_CONFIG5, - ONENAND_GPMC_CONFIG6, - 0 - }; - u32 size = GPMC_SIZE_128M; - u32 base = CONFIG_SYS_ONENAND_BASE; -#else - const u32 gpmc_regs[GPMC_MAX_REG] = { 0, 0, 0, 0, 0, 0, 0 }; - u32 size = 0; - u32 base = 0; -#endif /* global settings */ writel(0x00000008, &gpmc_cfg->sysconfig); writel(0x00000000, &gpmc_cfg->irqstatus); @@ -131,12 +159,16 @@ void gpmc_init(void) #else writel(0x00000012, &gpmc_cfg->config); #endif - /* - * Disable the GPMC0 config set by ROM code - */ + /* disable the GPMC0 config set by ROM code */ writel(0, &gpmc_cfg->cs[0].config7); sdelay(1000); - /* enable chip-select specific configurations */ - if (base != 0) - enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size); + + /* FIXME !!! */ +#if defined(CONFIG_NOR) + set_gpmc_cs0(0); +#elif defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) + set_gpmc_cs0(1); +#elif defined(CONFIG_CMD_ONENAND) + set_gpmc_cs0(2); +#endif } diff --git a/arch/arm/include/asm/arch-omap3/sys_proto.h b/arch/arm/include/asm/arch-omap3/sys_proto.h index 4c5aa99..5979340 100644 --- a/arch/arm/include/asm/arch-omap3/sys_proto.h +++ b/arch/arm/include/asm/arch-omap3/sys_proto.h @@ -45,6 +45,7 @@ void emif4_init(void); void gpmc_init(void); void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, u32 base, u32 size); +void set_gpmc_cs0(int flash_type);
void watchdog_init(void); void set_muxconf_regs(void);

Use newly introduced function. As it depends on previous RFC, lets turn in into proper patch once beforementioned problems are solved --- arch/arm/cpu/armv7/omap3/spl_id_nand.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap3/spl_id_nand.c b/arch/arm/cpu/armv7/omap3/spl_id_nand.c index 26d3aa4..0bf76fe 100644 --- a/arch/arm/cpu/armv7/omap3/spl_id_nand.c +++ b/arch/arm/cpu/armv7/omap3/spl_id_nand.c @@ -18,7 +18,7 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/mem.h>
-static struct gpmc *gpmc_config = (struct gpmc *)GPMC_BASE; +extern const struct gpmc *gpmc_cfg;
/* * Many boards will want to know the results of the NAND_CMD_READID command @@ -31,40 +31,27 @@ int identify_nand_chip(int *mfr, int *id) int loops = 1000;
/* Make sure that we have setup GPMC for NAND correctly. */ - writel(M_NAND_GPMC_CONFIG1, &gpmc_config->cs[0].config1); - writel(M_NAND_GPMC_CONFIG2, &gpmc_config->cs[0].config2); - writel(M_NAND_GPMC_CONFIG3, &gpmc_config->cs[0].config3); - writel(M_NAND_GPMC_CONFIG4, &gpmc_config->cs[0].config4); - writel(M_NAND_GPMC_CONFIG5, &gpmc_config->cs[0].config5); - writel(M_NAND_GPMC_CONFIG6, &gpmc_config->cs[0].config6); - - /* - * Enable the config. The CS size goes in bits 11:8. We set - * bit 6 to enable the CS and the base address goes into bits 5:0. - */ - writel((GPMC_SIZE_128M << 8) | (GPMC_CS_ENABLE << 6) | - ((NAND_BASE >> 24) & GPMC_BASEADDR_MASK), - &gpmc_config->cs[0].config7); + set_gpmc_cs0(1);
sdelay(2000);
/* Issue a RESET and then READID */ - writeb(NAND_CMD_RESET, &gpmc_config->cs[0].nand_cmd); - writeb(NAND_CMD_STATUS, &gpmc_config->cs[0].nand_cmd); - while ((readl(&gpmc_config->cs[0].nand_dat) & NAND_STATUS_READY) - != NAND_STATUS_READY) { + writeb(NAND_CMD_RESET, &gpmc_cfg->cs[0].nand_cmd); + writeb(NAND_CMD_STATUS, &gpmc_cfg->cs[0].nand_cmd); + while ((readl(&gpmc_cfg->cs[0].nand_dat) & NAND_STATUS_READY) + != NAND_STATUS_READY) { sdelay(100); if (--loops == 0) return 1; } - writeb(NAND_CMD_READID, &gpmc_config->cs[0].nand_cmd); + writeb(NAND_CMD_READID, &gpmc_cfg->cs[0].nand_cmd);
/* Set the address to read to 0x0 */ - writeb(0x0, &gpmc_config->cs[0].nand_adr); + writeb(0x0, &gpmc_cfg->cs[0].nand_adr);
/* Read off the manufacturer and device id. */ - *mfr = readb(&gpmc_config->cs[0].nand_dat); - *id = readb(&gpmc_config->cs[0].nand_dat); + *mfr = readb(&gpmc_cfg->cs[0].nand_dat); + *id = readb(&gpmc_cfg->cs[0].nand_dat);
return 0; }

Add timeout to onenand_wait ready loop as it hangs here indefinitely when chip not present. Once there, do the same for onenand_bbt_wait as well (note: recent Linux driver code does the same)
Signed-off-by: Ladislav Michl ladis@linux-mips.org --- drivers/mtd/onenand/onenand_base.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 03deabc..d194d97 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -20,6 +20,7 @@ */
#include <common.h> +#include <watchdog.h> #include <linux/compat.h> #include <linux/mtd/mtd.h> #include "linux/mtd/flashchip.h" @@ -467,15 +468,18 @@ static int onenand_read_ecc(struct onenand_chip *this) static int onenand_wait(struct mtd_info *mtd, int state) { struct onenand_chip *this = mtd->priv; - unsigned int flags = ONENAND_INT_MASTER; unsigned int interrupt = 0; unsigned int ctrl;
- while (1) { + /* Wait at most 20ms ... */ + u32 timeo = (CONFIG_SYS_HZ * 20) / 1000; + u32 time_start = get_timer(0); + do { + WATCHDOG_RESET(); + if (get_timer(time_start) > timeo) + return -EIO; interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); - if (interrupt & flags) - break; - } + } while ((interrupt & ONENAND_INT_MASTER) == 0);
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
@@ -1154,15 +1158,18 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, static int onenand_bbt_wait(struct mtd_info *mtd, int state) { struct onenand_chip *this = mtd->priv; - unsigned int flags = ONENAND_INT_MASTER; unsigned int interrupt; unsigned int ctrl;
- while (1) { + /* Wait at most 20ms ... */ + u32 timeo = (CONFIG_SYS_HZ * 20) / 1000; + u32 time_start = get_timer(0); + do { + WATCHDOG_RESET(); + if (get_timer(time_start) > timeo) + return ONENAND_BBT_READ_FATAL_ERROR; interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); - if (interrupt & flags) - break; - } + } while ((interrupt & ONENAND_INT_MASTER) == 0);
/* To get correct interrupt status in timeout case */ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); @@ -2536,7 +2543,8 @@ static int onenand_chip_probe(struct mtd_info *mtd) this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
/* Wait reset */ - this->wait(mtd, FL_RESETING); + if (this->wait(mtd, FL_RESETING)) + return -ENXIO;
/* Restore system configuration 1 */ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);

Signed-off-by: Ladislav Michl ladis@linux-mips.org --- board/micronas/vct/ebi_onenand.c | 4 +++- board/samsung/goni/onenand.c | 4 +++- board/samsung/smdkc100/onenand.c | 4 +++- board/samsung/universal_c210/onenand.c | 4 +++- drivers/mtd/onenand/onenand_uboot.c | 30 +++++++++++++++--------------- include/onenand_uboot.h | 2 +- 6 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/board/micronas/vct/ebi_onenand.c b/board/micronas/vct/ebi_onenand.c index 62eb648..ef892ca 100644 --- a/board/micronas/vct/ebi_onenand.c +++ b/board/micronas/vct/ebi_onenand.c @@ -169,7 +169,7 @@ static int ebi_write_bufferram(struct mtd_info *mtd, loff_t addr, int area, return 0; }
-void onenand_board_init(struct mtd_info *mtd) +int onenand_board_init(struct mtd_info *mtd) { struct onenand_chip *chip = mtd->priv;
@@ -181,4 +181,6 @@ void onenand_board_init(struct mtd_info *mtd)
chip->read_bufferram = ebi_read_bufferram; chip->write_bufferram = ebi_write_bufferram; + + return 0; } diff --git a/board/samsung/goni/onenand.c b/board/samsung/goni/onenand.c index b74d8e8..cbe1d12f 100644 --- a/board/samsung/goni/onenand.c +++ b/board/samsung/goni/onenand.c @@ -11,11 +11,13 @@ #include <linux/mtd/samsung_onenand.h> #include <onenand_uboot.h>
-void onenand_board_init(struct mtd_info *mtd) +int onenand_board_init(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv;
this->base = (void *)CONFIG_SYS_ONENAND_BASE; this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK; this->chip_probe = s5pc110_chip_probe; + + return 0; } diff --git a/board/samsung/smdkc100/onenand.c b/board/samsung/smdkc100/onenand.c index 577c1a5..994d91d 100644 --- a/board/samsung/smdkc100/onenand.c +++ b/board/samsung/smdkc100/onenand.c @@ -16,7 +16,7 @@ #include <asm/io.h> #include <asm/arch/clock.h>
-void onenand_board_init(struct mtd_info *mtd) +int onenand_board_init(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; struct s5pc100_clock *clk = @@ -65,4 +65,6 @@ void onenand_board_init(struct mtd_info *mtd) writel(value, &onenand->int_err_mask);
s3c_onenand_init(mtd); + + return 0; } diff --git a/board/samsung/universal_c210/onenand.c b/board/samsung/universal_c210/onenand.c index 28bc811..147a95e 100644 --- a/board/samsung/universal_c210/onenand.c +++ b/board/samsung/universal_c210/onenand.c @@ -10,11 +10,13 @@ #include <linux/mtd/onenand.h> #include <linux/mtd/samsung_onenand.h>
-void onenand_board_init(struct mtd_info *mtd) +int onenand_board_init(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv;
this->base = (void *)CONFIG_SYS_ONENAND_BASE; this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK; this->chip_probe = s5pc210_chip_probe; + + return 0; } diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c index ae60c3b..c15ec9d 100644 --- a/drivers/mtd/onenand/onenand_uboot.c +++ b/drivers/mtd/onenand/onenand_uboot.c @@ -24,33 +24,33 @@ static __attribute__((unused)) char dev_name[] = "onenand0";
void onenand_init(void) { + int err = 0; memset(&onenand_mtd, 0, sizeof(struct mtd_info)); memset(&onenand_chip, 0, sizeof(struct onenand_chip));
onenand_mtd.priv = &onenand_chip;
#ifdef CONFIG_USE_ONENAND_BOARD_INIT - /* - * It's used for some board init required - */ - onenand_board_init(&onenand_mtd); + /* It's used for some board init required */ + err = onenand_board_init(&onenand_mtd); #else onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE; #endif
- onenand_scan(&onenand_mtd, 1); + if (!err && !(onenand_scan(&onenand_mtd, 1))) {
- if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND) - puts("Flex-"); - puts("OneNAND: "); - print_size(onenand_chip.chipsize, "\n"); + if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND) + puts("Flex-"); + puts("OneNAND: ");
#ifdef CONFIG_MTD_DEVICE - /* - * Add MTD device so that we can reference it later - * via the mtdcore infrastructure (e.g. ubi). - */ - onenand_mtd.name = dev_name; - add_mtd_device(&onenand_mtd); + /* + * Add MTD device so that we can reference it later + * via the mtdcore infrastructure (e.g. ubi). + */ + onenand_mtd.name = dev_name; + add_mtd_device(&onenand_mtd); #endif + } + print_size(onenand_chip.chipsize, "\n"); } diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h index d69e0d2..995f0aa 100644 --- a/include/onenand_uboot.h +++ b/include/onenand_uboot.h @@ -26,7 +26,7 @@ extern struct mtd_info onenand_mtd; extern struct onenand_chip onenand_chip;
/* board */ -extern void onenand_board_init(struct mtd_info *); +extern int onenand_board_init(struct mtd_info *);
/* Functions */ extern void onenand_init(void);

On Fri, Jun 17, 2016 at 12:00:13PM +0200, Ladislav Michl wrote: [snip]
As we might want to use single binary also to boot from MMC or other sources, we cannot use boot_device to get a glue about used flash type. Also U-Boot should not count on being loaded by its own SPL. So, to make things easier to begin with, do we all agree that omap_gpmc:board_nand_init as well as its OneNAND counterpart should expect gpmc config1 register properly set and fail if something unexpected is found? That basically means if we should rely on CS0 config provided by first stage loader or try to rediscover flash devices (this problem does not exist when flash itself is boot source)
Lets overcome this limitation by introducing omap specific global gpmc_cs0_flash holding detected flash type. Single U-Boot and SPL binary is now running on all variants of IGEPv2 board. Modified patches previously sent as RFC are following this mail, but as they are based ot top of other fixes and cleanups I sent earlier they probably won't apply until someone takes some action (yes, NACK is also an action ;-))
regards, ladis

Allow boards to runtime detect flash type.
Signed-off-by: Ladislav Michl ladis@linux-mips.org --- arch/arm/cpu/armv7/omap-common/mem-common.c | 148 +++++++++++++++++----------- arch/arm/include/asm/arch-omap3/sys_proto.h | 1 + include/linux/mtd/omap_gpmc.h | 1 + 3 files changed, 92 insertions(+), 58 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap-common/mem-common.c b/arch/arm/cpu/armv7/omap-common/mem-common.c index 136a032..d72e82e 100644 --- a/arch/arm/cpu/armv7/omap-common/mem-common.c +++ b/arch/arm/cpu/armv7/omap-common/mem-common.c @@ -20,9 +20,20 @@ #include <asm/arch/sys_proto.h> #include <command.h> #include <linux/mtd/omap_gpmc.h> +#include <jffs2/load_kernel.h>
const struct gpmc *gpmc_cfg = (struct gpmc *)GPMC_BASE;
+#if defined(CONFIG_NOR) +char gpmc_cs0_flash = MTD_DEV_TYPE_NOR; +#elif defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) +char gpmc_cs0_flash = MTD_DEV_TYPE_NAND; +#elif defined(CONFIG_CMD_ONENAND) +char gpmc_cs0_flash = MTD_DEV_TYPE_ONENAND; +#else +char gpmc_cs0_flash = -1; +#endif + #if defined(CONFIG_OMAP34XX) /******************************************************** * mem_ok() - test used to see if timings are correct @@ -68,6 +79,81 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, sdelay(2000); }
+void set_gpmc_cs0(int flash_type) +{ + const u32 *gpmc_regs; + u32 base, size; +#if defined(CONFIG_NOR) + const u32 gpmc_regs_nor[GPMC_MAX_REG] = { + STNOR_GPMC_CONFIG1, + STNOR_GPMC_CONFIG2, + STNOR_GPMC_CONFIG3, + STNOR_GPMC_CONFIG4, + STNOR_GPMC_CONFIG5, + STNOR_GPMC_CONFIG6, + STNOR_GPMC_CONFIG7 + }; +#endif +#if defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) + const u32 gpmc_regs_nand[GPMC_MAX_REG] = { + M_NAND_GPMC_CONFIG1, + M_NAND_GPMC_CONFIG2, + M_NAND_GPMC_CONFIG3, + M_NAND_GPMC_CONFIG4, + M_NAND_GPMC_CONFIG5, + M_NAND_GPMC_CONFIG6, + 0 + }; +#endif +#if defined(CONFIG_CMD_ONENAND) + const u32 gpmc_regs_onenand[GPMC_MAX_REG] = { + ONENAND_GPMC_CONFIG1, + ONENAND_GPMC_CONFIG2, + ONENAND_GPMC_CONFIG3, + ONENAND_GPMC_CONFIG4, + ONENAND_GPMC_CONFIG5, + ONENAND_GPMC_CONFIG6, + 0 + }; +#endif + + switch (flash_type) { +#if defined(CONFIG_NOR) + case MTD_DEV_TYPE_NOR: + gpmc_regs = gpmc_regs_nor; + base = CONFIG_SYS_FLASH_BASE; + size = (CONFIG_SYS_FLASH_SIZE > 0x08000000) ? GPMC_SIZE_256M : + ((CONFIG_SYS_FLASH_SIZE > 0x04000000) ? GPMC_SIZE_128M : + ((CONFIG_SYS_FLASH_SIZE > 0x02000000) ? GPMC_SIZE_64M : + ((CONFIG_SYS_FLASH_SIZE > 0x01000000) ? GPMC_SIZE_32M : + GPMC_SIZE_16M))); + break; +#endif +#if defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) + case MTD_DEV_TYPE_NAND: + gpmc_regs = gpmc_regs_nand; + base = CONFIG_SYS_NAND_BASE; + size = GPMC_SIZE_16M; + break; +#endif +#if defined(CONFIG_CMD_ONENAND) + case MTD_DEV_TYPE_ONENAND: + gpmc_regs = gpmc_regs_onenand; + base = CONFIG_SYS_ONENAND_BASE; + size = GPMC_SIZE_128M; + break; +#endif + default: + /* disable the GPMC0 config set by ROM code */ + writel(0, &gpmc_cfg->cs[0].config7); + sdelay(1000); + return; + } + + /* enable chip-select specific configurations */ + enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size); +} + /***************************************************** * gpmc_init(): init gpmc bus * Init GPMC for x16, MuxMode (SDRAM in x32). @@ -75,68 +161,14 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, *****************************************************/ void gpmc_init(void) { -#if defined(CONFIG_NOR) -/* configure GPMC for NOR */ - const u32 gpmc_regs[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1, - STNOR_GPMC_CONFIG2, - STNOR_GPMC_CONFIG3, - STNOR_GPMC_CONFIG4, - STNOR_GPMC_CONFIG5, - STNOR_GPMC_CONFIG6, - STNOR_GPMC_CONFIG7 - }; - u32 base = CONFIG_SYS_FLASH_BASE; - u32 size = (CONFIG_SYS_FLASH_SIZE > 0x08000000) ? GPMC_SIZE_256M : - /* > 64MB */ ((CONFIG_SYS_FLASH_SIZE > 0x04000000) ? GPMC_SIZE_128M : - /* > 32MB */ ((CONFIG_SYS_FLASH_SIZE > 0x02000000) ? GPMC_SIZE_64M : - /* > 16MB */ ((CONFIG_SYS_FLASH_SIZE > 0x01000000) ? GPMC_SIZE_32M : - /* min 16MB */ GPMC_SIZE_16M))); -#elif defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND) -/* configure GPMC for NAND */ - const u32 gpmc_regs[GPMC_MAX_REG] = { M_NAND_GPMC_CONFIG1, - M_NAND_GPMC_CONFIG2, - M_NAND_GPMC_CONFIG3, - M_NAND_GPMC_CONFIG4, - M_NAND_GPMC_CONFIG5, - M_NAND_GPMC_CONFIG6, - 0 - }; - u32 base = CONFIG_SYS_NAND_BASE; - u32 size = GPMC_SIZE_16M; - -#elif defined(CONFIG_CMD_ONENAND) - const u32 gpmc_regs[GPMC_MAX_REG] = { ONENAND_GPMC_CONFIG1, - ONENAND_GPMC_CONFIG2, - ONENAND_GPMC_CONFIG3, - ONENAND_GPMC_CONFIG4, - ONENAND_GPMC_CONFIG5, - ONENAND_GPMC_CONFIG6, - 0 - }; - u32 size = GPMC_SIZE_128M; - u32 base = CONFIG_SYS_ONENAND_BASE; -#else - const u32 gpmc_regs[GPMC_MAX_REG] = { 0, 0, 0, 0, 0, 0, 0 }; - u32 size = 0; - u32 base = 0; -#endif /* global settings */ writel(0x00000008, &gpmc_cfg->sysconfig); writel(0x00000000, &gpmc_cfg->irqstatus); writel(0x00000000, &gpmc_cfg->irqenable); /* disable timeout, set a safe reset value */ writel(0x00001ff0, &gpmc_cfg->timeout_control); -#ifdef CONFIG_NOR - writel(0x00000200, &gpmc_cfg->config); -#else - writel(0x00000012, &gpmc_cfg->config); -#endif - /* - * Disable the GPMC0 config set by ROM code - */ - writel(0, &gpmc_cfg->cs[0].config7); - sdelay(1000); - /* enable chip-select specific configurations */ - if (base != 0) - enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size); + writel(gpmc_cs0_flash == MTD_DEV_TYPE_NOR ? + 0x00000200 : 0x00000012, &gpmc_cfg->config); + + set_gpmc_cs0(gpmc_cs0_flash); } diff --git a/arch/arm/include/asm/arch-omap3/sys_proto.h b/arch/arm/include/asm/arch-omap3/sys_proto.h index 4c5aa99..5979340 100644 --- a/arch/arm/include/asm/arch-omap3/sys_proto.h +++ b/arch/arm/include/asm/arch-omap3/sys_proto.h @@ -45,6 +45,7 @@ void emif4_init(void); void gpmc_init(void); void enable_gpmc_cs_config(const u32 *gpmc_config, const struct gpmc_cs *cs, u32 base, u32 size); +void set_gpmc_cs0(int flash_type);
void watchdog_init(void); void set_muxconf_regs(void); diff --git a/include/linux/mtd/omap_gpmc.h b/include/linux/mtd/omap_gpmc.h index f49ea3d..be3ce9d 100644 --- a/include/linux/mtd/omap_gpmc.h +++ b/include/linux/mtd/omap_gpmc.h @@ -93,5 +93,6 @@ struct gpmc {
/* Used for board specific gpmc initialization */ extern const struct gpmc *gpmc_cfg; +extern char gpmc_cs0_flash;
#endif /* __ASM_OMAP_GPMC_H */

Signed-off-by: Ladislav Michl ladis@linux-mips.org --- board/isee/igep00x0/igep00x0.c | 71 +++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 18 deletions(-)
diff --git a/board/isee/igep00x0/igep00x0.c b/board/isee/igep00x0/igep00x0.c index 5dfb7d2..b36709c 100644 --- a/board/isee/igep00x0/igep00x0.c +++ b/board/isee/igep00x0/igep00x0.c @@ -17,6 +17,10 @@ #include <asm/arch/mux.h> #include <asm/arch/sys_proto.h> #include <asm/mach-types.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/onenand.h> +#include <jffs2/load_kernel.h> #include "igep00x0.h"
DECLARE_GLOBAL_DATA_PTR; @@ -56,7 +60,25 @@ U_BOOT_DEVICE(igep_uart) = { */ int board_init(void) { - gpmc_init(); /* in SRAM or SDRAM, finish GPMC */ + int loops = 100; + + /* find out flash memory type, assume NAND first */ + gpmc_cs0_flash = MTD_DEV_TYPE_NAND; + gpmc_init(); + + /* Issue a RESET and then READID */ + writeb(NAND_CMD_RESET, &gpmc_cfg->cs[0].nand_cmd); + writeb(NAND_CMD_STATUS, &gpmc_cfg->cs[0].nand_cmd); + while ((readl(&gpmc_cfg->cs[0].nand_dat) & NAND_STATUS_READY) + != NAND_STATUS_READY) { + udelay(1); + if (--loops == 0) { + gpmc_cs0_flash = MTD_DEV_TYPE_ONENAND; + gpmc_init(); /* reinitialize for OneNAND */ + break; + } + } + /* boot param addr */ gd->bd->bi_boot_params = (OMAP34XX_SDRC_CS0 + 0x100);
@@ -75,29 +97,42 @@ int board_init(void) */ void get_board_mem_timings(struct board_sdrc_timings *timings) { - timings->mr = MICRON_V_MR_165; -#ifdef CONFIG_BOOT_NAND - timings->mcfg = MICRON_V_MCFG_200(256 << 20); - timings->ctrla = MICRON_V_ACTIMA_200; - timings->ctrlb = MICRON_V_ACTIMB_200; - timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_200MHz; -#else - if (get_cpu_family() == CPU_OMAP34XX) { - timings->mcfg = NUMONYX_V_MCFG_165(256 << 20); - timings->ctrla = NUMONYX_V_ACTIMA_165; - timings->ctrlb = NUMONYX_V_ACTIMB_165; - timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_165MHz; + int mfr, id, err = identify_nand_chip(&mfr, &id);
- } else { - timings->mcfg = NUMONYX_V_MCFG_200(256 << 20); - timings->ctrla = NUMONYX_V_ACTIMA_200; - timings->ctrlb = NUMONYX_V_ACTIMB_200; + timings->mr = MICRON_V_MR_165; + if (!err && mfr == NAND_MFR_MICRON) { + timings->mcfg = MICRON_V_MCFG_200(256 << 20); + timings->ctrla = MICRON_V_ACTIMA_200; + timings->ctrlb = MICRON_V_ACTIMB_200; timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_200MHz; + gpmc_cs0_flash = MTD_DEV_TYPE_NAND; + } else { + if (get_cpu_family() == CPU_OMAP34XX) { + timings->mcfg = NUMONYX_V_MCFG_165(256 << 20); + timings->ctrla = NUMONYX_V_ACTIMA_165; + timings->ctrlb = NUMONYX_V_ACTIMB_165; + timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_165MHz; + } else { + timings->mcfg = NUMONYX_V_MCFG_200(256 << 20); + timings->ctrla = NUMONYX_V_ACTIMA_200; + timings->ctrlb = NUMONYX_V_ACTIMB_200; + timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_200MHz; + } + gpmc_cs0_flash = MTD_DEV_TYPE_ONENAND; } -#endif } #endif
+int onenand_board_init(struct mtd_info *mtd) +{ + if (gpmc_cs0_flash == MTD_DEV_TYPE_ONENAND) { + struct onenand_chip *this = mtd->priv; + this->base = (void *)CONFIG_SYS_ONENAND_BASE; + return 0; + } + return 1; +} + #if defined(CONFIG_CMD_NET) static void reset_net_chip(int gpio) {
participants (1)
-
Ladislav Michl