"Das U-Boot" Source Tree
at master 276 lines 6.5 kB view raw
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 <dm.h> 12#include <fdt_support.h> 13#include <log.h> 14#include <mapmem.h> 15#include <asm/global_data.h> 16#include <asm/io.h> 17#include <dm/device-internal.h> 18#include <dm/util.h> 19 20DECLARE_GLOBAL_DATA_PTR; 21 22#if CONFIG_IS_ENABLED(OF_REAL) || CONFIG_IS_ENABLED(OF_CONTROL) 23fdt_addr_t devfdt_get_addr_index_parent(const struct udevice *dev, int index, 24 int offset, int parent) 25{ 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 dm_warn("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 dm_warn("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 dm_warn("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} 92#endif 93 94fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index) 95{ 96#if CONFIG_IS_ENABLED(OF_REAL) 97 int offset = dev_of_offset(dev); 98 int parent = fdt_parent_offset(gd->fdt_blob, offset); 99 return devfdt_get_addr_index_parent(dev, index, offset, parent); 100#else 101 return FDT_ADDR_T_NONE; 102#endif 103} 104 105void *devfdt_get_addr_index_ptr(const struct udevice *dev, int index) 106{ 107 fdt_addr_t addr = devfdt_get_addr_index(dev, index); 108 109 if (addr == FDT_ADDR_T_NONE) 110 return NULL; 111 112 return map_sysmem(addr, 0); 113} 114 115fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index, 116 fdt_size_t *size) 117{ 118#if CONFIG_IS_ENABLED(OF_CONTROL) 119 /* 120 * Only get the size in this first call. We'll get the addr in the 121 * next call to the exisiting dev_get_xxx function which handles 122 * all config options. 123 */ 124 int offset = dev_of_offset(dev); 125 int parent = fdt_parent_offset(gd->fdt_blob, offset); 126 fdtdec_get_addr_size_auto_parent(gd->fdt_blob, parent, offset, 127 "reg", index, size, false); 128 129 /* 130 * Get the base address via the existing function which handles 131 * all Kconfig cases 132 */ 133 return devfdt_get_addr_index_parent(dev, index, offset, parent); 134#else 135 return FDT_ADDR_T_NONE; 136#endif 137} 138 139void *devfdt_get_addr_size_index_ptr(const struct udevice *dev, int index, 140 fdt_size_t *size) 141{ 142 fdt_addr_t addr = devfdt_get_addr_size_index(dev, index, size); 143 144 if (addr == FDT_ADDR_T_NONE) 145 return NULL; 146 147 return map_sysmem(addr, 0); 148} 149 150fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name) 151{ 152#if CONFIG_IS_ENABLED(OF_CONTROL) 153 int index; 154 155 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), 156 "reg-names", name); 157 if (index < 0) 158 return FDT_ADDR_T_NONE; 159 160 return devfdt_get_addr_index(dev, index); 161#else 162 return FDT_ADDR_T_NONE; 163#endif 164} 165 166void *devfdt_get_addr_name_ptr(const struct udevice *dev, const char *name) 167{ 168 fdt_addr_t addr = devfdt_get_addr_name(dev, name); 169 170 if (addr == FDT_ADDR_T_NONE) 171 return NULL; 172 173 return map_sysmem(addr, 0); 174} 175 176fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev, 177 const char *name, fdt_size_t *size) 178{ 179#if CONFIG_IS_ENABLED(OF_CONTROL) 180 int index; 181 182 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), 183 "reg-names", name); 184 if (index < 0) 185 return FDT_ADDR_T_NONE; 186 187 return devfdt_get_addr_size_index(dev, index, size); 188#else 189 return FDT_ADDR_T_NONE; 190#endif 191} 192 193void *devfdt_get_addr_size_name_ptr(const struct udevice *dev, 194 const char *name, fdt_size_t *size) 195{ 196 fdt_addr_t addr = devfdt_get_addr_size_name(dev, name, size); 197 198 if (addr == FDT_ADDR_T_NONE) 199 return NULL; 200 201 return map_sysmem(addr, 0); 202} 203 204fdt_addr_t devfdt_get_addr(const struct udevice *dev) 205{ 206 return devfdt_get_addr_index(dev, 0); 207} 208 209void *devfdt_get_addr_ptr(const struct udevice *dev) 210{ 211 return devfdt_get_addr_index_ptr(dev, 0); 212} 213 214void *devfdt_remap_addr_index(const struct udevice *dev, int index) 215{ 216 fdt_addr_t addr = devfdt_get_addr_index(dev, index); 217 218 if (addr == FDT_ADDR_T_NONE) 219 return NULL; 220 221 return map_physmem(addr, 0, MAP_NOCACHE); 222} 223 224void *devfdt_remap_addr_name(const struct udevice *dev, const char *name) 225{ 226 fdt_addr_t addr = devfdt_get_addr_name(dev, name); 227 228 if (addr == FDT_ADDR_T_NONE) 229 return NULL; 230 231 return map_physmem(addr, 0, MAP_NOCACHE); 232} 233 234void *devfdt_remap_addr(const struct udevice *dev) 235{ 236 return devfdt_remap_addr_index(dev, 0); 237} 238 239void *devfdt_map_physmem(const struct udevice *dev, unsigned long size) 240{ 241 fdt_addr_t addr = devfdt_get_addr(dev); 242 243 if (addr == FDT_ADDR_T_NONE) 244 return NULL; 245 246 return map_physmem(addr, size, MAP_NOCACHE); 247} 248 249fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep) 250{ 251 ulong addr; 252 253 addr = devfdt_get_addr(dev); 254 if (CONFIG_IS_ENABLED(PCI) && addr == FDT_ADDR_T_NONE) { 255 struct fdt_pci_addr pci_addr; 256 u32 bar; 257 int ret; 258 259 ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32, 260 "reg", &pci_addr, sizep); 261 if (ret) { 262 /* try if there is any i/o-mapped register */ 263 ret = ofnode_read_pci_addr(dev_ofnode(dev), 264 FDT_PCI_SPACE_IO, "reg", 265 &pci_addr, sizep); 266 if (ret) 267 return FDT_ADDR_T_NONE; 268 } 269 ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar); 270 if (ret) 271 return FDT_ADDR_T_NONE; 272 addr = bar; 273 } 274 275 return addr; 276}