From ada79bca380009a85d1e643e5a4da0c079f28225 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 8 Aug 2022 23:33:57 +0300 Subject: [PATCH 01/18] regmap: mmio: Remove mmio_relaxed member from context There is no need to keep mmio_relaxed member in the context, it's onetime used during generation of the context. Remove it. Signed-off-by: Andy Shevchenko Acked-by: William Breathitt Gray Link: https://lore.kernel.org/r/20220808203401.35153-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 71f16be7e717..3a5c81e4ce84 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -16,7 +16,6 @@ struct regmap_mmio_context { void __iomem *regs; unsigned int val_bytes; - bool relaxed_mmio; bool attached_clk; struct clk *clk; @@ -290,7 +289,6 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ctx->regs = regs; ctx->val_bytes = config->val_bits / 8; - ctx->relaxed_mmio = config->use_relaxed_mmio; ctx->clk = ERR_PTR(-ENODEV); switch (regmap_get_val_endian(dev, ®map_mmio, config)) { @@ -301,7 +299,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, #endif switch (config->val_bits) { case 8: - if (ctx->relaxed_mmio) { + if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read8_relaxed; ctx->reg_write = regmap_mmio_write8_relaxed; } else { @@ -310,7 +308,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, } break; case 16: - if (ctx->relaxed_mmio) { + if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read16le_relaxed; ctx->reg_write = regmap_mmio_write16le_relaxed; } else { @@ -319,7 +317,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, } break; case 32: - if (ctx->relaxed_mmio) { + if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read32le_relaxed; ctx->reg_write = regmap_mmio_write32le_relaxed; } else { @@ -329,7 +327,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, break; #ifdef CONFIG_64BIT case 64: - if (ctx->relaxed_mmio) { + if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read64le_relaxed; ctx->reg_write = regmap_mmio_write64le_relaxed; } else { From 159dfabd207628c983e0c3c5ef607f496ff5e6a5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 8 Aug 2022 23:33:58 +0300 Subject: [PATCH 02/18] regmap: mmio: Get rid of broken 64-bit IO The current implementation, besides having no active users, is broken by design of regmap. For 64-bit IO we need to supply 64-bit value, otherwise there is no way to handle upper 32 bits in 64-bit register. Hence, remove the broken IO accessors for good and wait for real user that can fix entire regmap API for that. Signed-off-by: Andy Shevchenko Acked-by: William Breathitt Gray Link: https://lore.kernel.org/r/20220808203401.35153-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 49 ------------------------------- 1 file changed, 49 deletions(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 3a5c81e4ce84..b1bd93ea405e 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -32,9 +32,6 @@ static int regmap_mmio_regbits_check(size_t reg_bits) case 8: case 16: case 32: -#ifdef CONFIG_64BIT - case 64: -#endif return 0; default: return -EINVAL; @@ -56,11 +53,6 @@ static int regmap_mmio_get_min_stride(size_t val_bits) case 32: min_stride = 4; break; -#ifdef CONFIG_64BIT - case 64: - min_stride = 8; - break; -#endif default: return -EINVAL; } @@ -124,22 +116,6 @@ static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, iowrite32be(val, ctx->regs + reg); } -#ifdef CONFIG_64BIT -static void regmap_mmio_write64le(struct regmap_mmio_context *ctx, - unsigned int reg, - unsigned int val) -{ - writeq(val, ctx->regs + reg); -} - -static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context *ctx, - unsigned int reg, - unsigned int val) -{ - writeq_relaxed(val, ctx->regs + reg); -} -#endif - static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) { struct regmap_mmio_context *ctx = context; @@ -207,20 +183,6 @@ static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, return ioread32be(ctx->regs + reg); } -#ifdef CONFIG_64BIT -static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx, - unsigned int reg) -{ - return readq(ctx->regs + reg); -} - -static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx, - unsigned int reg) -{ - return readq_relaxed(ctx->regs + reg); -} -#endif - static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) { struct regmap_mmio_context *ctx = context; @@ -325,17 +287,6 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ctx->reg_write = regmap_mmio_write32le; } break; -#ifdef CONFIG_64BIT - case 64: - if (config->use_relaxed_mmio) { - ctx->reg_read = regmap_mmio_read64le_relaxed; - ctx->reg_write = regmap_mmio_write64le_relaxed; - } else { - ctx->reg_read = regmap_mmio_read64le; - ctx->reg_write = regmap_mmio_write64le; - } - break; -#endif default: ret = -EINVAL; goto err_free; From 93ce557679e1cf7742ad327d40a1499e7d8535b7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 8 Aug 2022 23:33:59 +0300 Subject: [PATCH 03/18] regmap: mmio: Introduce IO accessors that can talk to IO port Some users may use regmap MMIO for IO ports, and this can be done by assigning ioreadXX()/iowriteXX() and their Big Endian counterparts to the regmap context. Add IO port support with a corresponding flag added. While doing that, make sure that user won't select relaxed MMIO access along with IO port because the latter have no relaxed variants. Signed-off-by: Andy Shevchenko Acked-by: William Breathitt Gray Link: https://lore.kernel.org/r/20220808203401.35153-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 105 +++++++++++++++++++++++++++--- include/linux/regmap.h | 3 + 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index b1bd93ea405e..37f79e912d01 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -74,6 +74,12 @@ static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx, writeb_relaxed(val, ctx->regs + reg); } +static void regmap_mmio_iowrite8(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite8(val, ctx->regs + reg); +} + static void regmap_mmio_write16le(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) @@ -88,6 +94,12 @@ static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx, writew_relaxed(val, ctx->regs + reg); } +static void regmap_mmio_iowrite16le(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite16(val, ctx->regs + reg); +} + static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) @@ -95,6 +107,12 @@ static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, iowrite16be(val, ctx->regs + reg); } +static void regmap_mmio_iowrite16be(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite16be(val, ctx->regs + reg); +} + static void regmap_mmio_write32le(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) @@ -109,6 +127,12 @@ static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx, writel_relaxed(val, ctx->regs + reg); } +static void regmap_mmio_iowrite32le(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite32(val, ctx->regs + reg); +} + static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) @@ -116,6 +140,12 @@ static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, iowrite32be(val, ctx->regs + reg); } +static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val) +{ + iowrite32be(val, ctx->regs + reg); +} + static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) { struct regmap_mmio_context *ctx = context; @@ -147,6 +177,12 @@ static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx, return readb_relaxed(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread8(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread8(ctx->regs + reg); +} + static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx, unsigned int reg) { @@ -159,12 +195,24 @@ static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx return readw_relaxed(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread16le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread16(ctx->regs + reg); +} + static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx, unsigned int reg) { return ioread16be(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread16be(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread16be(ctx->regs + reg); +} + static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx, unsigned int reg) { @@ -177,12 +225,24 @@ static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx return readl_relaxed(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return ioread32(ctx->regs + reg); +} + static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, unsigned int reg) { return ioread32be(ctx->regs + reg); } +static unsigned int regmap_mmio_ioread32be(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; @@ -245,6 +305,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, if (config->reg_stride < min_stride) return ERR_PTR(-EINVAL); + if (config->use_relaxed_mmio && config->io_port) + return ERR_PTR(-EINVAL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return ERR_PTR(-ENOMEM); @@ -261,7 +324,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, #endif switch (config->val_bits) { case 8: - if (config->use_relaxed_mmio) { + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread8; + ctx->reg_write = regmap_mmio_iowrite8; + } else if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read8_relaxed; ctx->reg_write = regmap_mmio_write8_relaxed; } else { @@ -270,7 +336,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, } break; case 16: - if (config->use_relaxed_mmio) { + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread16le; + ctx->reg_write = regmap_mmio_iowrite16le; + } else if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read16le_relaxed; ctx->reg_write = regmap_mmio_write16le_relaxed; } else { @@ -279,7 +348,10 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, } break; case 32: - if (config->use_relaxed_mmio) { + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread32le; + ctx->reg_write = regmap_mmio_iowrite32le; + } else if (config->use_relaxed_mmio) { ctx->reg_read = regmap_mmio_read32le_relaxed; ctx->reg_write = regmap_mmio_write32le_relaxed; } else { @@ -298,16 +370,31 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, #endif switch (config->val_bits) { case 8: - ctx->reg_read = regmap_mmio_read8; - ctx->reg_write = regmap_mmio_write8; + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread8; + ctx->reg_write = regmap_mmio_iowrite8; + } else { + 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; + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread16be; + ctx->reg_write = regmap_mmio_iowrite16be; + } else { + 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; + if (config->io_port) { + ctx->reg_read = regmap_mmio_ioread32be; + ctx->reg_write = regmap_mmio_iowrite32be; + } else { + ctx->reg_read = regmap_mmio_read32be; + ctx->reg_write = regmap_mmio_write32be; + } break; default: ret = -EINVAL; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 7cf2157134ac..8cccc247cd37 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -311,6 +311,8 @@ typedef void (*regmap_unlock)(void *); * This field is a duplicate of a similar file in * 'struct regmap_bus' and serves exact same purpose. * Use it only for "no-bus" cases. + * @io_port: Support IO port accessors. Makes sense only when MMIO vs. IO port + * access can be distinguished. * @max_register: Optional, specifies the maximum valid register address. * @wr_table: Optional, points to a struct regmap_access_table specifying * valid ranges for write access. @@ -399,6 +401,7 @@ struct regmap_config { size_t max_raw_write; bool fast_io; + bool io_port; unsigned int max_register; const struct regmap_access_table *wr_table; From 7e7ba58c94127efa97c249e38cc2d1c0ed78b58f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 8 Aug 2022 23:34:00 +0300 Subject: [PATCH 04/18] regmap: mmio: Fix MMIO accessors to avoid talking to IO port Currently regmap MMIO is inconsistent with IO accessors. I.e. the Big Endian counterparts are using ioreadXXbe() / iowriteXXbe() which are not clean implementations of readXXbe(). That said, reimplement current Big Endian MMIO accessors by replacing ioread()/iowrite() with respective read()/write() and swab() calls. Note, there are no current in-kernel users that may utilize the functionality of the IO ports on Big Endian hardware. All drivers that use regmap MMIO either Little Endian, or they don't map IO ports in a way that ioreadXX()/iowriteXX() may be utilized. Signed-off-by: Andy Shevchenko Acked-by: William Breathitt Gray Link: https://lore.kernel.org/r/20220808203401.35153-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 37f79e912d01..eed488aad1b0 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -104,7 +104,7 @@ static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) { - iowrite16be(val, ctx->regs + reg); + writew(swab16(val), ctx->regs + reg); } static void regmap_mmio_iowrite16be(struct regmap_mmio_context *ctx, @@ -137,7 +137,7 @@ static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, unsigned int reg, unsigned int val) { - iowrite32be(val, ctx->regs + reg); + writel(swab32(val), ctx->regs + reg); } static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx, @@ -204,7 +204,7 @@ static unsigned int regmap_mmio_ioread16le(struct regmap_mmio_context *ctx, static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx, unsigned int reg) { - return ioread16be(ctx->regs + reg); + return swab16(readw(ctx->regs + reg)); } static unsigned int regmap_mmio_ioread16be(struct regmap_mmio_context *ctx, @@ -234,7 +234,7 @@ static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx, static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, unsigned int reg) { - return ioread32be(ctx->regs + reg); + return swab32(readl(ctx->regs + reg)); } static unsigned int regmap_mmio_ioread32be(struct regmap_mmio_context *ctx, From 060004431df4958a326d6a45107b2fe3406d10f2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Jul 2022 18:12:13 +0300 Subject: [PATCH 05/18] regmap: Make use of get_unaligned_be24(), put_unaligned_be24() Since we have a proper endianness converters for BE 24-bit data use them. While at it, format the code using switch-cases as it's done for the rest of the endianness handlers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220726151213.71712-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 37 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index fee221c5008c..e371acea7e0e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -288,15 +288,9 @@ static void regmap_format_16_native(void *buf, unsigned int val, memcpy(buf, &v, sizeof(v)); } -static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) +static void regmap_format_24_be(void *buf, unsigned int val, unsigned int shift) { - u8 *b = buf; - - val <<= shift; - - b[0] = val >> 16; - b[1] = val >> 8; - b[2] = val; + put_unaligned_be24(val << shift, buf); } static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) @@ -380,14 +374,9 @@ static unsigned int regmap_parse_16_native(const void *buf) return v; } -static unsigned int regmap_parse_24(const void *buf) +static unsigned int regmap_parse_24_be(const void *buf) { - const u8 *b = buf; - unsigned int ret = b[2]; - ret |= ((unsigned int)b[1]) << 8; - ret |= ((unsigned int)b[0]) << 16; - - return ret; + return get_unaligned_be24(buf); } static unsigned int regmap_parse_32_be(const void *buf) @@ -991,9 +980,13 @@ struct regmap *__regmap_init(struct device *dev, break; case 24: - if (reg_endian != REGMAP_ENDIAN_BIG) + switch (reg_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_reg = regmap_format_24_be; + break; + default: goto err_hwlock; - map->format.format_reg = regmap_format_24; + } break; case 32: @@ -1064,10 +1057,14 @@ struct regmap *__regmap_init(struct device *dev, } break; case 24: - if (val_endian != REGMAP_ENDIAN_BIG) + switch (val_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_val = regmap_format_24_be; + map->format.parse_val = regmap_parse_24_be; + break; + default: goto err_hwlock; - map->format.format_val = regmap_format_24; - map->format.parse_val = regmap_parse_24; + } break; case 32: switch (val_endian) { From c20cc099b30abd50f563e422aa72edcd7f92da55 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Aug 2022 22:48:31 +0200 Subject: [PATCH 06/18] regmap: Support accelerated noinc operations Several architectures have accelerated operations for MMIO operations writing to a single register, such as writesb, writesw, writesl, writesq, readsb, readsw, readsl and readsq but regmap currently cannot use them because we have no hooks for providing an accelerated noinc back-end for MMIO. Solve this by providing reg_[read/write]_noinc callbacks for the bus abstraction, so that the regmap-mmio bus can use this. Currently I do not see a need to support this for custom regmaps so it is only added to the bus. Callbacks are passed a void * with the array of values and a count which is the number of items of the byte chunk size for the specific register width. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220816204832.265837-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 123 ++++++++++++++++++++++++++++++++++- include/linux/regmap.h | 8 +++ 2 files changed, 128 insertions(+), 3 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index e371acea7e0e..41ff9f18b6a3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2129,6 +2129,99 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_raw_write); +static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg, + void *val, unsigned int val_len, bool write) +{ + size_t val_bytes = map->format.val_bytes; + size_t val_count = val_len / val_bytes; + unsigned int lastval; + u8 *u8p; + u16 *u16p; + u32 *u32p; +#ifdef CONFIG_64BIT + u64 *u64p; +#endif + int ret; + int i; + + switch (val_bytes) { + case 1: + u8p = val; + if (write) + lastval = (unsigned int)u8p[val_count - 1]; + break; + case 2: + u16p = val; + if (write) + lastval = (unsigned int)u16p[val_count - 1]; + break; + case 4: + u32p = val; + if (write) + lastval = (unsigned int)u32p[val_count - 1]; + break; +#ifdef CONFIG_64BIT + case 8: + u64p = val; + if (write) + lastval = (unsigned int)u64p[val_count - 1]; + break; +#endif + default: + return -EINVAL; + } + + /* + * Update the cache with the last value we write, the rest is just + * gone down in the hardware FIFO. We can't cache FIFOs. This makes + * sure a single read from the cache will work. + */ + if (write) { + if (!map->cache_bypass && !map->defer_caching) { + ret = regcache_write(map, reg, lastval); + if (ret != 0) + return ret; + if (map->cache_only) { + map->cache_dirty = true; + return 0; + } + } + ret = map->bus->reg_noinc_write(map->bus_context, reg, val, val_count); + } else { + ret = map->bus->reg_noinc_read(map->bus_context, reg, val, val_count); + } + + if (!ret && regmap_should_log(map)) { + dev_info(map->dev, "%x %s [", reg, write ? "<=" : "=>"); + for (i = 0; i < val_len; i++) { + switch (val_bytes) { + case 1: + pr_cont("%x", u8p[i]); + break; + case 2: + pr_cont("%x", u16p[i]); + break; + case 4: + pr_cont("%x", u32p[i]); + break; +#ifdef CONFIG_64BIT + case 8: + pr_cont("%llx", u64p[i]); + break; +#endif + default: + break; + } + if (i == (val_len - 1)) + pr_cont("]\n"); + else + pr_cont(","); + } + } + + return 0; +} + /** * regmap_noinc_write(): Write data from a register without incrementing the * register number @@ -2156,9 +2249,8 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, size_t write_len; int ret; - if (!map->write) - return -ENOTSUPP; - + if (!map->write && !(map->bus && map->bus->reg_noinc_write)) + return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) @@ -2173,6 +2265,15 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, goto out_unlock; } + /* + * Use the accelerated operation if we can. The val drops the const + * typing in order to facilitate code reuse in regmap_noinc_readwrite(). + */ + if (map->bus->reg_noinc_write) { + ret = regmap_noinc_readwrite(map, reg, (void *)val, val_len, true); + goto out_unlock; + } + while (val_len) { if (map->max_raw_write && map->max_raw_write < val_len) write_len = map->max_raw_write; @@ -2943,6 +3044,22 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg, goto out_unlock; } + /* Use the accelerated operation if we can */ + if (map->bus->reg_noinc_read) { + /* + * We have not defined the FIFO semantics for cache, as the + * cache is just one value deep. Should we return the last + * written value? Just avoid this by always reading the FIFO + * even when using cache. Cache only will not work. + */ + if (map->cache_only) { + ret = -EBUSY; + goto out_unlock; + } + ret = regmap_noinc_readwrite(map, reg, val, val_len, false); + goto out_unlock; + } + while (val_len) { if (map->max_raw_read && map->max_raw_read < val_len) read_len = map->max_raw_read; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 8cccc247cd37..ca3434dca3a0 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -492,8 +492,12 @@ typedef int (*regmap_hw_read)(void *context, void *val_buf, size_t val_size); typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg, unsigned int *val); +typedef int (*regmap_hw_reg_noinc_read)(void *context, unsigned int reg, + void *val, size_t val_count); typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg, unsigned int val); +typedef int (*regmap_hw_reg_noinc_write)(void *context, unsigned int reg, + const void *val, size_t val_count); typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg, unsigned int mask, unsigned int val); typedef struct regmap_async *(*regmap_hw_async_alloc)(void); @@ -514,6 +518,8 @@ typedef void (*regmap_hw_free_context)(void *context); * must serialise with respect to non-async I/O. * @reg_write: Write a single register value to the given register address. This * write operation has to complete when returning from the function. + * @reg_write_noinc: Write multiple register value to the same register. This + * write operation has to complete when returning from the function. * @reg_update_bits: Update bits operation to be used against volatile * registers, intended for devices supporting some mechanism * for setting clearing bits without having to @@ -541,9 +547,11 @@ struct regmap_bus { regmap_hw_gather_write gather_write; regmap_hw_async_write async_write; regmap_hw_reg_write reg_write; + regmap_hw_reg_noinc_write reg_noinc_write; regmap_hw_reg_update_bits reg_update_bits; regmap_hw_read read; regmap_hw_reg_read reg_read; + regmap_hw_reg_noinc_read reg_noinc_read; regmap_hw_free_context free_context; regmap_hw_async_alloc async_alloc; u8 read_flag_mask; From 81c0386c1376da54f05d6916936db5220df9f97d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Aug 2022 22:48:32 +0200 Subject: [PATCH 07/18] regmap: mmio: Support accelerared noinc operations 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. The Hexagon architecture turns out to have an incomplete : writesb() is not implemented. Fix this by doing what other architectures do: include into the file. Cc: Brian Cain Cc: linux-hexagon@vger.kernel.org Cc: Arnd Bergmann Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220816204832.265837-2-linus.walleij@linaro.org Signed-off-by: Mark Brown --- arch/hexagon/include/asm/io.h | 2 + drivers/base/regmap/regmap-mmio.c | 162 ++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index c33241425a5c..8e938dc1ca4b 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -308,6 +308,8 @@ static inline void outsl(unsigned long port, const void *buffer, int count) } } +#include + #endif /* __KERNEL__ */ #endif diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index eed488aad1b0..e8d2675463ac 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -16,6 +16,7 @@ struct regmap_mmio_context { void __iomem *regs; unsigned int val_bytes; + bool big_endian; bool attached_clk; struct clk *clk; @@ -165,6 +166,83 @@ 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++) + writew(swab16(valp[i]), ctx->regs + reg); + goto out_clk; + } + case 4: + { + const u32 *valp = (const u32 *)val; + for (i = 0; i < val_count; i++) + writel(swab32(valp[i]), ctx->regs + reg); + goto out_clk; + } +#ifdef CONFIG_64BIT + case 8: + { + const u64 *valp = (const u64 *)val; + for (i = 0; i < val_count; i++) + writeq(swab64(valp[i]), ctx->regs + reg); + goto out_clk; + } +#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) { @@ -262,6 +340,87 @@ 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; + } + + 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; + goto out_clk; + } + + /* + * 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] = swab16(valp[i]); + break; + } + case 4: + { + u32 *valp = (u32 *)val; + for (i = 0; i < val_count; i++) + valp[i] = swab32(valp[i]); + break; + } +#ifdef CONFIG_64BIT + case 8: + { + u64 *valp = (u64 *)val; + for (i = 0; i < val_count; i++) + valp[i] = swab64(valp[i]); + 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; @@ -278,6 +437,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, }; @@ -368,6 +529,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: if (config->io_port) { From f8f60615379c1b36d9220f3886fb9b229e95d8cd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 18 Aug 2022 14:12:27 +0200 Subject: [PATCH 08/18] regmap/hexagon: Properly fix the generic IO helpers I was too naive in just including into hexagon: one has to specify defines for every call that uses a (static) inline or this will not work. Fix it up by providing proper defines for all shorthands that hexagon provides. Compile-tested with hexagon LLVM which is the only working cross compiler for hexagon ATM after commenting out the -fno-inline-functions-called-once switch which isn't working with LLVM. Cc: Brian Cain Cc: linux-hexagon@vger.kernel.org Cc: Arnd Bergmann Fixes: 81c0386c1376 ("regmap: mmio: Support accelerared noinc operations") Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220818121227.151016-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- arch/hexagon/include/asm/io.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index 8e938dc1ca4b..46a099de85b7 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -308,6 +308,29 @@ static inline void outsl(unsigned long port, const void *buffer, int count) } } +/* + * These defines are necessary to use the generic io.h for filling in + * the missing parts of the API contract. This is because the platform + * uses (inline) functions rather than defines and the generic helper + * fills in the undefined. + */ +#define virt_to_phys virt_to_phys +#define phys_to_virt phys_to_virt +#define memset_io memset_io +#define memcpy_fromio memcpy_fromio +#define memcpy_toio memcpy_toio +#define readb readb +#define readw readw +#define readl readl +#define writeb writeb +#define writew writew +#define writel writel +#define insb insb +#define insw insw +#define insl insl +#define outsb outsb +#define outsw outsw +#define outsl outsl #include #endif /* __KERNEL__ */ From 026c99b508f060d3c85fda06b21e010683ef5590 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Tue, 16 Aug 2022 18:14:48 +0000 Subject: [PATCH 09/18] regmap: introduce value tracing for regmap bulk operations Currently, only one-register io operations support tracepoints with value logging. For the regmap bulk operations developer can view hw_start/hw_done tracepoints with starting reg number and registers count to be reading or writing. This patch injects tracepoints with dumping registers values in the hex format to regmap bulk reading and writing. Signed-off-by: Dmitry Rokosov Link: https://lore.kernel.org/r/20220816181451.5628-1-ddrokosov@sberdevices.ru Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 7 ++++++ drivers/base/regmap/trace.h | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 41ff9f18b6a3..63d9c6ab237e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2448,6 +2448,10 @@ out: kfree(wval); } + + if (!ret) + trace_regmap_bulk_write(map, reg, val, val_bytes * val_count); + return ret; } EXPORT_SYMBOL_GPL(regmap_bulk_write); @@ -3209,6 +3213,9 @@ out: map->unlock(map->lock_arg); } + if (!ret) + trace_regmap_bulk_read(map, reg, val, val_bytes * val_count); + return ret; } EXPORT_SYMBOL_GPL(regmap_bulk_read); diff --git a/drivers/base/regmap/trace.h b/drivers/base/regmap/trace.h index 9abee14df9ee..04329ba68ec5 100644 --- a/drivers/base/regmap/trace.h +++ b/drivers/base/regmap/trace.h @@ -64,6 +64,49 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, ); +DECLARE_EVENT_CLASS(regmap_bulk, + + TP_PROTO(struct regmap *map, unsigned int reg, + const void *val, int val_len), + + TP_ARGS(map, reg, val, val_len), + + TP_STRUCT__entry( + __string(name, regmap_name(map)) + __field(unsigned int, reg) + __dynamic_array(char, buf, val_len) + __field(int, val_len) + ), + + TP_fast_assign( + __assign_str(name, regmap_name(map)); + __entry->reg = reg; + __entry->val_len = val_len; + if (val) + memcpy(__get_dynamic_array(buf), val, val_len); + ), + + TP_printk("%s reg=%x val=%s", __get_str(name), + (unsigned int)__entry->reg, + __print_hex(__get_dynamic_array(buf), __entry->val_len)) +); + +DEFINE_EVENT(regmap_bulk, regmap_bulk_write, + + TP_PROTO(struct regmap *map, unsigned int reg, + const void *val, int val_len), + + TP_ARGS(map, reg, val, val_len) +); + +DEFINE_EVENT(regmap_bulk, regmap_bulk_read, + + TP_PROTO(struct regmap *map, unsigned int reg, + const void *val, int val_len), + + TP_ARGS(map, reg, val, val_len) +); + DECLARE_EVENT_CLASS(regmap_block, TP_PROTO(struct regmap *map, unsigned int reg, int count), From b7059927c3e32c96d2ff50c206549d8fac0ba69e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 23 Aug 2022 15:57:00 +0200 Subject: [PATCH 10/18] regmap: check right noinc bounds in debug print We were using the wrong bound in the debug prints: this needs to be the number of elements, not the number of bytes, since we're indexing into an element-size typed array. Fixes: c20cc099b30a ("regmap: Support accelerated noinc operations") Reported-by: Dan Carpenter Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220823135700.265019-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 63d9c6ab237e..c6d6d53e8cd3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2193,7 +2193,7 @@ static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg, if (!ret && regmap_should_log(map)) { dev_info(map->dev, "%x %s [", reg, write ? "<=" : "=>"); - for (i = 0; i < val_len; i++) { + for (i = 0; i < val_count; i++) { switch (val_bytes) { case 1: pr_cont("%x", u8p[i]); @@ -2212,7 +2212,7 @@ static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg, default: break; } - if (i == (val_len - 1)) + if (i == (val_count - 1)) pr_cont("]\n"); else pr_cont(","); From d57f2035c0455dfd5e4d29caa0266fad6febe6d6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Aug 2022 16:13:03 +0200 Subject: [PATCH 11/18] regmap: mmio: Fix rebase error A dangling pointless "ret 0" was left in and some unneeded whitespace can go too. Fixes: 81c0386c1376 ("regmap: mmio: Support accelerared noinc operations") Reported-by: Andy Shevchenko Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220831141303.501548-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index e8d2675463ac..b47ee3e8d050 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -410,14 +410,11 @@ static int regmap_mmio_noinc_read(void *context, unsigned int reg, } } - out_clk: if (!IS_ERR(ctx->clk)) clk_disable(ctx->clk); return ret; - - return 0; } From f78d5e1168e08429bc948d09b6dc11fec5e019f7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 16:23:34 +0300 Subject: [PATCH 12/18] regmap: trace: Remove useless check for NULL for bulk ops If the buffer pointer is NULL we already are in troubles since regmap bulk API expects caller to provide valid parameters, it dereferences that without any checks before we call for traces. Moreover, the current code will print garbage in the case of buffer is NULL and length is not 0. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220901132336.33234-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/trace.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/base/regmap/trace.h b/drivers/base/regmap/trace.h index 04329ba68ec5..e92edc4f4ca5 100644 --- a/drivers/base/regmap/trace.h +++ b/drivers/base/regmap/trace.h @@ -82,8 +82,7 @@ DECLARE_EVENT_CLASS(regmap_bulk, __assign_str(name, regmap_name(map)); __entry->reg = reg; __entry->val_len = val_len; - if (val) - memcpy(__get_dynamic_array(buf), val, val_len); + memcpy(__get_dynamic_array(buf), val, val_len); ), TP_printk("%s reg=%x val=%s", __get_str(name), From d10268a50bdbc03ebb6d340d63bf78c44d7c66a8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 16:23:35 +0300 Subject: [PATCH 13/18] regmap: trace: Remove explicit castings There is no need to have explicit castings to the same type the variables are of. Remove the explicit castings. Signed-off-by: Andy Shevchenko Reviewed-by: Steven Rostedt (Google) Link: https://lore.kernel.org/r/20220901132336.33234-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/trace.h | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/base/regmap/trace.h b/drivers/base/regmap/trace.h index e92edc4f4ca5..a0f83e44a9d1 100644 --- a/drivers/base/regmap/trace.h +++ b/drivers/base/regmap/trace.h @@ -32,9 +32,7 @@ DECLARE_EVENT_CLASS(regmap_reg, __entry->val = val; ), - TP_printk("%s reg=%x val=%x", __get_str(name), - (unsigned int)__entry->reg, - (unsigned int)__entry->val) + TP_printk("%s reg=%x val=%x", __get_str(name), __entry->reg, __entry->val) ); DEFINE_EVENT(regmap_reg, regmap_reg_write, @@ -85,8 +83,7 @@ DECLARE_EVENT_CLASS(regmap_bulk, memcpy(__get_dynamic_array(buf), val, val_len); ), - TP_printk("%s reg=%x val=%s", __get_str(name), - (unsigned int)__entry->reg, + TP_printk("%s reg=%x val=%s", __get_str(name), __entry->reg, __print_hex(__get_dynamic_array(buf), __entry->val_len)) ); @@ -124,9 +121,7 @@ DECLARE_EVENT_CLASS(regmap_block, __entry->count = count; ), - TP_printk("%s reg=%x count=%d", __get_str(name), - (unsigned int)__entry->reg, - (int)__entry->count) + TP_printk("%s reg=%x count=%d", __get_str(name), __entry->reg, __entry->count) ); DEFINE_EVENT(regmap_block, regmap_hw_read_start, @@ -196,8 +191,7 @@ DECLARE_EVENT_CLASS(regmap_bool, __entry->flag = flag; ), - TP_printk("%s flag=%d", __get_str(name), - (int)__entry->flag) + TP_printk("%s flag=%d", __get_str(name), __entry->flag) ); DEFINE_EVENT(regmap_bool, regmap_cache_only, @@ -283,8 +277,7 @@ TRACE_EVENT(regcache_drop_region, __entry->to = to; ), - TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from, - (unsigned int)__entry->to) + TP_printk("%s %u-%u", __get_str(name), __entry->from, __entry->to) ); #endif /* _TRACE_REGMAP_H */ From 6ed406ef9f74372282c3b515e64986120823f769 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 16:23:36 +0300 Subject: [PATCH 14/18] regmap: trace: Remove unneeded blank lines There is a few unneeded blank lines in some of event definitions, remove them in order to make those definitions consistent with the rest. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220901132336.33234-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/trace.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/base/regmap/trace.h b/drivers/base/regmap/trace.h index a0f83e44a9d1..704e106e5dbd 100644 --- a/drivers/base/regmap/trace.h +++ b/drivers/base/regmap/trace.h @@ -41,7 +41,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_write, unsigned int val), TP_ARGS(map, reg, val) - ); DEFINE_EVENT(regmap_reg, regmap_reg_read, @@ -50,7 +49,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read, unsigned int val), TP_ARGS(map, reg, val) - ); DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, @@ -59,7 +57,6 @@ DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, unsigned int val), TP_ARGS(map, reg, val) - ); DECLARE_EVENT_CLASS(regmap_bulk, @@ -199,7 +196,6 @@ DEFINE_EVENT(regmap_bool, regmap_cache_only, TP_PROTO(struct regmap *map, bool flag), TP_ARGS(map, flag) - ); DEFINE_EVENT(regmap_bool, regmap_cache_bypass, @@ -207,7 +203,6 @@ DEFINE_EVENT(regmap_bool, regmap_cache_bypass, TP_PROTO(struct regmap *map, bool flag), TP_ARGS(map, flag) - ); DECLARE_EVENT_CLASS(regmap_async, @@ -239,7 +234,6 @@ DEFINE_EVENT(regmap_async, regmap_async_io_complete, TP_PROTO(struct regmap *map), TP_ARGS(map) - ); DEFINE_EVENT(regmap_async, regmap_async_complete_start, @@ -247,7 +241,6 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_start, TP_PROTO(struct regmap *map), TP_ARGS(map) - ); DEFINE_EVENT(regmap_async, regmap_async_complete_done, @@ -255,7 +248,6 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done, TP_PROTO(struct regmap *map), TP_ARGS(map) - ); TRACE_EVENT(regcache_drop_region, From 2d4697375dea514be202abf563a9419e74489c25 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 00:27:42 +0300 Subject: [PATCH 15/18] swab: Add array operations For now, some simple array operations to swab. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220831212744.56435-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/swab.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/linux/swab.h b/include/linux/swab.h index bcff5149861a..9b804dbb0d79 100644 --- a/include/linux/swab.h +++ b/include/linux/swab.h @@ -20,4 +20,29 @@ # define swab64s __swab64s # define swahw32s __swahw32s # define swahb32s __swahb32s + +static inline void swab16_array(u16 *buf, unsigned int words) +{ + while (words--) { + swab16s(buf); + buf++; + } +} + +static inline void swab32_array(u32 *buf, unsigned int words) +{ + while (words--) { + swab32s(buf); + buf++; + } +} + +static inline void swab64_array(u64 *buf, unsigned int words) +{ + while (words--) { + swab64s(buf); + buf++; + } +} + #endif /* _LINUX_SWAB_H */ From 400dceb6f8b56472b36c5c2c8c3e0cbb7557d019 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 00:27:43 +0300 Subject: [PATCH 16/18] regmap: mmio: Use swabXX_array() helpers Since we have a few helpers to swab elements of a given size in an array use them instead of open coded variants. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220831212744.56435-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index b47ee3e8d050..8bd8d42de3fe 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "internal.h" @@ -345,7 +346,6 @@ static int regmap_mmio_noinc_read(void *context, unsigned int reg, { struct regmap_mmio_context *ctx = context; int ret = 0; - int i; if (!IS_ERR(ctx->clk)) { ret = clk_enable(ctx->clk); @@ -382,27 +382,15 @@ static int regmap_mmio_noinc_read(void *context, unsigned int reg, 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] = swab16(valp[i]); + swab16_array(val, val_count); break; - } case 4: - { - u32 *valp = (u32 *)val; - for (i = 0; i < val_count; i++) - valp[i] = swab32(valp[i]); + swab32_array(val, val_count); break; - } #ifdef CONFIG_64BIT case 8: - { - u64 *valp = (u64 *)val; - for (i = 0; i < val_count; i++) - valp[i] = swab64(valp[i]); + swab64_array(val, val_count); break; - } #endif default: ret = -EINVAL; From 26cc2a788a1903da3ccff97061099f091255ecaf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Sep 2022 00:27:44 +0300 Subject: [PATCH 17/18] regmap: spi-avmm: Use swabXX_array() helpers Since we have a few helpers to swab elements of a given size in an array use them instead of open coded variants. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220831212744.56435-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-spi-avmm.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/base/regmap/regmap-spi-avmm.c b/drivers/base/regmap/regmap-spi-avmm.c index ad1da83e849f..4c2b94b3e30b 100644 --- a/drivers/base/regmap/regmap-spi-avmm.c +++ b/drivers/base/regmap/regmap-spi-avmm.c @@ -7,6 +7,7 @@ #include #include #include +#include /* * This driver implements the regmap operations for a generic SPI @@ -162,19 +163,12 @@ struct spi_avmm_bridge { /* bridge buffer used in translation between protocol layers */ char trans_buf[TRANS_BUF_SIZE]; char phy_buf[PHY_BUF_SIZE]; - void (*swap_words)(char *buf, unsigned int len); + void (*swap_words)(void *buf, unsigned int len); }; -static void br_swap_words_32(char *buf, unsigned int len) +static void br_swap_words_32(void *buf, unsigned int len) { - u32 *p = (u32 *)buf; - unsigned int count; - - count = len / 4; - while (count--) { - *p = swab32p(p); - p++; - } + swab32_array(buf, len / 4); } /* From 01ed230761e51f0403b3f3845c11cb67014487e2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Sep 2022 09:04:45 +0100 Subject: [PATCH 18/18] regmap: mmio: replace return 0 with break in switch statement Variable min_stride is assigned a value that is never read, fix this by replacing the return 0 with a break statement. This also makes the case statement consistent with the other cases in the switch statement. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220922080445.818020-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 8bd8d42de3fe..3ccdd86a97e7 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -48,7 +48,7 @@ static int regmap_mmio_get_min_stride(size_t val_bits) case 8: /* The core treats 0 as 1 */ min_stride = 0; - return 0; + break; case 16: min_stride = 2; break;