Merge remote-tracking branch 'regmap/topic/mmio' into regmap-next
This commit is contained in:
Коммит
781aab8457
|
@ -5,15 +5,18 @@ Index Device Endianness properties
|
|||
---------------------------------------------------
|
||||
1 BE 'big-endian'
|
||||
2 LE 'little-endian'
|
||||
3 Native 'native-endian'
|
||||
|
||||
For one device driver, which will run in different scenarios above
|
||||
on different SoCs using the devicetree, we need one way to simplify
|
||||
this.
|
||||
|
||||
Required properties:
|
||||
- {big,little}-endian: these are boolean properties, if absent
|
||||
meaning that the CPU and the Device are in the same endianness mode,
|
||||
these properties are for register values and all the buffers only.
|
||||
Optional properties:
|
||||
- {big,little,native}-endian: these are boolean properties, if absent
|
||||
then the implementation will choose a default based on the device
|
||||
being controlled. These properties are for register values and all
|
||||
the buffers only. Native endian means that the CPU and device have
|
||||
the same endianness.
|
||||
|
||||
Examples:
|
||||
Scenario 1 : CPU in LE mode & device in LE mode.
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
timer: timer@10000040 {
|
||||
compatible = "syscon";
|
||||
reg = <0x10000040 0x2c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
periph_cntl: syscon@10000000 {
|
||||
compatible = "syscon";
|
||||
reg = <0x10000000 0x14>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot: syscon-reboot@10000008 {
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x60c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x60c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
sun_top_ctrl: syscon@404000 {
|
||||
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
|
||||
reg = <0x404000 0x51c>;
|
||||
little-endian;
|
||||
native-endian;
|
||||
};
|
||||
|
||||
reboot {
|
||||
|
|
|
@ -30,7 +30,7 @@ static int regcache_hw_init(struct regmap *map)
|
|||
int i, j;
|
||||
int ret;
|
||||
int count;
|
||||
unsigned int val;
|
||||
unsigned int reg, val;
|
||||
void *tmp_buf;
|
||||
|
||||
if (!map->num_reg_defaults_raw)
|
||||
|
@ -67,27 +67,46 @@ static int regcache_hw_init(struct regmap *map)
|
|||
ret = regmap_raw_read(map, 0, tmp_buf,
|
||||
map->cache_size_raw);
|
||||
map->cache_bypass = cache_bypass;
|
||||
if (ret < 0)
|
||||
goto err_cache_free;
|
||||
|
||||
map->reg_defaults_raw = tmp_buf;
|
||||
map->cache_free = 1;
|
||||
if (ret == 0) {
|
||||
map->reg_defaults_raw = tmp_buf;
|
||||
map->cache_free = 1;
|
||||
} else {
|
||||
kfree(tmp_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* fill the reg_defaults */
|
||||
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
|
||||
if (regmap_volatile(map, i * map->reg_stride))
|
||||
reg = i * map->reg_stride;
|
||||
|
||||
if (!regmap_readable(map, reg))
|
||||
continue;
|
||||
val = regcache_get_val(map, map->reg_defaults_raw, i);
|
||||
map->reg_defaults[j].reg = i * map->reg_stride;
|
||||
|
||||
if (regmap_volatile(map, reg))
|
||||
continue;
|
||||
|
||||
if (map->reg_defaults_raw) {
|
||||
val = regcache_get_val(map, map->reg_defaults_raw, i);
|
||||
} else {
|
||||
bool cache_bypass = map->cache_bypass;
|
||||
|
||||
map->cache_bypass = true;
|
||||
ret = regmap_read(map, reg, &val);
|
||||
map->cache_bypass = cache_bypass;
|
||||
if (ret != 0) {
|
||||
dev_err(map->dev, "Failed to read %d: %d\n",
|
||||
reg, ret);
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
||||
map->reg_defaults[j].reg = reg;
|
||||
map->reg_defaults[j].def = val;
|
||||
j++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_cache_free:
|
||||
kfree(tmp_buf);
|
||||
err_free:
|
||||
kfree(map->reg_defaults);
|
||||
|
||||
|
|
|
@ -25,26 +25,14 @@
|
|||
|
||||
struct regmap_mmio_context {
|
||||
void __iomem *regs;
|
||||
unsigned reg_bytes;
|
||||
unsigned val_bytes;
|
||||
unsigned pad_bytes;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline void regmap_mmio_regsize_check(size_t reg_size)
|
||||
{
|
||||
switch (reg_size) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
void (*reg_write)(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg, unsigned int val);
|
||||
unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg);
|
||||
};
|
||||
|
||||
static int regmap_mmio_regbits_check(size_t reg_bits)
|
||||
{
|
||||
|
@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits)
|
|||
return min_stride;
|
||||
}
|
||||
|
||||
static inline void regmap_mmio_count_check(size_t count, u32 offset)
|
||||
static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
BUG_ON(count <= offset);
|
||||
writeb(val, ctx->regs + reg);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
regmap_mmio_get_offset(const void *reg, size_t reg_size)
|
||||
static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
switch (reg_size) {
|
||||
case 1:
|
||||
return *(u8 *)reg;
|
||||
case 2:
|
||||
return *(u16 *)reg;
|
||||
case 4:
|
||||
return *(u32 *)reg;
|
||||
writew(val, ctx->regs + reg);
|
||||
}
|
||||
|
||||
static void regmap_mmio_write16be(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)
|
||||
{
|
||||
writel(val, ctx->regs + reg);
|
||||
}
|
||||
|
||||
static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
iowrite32be(val, ctx->regs + reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
return *(u64 *)reg;
|
||||
#endif
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
writeq(val, ctx->regs + reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int regmap_mmio_gather_write(void *context,
|
||||
const void *reg, size_t reg_size,
|
||||
const void *val, size_t val_size)
|
||||
static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct regmap_mmio_context *ctx = context;
|
||||
unsigned int offset;
|
||||
int ret;
|
||||
|
||||
regmap_mmio_regsize_check(reg_size);
|
||||
|
||||
if (!IS_ERR(ctx->clk)) {
|
||||
ret = clk_enable(ctx->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
offset = regmap_mmio_get_offset(reg, reg_size);
|
||||
|
||||
while (val_size) {
|
||||
switch (ctx->val_bytes) {
|
||||
case 1:
|
||||
writeb(*(u8 *)val, ctx->regs + offset);
|
||||
break;
|
||||
case 2:
|
||||
writew(*(u16 *)val, ctx->regs + offset);
|
||||
break;
|
||||
case 4:
|
||||
writel(*(u32 *)val, ctx->regs + offset);
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
writeq(*(u64 *)val, ctx->regs + offset);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Should be caught by regmap_mmio_check_config */
|
||||
BUG();
|
||||
}
|
||||
val_size -= ctx->val_bytes;
|
||||
val += ctx->val_bytes;
|
||||
offset += ctx->val_bytes;
|
||||
}
|
||||
ctx->reg_write(ctx, reg, val);
|
||||
|
||||
if (!IS_ERR(ctx->clk))
|
||||
clk_disable(ctx->clk);
|
||||
|
@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int regmap_mmio_write(void *context, const void *data, size_t count)
|
||||
static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct regmap_mmio_context *ctx = context;
|
||||
unsigned int offset = ctx->reg_bytes + ctx->pad_bytes;
|
||||
|
||||
regmap_mmio_count_check(count, offset);
|
||||
|
||||
return regmap_mmio_gather_write(context, data, ctx->reg_bytes,
|
||||
data + offset, count - offset);
|
||||
return readb(ctx->regs + reg);
|
||||
}
|
||||
|
||||
static int regmap_mmio_read(void *context,
|
||||
const void *reg, size_t reg_size,
|
||||
void *val, size_t val_size)
|
||||
static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg)
|
||||
{
|
||||
return readw(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_read32le(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg)
|
||||
{
|
||||
return readl(ctx->regs + reg);
|
||||
}
|
||||
|
||||
static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
|
||||
unsigned int reg)
|
||||
{
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct regmap_mmio_context *ctx = context;
|
||||
unsigned int offset;
|
||||
int ret;
|
||||
|
||||
regmap_mmio_regsize_check(reg_size);
|
||||
|
||||
if (!IS_ERR(ctx->clk)) {
|
||||
ret = clk_enable(ctx->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
offset = regmap_mmio_get_offset(reg, reg_size);
|
||||
|
||||
while (val_size) {
|
||||
switch (ctx->val_bytes) {
|
||||
case 1:
|
||||
*(u8 *)val = readb(ctx->regs + offset);
|
||||
break;
|
||||
case 2:
|
||||
*(u16 *)val = readw(ctx->regs + offset);
|
||||
break;
|
||||
case 4:
|
||||
*(u32 *)val = readl(ctx->regs + offset);
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
*(u64 *)val = readq(ctx->regs + offset);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Should be caught by regmap_mmio_check_config */
|
||||
BUG();
|
||||
}
|
||||
val_size -= ctx->val_bytes;
|
||||
val += ctx->val_bytes;
|
||||
offset += ctx->val_bytes;
|
||||
}
|
||||
*val = ctx->reg_read(ctx, reg);
|
||||
|
||||
if (!IS_ERR(ctx->clk))
|
||||
clk_disable(ctx->clk);
|
||||
|
@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context)
|
|||
kfree(context);
|
||||
}
|
||||
|
||||
static struct regmap_bus regmap_mmio = {
|
||||
static const struct regmap_bus regmap_mmio = {
|
||||
.fast_io = true,
|
||||
.write = regmap_mmio_write,
|
||||
.gather_write = regmap_mmio_gather_write,
|
||||
.read = regmap_mmio_read,
|
||||
.reg_write = regmap_mmio_write,
|
||||
.reg_read = regmap_mmio_read,
|
||||
.free_context = regmap_mmio_free_context,
|
||||
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
|
||||
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
|
||||
};
|
||||
|
||||
static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
|
||||
|
@ -265,24 +237,71 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
|
|||
if (config->reg_stride < min_stride)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
switch (config->reg_format_endian) {
|
||||
case REGMAP_ENDIAN_DEFAULT:
|
||||
case REGMAP_ENDIAN_NATIVE:
|
||||
break;
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ctx->regs = regs;
|
||||
ctx->val_bytes = config->val_bits / 8;
|
||||
ctx->reg_bytes = config->reg_bits / 8;
|
||||
ctx->pad_bytes = config->pad_bits / 8;
|
||||
ctx->clk = ERR_PTR(-ENODEV);
|
||||
|
||||
switch (config->reg_format_endian) {
|
||||
case REGMAP_ENDIAN_DEFAULT:
|
||||
case REGMAP_ENDIAN_LITTLE:
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
case REGMAP_ENDIAN_NATIVE:
|
||||
#endif
|
||||
switch (config->val_bits) {
|
||||
case 8:
|
||||
ctx->reg_read = regmap_mmio_read8;
|
||||
ctx->reg_write = regmap_mmio_write8;
|
||||
break;
|
||||
case 16:
|
||||
ctx->reg_read = regmap_mmio_read16le;
|
||||
ctx->reg_write = regmap_mmio_write16le;
|
||||
break;
|
||||
case 32:
|
||||
ctx->reg_read = regmap_mmio_read32le;
|
||||
ctx->reg_write = regmap_mmio_write32le;
|
||||
break;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 64:
|
||||
ctx->reg_read = regmap_mmio_read64le;
|
||||
ctx->reg_write = regmap_mmio_write64le;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
break;
|
||||
case REGMAP_ENDIAN_BIG:
|
||||
#ifdef __BIG_ENDIAN
|
||||
case REGMAP_ENDIAN_NATIVE:
|
||||
#endif
|
||||
switch (config->val_bits) {
|
||||
case 8:
|
||||
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;
|
||||
break;
|
||||
case 32:
|
||||
ctx->reg_read = regmap_mmio_read32be;
|
||||
ctx->reg_write = regmap_mmio_write32be;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (clk_id == NULL)
|
||||
return ctx;
|
||||
|
||||
|
|
|
@ -557,6 +557,8 @@ enum regmap_endian regmap_get_val_endian(struct device *dev,
|
|||
endian = REGMAP_ENDIAN_BIG;
|
||||
else if (of_property_read_bool(np, "little-endian"))
|
||||
endian = REGMAP_ENDIAN_LITTLE;
|
||||
else if (of_property_read_bool(np, "native-endian"))
|
||||
endian = REGMAP_ENDIAN_NATIVE;
|
||||
|
||||
/* If the endianness was specified in DT, use that */
|
||||
if (endian != REGMAP_ENDIAN_DEFAULT)
|
||||
|
@ -2253,6 +2255,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
|||
|
||||
WARN_ON(!map->bus);
|
||||
|
||||
if (!map->bus || !map->bus->read)
|
||||
return -EINVAL;
|
||||
|
||||
range = _regmap_range_lookup(map, reg);
|
||||
if (range) {
|
||||
ret = _regmap_select_page(map, ®, range,
|
||||
|
|
Загрузка…
Ссылка в новой задаче