Commit e795e5f4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regmap-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "There's no real overall theme to the regmap changes for this release,
  it's a collection of individual features.  The main bits are:

   - Support for 64 bit registers, mainly for MMIO use, from Xiubo Li.

   - Support for trigger type configuration for regmap-irq from Laxman
     Dewangan.

   - Use native physical I/O for MMIO register maps to avoid confusion
     with the conversions that readl() and writel() do to little endian
     on big endian systems (with some DT updates to fix some workarounds
     people were doing), code from Simon Arlott.

   - Use a binary search rather than iteraton to improve the runtime
     performance of the rbtree code from Nikesh Oswal"

* tag 'regmap-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: debugfs: Use seq_file for the access map
  regmap: irq: add support for configuration of trigger type
  regmap: use IS_ALIGNED instead of % to improve the performance
  regmap: cache: Move the num_reg_defaults check as early as possible
  regmap: cache: Add warning info for the cache check
  regmap: missing case statement
  regmap: shift wrapping bugs in 64 bit code
  regmap: cache: Add 64-bit mode support
  regmap: cache: To suppress the noise of checkpatch
  regmap: fix the warning about unused variable
  regmap: add 64-bit mode support
  regmap: mmio: Add regmap_mmio_get_min_stride
  regmap: mmio: remove the useless code
  regmap: Fix leftover from struct reg_default to struct reg_sequence change
  regmap: replace kmalloc with kmalloc_array
  regmap: replace kzalloc with kcalloc
  regmap: rbtree: When adding a reg do a bsearch for target node
  regmap-mmio: Use native endianness for read/write
