Commit 9b77fe3b80b038af7114f7dae4934773bb026f8e

Authored by Mario Six
Committed by Simon Glass
1 parent 45ef7f55c7

regmap: Add endianness support

Add support for switching the endianness of regmap accesses via the
"little-endian", "big-endian", and "native-endian" boolean properties in
the device tree.

The default endianness is native endianness.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

Showing 2 changed files with 138 additions and 10 deletions Side-by-side Diff

drivers/core/regmap.c
... ... @@ -164,6 +164,15 @@
164 164 return ret;
165 165 }
166 166  
  167 + if (ofnode_read_bool(node, "little-endian"))
  168 + map->endianness = REGMAP_LITTLE_ENDIAN;
  169 + else if (ofnode_read_bool(node, "big-endian"))
  170 + map->endianness = REGMAP_BIG_ENDIAN;
  171 + else if (ofnode_read_bool(node, "native-endian"))
  172 + map->endianness = REGMAP_NATIVE_ENDIAN;
  173 + else /* Default: native endianness */
  174 + map->endianness = REGMAP_NATIVE_ENDIAN;
  175 +
167 176 *mapp = map;
168 177  
169 178 return 0;
... ... @@ -188,6 +197,55 @@
188 197 return 0;
189 198 }
190 199  
  200 +static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
  201 +{
  202 + return readb(addr);
  203 +}
  204 +
  205 +static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
  206 +{
  207 + switch (endianness) {
  208 + case REGMAP_LITTLE_ENDIAN:
  209 + return in_le16(addr);
  210 + case REGMAP_BIG_ENDIAN:
  211 + return in_be16(addr);
  212 + case REGMAP_NATIVE_ENDIAN:
  213 + return readw(addr);
  214 + }
  215 +
  216 + return readw(addr);
  217 +}
  218 +
  219 +static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
  220 +{
  221 + switch (endianness) {
  222 + case REGMAP_LITTLE_ENDIAN:
  223 + return in_le32(addr);
  224 + case REGMAP_BIG_ENDIAN:
  225 + return in_be32(addr);
  226 + case REGMAP_NATIVE_ENDIAN:
  227 + return readl(addr);
  228 + }
  229 +
  230 + return readl(addr);
  231 +}
  232 +
  233 +#if defined(in_le64) && defined(in_be64) && defined(readq)
  234 +static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
  235 +{
  236 + switch (endianness) {
  237 + case REGMAP_LITTLE_ENDIAN:
  238 + return in_le64(addr);
  239 + case REGMAP_BIG_ENDIAN:
  240 + return in_be64(addr);
  241 + case REGMAP_NATIVE_ENDIAN:
  242 + return readq(addr);
  243 + }
  244 +
  245 + return readq(addr);
  246 +}
  247 +#endif
  248 +
