uboot/drivers/core/fdtaddr.c
<<
>>
Prefs
   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 <log.h>
  15#include <asm/global_data.h>
  16#include <asm/io.h>
  17#include <dm/device-internal.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
  22{
  23#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
  24        fdt_addr_t addr;
  25
  26        if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
  27                const fdt32_t *reg;
  28                int len = 0;
  29                int na, ns;
  30
  31                na = fdt_address_cells(gd->fdt_blob,
  32                                       dev_of_offset(dev->parent));
  33                if (na < 1) {
  34                        debug("bad #address-cells\n");
  35                        return FDT_ADDR_T_NONE;
  36                }
  37
  38                ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
  39                if (ns < 0) {
  40                        debug("bad #size-cells\n");
  41                        return FDT_ADDR_T_NONE;
  42                }
  43
  44                reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg",
  45                                  &len);
  46                if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
  47                        debug("Req index out of range\n");
  48                        return FDT_ADDR_T_NONE;
  49                }
  50
  51                reg += index * (na + ns);
  52
  53                if (ns || gd_size_cells_0()) {
  54                        /*
  55                         * Use the full-fledged translate function for complex
  56                         * bus setups.
  57                         */
  58                        addr = fdt_translate_address((void *)gd->fdt_blob,
  59                                                     dev_of_offset(dev), 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,
  70                                dev_of_offset(dev->parent), dev_of_offset(dev),
  71                                "reg", index, 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#else
  92        return FDT_ADDR_T_NONE;
  93#endif
  94}
  95
  96fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index,
  97                                      fdt_size_t *size)
  98{
  99#if CONFIG_IS_ENABLED(OF_CONTROL)
 100        /*
 101         * Only get the size in this first call. We'll get the addr in the
 102         * next call to the exisiting dev_get_xxx function which handles
 103         * all config options.
 104         */
 105        fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),
 106                                           "reg", index, size, false);
 107
 108        /*
 109         * Get the base address via the existing function which handles
 110         * all Kconfig cases
 111         */
 112        return devfdt_get_addr_index(dev, index);
 113#else
 114        return FDT_ADDR_T_NONE;
 115#endif
 116}
 117
 118fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name)
 119{
 120#if CONFIG_IS_ENABLED(OF_CONTROL)
 121        int index;
 122
 123        index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
 124                                      "reg-names", name);
 125        if (index < 0)
 126                return index;
 127
 128        return devfdt_get_addr_index(dev, index);
 129#else
 130        return FDT_ADDR_T_NONE;
 131#endif
 132}
 133
 134fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
 135                                     const char *name, fdt_size_t *size)
 136{
 137#if CONFIG_IS_ENABLED(OF_CONTROL)
 138        int index;
 139
 140        index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
 141                                      "reg-names", name);
 142        if (index < 0)
 143                return index;
 144
 145        return devfdt_get_addr_size_index(dev, index, size);
 146#else
 147        return FDT_ADDR_T_NONE;
 148#endif
 149}
 150
 151fdt_addr_t devfdt_get_addr(const struct udevice *dev)
 152{
 153        return devfdt_get_addr_index(dev, 0);
 154}
 155
 156void *devfdt_get_addr_ptr(const struct udevice *dev)
 157{
 158        fdt_addr_t addr = devfdt_get_addr_index(dev, 0);
 159
 160        return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr;
 161}
 162
 163void *devfdt_remap_addr_index(const struct udevice *dev, int index)
 164{
 165        fdt_addr_t addr = devfdt_get_addr_index(dev, index);
 166
 167        if (addr == FDT_ADDR_T_NONE)
 168                return NULL;
 169
 170        return map_physmem(addr, 0, MAP_NOCACHE);
 171}
 172
 173void *devfdt_remap_addr_name(const struct udevice *dev, const char *name)
 174{
 175        fdt_addr_t addr = devfdt_get_addr_name(dev, name);
 176
 177        if (addr == FDT_ADDR_T_NONE)
 178                return NULL;
 179
 180        return map_physmem(addr, 0, MAP_NOCACHE);
 181}
 182
 183void *devfdt_remap_addr(const struct udevice *dev)
 184{
 185        return devfdt_remap_addr_index(dev, 0);
 186}
 187
 188void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
 189{
 190        fdt_addr_t addr = devfdt_get_addr(dev);
 191
 192        if (addr == FDT_ADDR_T_NONE)
 193                return NULL;
 194
 195        return map_physmem(addr, size, MAP_NOCACHE);
 196}
 197
 198fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
 199{
 200        ulong addr;
 201
 202        addr = devfdt_get_addr(dev);
 203        if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
 204            addr == FDT_ADDR_T_NONE) {
 205                struct fdt_pci_addr pci_addr;
 206                u32 bar;
 207                int ret;
 208
 209                ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
 210                                           "reg", &pci_addr);
 211                if (ret) {
 212                        /* try if there is any i/o-mapped register */
 213                        ret = ofnode_read_pci_addr(dev_ofnode(dev),
 214                                                   FDT_PCI_SPACE_IO, "reg",
 215                                                   &pci_addr);
 216                        if (ret)
 217                                return FDT_ADDR_T_NONE;
 218                }
 219                ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
 220                if (ret)
 221                        return FDT_ADDR_T_NONE;
 222                addr = bar;
 223        }
 224
 225        return addr;
 226}
 227