mtd: physmap_of: add a hook for Gemini flash probing
authorLinus Walleij <linus.walleij@linaro.org>
Sat, 28 Jan 2017 21:50:48 +0000 (22:50 +0100)
committerBrian Norris <computersforpeace@gmail.com>
Wed, 8 Feb 2017 21:01:00 +0000 (13:01 -0800)
In order to support device tree probing of Gemini NOR flash
chips, a certain register in the syscon needs to be poked
to enable parallel flash mode.

Such things used to happen in "necessarily different" board
file code, and this indeed was also done for the Gemini, so
the MTD driver could treat it as any memory-mapped NOR flash,
but this is not the way in the future: board files need to
go, and hardware concerns distributed down to the applicable
drivers.

This adds a hook in the same way that the Versatile did: if
the Kconfig symbol is not selected the net total of supporting
Gemini should be zero bytes of added code. To live up to this
promise, also the return value error print from the Versatile
extra probe call get to be removed in this patch, all printing
need to happen in the add-ons.

Cc: Janos Laube <janos.dev@gmail.com>
Cc: Paulius Zaleckas <paulius.zaleckas@gmail.com>
Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Marek Vasut <marek.vasut@gmail.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/physmap_of_gemini.c [new file with mode: 0644]
drivers/mtd/maps/physmap_of_gemini.h [new file with mode: 0644]

index 5bcc896a48c3372ad192ae403f49268eb8f49c44..542fdf8e81faf7a7152b5cb8312ed4721645a86d 100644 (file)
@@ -75,7 +75,7 @@ config MTD_PHYSMAP_OF
          taken from OF device tree.
 
 config MTD_PHYSMAP_OF_VERSATILE
-       bool "Support ARM Versatile physmap OF"
+       bool "ARM Versatile OF-based physical memory map handling"
        depends on MTD_PHYSMAP_OF
        depends on MFD_SYSCON
        default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || ARCH_REALVIEW)
@@ -84,6 +84,16 @@ config MTD_PHYSMAP_OF_VERSATILE
          platforms, basically to add a VPP (write protection) callback so
          the flash can be taken out of write protection.
 
+config MTD_PHYSMAP_OF_GEMINI
+       bool "Cortina Gemini OF-based physical memory map handling"
+       depends on MTD_PHYSMAP_OF
+       depends on MFD_SYSCON
+       default ARCH_GEMINI
+       help
+         This provides some extra DT physmap parsing for the Gemini
+         platforms, some detection and setting up parallel mode on the
+         external interface.
+
 config MTD_PMC_MSP_EVM
        tristate "CFI Flash device mapped on PMC-Sierra MSP"
        depends on PMC_MSP && MTD_CFI
index 644f7d36d35dc942b83cb151ad11c3aea6eabc53..2fec1e0c2371939d09fe966214925c435ec72bfa 100644 (file)
@@ -18,9 +18,8 @@ obj-$(CONFIG_MTD_TSUNAMI)     += tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)       += pxa2xx-flash.o
 obj-$(CONFIG_MTD_PHYSMAP)      += physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
-ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE
-obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of_versatile.o
-endif
+obj-$(CONFIG_MTD_PHYSMAP_OF_VERSATILE) += physmap_of_versatile.o
+obj-$(CONFIG_MTD_PHYSMAP_OF_GEMINI)    += physmap_of_gemini.o
 obj-$(CONFIG_MTD_PISMO)                += pismo.o
 obj-$(CONFIG_MTD_PMC_MSP_EVM)   += pmcmsp-flash.o
 obj-$(CONFIG_MTD_PCMCIA)       += pcmciamtd.o
