Message ID | 60361.192.168.10.89.1247482584.squirrel@dbdmail.itg.ti.com |
---|---|
State | New, archived |
Headers | show |
* vimal singh <vimalsingh@ti.com> [090713 13:56]: > Patch updated for ' ioreadX / iowriteX and ioreadX_rep / iowriteX_rep' as per > David Brownell's comment. I updated 'omap_(read/write)_buf16' fucntions also > for this. > > -vimal > > This patch adds prefetch support to access nand flash in mpu mode. > This patch also adds 8-bit nand support (omap_read/write_buf8). > Prefetch can be used for both 8- and 16-bit devices. > > Signed-off-by: Vimal Singh <vimalsingh@ti.com> Sorry for the delay. I've looked at the GPMC part, and that now looks OK to me. So I'm OK for this to get integrated via the MTD list. Acked-by: Tony Lindgren <tony@atomide.com> > --- > > --- > arch/arm/mach-omap2/gpmc.c | 63 ++++++++++++ > arch/arm/plat-omap/include/mach/gpmc.h | 4 > drivers/mtd/nand/Kconfig | 8 + > drivers/mtd/nand/omap2.c | 161 +++++++++++++++++++++++++++++++-- > 4 files changed, 226 insertions(+), 10 deletions(-) > > Index: mtd-2.6/arch/arm/mach-omap2/gpmc.c > =================================================================== > --- mtd-2.6.orig/arch/arm/mach-omap2/gpmc.c > +++ mtd-2.6/arch/arm/mach-omap2/gpmc.c > @@ -57,6 +57,11 @@ > #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ > #define GPMC_SECTION_SHIFT 28 /* 128 MB */ > > +#define PREFETCH_FIFOTHRESHOLD (0x40 << 8) > +#define CS_NUM_SHIFT 24 > +#define ENABLE_PREFETCH (0x1 << 7) > +#define DMA_MPU_MODE 2 > + > static struct resource gpmc_mem_root; > static struct resource gpmc_cs_mem[GPMC_CS_NUM]; > static DEFINE_SPINLOCK(gpmc_mem_lock); > @@ -386,6 +391,63 @@ void gpmc_cs_free(int cs) > } > EXPORT_SYMBOL(gpmc_cs_free); > > +/** > + * gpmc_prefetch_enable - configures and starts prefetch transfer > + * @cs: nand cs (chip select) number > + * @dma_mode: dma mode enable (1) or disable (0) > + * @u32_count: number of bytes to be transferred > + * @is_write: prefetch read(0) or write post(1) mode > + */ > +int gpmc_prefetch_enable(int cs, int dma_mode, > + unsigned int u32_count, int is_write) > +{ > + uint32_t prefetch_config1; > + > + if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) { > + /* Set the amount of bytes to be prefetched */ > + gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count); > + > + /* Set dma/mpu mode, the prefetch read / post write and > + * enable the engine. Set which cs is has requested for. > + */ > + prefetch_config1 = ((cs << CS_NUM_SHIFT) | > + PREFETCH_FIFOTHRESHOLD | > + ENABLE_PREFETCH | > + (dma_mode << DMA_MPU_MODE) | > + (0x1 & is_write)); > + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1); > + } else { > + return -EBUSY; > + } > + /* Start the prefetch engine */ > + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1); > + > + return 0; > +} > +EXPORT_SYMBOL(gpmc_prefetch_enable); > + > +/** > + * gpmc_prefetch_reset - disables and stops the prefetch engine > + */ > +void gpmc_prefetch_reset(void) > +{ > + /* Stop the PFPW engine */ > + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0); > + > + /* Reset/disable the PFPW engine */ > + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0); > +} > +EXPORT_SYMBOL(gpmc_prefetch_reset); > + > +/** > + * gpmc_prefetch_status - reads prefetch status of engine > + */ > +int gpmc_prefetch_status(void) > +{ > + return gpmc_read_reg(GPMC_PREFETCH_STATUS); > +} > +EXPORT_SYMBOL(gpmc_prefetch_status); > + > static void __init gpmc_mem_init(void) > { > int cs; > @@ -452,6 +514,5 @@ void __init gpmc_init(void) > l &= 0x03 << 3; > l |= (0x02 << 3) | (1 << 0); > gpmc_write_reg(GPMC_SYSCONFIG, l); > - > gpmc_mem_init(); > } > Index: mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h > =================================================================== > --- mtd-2.6.orig/arch/arm/plat-omap/include/mach/gpmc.h > +++ mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h > @@ -103,6 +103,10 @@ extern int gpmc_cs_request(int cs, unsig > extern void gpmc_cs_free(int cs); > extern int gpmc_cs_set_reserved(int cs, int reserved); > extern int gpmc_cs_reserved(int cs); > +extern int gpmc_prefetch_enable(int cs, int dma_mode, > + unsigned int u32_count, int is_write); > +extern void gpmc_prefetch_reset(void); > +extern int gpmc_prefetch_status(void); > extern void __init gpmc_init(void); > > #endif > Index: mtd-2.6/drivers/mtd/nand/Kconfig > =================================================================== > --- mtd-2.6.orig/drivers/mtd/nand/Kconfig > +++ mtd-2.6/drivers/mtd/nand/Kconfig > @@ -80,6 +80,14 @@ config MTD_NAND_OMAP2 > help > Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. > > +config MTD_NAND_OMAP_PREFETCH > + bool "GPMC prefetch support for NAND Flash device" > + depends on MTD_NAND && MTD_NAND_OMAP2 > + default y > + help > + The NAND device can be accessed for Read/Write using GPMC PREFETCH engine > + to improve the performance. > + > config MTD_NAND_TS7250 > tristate "NAND Flash device on TS-7250 board" > depends on MACH_TS72XX > Index: mtd-2.6/drivers/mtd/nand/omap2.c > =================================================================== > --- mtd-2.6.orig/drivers/mtd/nand/omap2.c > +++ mtd-2.6/drivers/mtd/nand/omap2.c > @@ -112,6 +112,16 @@ > static const char *part_probes[] = { "cmdlinepart", NULL }; > #endif > > +#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH > +static int use_prefetch = 1; > + > +/* "modprobe ... use_prefetch=0" etc */ > +module_param(use_prefetch, bool, 0); > +MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH"); > +#else > +const int use_prefetch; > +#endif > + > struct omap_nand_info { > struct nand_hw_control controller; > struct omap_nand_platform_data *pdata; > @@ -124,6 +134,7 @@ struct omap_nand_info { > unsigned long phys_base; > void __iomem *gpmc_cs_baseaddr; > void __iomem *gpmc_baseaddr; > + void __iomem *nand_pref_fifo_add; > }; > > /** > @@ -189,6 +200,38 @@ static void omap_hwcontrol(struct mtd_in > } > > /** > + * omap_read_buf8 - read data from NAND controller into buffer > + * @mtd: MTD device structure > + * @buf: buffer to store date > + * @len: number of bytes to read > + */ > +static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len) > +{ > + struct nand_chip *nand = mtd->priv; > + > + ioread8_rep(nand->IO_ADDR_R, buf, len); > +} > + > +/** > + * omap_write_buf8 - write buffer to NAND controller > + * @mtd: MTD device structure > + * @buf: data buffer > + * @len: number of bytes to write > + */ > +static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) > +{ > + struct omap_nand_info *info = container_of(mtd, > + struct omap_nand_info, mtd); > + u_char *p = (u_char *)buf; > + > + while (len--) { > + iowrite8(*p++, info->nand.IO_ADDR_W); > + while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + > + GPMC_STATUS) & GPMC_BUF_FULL)); > + } > +} > + > +/** > * omap_read_buf16 - read data from NAND controller into buffer > * @mtd: MTD device structure > * @buf: buffer to store date > @@ -198,7 +241,7 @@ static void omap_read_buf16(struct mtd_i > { > struct nand_chip *nand = mtd->priv; > > - __raw_readsw(nand->IO_ADDR_R, buf, len / 2); > + ioread16_rep(nand->IO_ADDR_R, buf, len / 2); > } > > /** > @@ -217,13 +260,101 @@ static void omap_write_buf16(struct mtd_ > len >>= 1; > > while (len--) { > - writew(*p++, info->nand.IO_ADDR_W); > + iowrite16(*p++, info->nand.IO_ADDR_W); > > while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + > GPMC_STATUS) & GPMC_BUF_FULL)) > ; > } > } > + > +/** > + * omap_read_buf_pref - read data from NAND controller into buffer > + * @mtd: MTD device structure > + * @buf: buffer to store date > + * @len: number of bytes to read > + */ > +static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) > +{ > + struct omap_nand_info *info = container_of(mtd, > + struct omap_nand_info, mtd); > + uint32_t pfpw_status = 0, r_count = 0; > + int ret = 0; > + u32 *p = (u32 *)buf; > + > + /* take care of subpage reads */ > + for (; len % 4 != 0; ) { > + *buf++ = __raw_readb(info->nand.IO_ADDR_R); > + len--; > + } > + p = (u32 *) buf; > + > + /* configure and start prefetch transfer */ > + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0); > + if (ret) { > + /* PFPW engine is busy, use cpu copy method */ > + if (info->nand.options & NAND_BUSWIDTH_16) > + omap_read_buf16(mtd, buf, len); > + else > + omap_read_buf8(mtd, buf, len); > + } else { > + do { > + pfpw_status = gpmc_prefetch_status(); > + r_count = ((pfpw_status >> 24) & 0x7F) >> 2; > + ioread32_rep(info->nand_pref_fifo_add, p, r_count); > + p += r_count; > + len -= r_count << 2; > + } while (len); > + > + /* disable and stop the PFPW engine */ > + gpmc_prefetch_reset(); > + } > +} > + > +/** > + * omap_write_buf_pref - write buffer to NAND controller > + * @mtd: MTD device structure > + * @buf: data buffer > + * @len: number of bytes to write > + */ > +static void omap_write_buf_pref(struct mtd_info *mtd, > + const u_char *buf, int len) > +{ > + struct omap_nand_info *info = container_of(mtd, > + struct omap_nand_info, mtd); > + uint32_t pfpw_status = 0, w_count = 0; > + int i = 0, ret = 0; > + u16 *p = (u16 *) buf; > + > + /* take care of subpage writes */ > + if (len % 2 != 0) { > + writeb(*buf, info->nand.IO_ADDR_R); > + p = (u16 *)(buf + 1); > + len--; > + } > + > + /* configure and start prefetch transfer */ > + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1); > + if (ret) { > + /* PFPW engine is busy, use cpu copy method */ > + if (info->nand.options & NAND_BUSWIDTH_16) > + omap_write_buf16(mtd, buf, len); > + else > + omap_write_buf8(mtd, buf, len); > + } else { > + pfpw_status = gpmc_prefetch_status(); > + while (pfpw_status & 0x3FFF) { > + w_count = ((pfpw_status >> 24) & 0x7F) >> 1; > + for (i = 0; (i < w_count) && len; i++, len -= 2) > + iowrite16(*p++, info->nand_pref_fifo_add); > + pfpw_status = gpmc_prefetch_status(); > + } > + > + /* disable and stop the PFPW engine */ > + gpmc_prefetch_reset(); > + } > +} > + > /** > * omap_verify_buf - Verify chip data against buffer > * @mtd: MTD device structure > @@ -658,17 +789,12 @@ static int __devinit omap_nand_probe(str > err = -ENOMEM; > goto out_release_mem_region; > } > + > info->nand.controller = &info->controller; > > info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; > info->nand.cmd_ctrl = omap_hwcontrol; > > - /* REVISIT: only supports 16-bit NAND flash */ > - > - info->nand.read_buf = omap_read_buf16; > - info->nand.write_buf = omap_write_buf16; > - info->nand.verify_buf = omap_verify_buf; > - > /* > * If RDY/BSY line is connected to OMAP then use the omap ready > * funcrtion and the generic nand_wait function which reads the status > @@ -689,6 +815,23 @@ static int __devinit omap_nand_probe(str > == 0x1000) > info->nand.options |= NAND_BUSWIDTH_16; > > + if (use_prefetch) { > + /* copy the virtual address of nand base for fifo access */ > + info->nand_pref_fifo_add = info->nand.IO_ADDR_R; > + > + info->nand.read_buf = omap_read_buf_pref; > + info->nand.write_buf = omap_write_buf_pref; > + } else { > + if (info->nand.options & NAND_BUSWIDTH_16) { > + info->nand.read_buf = omap_read_buf16; > + info->nand.write_buf = omap_write_buf16; > + } else { > + info->nand.read_buf = omap_read_buf8; > + info->nand.write_buf = omap_write_buf8; > + } > + } > + info->nand.verify_buf = omap_verify_buf; > + > #ifdef CONFIG_MTD_NAND_OMAP_HWECC > info->nand.ecc.bytes = 3; > info->nand.ecc.size = 512; > @@ -746,7 +889,7 @@ static int omap_nand_remove(struct platf > platform_set_drvdata(pdev, NULL); > /* Release NAND device, its internal structures and partitions */ > nand_release(&info->mtd); > - iounmap(info->nand.IO_ADDR_R); > + iounmap(info->nand_pref_fifo_add); > kfree(&info->mtd); > return 0; > } > >
On Mon, Aug 10, 2009 at 9:57 PM, Tony Lindgren<tony@atomide.com> wrote: > * vimal singh <vimalsingh@ti.com> [090713 13:56]: >> Patch updated for ' ioreadX / iowriteX and ioreadX_rep / iowriteX_rep' as per >> David Brownell's comment. I updated 'omap_(read/write)_buf16' fucntions also >> for this. >> >> -vimal >> >> This patch adds prefetch support to access nand flash in mpu mode. >> This patch also adds 8-bit nand support (omap_read/write_buf8). >> Prefetch can be used for both 8- and 16-bit devices. >> >> Signed-off-by: Vimal Singh <vimalsingh@ti.com> > > Sorry for the delay. I've looked at the GPMC part, and that now looks OK > to me. So I'm OK for this to get integrated via the MTD list. > > Acked-by: Tony Lindgren <tony@atomide.com> > Can you give your ack to below patch too? http://lists.infradead.org/pipermail/linux-mtd/2009-July/026373.html > >> --- >> >> --- >> arch/arm/mach-omap2/gpmc.c | 63 ++++++++++++ >> arch/arm/plat-omap/include/mach/gpmc.h | 4 >> drivers/mtd/nand/Kconfig | 8 + >> drivers/mtd/nand/omap2.c | 161 +++++++++++++++++++++++++++++++-- >> 4 files changed, 226 insertions(+), 10 deletions(-) >> >> Index: mtd-2.6/arch/arm/mach-omap2/gpmc.c >> =================================================================== >> --- mtd-2.6.orig/arch/arm/mach-omap2/gpmc.c >> +++ mtd-2.6/arch/arm/mach-omap2/gpmc.c >> @@ -57,6 +57,11 @@ >> #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ >> #define GPMC_SECTION_SHIFT 28 /* 128 MB */ >> >> +#define PREFETCH_FIFOTHRESHOLD (0x40 << 8) >> +#define CS_NUM_SHIFT 24 >> +#define ENABLE_PREFETCH (0x1 << 7) >> +#define DMA_MPU_MODE 2 >> + >> static struct resource gpmc_mem_root; >> static struct resource gpmc_cs_mem[GPMC_CS_NUM]; >> static DEFINE_SPINLOCK(gpmc_mem_lock); >> @@ -386,6 +391,63 @@ void gpmc_cs_free(int cs) >> } >> EXPORT_SYMBOL(gpmc_cs_free); >> >> +/** >> + * gpmc_prefetch_enable - configures and starts prefetch transfer >> + * @cs: nand cs (chip select) number >> + * @dma_mode: dma mode enable (1) or disable (0) >> + * @u32_count: number of bytes to be transferred >> + * @is_write: prefetch read(0) or write post(1) mode >> + */ >> +int gpmc_prefetch_enable(int cs, int dma_mode, >> + unsigned int u32_count, int is_write) >> +{ >> + uint32_t prefetch_config1; >> + >> + if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) { >> + /* Set the amount of bytes to be prefetched */ >> + gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count); >> + >> + /* Set dma/mpu mode, the prefetch read / post write and >> + * enable the engine. Set which cs is has requested for. >> + */ >> + prefetch_config1 = ((cs << CS_NUM_SHIFT) | >> + PREFETCH_FIFOTHRESHOLD | >> + ENABLE_PREFETCH | >> + (dma_mode << DMA_MPU_MODE) | >> + (0x1 & is_write)); >> + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1); >> + } else { >> + return -EBUSY; >> + } >> + /* Start the prefetch engine */ >> + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1); >> + >> + return 0; >> +} >> +EXPORT_SYMBOL(gpmc_prefetch_enable); >> + >> +/** >> + * gpmc_prefetch_reset - disables and stops the prefetch engine >> + */ >> +void gpmc_prefetch_reset(void) >> +{ >> + /* Stop the PFPW engine */ >> + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0); >> + >> + /* Reset/disable the PFPW engine */ >> + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0); >> +} >> +EXPORT_SYMBOL(gpmc_prefetch_reset); >> + >> +/** >> + * gpmc_prefetch_status - reads prefetch status of engine >> + */ >> +int gpmc_prefetch_status(void) >> +{ >> + return gpmc_read_reg(GPMC_PREFETCH_STATUS); >> +} >> +EXPORT_SYMBOL(gpmc_prefetch_status); >> + >> static void __init gpmc_mem_init(void) >> { >> int cs; >> @@ -452,6 +514,5 @@ void __init gpmc_init(void) >> l &= 0x03 << 3; >> l |= (0x02 << 3) | (1 << 0); >> gpmc_write_reg(GPMC_SYSCONFIG, l); >> - >> gpmc_mem_init(); >> } >> Index: mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h >> =================================================================== >> --- mtd-2.6.orig/arch/arm/plat-omap/include/mach/gpmc.h >> +++ mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h >> @@ -103,6 +103,10 @@ extern int gpmc_cs_request(int cs, unsig >> extern void gpmc_cs_free(int cs); >> extern int gpmc_cs_set_reserved(int cs, int reserved); >> extern int gpmc_cs_reserved(int cs); >> +extern int gpmc_prefetch_enable(int cs, int dma_mode, >> + unsigned int u32_count, int is_write); >> +extern void gpmc_prefetch_reset(void); >> +extern int gpmc_prefetch_status(void); >> extern void __init gpmc_init(void); >> >> #endif >> Index: mtd-2.6/drivers/mtd/nand/Kconfig >> =================================================================== >> --- mtd-2.6.orig/drivers/mtd/nand/Kconfig >> +++ mtd-2.6/drivers/mtd/nand/Kconfig >> @@ -80,6 +80,14 @@ config MTD_NAND_OMAP2 >> help >> Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. >> >> +config MTD_NAND_OMAP_PREFETCH >> + bool "GPMC prefetch support for NAND Flash device" >> + depends on MTD_NAND && MTD_NAND_OMAP2 >> + default y >> + help >> + The NAND device can be accessed for Read/Write using GPMC PREFETCH engine >> + to improve the performance. >> + >> config MTD_NAND_TS7250 >> tristate "NAND Flash device on TS-7250 board" >> depends on MACH_TS72XX >> Index: mtd-2.6/drivers/mtd/nand/omap2.c >> =================================================================== >> --- mtd-2.6.orig/drivers/mtd/nand/omap2.c >> +++ mtd-2.6/drivers/mtd/nand/omap2.c >> @@ -112,6 +112,16 @@ >> static const char *part_probes[] = { "cmdlinepart", NULL }; >> #endif >> >> +#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH >> +static int use_prefetch = 1; >> + >> +/* "modprobe ... use_prefetch=0" etc */ >> +module_param(use_prefetch, bool, 0); >> +MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH"); >> +#else >> +const int use_prefetch; >> +#endif >> + >> struct omap_nand_info { >> struct nand_hw_control controller; >> struct omap_nand_platform_data *pdata; >> @@ -124,6 +134,7 @@ struct omap_nand_info { >> unsigned long phys_base; >> void __iomem *gpmc_cs_baseaddr; >> void __iomem *gpmc_baseaddr; >> + void __iomem *nand_pref_fifo_add; >> }; >> >> /** >> @@ -189,6 +200,38 @@ static void omap_hwcontrol(struct mtd_in >> } >> >> /** >> + * omap_read_buf8 - read data from NAND controller into buffer >> + * @mtd: MTD device structure >> + * @buf: buffer to store date >> + * @len: number of bytes to read >> + */ >> +static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len) >> +{ >> + struct nand_chip *nand = mtd->priv; >> + >> + ioread8_rep(nand->IO_ADDR_R, buf, len); >> +} >> + >> +/** >> + * omap_write_buf8 - write buffer to NAND controller >> + * @mtd: MTD device structure >> + * @buf: data buffer >> + * @len: number of bytes to write >> + */ >> +static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) >> +{ >> + struct omap_nand_info *info = container_of(mtd, >> + struct omap_nand_info, mtd); >> + u_char *p = (u_char *)buf; >> + >> + while (len--) { >> + iowrite8(*p++, info->nand.IO_ADDR_W); >> + while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + >> + GPMC_STATUS) & GPMC_BUF_FULL)); >> + } >> +} >> + >> +/** >> * omap_read_buf16 - read data from NAND controller into buffer >> * @mtd: MTD device structure >> * @buf: buffer to store date >> @@ -198,7 +241,7 @@ static void omap_read_buf16(struct mtd_i >> { >> struct nand_chip *nand = mtd->priv; >> >> - __raw_readsw(nand->IO_ADDR_R, buf, len / 2); >> + ioread16_rep(nand->IO_ADDR_R, buf, len / 2); >> } >> >> /** >> @@ -217,13 +260,101 @@ static void omap_write_buf16(struct mtd_ >> len >>= 1; >> >> while (len--) { >> - writew(*p++, info->nand.IO_ADDR_W); >> + iowrite16(*p++, info->nand.IO_ADDR_W); >> >> while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + >> GPMC_STATUS) & GPMC_BUF_FULL)) >> ; >> } >> } >> + >> +/** >> + * omap_read_buf_pref - read data from NAND controller into buffer >> + * @mtd: MTD device structure >> + * @buf: buffer to store date >> + * @len: number of bytes to read >> + */ >> +static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) >> +{ >> + struct omap_nand_info *info = container_of(mtd, >> + struct omap_nand_info, mtd); >> + uint32_t pfpw_status = 0, r_count = 0; >> + int ret = 0; >> + u32 *p = (u32 *)buf; >> + >> + /* take care of subpage reads */ >> + for (; len % 4 != 0; ) { >> + *buf++ = __raw_readb(info->nand.IO_ADDR_R); >> + len--; >> + } >> + p = (u32 *) buf; >> + >> + /* configure and start prefetch transfer */ >> + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0); >> + if (ret) { >> + /* PFPW engine is busy, use cpu copy method */ >> + if (info->nand.options & NAND_BUSWIDTH_16) >> + omap_read_buf16(mtd, buf, len); >> + else >> + omap_read_buf8(mtd, buf, len); >> + } else { >> + do { >> + pfpw_status = gpmc_prefetch_status(); >> + r_count = ((pfpw_status >> 24) & 0x7F) >> 2; >> + ioread32_rep(info->nand_pref_fifo_add, p, r_count); >> + p += r_count; >> + len -= r_count << 2; >> + } while (len); >> + >> + /* disable and stop the PFPW engine */ >> + gpmc_prefetch_reset(); >> + } >> +} >> + >> +/** >> + * omap_write_buf_pref - write buffer to NAND controller >> + * @mtd: MTD device structure >> + * @buf: data buffer >> + * @len: number of bytes to write >> + */ >> +static void omap_write_buf_pref(struct mtd_info *mtd, >> + const u_char *buf, int len) >> +{ >> + struct omap_nand_info *info = container_of(mtd, >> + struct omap_nand_info, mtd); >> + uint32_t pfpw_status = 0, w_count = 0; >> + int i = 0, ret = 0; >> + u16 *p = (u16 *) buf; >> + >> + /* take care of subpage writes */ >> + if (len % 2 != 0) { >> + writeb(*buf, info->nand.IO_ADDR_R); >> + p = (u16 *)(buf + 1); >> + len--; >> + } >> + >> + /* configure and start prefetch transfer */ >> + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1); >> + if (ret) { >> + /* PFPW engine is busy, use cpu copy method */ >> + if (info->nand.options & NAND_BUSWIDTH_16) >> + omap_write_buf16(mtd, buf, len); >> + else >> + omap_write_buf8(mtd, buf, len); >> + } else { >> + pfpw_status = gpmc_prefetch_status(); >> + while (pfpw_status & 0x3FFF) { >> + w_count = ((pfpw_status >> 24) & 0x7F) >> 1; >> + for (i = 0; (i < w_count) && len; i++, len -= 2) >> + iowrite16(*p++, info->nand_pref_fifo_add); >> + pfpw_status = gpmc_prefetch_status(); >> + } >> + >> + /* disable and stop the PFPW engine */ >> + gpmc_prefetch_reset(); >> + } >> +} >> + >> /** >> * omap_verify_buf - Verify chip data against buffer >> * @mtd: MTD device structure >> @@ -658,17 +789,12 @@ static int __devinit omap_nand_probe(str >> err = -ENOMEM; >> goto out_release_mem_region; >> } >> + >> info->nand.controller = &info->controller; >> >> info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; >> info->nand.cmd_ctrl = omap_hwcontrol; >> >> - /* REVISIT: only supports 16-bit NAND flash */ >> - >> - info->nand.read_buf = omap_read_buf16; >> - info->nand.write_buf = omap_write_buf16; >> - info->nand.verify_buf = omap_verify_buf; >> - >> /* >> * If RDY/BSY line is connected to OMAP then use the omap ready >> * funcrtion and the generic nand_wait function which reads the status >> @@ -689,6 +815,23 @@ static int __devinit omap_nand_probe(str >> == 0x1000) >> info->nand.options |= NAND_BUSWIDTH_16; >> >> + if (use_prefetch) { >> + /* copy the virtual address of nand base for fifo access */ >> + info->nand_pref_fifo_add = info->nand.IO_ADDR_R; >> + >> + info->nand.read_buf = omap_read_buf_pref; >> + info->nand.write_buf = omap_write_buf_pref; >> + } else { >> + if (info->nand.options & NAND_BUSWIDTH_16) { >> + info->nand.read_buf = omap_read_buf16; >> + info->nand.write_buf = omap_write_buf16; >> + } else { >> + info->nand.read_buf = omap_read_buf8; >> + info->nand.write_buf = omap_write_buf8; >> + } >> + } >> + info->nand.verify_buf = omap_verify_buf; >> + >> #ifdef CONFIG_MTD_NAND_OMAP_HWECC >> info->nand.ecc.bytes = 3; >> info->nand.ecc.size = 512; >> @@ -746,7 +889,7 @@ static int omap_nand_remove(struct platf >> platform_set_drvdata(pdev, NULL); >> /* Release NAND device, its internal structures and partitions */ >> nand_release(&info->mtd); >> - iounmap(info->nand.IO_ADDR_R); >> + iounmap(info->nand_pref_fifo_add); >> kfree(&info->mtd); >> return 0; >> } >> >> > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >
On 08/11/2009 08:45 AM, vimal singh wrote: > On Mon, Aug 10, 2009 at 9:57 PM, Tony Lindgren<tony@atomide.com> wrote: >> * vimal singh<vimalsingh@ti.com> [090713 13:56]: >>> Patch updated for ' ioreadX / iowriteX and ioreadX_rep / iowriteX_rep' as per >>> David Brownell's comment. I updated 'omap_(read/write)_buf16' fucntions also >>> for this. >>> >>> -vimal >>> >>> This patch adds prefetch support to access nand flash in mpu mode. >>> This patch also adds 8-bit nand support (omap_read/write_buf8). >>> Prefetch can be used for both 8- and 16-bit devices. >>> >>> Signed-off-by: Vimal Singh<vimalsingh@ti.com> >> Sorry for the delay. I've looked at the GPMC part, and that now looks OK >> to me. So I'm OK for this to get integrated via the MTD list. >> >> Acked-by: Tony Lindgren<tony@atomide.com> >> > > Can you give your ack to below patch too? > > http://lists.infradead.org/pipermail/linux-mtd/2009-July/026373.html I've picked up both of your patches, please, check: http://git.infradead.org/users/dedekind/l2-mtd-2.6.git/commit/33f48f597315842f39427ee4261cbf82a9afeaf3 http://git.infradead.org/users/dedekind/l2-mtd-2.6.git/commit/b67d52c91b26e97f981f2c292619d31667d5b272
On Tue, Aug 11, 2009 at 11:51 AM, Artem Bityutskiy<dedekind1@gmail.com> wrote: > On 08/11/2009 08:45 AM, vimal singh wrote: >> >> On Mon, Aug 10, 2009 at 9:57 PM, Tony Lindgren<tony@atomide.com> wrote: >>> >>> * vimal singh<vimalsingh@ti.com> [090713 13:56]: >>>> >>>> Patch updated for ' ioreadX / iowriteX and ioreadX_rep / iowriteX_rep' >>>> as per >>>> David Brownell's comment. I updated 'omap_(read/write)_buf16' fucntions >>>> also >>>> for this. >>>> >>>> -vimal >>>> >>>> This patch adds prefetch support to access nand flash in mpu mode. >>>> This patch also adds 8-bit nand support (omap_read/write_buf8). >>>> Prefetch can be used for both 8- and 16-bit devices. >>>> >>>> Signed-off-by: Vimal Singh<vimalsingh@ti.com> >>> >>> Sorry for the delay. I've looked at the GPMC part, and that now looks OK >>> to me. So I'm OK for this to get integrated via the MTD list. >>> >>> Acked-by: Tony Lindgren<tony@atomide.com> >>> >> >> Can you give your ack to below patch too? >> >> http://lists.infradead.org/pipermail/linux-mtd/2009-July/026373.html > > I've picked up both of your patches, please, check: > http://git.infradead.org/users/dedekind/l2-mtd-2.6.git/commit/33f48f597315842f39427ee4261cbf82a9afeaf3 > http://git.infradead.org/users/dedekind/l2-mtd-2.6.git/commit/b67d52c91b26e97f981f2c292619d31667d5b272 > Thanks Artem. > -- > Best Regards, > Artem Bityutskiy (Артём Битюцкий) >
Hi David, On Tue, Aug 11, 2009 at 11:59 AM, vimal singh<vimal.newwork@gmail.com> wrote: > On Tue, Aug 11, 2009 at 11:51 AM, Artem Bityutskiy<dedekind1@gmail.com> wrote: >> On 08/11/2009 08:45 AM, vimal singh wrote: >>> >>> On Mon, Aug 10, 2009 at 9:57 PM, Tony Lindgren<tony@atomide.com> wrote: >>>> >>>> * vimal singh<vimalsingh@ti.com> [090713 13:56]: >>>>> >>>>> Patch updated for ' ioreadX / iowriteX and ioreadX_rep / iowriteX_rep' >>>>> as per >>>>> David Brownell's comment. I updated 'omap_(read/write)_buf16' fucntions >>>>> also >>>>> for this. >>>>> >>>>> -vimal >>>>> >>>>> This patch adds prefetch support to access nand flash in mpu mode. >>>>> This patch also adds 8-bit nand support (omap_read/write_buf8). >>>>> Prefetch can be used for both 8- and 16-bit devices. >>>>> >>>>> Signed-off-by: Vimal Singh<vimalsingh@ti.com> >>>> >>>> Sorry for the delay. I've looked at the GPMC part, and that now looks OK >>>> to me. So I'm OK for this to get integrated via the MTD list. >>>> >>>> Acked-by: Tony Lindgren<tony@atomide.com> >>>> >>> >>> Can you give your ack to below patch too? >>> >>> http://lists.infradead.org/pipermail/linux-mtd/2009-July/026373.html >> >> I've picked up both of your patches, please, check: >> http://git.infradead.org/users/dedekind/l2-mtd-2.6.git/commit/33f48f597315842f39427ee4261cbf82a9afeaf3 >> http://git.infradead.org/users/dedekind/l2-mtd-2.6.git/commit/b67d52c91b26e97f981f2c292619d31667d5b272 >> > Is there any chance for these patches to get merged in this merge window? These have been waiting for long time. -Vimal > Thanks Artem. > >> -- >> Best Regards, >> Artem Bityutskiy (Артём Битюцкий) >> >
Index: mtd-2.6/arch/arm/mach-omap2/gpmc.c =================================================================== --- mtd-2.6.orig/arch/arm/mach-omap2/gpmc.c +++ mtd-2.6/arch/arm/mach-omap2/gpmc.c @@ -57,6 +57,11 @@ #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ #define GPMC_SECTION_SHIFT 28 /* 128 MB */ +#define PREFETCH_FIFOTHRESHOLD (0x40 << 8) +#define CS_NUM_SHIFT 24 +#define ENABLE_PREFETCH (0x1 << 7) +#define DMA_MPU_MODE 2 + static struct resource gpmc_mem_root; static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); @@ -386,6 +391,63 @@ void gpmc_cs_free(int cs) } EXPORT_SYMBOL(gpmc_cs_free); +/** + * gpmc_prefetch_enable - configures and starts prefetch transfer + * @cs: nand cs (chip select) number + * @dma_mode: dma mode enable (1) or disable (0) + * @u32_count: number of bytes to be transferred + * @is_write: prefetch read(0) or write post(1) mode + */ +int gpmc_prefetch_enable(int cs, int dma_mode, + unsigned int u32_count, int is_write) +{ + uint32_t prefetch_config1; + + if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) { + /* Set the amount of bytes to be prefetched */ + gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count); + + /* Set dma/mpu mode, the prefetch read / post write and + * enable the engine. Set which cs is has requested for. + */ + prefetch_config1 = ((cs << CS_NUM_SHIFT) | + PREFETCH_FIFOTHRESHOLD | + ENABLE_PREFETCH | + (dma_mode << DMA_MPU_MODE) | + (0x1 & is_write)); + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1); + } else { + return -EBUSY; + } + /* Start the prefetch engine */ + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1); + + return 0; +} +EXPORT_SYMBOL(gpmc_prefetch_enable); + +/** + * gpmc_prefetch_reset - disables and stops the prefetch engine + */ +void gpmc_prefetch_reset(void) +{ + /* Stop the PFPW engine */ + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0); + + /* Reset/disable the PFPW engine */ + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0); +} +EXPORT_SYMBOL(gpmc_prefetch_reset); + +/** + * gpmc_prefetch_status - reads prefetch status of engine + */ +int gpmc_prefetch_status(void) +{ + return gpmc_read_reg(GPMC_PREFETCH_STATUS); +} +EXPORT_SYMBOL(gpmc_prefetch_status); + static void __init gpmc_mem_init(void) { int cs; @@ -452,6 +514,5 @@ void __init gpmc_init(void) l &= 0x03 << 3; l |= (0x02 << 3) | (1 << 0); gpmc_write_reg(GPMC_SYSCONFIG, l); - gpmc_mem_init(); } Index: mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h =================================================================== --- mtd-2.6.orig/arch/arm/plat-omap/include/mach/gpmc.h +++ mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h @@ -103,6 +103,10 @@ extern int gpmc_cs_request(int cs, unsig extern void gpmc_cs_free(int cs); extern int gpmc_cs_set_reserved(int cs, int reserved); extern int gpmc_cs_reserved(int cs); +extern int gpmc_prefetch_enable(int cs, int dma_mode, + unsigned int u32_count, int is_write); +extern void gpmc_prefetch_reset(void); +extern int gpmc_prefetch_status(void); extern void __init gpmc_init(void); #endif Index: mtd-2.6/drivers/mtd/nand/Kconfig =================================================================== --- mtd-2.6.orig/drivers/mtd/nand/Kconfig +++ mtd-2.6/drivers/mtd/nand/Kconfig @@ -80,6 +80,14 @@ config MTD_NAND_OMAP2 help Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. +config MTD_NAND_OMAP_PREFETCH + bool "GPMC prefetch support for NAND Flash device" + depends on MTD_NAND && MTD_NAND_OMAP2 + default y + help + The NAND device can be accessed for Read/Write using GPMC PREFETCH engine + to improve the performance. + config MTD_NAND_TS7250 tristate "NAND Flash device on TS-7250 board" depends on MACH_TS72XX Index: mtd-2.6/drivers/mtd/nand/omap2.c =================================================================== --- mtd-2.6.orig/drivers/mtd/nand/omap2.c +++ mtd-2.6/drivers/mtd/nand/omap2.c @@ -112,6 +112,16 @@ static const char *part_probes[] = { "cmdlinepart", NULL }; #endif +#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH +static int use_prefetch = 1; + +/* "modprobe ... use_prefetch=0" etc */ +module_param(use_prefetch, bool, 0); +MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH"); +#else +const int use_prefetch; +#endif + struct omap_nand_info { struct nand_hw_control controller; struct omap_nand_platform_data *pdata; @@ -124,6 +134,7 @@ struct omap_nand_info { unsigned long phys_base; void __iomem *gpmc_cs_baseaddr; void __iomem *gpmc_baseaddr; + void __iomem *nand_pref_fifo_add; }; /** @@ -189,6 +200,38 @@ static void omap_hwcontrol(struct mtd_in } /** + * omap_read_buf8 - read data from NAND controller into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *nand = mtd->priv; + + ioread8_rep(nand->IO_ADDR_R, buf, len); +} + +/** + * omap_write_buf8 - write buffer to NAND controller + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + u_char *p = (u_char *)buf; + + while (len--) { + iowrite8(*p++, info->nand.IO_ADDR_W); + while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + + GPMC_STATUS) & GPMC_BUF_FULL)); + } +} + +/** * omap_read_buf16 - read data from NAND controller into buffer * @mtd: MTD device structure * @buf: buffer to store date @@ -198,7 +241,7 @@ static void omap_read_buf16(struct mtd_i { struct nand_chip *nand = mtd->priv; - __raw_readsw(nand->IO_ADDR_R, buf, len / 2); + ioread16_rep(nand->IO_ADDR_R, buf, len / 2); } /** @@ -217,13 +260,101 @@ static void omap_write_buf16(struct mtd_ len >>= 1; while (len--) { - writew(*p++, info->nand.IO_ADDR_W); + iowrite16(*p++, info->nand.IO_ADDR_W); while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + GPMC_STATUS) & GPMC_BUF_FULL)) ; } } + +/** + * omap_read_buf_pref - read data from NAND controller into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + uint32_t pfpw_status = 0, r_count = 0; + int ret = 0; + u32 *p = (u32 *)buf; + + /* take care of subpage reads */ + for (; len % 4 != 0; ) { + *buf++ = __raw_readb(info->nand.IO_ADDR_R); + len--; + } + p = (u32 *) buf; + + /* configure and start prefetch transfer */ + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0); + if (ret) { + /* PFPW engine is busy, use cpu copy method */ + if (info->nand.options & NAND_BUSWIDTH_16) + omap_read_buf16(mtd, buf, len); + else + omap_read_buf8(mtd, buf, len); + } else { + do { + pfpw_status = gpmc_prefetch_status(); + r_count = ((pfpw_status >> 24) & 0x7F) >> 2; + ioread32_rep(info->nand_pref_fifo_add, p, r_count); + p += r_count; + len -= r_count << 2; + } while (len); + + /* disable and stop the PFPW engine */ + gpmc_prefetch_reset(); + } +} + +/** + * omap_write_buf_pref - write buffer to NAND controller + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void omap_write_buf_pref(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + uint32_t pfpw_status = 0, w_count = 0; + int i = 0, ret = 0; + u16 *p = (u16 *) buf; + + /* take care of subpage writes */ + if (len % 2 != 0) { + writeb(*buf, info->nand.IO_ADDR_R); + p = (u16 *)(buf + 1); + len--; + } + + /* configure and start prefetch transfer */ + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1); + if (ret) { + /* PFPW engine is busy, use cpu copy method */ + if (info->nand.options & NAND_BUSWIDTH_16) + omap_write_buf16(mtd, buf, len); + else + omap_write_buf8(mtd, buf, len); + } else { + pfpw_status = gpmc_prefetch_status(); + while (pfpw_status & 0x3FFF) { + w_count = ((pfpw_status >> 24) & 0x7F) >> 1; + for (i = 0; (i < w_count) && len; i++, len -= 2) + iowrite16(*p++, info->nand_pref_fifo_add); + pfpw_status = gpmc_prefetch_status(); + } + + /* disable and stop the PFPW engine */ + gpmc_prefetch_reset(); + } +} + /** * omap_verify_buf - Verify chip data against buffer * @mtd: MTD device structure @@ -658,17 +789,12 @@ static int __devinit omap_nand_probe(str err = -ENOMEM; goto out_release_mem_region; } + info->nand.controller = &info->controller; info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; info->nand.cmd_ctrl = omap_hwcontrol; - /* REVISIT: only supports 16-bit NAND flash */ - - info->nand.read_buf = omap_read_buf16; - info->nand.write_buf = omap_write_buf16; - info->nand.verify_buf = omap_verify_buf; - /* * If RDY/BSY line is connected to OMAP then use the omap ready * funcrtion and the generic nand_wait function which reads the status @@ -689,6 +815,23 @@ static int __devinit omap_nand_probe(str == 0x1000) info->nand.options |= NAND_BUSWIDTH_16; + if (use_prefetch) { + /* copy the virtual address of nand base for fifo access */ + info->nand_pref_fifo_add = info->nand.IO_ADDR_R; + + info->nand.read_buf = omap_read_buf_pref; + info->nand.write_buf = omap_write_buf_pref; + } else { + if (info->nand.options & NAND_BUSWIDTH_16) { + info->nand.read_buf = omap_read_buf16; + info->nand.write_buf = omap_write_buf16; + } else { + info->nand.read_buf = omap_read_buf8; + info->nand.write_buf = omap_write_buf8; + } + } + info->nand.verify_buf = omap_verify_buf; + #ifdef CONFIG_MTD_NAND_OMAP_HWECC info->nand.ecc.bytes = 3; info->nand.ecc.size = 512; @@ -746,7 +889,7 @@ static int omap_nand_remove(struct platf platform_set_drvdata(pdev, NULL); /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); - iounmap(info->nand.IO_ADDR_R); + iounmap(info->nand_pref_fifo_add); kfree(&info->mtd); return 0; }
Patch updated for ' ioreadX / iowriteX and ioreadX_rep / iowriteX_rep' as per David Brownell's comment. I updated 'omap_(read/write)_buf16' fucntions also for this. -vimal This patch adds prefetch support to access nand flash in mpu mode. This patch also adds 8-bit nand support (omap_read/write_buf8). Prefetch can be used for both 8- and 16-bit devices. Signed-off-by: Vimal Singh <vimalsingh@ti.com> --- --- arch/arm/mach-omap2/gpmc.c | 63 ++++++++++++ arch/arm/plat-omap/include/mach/gpmc.h | 4 drivers/mtd/nand/Kconfig | 8 + drivers/mtd/nand/omap2.c | 161 +++++++++++++++++++++++++++++++-- 4 files changed, 226 insertions(+), 10 deletions(-)