Hi Daniel,

While trying to enable GPMC prefetch myself I ran into your patch and
tested it. Here's some comments.

On Wed, Jun 25, 2014 at 02:43:32PM +0200, Daniel Mack wrote:
> Enable GPMC's prefetch feature for NAND access. This speeds up NAND read
> access a lot by pre-fetching contents in the background and reading them
> through the FIFO address.
> 
> The current implementation has two limitations:
> 
>  a) it only works in 8-bit mode
>  b) it only supports read access
> 
> Both is easily fixable by someone who has hardware to implement it.
> 
> Note that U-Boot code uses non word-aligned buffers to read data into, and
> request read lengths that are not multiples of 4, so both partial buffers
> (head and tail) have to be addressed.
> 
> Tested on AM335x hardware.
> 
> Signed-off-by: Daniel Mack <zon...@gmail.com>
> ---
>  doc/README.nand               |   5 ++
>  drivers/mtd/nand/omap_gpmc.c  | 115 
> +++++++++++++++++++++++++++++++++++++++++-
>  include/linux/mtd/omap_gpmc.h |   6 ++-
>  3 files changed, 123 insertions(+), 3 deletions(-)
> 
> diff --git a/doc/README.nand b/doc/README.nand
> index 70cf768..6459f2a 100644
> --- a/doc/README.nand
> +++ b/doc/README.nand
> @@ -292,6 +292,11 @@ Platform specific options
>               Thus BCH16 can be supported on 4K page NAND.
>  
>  
> +    CONFIG_NAND_OMAP_PREFETCH
This doesn't match the actual config in omap_gpmc.c

> +     On OMAP platforms that use the GPMC controller (CONFIG_NAND_OMAP_GPMC),
> +     this options enables the code that uses the prefetch mode to speed up
> +     read operations.
> +
>  NOTE:
>  =====
>  
> diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
> index 1acf06b..e2d57bd 100644
> --- a/drivers/mtd/nand/omap_gpmc.c
> +++ b/drivers/mtd/nand/omap_gpmc.c
> @@ -446,6 +446,113 @@ static int omap_correct_data_bch(struct mtd_info *mtd, 
> uint8_t *dat,
>       return (err) ? err : error_count;
>  }
>  
> +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
> +
> +#define PREFETCH_CONFIG1_CS_SHIFT    24
> +#define PREFETCH_FIFOTHRESHOLD_MAX   0x40
> +#define PREFETCH_FIFOTHRESHOLD(val)  ((val) << 8)
> +#define PREFETCH_STATUS_COUNT(val)   (val & 0x00003fff)
> +#define PREFETCH_STATUS_FIFO_CNT(val)        ((val >> 24) & 0x7F)
> +#define ENABLE_PREFETCH                      (1 << 7)
> +
> +/**
> + * omap_prefetch_enable - configures and starts prefetch transfer
> + * @fifo_th: fifo threshold to be used for read/ write
> + * @count: number of bytes to be transferred
> + * @is_write: prefetch read(0) or write post(1) mode
> + */
> +static int omap_prefetch_enable(int fifo_th, unsigned int count, int 
> is_write)
> +{
> +     uint32_t val;
> +
> +     if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
> +             return -EINVAL;
> +
> +     if (readl(&gpmc_cfg->prefetch_control))
> +             return -EBUSY;
> +
> +     /* Set the amount of bytes to be prefetched */
> +     writel(count, &gpmc_cfg->prefetch_config2);
> +
> +     val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) |
On a current U-boot "cs" doesn't exist. I think you might want to pass a
"struct omap_nand_info *" and use info->cs.

I fixed this last bit, and tested it. It results in 2.5x speed
improvements on a Micron NAND. So, thanks :) !

If you resend, you have my Reviewed-by and Tested-by.

