mirror of
https://github.com/Fishwaldo/opensbi.git
synced 2025-03-15 19:31:32 +00:00
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>
This commit is contained in:
parent
8e97275d97
commit
f21d8f7d59
4 changed files with 273 additions and 0 deletions
|
@ -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
|
||||
|
|
262
lib/utils/regmap/fdt_regmap_syscon.c
Normal file
262
lib/utils/regmap/fdt_regmap_syscon.c
Normal file
|
@ -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,
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -19,6 +19,7 @@ CONFIG_FDT_IRQCHIP_APLIC=y
|
|||
CONFIG_FDT_IRQCHIP_IMSIC=y
|
||||
CONFIG_FDT_IRQCHIP_PLIC=y
|
||||
CONFIG_FDT_REGMAP=y
|
||||
CONFIG_FDT_REGMAP_SYSCON=y
|
||||
CONFIG_FDT_RESET=y
|
||||
CONFIG_FDT_RESET_ATCWDT200=y
|
||||
CONFIG_FDT_RESET_GPIO=y
|
||||
|
|
Loading…
Add table
Reference in a new issue