xrp_address_map.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * xrp_address_map: CPU->DSP physical address translator
  3. *
  4. * Copyright (c) 2017 Cadence Design Systems, Inc.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  21. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  22. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  23. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. *
  25. * Alternatively you can use and distribute this file under the terms of
  26. * the GNU General Public License version 2 or later.
  27. */
  28. #include <linux/bsearch.h>
  29. #include <linux/device.h>
  30. #include <linux/of.h>
  31. #include <linux/of_address.h>
  32. #include <linux/slab.h>
  33. #include <linux/sort.h>
  34. #include "xrp_address_map.h"
  35. #if IS_ENABLED(CONFIG_OF)
  36. static int xrp_compare_address_sort(const void *a, const void *b)
  37. {
  38. const struct xrp_address_map_entry *pa = a;
  39. const struct xrp_address_map_entry *pb = b;
  40. if (pa->src_addr < pb->src_addr &&
  41. pb->src_addr - pa->src_addr >= pa->size)
  42. return -1;
  43. if (pa->src_addr > pb->src_addr &&
  44. pa->src_addr - pb->src_addr >= pb->size)
  45. return 1;
  46. return 0;
  47. }
  48. #endif
  49. int xrp_init_address_map(struct device *dev,
  50. struct xrp_address_map *map)
  51. {
  52. int ret = 0;
  53. #if IS_ENABLED(CONFIG_OF)
  54. struct device_node *pnode = dev->of_node;
  55. struct device_node *node;
  56. int rlen, off;
  57. const __be32 *ranges = of_get_property(pnode, "ranges", &rlen);
  58. int na, pna, ns;
  59. int i;
  60. if (!ranges) {
  61. dev_dbg(dev, "%s: no 'ranges' property in the device tree, no translation at that level\n",
  62. __func__);
  63. goto empty;
  64. }
  65. node = of_get_next_child(pnode, NULL);
  66. if (!node) {
  67. dev_warn(dev, "%s: no child node found in the device tree, no translation at that level\n",
  68. __func__);
  69. goto empty;
  70. }
  71. na = of_n_addr_cells(node);
  72. ns = of_n_size_cells(node);
  73. pna = of_n_addr_cells(pnode);
  74. rlen /= 4;
  75. map->n = rlen / (na + pna + ns);
  76. map->entry = kmalloc_array(map->n, sizeof(*map->entry), GFP_KERNEL);
  77. if (!map->entry) {
  78. ret = -ENOMEM;
  79. goto err;
  80. }
  81. dev_dbg(dev,
  82. "%s: na = %d, pna = %d, ns = %d, rlen = %d cells, n = %d\n",
  83. __func__, na, pna, ns, rlen, map->n);
  84. for (off = 0, i = 0; off < rlen; off += na + pna + ns, ++i) {
  85. map->entry[i].src_addr = of_translate_address(node,
  86. ranges + off);
  87. map->entry[i].dst_addr = of_read_number(ranges + off, na);
  88. map->entry[i].size = of_read_number(ranges + off + na + pna,
  89. ns);
  90. dev_dbg(dev,
  91. " src_addr = 0x%llx, dst_addr = 0x%lx, size = 0x%lx\n",
  92. (unsigned long long)map->entry[i].src_addr,
  93. (unsigned long)map->entry[i].dst_addr,
  94. (unsigned long)map->entry[i].size);
  95. }
  96. sort(map->entry, map->n, sizeof(*map->entry),
  97. xrp_compare_address_sort, NULL);
  98. err:
  99. of_node_put(node);
  100. return ret;
  101. empty:
  102. #endif
  103. map->n = 1;
  104. map->entry = kmalloc(sizeof(*map->entry), GFP_KERNEL);
  105. map->entry->src_addr = 0;
  106. map->entry->dst_addr = 0;
  107. map->entry->size = ~0ul;
  108. return ret;
  109. }
  110. void xrp_free_address_map(struct xrp_address_map *map)
  111. {
  112. if(!map->entry)
  113. kfree(map->entry);
  114. }
  115. static int xrp_compare_address_search(const void *a, const void *b)
  116. {
  117. const phys_addr_t *pa = a;
  118. return xrp_compare_address(*pa, b);
  119. }
  120. struct xrp_address_map_entry *
  121. xrp_get_address_mapping(const struct xrp_address_map *map, phys_addr_t addr)
  122. {
  123. struct xrp_address_map_entry *entry =
  124. bsearch(&addr, map->entry, map->n, sizeof(*map->entry),
  125. xrp_compare_address_search);
  126. return entry;
  127. }
  128. u32 xrp_translate_to_dsp(const struct xrp_address_map *map, phys_addr_t addr)
  129. {
  130. struct xrp_address_map_entry *entry = xrp_get_address_mapping(map, addr);
  131. if (!entry)
  132. return XRP_NO_TRANSLATION;
  133. return entry->dst_addr + addr - entry->src_addr;
  134. }
  135. phys_addr_t xrp_translate_dsp_to_host(const struct xrp_address_map *map,u32 addr)
  136. {
  137. int loop;
  138. struct xrp_address_map_entry *entry=NULL;
  139. for(loop=0;loop<map->n;loop++)
  140. {
  141. if((map->entry[loop].dst_addr<=addr) &&
  142. ((map->entry[loop].dst_addr+map->entry[loop].size)>addr))
  143. {
  144. // pr_debug("%s\n",__func__);
  145. entry= &map->entry[loop];
  146. break;
  147. }
  148. }
  149. if(entry == NULL)
  150. {
  151. return (phys_addr_t)OF_BAD_ADDR;
  152. }
  153. pr_debug("%s,entry(%d),device:(0x%08x,0x%08x),target:0x%08x\n",
  154. __func__,loop,entry->dst_addr,entry->dst_addr+entry->size,addr);
  155. return entry->src_addr+addr-entry->dst_addr;
  156. }