summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2020-03-24 13:19:34 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2020-04-14 09:13:19 +0200
commitef46f2db0001d4d5b66ddd34346aa36625dbf452 (patch)
tree2a87a67f0e577ceb3e23668b51893789218d1e6a /drivers/base
parentd32a774ebbe8465c84e279a577d458890ef326e7 (diff)
downloadbarebox-ef46f2db0001d4d5b66ddd34346aa36625dbf452.tar.gz
barebox-ef46f2db0001d4d5b66ddd34346aa36625dbf452.tar.xz
regmap-mmio: Add big endian support
Add support for parsing the big-endian device tree property. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/internal.h4
-rw-r--r--drivers/base/regmap/regmap-mmio.c119
-rw-r--r--drivers/base/regmap/regmap.c46
3 files changed, 128 insertions, 41 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5b19459828..4c7460fa4c 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -22,4 +22,8 @@ struct regmap {
struct cdev cdev;
};
+enum regmap_endian regmap_get_val_endian(struct device_d *dev,
+ const struct regmap_bus *bus,
+ const struct regmap_config *config);
+
#endif
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index ef6a7db6fd..7ca95d6bea 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -86,6 +86,20 @@ static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
writel(val, ctx->regs + reg);
}
+static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
+{
+ iowrite16be(val, ctx->regs + reg);
+}
+
+static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
+ unsigned int reg,
+ unsigned int val)
+{
+ iowrite32be(val, ctx->regs + reg);
+}
+
#ifdef CONFIG_64BIT
static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
unsigned int reg,
@@ -137,6 +151,18 @@ static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
}
#endif
+static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return ioread16be(ctx->regs + reg);
+}
+
+static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
+ unsigned int reg)
+{
+ return ioread32be(ctx->regs + reg);
+}
+
static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
{
struct regmap_mmio_context *ctx = context;
@@ -156,9 +182,11 @@ static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
static const struct regmap_bus regmap_mmio = {
.reg_write = regmap_mmio_write,
.reg_read = regmap_mmio_read,
+ .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
-static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+static struct regmap_mmio_context *regmap_mmio_gen_context(struct device_d *dev,
+ void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
@@ -184,25 +212,58 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
- switch (config->val_bits) {
- case 8:
- ctx->reg_read = regmap_mmio_read8;
- ctx->reg_write = regmap_mmio_write8;
- break;
- case 16:
- ctx->reg_read = regmap_mmio_read16le;
- ctx->reg_write = regmap_mmio_write16le;
- break;
- case 32:
- ctx->reg_read = regmap_mmio_read32le;
- ctx->reg_write = regmap_mmio_write32le;
- break;
+ switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
+ case REGMAP_ENDIAN_DEFAULT:
+ case REGMAP_ENDIAN_LITTLE:
+#ifdef __LITTLE_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
+#endif
+ switch (config->val_bits) {
+ case 8:
+ ctx->reg_read = regmap_mmio_read8;
+ ctx->reg_write = regmap_mmio_write8;
+ break;
+ case 16:
+ ctx->reg_read = regmap_mmio_read16le;
+ ctx->reg_write = regmap_mmio_write16le;
+ break;
+ case 32:
+ ctx->reg_read = regmap_mmio_read32le;
+ ctx->reg_write = regmap_mmio_write32le;
+ break;
#ifdef CONFIG_64BIT
- case 64:
- ctx->reg_read = regmap_mmio_read64le;
- ctx->reg_write = regmap_mmio_write64le;
+ case 64:
+ ctx->reg_read = regmap_mmio_read64le;
+ ctx->reg_write = regmap_mmio_write64le;
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ goto err_free;
+ }
break;
+ case REGMAP_ENDIAN_BIG:
+#ifdef __BIG_ENDIAN
+ case REGMAP_ENDIAN_NATIVE:
#endif
+ switch (config->val_bits) {
+ case 8:
+ ctx->reg_read = regmap_mmio_read8;
+ ctx->reg_write = regmap_mmio_write8;
+ break;
+ case 16:
+ ctx->reg_read = regmap_mmio_read16be;
+ ctx->reg_write = regmap_mmio_write16be;
+ break;
+ case 32:
+ ctx->reg_read = regmap_mmio_read32be;
+ ctx->reg_write = regmap_mmio_write32be;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_free;
+ }
+ break;
default:
ret = -EINVAL;
goto err_free;
@@ -223,7 +284,7 @@ struct regmap *regmap_init_mmio_clk(struct device_d *dev,
{
struct regmap_mmio_context *ctx;
- ctx = regmap_mmio_gen_context(regs, config);
+ ctx = regmap_mmio_gen_context(dev, regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
@@ -238,28 +299,6 @@ struct regmap *regmap_init_mmio_clk(struct device_d *dev,
return regmap_init(dev, &regmap_mmio, ctx, config);
}
-struct regmap *of_regmap_init_mmio_clk(struct device_node *np,
- const char *clk_id,
- void __iomem *regs,
- const struct regmap_config *config)
-{
- struct regmap_mmio_context *ctx;
-
- ctx = regmap_mmio_gen_context(regs, config);
- if (IS_ERR(ctx))
- return ERR_CAST(ctx);
-
- if (clk_id) {
- ctx->clk = of_clk_get_by_name(np, clk_id);
- if (IS_ERR(ctx->clk)) {
- kfree(ctx);
- return ERR_CAST(ctx->clk);
- }
- }
-
- return regmap_init(NULL, &regmap_mmio, ctx, config);
-}
-
int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
{
struct regmap_mmio_context *ctx = map->bus_context;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index dc7b4f276f..ee5120fd74 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -28,6 +28,50 @@
static LIST_HEAD(regmaps);
+enum regmap_endian regmap_get_val_endian(struct device_d *dev,
+ const struct regmap_bus *bus,
+ const struct regmap_config *config)
+{
+ struct device_node *np;
+ enum regmap_endian endian;
+
+ /* Retrieve the endianness specification from the regmap config */
+ endian = config->val_format_endian;
+
+ /* If the regmap config specified a non-default value, use that */
+ if (endian != REGMAP_ENDIAN_DEFAULT)
+ return endian;
+
+ /* If the dev and dev->device_node exist try to get endianness from DT */
+ if (dev && dev->device_node) {
+ np = dev->device_node;
+
+ /* Parse the device's DT node for an endianness specification */
+ if (of_property_read_bool(np, "big-endian"))
+ endian = REGMAP_ENDIAN_BIG;
+ else if (of_property_read_bool(np, "little-endian"))
+ endian = REGMAP_ENDIAN_LITTLE;
+ else if (of_property_read_bool(np, "native-endian"))
+ endian = REGMAP_ENDIAN_NATIVE;
+
+ /* If the endianness was specified in DT, use that */
+ if (endian != REGMAP_ENDIAN_DEFAULT)
+ return endian;
+ }
+
+ /* Retrieve the endianness specification from the bus config */
+ if (bus && bus->val_format_endian_default)
+ endian = bus->val_format_endian_default;
+
+ /* If the bus specified a non-default value, use that */
+ if (endian != REGMAP_ENDIAN_DEFAULT)
+ return endian;
+
+ /* Use this if no other value was found */
+ return REGMAP_ENDIAN_BIG;
+}
+EXPORT_SYMBOL_GPL(regmap_get_val_endian);
+
/*
* regmap_init - initialize and register a regmap
*
@@ -101,7 +145,7 @@ struct regmap *of_node_to_regmap(struct device_node *node)
struct regmap *map;
list_for_each_entry(map, &regmaps, list) {
- if (map->dev->device_node == node)
+ if (map->dev && map->dev->device_node == node)
return map;
}