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 if (ns) { 53 /* 54 * Use the full-fledged translate function for complex 55 * bus setups. 56 */ 57 addr = fdt_translate_address((void *)gd->fdt_blob, 58 dev_of_offset(dev), reg); 59 } else { 60 /* Non translatable if #size-cells == 0 */ 61 addr = fdt_read_number(reg, na); 62 } 63 } else { 64 /* 65 * Use the "simple" translate function for less complex 66 * bus setups. 67 */ 68 addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, 69 dev_of_offset(dev->parent), dev_of_offset(dev), 70 "reg", index, NULL, false); 71 if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) { 72 if (device_get_uclass_id(dev->parent) == 73 UCLASS_SIMPLE_BUS) 74 addr = simple_bus_translate(dev->parent, addr); 75 } 76 } 77 78 /* 79 * Some platforms need a special address translation. Those 80 * platforms (e.g. mvebu in SPL) can configure a translation 81 * offset in the DM by calling dm_set_translation_offset() that 82 * will get added to all addresses returned by devfdt_get_addr(). 83 */ 84 addr += dm_get_translation_offset(); 85 86 return addr; 87 #else 88 return FDT_ADDR_T_NONE; 89 #endif 90 } 91 92 fdt_addr_t devfdt_get_addr_size_index(struct udevice *dev, int index, 93 fdt_size_t *size) 94 { 95 #if CONFIG_IS_ENABLED(OF_CONTROL) 96 /* 97 * Only get the size in this first call. We'll get the addr in the 98 * next call to the exisiting dev_get_xxx function which handles 99 * all config options. 100 */ 101 fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev), 102 "reg", index, size, false); 103 104 /* 105 * Get the base address via the existing function which handles 106 * all Kconfig cases 107 */ 108 return devfdt_get_addr_index(dev, index); 109 #else 110 return FDT_ADDR_T_NONE; 111 #endif 112 } 113 114 fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name) 115 { 116 #if CONFIG_IS_ENABLED(OF_CONTROL) 117 int index; 118 119 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), 120 "reg-names", name); 121 if (index < 0) 122 return index; 123 124 return devfdt_get_addr_index(dev, index); 125 #else 126 return FDT_ADDR_T_NONE; 127 #endif 128 } 129 130 fdt_addr_t devfdt_get_addr(struct udevice *dev) 131 { 132 return devfdt_get_addr_index(dev, 0); 133 } 134 135 void *devfdt_get_addr_ptr(struct udevice *dev) 136 { 137 return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0); 138 } 139 140 void *devfdt_map_physmem(struct udevice *dev, unsigned long size) 141 { 142 fdt_addr_t addr = devfdt_get_addr(dev); 143 144 if (addr == FDT_ADDR_T_NONE) 145 return NULL; 146 147 return map_physmem(addr, size, MAP_NOCACHE); 148 } 149