a5e4e74825608e0b6a0750196f33df46615422ed
[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 <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 static struct regmap *regmap_alloc_count(int count)
21 {
22         struct regmap *map;
23
24         map = malloc(sizeof(struct regmap));
25         if (!map)
26                 return NULL;
27         if (count <= 1) {
28                 map->range = &map->base_range;
29         } else {
30                 map->range = malloc(count * sizeof(struct regmap_range));
31                 if (!map->range) {
32                         free(map);
33                         return NULL;
34                 }
35         }
36         map->range_count = count;
37
38         return map;
39 }
40
41 #if CONFIG_IS_ENABLED(OF_PLATDATA)
42 int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
43                              struct regmap **mapp)
44 {
45         struct regmap_range *range;
46         struct regmap *map;
47
48         map = regmap_alloc_count(count);
49         if (!map)
50                 return -ENOMEM;
51
52         map->base = *reg;
53         for (range = map->range; 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 int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
64 {
65         struct regmap_range *range;
66         struct regmap *map;
67         int count;
68         int addr_len, size_len, both_len;
69         int len;
70         int index;
71         ofnode node = dev_ofnode(dev);
72         struct resource r;
73
74         addr_len = dev_read_simple_addr_cells(dev->parent);
75         size_len = dev_read_simple_size_cells(dev->parent);
76         both_len = addr_len + size_len;
77
78         len = dev_read_size(dev, "reg");
79         if (len < 0)
80                 return len;
81         len /= sizeof(fdt32_t);
82         count = len / both_len;
83         if (!count)
84                 return -EINVAL;
85
86         map = regmap_alloc_count(count);
87         if (!map)
88                 return -ENOMEM;
89
90         for (range = map->range, index = 0; count > 0;
91              count--, range++, index++) {
92                 fdt_size_t sz;
93                 if (of_live_active()) {
94                         of_address_to_resource(ofnode_to_np(node), index, &r);
95                         range->start = r.start;
96                         range->size = r.end - r.start + 1;
97                 } else {
98                         range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
99                                         dev_of_offset(dev), "reg", index,
100                                         addr_len, size_len, &sz, true);
101                         range->size = sz;
102                 }
103         }
104         map->base = map->range[0].start;
105
106         *mapp = map;
107
108         return 0;
109 }
110 #endif
111
112 void *regmap_get_range(struct regmap *map, unsigned int range_num)
113 {
114         struct regmap_range *range;
115
116         if (range_num >= map->range_count)
117                 return NULL;
118         range = &map->range[range_num];
119
120         return map_sysmem(range->start, range->size);
121 }
122
123 int regmap_uninit(struct regmap *map)
124 {
125         if (map->range_count > 1)
126                 free(map->range);
127         free(map);
128
129         return 0;
130 }
131
132 int regmap_read(struct regmap *map, uint offset, uint *valp)
133 {
134         uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
135
136         *valp = le32_to_cpu(readl(ptr));
137
138         return 0;
139 }
140
141 int regmap_write(struct regmap *map, uint offset, uint val)
142 {
143         uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
144
145         writel(cpu_to_le32(val), ptr);
146
147         return 0;
148 }