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