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