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