* [PATCH 1/2] regmap: allow busses to request formatting with specific endianness
@ 2012-05-23 22:33 Stephen Warren
2012-05-23 22:33 ` [PATCH 2/2] regmap: mmio: request native endian formatting Stephen Warren
2012-05-23 23:16 ` [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Mark Brown
0 siblings, 2 replies; 5+ messages in thread
From: Stephen Warren @ 2012-05-23 22:33 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Stephen Warren
From: Stephen Warren <swarren@nvidia.com>
Add a field to struct regmap_bus that allows bus drivers to request that
register addresses and values be formatted with a specific endianness.
The default endianness is unchanged from current operation: Big.
Implement native endian formatting/parsing for 16- and 32-bit values.
This will be enough to support regmap-mmio.c.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
I'm not 100% sure if this is the approach you had in mind. However, anything
more all-encompassing would require separating the concepts of endianness and
serialization that are coupled together in functions like
regmap_format_4_12_write, and I'm not sure how that would work conceptually.
drivers/base/regmap/regmap.c | 90 +++++++++++++++++++++++++++++++++++++-----
include/linux/regmap.h | 9 ++++
2 files changed, 89 insertions(+), 10 deletions(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 2aa076e..33da8bd 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -119,13 +119,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
b[0] = val << shift;
}
-static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
{
__be16 *b = buf;
b[0] = cpu_to_be16(val << shift);
}
+static void regmap_format_16_native(void *buf, unsigned int val,
+ unsigned int shift)
+{
+ *(u16 *)buf = val << shift;
+}
+
static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
@@ -137,13 +143,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
b[2] = val;
}
-static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
{
__be32 *b = buf;
b[0] = cpu_to_be32(val << shift);
}
+static void regmap_format_32_native(void *buf, unsigned int val,
+ unsigned int shift)
+{
+ *(u32 *)buf = val << shift;
+}
+
static unsigned int regmap_parse_8(void *buf)
{
u8 *b = buf;
@@ -151,7 +163,7 @@ static unsigned int regmap_parse_8(void *buf)
return b[0];
}
-static unsigned int regmap_parse_16(void *buf)
+static unsigned int regmap_parse_16_be(void *buf)
{
__be16 *b = buf;
@@ -160,6 +172,11 @@ static unsigned int regmap_parse_16(void *buf)
return b[0];
}
+static unsigned int regmap_parse_16_native(void *buf)
+{
+ return *(u16 *)buf;
+}
+
static unsigned int regmap_parse_24(void *buf)
{
u8 *b = buf;
@@ -170,7 +187,7 @@ static unsigned int regmap_parse_24(void *buf)
return ret;
}
-static unsigned int regmap_parse_32(void *buf)
+static unsigned int regmap_parse_32_be(void *buf)
{
__be32 *b = buf;
@@ -179,6 +196,11 @@ static unsigned int regmap_parse_32(void *buf)
return b[0];
}
+static unsigned int regmap_parse_32_native(void *buf)
+{
+ return *(u32 *)buf;
+}
+
static void regmap_lock_mutex(struct regmap *map)
{
mutex_lock(&map->mutex);
@@ -279,6 +301,8 @@ struct regmap *regmap_init(struct device *dev,
case 2:
switch (config->val_bits) {
case 6:
+ if (bus->format_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
map->format.format_write = regmap_format_2_6_write;
break;
default:
@@ -289,6 +313,8 @@ struct regmap *regmap_init(struct device *dev,
case 4:
switch (config->val_bits) {
case 12:
+ if (bus->format_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
map->format.format_write = regmap_format_4_12_write;
break;
default:
@@ -299,6 +325,8 @@ struct regmap *regmap_init(struct device *dev,
case 7:
switch (config->val_bits) {
case 9:
+ if (bus->format_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
map->format.format_write = regmap_format_7_9_write;
break;
default:
@@ -309,6 +337,8 @@ struct regmap *regmap_init(struct device *dev,
case 10:
switch (config->val_bits) {
case 14:
+ if (bus->format_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
map->format.format_write = regmap_format_10_14_write;
break;
default:
@@ -321,11 +351,29 @@ struct regmap *regmap_init(struct device *dev,
break;
case 16:
- map->format.format_reg = regmap_format_16;
+ switch (bus->format_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_reg = regmap_format_16_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_reg = regmap_format_16_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
case 32:
- map->format.format_reg = regmap_format_32;
+ switch (bus->format_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_reg = regmap_format_32_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_reg = regmap_format_32_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
default:
@@ -338,16 +386,38 @@ struct regmap *regmap_init(struct device *dev,
map->format.parse_val = regmap_parse_8;
break;
case 16:
- map->format.format_val = regmap_format_16;
- map->format.parse_val = regmap_parse_16;
+ switch (bus->format_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_val = regmap_format_16_be;
+ map->format.parse_val = regmap_parse_16_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_val = regmap_format_16_native;
+ map->format.parse_val = regmap_parse_16_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
case 24:
+ if (bus->format_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
map->format.format_val = regmap_format_24;
map->format.parse_val = regmap_parse_24;
break;
case 32:
- map->format.format_val = regmap_format_32;
- map->format.parse_val = regmap_parse_32;
+ switch (bus->format_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_val = regmap_format_32_be;
+ map->format.parse_val = regmap_parse_32_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_val = regmap_format_32_native;
+ map->format.parse_val = regmap_parse_32_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
}
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 56af22e..6452afd 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -121,6 +121,12 @@ typedef int (*regmap_hw_read)(void *context,
void *val_buf, size_t val_size);
typedef void (*regmap_hw_free_context)(void *context);
+enum regmap_endian {
+ REGMAP_ENDIAN_BIG = 0, /* Compatible default if unspecified */
+ REGMAP_ENDIAN_LITTLE,
+ REGMAP_ENDIAN_NATIVE,
+};
+
/**
* Description of a hardware bus for the register map infrastructure.
*
@@ -133,6 +139,8 @@ typedef void (*regmap_hw_free_context)(void *context);
* data.
* @read_flag_mask: Mask to be set in the top byte of the register when doing
* a read.
+ * @format_endian: Endianness for formatted register addresses, values, or
+ * serialized combinations thereof.
*/
struct regmap_bus {
bool fast_io;
@@ -141,6 +149,7 @@ struct regmap_bus {
regmap_hw_read read;
regmap_hw_free_context free_context;
u8 read_flag_mask;
+ enum regmap_endian format_endian;
};
struct regmap *regmap_init(struct device *dev,
--
1.7.0.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] regmap: mmio: request native endian formatting
2012-05-23 22:33 [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Stephen Warren
@ 2012-05-23 22:33 ` Stephen Warren
2012-05-23 23:16 ` [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Mark Brown
1 sibling, 0 replies; 5+ messages in thread
From: Stephen Warren @ 2012-05-23 22:33 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Stephen Warren
From: Stephen Warren <swarren@nvidia.com>
This will avoid the regmap core converting all addresses and values into
big endian, only for the mmio bus driver to have to convert them back to
native endian.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
drivers/base/regmap/regmap-mmio.c | 17 +++++++++--------
1 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index febd6de..49cdf59 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -37,7 +37,7 @@ static int regmap_mmio_gather_write(void *context,
BUG_ON(reg_size != 4);
- offset = be32_to_cpup(reg);
+ offset = *(u32 *)reg;
while (val_size) {
switch (ctx->val_bytes) {
@@ -45,14 +45,14 @@ static int regmap_mmio_gather_write(void *context,
writeb(*(u8 *)val, ctx->regs + offset);
break;
case 2:
- writew(be16_to_cpup(val), ctx->regs + offset);
+ writew(*(u16 *)val, ctx->regs + offset);
break;
case 4:
- writel(be32_to_cpup(val), ctx->regs + offset);
+ writel(*(u32 *)val, ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
- writeq(be64_to_cpup(val), ctx->regs + offset);
+ writeq(*(u64 *)val, ctx->regs + offset);
break;
#endif
default:
@@ -83,7 +83,7 @@ static int regmap_mmio_read(void *context,
BUG_ON(reg_size != 4);
- offset = be32_to_cpup(reg);
+ offset = *(u32 *)reg;
while (val_size) {
switch (ctx->val_bytes) {
@@ -91,14 +91,14 @@ static int regmap_mmio_read(void *context,
*(u8 *)val = readb(ctx->regs + offset);
break;
case 2:
- *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
+ *(u16 *)val = readw(ctx->regs + offset);
break;
case 4:
- *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
+ *(u32 *)val = readl(ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
- *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
+ *(u64 *)val = readq(ctx->regs + offset);
break;
#endif
default:
@@ -124,6 +124,7 @@ static struct regmap_bus regmap_mmio = {
.gather_write = regmap_mmio_gather_write,
.read = regmap_mmio_read,
.free_context = regmap_mmio_free_context,
+ .format_endian = REGMAP_ENDIAN_NATIVE,
};
struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
--
1.7.0.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] regmap: allow busses to request formatting with specific endianness
2012-05-23 22:33 [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Stephen Warren
2012-05-23 22:33 ` [PATCH 2/2] regmap: mmio: request native endian formatting Stephen Warren
@ 2012-05-23 23:16 ` Mark Brown
2012-05-23 23:28 ` Stephen Warren
1 sibling, 1 reply; 5+ messages in thread
From: Mark Brown @ 2012-05-23 23:16 UTC (permalink / raw)
To: Stephen Warren; +Cc: linux-kernel, Stephen Warren
[-- Attachment #1: Type: text/plain, Size: 911 bytes --]
On Wed, May 23, 2012 at 04:33:53PM -0600, Stephen Warren wrote:
> I'm not 100% sure if this is the approach you had in mind. However, anything
> more all-encompassing would require separating the concepts of endianness and
I wouldn't do this on the bus in the first instance, I'd do it on the
device - it's pretty much orthogonal to the bus what the device wants
and it's perfectly plausible that a device on another bus might've made
unusual endiannness choices. Otherwise it's pretty much what I was
thinking of.
For MMIO I'd expect that a large proportion of devices on platform buses
would pick native endianness.
> serialization that are coupled together in functions like
> regmap_format_4_12_write, and I'm not sure how that would work conceptually.
Anything using format_write() can be ignored, it's already lost large
chunks of functionality just from that. Non-integer byte sizes cause
issues.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] regmap: allow busses to request formatting with specific endianness
2012-05-23 23:16 ` [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Mark Brown
@ 2012-05-23 23:28 ` Stephen Warren
2012-05-23 23:35 ` Mark Brown
0 siblings, 1 reply; 5+ messages in thread
From: Stephen Warren @ 2012-05-23 23:28 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Stephen Warren
On 05/23/2012 05:16 PM, Mark Brown wrote:
> On Wed, May 23, 2012 at 04:33:53PM -0600, Stephen Warren wrote:
>
>> I'm not 100% sure if this is the approach you had in mind.
>> However, anything more all-encompassing would require separating
>> the concepts of endianness and
>
> I wouldn't do this on the bus in the first instance, I'd do it on
> the device - it's pretty much orthogonal to the bus what the device
> wants and it's perfectly plausible that a device on another bus
> might've made unusual endiannness choices. Otherwise it's pretty
> much what I was thinking of.
>
> For MMIO I'd expect that a large proportion of devices on platform
> buses would pick native endianness.
I did briefly consider making this a property of regmap_config rather
than regmap_bus, but as you say, it'd mean every MMIO user would have
to specify the endianness value.
Also, it doesn't seem right for a device to be able to specify
register formatting endianness for MMIO; presumably we'd always want
that native.
Perhaps the solution is to have two fields; one for address formatting
(the endianness of which regmap-mmio.c will error-check is "native",
like it error-checks other fields) and a second for value
formatting/parsing, which I can see a device might want to influence
(e.g. to fix a byte swap in HW).
I suppose we could avoid every device having to specify the endianness
by introducing a fourth "DEFAULT" value == 0, and having the bus
define what default means - that way, I wouldn't have to edit any
drivers due to adding the regmap_bus field.
>> serialization that are coupled together in functions like
>> regmap_format_4_12_write, and I'm not sure how that would work
>> conceptually.
>
> Anything using format_write() can be ignored, it's already lost
> large chunks of functionality just from that. Non-integer byte
> sizes cause issues.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] regmap: allow busses to request formatting with specific endianness
2012-05-23 23:28 ` Stephen Warren
@ 2012-05-23 23:35 ` Mark Brown
0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2012-05-23 23:35 UTC (permalink / raw)
To: Stephen Warren; +Cc: linux-kernel, Stephen Warren
[-- Attachment #1: Type: text/plain, Size: 975 bytes --]
On Wed, May 23, 2012 at 05:28:39PM -0600, Stephen Warren wrote:
> I did briefly consider making this a property of regmap_config rather
> than regmap_bus, but as you say, it'd mean every MMIO user would have
> to specify the endianness value.
I didn't say that, that'd be appauling!
> Also, it doesn't seem right for a device to be able to specify
> register formatting endianness for MMIO; presumably we'd always want
> that native.
Depends on what's going on with bought in IP and register map standards
(and things like PCI) - you do get non-native IPs turning up often enough.
> I suppose we could avoid every device having to specify the endianness
> by introducing a fourth "DEFAULT" value == 0, and having the bus
> define what default means - that way, I wouldn't have to edit any
> drivers due to adding the regmap_bus field.
That's absolutely essential, there's already an explicit idea of this in
the current code's assumption that everything is big endian.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-05-23 23:35 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-23 22:33 [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Stephen Warren
2012-05-23 22:33 ` [PATCH 2/2] regmap: mmio: request native endian formatting Stephen Warren
2012-05-23 23:16 ` [PATCH 1/2] regmap: allow busses to request formatting with specific endianness Mark Brown
2012-05-23 23:28 ` Stephen Warren
2012-05-23 23:35 ` Mark Brown
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.