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