diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index 7d76ede984d8..186ea9dc0942 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig @@ -29,4 +29,10 @@ config MTD_ONENAND_OMAP help Support for OneNAND flash on TI OMAP board. +config MTD_ONENAND_SYNC_READ + bool "OneNAND Sync. Burst Read Support" + depends on ARCH_OMAP + help + This enables support for Sync. Burst Read. + endmenu diff --git a/drivers/mtd/onenand/omap-onenand.c b/drivers/mtd/onenand/omap-onenand.c index 56e1aec6b835..7c89549f7f58 100644 --- a/drivers/mtd/onenand/omap-onenand.c +++ b/drivers/mtd/onenand/omap-onenand.c @@ -25,9 +25,10 @@ #include #include #include +#include #define OMAP_ONENAND_FLASH_START1 OMAP_CS2A_PHYS -#define OMAP_ONENAND_FLASH_START2 OMAP_CS0_PHYS +#define OMAP_ONENAND_FLASH_START2 omap_cs3_phys() /* * MTD structure for OMAP board */ @@ -68,10 +69,66 @@ static struct mtd_partition static_partition[] = { }, }; -const char *part_probes[] = { "cmdlinepart", NULL, }; +static const char *part_probes[] = { "cmdlinepart", NULL, }; #endif +#ifdef CONFIG_MTD_ONENAND_SYNC_READ +static unsigned int omap_emifs_cs; + +static void omap_find_emifs_cs(unsigned int addr) +{ + /* Check CS3 */ + if (OMAP_EMIFS_CONFIG_REG & OMAP_EMIFS_CONFIG_BM && addr == 0x0) { + omap_emifs_cs = 3; + } else { + omap_emifs_cs = (addr >> 26); + } +} + +/** + * omap_onenand_mmcontrol - Control OMAP EMIFS + */ +static void omap_onenand_mmcontrol(struct mtd_info *mtd, int sync_read) +{ + struct onenand_chip *this = mtd->priv; + static unsigned long omap_emifs_ccs, omap_emifs_acs; + static unsigned long onenand_sys_cfg1; + int config, emifs_ccs, emifs_acs; + + if (sync_read) { + /* + * Note: BRL and RDWST is equal + */ + omap_emifs_ccs = EMIFS_CCS(omap_emifs_cs); + omap_emifs_acs = EMIFS_ACS(omap_emifs_cs); + + emifs_ccs = 0x41141; + emifs_acs = 0x1; + + /* OneNAND System Configuration 1 */ + onenand_sys_cfg1 = this->read_word(this->base + ONENAND_REG_SYS_CFG1); + config = (onenand_sys_cfg1 + & ~(0x3f << ONENAND_SYS_CFG1_BL_SHIFT)) + | ONENAND_SYS_CFG1_SYNC_READ + | ONENAND_SYS_CFG1_BRL_4 + | ONENAND_SYS_CFG1_BL_8; + } else { + emifs_ccs = omap_emifs_ccs; + emifs_acs = omap_emifs_acs; + config = onenand_sys_cfg1; + } + + this->write_word(config, this->base + ONENAND_REG_SYS_CFG1); + EMIFS_CCS(omap_emifs_cs) = emifs_ccs; + EMIFS_ACS(omap_emifs_cs) = emifs_acs; +} +#else +#define omap_find_emifs_cs(x) do { } while (0) +#define omap_onenand_mmcontrol NULL +#endif + + /* Scan to find existance of the device at base. This also allocates oob and data internal buffers */ static char onenand_name[] = "onenand"; @@ -102,14 +159,19 @@ static int __init omap_onenand_init (void) /* Link the private data with the MTD structure */ omap_onenand_mtd->priv = this; + this->mmcontrol = omap_onenand_mmcontrol; /* try the first address */ this->base = ioremap(OMAP_ONENAND_FLASH_START1, SZ_128K); + omap_find_emifs_cs(OMAP_ONENAND_FLASH_START1); + omap_onenand_mtd->name = onenand_name; if (onenand_scan(omap_onenand_mtd, 1)){ /* try the second address */ iounmap(this->base); this->base = ioremap(OMAP_ONENAND_FLASH_START2, SZ_128K); + omap_find_emifs_cs(OMAP_ONENAND_FLASH_START2); + if (onenand_scan(omap_onenand_mtd, 1)) { iounmap(this->base); err = -ENXIO; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index bcce22ae3cb1..e87489505772 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -378,6 +378,35 @@ static int onenand_read_bufferram(struct mtd_info *mtd, int area, return 0; } +/** + * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode + * @param mtd MTD data structure + * @param area BufferRAM area + * @param buffer the databuffer to put/get data + * @param offset offset to read from or write to + * @param count number of bytes to read/write + * + * Read the BufferRAM area with Sync. Burst Mode + */ +static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, size_t count) +{ + struct onenand_chip *this = mtd->priv; + void __iomem *bufferram; + + bufferram = this->base + area; + + bufferram += onenand_bufferram_offset(mtd, area); + + this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); + + memcpy(buffer, bufferram + offset, count); + + this->mmcontrol(mtd, 0); + + return 0; +} + /** * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area * @param mtd MTD data structure @@ -1273,8 +1302,8 @@ static int onenand_check_maf(int manuf) break; } - printk(KERN_DEBUG "OneNAND Manufacturer: %s\n", - onenand_manuf_ids[i].name); + printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", + onenand_manuf_ids[i].name, manuf); return (i != ONENAND_MFR_UNKNOWN); } @@ -1385,6 +1414,12 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) if (onenand_probe(mtd)) return -ENXIO; + /* Set Sync. Burst Read after probing */ + if (this->mmcontrol) { + printk(KERN_INFO "OneNAND Sync. Burst Read support\n"); + this->read_bufferram = onenand_sync_read_bufferram; + } + this->state = FL_READY; init_waitqueue_head(&this->wq); spin_lock_init(&this->chip_lock); diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index b9a64117d646..c557caa24a6c 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -95,6 +95,7 @@ struct onenand_chip { const unsigned char *buffer, int offset, size_t count); unsigned short (*read_word)(void __iomem *addr); void (*write_word)(unsigned short value, void __iomem *addr); + void (*mmcontrol)(struct mtd_info *mtd, int sync_read); spinlock_t chip_lock; wait_queue_head_t wq; diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index 4a2daad7d738..d7832ef8ed63 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h @@ -121,8 +121,21 @@ * System Configuration 1 Register F221h (R, R/W) */ #define ONENAND_SYS_CFG1_SYNC_READ (1 << 15) -#define ONENAND_SYS_CFG1_BRL (1 << 12) -#define ONENAND_SYS_CFG1_BL (1 << 9) +#define ONENAND_SYS_CFG1_BRL_7 (7 << 12) +#define ONENAND_SYS_CFG1_BRL_6 (6 << 12) +#define ONENAND_SYS_CFG1_BRL_5 (5 << 12) +#define ONENAND_SYS_CFG1_BRL_4 (4 << 12) +#define ONENAND_SYS_CFG1_BRL_3 (3 << 12) +#define ONENAND_SYS_CFG1_BRL_10 (2 << 12) +#define ONENAND_SYS_CFG1_BRL_9 (1 << 12) +#define ONENAND_SYS_CFG1_BRL_8 (0 << 12) +#define ONENAND_SYS_CFG1_BRL_SHIFT (12) +#define ONENAND_SYS_CFG1_BL_32 (4 << 9) +#define ONENAND_SYS_CFG1_BL_16 (3 << 9) +#define ONENAND_SYS_CFG1_BL_8 (2 << 9) +#define ONENAND_SYS_CFG1_BL_4 (1 << 9) +#define ONENAND_SYS_CFG1_BL_CONT (0 << 9) +#define ONENAND_SYS_CFG1_BL_SHIFT (9) #define ONENAND_SYS_CFG1_NO_ECC (1 << 8) #define ONENAND_SYS_CFG1_RDY (1 << 7) #define ONENAND_SYS_CFG1_INT (1 << 6)