diff options
Diffstat (limited to 'roms/u-boot/drivers/core/fdtaddr.c')
-rw-r--r-- | roms/u-boot/drivers/core/fdtaddr.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/core/fdtaddr.c b/roms/u-boot/drivers/core/fdtaddr.c new file mode 100644 index 000000000..b9874c743 --- /dev/null +++ b/roms/u-boot/drivers/core/fdtaddr.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Device addresses + * + * Copyright (c) 2017 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann <morpheus.ibis@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <fdt_support.h> +#include <log.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <dm/device-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) + fdt_addr_t addr; + + if (CONFIG_IS_ENABLED(OF_TRANSLATE)) { + const fdt32_t *reg; + int len = 0; + int na, ns; + + na = fdt_address_cells(gd->fdt_blob, + dev_of_offset(dev->parent)); + if (na < 1) { + debug("bad #address-cells\n"); + return FDT_ADDR_T_NONE; + } + + ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent)); + if (ns < 0) { + debug("bad #size-cells\n"); + return FDT_ADDR_T_NONE; + } + + reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg", + &len); + if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) { + debug("Req index out of range\n"); + return FDT_ADDR_T_NONE; + } + + reg += index * (na + ns); + + if (ns) { + /* + * Use the full-fledged translate function for complex + * bus setups. + */ + addr = fdt_translate_address((void *)gd->fdt_blob, + dev_of_offset(dev), reg); + } else { + /* Non translatable if #size-cells == 0 */ + addr = fdt_read_number(reg, na); + } + } else { + /* + * Use the "simple" translate function for less complex + * bus setups. + */ + addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, + dev_of_offset(dev->parent), dev_of_offset(dev), + "reg", index, NULL, false); + if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) { + if (device_get_uclass_id(dev->parent) == + UCLASS_SIMPLE_BUS) + addr = simple_bus_translate(dev->parent, addr); + } + } + +#if defined(CONFIG_TRANSLATION_OFFSET) + /* + * Some platforms need a special address translation. Those + * platforms (e.g. mvebu in SPL) can configure a translation + * offset by setting this value in the GD and enaling this + * feature via CONFIG_TRANSLATION_OFFSET. This value will + * get added to all addresses returned by devfdt_get_addr(). + */ + addr += gd->translation_offset; +#endif + + return addr; +#else + return FDT_ADDR_T_NONE; +#endif +} + +fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index, + fdt_size_t *size) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) + /* + * Only get the size in this first call. We'll get the addr in the + * next call to the exisiting dev_get_xxx function which handles + * all config options. + */ + fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev), + "reg", index, size, false); + + /* + * Get the base address via the existing function which handles + * all Kconfig cases + */ + return devfdt_get_addr_index(dev, index); +#else + return FDT_ADDR_T_NONE; +#endif +} + +fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) + int index; + + index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), + "reg-names", name); + if (index < 0) + return index; + + return devfdt_get_addr_index(dev, index); +#else + return FDT_ADDR_T_NONE; +#endif +} + +fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev, + const char *name, fdt_size_t *size) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) + int index; + + index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), + "reg-names", name); + if (index < 0) + return index; + + return devfdt_get_addr_size_index(dev, index, size); +#else + return FDT_ADDR_T_NONE; +#endif +} + +fdt_addr_t devfdt_get_addr(const struct udevice *dev) +{ + return devfdt_get_addr_index(dev, 0); +} + +void *devfdt_get_addr_ptr(const struct udevice *dev) +{ + fdt_addr_t addr = devfdt_get_addr_index(dev, 0); + + return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr; +} + +void *devfdt_remap_addr_index(const struct udevice *dev, int index) +{ + fdt_addr_t addr = devfdt_get_addr_index(dev, index); + + if (addr == FDT_ADDR_T_NONE) + return NULL; + + return map_physmem(addr, 0, MAP_NOCACHE); +} + +void *devfdt_remap_addr_name(const struct udevice *dev, const char *name) +{ + fdt_addr_t addr = devfdt_get_addr_name(dev, name); + + if (addr == FDT_ADDR_T_NONE) + return NULL; + + return map_physmem(addr, 0, MAP_NOCACHE); +} + +void *devfdt_remap_addr(const struct udevice *dev) +{ + return devfdt_remap_addr_index(dev, 0); +} + +void *devfdt_map_physmem(const struct udevice *dev, unsigned long size) +{ + fdt_addr_t addr = devfdt_get_addr(dev); + + if (addr == FDT_ADDR_T_NONE) + return NULL; + + return map_physmem(addr, size, MAP_NOCACHE); +} + +fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev) +{ + ulong addr; + + addr = devfdt_get_addr(dev); + if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) && + addr == FDT_ADDR_T_NONE) { + struct fdt_pci_addr pci_addr; + u32 bar; + int ret; + + ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32, + "reg", &pci_addr); + if (ret) { + /* try if there is any i/o-mapped register */ + ret = ofnode_read_pci_addr(dev_ofnode(dev), + FDT_PCI_SPACE_IO, "reg", + &pci_addr); + if (ret) + return FDT_ADDR_T_NONE; + } + ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar); + if (ret) + return FDT_ADDR_T_NONE; + addr = bar; + } + + return addr; +} |