regmap: zero out the regmap on allocation
[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 <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
22 DECLARE_GLOBAL_DATA_PTR;
23
24 /**
25  * regmap_alloc() - Allocate a regmap with a given number of ranges.
26  *
27  * @count: Number of ranges to be allocated for the regmap.
28  * Return: A pointer to the newly allocated regmap, or NULL on error.
29  */
30 static struct regmap *regmap_alloc(int count)
31 {
32         struct regmap *map;
33         size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count;
34
35         map = calloc(1, size);
36         if (!map)
37                 return NULL;
38         map->range_count = count;
39
40         return map;
41 }
42
43 #if CONFIG_IS_ENABLED(OF_PLATDATA)
44 int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
45                              struct regmap **mapp)
46 {
47         struct regmap_range *range;
48         struct regmap *map;
49
50         map = regmap_alloc(count);
51         if (!map)
52                 return -ENOMEM;
53
54         for (range = map->ranges; count > 0; reg += 2, range++, count--) {
55                 range->start = *reg;
56                 range->size = reg[1];
57         }
58
59         *mapp = map;
60
61         return 0;
62 }
63 #else
64 /**
65  * init_range() - Initialize a single range of a regmap
66  * @node:     Device node that will use the map in question
67  * @range:    Pointer to a regmap_range structure that will be initialized
68  * @addr_len: The length of the addr parts of the reg property
69  * @size_len: The length of the size parts of the reg property
70  * @index:    The index of the range to initialize
71  *
72  * This function will read the necessary 'reg' information from the device tree
73  * (the 'addr' part, and the 'length' part), and initialize the range in
74  * quesion.
75  *
76  * Return: 0 if OK, -ve on error
77  */
78 static int init_range(ofnode node, struct regmap_range *range, int addr_len,
79                       int size_len, int index)
80 {
81         fdt_size_t sz;
82         struct resource r;
83
84         if (of_live_active()) {
85                 int ret;
86
87                 ret = of_address_to_resource(ofnode_to_np(node),
88                                              index, &r);
89                 if (ret) {
90                         debug("%s: Could not read resource of range %d (ret = %d)\n",
91                               ofnode_get_name(node), index, ret);
92                         return ret;
93                 }
94
95                 range->start = r.start;
96                 range->size = r.end - r.start + 1;
97         } else {
98                 int offset = ofnode_to_offset(node);
99
100                 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset,
101                                                           "reg", index,
102                                                           addr_len, size_len,
103                                                           &sz, true);
104                 if (range->start == FDT_ADDR_T_NONE) {
105                         debug("%s: Could not read start of range %d\n",
106                               ofnode_get_name(node), index);
107                         return -EINVAL;
108                 }
109
110                 range->size = sz;
111         }
112
113         return 0;
114 }
115
116 int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index)
117 {
118         struct regmap *map;
119         int addr_len, size_len;
120         int ret;
121
122         addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
123         if (addr_len < 0) {
124                 debug("%s: Error while reading the addr length (ret = %d)\n",
125                       ofnode_get_name(node), addr_len);
126                 return addr_len;
127         }
128
129         size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
130         if (size_len < 0) {
131                 debug("%s: Error while reading the size length: (ret = %d)\n",
132                       ofnode_get_name(node), size_len);
133                 return size_len;
134         }
135
136         map = regmap_alloc(1);
137         if (!map)
138                 return -ENOMEM;
139
140         ret = init_range(node, map->ranges, addr_len, size_len, index);
141         if (ret)
142                 goto err;
143
144         if (ofnode_read_bool(node, "little-endian"))
145                 map->endianness = REGMAP_LITTLE_ENDIAN;
146         else if (ofnode_read_bool(node, "big-endian"))
147                 map->endianness = REGMAP_BIG_ENDIAN;
148         else if (ofnode_read_bool(node, "native-endian"))
149                 map->endianness = REGMAP_NATIVE_ENDIAN;
150         else /* Default: native endianness */
151                 map->endianness = REGMAP_NATIVE_ENDIAN;
152
153         *mapp = map;
154
155         return 0;
156 err:
157         regmap_uninit(map);
158
159         return ret;
160 }
161
162 int regmap_init_mem(ofnode node, struct regmap **mapp)
163 {
164         struct regmap_range *range;
165         struct regmap *map;
166         int count;
167         int addr_len, size_len, both_len;
168         int len;
169         int index;
170         int ret;
171
172         addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
173         if (addr_len < 0) {
174                 debug("%s: Error while reading the addr length (ret = %d)\n",
175                       ofnode_get_name(node), addr_len);
176                 return addr_len;
177         }
178
179         size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
180         if (size_len < 0) {
181                 debug("%s: Error while reading the size length: (ret = %d)\n",
182                       ofnode_get_name(node), size_len);
183                 return size_len;
184         }
185
186         both_len = addr_len + size_len;
187         if (!both_len) {
188                 debug("%s: Both addr and size length are zero\n",
189                       ofnode_get_name(node));
190                 return -EINVAL;
191         }
192
193         len = ofnode_read_size(node, "reg");
194         if (len < 0) {
195                 debug("%s: Error while reading reg size (ret = %d)\n",
196                       ofnode_get_name(node), len);
197                 return len;
198         }
199         len /= sizeof(fdt32_t);
200         count = len / both_len;
201         if (!count) {
202                 debug("%s: Not enough data in reg property\n",
203                       ofnode_get_name(node));
204                 return -EINVAL;
205         }
206
207         map = regmap_alloc(count);
208         if (!map)
209                 return -ENOMEM;
210
211         for (range = map->ranges, index = 0; count > 0;
212              count--, range++, index++) {
213                 ret = init_range(node, range, addr_len, size_len, index);
214                 if (ret)
215                         goto err;
216         }
217
218         if (ofnode_read_bool(node, "little-endian"))
219                 map->endianness = REGMAP_LITTLE_ENDIAN;
220         else if (ofnode_read_bool(node, "big-endian"))
221                 map->endianness = REGMAP_BIG_ENDIAN;
222         else if (ofnode_read_bool(node, "native-endian"))
223                 map->endianness = REGMAP_NATIVE_ENDIAN;
224         else /* Default: native endianness */
225                 map->endianness = REGMAP_NATIVE_ENDIAN;
226
227         *mapp = map;
228
229         return 0;
230 err:
231         regmap_uninit(map);
232
233         return ret;
234 }
235
236 static void devm_regmap_release(struct udevice *dev, void *res)
237 {
238         regmap_uninit(*(struct regmap **)res);
239 }
240
241 struct regmap *devm_regmap_init(struct udevice *dev,
242                                 const struct regmap_bus *bus,
243                                 void *bus_context,
244                                 const struct regmap_config *config)
245 {
246         int rc;
247         struct regmap **mapp;
248
249         mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
250                             __GFP_ZERO);
251         if (unlikely(!mapp))
252                 return ERR_PTR(-ENOMEM);
253
254         rc = regmap_init_mem(dev_ofnode(dev), mapp);
255         if (rc)
256                 return ERR_PTR(rc);
257
258         devres_add(dev, mapp);
259         return *mapp;
260 }
261 #endif
262
263 void *regmap_get_range(struct regmap *map, unsigned int range_num)
264 {
265         struct regmap_range *range;
266
267         if (range_num >= map->range_count)
268                 return NULL;
269         range = &map->ranges[range_num];
270
271         return map_sysmem(range->start, range->size);
272 }
273
274 int regmap_uninit(struct regmap *map)
275 {
276         free(map);
277
278         return 0;
279 }
280
281 static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
282 {
283         return readb(addr);
284 }
285
286 static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
287 {
288         switch (endianness) {
289         case REGMAP_LITTLE_ENDIAN:
290                 return in_le16(addr);
291         case REGMAP_BIG_ENDIAN:
292                 return in_be16(addr);
293         case REGMAP_NATIVE_ENDIAN:
294                 return readw(addr);
295         }
296
297         return readw(addr);
298 }
299
300 static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
301 {
302         switch (endianness) {
303         case REGMAP_LITTLE_ENDIAN:
304                 return in_le32(addr);
305         case REGMAP_BIG_ENDIAN:
306                 return in_be32(addr);
307         case REGMAP_NATIVE_ENDIAN:
308                 return readl(addr);
309         }
310
311         return readl(addr);
312 }
313
314 #if defined(in_le64) && defined(in_be64) && defined(readq)
315 static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
316 {
317         switch (endianness) {
318         case REGMAP_LITTLE_ENDIAN:
319                 return in_le64(addr);
320         case REGMAP_BIG_ENDIAN:
321                 return in_be64(addr);
322         case REGMAP_NATIVE_ENDIAN:
323                 return readq(addr);
324         }
325
326         return readq(addr);
327 }
328 #endif
329
330 int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
331                           void *valp, size_t val_len)
332 {
333         struct regmap_range *range;
334         void *ptr;
335
336         if (range_num >= map->range_count) {
337                 debug("%s: range index %d larger than range count\n",
338                       __func__, range_num);
339                 return -ERANGE;
340         }
341         range = &map->ranges[range_num];
342
343         if (offset + val_len > range->size) {
344                 debug("%s: offset/size combination invalid\n", __func__);
345                 return -ERANGE;
346         }
347
348         ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
349
350         switch (val_len) {
351         case REGMAP_SIZE_8:
352                 *((u8 *)valp) = __read_8(ptr, map->endianness);
353                 break;
354         case REGMAP_SIZE_16:
355                 *((u16 *)valp) = __read_16(ptr, map->endianness);
356                 break;
357         case REGMAP_SIZE_32:
358                 *((u32 *)valp) = __read_32(ptr, map->endianness);
359                 break;
360 #if defined(in_le64) && defined(in_be64) && defined(readq)
361         case REGMAP_SIZE_64:
362                 *((u64 *)valp) = __read_64(ptr, map->endianness);
363                 break;
364 #endif
365         default:
366                 debug("%s: regmap size %zu unknown\n", __func__, val_len);
367                 return -EINVAL;
368         }
369
370         return 0;
371 }
372
373 int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
374 {
375         return regmap_raw_read_range(map, 0, offset, valp, val_len);
376 }
377
378 int regmap_read(struct regmap *map, uint offset, uint *valp)
379 {
380         return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
381 }
382
383 static inline void __write_8(u8 *addr, const u8 *val,
384                              enum regmap_endianness_t endianness)
385 {
386         writeb(*val, addr);
387 }
388
389 static inline void __write_16(u16 *addr, const u16 *val,
390                               enum regmap_endianness_t endianness)
391 {
392         switch (endianness) {
393         case REGMAP_NATIVE_ENDIAN:
394                 writew(*val, addr);
395                 break;
396         case REGMAP_LITTLE_ENDIAN:
397                 out_le16(addr, *val);
398                 break;
399         case REGMAP_BIG_ENDIAN:
400                 out_be16(addr, *val);
401                 break;
402         }
403 }
404
405 static inline void __write_32(u32 *addr, const u32 *val,
406                               enum regmap_endianness_t endianness)
407 {
408         switch (endianness) {
409         case REGMAP_NATIVE_ENDIAN:
410                 writel(*val, addr);
411                 break;
412         case REGMAP_LITTLE_ENDIAN:
413                 out_le32(addr, *val);
414                 break;
415         case REGMAP_BIG_ENDIAN:
416                 out_be32(addr, *val);
417                 break;
418         }
419 }
420
421 #if defined(out_le64) && defined(out_be64) && defined(writeq)
422 static inline void __write_64(u64 *addr, const u64 *val,
423                               enum regmap_endianness_t endianness)
424 {
425         switch (endianness) {
426         case REGMAP_NATIVE_ENDIAN:
427                 writeq(*val, addr);
428                 break;
429         case REGMAP_LITTLE_ENDIAN:
430                 out_le64(addr, *val);
431                 break;
432         case REGMAP_BIG_ENDIAN:
433                 out_be64(addr, *val);
434                 break;
435         }
436 }
437 #endif
438
439 int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
440                            const void *val, size_t val_len)
441 {
442         struct regmap_range *range;
443         void *ptr;
444
445         if (range_num >= map->range_count) {
446                 debug("%s: range index %d larger than range count\n",
447                       __func__, range_num);
448                 return -ERANGE;
449         }
450         range = &map->ranges[range_num];
451
452         if (offset + val_len > range->size) {
453                 debug("%s: offset/size combination invalid\n", __func__);
454                 return -ERANGE;
455         }
456
457         ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
458
459         switch (val_len) {
460         case REGMAP_SIZE_8:
461                 __write_8(ptr, val, map->endianness);
462                 break;
463         case REGMAP_SIZE_16:
464                 __write_16(ptr, val, map->endianness);
465                 break;
466         case REGMAP_SIZE_32:
467                 __write_32(ptr, val, map->endianness);
468                 break;
469 #if defined(out_le64) && defined(out_be64) && defined(writeq)
470         case REGMAP_SIZE_64:
471                 __write_64(ptr, val, map->endianness);
472                 break;
473 #endif
474         default:
475                 debug("%s: regmap size %zu unknown\n", __func__, val_len);
476                 return -EINVAL;
477         }
478
479         return 0;
480 }
481
482 int regmap_raw_write(struct regmap *map, uint offset, const void *val,
483                      size_t val_len)
484 {
485         return regmap_raw_write_range(map, 0, offset, val, val_len);
486 }
487
488 int regmap_write(struct regmap *map, uint offset, uint val)
489 {
490         return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
491 }
492
493 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
494 {
495         uint reg;
496         int ret;
497
498         ret = regmap_read(map, offset, &reg);
499         if (ret)
500                 return ret;
501
502         reg &= ~mask;
503
504         return regmap_write(map, offset, reg | (val & mask));
505 }