Re: [U-Boot] [PATCH v2 1/2] mtd: OMAP: Enable GPMC prefetch mode

2014-12-20 Thread Guido Martínez
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_SHIFT24
 +#define PREFETCH_FIFOTHRESHOLD_MAX   0x40
 +#define PREFETCH_FIFOTHRESHOLD(val)  ((val)  8)
 +#define PREFETCH_STATUS_COUNT(val)   (val  0x3fff)
 +#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, 

Re: [U-Boot] [PATCH v2 1/2] mtd: OMAP: Enable GPMC prefetch mode

2014-12-20 Thread Daniel Mack
Hi Guido,

thanks for your feedback!

On 12/19/2014 05:27 PM, Guido Martínez wrote:
 +/**
 + * 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.

That's great to hear. However, I'm not currently working on this
project, so I don't have a chance to respin the patch. In case any of
the maintainers is interested, I guess that's easy enough to tweak on
the fly when merging the patch :)


Thanks,
Daniel


___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


[U-Boot] [PATCH v2 1/2] mtd: OMAP: Enable GPMC prefetch mode

2014-06-25 Thread Daniel Mack
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
+   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  0x3fff)
+#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) |
+   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