lkml.org 
[lkml]   [2022]   [Aug]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
    Date
    Use the newly added callback for accelerated noinc MMIO
    to provide writesb, writesw, writesl, writesq, readsb, readsw,
    readsl and readsq.

    A special quirk is needed to deal with big endian regmaps: there
    are no accelerated operations defined for big endian, so fall
    back to calling the big endian operations itereatively for this
    case.

    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
    ---
    ChangeLog v2->v3:
    - Rebase on kernel v6.0-rc1
    ChangeLog v1->v2:
    - No changes.
    ---
    drivers/base/regmap/regmap-mmio.c | 153 ++++++++++++++++++++++++++++++
    1 file changed, 153 insertions(+)

    diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
    index 71f16be7e717..031ee91020e8 100644
    --- a/drivers/base/regmap/regmap-mmio.c
    +++ b/drivers/base/regmap/regmap-mmio.c
    @@ -17,6 +17,7 @@ struct regmap_mmio_context {
    void __iomem *regs;
    unsigned int val_bytes;
    bool relaxed_mmio;
    + bool big_endian;

    bool attached_clk;
    struct clk *clk;
    @@ -160,6 +161,79 @@ static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
    return 0;
    }

    +static int regmap_mmio_noinc_write(void *context, unsigned int reg,
    + const void *val, size_t val_count)
    +{
    + struct regmap_mmio_context *ctx = context;
    + int ret = 0;
    + int i;
    +
    + if (!IS_ERR(ctx->clk)) {
    + ret = clk_enable(ctx->clk);
    + if (ret < 0)
    + return ret;
    + }
    +
    + /*
    + * There are no native, assembly-optimized write single register
    + * operations for big endian, so fall back to emulation if this
    + * is needed. (Single bytes are fine, they are not affected by
    + * endianness.)
    + */
    + if (ctx->big_endian && (ctx->val_bytes > 1)) {
    + switch (ctx->val_bytes) {
    + case 2:
    + {
    + const u16 *valp = (const u16 *)val;
    + for (i = 0; i < val_count; i++)
    + iowrite16be(valp[i], ctx->regs + reg);
    + break;
    + }
    + case 4:
    + {
    + const u32 *valp = (const u32 *)val;
    + for (i = 0; i < val_count; i++)
    + iowrite32be(valp[i], ctx->regs + reg);
    + break;
    + }
    +#ifdef CONFIG_64BIT
    + case 8:
    + /* This is just too esoteric */
    + fallthrough;
    +#endif
    + default:
    + ret = -EINVAL;
    + goto out_clk;
    + }
    + }
    +
    + switch (ctx->val_bytes) {
    + case 1:
    + writesb(ctx->regs + reg, (const u8 *)val, val_count);
    + break;
    + case 2:
    + writesw(ctx->regs + reg, (const u16 *)val, val_count);
    + break;
    + case 4:
    + writesl(ctx->regs + reg, (const u32 *)val, val_count);
    + break;
    +#ifdef CONFIG_64BIT
    + case 8:
    + writesq(ctx->regs + reg, (const u64 *)val, val_count);
    + break;
    +#endif
    + default:
    + ret = -EINVAL;
    + break;
    + }
    +
    +out_clk:
    + if (!IS_ERR(ctx->clk))
    + clk_disable(ctx->clk);
    +
    + return ret;
    +}
    +
    static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
    unsigned int reg)
    {
    @@ -241,6 +315,82 @@ static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
    return 0;
    }

    +static int regmap_mmio_noinc_read(void *context, unsigned int reg,
    + void *val, size_t val_count)
    +{
    + struct regmap_mmio_context *ctx = context;
    + int ret = 0;
    + int i;
    +
    + if (!IS_ERR(ctx->clk)) {
    + ret = clk_enable(ctx->clk);
    + if (ret < 0)
    + return ret;
    + }
    +
    + /*
    + * There are no native, assembly-optimized write single register
    + * operations for big endian, so fall back to emulation if this
    + * is needed. (Single bytes are fine, they are not affected by
    + * endianness.)
    + */
    + if (ctx->big_endian && (ctx->val_bytes > 1)) {
    + switch (ctx->val_bytes) {
    + case 2:
    + {
    + u16 *valp = (u16 *)val;
    + for (i = 0; i < val_count; i++)
    + valp[i] = ioread16be(ctx->regs + reg);
    + break;
    + }
    + case 4:
    + {
    + u32 *valp = (u32 *)val;
    + for (i = 0; i < val_count; i++)
    + valp[i] = ioread32be(ctx->regs + reg);
    + break;
    + }
    +#ifdef CONFIG_64BIT
    + case 8:
    + /* This is just too esoteric */
    + fallthrough;
    +#endif
    + default:
    + ret = -EINVAL;
    + goto out_clk;
    + }
    + }
    +
    + switch (ctx->val_bytes) {
    + case 1:
    + readsb(ctx->regs + reg, (u8 *)val, val_count);
    + break;
    + case 2:
    + readsw(ctx->regs + reg, (u16 *)val, val_count);
    + break;
    + case 4:
    + readsl(ctx->regs + reg, (u32 *)val, val_count);
    + break;
    +#ifdef CONFIG_64BIT
    + case 8:
    + readsq(ctx->regs + reg, (u64 *)val, val_count);
    + break;
    +#endif
    + default:
    + ret = -EINVAL;
    + break;
    + }
    +
    +out_clk:
    + if (!IS_ERR(ctx->clk))
    + clk_disable(ctx->clk);
    +
    + return ret;
    +
    + return 0;
    +}
    +
    +
    static void regmap_mmio_free_context(void *context)
    {
    struct regmap_mmio_context *ctx = context;
    @@ -257,6 +407,8 @@ static const struct regmap_bus regmap_mmio = {
    .fast_io = true,
    .reg_write = regmap_mmio_write,
    .reg_read = regmap_mmio_read,
    + .reg_noinc_write = regmap_mmio_noinc_write,
    + .reg_noinc_read = regmap_mmio_noinc_read,
    .free_context = regmap_mmio_free_context,
    .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
    };
    @@ -347,6 +499,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
    #ifdef __BIG_ENDIAN
    case REGMAP_ENDIAN_NATIVE:
    #endif
    + ctx->big_endian = true;
    switch (config->val_bits) {
    case 8:
    ctx->reg_read = regmap_mmio_read8;
    --
    2.37.2
    \
     
     \ /
      Last update: 2022-08-16 15:11    [W:2.452 / U:0.116 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site