]> git.sur5r.net Git - u-boot/blobdiff - drivers/mtd/nand/omap_gpmc.c
powerpc: ppc4xx: remove PPChameleonEVB, CATcenter boards
[u-boot] / drivers / mtd / nand / omap_gpmc.c
index db1599e9a641402e811c9e6172e35909098a0769..fc64f4814484e8052410f4769c60240ae67dc510 100644 (file)
@@ -73,14 +73,11 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
                writeb(cmd, this->IO_ADDR_W);
 }
 
-#ifdef CONFIG_SPL_BUILD
 /* Check wait pin as dev ready indicator */
-int omap_spl_dev_ready(struct mtd_info *mtd)
+static int omap_dev_ready(struct mtd_info *mtd)
 {
        return gpmc_cfg->status & (1 << 8);
 }
-#endif
-
 
 /*
  * gen_true_ecc - This function will generate true ECC value, which
@@ -161,23 +158,6 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
        return 0;
 }
 
-/*
- * omap_reverse_list - re-orders list elements in reverse order [internal]
- * @list:      pointer to start of list
- * @length:    length of list
-*/
-void omap_reverse_list(u8 *list, unsigned int length)
-{
-       unsigned int i, j;
-       unsigned int half_length = length / 2;
-       u8 tmp;
-       for (i = 0, j = length - 1; i < half_length; i++, j--) {
-               tmp = list[i];
-               list[i] = list[j];
-               list[j] = tmp;
-       }
-}
-
 /*
  * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
  * @mtd:       MTD device structure
@@ -350,6 +330,23 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
 }
 
 #ifdef CONFIG_NAND_OMAP_ELM
+/*
+ * omap_reverse_list - re-orders list elements in reverse order [internal]
+ * @list:      pointer to start of list
+ * @length:    length of list
+*/
+static void omap_reverse_list(u8 *list, unsigned int length)
+{
+       unsigned int i, j;
+       unsigned int half_length = length / 2;
+       u8 tmp;
+       for (i = 0, j = length - 1; i < half_length; i++, j--) {
+               tmp = list[i];
+               list[i] = list[j];
+               list[j] = tmp;
+       }
+}
+
 /*
  * omap_correct_data_bch - Compares the ecc read from nand spare area
  * with ECC registers values and corrects one bit error if it has occured
@@ -371,8 +368,9 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
        uint32_t error_loc[ELM_MAX_ERROR_COUNT];
        enum bch_level bch_type;
        uint32_t i, ecc_flag = 0;
-       uint8_t count, err = 0;
+       uint8_t count;
        uint32_t byte_pos, bit_pos;
+       int err = 0;
 
        /* check calculated ecc */
        for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
@@ -443,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
@@ -882,12 +989,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->dev_ready = omap_spl_dev_ready;
+               nand->read_buf = omap_nand_read_prefetch8;
 #endif
+
+       nand->dev_ready = omap_dev_ready;
+
        return 0;
 }