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 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 /* 78 * Some platforms need a special address translation. Those 79 * platforms (e.g. mvebu in SPL) can configure a translation 80 * offset in the DM by calling dm_set_translation_offset() that 81 * will get added to all addresses returned by devfdt_get_addr(). 82 */ 83 addr += dm_get_translation_offset(); 84 85 return addr; 86 #else 87 return FDT_ADDR_T_NONE; 88 #endif 89 } 90 91 fdt_addr_t devfdt_get_addr_size_index(struct udevice *dev, int index, 92 fdt_size_t *size) 93 { 94 #if CONFIG_IS_ENABLED(OF_CONTROL) 95 /* 96 * Only get the size in this first call. We'll get the addr in the 97 * next call to the exisiting dev_get_xxx function which handles 98 * all config options. 99 */ 100 fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev), 101 "reg", index, size, false); 102 103 /* 104 * Get the base address via the existing function which handles 105 * all Kconfig cases 106 */ 107 return devfdt_get_addr_index(dev, index); 108 #else 109 return FDT_ADDR_T_NONE; 110 #endif 111 } 112 113 fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name) 114 { 115 #if CONFIG_IS_ENABLED(OF_CONTROL) 116 int index; 117 118 index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), 119 "reg-names", name); 120 if (index < 0) 121 return index; 122 123 return devfdt_get_addr_index(dev, index); 124 #else 125 return FDT_ADDR_T_NONE; 126 #endif 127 } 128 129 fdt_addr_t devfdt_get_addr(struct udevice *dev) 130 { 131 return devfdt_get_addr_index(dev, 0); 132 } 133 134 void *devfdt_get_addr_ptr(struct udevice *dev) 135 { 136 return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0); 137 } 138 139 void *devfdt_remap_addr_index(struct udevice *dev, int index) 140 { 141 fdt_addr_t addr = devfdt_get_addr(dev); 142 143 if (addr == FDT_ADDR_T_NONE) 144 return NULL; 145 146 return map_physmem(addr, 0, MAP_NOCACHE); 147 } 148 149 void *devfdt_remap_addr(struct udevice *dev) 150 { 151 return devfdt_remap_addr_index(dev, 0); 152 } 153 154 void *devfdt_map_physmem(struct udevice *dev, unsigned long size) 155 { 156 fdt_addr_t addr = devfdt_get_addr(dev); 157 158 if (addr == FDT_ADDR_T_NONE) 159 return NULL; 160 161 return map_physmem(addr, size, MAP_NOCACHE); 162 } 163