]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
mtd: physmap: Add Baikal-T1 physically mapped ROM support
authorSerge Semin <Sergey.Semin@baikalelectronics.ru>
Sun, 20 Sep 2020 11:14:44 +0000 (14:14 +0300)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Fri, 2 Oct 2020 07:08:22 +0000 (09:08 +0200)
Baikal-T1 Boot Controller provides an access to a RO storages, which are
physically mapped into the SoC MMIO space. In particularly there are
Internal ROM embedded into the SoC with a pre-installed firmware,
externally attached SPI flash (also accessed in the read-only mode) and a
memory region, which mirrors one of them in accordance with the currently
enabled system boot mode (also called Boot ROM).

This commit adds the Internal ROM support to the physmap driver of the MTD
kernel subsystem. The driver will create the Internal ROM MTD as long as
it is defined in the system dts file. The physically mapped SPI flash
region will be used to implement the SPI-mem interface. The mirroring
memory region won't be accessible directly since it's redundant due to
both bootable regions being exposed anyway.

Note we had to create a dedicated code for the ROMs since read from the
corresponding memory regions must be done via the dword-aligned addresses.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: linux-mips@vger.kernel.org
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200920111445.21816-1-Sergey.Semin@baikalelectronics.ru
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/physmap-bt1-rom.c [new file with mode: 0644]
drivers/mtd/maps/physmap-bt1-rom.h [new file with mode: 0644]
drivers/mtd/maps/physmap-core.c

index fd37553f1b0709977b7666419e58ed098ab1f336..6650acbc961e972089aa97fdf56f90b987075a71 100644 (file)
@@ -75,6 +75,17 @@ config MTD_PHYSMAP_OF
          physically into the CPU's memory. The mapping description here is
          taken from OF device tree.
 
+config MTD_PHYSMAP_BT1_ROM
+       bool "Baikal-T1 Boot ROMs OF-based physical memory map handling"
+       depends on MTD_PHYSMAP_OF
+       depends on MIPS_BAIKAL_T1 || COMPILE_TEST
+       select MTD_COMPLEX_MAPPINGS
+       select MULTIPLEXER
+       select MUX_MMIO
+       help
+         This provides some extra DT physmap parsing for the Baikal-T1
+         platforms, some detection and setting up ROMs-specific accessors.
+
 config MTD_PHYSMAP_VERSATILE
        bool "ARM Versatile OF-based physical memory map handling"
        depends on MTD_PHYSMAP_OF
index c0da86a5d26fcc00767ea4b21ee5b0b1dfc9a36d..79f018cf412f75253903e48db3b070de731e589c 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_CK804XROM)   += ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)       += pxa2xx-flash.o
 physmap-objs-y                 += physmap-core.o
+physmap-objs-$(CONFIG_MTD_PHYSMAP_BT1_ROM) += physmap-bt1-rom.o
 physmap-objs-$(CONFIG_MTD_PHYSMAP_VERSATILE) += physmap-versatile.o
 physmap-objs-$(CONFIG_MTD_PHYSMAP_GEMINI) += physmap-gemini.o
 physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o
