1 /* 2 * Device addresses 3 * 4 * Copyright (c) 2017 Google, Inc 5 * 6 * (C) Copyright 2012 7 * Pavel Herrmann <morpheus.ibis@gmail.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <dm.h> 14 #include <fdt_support.h> 15 #include <asm/io.h> 16 #include <dm/device-internal.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 fdt_addr_t devfdt_get_addr_index(struct udevice *dev, int index) 21 { 22 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) 23 fdt_addr_t addr; 24 25 if (CONFIG_IS_ENABLED(OF_TRANSLATE)) { 26 const fdt32_t *reg; 27 int len = 0; 28 int na, ns; 29 30 na = fdt_address_cells(gd->fdt_blob, 31 dev_of_offset(dev->parent)); 32 if (na < 1) { 33 debug("bad #address-cells\n"); 34 return FDT_ADDR_T_NONE; 35 } 36 37 ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent)); 38 if (ns < 0) { 39 debug("bad #size-cells\n"); 40 return FDT_ADDR_T_NONE; 41 } 42 43 reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg", 44 &len); 45 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) { 46 debug("Req index out of range\n"); 47 return FDT_ADDR_T_NONE; 48 } 49 50 reg += index * (na + ns); 51 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 /* 60 * Use the "simple" translate function for less complex 61 * bus setups. 62 */ 63 addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, 64 dev_of_offset(dev->parent), dev_of_offset(dev), 65 "reg", index, NULL, false); 66 if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) { 67 if (device_get_uclass_id(dev->parent) == 68 UCLASS_SIMPLE_BUS) 69 addr = simple_bus_translate(dev->parent, addr); 70 } 71 } 72 73 /* 74 * Some platforms need a special address translation. Those 75 * platforms (e.g. mvebu in SPL) can configure a translation 76 * offset in the DM by calling dm_set_translation_offset() that 77 * will get added to all addresses returned by devfdt_get_addr(). 78 */ 79 addr += dm_get_translation_offset(); 80 81 return addr; 82 #else 83 return FDT_ADDR_T_NONE; 84 #endif 85 } 86 87 fdt_addr_t devfdt_get_addr_size_index(struct udevice *dev, int index, 88 fdt_size_t *size) 89 { 90 #if CONFIG_IS_ENABLED(OF_CONTROL) 91 /* 92 * Only get the size in this first call. We'll get the addr in the 93 * next call to the exisiting dev_get_xxx function which handles 94 * all config options. 95 */ 96 fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev), 97 "reg", index, size, false); 98 99 /* 100 * Get the base address via the existing function which handles 101 * all Kconfig cases 102 */ 103 return devfdt_get_addr_index(dev, index); 104 #else 105 return FDT_ADDR_T_NONE; 106 #endif 107 } 108 109 fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name) 110 { 111 #if CONFIG_IS_ENABLED(OF_CONTROL) 112 int index; 113 114 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), 115 "reg-names", name); 116 if (index < 0) 117 return index; 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(struct udevice *dev) 126 { 127 return devfdt_get_addr_index(dev, 0); 128 } 129 130 void *devfdt_get_addr_ptr(struct udevice *dev) 131 { 132 return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0); 133 } 134 135 void *devfdt_map_physmem(struct udevice *dev, unsigned long size) 136 { 137 fdt_addr_t addr = devfdt_get_addr(dev); 138 139 if (addr == FDT_ADDR_T_NONE) 140 return NULL; 141 142 return map_physmem(addr, size, MAP_NOCACHE); 143 } 144