Skip to content

Commit c20cc09

Browse files
linuswbroonie
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 77672e0 commit c20cc09

File tree

2 files changed

+128
-3
lines changed

2 files changed

+128
-3
lines changed

drivers/base/regmap/regmap.c

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,99 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
21292129
}
21302130
EXPORT_SYMBOL_GPL(regmap_raw_write);
21312131

2132+
static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg,
2133+
void *val, unsigned int val_len, bool write)
2134+
{
2135+
size_t val_bytes = map->format.val_bytes;
2136+
size_t val_count = val_len / val_bytes;
2137+
unsigned int lastval;
2138+
u8 *u8p;
2139+
u16 *u16p;
2140+
u32 *u32p;
2141+
#ifdef CONFIG_64BIT
2142+
u64 *u64p;
2143+
#endif
2144+
int ret;
2145+
int i;
2146+
2147+
switch (val_bytes) {
2148+
case 1:
2149+
u8p = val;
2150+
if (write)
2151+
lastval = (unsigned int)u8p[val_count - 1];
2152+
break;
2153+
case 2:
2154+
u16p = val;
2155+
if (write)
2156+
lastval = (unsigned int)u16p[val_count - 1];
2157+
break;
2158+
case 4:
2159+
u32p = val;
2160+
if (write)
2161+
lastval = (unsigned int)u32p[val_count - 1];
2162+
break;
2163+
#ifdef CONFIG_64BIT
2164+
case 8:
2165+
u64p = val;
2166+
if (write)
2167+
lastval = (unsigned int)u64p[val_count - 1];
2168+
break;
2169+
#endif
2170+
default:
2171+
return -EINVAL;
2172+
}
2173+
2174+
/*
2175+
* Update the cache with the last value we write, the rest is just
2176+
* gone down in the hardware FIFO. We can't cache FIFOs. This makes
2177+
* sure a single read from the cache will work.
2178+
*/
2179+
if (write) {
2180+
if (!map->cache_bypass && !map->defer_caching) {
2181+
ret = regcache_write(map, reg, lastval);
2182+
if (ret != 0)
2183+
return ret;
2184+
if (map->cache_only) {
2185+
map->cache_dirty = true;
2186+
return 0;
2187+
}
2188+
}
2189+
ret = map->bus->reg_noinc_write(map->bus_context, reg, val, val_count);
2190+
} else {
2191+
ret = map->bus->reg_noinc_read(map->bus_context, reg, val, val_count);
2192+
}
2193+
2194+
if (!ret && regmap_should_log(map)) {
2195+
dev_info(map->dev, "%x %s [", reg, write ? "<=" : "=>");
2196+
for (i = 0; i < val_len; i++) {
2197+
switch (val_bytes) {
2198+
case 1:
2199+
pr_cont("%x", u8p[i]);
2200+
break;
2201+
case 2:
2202+
pr_cont("%x", u16p[i]);
2203+
break;
2204+
case 4:
2205+
pr_cont("%x", u32p[i]);
2206+
break;
2207+
#ifdef CONFIG_64BIT
2208+
case 8:
2209+
pr_cont("%llx", u64p[i]);
2210+
break;
2211+
#endif
2212+
default:
2213+
break;
2214+
}
2215+
if (i == (val_len - 1))
2216+
pr_cont("]\n");
2217+
else
2218+
pr_cont(",");
2219+
}
2220+
}
2221+
2222+
return 0;
2223+
}
2224+
21322225
/**
21332226
* regmap_noinc_write(): Write data from a register without incrementing the
21342227
* register number
@@ -2156,9 +2249,8 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
21562249
size_t write_len;
21572250
int ret;
21582251

2159-
if (!map->write)
2160-
return -ENOTSUPP;
2161-
2252+
if (!map->write && !(map->bus && map->bus->reg_noinc_write))
2253+
return -EINVAL;
21622254
if (val_len % map->format.val_bytes)
21632255
return -EINVAL;
21642256
if (!IS_ALIGNED(reg, map->reg_stride))
@@ -2173,6 +2265,15 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
21732265
goto out_unlock;
21742266
}
21752267

2268+
/*
2269+
* Use the accelerated operation if we can. The val drops the const
2270+
* typing in order to facilitate code reuse in regmap_noinc_readwrite().
2271+
*/
2272+
if (map->bus->reg_noinc_write) {
2273+
ret = regmap_noinc_readwrite(map, reg, (void *)val, val_len, true);
2274+
goto out_unlock;
2275+
}
2276+
21762277
while (val_len) {
21772278
if (map->max_raw_write && map->max_raw_write < val_len)
21782279
write_len = map->max_raw_write;
@@ -2943,6 +3044,22 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
29433044
goto out_unlock;
29443045
}
29453046

3047+
/* Use the accelerated operation if we can */
3048+
if (map->bus->reg_noinc_read) {
3049+
/*
3050+
* We have not defined the FIFO semantics for cache, as the
3051+
* cache is just one value deep. Should we return the last
3052+
* written value? Just avoid this by always reading the FIFO
3053+
* even when using cache. Cache only will not work.
3054+
*/
3055+
if (map->cache_only) {
3056+
ret = -EBUSY;
3057+
goto out_unlock;
3058+
}
3059+
ret = regmap_noinc_readwrite(map, reg, val, val_len, false);
3060+
goto out_unlock;
3061+
}
3062+
29463063
while (val_len) {
29473064
if (map->max_raw_read && map->max_raw_read < val_len)
29483065
read_len = map->max_raw_read;

include/linux/regmap.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,12 @@ typedef int (*regmap_hw_read)(void *context,
492492
void *val_buf, size_t val_size);
493493
typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
494494
unsigned int *val);
495+
typedef int (*regmap_hw_reg_noinc_read)(void *context, unsigned int reg,
496+
void *val, size_t val_count);
495497
typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
496498
unsigned int val);
499+
typedef int (*regmap_hw_reg_noinc_write)(void *context, unsigned int reg,
500+
const void *val, size_t val_count);
497501
typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg,
498502
unsigned int mask, unsigned int val);
499503
typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
@@ -514,6 +518,8 @@ typedef void (*regmap_hw_free_context)(void *context);
514518
* must serialise with respect to non-async I/O.
515519
* @reg_write: Write a single register value to the given register address. This
516520
* write operation has to complete when returning from the function.
521+
* @reg_write_noinc: Write multiple register value to the same register. This
522+
* write operation has to complete when returning from the function.
517523
* @reg_update_bits: Update bits operation to be used against volatile
518524
* registers, intended for devices supporting some mechanism
519525
* for setting clearing bits without having to
@@ -541,9 +547,11 @@ struct regmap_bus {
541547
regmap_hw_gather_write gather_write;
542548
regmap_hw_async_write async_write;
543549
regmap_hw_reg_write reg_write;
550+
regmap_hw_reg_noinc_write reg_noinc_write;
544551
regmap_hw_reg_update_bits reg_update_bits;
545552
regmap_hw_read read;
546553
regmap_hw_reg_read reg_read;
554+
regmap_hw_reg_noinc_read reg_noinc_read;
547555
regmap_hw_free_context free_context;
548556
regmap_hw_async_alloc async_alloc;
549557
u8 read_flag_mask;

0 commit comments

Comments
 (0)