fdtaddr.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. /*
  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. /*
  51. * Use the "simple" translate function for less complex
  52. * bus setups.
  53. */
  54. addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
  55. dev_of_offset(dev->parent), dev_of_offset(dev),
  56. "reg", index, NULL, false);
  57. if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
  58. if (device_get_uclass_id(dev->parent) ==
  59. UCLASS_SIMPLE_BUS)
  60. addr = simple_bus_translate(dev->parent, addr);
  61. }
  62. }
  63. /*
  64. * Some platforms need a special address translation. Those
  65. * platforms (e.g. mvebu in SPL) can configure a translation
  66. * offset in the DM by calling dm_set_translation_offset() that
  67. * will get added to all addresses returned by devfdt_get_addr().
  68. */
  69. addr += dm_get_translation_offset();
  70. return addr;
  71. #else
  72. return FDT_ADDR_T_NONE;
  73. #endif
  74. }
  75. fdt_addr_t devfdt_get_addr_size_index(struct udevice *dev, int index,
  76. fdt_size_t *size)
  77. {
  78. #if CONFIG_IS_ENABLED(OF_CONTROL)
  79. /*
  80. * Only get the size in this first call. We'll get the addr in the
  81. * next call to the exisiting dev_get_xxx function which handles
  82. * all config options.
  83. */
  84. fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev_of_offset(dev),
  85. "reg", index, size, false);
  86. /*
  87. * Get the base address via the existing function which handles
  88. * all Kconfig cases
  89. */
  90. return devfdt_get_addr_index(dev, index);
  91. #else
  92. return FDT_ADDR_T_NONE;
  93. #endif
  94. }
  95. fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name)
  96. {
  97. #if CONFIG_IS_ENABLED(OF_CONTROL)
  98. int index;
  99. index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
  100. "reg-names", name);
  101. if (index < 0)
  102. return index;
  103. return devfdt_get_addr_index(dev, index);
  104. #else
  105. return FDT_ADDR_T_NONE;
  106. #endif
  107. }
  108. fdt_addr_t devfdt_get_addr(struct udevice *dev)
  109. {
  110. return devfdt_get_addr_index(dev, 0);
  111. }
  112. void *devfdt_get_addr_ptr(struct udevice *dev)
  113. {
  114. return (void *)(uintptr_t)devfdt_get_addr_index(dev, 0);
  115. }
  116. void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
  117. {
  118. fdt_addr_t addr = devfdt_get_addr(dev);
  119. if (addr == FDT_ADDR_T_NONE)
  120. return NULL;
  121. return map_physmem(addr, size, MAP_NOCACHE);
  122. }