]> Git Repo - u-boot.git/blob - drivers/core/regmap.c
Merge tag 'dm-pull-14dec20' of git://git.denx.de/u-boot-dm into next
[u-boot.git] / drivers / core / regmap.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * Written by Simon Glass <[email protected]>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <log.h>
11 #include <linux/libfdt.h>
12 #include <malloc.h>
13 #include <mapmem.h>
14 #include <regmap.h>
15 #include <asm/io.h>
16 #include <dm/of_addr.h>
17 #include <dm/devres.h>
18 #include <linux/ioport.h>
19 #include <linux/compat.h>
20 #include <linux/err.h>
21 #include <linux/bitops.h>
22
23 /*
24  * Internal representation of a regmap field. Instead of storing the MSB and
25  * LSB, store the shift and mask. This makes the code a bit cleaner and faster
26  * because the shift and mask don't have to be calculated every time.
27  */
28 struct regmap_field {
29         struct regmap *regmap;
30         unsigned int mask;
31         /* lsb */
32         unsigned int shift;
33         unsigned int reg;
34 };
35
36 DECLARE_GLOBAL_DATA_PTR;
37
38 /**
39  * regmap_alloc() - Allocate a regmap with a given number of ranges.
40  *
41  * @count: Number of ranges to be allocated for the regmap.
42  *
43  * The default regmap width is set to REGMAP_SIZE_32. Callers can override it
44  * if they need.
45  *
46  * Return: A pointer to the newly allocated regmap, or NULL on error.
47  */
48 static struct regmap *regmap_alloc(int count)
49 {
50         struct regmap *map;
51         size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count;
52
53         map = calloc(1, size);
54         if (!map)
55                 return NULL;
56         map->range_count = count;
57         map->width = REGMAP_SIZE_32;
58
59         return map;
60 }
61
62 #if CONFIG_IS_ENABLED(OF_PLATDATA)
63 int regmap_init_mem_plat(struct udevice *dev, fdt_val_t *reg, int count,
64                          struct regmap **mapp)
65 {
66         struct regmap_range *range;
67         struct regmap *map;
68
69         map = regmap_alloc(count);
70         if (!map)
71                 return -ENOMEM;
72
73         for (range = map->ranges; count > 0; reg += 2, range++, count--) {
74                 range->start = *reg;
75                 range->size = reg[1];
76         }
77
78         *mapp = map;
79
80         return 0;
81 }
82 #else
83 /**
84  * init_range() - Initialize a single range of a regmap
85  * @node:     Device node that will use the map in question
86  * @range:    Pointer to a regmap_range structure that will be initialized
87  * @addr_len: The length of the addr parts of the reg property
88  * @size_len: The length of the size parts of the reg property
89  * @index:    The index of the range to initialize
90  *
91  * This function will read the necessary 'reg' information from the device tree
92  * (the 'addr' part, and the 'length' part), and initialize the range in
93  * quesion.
94  *
95  * Return: 0 if OK, -ve on error
96  */
97 static int init_range(ofnode node, struct regmap_range *range, int addr_len,
98                       int size_len, int index)
99 {
100         fdt_size_t sz;
101         struct resource r;
102
103         if (of_live_active()) {
104                 int ret;
105
106                 ret = of_address_to_resource(ofnode_to_np(node),
107                                              index, &r);
108                 if (ret) {
109                         debug("%s: Could not read resource of range %d (ret = %d)\n",
110                               ofnode_get_name(node), index, ret);
111                         return ret;
112                 }
113
114                 range->start = r.start;
115                 range->size = r.end - r.start + 1;
116         } else {
117                 int offset = ofnode_to_offset(node);
118
119                 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset,
120                                                           "reg", index,
121                                                           addr_len, size_len,
122                                                           &sz, true);
123                 if (range->start == FDT_ADDR_T_NONE) {
124                         debug("%s: Could not read start of range %d\n",
125                               ofnode_get_name(node), index);
126                         return -EINVAL;
127                 }
128
129                 range->size = sz;
130         }
131
132         return 0;
133 }
134
135 int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index)
136 {
137         struct regmap *map;
138         int addr_len, size_len;
139         int ret;
140
141         addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
142         if (addr_len < 0) {
143                 debug("%s: Error while reading the addr length (ret = %d)\n",
144                       ofnode_get_name(node), addr_len);
145                 return addr_len;
146         }
147
148         size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
149         if (size_len < 0) {
150                 debug("%s: Error while reading the size length: (ret = %d)\n",
151                       ofnode_get_name(node), size_len);
152                 return size_len;
153         }
154
155         map = regmap_alloc(1);
156         if (!map)
157                 return -ENOMEM;
158
159         ret = init_range(node, map->ranges, addr_len, size_len, index);
160         if (ret)
161                 goto err;
162
163         if (ofnode_read_bool(node, "little-endian"))
164                 map->endianness = REGMAP_LITTLE_ENDIAN;
165         else if (ofnode_read_bool(node, "big-endian"))
166                 map->endianness = REGMAP_BIG_ENDIAN;
167         else if (ofnode_read_bool(node, "native-endian"))
168                 map->endianness = REGMAP_NATIVE_ENDIAN;
169         else /* Default: native endianness */
170                 map->endianness = REGMAP_NATIVE_ENDIAN;
171
172         *mapp = map;
173
174         return 0;
175 err:
176         regmap_uninit(map);
177
178         return ret;
179 }
180
181 int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size,
182                           struct regmap **mapp)
183 {
184         struct regmap *map;
185         struct regmap_range *range;
186
187         map = regmap_alloc(1);
188         if (!map)
189                 return -ENOMEM;
190
191         range = &map->ranges[0];
192         range->start = r_start;
193         range->size = r_size;
194
195         if (ofnode_read_bool(node, "little-endian"))
196                 map->endianness = REGMAP_LITTLE_ENDIAN;
197         else if (ofnode_read_bool(node, "big-endian"))
198                 map->endianness = REGMAP_BIG_ENDIAN;
199         else if (ofnode_read_bool(node, "native-endian"))
200                 map->endianness = REGMAP_NATIVE_ENDIAN;
201         else /* Default: native endianness */
202                 map->endianness = REGMAP_NATIVE_ENDIAN;
203
204         *mapp = map;
205         return 0;
206 }
207
208 int regmap_init_mem(ofnode node, struct regmap **mapp)
209 {
210         struct regmap_range *range;
211         struct regmap *map;
212         int count;
213         int addr_len, size_len, both_len;
214         int len;
215         int index;
216         int ret;
217
218         addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
219         if (addr_len < 0) {
220                 debug("%s: Error while reading the addr length (ret = %d)\n",
221                       ofnode_get_name(node), addr_len);
222                 return addr_len;
223         }
224
225         size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
226         if (size_len < 0) {
227                 debug("%s: Error while reading the size length: (ret = %d)\n",
228                       ofnode_get_name(node), size_len);
229                 return size_len;
230         }
231
232         both_len = addr_len + size_len;
233         if (!both_len) {
234                 debug("%s: Both addr and size length are zero\n",
235                       ofnode_get_name(node));
236                 return -EINVAL;
237         }
238
239         len = ofnode_read_size(node, "reg");
240         if (len < 0) {
241                 debug("%s: Error while reading reg size (ret = %d)\n",
242                       ofnode_get_name(node), len);
243                 return len;
244         }
245         len /= sizeof(fdt32_t);
246         count = len / both_len;
247         if (!count) {
248                 debug("%s: Not enough data in reg property\n",
249                       ofnode_get_name(node));
250                 return -EINVAL;
251         }
252
253         map = regmap_alloc(count);
254         if (!map)
255                 return -ENOMEM;
256
257         for (range = map->ranges, index = 0; count > 0;
258              count--, range++, index++) {
259                 ret = init_range(node, range, addr_len, size_len, index);
260                 if (ret)
261                         goto err;
262         }
263
264         if (ofnode_read_bool(node, "little-endian"))
265                 map->endianness = REGMAP_LITTLE_ENDIAN;
266         else if (ofnode_read_bool(node, "big-endian"))
267                 map->endianness = REGMAP_BIG_ENDIAN;
268         else if (ofnode_read_bool(node, "native-endian"))
269                 map->endianness = REGMAP_NATIVE_ENDIAN;
270         else /* Default: native endianness */
271                 map->endianness = REGMAP_NATIVE_ENDIAN;
272
273         *mapp = map;
274
275         return 0;
276 err:
277         regmap_uninit(map);
278
279         return ret;
280 }
281
282 static void devm_regmap_release(struct udevice *dev, void *res)
283 {
284         regmap_uninit(*(struct regmap **)res);
285 }
286
287 struct regmap *devm_regmap_init(struct udevice *dev,
288                                 const struct regmap_bus *bus,
289                                 void *bus_context,
290                                 const struct regmap_config *config)
291 {
292         int rc;
293         struct regmap **mapp, *map;
294
295         mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
296                             __GFP_ZERO);
297         if (unlikely(!mapp))
298                 return ERR_PTR(-ENOMEM);
299
300         if (config && config->r_size != 0)
301                 rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start,
302                                            config->r_size, mapp);
303         else
304                 rc = regmap_init_mem(dev_ofnode(dev), mapp);
305         if (rc)
306                 return ERR_PTR(rc);
307
308         map = *mapp;
309         if (config) {
310                 map->width = config->width;
311                 map->reg_offset_shift = config->reg_offset_shift;
312         }
313
314         devres_add(dev, mapp);
315         return *mapp;
316 }
317 #endif
318
319 void *regmap_get_range(struct regmap *map, unsigned int range_num)
320 {
321         struct regmap_range *range;
322
323         if (range_num >= map->range_count)
324                 return NULL;
325         range = &map->ranges[range_num];
326
327         return map_sysmem(range->start, range->size);
328 }
329
330 int regmap_uninit(struct regmap *map)
331 {
332         free(map);
333
334         return 0;
335 }
336
337 static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
338 {
339         return readb(addr);
340 }
341
342 static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
343 {
344         switch (endianness) {
345         case REGMAP_LITTLE_ENDIAN:
346                 return in_le16(addr);
347         case REGMAP_BIG_ENDIAN:
348                 return in_be16(addr);
349         case REGMAP_NATIVE_ENDIAN:
350                 return readw(addr);
351         }
352
353         return readw(addr);
354 }
355
356 static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
357 {
358         switch (endianness) {
359         case REGMAP_LITTLE_ENDIAN:
360                 return in_le32(addr);
361         case REGMAP_BIG_ENDIAN:
362                 return in_be32(addr);
363         case REGMAP_NATIVE_ENDIAN:
364                 return readl(addr);
365         }
366
367         return readl(addr);
368 }
369
370 #if defined(in_le64) && defined(in_be64) && defined(readq)
371 static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
372 {
373         switch (endianness) {
374         case REGMAP_LITTLE_ENDIAN:
375                 return in_le64(addr);
376         case REGMAP_BIG_ENDIAN:
377                 return in_be64(addr);
378         case REGMAP_NATIVE_ENDIAN:
379                 return readq(addr);
380         }
381
382         return readq(addr);
383 }
384 #endif
385
386 int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
387                           void *valp, size_t val_len)
388 {
389         struct regmap_range *range;
390         void *ptr;
391
392         if (range_num >= map->range_count) {
393                 debug("%s: range index %d larger than range count\n",
394                       __func__, range_num);
395                 return -ERANGE;
396         }
397         range = &map->ranges[range_num];
398
399         offset <<= map->reg_offset_shift;
400         if (offset + val_len > range->size) {
401                 debug("%s: offset/size combination invalid\n", __func__);
402                 return -ERANGE;
403         }
404
405         ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
406
407         switch (val_len) {
408         case REGMAP_SIZE_8:
409                 *((u8 *)valp) = __read_8(ptr, map->endianness);
410                 break;
411         case REGMAP_SIZE_16:
412                 *((u16 *)valp) = __read_16(ptr, map->endianness);
413                 break;
414         case REGMAP_SIZE_32:
415                 *((u32 *)valp) = __read_32(ptr, map->endianness);
416                 break;
417 #if defined(in_le64) && defined(in_be64) && defined(readq)
418         case REGMAP_SIZE_64:
419                 *((u64 *)valp) = __read_64(ptr, map->endianness);
420                 break;
421 #endif
422         default:
423                 debug("%s: regmap size %zu unknown\n", __func__, val_len);
424                 return -EINVAL;
425         }
426
427         return 0;
428 }
429
430 int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
431 {
432         return regmap_raw_read_range(map, 0, offset, valp, val_len);
433 }
434
435 int regmap_read(struct regmap *map, uint offset, uint *valp)
436 {
437         return regmap_raw_read(map, offset, valp, map->width);
438 }
439
440 static inline void __write_8(u8 *addr, const u8 *val,
441                              enum regmap_endianness_t endianness)
442 {
443         writeb(*val, addr);
444 }
445
446 static inline void __write_16(u16 *addr, const u16 *val,
447                               enum regmap_endianness_t endianness)
448 {
449         switch (endianness) {
450         case REGMAP_NATIVE_ENDIAN:
451                 writew(*val, addr);
452                 break;
453         case REGMAP_LITTLE_ENDIAN:
454                 out_le16(addr, *val);
455                 break;
456         case REGMAP_BIG_ENDIAN:
457                 out_be16(addr, *val);
458                 break;
459         }
460 }
461
462 static inline void __write_32(u32 *addr, const u32 *val,
463                               enum regmap_endianness_t endianness)
464 {
465         switch (endianness) {
466         case REGMAP_NATIVE_ENDIAN:
467                 writel(*val, addr);
468                 break;
469         case REGMAP_LITTLE_ENDIAN:
470                 out_le32(addr, *val);
471                 break;
472         case REGMAP_BIG_ENDIAN:
473                 out_be32(addr, *val);
474                 break;
475         }
476 }
477
478 #if defined(out_le64) && defined(out_be64) && defined(writeq)
479 static inline void __write_64(u64 *addr, const u64 *val,
480                               enum regmap_endianness_t endianness)
481 {
482         switch (endianness) {
483         case REGMAP_NATIVE_ENDIAN:
484                 writeq(*val, addr);
485                 break;
486         case REGMAP_LITTLE_ENDIAN:
487                 out_le64(addr, *val);
488                 break;
489         case REGMAP_BIG_ENDIAN:
490                 out_be64(addr, *val);
491                 break;
492         }
493 }
494 #endif
495
496 int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
497                            const void *val, size_t val_len)
498 {
499         struct regmap_range *range;
500         void *ptr;
501
502         if (range_num >= map->range_count) {
503                 debug("%s: range index %d larger than range count\n",
504                       __func__, range_num);
505                 return -ERANGE;
506         }
507         range = &map->ranges[range_num];
508
509         offset <<= map->reg_offset_shift;
510         if (offset + val_len > range->size) {
511                 debug("%s: offset/size combination invalid\n", __func__);
512                 return -ERANGE;
513         }
514
515         ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
516
517         switch (val_len) {
518         case REGMAP_SIZE_8:
519                 __write_8(ptr, val, map->endianness);
520                 break;
521         case REGMAP_SIZE_16:
522                 __write_16(ptr, val, map->endianness);
523                 break;
524         case REGMAP_SIZE_32:
525                 __write_32(ptr, val, map->endianness);
526                 break;
527 #if defined(out_le64) && defined(out_be64) && defined(writeq)
528         case REGMAP_SIZE_64:
529                 __write_64(ptr, val, map->endianness);
530                 break;
531 #endif
532         default:
533                 debug("%s: regmap size %zu unknown\n", __func__, val_len);
534                 return -EINVAL;
535         }
536
537         return 0;
538 }
539
540 int regmap_raw_write(struct regmap *map, uint offset, const void *val,
541                      size_t val_len)
542 {
543         return regmap_raw_write_range(map, 0, offset, val, val_len);
544 }
545
546 int regmap_write(struct regmap *map, uint offset, uint val)
547 {
548         return regmap_raw_write(map, offset, &val, map->width);
549 }
550
551 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
552 {
553         uint reg;
554         int ret;
555
556         ret = regmap_read(map, offset, &reg);
557         if (ret)
558                 return ret;
559
560         reg &= ~mask;
561
562         return regmap_write(map, offset, reg | (val & mask));
563 }
564
565 int regmap_field_read(struct regmap_field *field, unsigned int *val)
566 {
567         int ret;
568         unsigned int reg_val;
569
570         ret = regmap_read(field->regmap, field->reg, &reg_val);
571         if (ret != 0)
572                 return ret;
573
574         reg_val &= field->mask;
575         reg_val >>= field->shift;
576         *val = reg_val;
577
578         return ret;
579 }
580
581 int regmap_field_write(struct regmap_field *field, unsigned int val)
582 {
583         return regmap_update_bits(field->regmap, field->reg, field->mask,
584                                   val << field->shift);
585 }
586
587 static void regmap_field_init(struct regmap_field *rm_field,
588                               struct regmap *regmap,
589                               struct reg_field reg_field)
590 {
591         rm_field->regmap = regmap;
592         rm_field->reg = reg_field.reg;
593         rm_field->shift = reg_field.lsb;
594         rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
595 }
596
597 struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
598                                              struct regmap *regmap,
599                                              struct reg_field reg_field)
600 {
601         struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
602                                                      GFP_KERNEL);
603         if (!rm_field)
604                 return ERR_PTR(-ENOMEM);
605
606         regmap_field_init(rm_field, regmap, reg_field);
607
608         return rm_field;
609 }
610
611 void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
612 {
613         devm_kfree(dev, field);
614 }
615
616 struct regmap_field *regmap_field_alloc(struct regmap *regmap,
617                                         struct reg_field reg_field)
618 {
619         struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
620
621         if (!rm_field)
622                 return ERR_PTR(-ENOMEM);
623
624         regmap_field_init(rm_field, regmap, reg_field);
625
626         return rm_field;
627 }
628
629 void regmap_field_free(struct regmap_field *field)
630 {
631         kfree(field);
632 }
This page took 0.063274 seconds and 4 git commands to generate.