|
@@ -441,6 +441,115 @@ 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
|
|
|
+ * @cs: chip select to use
|
|
|
+ */
|
|
|
+static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs)
|
|
|
+{
|
|
|
+ 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;
|
|
|
+ struct omap_nand_info *info = chip->priv;
|
|
|
+
|
|
|
+ ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs);
|
|
|
+ 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
|
|
@@ -880,11 +989,12 @@ 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
|
|
|
|
|
|
nand->dev_ready = omap_dev_ready;
|