regmap: implement register striding
regmap_config.reg_stride is introduced. All extant register addresses are a multiple of this value. Users of serial-oriented regmap busses will typically set this to 1. Users of the MMIO regmap bus will typically set this based on the value size of their registers, in bytes, so 4 for a 32-bit register. Throughout the regmap code, actual register addresses are used. Wherever the register address is used to index some array of values, the address is divided by the stride to determine the index, or vice-versa. Error- checking is added to all entry-points for register address data to ensure that register addresses actually satisfy the specified stride. The MMIO bus ensures that the specified stride is large enough for the register size. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:

committed by
Mark Brown

parent
c0cc6fe1d0
commit
f01ee60fff
@@ -39,11 +39,12 @@ struct regcache_rbtree_ctx {
|
||||
};
|
||||
|
||||
static inline void regcache_rbtree_get_base_top_reg(
|
||||
struct regmap *map,
|
||||
struct regcache_rbtree_node *rbnode,
|
||||
unsigned int *base, unsigned int *top)
|
||||
{
|
||||
*base = rbnode->base_reg;
|
||||
*top = rbnode->base_reg + rbnode->blklen - 1;
|
||||
*top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
|
||||
}
|
||||
|
||||
static unsigned int regcache_rbtree_get_register(
|
||||
@@ -70,7 +71,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
|
||||
|
||||
rbnode = rbtree_ctx->cached_rbnode;
|
||||
if (rbnode) {
|
||||
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
|
||||
regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
|
||||
&top_reg);
|
||||
if (reg >= base_reg && reg <= top_reg)
|
||||
return rbnode;
|
||||
}
|
||||
@@ -78,7 +80,8 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
|
||||
node = rbtree_ctx->root.rb_node;
|
||||
while (node) {
|
||||
rbnode = container_of(node, struct regcache_rbtree_node, node);
|
||||
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
|
||||
regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
|
||||
&top_reg);
|
||||
if (reg >= base_reg && reg <= top_reg) {
|
||||
rbtree_ctx->cached_rbnode = rbnode;
|
||||
return rbnode;
|
||||
@@ -92,7 +95,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int regcache_rbtree_insert(struct rb_root *root,
|
||||
static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
|
||||
struct regcache_rbtree_node *rbnode)
|
||||
{
|
||||
struct rb_node **new, *parent;
|
||||
@@ -106,7 +109,7 @@ static int regcache_rbtree_insert(struct rb_root *root,
|
||||
rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
|
||||
node);
|
||||
/* base and top registers of the current rbnode */
|
||||
regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
|
||||
regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
|
||||
&top_reg_tmp);
|
||||
/* base register of the rbnode to be added */
|
||||
base_reg = rbnode->base_reg;
|
||||
@@ -138,7 +141,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
|
||||
unsigned int base, top;
|
||||
int nodes = 0;
|
||||
int registers = 0;
|
||||
int average;
|
||||
int this_registers, average;
|
||||
|
||||
map->lock(map);
|
||||
|
||||
@@ -146,11 +149,12 @@ static int rbtree_show(struct seq_file *s, void *ignored)
|
||||
node = rb_next(node)) {
|
||||
n = container_of(node, struct regcache_rbtree_node, node);
|
||||
|
||||
regcache_rbtree_get_base_top_reg(n, &base, &top);
|
||||
seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1);
|
||||
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
|
||||
this_registers = ((top - base) / map->reg_stride) + 1;
|
||||
seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
|
||||
|
||||
nodes++;
|
||||
registers += top - base + 1;
|
||||
registers += this_registers;
|
||||
}
|
||||
|
||||
if (nodes)
|
||||
@@ -255,7 +259,7 @@ static int regcache_rbtree_read(struct regmap *map,
|
||||
|
||||
rbnode = regcache_rbtree_lookup(map, reg);
|
||||
if (rbnode) {
|
||||
reg_tmp = reg - rbnode->base_reg;
|
||||
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
|
||||
*value = regcache_rbtree_get_register(rbnode, reg_tmp,
|
||||
map->cache_word_size);
|
||||
} else {
|
||||
@@ -310,7 +314,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||
*/
|
||||
rbnode = regcache_rbtree_lookup(map, reg);
|
||||
if (rbnode) {
|
||||
reg_tmp = reg - rbnode->base_reg;
|
||||
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
|
||||
val = regcache_rbtree_get_register(rbnode, reg_tmp,
|
||||
map->cache_word_size);
|
||||
if (val == value)
|
||||
@@ -321,13 +325,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||
/* look for an adjacent register to the one we are about to add */
|
||||
for (node = rb_first(&rbtree_ctx->root); node;
|
||||
node = rb_next(node)) {
|
||||
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node);
|
||||
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
|
||||
node);
|
||||
for (i = 0; i < rbnode_tmp->blklen; i++) {
|
||||
reg_tmp = rbnode_tmp->base_reg + i;
|
||||
if (abs(reg_tmp - reg) != 1)
|
||||
reg_tmp = rbnode_tmp->base_reg +
|
||||
(i * map->reg_stride);
|
||||
if (abs(reg_tmp - reg) != map->reg_stride)
|
||||
continue;
|
||||
/* decide where in the block to place our register */
|
||||
if (reg_tmp + 1 == reg)
|
||||
if (reg_tmp + map->reg_stride == reg)
|
||||
pos = i + 1;
|
||||
else
|
||||
pos = i;
|
||||
@@ -357,7 +363,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||
return -ENOMEM;
|
||||
}
|
||||
regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
|
||||
regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
|
||||
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
|
||||
rbtree_ctx->cached_rbnode = rbnode;
|
||||
}
|
||||
|
||||
@@ -397,7 +403,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
|
||||
end = rbnode->blklen;
|
||||
|
||||
for (i = base; i < end; i++) {
|
||||
regtmp = rbnode->base_reg + i;
|
||||
regtmp = rbnode->base_reg + (i * map->reg_stride);
|
||||
val = regcache_rbtree_get_register(rbnode, i,
|
||||
map->cache_word_size);
|
||||
|
||||
|
Reference in New Issue
Block a user