parents 581dbc8b 6cb07abc
......@@ -73,7 +73,6 @@
timer: timer@10000040 {
compatible = "syscon";
reg = <0x10000040 0x2c>;
little-endian;
};
reboot {
......
......@@ -98,7 +98,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>;
little-endian;
};
reboot {
......
......@@ -118,7 +118,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
little-endian;
};
reboot {
......
......@@ -112,7 +112,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
little-endian;
};
reboot {
......
......@@ -112,7 +112,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
little-endian;
};
reboot {
......
......@@ -118,7 +118,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
little-endian;
};
reboot {
......
......@@ -99,7 +99,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>;
little-endian;
};
reboot {
......
......@@ -100,7 +100,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
little-endian;
};
reboot {
......
......@@ -114,7 +114,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
little-endian;
};
reboot {
......
......@@ -21,7 +21,7 @@ static int regcache_flat_init(struct regmap *map)
int i;
unsigned int *cache;
map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1),
map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
GFP_KERNEL);
if (!map->cache)
return -ENOMEM;
......
......@@ -139,7 +139,7 @@ static int regcache_lzo_init(struct regmap *map)
ret = 0;
blkcount = regcache_lzo_block_count(map);
map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
map->cache = kcalloc(blkcount, sizeof(*lzo_blocks),
GFP_KERNEL);
if (!map->cache)
return -ENOMEM;
......@@ -152,8 +152,8 @@ static int regcache_lzo_init(struct regmap *map)
* that register.
*/
bmp_size = map->num_reg_defaults_raw;
sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
GFP_KERNEL);
sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long),
GFP_KERNEL);
if (!sync_bmp) {
ret = -ENOMEM;
goto err;
......
......@@ -361,13 +361,14 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
rbnode->base_reg = reg;
}
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
GFP_KERNEL);
rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
GFP_KERNEL);
if (!rbnode->block)
goto err_free;
rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) *
sizeof(*rbnode->cache_present), GFP_KERNEL);
rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
sizeof(*rbnode->cache_present),
GFP_KERNEL);
if (!rbnode->cache_present)
goto err_free_block;
......@@ -413,8 +414,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
max = reg + max_dist;
/* 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)) {
node = rbtree_ctx->root.rb_node;
while (node) {
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
node);
......@@ -425,6 +426,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
new_base_reg = min(reg, base_reg);
new_top_reg = max(reg, top_reg);
} else {
if (max < base_reg)
node = node->rb_left;
else
node = node->rb_right;
continue;
}
......
......@@ -100,15 +100,25 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
int i;
void *tmp_buf;
for (i = 0; i < config->num_reg_defaults; i++)
if (config->reg_defaults[i].reg % map->reg_stride)
return -EINVAL;
if (map->cache_type == REGCACHE_NONE) {
if (config->reg_defaults || config->num_reg_defaults_raw)
dev_warn(map->dev,
"No cache used with register defaults set!\n");
map->cache_bypass = true;
return 0;
}
if (config->reg_defaults && !config->num_reg_defaults) {
dev_err(map->dev,
"Register defaults are set without the number!\n");
return -EINVAL;
}
for (i = 0; i < config->num_reg_defaults; i++)
if (config->reg_defaults[i].reg % map->reg_stride)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(cache_types); i++)
if (cache_types[i]->type == map->cache_type)
break;
......@@ -138,8 +148,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
* a copy of it.
*/
if (config->reg_defaults) {
if (!map->num_reg_defaults)
return -EINVAL;
tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
sizeof(struct reg_default), GFP_KERNEL);
if (!tmp_buf)
......@@ -535,19 +543,30 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
switch (map->cache_word_size) {
case 1: {
u8 *cache = base;
cache[idx] = val;
break;
}
case 2: {
u16 *cache = base;
cache[idx] = val;
break;
}
case 4: {
u32 *cache = base;
cache[idx] = val;
break;
}
#ifdef CONFIG_64BIT
case 8: {
u64 *cache = base;
cache[idx] = val;
break;
}
#endif
default:
BUG();
}
......@@ -568,16 +587,26 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
switch (map->cache_word_size) {
case 1: {
const u8 *cache = base;
return cache[idx];
}
case 2: {
const u16 *cache = base;
return cache[idx];
}
case 4: {
const u32 *cache = base;
return cache[idx];
}
#ifdef CONFIG_64BIT
case 8: {
const u64 *cache = base;
return cache[idx];
}
#endif
default:
BUG();
}
......
......@@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = {
.llseek = default_llseek,
};
static ssize_t regmap_access_read_file(struct file *file,
char __user *user_buf, size_t count,
loff_t *ppos)
static int regmap_access_show(struct seq_file *s, void *ignored)
{
int reg_len, tot_len;
size_t buf_pos = 0;
loff_t p = 0;
ssize_t ret;
int i;
struct regmap *map = file->private_data;
char *buf;
if (*ppos < 0 || !count)
return -EINVAL;
struct regmap *map = s->private;
int i, reg_len;
buf = kmalloc(count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Calculate the length of a fixed format */
reg_len = regmap_calc_reg_len(map->max_register);
tot_len = reg_len + 10; /* ': R W V P\n' */
for (i = 0; i <= map->max_register; i += map->reg_stride) {
/* Ignore registers which are neither readable nor writable */
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
continue;
/* If we're in the region the user is trying to read */
if (p >= *ppos) {
/* ...but not beyond it */
if (buf_pos + tot_len + 1 >= count)
break;
/* Format the register */
snprintf(buf + buf_pos, count - buf_pos,
"%.*x: %c %c %c %c\n",
reg_len, i,
regmap_readable(map, i) ? 'y' : 'n',
regmap_writeable(map, i) ? 'y' : 'n',
regmap_volatile(map, i) ? 'y' : 'n',
regmap_precious(map, i) ? 'y' : 'n');
buf_pos += tot_len;
}
p += tot_len;
}
ret = buf_pos;
if (copy_to_user(user_buf, buf, buf_pos)) {
ret = -EFAULT;
goto out;
/* Format the register */
seq_printf(s, "%.*x: %c %c %c %c\n", reg_len, i,
regmap_readable(map, i) ? 'y' : 'n',
regmap_writeable(map, i) ? 'y' : 'n',
regmap_volatile(map, i) ? 'y' : 'n',
regmap_precious(map, i) ? 'y' : 'n');
}
*ppos += buf_pos;
return 0;
}
out:
kfree(buf);
return ret;
static int access_open(struct inode *inode, struct file *file)
{
return single_open(file, regmap_access_show, inode->i_private);
}
static const struct file_operations regmap_access_fops = {
.open = simple_open,
.read = regmap_access_read_file,
.llseek = default_llseek,
.open = access_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static ssize_t regmap_cache_only_write_file(struct file *file,
......
......@@ -39,8 +39,11 @@ struct regmap_irq_chip_data {
unsigned int *mask_buf;
unsigned int *mask_buf_def;
unsigned int *wake_buf;
unsigned int *type_buf;
unsigned int *type_buf_def;
unsigned int irq_reg_stride;
unsigned int type_reg_stride;
};
static inline const
......@@ -144,6 +147,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
}
}
for (i = 0; i < d->chip->num_type_reg; i++) {
if (!d->type_buf_def[i])
continue;
reg = d->chip->type_base +
(i * map->reg_stride * d->type_reg_stride);
if (d->chip->type_invert)
ret = regmap_update_bits(d->map, reg,
d->type_buf_def[i], ~d->type_buf[i]);
else
ret = regmap_update_bits(d->map, reg,
d->type_buf_def[i], d->type_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync type in %x\n",
reg);
}
if (d->chip->runtime_pm)
pm_runtime_put(map->dev);
......@@ -178,6 +197,38 @@ static void regmap_irq_disable(struct irq_data *data)
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
}
static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
int reg = irq_data->type_reg_offset / map->reg_stride;
if (!(irq_data->type_rising_mask | irq_data->type_falling_mask))
return 0;
d->type_buf[reg] &= ~(irq_data->type_falling_mask |
irq_data->type_rising_mask);
switch (type) {
case IRQ_TYPE_EDGE_FALLING:
d->type_buf[reg] |= irq_data->type_falling_mask;
break;
case IRQ_TYPE_EDGE_RISING:
d->type_buf[reg] |= irq_data->type_rising_mask;
break;
case IRQ_TYPE_EDGE_BOTH:
d->type_buf[reg] |= (irq_data->type_falling_mask |
irq_data->type_rising_mask);
break;
default:
return -EINVAL;
}
return 0;
}
static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
......@@ -204,6 +255,7 @@ static const struct irq_chip regmap_irq_chip = {
.irq_bus_sync_unlock = regmap_irq_sync_unlock,
.irq_disable = regmap_irq_disable,
.irq_enable = regmap_irq_enable,
.irq_set_type = regmap_irq_set_type,
.irq_set_wake = regmap_irq_set_wake,
};
......@@ -386,28 +438,40 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d)
return -ENOMEM;
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->status_buf)
goto err_alloc;
d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->mask_buf)
goto err_alloc;
d->mask_buf_def = kzalloc(sizeof(unsigned int) * chip->num_regs,
d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->mask_buf_def)
goto err_alloc;
if (chip->wake_base) {
d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->wake_buf)
goto err_alloc;
}
if (chip->num_type_reg) {
d->type_buf_def = kcalloc(chip->num_type_reg,
sizeof(unsigned int), GFP_KERNEL);
if (!d->type_buf_def)
goto err_alloc;
d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
GFP_KERNEL);
if (!d->type_buf)
goto err_alloc;
}
d->irq_chip = regmap_irq_chip;
d->irq_chip.name = chip->name;
d->irq = irq;
......@@ -420,10 +484,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
else
d->irq_reg_stride = 1;
if (chip->type_reg_stride)
d->type_reg_stride = chip->type_reg_stride;
else
d->type_reg_stride = 1;
if (!map->use_single_read && map->reg_stride == 1 &&
d->irq_reg_stride == 1) {
d->status_reg_buf = kmalloc(map->format.val_bytes *
chip->num_regs, GFP_KERNEL);
d->status_reg_buf = kmalloc_array(chip->num_regs,
map->format.val_bytes,
GFP_KERNEL);
if (!d->status_reg_buf)
goto err_alloc;
}
......@@ -511,6 +581,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
}
}
if (chip->num_type_reg) {
for (i = 0; i < chip->num_irqs; i++) {
reg = chip->irqs[i].type_reg_offset / map->reg_stride;
d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |
chip->irqs[i].type_falling_mask;
}
for (i = 0; i < chip->num_type_reg; ++i) {
if (!d->type_buf_def[i])
continue;
reg = chip->type_base +
(i * map->reg_stride * d->type_reg_stride);
if (chip->type_invert)
ret = regmap_update_bits(map, reg,
d->type_buf_def[i], 0xFF);
else
ret = regmap_update_bits(map, reg,
d->type_buf_def[i], 0x0);
if (ret != 0) {
dev_err(map->dev,
"Failed to set type in 0x%x: %x\n",
reg, ret);
goto err_alloc;
}
}
}
if (irq_base)
d->domain = irq_domain_add_legacy(map->dev->of_node,
chip->num_irqs, irq_base, 0,
......@@ -541,6 +638,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
err_domain:
/* Should really dispose of the domain but... */
err_alloc:
kfree(d->type_buf);
kfree(d->type_buf_def);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
......@@ -564,6 +663,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
free_irq(irq, d);
irq_domain_remove(d->domain);
kfree(d->type_buf);
kfree(d->type_buf_def);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
......
......@@ -61,6 +61,33 @@ static int regmap_mmio_regbits_check(size_t reg_bits)
}
}
static int regmap_mmio_get_min_stride(size_t val_bits)
{
int min_stride;
switch (val_bits) {
case 8:
/* The core treats 0 as 1 */
min_stride = 0;
return 0;
case 16:
min_stride = 2;
break;
case 32:
min_stride = 4;
break;
#ifdef CONFIG_64BIT
case 64:
min_stride = 8;
break;
#endif
default:
return -EINVAL;
}
return min_stride;
}
static inline void regmap_mmio_count_check(size_t count, u32 offset)
{
BUG_ON(count <= offset);
......@@ -106,17 +133,17 @@ static int regmap_mmio_gather_write(void *context,
while (val_size) {
switch (ctx->val_bytes) {
case 1:
writeb(*(u8 *)val, ctx->regs + offset);
__raw_writeb(*(u8 *)val, ctx->regs + offset);
break;
case 2:
writew(*(u16 *)val, ctx->regs + offset);
__raw_writew(*(u16 *)val, ctx->regs + offset);
break;
case 4:
writel(*(u32 *)val, ctx->regs + offset);
__raw_writel(*(u32 *)val, ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
writeq(*(u64 *)val, ctx->regs + offset);
__raw_writeq(*(u64 *)val, ctx->regs + offset);
break;
#endif
default:
......@@ -166,17 +193,17 @@ static int regmap_mmio_read(void *context,
while (val_size) {
switch (ctx->val_bytes) {
case 1:
*(u8 *)val = readb(ctx->regs + offset);
*(u8 *)val = __raw_readb(ctx->regs + offset);
break;
case 2:
*(u16 *)val = readw(ctx->regs + offset);
*(u16 *)val = __raw_readw(ctx->regs + offset);
break;
case 4:
*(u32 *)val = readl(ctx->regs + offset);
*(u32 *)val = __raw_readl(ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
*(u64 *)val = readq(ctx->regs + offset);
*(u64 *)val = __raw_readq(ctx->regs + offset);
break;
#endif
default:
......@@ -231,26 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
if (config->pad_bits)
return ERR_PTR(-EINVAL);
switch (config->val_bits) {
case 8:
/* The core treats 0 as 1 */
min_stride = 0;
break;
case 16:
min_stride = 2;
break;
case 32:
min_stride = 4;
break;
#ifdef CONFIG_64BIT
case 64:
min_stride = 8;
break;
#endif
break;
default:
return ERR_PTR(-EINVAL);
}
min_stride = regmap_mmio_get_min_stride(config->val_bits);
if (min_stride < 0)
return ERR_PTR(min_stride);
if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL);
......
......@@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val,
*(u32 *)buf = val << shift;
}
#ifdef CONFIG_64BIT
static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
{
__be64 *b = buf;
b[0] = cpu_to_be64((u64)val << shift);
}
static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
{
__le64 *b = buf;
b[0] = cpu_to_le64((u64)val << shift);
}
static void regmap_format_64_native(void *buf, unsigned int val,
unsigned int shift)
{
*(u64 *)buf = (u64)val << shift;
}
#endif
static void regmap_parse_inplace_noop(void *buf)
{
}
......@@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *buf)
return *(u32 *)buf;
}
#ifdef CONFIG_64BIT
static unsigned int regmap_parse_64_be(const void *buf)
{
const __be64 *b = buf;
return be64_to_cpu(b[0]);
}
static unsigned int regmap_parse_64_le(const void *buf)
{
const __le64 *b = buf;
return le64_to_cpu(b[0]);
}
static void regmap_parse_64_be_inplace(void *buf)
{
__be64 *b = buf;
b[0] = be64_to_cpu(b[0]);
}
static void regmap_parse_64_le_inplace(void *buf)
{
__le64 *b = buf;
b[0] = le64_to_cpu(b[0]);
}
static unsigned int regmap_parse_64_native(const void *buf)
{
return *(u64 *)buf;
}
#endif