aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/gemini/patches-4.19/0006-mtd-physmap_of_gemini-Handle-pin-control.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/gemini/patches-4.19/0006-mtd-physmap_of_gemini-Handle-pin-control.patch')
-rw-r--r--target/linux/gemini/patches-4.19/0006-mtd-physmap_of_gemini-Handle-pin-control.patch194
1 files changed, 194 insertions, 0 deletions
diff --git a/target/linux/gemini/patches-4.19/0006-mtd-physmap_of_gemini-Handle-pin-control.patch b/target/linux/gemini/patches-4.19/0006-mtd-physmap_of_gemini-Handle-pin-control.patch
new file mode 100644
index 0000000000..47aa38a6ab
--- /dev/null
+++ b/target/linux/gemini/patches-4.19/0006-mtd-physmap_of_gemini-Handle-pin-control.patch
@@ -0,0 +1,194 @@
+From 8e5e628a9de439d02914b85a48e1ac3e04ea486a Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Thu, 11 Oct 2018 20:03:49 +0200
+Subject: [PATCH 06/18] mtd: physmap_of_gemini: Handle pin control
+
+This enables the complex mapping for the Gemini and kicks in
+custom read/write functions that will wrap the existing
+simple functions in calls to enable/disable the parallel
+flash pins using pin controls.
+
+This is necessary on some hardware such as the D-Link
+DIR-685 where all flash pins are patched in/out at the same
+time, but some of the flash pins are in practice unused by
+the flash and have anyway been reused as GPIO.
+
+This concerns specifically CE1 on the Gemini. There is only
+one flash chip, so only CE0 is used, and the line for CE1
+has been reused as chip select for the emulated SPI port
+connected to the display. If we try to use the same lines
+for flash and GPIO at the same time, one of them will loose:
+the GPIO line will disappear because it gets disconnected
+from the pin when the flash group is muxed out.
+
+Fix this by introducing two pin control states named simply
+"enabled" and "disabled" and only enable the flash lines
+when absolutely necessary (during read/write/copy). This
+way, they are available for GPIO at all other times and
+the display works.
+
+Collect all the state variables in a struct named
+struct gemini_flash and allocate this struct at probe
+time.
+
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/mtd/maps/Kconfig | 1 +
+ drivers/mtd/maps/physmap_of_gemini.c | 105 ++++++++++++++++++++++++++-
+ 2 files changed, 105 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
+index afb36bff13a7..00efbf246849 100644
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -89,6 +89,7 @@ config MTD_PHYSMAP_OF_GEMINI
+ depends on MTD_PHYSMAP_OF
+ depends on MFD_SYSCON
+ default ARCH_GEMINI
++ select MTD_COMPLEX_MAPPINGS
+ help
+ This provides some extra DT physmap parsing for the Gemini
+ platforms, some detection and setting up parallel mode on the
+diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c
+index 830b1b7e702b..7c2b67460192 100644
+--- a/drivers/mtd/maps/physmap_of_gemini.c
++++ b/drivers/mtd/maps/physmap_of_gemini.c
+@@ -10,9 +10,11 @@
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/mtd/map.h>
++#include <linux/mtd/xip.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/regmap.h>
+ #include <linux/bitops.h>
++#include <linux/pinctrl/consumer.h>
+ #include "physmap_of_gemini.h"
+
+ /*
+@@ -49,6 +51,77 @@ static const struct of_device_id syscon_match[] = {
+ { },
+ };
+
++struct gemini_flash {
++ struct device *dev;
++ struct pinctrl *p;
++ struct pinctrl_state *enabled_state;
++ struct pinctrl_state *disabled_state;
++};
++
++/* Static local state */
++static struct gemini_flash *gf;
++
++static void gemini_flash_enable_pins(void)
++{
++ int ret;
++
++ if (IS_ERR(gf->enabled_state))
++ return;
++ ret = pinctrl_select_state(gf->p, gf->enabled_state);
++ if (ret)
++ dev_err(gf->dev, "failed to enable pins\n");
++}
++
++static void gemini_flash_disable_pins(void)
++{
++ int ret;
++
++ if (IS_ERR(gf->disabled_state))
++ return;
++ ret = pinctrl_select_state(gf->p, gf->disabled_state);
++ if (ret)
++ dev_err(gf->dev, "failed to disable pins\n");
++}
++
++static map_word __xipram gemini_flash_map_read(struct map_info *map,
++ unsigned long ofs)
++{
++ map_word __xipram ret;
++
++ gemini_flash_enable_pins();
++ ret = inline_map_read(map, ofs);
++ gemini_flash_disable_pins();
++
++ return ret;
++}
++
++static void __xipram gemini_flash_map_write(struct map_info *map,
++ const map_word datum,
++ unsigned long ofs)
++{
++ gemini_flash_enable_pins();
++ inline_map_write(map, datum, ofs);
++ gemini_flash_disable_pins();
++}
++
++static void __xipram gemini_flash_map_copy_from(struct map_info *map,
++ void *to, unsigned long from,
++ ssize_t len)
++{
++ gemini_flash_enable_pins();
++ inline_map_copy_from(map, to, from, len);
++ gemini_flash_disable_pins();
++}
++
++static void __xipram gemini_flash_map_copy_to(struct map_info *map,
++ unsigned long to,
++ const void *from, ssize_t len)
++{
++ gemini_flash_enable_pins();
++ inline_map_copy_to(map, to, from, len);
++ gemini_flash_disable_pins();
++}
++
+ int of_flash_probe_gemini(struct platform_device *pdev,
+ struct device_node *np,
+ struct map_info *map)
+@@ -62,6 +135,11 @@ int of_flash_probe_gemini(struct platform_device *pdev,
+ if (!of_device_is_compatible(np, "cortina,gemini-flash"))
+ return 0;
+
++ gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL);
++ if (!gf)
++ return -ENOMEM;
++ gf->dev = dev;
++
+ rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(rmap)) {
+ dev_err(dev, "no syscon\n");
+@@ -96,7 +174,32 @@ int of_flash_probe_gemini(struct platform_device *pdev,
+ map->bankwidth * 8);
+ }
+
+- dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n");
++ gf->p = devm_pinctrl_get(dev);
++ if (IS_ERR(gf->p)) {
++ dev_err(dev, "no pinctrl handle\n");
++ ret = PTR_ERR(gf->p);
++ return ret;
++ }
++
++ gf->enabled_state = pinctrl_lookup_state(gf->p, "enabled");
++ if (IS_ERR(gf->enabled_state))
++ dev_err(dev, "no enabled pin control state\n");
++
++ gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled");
++ if (IS_ERR(gf->enabled_state)) {
++ dev_err(dev, "no disabled pin control state\n");
++ } else {
++ ret = pinctrl_select_state(gf->p, gf->disabled_state);
++ if (ret)
++ dev_err(gf->dev, "failed to disable pins\n");
++ }
++
++ map->read = gemini_flash_map_read;
++ map->write = gemini_flash_map_write;
++ map->copy_from = gemini_flash_map_copy_from;
++ map->copy_to = gemini_flash_map_copy_to;
++
++ dev_info(dev, "initialized Gemini-specific physmap control\n");
+
+ return 0;
+ }
+--
+2.19.2
+