]> git.ipfire.org Git - thirdparty/u-boot.git/blob - drivers/core/fdtaddr.c
dm: core: Fix address translation in devfdt_get_addr_index()
[thirdparty/u-boot.git] / drivers / core / fdtaddr.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Device addresses
4 *
5 * Copyright (c) 2017 Google, Inc
6 *
7 * (C) Copyright 2012
8 * Pavel Herrmann <morpheus.ibis@gmail.com>
9 */
10
11 #include <common.h>
12 #include <dm.h>
13 #include <fdt_support.h>
14 #include <log.h>
15 #include <mapmem.h>
16 #include <asm/global_data.h>
17 #include <asm/io.h>
18 #include <dm/device-internal.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
23 {
24 #if CONFIG_IS_ENABLED(OF_REAL)
25 int offset = dev_of_offset(dev);
26 int parent = fdt_parent_offset(gd->fdt_blob, offset);
27 fdt_addr_t addr;
28
29 if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
30 const fdt32_t *reg;
31 int len = 0;
32 int na, ns;
33
34 na = fdt_address_cells(gd->fdt_blob, parent);
35 if (na < 1) {
36 debug("bad #address-cells\n");
37 return FDT_ADDR_T_NONE;
38 }
39
40 ns = fdt_size_cells(gd->fdt_blob, parent);
41 if (ns < 0) {
42 debug("bad #size-cells\n");
43 return FDT_ADDR_T_NONE;
44 }
45
46 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
47 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
48 debug("Req index out of range\n");
49 return FDT_ADDR_T_NONE;
50 }
51
52 reg += index * (na + ns);
53
54 if (ns) {
55 /*
56 * Use the full-fledged translate function for complex
57 * bus setups.
58 */
59 addr = fdt_translate_address((void *)gd->fdt_blob,
60 offset, reg);
61 } else {
62 /* Non translatable if #size-cells == 0 */
63 addr = fdt_read_number(reg, na);
64 }
65 } else {
66 /*
67 * Use the "simple" translate function for less complex
68 * bus setups.
69 */
70 addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, parent,
71 offset, "reg", index,
72 NULL, false);
73 if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
74 if (device_get_uclass_id(dev->parent) ==
75 UCLASS_SIMPLE_BUS)
76 addr = simple_bus_translate(dev->parent, addr);
77 }
78 }
79
80 #if defined(CONFIG_TRANSLATION_OFFSET)
81 /*
82 * Some platforms need a special address translation. Those
83 * platforms (e.g. mvebu in SPL) can configure a translation
84 * offset by setting this value in the GD and enaling this
85 * feature via CONFIG_TRANSLATION_OFFSET. This value will
86 * get added to all addresses returned by devfdt_get_addr().
87 */
88 addr += gd->translation_offset;
89 #endif
90
91 return addr;
92 #else
93 return FDT_ADDR_T_NONE;
94 #endif
95 }
96
97 void *devfdt_get_addr_index_ptr(const struct udevice *dev, int index)
98 {
99 fdt_addr_t addr = devfdt_get_addr_index(dev, index);
100
101 if (addr == FDT_ADDR_T_NONE)
102 return NULL;
103
104 return map_sysmem(addr, 0);
105 }
106
107 fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index,
108 fdt_size_t *size)
109 {
110 #if CONFIG_IS_ENABLED(OF_CONTROL)
111 /*
112 * Only get the size in this first call. We'll get the addr in the
113 * next call to the exisiting dev_get_xxx function which handles
114 * all config options.
115 */
116 fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),
117 "reg", index, size, false);
118
119 /*
120 * Get the base address via the existing function which handles
121 * all Kconfig cases
122 */
123 return devfdt_get_addr_index(dev, index);
124 #else
125 return FDT_ADDR_T_NONE;
126 #endif
127 }
128
129 void *devfdt_get_addr_size_index_ptr(const struct udevice *dev, int index,
130 fdt_size_t *size)
131 {
132 fdt_addr_t addr = devfdt_get_addr_size_index(dev, index, size);
133
134 if (addr == FDT_ADDR_T_NONE)
135 return NULL;
136
137 return map_sysmem(addr, 0);
138 }
139
140 fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name)
141 {
142 #if CONFIG_IS_ENABLED(OF_CONTROL)
143 int index;
144
145 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
146 "reg-names", name);
147 if (index < 0)
148 return FDT_ADDR_T_NONE;
149
150 return devfdt_get_addr_index(dev, index);
151 #else
152 return FDT_ADDR_T_NONE;
153 #endif
154 }
155
156 void *devfdt_get_addr_name_ptr(const struct udevice *dev, const char *name)
157 {
158 fdt_addr_t addr = devfdt_get_addr_name(dev, name);
159
160 if (addr == FDT_ADDR_T_NONE)
161 return NULL;
162
163 return map_sysmem(addr, 0);
164 }
165
166 fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
167 const char *name, fdt_size_t *size)
168 {
169 #if CONFIG_IS_ENABLED(OF_CONTROL)
170 int index;
171
172 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
173 "reg-names", name);
174 if (index < 0)
175 return FDT_ADDR_T_NONE;
176
177 return devfdt_get_addr_size_index(dev, index, size);
178 #else
179 return FDT_ADDR_T_NONE;
180 #endif
181 }
182
183 void *devfdt_get_addr_size_name_ptr(const struct udevice *dev,
184 const char *name, fdt_size_t *size)
185 {
186 fdt_addr_t addr = devfdt_get_addr_size_name(dev, name, size);
187
188 if (addr == FDT_ADDR_T_NONE)
189 return NULL;
190
191 return map_sysmem(addr, 0);
192 }
193
194 fdt_addr_t devfdt_get_addr(const struct udevice *dev)
195 {
196 return devfdt_get_addr_index(dev, 0);
197 }
198
199 void *devfdt_get_addr_ptr(const struct udevice *dev)
200 {
201 return devfdt_get_addr_index_ptr(dev, 0);
202 }
203
204 void *devfdt_remap_addr_index(const struct udevice *dev, int index)
205 {
206 fdt_addr_t addr = devfdt_get_addr_index(dev, index);
207
208 if (addr == FDT_ADDR_T_NONE)
209 return NULL;
210
211 return map_physmem(addr, 0, MAP_NOCACHE);
212 }
213
214 void *devfdt_remap_addr_name(const struct udevice *dev, const char *name)
215 {
216 fdt_addr_t addr = devfdt_get_addr_name(dev, name);
217
218 if (addr == FDT_ADDR_T_NONE)
219 return NULL;
220
221 return map_physmem(addr, 0, MAP_NOCACHE);
222 }
223
224 void *devfdt_remap_addr(const struct udevice *dev)
225 {
226 return devfdt_remap_addr_index(dev, 0);
227 }
228
229 void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
230 {
231 fdt_addr_t addr = devfdt_get_addr(dev);
232
233 if (addr == FDT_ADDR_T_NONE)
234 return NULL;
235
236 return map_physmem(addr, size, MAP_NOCACHE);
237 }
238
239 fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
240 {
241 ulong addr;
242
243 addr = devfdt_get_addr(dev);
244 if (CONFIG_IS_ENABLED(PCI) && addr == FDT_ADDR_T_NONE) {
245 struct fdt_pci_addr pci_addr;
246 u32 bar;
247 int ret;
248
249 ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
250 "reg", &pci_addr, sizep);
251 if (ret) {
252 /* try if there is any i/o-mapped register */
253 ret = ofnode_read_pci_addr(dev_ofnode(dev),
254 FDT_PCI_SPACE_IO, "reg",
255 &pci_addr, sizep);
256 if (ret)
257 return FDT_ADDR_T_NONE;
258 }
259 ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
260 if (ret)
261 return FDT_ADDR_T_NONE;
262 addr = bar;
263 }
264
265 return addr;
266 }