mtd: nand: denali: allow to override corrupted revision register
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Fri, 15 Sep 2017 12:43:19 +0000 (21:43 +0900)
committerMasahiro Yamada <yamada.masahiro@socionext.com>
Mon, 18 Sep 2017 11:26:00 +0000 (20:26 +0900)
The Denali IP does not update the revision register properly.
Allow to override it with SoC data associated with compatible.

Linux had already finished big surgery of this driver, but I need
to prepare the NAND core before the full sync of the driver.
For now, I am fixing the most fatal problem on UniPhier platform.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c

index 47cf37d1d9b7d2934d1c5e04a0aef0361758c907..54718f418c669f6bc50fe91385c7dee09f0d06be 100644 (file)
@@ -10,7 +10,7 @@
 #include <malloc.h>
 #include <nand.h>
 #include <linux/errno.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include "denali.h"
 
@@ -433,17 +433,13 @@ static void find_valid_banks(struct denali_nand_info *denali)
  */
 static void detect_max_banks(struct denali_nand_info *denali)
 {
-       uint32_t features = readl(denali->flash_reg + FEATURES);
-       /*
-        * Read the revision register, so we can calculate the max_banks
-        * properly: the encoding changed from rev 5.0 to 5.1
-        */
-       u32 revision = MAKE_COMPARABLE_REVISION(
-                               readl(denali->flash_reg + REVISION));
-       if (revision < REVISION_5_1)
-               denali->max_banks = 2 << (features & FEATURES__N_BANKS);
-       else
-               denali->max_banks = 1 << (features & FEATURES__N_BANKS);
+       uint32_t features = ioread32(denali->flash_reg + FEATURES);
+
+       denali->max_banks = 1 << (features & FEATURES__N_BANKS);
+
+       /* the encoding changed from rev 5.0 to 5.1 */
+       if (denali->revision < 0x0501)
+               denali->max_banks <<= 1;
 }
 
 static void detect_partition_feature(struct denali_nand_info *denali)
@@ -1153,6 +1149,13 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
 /* Initialization code to bring the device up to a known good state */
 static void denali_hw_init(struct denali_nand_info *denali)
 {
+       /*
+        * The REVISION register may not be reliable.  Platforms are allowed to
+        * override it.
+        */
+       if (!denali->revision)
+               denali->revision = swab16(ioread32(denali->flash_reg + REVISION));
+
        /*
         * tell driver how many bit controller will skip before writing
         * ECC code in OOB. This is normally used for bad block marker
index 694bce53a955f272891a81b43e5cec3f8f394c50..08db48843da357ee1ef0412e7a9e5a200b70c4c8 100644 (file)
 
 #define REVISION                               0x370
 #define     REVISION__VALUE                            0xffff
-#define MAKE_COMPARABLE_REVISION(x)            swab16((x) & REVISION__VALUE)
-#define REVISION_5_1                           0x00000501
 
 #define ONFI_DEVICE_FEATURES                   0x380
 #define     ONFI_DEVICE_FEATURES__VALUE                        0x003f
@@ -462,8 +460,13 @@ struct denali_nand_info {
        uint32_t blksperchip;
        uint32_t bbtskipbytes;
        uint32_t max_banks;
+       unsigned int revision;
+       unsigned int caps;
 };
 
+#define DENALI_CAP_HW_ECC_FIXUP                        BIT(0)
+#define DENALI_CAP_DMA_64BIT                   BIT(1)
+
 int denali_init(struct denali_nand_info *denali);
 
 #endif /* __DENALI_H__ */
index 0a6155c748c493f80e677289f2434bb8182bdf35..4afd679a04b2c9eeb559d3e22ed65b09513979ec 100644 (file)
 
 #include "denali.h"
 
+struct denali_dt_data {
+       unsigned int revision;
+       unsigned int caps;
+};
+
+static const struct denali_dt_data denali_socfpga_data = {
+       .caps = DENALI_CAP_HW_ECC_FIXUP,
+};
+
+static const struct denali_dt_data denali_uniphier_v5a_data = {
+       .caps = DENALI_CAP_HW_ECC_FIXUP |
+               DENALI_CAP_DMA_64BIT,
+};
+
+static const struct denali_dt_data denali_uniphier_v5b_data = {
+       .revision = 0x0501,
+       .caps = DENALI_CAP_HW_ECC_FIXUP |
+               DENALI_CAP_DMA_64BIT,
+};
+
 static const struct udevice_id denali_nand_dt_ids[] = {
        {
                .compatible = "altr,socfpga-denali-nand",
+               .data = (unsigned long)&denali_socfpga_data,
        },
        {
                .compatible = "socionext,uniphier-denali-nand-v5a",
+               .data = (unsigned long)&denali_uniphier_v5a_data,
        },
        {
                .compatible = "socionext,uniphier-denali-nand-v5b",
+               .data = (unsigned long)&denali_uniphier_v5b_data,
        },
        { /* sentinel */ }
 };
@@ -28,9 +51,16 @@ static const struct udevice_id denali_nand_dt_ids[] = {
 static int denali_dt_probe(struct udevice *dev)
 {
        struct denali_nand_info *denali = dev_get_priv(dev);
+       const struct denali_dt_data *data;
        struct resource res;
        int ret;
 
+       data = (void *)dev_get_driver_data(dev);
+       if (data) {
+               denali->revision = data->revision;
+               denali->caps = data->caps;
+       }
+
        ret = dev_read_resource_byname(dev, "denali_reg", &res);
        if (ret)
                return ret;