> +             PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH;
> +     writel(val, &gpmc_cfg->prefetch_config1);
> +
> +     /*  Start the prefetch engine */
> +     writel(1, &gpmc_cfg->prefetch_control);
> +
> +     return 0;
> +}
> +
> +/**
> + * omap_prefetch_reset - disables and stops the prefetch engine
> + */
> +static void omap_prefetch_reset(void)
> +{
> +     writel(0, &gpmc_cfg->prefetch_control);
> +     writel(0, &gpmc_cfg->prefetch_config1);
> +}
> +
> +static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, 
> int len)
> +{
> +     int ret;
> +     uint32_t cnt;
> +
> +     ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0);
> +     if (ret < 0)
> +             return ret;
> +
> +     do {
> +             int i;
> +
> +             cnt = readl(&gpmc_cfg->prefetch_status);
> +             cnt = PREFETCH_STATUS_FIFO_CNT(cnt);
> +
> +             for (i = 0; i < cnt / 4; i++) {
> +                     *buf++ = readl(CONFIG_SYS_NAND_BASE);
> +                     len -= 4;
> +             }
> +     } while (len);
> +
> +     omap_prefetch_reset();
> +
> +     return 0;
> +}
> +
> +static void omap_nand_read_prefetch8(struct mtd_info *mtd, uint8_t *buf, int 
> len)
> +{
> +     int ret;
> +     uint32_t head, tail;
> +     struct nand_chip *chip = mtd->priv;
> +
> +     /*
> +      * If the destination buffer is unaligned, start with reading
> +      * the overlap byte-wise.
> +      */
> +     head = ((uint32_t) buf) % 4;
> +     if (head) {
> +             nand_read_buf(mtd, buf, head);
> +             buf += head;
> +             len -= head;
> +     }
> +
> +     /*
> +      * Only transfer multiples of 4 bytes in a pre-fetched fashion.
> +      * If there's a residue, care for it byte-wise afterwards.
> +      */
> +     tail = len % 4;
> +
> +     ret = __read_prefetch_aligned(chip, (uint32_t *) buf, len - tail);
> +     if (ret < 0) {
> +             /* fallback in case the prefetch engine is busy */
> +             nand_read_buf(mtd, buf, len);
> +     } else if (tail) {
> +             buf += len - tail;
> +             nand_read_buf(mtd, buf, tail);
> +     }
> +}
> +#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */
> +
>  /**
>   * omap_read_page_bch - hardware ecc based page read function
>   * @mtd:     mtd info structure
> @@ -883,11 +990,15 @@ int board_nand_init(struct nand_chip *nand)
>       if (err)
>               return err;
>  
> -#ifdef CONFIG_SPL_BUILD
> +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
> +     /* TODO: Implement for 16-bit bus width */
>       if (nand->options & NAND_BUSWIDTH_16)
>               nand->read_buf = nand_read_buf16;
>       else
> -             nand->read_buf = nand_read_buf;
> +             nand->read_buf = omap_nand_read_prefetch8;
> +#endif
> +
> +#ifdef CONFIG_SPL_BUILD
>       nand->dev_ready = omap_spl_dev_ready;
>  #endif
>  
> diff --git a/include/linux/mtd/omap_gpmc.h b/include/linux/mtd/omap_gpmc.h
> index 9a86582..6cbae45 100644
> --- a/include/linux/mtd/omap_gpmc.h
> +++ b/include/linux/mtd/omap_gpmc.h
> @@ -66,7 +66,11 @@ struct gpmc {
>       u32 status;             /* 0x54 */
>       u8 res5[0x8];           /* 0x58 */
>       struct gpmc_cs cs[8];   /* 0x60, 0x90, .. */
> -     u8 res6[0x14];          /* 0x1E0 */
> +     u32 prefetch_config1;   /* 0x1E0 */
> +     u32 prefetch_config2;   /* 0x1E4 */
> +     u32 res6;               /* 0x1E8 */
> +     u32 prefetch_control;   /* 0x1EC */
> +     u32 prefetch_status;    /* 0x1F0 */
>       u32 ecc_config;         /* 0x1F4 */
>       u32 ecc_control;        /* 0x1F8 */
>       u32 ecc_size_config;    /* 0x1FC */

-- 
Guido Martínez, VanguardiaSur
www.vanguardiasur.com.ar
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to