arm: iproc: add NAND driver
Subsystems (4)
PATCH 1/1 arm: iproc: add NAND driver
From: Jiandong Zheng <[email protected]>
Add support for the iproc NAND, and enable on Cygnus and NSP boards.
---
arch/arm/include/asm/arch-bcmcygnus/configs.h | 11 + arch/arm/include/asm/arch-bcmnsp/configs.h | 11 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/iproc_nand.c | 1732 +++++++++++++++++++++++++ drivers/mtd/nand/iproc_nand_cygnus.h | 111 ++ drivers/mtd/nand/iproc_nand_ns_plus.h | 113 ++ 6 files changed, 1979 insertions(+) create mode 100644 drivers/mtd/nand/iproc_nand.c create mode 100644 drivers/mtd/nand/iproc_nand_cygnus.h create mode 100644 drivers/mtd/nand/iproc_nand_ns_plus.h
arch/arm/include/asm/arch-bcmcygnus/configs.h +11 -0
@@ -10,6 +10,7 @@#include <asm/iproc-common/configs.h> /* uArchitecture specifics */ +#define CONFIG_CYGNUS /* Serial Info */ /* Post pad 3 bytes after each reg addr */
@@ -22,4 +23,14 @@#define CONFIG_CONS_INDEX 3#define CONFIG_SYS_NS16550_COM3 0x18023000 +/* NAND configuration */ +#define CONFIG_CMD_NAND +#define CONFIG_NAND_IPROC +#define CONFIG_IPROC_NAND_TIMING_MODE 5 +#define CONFIG_SYS_NAND_BASE 0 +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_MAX_NAND_CHIPS 1 +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_SYS_NAND_ONFI_DETECTION +#endif /* __ARCH_CONFIGS_H */
arch/arm/include/asm/arch-bcmnsp/configs.h +11 -0
@@ -10,6 +10,7 @@#include <asm/iproc-common/configs.h> /* uArchitecture specifics */ +#define CONFIG_NS_PLUS /* Serial Info */ /* no padding */
@@ -19,4 +20,14 @@#define CONFIG_CONS_INDEX 1#define CONFIG_SYS_NS16550_COM1 0x18000300 +/* NAND configuration */ +#define CONFIG_CMD_NAND +#define CONFIG_NAND_IPROC +#define CONFIG_IPROC_NAND_TIMING_MODE 5 +#define CONFIG_SYS_NAND_BASE 0 +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_MAX_NAND_CHIPS 1 +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_SYS_NAND_ONFI_DETECTION +#endif /* __ARCH_CONFIGS_H */
drivers/mtd/nand/Makefile +1 -0
@@ -48,6 +48,7 @@ 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_IPROC) += iproc_nand.o obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
drivers/mtd/nand/iproc_nand.c new file +1732 -0
1,732 lines not on this page · raw message
drivers/mtd/nand/iproc_nand_cygnus.h new file +111 -0
111 lines not on this page · raw message
drivers/mtd/nand/iproc_nand_ns_plus.h new file +113 -0
113 lines not on this page · raw message
Signature · 1 line
1.8.5
PATCH 1/1 arm: iproc: add NAND driver
Quoted 24 lines · Steve Rae
From: Jiandong Zheng <[email protected]>
Add support for the iproc NAND, and enable on Cygnus and NSP boards.
Signed-off-by Jiandong Zheng <[email protected]>Signed-off-by Steve Rae <[email protected]>---
arch/arm/include/asm/arch-bcmcygnus/configs.h | 11 + arch/arm/include/asm/arch-bcmnsp/configs.h | 11 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/iproc_nand.c | 1732 +++++++++++++++++++++++++ drivers/mtd/nand/iproc_nand_cygnus.h | 111 ++ drivers/mtd/nand/iproc_nand_ns_plus.h | 113 ++ 6 files changed, 1979 insertions(+) create mode 100644 drivers/mtd/nand/iproc_nand.c create mode 100644 drivers/mtd/nand/iproc_nand_cygnus.h create mode 100644 drivers/mtd/nand/iproc_nand_ns_plus.harch/arm/include/asm/arch-bcmcygnus/configs.h +0
-0
arch/arm/include/asm/arch-bcmcygnus/configs.h line 13
Quoted 4 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +1
-0@@ -10,6 +10,7 @@#include <asm/iproc-common/configs.h> /* uArchitecture specifics */ +#define CONFIG_CYGNUS
Undocumented, should be in kconfig, and the name is too vague.
Quoted 5 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +0
-0/* Serial Info */ /* Post pad 3 bytes after each reg addr */ @@ -22,4 +23,14 @@#define CONFIG_CONS_INDEX 3#define CONFIG_SYS_NS16550_COM3 0x18023000
arch/arm/include/asm/arch-bcmcygnus/configs.h line 34
Quoted 10 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +9
-0+/* NAND configuration */ +#define CONFIG_CMD_NAND +#define CONFIG_NAND_IPROC +#define CONFIG_IPROC_NAND_TIMING_MODE 5 +#define CONFIG_SYS_NAND_BASE 0 +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_MAX_NAND_CHIPS 1 +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_SYS_NAND_ONFI_DETECTION
CONFIG_IPROC_NAND_TIMING_MODE and CONFIG_NAND_IPROC are undocumented, and new symbols should be done in kconfig.
Please be consistent about CONFIG_NAND_IPROC* versus CONFIG_IPROC_NAND* (I prefer the former).
If this timing mode is describing hardware, rather than user config, it should be CONFIG_SYS_NAND_IPROC_TIMING_MODE.
arch/arm/include/asm/arch-bcmnsp/configs.h line 13
Quoted 10 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +0
-0#endif /* __ARCH_CONFIGS_H */ arch/arm/include/asm/arch-bcmnsp/configs.h +1
-0@@ -10,6 +10,7 @@#include <asm/iproc-common/configs.h> /* uArchitecture specifics */ +#define CONFIG_NS_PLUS
Undocumented, should be in kconfig, and the name is too vague.
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 4 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +4
-0+/* +* Definitions +*/ +#define DRV_NAME "iproc_nand"
I suggest using __func__ instead.
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 6 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +6
-0+/* +* IRQ operations +*/ +#define NAND_ACK_IRQ (bit) writel(1, ((u32 *)ctrl.nand_intr_regs) + (bit)) + +#define NAND_TEST_IRQ (bit) (readl(((u32 *)ctrl.nand_intr_regs) + (bit)) & 1)
This is the only place you ever use nand_intr_regs, so why not just define it as a u32 pointer? Also, use __iomem.
Quoted 7 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +7
-0+ +/* +* Data access macros for endianness +*/ +#ifdef __LITTLE_ENDIAN +#define NAND_BEGIN_DATA_ACCESS () \ + writel(readl(ctrl.nand_idm_io_ctrl_direct_reg) | \
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+ IDMFLD_NAND_IO_CONTROL_DIRECT_APB_LE_MODE, \ + ctrl.nand_idm_io_ctrl_direct_reg) +#define NAND_END_DATA_ACCESS () \ + writel(readl(ctrl.nand_idm_io_ctrl_direct_reg) & \ + ~IDMFLD_NAND_IO_CONTROL_DIRECT_APB_LE_MODE, \ + ctrl.nand_idm_io_ctrl_direct_reg) +#else /* !__LITTLE_ENDIAN */ +#define NAND_BEGIN_DATA_ACCESS () +#define NAND_END_DATA_ACCESS () +#endif /* !__LITTLE_ENDIAN */
Huh?
Quoted 41 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +41
-0+ +/* +* Misc NAND controller configuration/status macros +*/ +#define NC_REG_CONFIG (cs) (NCREG_CONFIG_CS0 + ((cs) << 4)) + +#define WR_CONFIG (cs, field, val) do { \ + u32 reg = NC_REG_CONFIG(cs), contents = NAND_REG_RD(reg); \ + contents &= ~(NCFLD_CONFIG_CS0_##field##_MASK); \ + contents |= (val) << NCFLD_CONFIG_CS0_##field##_SHIFT; \ + NAND_REG_WR(reg, contents); \ +} while (0) + +#define RD_CONFIG (cs, field) \ + ((NAND_REG_RD(NC_REG_CONFIG(cs)) & NCFLD_CONFIG_CS0_##field##_MASK) \ + >> NCFLD_CONFIG_CS0_##field##_SHIFT) + +#define NC_REG_ACC_CONTROL (cs) (NCREG_ACC_CONTROL_CS0 + ((cs) << 4)) + +#define WR_ACC_CONTROL (cs, field, val) do { \ + u32 reg = NC_REG_ACC_CONTROL(cs), contents = NAND_REG_RD(reg); \ + contents &= ~(NCFLD_ACC_CONTROL_CS0_##field##_MASK); \ + contents |= (val) << NCFLD_ACC_CONTROL_CS0_##field##_SHIFT; \ + NAND_REG_WR(reg, contents); \ +} while (0) + +#define RD_ACC_CONTROL (cs, field) \ + ((NAND_REG_RD(NC_REG_ACC_CONTROL(cs)) & \ + NCFLD_ACC_CONTROL_CS0_##field##_MASK) \ + >> NCFLD_ACC_CONTROL_CS0_##field##_SHIFT) + +#define CORR_ERROR_COUNT (NAND_REG_RD(NCREG_CORR_ERROR_COUNT)) +#define UNCORR_ERROR_COUNT (NAND_REG_RD(NCREG_UNCORR_ERROR_COUNT)) + +#define WR_CORR_THRESH (cs, val) do { \ + u32 contents = NAND_REG_RD(NCREG_CORR_STAT_THRESHOLD); \ + u32 shift = NCFLD_CORR_STAT_THRESHOLD_CS1_SHIFT * (cs); \ + contents &= ~(NCFLD_CORR_STAT_THRESHOLD_CS0_MASK << shift); \ + contents |= ((val) & NCFLD_CORR_STAT_THRESHOLD_CS0_MASK) << shift; \ + NAND_REG_WR(NCREG_CORR_STAT_THRESHOLD, contents); \ +} while (0)
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+ +#define NC_REG_TIMING1 (cs) (NCREG_TIMING_1_CS0 + ((cs) << 4)) +#define NC_REG_TIMING2 (cs) (NCREG_TIMING_2_CS0 + ((cs) << 4)) + +#define NAND_STRAP_TYPE \ + ((readl(ctrl.nand_strap_regs) & ctrl.data->strap_type_bitfield.mask) \ + >> ctrl.data->strap_type_bitfield.shift) +#define NAND_STRAP_PAGE \ + ((readl(ctrl.nand_strap_regs) & ctrl.data->strap_page_bitfield.mask) \ + >> ctrl.data->strap_page_bitfield.shift)
Please use functions instead of macros where possible.
Quoted 4 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +4
-0+ +/* +* Internal structures +*/
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+struct nand_strap_type { +uint8_t sector_1k; +uint8_t ecc_level; +uint16_t spare_size; +}; + +struct nand_strap_bitfield { +uint32_t mask; +uint32_t shift; +};
What does "strap" mean here?
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+/* +* Internal support functions +*/ +static inline int fls64 (u64 x) +{ +u32 h = x >>32 ; +if (h) +return fls (h) +32 ; +return fls (x); +}
Put this in a generic header.
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 9 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +9
-0+/* +* NAND MTD API: read/program/erase +*/ + +static void iproc_nand_cmd_ctrl (struct mtd_info *mtd, +int dat,unsigned int ctrl) +{ +/* intentionally left blank */ +}
Leave cmd_ctrl NULL instead of making it empty.
Quoted 70 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +70
-0+static int iproc_nand_read (struct mtd_info *mtd, +struct nand_chip *chip,u64 addr,unsigned int trans, +u32 *buf,u8 *oob) +{ +struct iproc_nand_host *host = chip->priv; +u64 start_addr = addr; +int i; +int oob_bytes; +unsigned int max_bitflips, bitflips; +unsigned int corr_error_count, uncorr_error_count; +u32 *sector_buf = buf; +u8 *sector_oob = oob; + +debug ("%s %llx -> %p (trans %x)\n" , __func__, + (unsigned long long )addr, buf, trans); + +BUG_ON (!oob); + +NAND_ACK_IRQ (NCINTR_UNC ); +NAND_ACK_IRQ (NCINTR_CORR ); + max_bitflips =0 ; + corr_error_count =0 ; + uncorr_error_count =0 ; + +NAND_REG_WR (NCREG_CMD_EXT_ADDRESS , + (host->cs <<16 ) | ((addr >>32 ) &0xffff )); + +for (i =0 ; i < trans; i++, addr +=FC_BYTES ) { +if (!host->hwcfg.sector_size_1k || ((i &0x1 ) ==0 )) { + sector_buf = buf; + sector_oob = oob; + } + +NAND_REG_WR (NCREG_CMD_ADDRESS , addr &0xffffffff ); + +if (ctrl.data_cache_invalid) { +if ((i ==0 ) &&RD_ACC_CONTROL (host->cs,PAGE_HIT_EN )) +/* +* temporarily disable the PAGE_HIT to force +* data to be read from NAND +*/ +WR_ACC_CONTROL (host->cs,PAGE_HIT_EN ,0 ); +else + ctrl.data_cache_invalid =0 ; + } + +/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */ +iproc_nand_send_cmd (CMD_PAGE_READ ); +iproc_nand_waitfunc (mtd, chip); + +/* OOB bytes per sector */ + oob_bytes = (mtd->oobsize / trans) << + host->hwcfg.sector_size_1k; +/* OOB bytes per 512B transfer */ +if (host->hwcfg.sector_size_1k && (i &0x01 )) + oob_bytes =max (0 , oob_bytes - +MAX_CONTROLLER_OOB_BYTES ); + oob_bytes =min (oob_bytes,MAX_CONTROLLER_OOB_BYTES ); + +iproc_nand_cache_read (&buf, &oob, oob_bytes); + +if (ctrl.data_cache_invalid) { +/* re-enable PAGE_HIT */ +WR_ACC_CONTROL (host->cs,PAGE_HIT_EN ,1 ); + ctrl.data_cache_invalid =0 ; + } + +if (buf && (!host->hwcfg.sector_size_1k || (i &0x1 ))) { +/* check uncorrectable errors */ +if (NAND_TEST_IRQ (NCINTR_UNC )) {
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+if (erased_sector (mtd, + (u8 *)sector_buf, + sector_oob, + &bitflips)) { + corr_error_count += bitflips; +if (bitflips > max_bitflips) + max_bitflips = bitflips; + }else { + uncorr_error_count +=1 ; + }
This level of indentation should be a hint that this function needs to be broken up into smaller ones.
Quoted 31 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +31
-0+NAND_ACK_IRQ (NCINTR_UNC ); + ctrl.data_cache_invalid =1 ; + } +/* check correctable errors */ +if (NAND_TEST_IRQ (NCINTR_CORR )) { + bitflips =CORR_ERROR_COUNT ; + corr_error_count += bitflips; +if (bitflips > max_bitflips) + max_bitflips = bitflips; +NAND_ACK_IRQ (NCINTR_CORR ); + ctrl.data_cache_invalid =1 ; + } + } + } +if (uncorr_error_count) { +printf (DRV_NAME ": %d uncorrectable errors at 0x%llx\n" , + uncorr_error_count, (unsigned long long )start_addr); + mtd->ecc_stats.failed += uncorr_error_count; +/* NAND layer expects zero on ECC errors */ +return 0 ; + } +if (max_bitflips) { +debug ("%s: corrected %d bit errors at 0x%llx\n" , + __func__, max_bitflips, (unsigned long long )start_addr); + mtd->ecc_stats.corrected += corr_error_count; +return max_bitflips; + } + +return 0 ; +} +
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+static int iproc_nand_read_page (struct mtd_info *mtd, +struct nand_chip *chip, +uint8_t *buf, +int oob_required, +int page) +{ +struct iproc_nand_host *host = chip->priv; + +BUG_ON (!buf); +
What's with all these !buf checks? Do you think it's more likely that you'll get a NULL buf than any of the other pointers that get passed in?
Quoted 6 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +6
-0+static int iproc_nand_mark_bad (struct mtd_info *mtd,loff_t ofs) +{ +struct nand_chip *chip = mtd->priv; +u64 blk_addr = (u64 )ofs; + +debug ("%s %llx\n" , __func__, (unsigned long long )ofs);
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+ +/* get NAND block address */ + blk_addr &= ~((1 << chip->phys_erase_shift) -1 ); + +memset (chip->oob_poi,0xff , mtd->oobsize); + chip->oob_poi[chip->badblockpos] =0 ; + +return iproc_nand_write (mtd, chip, blk_addr,NULL , + (u8 *)chip->oob_poi); +}
Why do you need a custom version of this?
Quoted 8 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +8
-0+ +/* +* Per-CS setup (1 NAND device) +*/ + +static const unsigned int block_sizes[] = {8 ,16 ,128 ,256 ,512 ,1024 ,2048 }; +static const unsigned int page_sizes[] = {512 ,2048 ,4096 ,8192 }; +
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+static void iproc_nand_set_cfg (struct iproc_nand_host *host, +struct iproc_nand_cfg *cfg) +{ +int i, found; + +for (i =0 , found =0 ; i <ARRAY_SIZE (block_sizes); i++) +if ((block_sizes[i] <<10 ) == cfg->block_size) { +WR_CONFIG (host->cs,BLOCK_SIZE , i); + found =1 ; + }
U-Boot coding style requires braces around multiline statements.
Quoted 59 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +59
-0+debug ("%s: mtd configuration\n" +"\tdevice_size 0x%llx\n" +"\tblock_size 0x%x\n" +"\tpage_size 0x%x\n" +"\tdevice_width 0x%x\n" +"\tcol_adr_bytes 0x%x\n" +"\tblk_adr_bytes 0x%x\n" +"\tspare_area_size 0x%x\n" +"\tecc_level 0x%x\n" +"\tsector_size_1k 0x%x\n" , + __func__, + new_cfg.device_size, + new_cfg.block_size, + new_cfg.page_size, + new_cfg.device_width, + new_cfg.col_adr_bytes, + new_cfg.blk_adr_bytes, + new_cfg.spare_area_size, + new_cfg.ecc_level, + new_cfg.sector_size_1k); + +/* check settings determined by controller auto-init */ +if (ctrl.auto_inited) { +debug ("%s: auto-init configuration\n" +"\tdevice_size 0x%llx\n" +"\tblock_size 0x%x\n" +"\tpage_size 0x%x\n" +"\tdevice_width 0x%x\n" +"\tcol_adr_bytes 0x%x\n" +"\tblk_adr_bytes 0x%x\n" +"\tspare_area_size 0x%x\n" +"\tecc_level 0x%x\n" +"\tsector_size_1k 0x%x\n" , + __func__, + orig_cfg.device_size, + orig_cfg.block_size, + orig_cfg.page_size, + orig_cfg.device_width, + orig_cfg.col_adr_bytes, + orig_cfg.blk_adr_bytes, + orig_cfg.spare_area_size, + orig_cfg.ecc_level, + orig_cfg.sector_size_1k); +/* check basic device attributes first */ +if (orig_cfg.device_size != new_cfg.device_size || + orig_cfg.block_size != new_cfg.block_size || + orig_cfg.page_size != new_cfg.page_size || + orig_cfg.device_width != new_cfg.device_width || + orig_cfg.col_adr_bytes != new_cfg.col_adr_bytes || + orig_cfg.blk_adr_bytes != new_cfg.blk_adr_bytes || + orig_cfg.ful_adr_bytes != new_cfg.ful_adr_bytes || + orig_cfg.ecc_level ==0 || + ((orig_cfg.ecc_code ==ECC_CODE_BCH ) && + (orig_cfg.ecc_level > + iproc_max_bch_ecc_level[orig_cfg.sector_size_1k])) || + orig_cfg.spare_area_size > new_cfg.spare_area_size || + ((orig_cfg.ecc_code ==ECC_CODE_BCH ) && + (iproc_bch_ecc_bytes[orig_cfg.ecc_level] > + orig_cfg.spare_area_size))) {
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+/* ignore invalid auto-init settings */ + ctrl.auto_inited =0 ; +printf (DRV_NAME ": invalid auto-init settings\n" ); + + }else { +/* auto-init has initialized the flash correctly. */ + new_cfg = orig_cfg; +printf (DRV_NAME ": following auto-init settings\n" ); + } + }
This is a bit elaborate... what is "auto-init"?
Quoted 5 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +5
-0+static void iproc_nand_timing_setup (struct iproc_nand_host *host) +{ +struct nand_chip *chip = &host->chip; +int onfi_tmode;/* bit mask of supported onfi timing modes */ +
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+/* +* ctrl.tmode has the configured tmode upper limit [0-5] +* or is -1 to indicate power-on default timing +*/ +if (ctrl.tmode <0 || ctrl.tmode >=ONFI_TIMING_MODES ) +return ; + +if (chip->onfi_version) { + onfi_tmode =le16_to_cpu (get_unaligned ( + (u16 *)&chip->onfi_params.async_timing_mode));
Fix onfi_get_async_timing_mode() instead, and have it use get_unaligned_le16().
Quoted 12 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +12
-0+if ((onfi_tmode ==0 ) || (onfi_tmode & ~0x3F )) { +printf (DRV_NAME +": invalid ONFI timing mode ignored 0x%x\n" , + onfi_tmode); + }else { +/* +* select the maximum supported ONFI timing mode +* that is lower than the configured limit +*/ +while (ctrl.tmode >0 ) { +if (onfi_tmode & (1 << ctrl.tmode)) +break ;
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+ ctrl.tmode--; + } + } + } + +NAND_REG_WR (NC_REG_TIMING1 (host->cs), + ctrl.data->onfi_tmode[ctrl.tmode].timing1); +NAND_REG_WR (NC_REG_TIMING2 (host->cs), + ctrl.data->onfi_tmode[ctrl.tmode].timing2); +printf (DRV_NAME ": timing mode %d\n" , ctrl.tmode);
This verbosity is not appropriate for normal driver init.
Quoted 20 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +20
-0+#ifdef CONFIG_SYS_MAX_NAND_CHIPS +#if (CONFIG_SYS_MAX_NAND_CHIPS >NAND_MAX_CS ) +#error "Invalid CONFIG_SYS_MAX_NAND_CHIPS value" +#endif + ctrl.max_cs =CONFIG_SYS_MAX_NAND_CHIPS ; +#else + ctrl.max_cs =1 ; +#endif + +/* write protect configuration */ +#ifdef CONFIG_IPROC_NAND_WP_MODE +#if ((CONFIG_IPROC_NAND_WP_MODE <0 ) || \ + (CONFIG_IPROC_NAND_WP_MODE >WP_ALWAYS_CLEARED )) +#error "Invalid CONFIG_IPROC_NAND_WP_MODE value" +#endif + ctrl.wp_mode =CONFIG_IPROC_NAND_WP_MODE ; +#else + ctrl.wp_mode =WP_SET_BY_DEFAULT ; +#endif +
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+/* timing mode configuration */ +#ifdef CONFIG_IPROC_NAND_TIMING_MODE +#if ((CONFIG_IPROC_NAND_TIMING_MODE <0 ) || \ + (CONFIG_IPROC_NAND_TIMING_MODE >=ONFI_TIMING_MODES )) +#error "Invalid CONFIG_IPROC_NAND_TIMING_MODE value" +#endif + ctrl.tmode =CONFIG_IPROC_NAND_TIMING_MODE ; +#else + ctrl.tmode =-1 ;/* use default timing configuration */ +#endif
These would be more readable as:
#ifdef CONFIG_FOO
#define CONFIG_FOO <default_value>
#endif
...
BUILD_BUG_ON(CONFIG_FOO is bad);
ctrl.foo = CONFIG_FOO;
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 8 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +8
-0+debug ("%s: nand_regs %p\n" , __func__, ctrl.nand_regs); +debug ("%s: nand_intr_regs %p\n" , __func__, ctrl.nand_intr_regs); +debug ("%s: nand_idm_regs %p\n" , __func__, ctrl.nand_idm_regs); +debug ("%s: nand_idm_io_ctrl_direct_reg %p\n" , __func__, + ctrl.nand_idm_io_ctrl_direct_reg); +debug ("%s: nand_strap_regs %p\n" , __func__, ctrl.nand_strap_regs); +debug ("%s: max_cs %d\n" , __func__, ctrl.max_cs); +debug ("%s: wp_mode %d\n" , __func__, ctrl.wp_mode);
This driver has a lot of debug clutter. Is it really
Quoted 1 line
+#ifdef
CONFIG_IPROC_NAND_AUTO_INIT
Undocumented, and should be in kconfig.
Quoted 19 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +19
-0+int iproc_nand_init (void ) +{ +struct iproc_nand_host *host; +struct mtd_info *mtd; +struct nand_chip *chip; + +NAND_REG_WR (NCREG_SEMAPHORE ,0 ); + + host = &nand_host; +memset (host,0 ,sizeof (*host)); + + host->mtd = &nand_info[0 ]; + + host->cs =0 ; + + mtd = host->mtd; + chip = &host->chip; + + chip->priv = host;
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+ mtd->priv = chip; + mtd->name ="iproc_nand" ; +/* +* set mtd bitflip threshold to 1 as the desired threshold will +* be set in the controller register. +*/ + mtd->bitflip_threshold =1 ; + + chip->IO_ADDR_R = (void *)0xdeadbeef ; + chip->IO_ADDR_W = (void *)0xdeadbeef ;
Why?
Quoted 22 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +22
-0+ chip->cmd_ctrl = iproc_nand_cmd_ctrl; + chip->cmdfunc = iproc_nand_cmdfunc; + chip->waitfunc = iproc_nand_waitfunc; + chip->read_byte = iproc_nand_read_byte; + chip->read_buf = iproc_nand_read_buf; +if (ctrl.max_cs >1 ) + chip->select_chip = iproc_nand_select_chip; + + chip->block_bad = iproc_nand_block_bad; + chip->block_markbad = iproc_nand_mark_bad; + + chip->ecc.mode =NAND_ECC_HW ; + chip->ecc.layout = &iproc_nand_oob_layout; + chip->ecc.read_page = iproc_nand_read_page; + chip->ecc.write_page = iproc_nand_write_page; + chip->ecc.read_page_raw = iproc_nand_read_page_raw; + chip->ecc.write_page_raw = iproc_nand_write_page_raw; + + chip->ecc.write_oob_raw = iproc_nand_write_oob_raw; + chip->ecc.read_oob_raw = iproc_nand_read_oob_raw; + + chip->ecc.read_oob = (void *)iproc_nand_read_oob;
arch/arm/include/asm/arch-bcmnsp/configs.h
Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10
-0+ chip->ecc.write_oob = iproc_nand_write_oob; + + chip->controller = &ctrl.controller; + +if (nand_scan_ident (mtd, ctrl.max_cs,NULL )) +return -ENXIO ; + + chip->options |=NAND_NO_SUBPAGE_WRITE |NAND_SKIP_BBTSCAN ; + + chip->bbt_options |=NAND_BBT_USE_FLASH |NAND_BBT_NO_OOB ;
Why skip the BBT scan?
-Scott