index 3fad35942895c0186dfa08d22ab655fc0a4ed37f..14e8909c99555bb89a84f5c7671b3985b315c883 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
+#include "physmap_of_gemini.h"
 #include "physmap_of_versatile.h"
 
 struct of_flash_list {
@@ -241,11 +242,13 @@ static int of_flash_probe(struct platform_device *dev)
                info->list[i].map.size = res_size;
                info->list[i].map.bankwidth = be32_to_cpup(width);
                info->list[i].map.device_node = dp;
+
+               err = of_flash_probe_gemini(dev, dp, &info->list[i].map);
+               if (err)
+                       return err;
                err = of_flash_probe_versatile(dev, dp, &info->list[i].map);
-               if (err) {
-                       dev_err(&dev->dev, "Can't probe Versatile VPP\n");
+               if (err)
                        return err;
-               }
 
                err = -ENOMEM;
                info->list[i].map.virt = ioremap(info->list[i].map.phys,
diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c
new file mode 100644 (file)
index 0000000..e99db77
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Cortina Systems Gemini OF physmap add-on
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This SoC has an elaborate flash control register, so we need to
+ * detect and set it up when booting on this platform.
+ */
+#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/mtd/map.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include "physmap_of_gemini.h"
+
+/*
+ * The Flash-relevant parts of the global status register
+ * These would also be relevant for a NAND driver.
+ */
+#define GLOBAL_STATUS                  0x04
+#define FLASH_TYPE_MASK                        (0x3 << 24)
+#define FLASH_TYPE_NAND_2K             (0x3 << 24)
+#define FLASH_TYPE_NAND_512            (0x2 << 24)
+#define FLASH_TYPE_PARALLEL            (0x1 << 24)
+#define FLASH_TYPE_SERIAL              (0x0 << 24)
+/* if parallel */
+#define FLASH_WIDTH_16BIT              (1 << 23)       /* else 8 bit */
+/* if serial */
+#define FLASH_ATMEL                    (1 << 23)       /* else STM */
+
+#define FLASH_SIZE_MASK                        (0x3 << 21)
+#define NAND_256M                      (0x3 << 21)     /* and more */
+#define NAND_128M                      (0x2 << 21)
+#define NAND_64M                       (0x1 << 21)
+#define NAND_32M                       (0x0 << 21)
+#define ATMEL_16M                      (0x3 << 21)     /* and more */
+#define ATMEL_8M                       (0x2 << 21)
+#define ATMEL_4M_2M                    (0x1 << 21)
+#define ATMEL_1M                       (0x0 << 21)     /* and less */
+#define STM_32M                                (1 << 22)       /* and more */
+#define STM_16M                                (0 << 22)       /* and less */
+
+#define FLASH_PARALLEL_HIGH_PIN_CNT    (1 << 20)       /* else low pin cnt */
+
+/* Miscellaneous Control Register */
+#define GLOBAL_MISC_CTRL               0x30
+#define FLASH_PADS_MASK                        0x07
+#define NAND_PADS_DISABLE              BIT(2)
+#define PFLASH_PADS_DISABLE            BIT(1)
+#define SFLASH_PADS_DISABLE            BIT(0)
+
+static const struct of_device_id syscon_match[] = {
+       { .compatible = "cortina,gemini-syscon" },
+       { },
+};
+
+int of_flash_probe_gemini(struct platform_device *pdev,
+                         struct device_node *np,
+                         struct map_info *map)
+{
+       static struct regmap *rmap;
+       struct device *dev = &pdev->dev;
+       u32 val;
+       int ret;
+
+       /* Multiplatform guard */
+       if (!of_device_is_compatible(np, "cortina,gemini-flash"))
+               return 0;
+
+       rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
+       if (IS_ERR(rmap)) {
+               dev_err(dev, "no syscon\n");
+               return PTR_ERR(rmap);
+       }
+
+       ret = regmap_read(rmap, GLOBAL_STATUS, &val);
+       if (ret) {
+               dev_err(dev, "failed to read global status register\n");
+               return -ENODEV;
+       }
+       dev_dbg(dev, "global status reg: %08x\n", val);
+
+       /*
+        * It would be contradictory if a physmap flash was NOT parallel.
+        */
+       if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) {
+               dev_err(dev, "flash is not parallel\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Complain if DT data and hardware definition is different.
+        */
+       if (val & FLASH_WIDTH_16BIT) {
+               if (map->bankwidth != 2)
+                       dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n",
+                                map->bankwidth * 8);
+       } else {
+               if (map->bankwidth != 1)
+                       dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n",
+                                map->bankwidth * 8);
+       }
+
+       /* Activate parallel (NOR flash) mode */
+       ret = regmap_update_bits(rmap, GLOBAL_MISC_CTRL,
+                                FLASH_PADS_MASK,
+                                SFLASH_PADS_DISABLE | NAND_PADS_DISABLE);
+       if (ret) {
+               dev_err(dev, "unable to set up physmap pads\n");
+               return -ENODEV;
+       }
+
+       dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_flash_probe_gemini);
diff --git a/drivers/mtd/maps/physmap_of_gemini.h b/drivers/mtd/maps/physmap_of_gemini.h
new file mode 100644 (file)
index 0000000..c675025
--- /dev/null
@@ -0,0 +1,16 @@
+#include <linux/of.h>
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI
+int of_flash_probe_gemini(struct platform_device *pdev,
+                         struct device_node *np,
+                         struct map_info *map);
+#else
+static inline
+int of_flash_probe_gemini(struct platform_device *pdev,
+                         struct device_node *np,
+                         struct map_info *map)
+{
+       return 0;
+}
+#endif