]> Git Repo - u-boot.git/blob - drivers/core/regmap.c
common: Drop asm/global_data.h from common header
[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 <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         mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
297                             __GFP_ZERO);
298         if (unlikely(!mapp))
299                 return ERR_PTR(-ENOMEM);
300
301         if (config && config->r_size != 0)
302                 rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start,
303                                            config->r_size, mapp);
304         else
305                 rc = regmap_init_mem(dev_ofnode(dev), mapp);
306         if (rc)
307                 return ERR_PTR(rc);
308
309         map = *mapp;
310         if (config) {
311                 map->width = config->width;
312                 map->reg_offset_shift = config->reg_offset_shift;
313         }
314
315         devres_add(dev, mapp);
316         return *mapp;
317 }
318 #endif
319
320 void *regmap_get_range(struct regmap *map, unsigned int range_num)
321 {
322         struct regmap_range *range;
323
324         if (range_num >= map->range_count)
325                 return NULL;
326         range = &map->ranges[range_num];
327
328         return map_sysmem(range->start, range->size);
329 }
330
331 int regmap_uninit(struct regmap *map)
332 {
333         free(map);
334
335         return 0;
336 }
337
338 static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
339 {
340         return readb(addr);
341 }
342
343 static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
344 {
345         switch (endianness) {
346         case REGMAP_LITTLE_ENDIAN:
347                 return in_le16(addr);
348         case REGMAP_BIG_ENDIAN:
349                 return in_be16(addr);
350         case REGMAP_NATIVE_ENDIAN:
351                 return readw(addr);
352         }
353
354         return readw(addr);
355 }
356
357 static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
358 {
359         switch (endianness) {
360         case REGMAP_LITTLE_ENDIAN:
361                 return in_le32(addr);
362         case REGMAP_BIG_ENDIAN:
363                 return in_be32(addr);
364         case REGMAP_NATIVE_ENDIAN:
365                 return readl(addr);
366         }
367
368         return readl(addr);
369 }
370
371 #if defined(in_le64) && defined(in_be64) && defined(readq)
372 static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
373 {
374         switch (endianness) {
375         case REGMAP_LITTLE_ENDIAN:
376                 return in_le64(addr);
377         case REGMAP_BIG_ENDIAN:
378                 return in_be64(addr);
379         case REGMAP_NATIVE_ENDIAN:
380                 return readq(addr);
381         }
382
383         return readq(addr);
384 }
385 #endif
386
387 int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
388                           void *valp, size_t val_len)
389 {
390         struct regmap_range *range;
391         void *ptr;
392
393         if (range_num >= map->range_count) {
394                 debug("%s: range index %d larger than range count\n",
395                       __func__, range_num);
396                 return -ERANGE;
397         }
398         range = &map->ranges[range_num];
399
400         offset <<= map->reg_offset_shift;
401         if (offset + val_len > range->size) {
402                 debug("%s: offset/size combination invalid\n", __func__);
403                 return -ERANGE;
404         }
405
406         ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
407
408         switch (val_len) {
409         case REGMAP_SIZE_8:
410                 *((u8 *)valp) = __read_8(ptr, map->endianness);
411                 break;
412         case REGMAP_SIZE_16:
413                 *((u16 *)valp) = __read_16(ptr, map->endianness);
414                 break;
415         case REGMAP_SIZE_32:
416                 *((u32 *)valp) = __read_32(ptr, map->endianness);
417                 break;
418 #if defined(in_le64) && defined(in_be64) && defined(readq)
419         case REGMAP_SIZE_64:
420                 *((u64 *)valp) = __read_64(ptr, map->endianness);
421                 break;
422 #endif
423         default:
424                 debug("%s: regmap size %zu unknown\n", __func__, val_len);
425                 return -EINVAL;
426         }
427
428         return 0;
429 }
430
431 int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
432 {
433         return regmap_raw_read_range(map, 0, offset, valp, val_len);
434 }
435
436 int regmap_read(struct regmap *map, uint offset, uint *valp)
437 {
438         return regmap_raw_read(map, offset, valp, map->width);
439 }
440
441 static inline void __write_8(u8 *addr, const u8 *val,
442                              enum regmap_endianness_t endianness)
443 {
444         writeb(*val, addr);
445 }
446
447 static inline void __write_16(u16 *addr, const u16 *val,
448                               enum regmap_endianness_t endianness)
449 {
450         switch (endianness) {
451         case REGMAP_NATIVE_ENDIAN:
452                 writew(*val, addr);
453                 break;
454         case REGMAP_LITTLE_ENDIAN:
455                 out_le16(addr, *val);
456                 break;
457         case REGMAP_BIG_ENDIAN:
458                 out_be16(addr, *val);
459                 break;
460         }
461 }
462
463 static inline void __write_32(u32 *addr, const u32 *val,
464                               enum regmap_endianness_t endianness)
465 {
466         switch (endianness) {
467         case REGMAP_NATIVE_ENDIAN:
468                 writel(*val, addr);
469                 break;
470         case REGMAP_LITTLE_ENDIAN:
471                 out_le32(addr, *val);
472                 break;
473         case REGMAP_BIG_ENDIAN:
474                 out_be32(addr, *val);
475                 break;
476         }
477 }
478
479 #if defined(out_le64) && defined(out_be64) && defined(writeq)
480 static inline void __write_64(u64 *addr, const u64 *val,
481                               enum regmap_endianness_t endianness)
482 {
483         switch (endianness) {
484         case REGMAP_NATIVE_ENDIAN:
485                 writeq(*val, addr);
486                 break;
487         case REGMAP_LITTLE_ENDIAN:
488                 out_le64(addr, *val);
489                 break;
490         case REGMAP_BIG_ENDIAN:
491                 out_be64(addr, *val);
492                 break;
493         }
494 }
495 #endif
496
497 int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
498                            const void *val, size_t val_len)
499 {
500         struct regmap_range *range;
501         void *ptr;
502
503         if (range_num >= map->range_count) {
504                 debug("%s: range index %d larger than range count\n",
505                       __func__, range_num);
506                 return -ERANGE;
507         }
508         range = &map->ranges[range_num];
509
510         offset <<= map->reg_offset_shift;
511         if (offset + val_len > range->size) {
512                 debug("%s: offset/size combination invalid\n", __func__);
513                 return -ERANGE;
514         }
515
516         ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
517
518         switch (val_len) {
519         case REGMAP_SIZE_8:
520                 __write_8(ptr, val, map->endianness);
521                 break;
522         case REGMAP_SIZE_16:
523                 __write_16(ptr, val, map->endianness);
524                 break;
525         case REGMAP_SIZE_32:
526                 __write_32(ptr, val, map->endianness);
527                 break;
528 #if defined(out_le64) && defined(out_be64) && defined(writeq)
529         case REGMAP_SIZE_64:
530                 __write_64(ptr, val, map->endianness);
531                 break;
532 #endif
533         default:
534                 debug("%s: regmap size %zu unknown\n", __func__, val_len);
535                 return -EINVAL;
536         }
537
538         return 0;
539 }
540
541 int regmap_raw_write(struct regmap *map, uint offset, const void *val,
542                      size_t val_len)
543 {
544         return regmap_raw_write_range(map, 0, offset, val, val_len);
545 }
546
547 int regmap_write(struct regmap *map, uint offset, uint val)
548 {
549         return regmap_raw_write(map, offset, &val, map->width);
550 }
551
552 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
553 {
554         uint reg;
555         int ret;
556
557         ret = regmap_read(map, offset, &reg);
558         if (ret)
559                 return ret;
560
561         reg &= ~mask;
562
563         return regmap_write(map, offset, reg | (val & mask));
564 }
565
566 int regmap_field_read(struct regmap_field *field, unsigned int *val)
567 {
568         int ret;
569         unsigned int reg_val;
570
571         ret = regmap_read(field->regmap, field->reg, &reg_val);
572         if (ret != 0)
573                 return ret;
574
575         reg_val &= field->mask;
576         reg_val >>= field->shift;
577         *val = reg_val;
578
579         return ret;
580 }
581
582 int regmap_field_write(struct regmap_field *field, unsigned int val)
583 {
584         return regmap_update_bits(field->regmap, field->reg, field->mask,
585                                   val << field->shift);
586 }
587
588 static void regmap_field_init(struct regmap_field *rm_field,
589                               struct regmap *regmap,
590                               struct reg_field reg_field)
591 {
592         rm_field->regmap = regmap;
593         rm_field->reg = reg_field.reg;
594         rm_field->shift = reg_field.lsb;
595         rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
596 }
597
598 struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
599                                              struct regmap *regmap,
600                                              struct reg_field reg_field)
601 {
602         struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
603                                                      GFP_KERNEL);
604         if (!rm_field)
605                 return ERR_PTR(-ENOMEM);
606
607         regmap_field_init(rm_field, regmap, reg_field);
608
609         return rm_field;
610 }
611
612 void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
613 {
614         devm_kfree(dev, field);
615 }
616
617 struct regmap_field *regmap_field_alloc(struct regmap *regmap,
618                                         struct reg_field reg_field)
619 {
620         struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
621
622         if (!rm_field)
623                 return ERR_PTR(-ENOMEM);
624
625         regmap_field_init(rm_field, regmap, reg_field);
626
627         return rm_field;
628 }
629
630 void regmap_field_free(struct regmap_field *field)
631 {
632         kfree(field);
633 }
This page took 0.062306 seconds and 4 git commands to generate.