From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753391AbZHKNM0 (ORCPT ); Tue, 11 Aug 2009 09:12:26 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752336AbZHKNMZ (ORCPT ); Tue, 11 Aug 2009 09:12:25 -0400 Received: from qw-out-2122.google.com ([74.125.92.25]:1070 "EHLO qw-out-2122.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752368AbZHKNMY convert rfc822-to-8bit (ORCPT ); Tue, 11 Aug 2009 09:12:24 -0400 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type:content-transfer-encoding; b=K9ElpIYSoweg7mputwD28TuUcJesp/JvCnhmVVPSNevvz2F1LmUH24CUEt6rFyfWoL PLLP4M6PR0wKrwatTf1eEAdoeGYHQPm1A1vXavQHpL8CzChuGh/wTztc25ygtG7L1gAg fLbhjTq2k2Boa5dkdak39/2bRTH23fM6F1zgU= MIME-Version: 1.0 In-Reply-To: <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> <20090810162734.GH1938@atomide.com> From: vimal singh Date: Tue, 11 Aug 2009 11:15:45 +0530 Message-ID: Subject: Re: [PATCH-v3 1:2] [MTD][NAND]omap: Adding support for nand prefetch-read and post-write, in MPU mode. To: Tony Lindgren Cc: vimal singh , 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 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, Aug 10, 2009 at 9:57 PM, Tony Lindgren wrote: > * 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 > 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 > -- --- Regards, \/ | |\/| /-\ |_ ____ __o ------ -\<, ----- ( )/ ( )