Merge tag 'xilinx-for-v2023.01-rc3' of https://source.denx.de/u-boot/custodians/u...
[platform/kernel/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 <asm/global_data.h>
16 #include <asm/io.h>
17 #include <dm/device-internal.h>
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
22 {
23 #if CONFIG_IS_ENABLED(OF_REAL)
24         int offset = dev_of_offset(dev);
25         int parent = dev_of_offset(dev->parent);
26         fdt_addr_t addr;
27
28         if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
29                 const fdt32_t *reg;
30                 int len = 0;
31                 int na, ns;
32
33                 na = fdt_address_cells(gd->fdt_blob, parent);
34                 if (na < 1) {
35                         debug("bad #address-cells\n");
36                         return FDT_ADDR_T_NONE;
37                 }
38
39                 ns = fdt_size_cells(gd->fdt_blob, parent);
40                 if (ns < 0) {
41                         debug("bad #size-cells\n");
42                         return FDT_ADDR_T_NONE;
43                 }
44
45                 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
46                 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
47                         debug("Req index out of range\n");
48                         return FDT_ADDR_T_NONE;
49                 }
50
51                 reg += index * (na + ns);
52
53                 if (ns) {
54                         /*
55                          * Use the full-fledged translate function for complex
56                          * bus setups.
57                          */
58                         addr = fdt_translate_address((void *)gd->fdt_blob,
59                                                      offset, reg);
60                 } else {
61                         /* Non translatable if #size-cells == 0 */
62                         addr = fdt_read_number(reg, na);
63                 }
64         } else {
65                 /*
66                  * Use the "simple" translate function for less complex
67                  * bus setups.
68                  */
69                 addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, parent,
70                                                         offset, "reg", index,
71                                                         NULL, false);
72                 if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
73                         if (device_get_uclass_id(dev->parent) ==
74                             UCLASS_SIMPLE_BUS)
75                                 addr = simple_bus_translate(dev->parent, addr);
76                 }
77         }
78
79 #if defined(CONFIG_TRANSLATION_OFFSET)
80         /*
81          * Some platforms need a special address translation. Those
82          * platforms (e.g. mvebu in SPL) can configure a translation
83          * offset by setting this value in the GD and enaling this
84          * feature via CONFIG_TRANSLATION_OFFSET. This value will
85          * get added to all addresses returned by devfdt_get_addr().
86          */
87         addr += gd->translation_offset;
88 #endif
89
90         return addr;
91 #else
92         return FDT_ADDR_T_NONE;
93 #endif
94 }
95
96 void *devfdt_get_addr_index_ptr(const struct udevice *dev, int index)
97 {
98         fdt_addr_t addr = devfdt_get_addr_index(dev, index);
99
100         return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr;
101 }
102
103 fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index,
104                                       fdt_size_t *size)
105 {
106 #if CONFIG_IS_ENABLED(OF_CONTROL)
107         /*
108          * Only get the size in this first call. We'll get the addr in the
109          * next call to the exisiting dev_get_xxx function which handles
110          * all config options.
111          */
112         fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),
113                                            "reg", index, size, false);
114
115         /*
116          * Get the base address via the existing function which handles
117          * all Kconfig cases
118          */
119         return devfdt_get_addr_index(dev, index);
120 #else
121         return FDT_ADDR_T_NONE;
122 #endif
123 }
124
125 fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name)
126 {
127 #if CONFIG_IS_ENABLED(OF_CONTROL)
128         int index;
129
130         index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
131                                       "reg-names", name);
132         if (index < 0)
133                 return index;
134
135         return devfdt_get_addr_index(dev, index);
136 #else
137         return FDT_ADDR_T_NONE;
138 #endif
139 }
140
141 fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
142                                      const char *name, fdt_size_t *size)
143 {
144 #if CONFIG_IS_ENABLED(OF_CONTROL)
145         int index;
146
147         index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
148                                       "reg-names", name);
149         if (index < 0)
150                 return index;
151
152         return devfdt_get_addr_size_index(dev, index, size);
153 #else
154         return FDT_ADDR_T_NONE;
155 #endif
156 }
157
158 fdt_addr_t devfdt_get_addr(const struct udevice *dev)
159 {
160         return devfdt_get_addr_index(dev, 0);
161 }
162
163 void *devfdt_get_addr_ptr(const struct udevice *dev)
164 {
165         return devfdt_get_addr_index_ptr(dev, 0);
166 }
167
168 void *devfdt_remap_addr_index(const struct udevice *dev, int index)
169 {
170         fdt_addr_t addr = devfdt_get_addr_index(dev, index);
171
172         if (addr == FDT_ADDR_T_NONE)
173                 return NULL;
174
175         return map_physmem(addr, 0, MAP_NOCACHE);
176 }
177
178 void *devfdt_remap_addr_name(const struct udevice *dev, const char *name)
179 {
180         fdt_addr_t addr = devfdt_get_addr_name(dev, name);
181
182         if (addr == FDT_ADDR_T_NONE)
183                 return NULL;
184
185         return map_physmem(addr, 0, MAP_NOCACHE);
186 }
187
188 void *devfdt_remap_addr(const struct udevice *dev)
189 {
190         return devfdt_remap_addr_index(dev, 0);
191 }
192
193 void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
194 {
195         fdt_addr_t addr = devfdt_get_addr(dev);
196
197         if (addr == FDT_ADDR_T_NONE)
198                 return NULL;
199
200         return map_physmem(addr, size, MAP_NOCACHE);
201 }
202
203 fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
204 {
205         ulong addr;
206
207         addr = devfdt_get_addr(dev);
208         if (CONFIG_IS_ENABLED(PCI) && addr == FDT_ADDR_T_NONE) {
209                 struct fdt_pci_addr pci_addr;
210                 u32 bar;
211                 int ret;
212
213                 ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
214                                            "reg", &pci_addr);
215                 if (ret) {
216                         /* try if there is any i/o-mapped register */
217                         ret = ofnode_read_pci_addr(dev_ofnode(dev),
218                                                    FDT_PCI_SPACE_IO, "reg",
219                                                    &pci_addr);
220                         if (ret)
221                                 return FDT_ADDR_T_NONE;
222                 }
223                 ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
224                 if (ret)
225                         return FDT_ADDR_T_NONE;
226                 addr = bar;
227         }
228
229         return addr;
230 }