Skip to content

Commit 81c0386

Browse files
linuswbroonie
authored andcommitted
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 <asm/io.h>: writesb() is not implemented. Fix this by doing what other architectures do: include <asm-generic/io.h> into the <asm/io.h> file. Cc: Brian Cain <[email protected]> Cc: [email protected] Cc: Arnd Bergmann <[email protected]> Signed-off-by: Linus Walleij <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent c20cc09 commit 81c0386

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

arch/hexagon/include/asm/io.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ static inline void outsl(unsigned long port, const void *buffer, int count)
308308
}
309309
}
310310

311+
#include <asm-generic/io.h>
312+
311313
#endif /* __KERNEL__ */
312314

313315
#endif

drivers/base/regmap/regmap-mmio.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
struct regmap_mmio_context {
1717
void __iomem *regs;
1818
unsigned int val_bytes;
19+
bool big_endian;
1920

2021
bool attached_clk;
2122
struct clk *clk;
@@ -165,6 +166,83 @@ static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
165166
return 0;
166167
}
167168

169+
static int regmap_mmio_noinc_write(void *context, unsigned int reg,
170+
const void *val, size_t val_count)
171+
{
172+
struct regmap_mmio_context *ctx = context;
173+
int ret = 0;
174+
int i;
175+
176+
if (!IS_ERR(ctx->clk)) {
177+
ret = clk_enable(ctx->clk);
178+
if (ret < 0)
179+
return ret;
180+
}
181+
182+
/*
183+
* There are no native, assembly-optimized write single register
184+
* operations for big endian, so fall back to emulation if this
185+
* is needed. (Single bytes are fine, they are not affected by
186+
* endianness.)
187+
*/
188+
if (ctx->big_endian && (ctx->val_bytes > 1)) {
189+
switch (ctx->val_bytes) {
190+
case 2:
191+
{
192+
const u16 *valp = (const u16 *)val;
193+
for (i = 0; i < val_count; i++)
194+
writew(swab16(valp[i]), ctx->regs + reg);
195+
goto out_clk;
196+
}
197+
case 4:
198+
{
199+
const u32 *valp = (const u32 *)val;
200+
for (i = 0; i < val_count; i++)
201+
writel(swab32(valp[i]), ctx->regs + reg);
202+
goto out_clk;
203+
}
204+
#ifdef CONFIG_64BIT
205+
case 8:
206+
{
207+
const u64 *valp = (const u64 *)val;
208+
for (i = 0; i < val_count; i++)
209+
writeq(swab64(valp[i]), ctx->regs + reg);
210+
goto out_clk;
211+
}
212+
#endif
213+
default:
214+
ret = -EINVAL;
215+
goto out_clk;
216+
}
217+
}
218+
219+
switch (ctx->val_bytes) {
220+
case 1:
221+
writesb(ctx->regs + reg, (const u8 *)val, val_count);
222+
break;
223+
case 2:
224+
writesw(ctx->regs + reg, (const u16 *)val, val_count);
225+
break;
226+
case 4:
227+
writesl(ctx->regs + reg, (const u32 *)val, val_count);
228+
break;
229+
#ifdef CONFIG_64BIT
230+
case 8:
231+
writesq(ctx->regs + reg, (const u64 *)val, val_count);
232+
break;
233+
#endif
234+
default:
235+
ret = -EINVAL;
236+
break;
237+
}
238+
239+
out_clk:
240+
if (!IS_ERR(ctx->clk))
241+
clk_disable(ctx->clk);
242+
243+
return ret;
244+
}
245+
168246
static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
169247
unsigned int reg)
170248
{
@@ -262,6 +340,87 @@ static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
262340
return 0;
263341
}
264342

343+
static int regmap_mmio_noinc_read(void *context, unsigned int reg,
344+
void *val, size_t val_count)
345+
{
346+
struct regmap_mmio_context *ctx = context;
347+
int ret = 0;
348+
int i;
349+
350+
if (!IS_ERR(ctx->clk)) {
351+
ret = clk_enable(ctx->clk);
352+
if (ret < 0)
353+
return ret;
354+
}
355+
356+
switch (ctx->val_bytes) {
357+
case 1:
358+
readsb(ctx->regs + reg, (u8 *)val, val_count);
359+
break;
360+
case 2:
361+
readsw(ctx->regs + reg, (u16 *)val, val_count);
362+
break;
363+
case 4:
364+
readsl(ctx->regs + reg, (u32 *)val, val_count);
365+
break;
366+
#ifdef CONFIG_64BIT
367+
case 8:
368+
readsq(ctx->regs + reg, (u64 *)val, val_count);
369+
break;
370+
#endif
371+
default:
372+
ret = -EINVAL;
373+
goto out_clk;
374+
}
375+
376+
/*
377+
* There are no native, assembly-optimized write single register
378+
* operations for big endian, so fall back to emulation if this
379+
* is needed. (Single bytes are fine, they are not affected by
380+
* endianness.)
381+
*/
382+
if (ctx->big_endian && (ctx->val_bytes > 1)) {
383+
switch (ctx->val_bytes) {
384+
case 2:
385+
{
386+
u16 *valp = (u16 *)val;
387+
for (i = 0; i < val_count; i++)
388+
valp[i] = swab16(valp[i]);
389+
break;
390+
}
391+
case 4:
392+
{
393+
u32 *valp = (u32 *)val;
394+
for (i = 0; i < val_count; i++)
395+
valp[i] = swab32(valp[i]);
396+
break;
397+
}
398+
#ifdef CONFIG_64BIT
399+
case 8:
400+
{
401+
u64 *valp = (u64 *)val;
402+
for (i = 0; i < val_count; i++)
403+
valp[i] = swab64(valp[i]);
404+
break;
405+
}
406+
#endif
407+
default:
408+
ret = -EINVAL;
409+
break;
410+
}
411+
}
412+
413+
414+
out_clk:
415+
if (!IS_ERR(ctx->clk))
416+
clk_disable(ctx->clk);
417+
418+
return ret;
419+
420+
return 0;
421+
}
422+
423+
265424
static void regmap_mmio_free_context(void *context)
266425
{
267426
struct regmap_mmio_context *ctx = context;
@@ -278,6 +437,8 @@ static const struct regmap_bus regmap_mmio = {
278437
.fast_io = true,
279438
.reg_write = regmap_mmio_write,
280439
.reg_read = regmap_mmio_read,
440+
.reg_noinc_write = regmap_mmio_noinc_write,
441+
.reg_noinc_read = regmap_mmio_noinc_read,
281442
.free_context = regmap_mmio_free_context,
282443
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
283444
};
@@ -368,6 +529,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
368529
#ifdef __BIG_ENDIAN
369530
case REGMAP_ENDIAN_NATIVE:
370531
#endif
532+
ctx->big_endian = true;
371533
switch (config->val_bits) {
372534
case 8:
373535
if (config->io_port) {

0 commit comments

Comments
 (0)