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