aboutsummaryrefslogtreecommitdiff
path: root/lib/utils
diff options
context:
space:
mode:
authorAnup Patel <apatel@ventanamicro.com>2023-07-21 13:40:03 +0530
committerAnup Patel <anup@brainfault.org>2023-07-31 14:09:13 +0530
commitf21d8f7d59114fdf73a56603ff082ce23797d9e5 (patch)
tree8321503645d9a205e4c91b8b804ea0d4573b69b6 /lib/utils
parent8e97275d97bbfb9b990a5e7beafe99bea0e3f538 (diff)
downloadopensbi-f21d8f7d59114fdf73a56603ff082ce23797d9e5.zip
opensbi-f21d8f7d59114fdf73a56603ff082ce23797d9e5.tar.gz
opensbi-f21d8f7d59114fdf73a56603ff082ce23797d9e5.tar.bz2
lib: utils/regmap: Add simple FDT based syscon regmap driver
Let us add a simple FDT based system regmap driver which follows the device tree bindings already defined in the Linux kernel. Signed-off-by: Anup Patel <apatel@ventanamicro.com> Reviewed-by: Xiang W <wxjstz@126.com>
Diffstat (limited to 'lib/utils')
-rw-r--r--lib/utils/regmap/Kconfig7
-rw-r--r--lib/utils/regmap/fdt_regmap_syscon.c262
-rw-r--r--lib/utils/regmap/objects.mk3
3 files changed, 272 insertions, 0 deletions
diff --git a/lib/utils/regmap/Kconfig b/lib/utils/regmap/Kconfig
index b1ff501..62d9f93 100644
--- a/lib/utils/regmap/Kconfig
+++ b/lib/utils/regmap/Kconfig
@@ -8,6 +8,13 @@ config FDT_REGMAP
select REGMAP
default n
+if FDT_REGMAP
+
+config FDT_REGMAP_SYSCON
+ bool "Syscon regmap FDT driver"
+ default n
+endif
+
config REGMAP
bool "Regmap support"
default n
diff --git a/lib/utils/regmap/fdt_regmap_syscon.c b/lib/utils/regmap/fdt_regmap_syscon.c
new file mode 100644
index 0000000..29263dd
--- /dev/null
+++ b/lib/utils/regmap/fdt_regmap_syscon.c
@@ -0,0 +1,262 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <apatel@ventanamicro.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_byteorder.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_heap.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/regmap/fdt_regmap.h>
+
+enum syscon_regmap_endian {
+ SYSCON_ENDIAN_NATIVE = 0,
+ SYSCON_ENDIAN_LITTLE,
+ SYSCON_ENDIAN_BIG,
+ SYSCON_ENDIAN_MAX
+};
+
+struct syscon_regmap {
+ u32 reg_io_width;
+ enum syscon_regmap_endian reg_endian;
+ unsigned long addr;
+ struct regmap rmap;
+};
+
+#define to_syscon_regmap(__rmap) \
+ container_of((__rmap), struct syscon_regmap, rmap)
+
+static int regmap_syscon_read_8(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = readb((volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_write_8(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writeb(val, (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_read_16(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = readw((volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_write_16(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writew(val, (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_read_32(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = readl((volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_write_32(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writel(val, (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_read_le16(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = le16_to_cpu(readw((volatile void *)(srm->addr + reg)));
+ return 0;
+}
+
+static int regmap_syscon_write_le16(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writew(cpu_to_le16(val), (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_read_le32(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = le32_to_cpu(readl((volatile void *)(srm->addr + reg)));
+ return 0;
+}
+
+static int regmap_syscon_write_le32(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writel(cpu_to_le32(val), (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_read_be16(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = be16_to_cpu(readl((volatile void *)(srm->addr + reg)));
+ return 0;
+}
+
+static int regmap_syscon_write_be16(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writel(cpu_to_be16(val), (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_read_be32(struct regmap *rmap, unsigned int reg,
+ unsigned int *val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ *val = be32_to_cpu(readl((volatile void *)(srm->addr + reg)));
+ return 0;
+}
+
+static int regmap_syscon_write_be32(struct regmap *rmap, unsigned int reg,
+ unsigned int val)
+{
+ struct syscon_regmap *srm = to_syscon_regmap(rmap);
+
+ writel(cpu_to_be32(val), (volatile void *)(srm->addr + reg));
+ return 0;
+}
+
+static int regmap_syscon_init(void *fdt, int nodeoff, u32 phandle,
+ const struct fdt_match *match)
+{
+ struct syscon_regmap *srm;
+ uint64_t addr, size;
+ const fdt32_t *val;
+ int rc, len;
+
+ srm = sbi_zalloc(sizeof(*srm));
+ if (!srm)
+ return SBI_ENOMEM;
+
+ val = fdt_getprop(fdt, nodeoff, "reg-io-width", &len);
+ srm->reg_io_width = val ? fdt32_to_cpu(*val) : 4;
+
+ if (fdt_getprop(fdt, nodeoff, "native-endian", &len))
+ srm->reg_endian = SYSCON_ENDIAN_NATIVE;
+ else if (fdt_getprop(fdt, nodeoff, "little-endian", &len))
+ srm->reg_endian = SYSCON_ENDIAN_LITTLE;
+ else if (fdt_getprop(fdt, nodeoff, "big-endian", &len))
+ srm->reg_endian = SYSCON_ENDIAN_BIG;
+ else
+ srm->reg_endian = SYSCON_ENDIAN_NATIVE;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, &size);
+ if (rc)
+ goto fail_free_syscon;
+ srm->addr = addr;
+
+ srm->rmap.id = phandle;
+ srm->rmap.reg_shift = 0;
+ srm->rmap.reg_stride = srm->reg_io_width * 8;
+ srm->rmap.reg_base = 0;
+ srm->rmap.reg_max = size / srm->reg_io_width;
+ switch (srm->reg_io_width) {
+ case 1:
+ srm->rmap.reg_read = regmap_syscon_read_8;
+ srm->rmap.reg_write = regmap_syscon_write_8;
+ break;
+ case 2:
+ switch (srm->reg_endian) {
+ case SYSCON_ENDIAN_NATIVE:
+ srm->rmap.reg_read = regmap_syscon_read_16;
+ srm->rmap.reg_write = regmap_syscon_write_16;
+ break;
+ case SYSCON_ENDIAN_LITTLE:
+ srm->rmap.reg_read = regmap_syscon_read_le16;
+ srm->rmap.reg_write = regmap_syscon_write_le16;
+ break;
+ case SYSCON_ENDIAN_BIG:
+ srm->rmap.reg_read = regmap_syscon_read_be16;
+ srm->rmap.reg_write = regmap_syscon_write_be16;
+ break;
+ default:
+ rc = SBI_EINVAL;
+ goto fail_free_syscon;
+ }
+ break;
+ case 4:
+ switch (srm->reg_endian) {
+ case SYSCON_ENDIAN_NATIVE:
+ srm->rmap.reg_read = regmap_syscon_read_32;
+ srm->rmap.reg_write = regmap_syscon_write_32;
+ break;
+ case SYSCON_ENDIAN_LITTLE:
+ srm->rmap.reg_read = regmap_syscon_read_le32;
+ srm->rmap.reg_write = regmap_syscon_write_le32;
+ break;
+ case SYSCON_ENDIAN_BIG:
+ srm->rmap.reg_read = regmap_syscon_read_be32;
+ srm->rmap.reg_write = regmap_syscon_write_be32;
+ break;
+ default:
+ rc = SBI_EINVAL;
+ goto fail_free_syscon;
+ }
+ break;
+ default:
+ rc = SBI_EINVAL;
+ goto fail_free_syscon;
+ }
+
+ rc = regmap_add(&srm->rmap);
+ if (rc)
+ goto fail_free_syscon;
+
+ return 0;
+
+fail_free_syscon:
+ sbi_free(srm);
+ return rc;
+}
+
+static const struct fdt_match regmap_syscon_match[] = {
+ { .compatible = "syscon" },
+ { },
+};
+
+struct fdt_regmap fdt_regmap_syscon = {
+ .match_table = regmap_syscon_match,
+ .init = regmap_syscon_init,
+};
diff --git a/lib/utils/regmap/objects.mk b/lib/utils/regmap/objects.mk
index 5ce2373..5bd139f 100644
--- a/lib/utils/regmap/objects.mk
+++ b/lib/utils/regmap/objects.mk
@@ -10,4 +10,7 @@
libsbiutils-objs-$(CONFIG_FDT_REGMAP) += regmap/fdt_regmap.o
libsbiutils-objs-$(CONFIG_FDT_REGMAP) += regmap/fdt_regmap_drivers.o
+carray-fdt_regmap_drivers-$(CONFIG_FDT_REGMAP_SYSCON) += fdt_regmap_syscon
+libsbiutils-objs-$(CONFIG_FDT_REGMAP_SYSCON) += regmap/fdt_regmap_syscon.o
+
libsbiutils-objs-$(CONFIG_REGMAP) += regmap/regmap.o