diff --git a/drivers/mtd/maps/physmap-bt1-rom.c b/drivers/mtd/maps/physmap-bt1-rom.c
new file mode 100644 (file)
index 0000000..27cfe1c
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
+ *
+ * Authors:
+ *   Serge Semin <Sergey.Semin@baikalelectronics.ru>
+ *
+ * Baikal-T1 Physically Mapped Internal ROM driver
+ */
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/xip.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "physmap-bt1-rom.h"
+
+/*
+ * Baikal-T1 SoC ROMs are only accessible by the dword-aligned instructions.
+ * We have to take this into account when implementing the data read-methods.
+ * Note there is no need in bothering with endianness, since both Baikal-T1
+ * CPU and MMIO are LE.
+ */
+static map_word __xipram bt1_rom_map_read(struct map_info *map,
+                                         unsigned long ofs)
+{
+       void __iomem *src = map->virt + ofs;
+       unsigned long shift;
+       map_word ret;
+       u32 data;
+
+       /* Read data within offset dword. */
+       shift = (unsigned long)src & 0x3;
+       data = readl_relaxed(src - shift);
+       if (!shift) {
+               ret.x[0] = data;
+               return ret;
+       }
+       ret.x[0] = data >> (shift * BITS_PER_BYTE);
+
+       /* Read data from the next dword. */
+       shift = 4 - shift;
+       if (ofs + shift >= map->size)
+               return ret;
+
+       data = readl_relaxed(src + shift);
+       ret.x[0] |= data << (shift * BITS_PER_BYTE);
+
+       return ret;
+}
+
+static void __xipram bt1_rom_map_copy_from(struct map_info *map,
+                                          void *to, unsigned long from,
+                                          ssize_t len)
+{
+       void __iomem *src = map->virt + from;
+       ssize_t shift, chunk;
+       u32 data;
+
+       if (len <= 0 || from >= map->size)
+               return;
+
+       /* Make sure we don't go over the map limit. */
+       len = min_t(ssize_t, map->size - from, len);
+
+       /*
+        * Since requested data size can be pretty big we have to implement
+        * the copy procedure as optimal as possible. That's why it's split
+        * up into the next three stages: unaligned head, aligned body,
+        * unaligned tail.
+        */
+       shift = (ssize_t)src & 0x3;
+       if (shift) {
+               chunk = min_t(ssize_t, 4 - shift, len);
+               data = readl_relaxed(src - shift);
+               memcpy(to, &data + shift, chunk);
+               src += chunk;
+               to += chunk;
+               len -= chunk;
+       }
+
+       while (len >= 4) {
+               data = readl_relaxed(src);
+               memcpy(to, &data, 4);
+               src += 4;
+               to += 4;
+               len -= 4;
+       }
+
+       if (len) {
+               data = readl_relaxed(src);
+               memcpy(to, &data, len);
+       }
+}
+
+int of_flash_probe_bt1_rom(struct platform_device *pdev,
+                          struct device_node *np,
+                          struct map_info *map)
+{
+       struct device *dev = &pdev->dev;
+
+       /* It's supposed to be read-only MTD. */
+       if (!of_device_is_compatible(np, "mtd-rom")) {
+               dev_info(dev, "No mtd-rom compatible string\n");
+               return 0;
+       }
+
+       /* Multiplatform guard. */
+       if (!of_device_is_compatible(np, "baikal,bt1-int-rom"))
+               return 0;
+
+       /* Sanity check the device parameters retrieved from DTB. */
+       if (map->bankwidth != 4)
+               dev_warn(dev, "Bank width is supposed to be 32 bits wide\n");
+
+       map->read = bt1_rom_map_read;
+       map->copy_from = bt1_rom_map_copy_from;
+
+       return 0;
+}
diff --git a/drivers/mtd/maps/physmap-bt1-rom.h b/drivers/mtd/maps/physmap-bt1-rom.h
new file mode 100644 (file)
index 0000000..6782899
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/mtd/map.h>
+#include <linux/of.h>
+
+#ifdef CONFIG_MTD_PHYSMAP_BT1_ROM
+int of_flash_probe_bt1_rom(struct platform_device *pdev,
+                          struct device_node *np,
+                          struct map_info *map);
+#else
+static inline
+int of_flash_probe_bt1_rom(struct platform_device *pdev,
+                          struct device_node *np,
+                          struct map_info *map)
+{
+       return 0;
+}
+#endif
index 6372197ad8656122a23d3c6a2d6fc97932ace43f..001ed5deb622aacfa82b58c0ac7dcf03a3b1085c 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/gpio/consumer.h>
 
+#include "physmap-bt1-rom.h"
 #include "physmap-gemini.h"
 #include "physmap-ixp4xx.h"
 #include "physmap-versatile.h"
@@ -371,6 +372,10 @@ static int physmap_flash_of_init(struct platform_device *dev)
                info->maps[i].bankwidth = bankwidth;
                info->maps[i].device_node = dp;
 
+               err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]);
+               if (err)
+                       return err;
+
                err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
                if (err)
                        return err;