From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755703AbZHJQ2M (ORCPT ); Mon, 10 Aug 2009 12:28:12 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755574AbZHJQ2K (ORCPT ); Mon, 10 Aug 2009 12:28:10 -0400 Received: from mho-01-ewr.mailhop.org ([204.13.248.71]:58236 "EHLO mho-01-ewr.mailhop.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755670AbZHJQ2I (ORCPT ); Mon, 10 Aug 2009 12:28:08 -0400 X-Mail-Handler: MailHop Outbound by DynDNS X-Originating-IP: 72.249.23.125 X-Report-Abuse-To: abuse@dyndns.com (see http://www.dyndns.com/services/mailhop/outbound_abuse.html for abuse reporting information) X-MHO-User: U2FsdGVkX1+ynrTwnfbg9AsUmbYEYH0Q Date: Mon, 10 Aug 2009 19:27:34 +0300 From: Tony Lindgren To: vimal singh Cc: linux-mtd@lists.infradead.org, dwmw2@infradead.org, dedekind@infradead.org, david-b@pacbell.net, linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org Subject: Re: [PATCH-v3 1:2] [MTD][NAND]omap: Adding support for nand prefetch-read and post-write, in MPU mode. Message-ID: <20090810162734.GH1938@atomide.com> References: <61339.192.168.10.89.1247226725.squirrel@dbdmail.itg.ti.com> <48097.192.168.10.89.1247232736.squirrel@dbdmail.itg.ti.com> <60361.192.168.10.89.1247482584.squirrel@dbdmail.itg.ti.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <60361.192.168.10.89.1247482584.squirrel@dbdmail.itg.ti.com> User-Agent: Mutt/1.5.18 (2008-05-17) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org * vimal singh [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 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 > --- > > --- > 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; > } > >