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