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 <asm/io.h>
  15#include <dm/device-internal.h>
  16
  17DECLARE_GLOBAL_DATA_PTR;
  18
  19fdt_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
  91fdt_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
 113fdt_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
 129fdt_addr_t devfdt_get_addr(struct udevice *dev)
 130{
 131        return devfdt_get_addr_index(dev, 0);
 132}
 133
 134void *devfdt_get_addr_ptr(struct udevice *dev)
 135{
 136        return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0);
 137}
 138
 139void *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
 149void *devfdt_remap_addr(struct udevice *dev)
 150{
 151        return devfdt_remap_addr_index(dev, 0);
 152}
 153
 154void *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