191 249 int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
192 250 void *valp, size_t val_len)
193 251 {
194 252  
195 253  
196 254  
197 255  
... ... @@ -210,17 +268,17 @@
210 268  
211 269 switch (val_len) {
212 270 case REGMAP_SIZE_8:
213   - *((u8 *)valp) = readb((u8 *)ptr);
  271 + *((u8 *)valp) = __read_8(ptr, map->endianness);
214 272 break;
215 273 case REGMAP_SIZE_16:
216   - *((u16 *)valp) = readw((u16 *)ptr);
  274 + *((u16 *)valp) = __read_16(ptr, map->endianness);
217 275 break;
218 276 case REGMAP_SIZE_32:
219   - *((u32 *)valp) = readl((u32 *)ptr);
  277 + *((u32 *)valp) = __read_32(ptr, map->endianness);
220 278 break;
221   -#if defined(readq)
  279 +#if defined(in_le64) && defined(in_be64) && defined(readq)
222 280 case REGMAP_SIZE_64:
223   - *((u64 *)valp) = readq((u64 *)ptr);
  281 + *((u64 *)valp) = __read_64(ptr, map->endianness);
224 282 break;
225 283 #endif
226 284 default:
... ... @@ -241,6 +299,62 @@
241 299 return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
242 300 }
243 301  
  302 +static inline void __write_8(u8 *addr, const u8 *val,
  303 + enum regmap_endianness_t endianness)
  304 +{
  305 + writeb(*val, addr);
  306 +}
  307 +
  308 +static inline void __write_16(u16 *addr, const u16 *val,
  309 + enum regmap_endianness_t endianness)
  310 +{
  311 + switch (endianness) {
  312 + case REGMAP_NATIVE_ENDIAN:
  313 + writew(*val, addr);
  314 + break;
  315 + case REGMAP_LITTLE_ENDIAN:
  316 + out_le16(addr, *val);
  317 + break;
  318 + case REGMAP_BIG_ENDIAN:
  319 + out_be16(addr, *val);
  320 + break;
  321 + }
  322 +}
  323 +
  324 +static inline void __write_32(u32 *addr, const u32 *val,
  325 + enum regmap_endianness_t endianness)
  326 +{
  327 + switch (endianness) {
  328 + case REGMAP_NATIVE_ENDIAN:
  329 + writel(*val, addr);
  330 + break;
  331 + case REGMAP_LITTLE_ENDIAN:
  332 + out_le32(addr, *val);
  333 + break;
  334 + case REGMAP_BIG_ENDIAN:
  335 + out_be32(addr, *val);
  336 + break;
  337 + }
  338 +}
  339 +
  340 +#if defined(out_le64) && defined(out_be64) && defined(writeq)
  341 +static inline void __write_64(u64 *addr, const u64 *val,
  342 + enum regmap_endianness_t endianness)
  343 +{
  344 + switch (endianness) {
  345 + case REGMAP_NATIVE_ENDIAN:
  346 + writeq(*val, addr);
  347 + break;
  348 + case REGMAP_LITTLE_ENDIAN:
  349 + out_le64(addr, *val);
  350 + break;
  351 + case REGMAP_BIG_ENDIAN:
  352 + out_be64(addr, *val);
  353 + break;
  354 + }
  355 +}
  356 +#endif
  357 +
244 358 int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
245 359 const void *val, size_t val_len)
246 360 {
247 361  
248 362  
249 363  
250 364  
... ... @@ -263,17 +377,17 @@
263 377  
264 378 switch (val_len) {
265 379 case REGMAP_SIZE_8:
266   - writeb(*((u8 *)val), (u8 *)ptr);
  380 + __write_8(ptr, val, map->endianness);
267 381 break;
268 382 case REGMAP_SIZE_16:
269   - writew(*((u16 *)val), (u16 *)ptr);
  383 + __write_16(ptr, val, map->endianness);
270 384 break;
271 385 case REGMAP_SIZE_32:
272   - writel(*((u32 *)val), (u32 *)ptr);
  386 + __write_32(ptr, val, map->endianness);
273 387 break;
274   -#if defined(writeq)
  388 +#if defined(out_le64) && defined(out_be64) && defined(writeq)
275 389 case REGMAP_SIZE_64:
276   - writeq(*((u64 *)val), (u64 *)ptr);
  390 + __write_64(ptr, val, map->endianness);
277 391 break;
278 392 #endif
279 393 default:
... ... @@ -23,6 +23,19 @@
23 23 };
24 24  
25 25 /**
  26 + * enum regmap_endianness_t - Endianness for regmap reads and writes
  27 + *
  28 + * @REGMAP_NATIVE_ENDIAN: Native endian read/write accesses
  29 + * @REGMAP_LITTLE_ENDIAN: Little endian read/write accesses
  30 + * @REGMAP_BIG_ENDIAN: Big endian read/write accesses
  31 + */
  32 +enum regmap_endianness_t {
  33 + REGMAP_NATIVE_ENDIAN,
  34 + REGMAP_LITTLE_ENDIAN,
  35 + REGMAP_BIG_ENDIAN,
  36 +};
  37 +
  38 +/**
26 39 * struct regmap_range - a register map range
27 40 *
28 41 * @start: Start address
... ... @@ -40,6 +53,7 @@
40 53 * @ranges: Array of ranges
41 54 */
42 55 struct regmap {
  56 + enum regmap_endianness_t endianness;
43 57 int range_count;
44 58 struct regmap_range ranges[0];
45 59 };