fdtaddr.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. #include <common.h>
  11. #include <dm.h>
  12. #include <fdt_support.h>
  13. #include <asm/io.h>
  14. #include <dm/device-internal.h>
  15. DECLARE_GLOBAL_DATA_PTR;
  16. fdt_addr_t devfdt_get_addr_index(struct udevice *dev, int index)
  17. {
  18. #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
  19. fdt_addr_t addr;
  20. if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
  21. const fdt32_t *reg;
  22. int len = 0;
  23. int na, ns;
  24. na = fdt_address_cells(gd->fdt_blob,
  25. dev_of_offset(dev->parent));
  26. if (na < 1) {
  27. debug("bad #address-cells\n");
  28. return FDT_ADDR_T_NONE;
  29. }
  30. ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
  31. if (ns < 0) {
  32. debug("bad #size-cells\n");
  33. return FDT_ADDR_T_NONE;
  34. }
  35. reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg",
  36. &len);
  37. if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
  38. debug("Req index out of range\n");
  39. return FDT_ADDR_T_NONE;
  40. }
  41. reg += index * (na + ns);
  42. if (ns) {
  43. /*
  44. * Use the full-fledged translate function for complex
  45. * bus setups.
  46. */
  47. addr = fdt_translate_address((void *)gd->fdt_blob,
  48. dev_of_offset(dev), reg);
  49. } else {
  50. /* Non translatable if #size-cells == 0 */
  51. addr = fdt_read_number(reg, na);
  52. }
  53. } else {
  54. /*
  55. * Use the "simple" translate function for less complex
  56. * bus setups.
  57. */
  58. addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
  59. dev_of_offset(dev->parent), dev_of_offset(dev),
  60. "reg", index, NULL, false);
  61. if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
  62. if (device_get_uclass_id(dev->parent) ==
  63. UCLASS_SIMPLE_BUS)
  64. addr = simple_bus_translate(dev->parent, addr);
  65. }
  66. }
  67. /*
  68. * Some platforms need a special address translation. Those
  69. * platforms (e.g. mvebu in SPL) can configure a translation
  70. * offset in the DM by calling dm_set_translation_offset() that
  71. * will get added to all addresses returned by devfdt_get_addr().
  72. */
  73. addr += dm_get_translation_offset();
  74. return addr;
  75. #else
  76. return FDT_ADDR_T_NONE;
  77. #endif
  78. }
  79. fdt_addr_t devfdt_get_addr_size_index(struct udevice *dev, int index,
  80. fdt_size_t *size)
  81. {
  82. #if CONFIG_IS_ENABLED(OF_CONTROL)
  83. /*
  84. * Only get the size in this first call. We'll get the addr in the
  85. * next call to the exisiting dev_get_xxx function which handles
  86. * all config options.
  87. */
  88. fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),
  89. "reg", index, size, false);
  90. /*
  91. * Get the base address via the existing function which handles
  92. * all Kconfig cases
  93. */
  94. return devfdt_get_addr_index(dev, index);
  95. #else
  96. return FDT_ADDR_T_NONE;
  97. #endif
  98. }
  99. fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name)
  100. {
  101. #if CONFIG_IS_ENABLED(OF_CONTROL)
  102. int index;
  103. index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
  104. "reg-names", name);
  105. if (index < 0)
  106. return index;
  107. return devfdt_get_addr_index(dev, index);
  108. #else
  109. return FDT_ADDR_T_NONE;
  110. #endif
  111. }
  112. fdt_addr_t devfdt_get_addr(struct udevice *dev)
  113. {
  114. return devfdt_get_addr_index(dev, 0);
  115. }
  116. void *devfdt_get_addr_ptr(struct udevice *dev)
  117. {
  118. return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0);
  119. }
  120. void *devfdt_remap_addr_index(struct udevice *dev, int index)
  121. {
  122. fdt_addr_t addr = devfdt_get_addr(dev);
  123. if (addr == FDT_ADDR_T_NONE)
  124. return NULL;
  125. return map_physmem(addr, 0, MAP_NOCACHE);
  126. }
  127. void *devfdt_remap_addr(struct udevice *dev)
  128. {
  129. return devfdt_remap_addr_index(dev, 0);
  130. }
  131. void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
  132. {
  133. fdt_addr_t addr = devfdt_get_addr(dev);
  134. if (addr == FDT_ADDR_T_NONE)
  135. return NULL;
  136. return map_physmem(addr, size, MAP_NOCACHE);
  137. }