mtd: brcmnand: iProc big endian and ONFI support
authorRay Jui <ray.jui@broadcom.com>
Wed, 20 Jul 2016 21:53:50 +0000 (14:53 -0700)
committerBoris Brezillon <boris.brezillon@free-electrons.com>
Fri, 23 Sep 2016 07:35:16 +0000 (09:35 +0200)
This patch adds big endian and ONFI support for various iProc based
SoCs that use the core brcmstb NAND controller

This patch was originally implemented by Prafulla Kota
<prafulla.kota@broadcom.com> and fully tested on iProc based NS2 SVK

Signed-off-by: Prafulla Kota <prafulla.kota@broadcom.com>
Signed-off-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Kamal Dasu <kdasu.kdev@gmail.com>
Acked-by: Kamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/brcmnand/brcmnand.h
drivers/mtd/nand/brcmnand/iproc_nand.c

index 82ec36b..9d2424b 100644 (file)
@@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
                u32 *flash_cache = (u32 *)ctrl->flash_cache;
                int i;
 
-               brcmnand_soc_data_bus_prepare(ctrl->soc);
+               brcmnand_soc_data_bus_prepare(ctrl->soc, true);
 
                /*
                 * Must cache the FLASH_CACHE now, since changes in
@@ -1349,7 +1349,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
                         */
                        flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
 
-               brcmnand_soc_data_bus_unprepare(ctrl->soc);
+               brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
 
                /* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
                if (host->hwcfg.sector_size_1k)
@@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
                brcmnand_waitfunc(mtd, chip);
 
                if (likely(buf)) {
-                       brcmnand_soc_data_bus_prepare(ctrl->soc);
+                       brcmnand_soc_data_bus_prepare(ctrl->soc, false);
 
                        for (j = 0; j < FC_WORDS; j++, buf++)
                                *buf = brcmnand_read_fc(ctrl, j);
 
-                       brcmnand_soc_data_bus_unprepare(ctrl->soc);
+                       brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
                }
 
                if (oob)
@@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
                (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
 
                if (buf) {
-                       brcmnand_soc_data_bus_prepare(ctrl->soc);
+                       brcmnand_soc_data_bus_prepare(ctrl->soc, false);
 
                        for (j = 0; j < FC_WORDS; j++, buf++)
                                brcmnand_write_fc(ctrl, j, *buf);
 
-                       brcmnand_soc_data_bus_unprepare(ctrl->soc);
+                       brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
                } else if (oob) {
                        for (j = 0; j < FC_WORDS; j++)
                                brcmnand_write_fc(ctrl, j, 0xffffffff);
index ef5eabb..5c44cd4 100644 (file)
@@ -23,19 +23,22 @@ struct dev_pm_ops;
 struct brcmnand_soc {
        bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
        void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
-       void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
+       void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
+                                bool is_param);
 };
 
-static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc)
+static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
+                                                bool is_param)
 {
        if (soc && soc->prepare_data_bus)
-               soc->prepare_data_bus(soc, true);
+               soc->prepare_data_bus(soc, true, is_param);
 }
 
-static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc)
+static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
+                                                  bool is_param)
 {
        if (soc && soc->prepare_data_bus)
-               soc->prepare_data_bus(soc, false);
+               soc->prepare_data_bus(soc, false, is_param);
 }
 
 static inline u32 brcmnand_readl(void __iomem *addr)
index 585596c..4c6ae11 100644 (file)
@@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
        spin_unlock_irqrestore(&priv->idm_lock, flags);
 }
 
-static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
+static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
+                                 bool is_param)
 {
        struct iproc_nand_soc *priv =
                        container_of(soc, struct iproc_nand_soc, soc);
@@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
 
        val = brcmnand_readl(mmio);
 
-       if (prepare)
-               val |= IPROC_NAND_APB_LE_MODE;
-       else
+       /*
+        * In the case of BE or when dealing with NAND data, alway configure
+        * the APB bus to LE mode before accessing the FIFO and back to BE mode
+        * after the access is done
+        */
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
+               if (prepare)
+                       val |= IPROC_NAND_APB_LE_MODE;
+               else
+                       val &= ~IPROC_NAND_APB_LE_MODE;
+       } else { /* when in LE accessing the parameter page, keep APB in BE */
                val &= ~IPROC_NAND_APB_LE_MODE;
+       }
 
        brcmnand_writel(val, mmio);