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