fdtaddr.c 3.4 KB

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