dcr.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
  4. * <[email protected]>
  5. */
  6. #undef DEBUG
  7. #include <linux/kernel.h>
  8. #include <linux/export.h>
  9. #include <linux/of_address.h>
  10. #include <asm/dcr.h>
  11. #ifdef CONFIG_PPC_DCR_MMIO
  12. static struct device_node *find_dcr_parent(struct device_node *node)
  13. {
  14. struct device_node *par, *tmp;
  15. const u32 *p;
  16. for (par = of_node_get(node); par;) {
  17. if (of_get_property(par, "dcr-controller", NULL))
  18. break;
  19. p = of_get_property(par, "dcr-parent", NULL);
  20. tmp = par;
  21. if (p == NULL)
  22. par = of_get_parent(par);
  23. else
  24. par = of_find_node_by_phandle(*p);
  25. of_node_put(tmp);
  26. }
  27. return par;
  28. }
  29. #endif
  30. #if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
  31. bool dcr_map_ok_generic(dcr_host_t host)
  32. {
  33. if (host.type == DCR_HOST_NATIVE)
  34. return dcr_map_ok_native(host.host.native);
  35. else if (host.type == DCR_HOST_MMIO)
  36. return dcr_map_ok_mmio(host.host.mmio);
  37. else
  38. return false;
  39. }
  40. EXPORT_SYMBOL_GPL(dcr_map_ok_generic);
  41. dcr_host_t dcr_map_generic(struct device_node *dev,
  42. unsigned int dcr_n,
  43. unsigned int dcr_c)
  44. {
  45. dcr_host_t host;
  46. struct device_node *dp;
  47. const char *prop;
  48. host.type = DCR_HOST_INVALID;
  49. dp = find_dcr_parent(dev);
  50. if (dp == NULL)
  51. return host;
  52. prop = of_get_property(dp, "dcr-access-method", NULL);
  53. pr_debug("dcr_map_generic(dcr-access-method = %s)\n", prop);
  54. if (!strcmp(prop, "native")) {
  55. host.type = DCR_HOST_NATIVE;
  56. host.host.native = dcr_map_native(dev, dcr_n, dcr_c);
  57. } else if (!strcmp(prop, "mmio")) {
  58. host.type = DCR_HOST_MMIO;
  59. host.host.mmio = dcr_map_mmio(dev, dcr_n, dcr_c);
  60. }
  61. of_node_put(dp);
  62. return host;
  63. }
  64. EXPORT_SYMBOL_GPL(dcr_map_generic);
  65. void dcr_unmap_generic(dcr_host_t host, unsigned int dcr_c)
  66. {
  67. if (host.type == DCR_HOST_NATIVE)
  68. dcr_unmap_native(host.host.native, dcr_c);
  69. else if (host.type == DCR_HOST_MMIO)
  70. dcr_unmap_mmio(host.host.mmio, dcr_c);
  71. else /* host.type == DCR_HOST_INVALID */
  72. WARN_ON(true);
  73. }
  74. EXPORT_SYMBOL_GPL(dcr_unmap_generic);
  75. u32 dcr_read_generic(dcr_host_t host, unsigned int dcr_n)
  76. {
  77. if (host.type == DCR_HOST_NATIVE)
  78. return dcr_read_native(host.host.native, dcr_n);
  79. else if (host.type == DCR_HOST_MMIO)
  80. return dcr_read_mmio(host.host.mmio, dcr_n);
  81. else /* host.type == DCR_HOST_INVALID */
  82. WARN_ON(true);
  83. return 0;
  84. }
  85. EXPORT_SYMBOL_GPL(dcr_read_generic);
  86. void dcr_write_generic(dcr_host_t host, unsigned int dcr_n, u32 value)
  87. {
  88. if (host.type == DCR_HOST_NATIVE)
  89. dcr_write_native(host.host.native, dcr_n, value);
  90. else if (host.type == DCR_HOST_MMIO)
  91. dcr_write_mmio(host.host.mmio, dcr_n, value);
  92. else /* host.type == DCR_HOST_INVALID */
  93. WARN_ON(true);
  94. }
  95. EXPORT_SYMBOL_GPL(dcr_write_generic);
  96. #endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
  97. unsigned int dcr_resource_start(const struct device_node *np,
  98. unsigned int index)
  99. {
  100. unsigned int ds;
  101. const u32 *dr = of_get_property(np, "dcr-reg", &ds);
  102. if (dr == NULL || ds & 1 || index >= (ds / 8))
  103. return 0;
  104. return dr[index * 2];
  105. }
  106. EXPORT_SYMBOL_GPL(dcr_resource_start);
  107. unsigned int dcr_resource_len(const struct device_node *np, unsigned int index)
  108. {
  109. unsigned int ds;
  110. const u32 *dr = of_get_property(np, "dcr-reg", &ds);
  111. if (dr == NULL || ds & 1 || index >= (ds / 8))
  112. return 0;
  113. return dr[index * 2 + 1];
  114. }
  115. EXPORT_SYMBOL_GPL(dcr_resource_len);
  116. #ifdef CONFIG_PPC_DCR_MMIO
  117. static u64 of_translate_dcr_address(struct device_node *dev,
  118. unsigned int dcr_n,
  119. unsigned int *out_stride)
  120. {
  121. struct device_node *dp;
  122. const u32 *p;
  123. unsigned int stride;
  124. u64 ret = OF_BAD_ADDR;
  125. dp = find_dcr_parent(dev);
  126. if (dp == NULL)
  127. return OF_BAD_ADDR;
  128. /* Stride is not properly defined yet, default to 0x10 for Axon */
  129. p = of_get_property(dp, "dcr-mmio-stride", NULL);
  130. stride = (p == NULL) ? 0x10 : *p;
  131. /* XXX FIXME: Which property name is to use of the 2 following ? */
  132. p = of_get_property(dp, "dcr-mmio-range", NULL);
  133. if (p == NULL)
  134. p = of_get_property(dp, "dcr-mmio-space", NULL);
  135. if (p == NULL)
  136. goto done;
  137. /* Maybe could do some better range checking here */
  138. ret = of_translate_address(dp, p);
  139. if (ret != OF_BAD_ADDR)
  140. ret += (u64)(stride) * (u64)dcr_n;
  141. if (out_stride)
  142. *out_stride = stride;
  143. done:
  144. of_node_put(dp);
  145. return ret;
  146. }
  147. dcr_host_mmio_t dcr_map_mmio(struct device_node *dev,
  148. unsigned int dcr_n,
  149. unsigned int dcr_c)
  150. {
  151. dcr_host_mmio_t ret = { .token = NULL, .stride = 0, .base = dcr_n };
  152. u64 addr;
  153. pr_debug("dcr_map(%pOF, 0x%x, 0x%x)\n",
  154. dev, dcr_n, dcr_c);
  155. addr = of_translate_dcr_address(dev, dcr_n, &ret.stride);
  156. pr_debug("translates to addr: 0x%llx, stride: 0x%x\n",
  157. (unsigned long long) addr, ret.stride);
  158. if (addr == OF_BAD_ADDR)
  159. return ret;
  160. pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride);
  161. ret.token = ioremap(addr, dcr_c * ret.stride);
  162. if (ret.token == NULL)
  163. return ret;
  164. pr_debug("mapped at 0x%p -> base is 0x%p\n",
  165. ret.token, ret.token - dcr_n * ret.stride);
  166. ret.token -= dcr_n * ret.stride;
  167. return ret;
  168. }
  169. EXPORT_SYMBOL_GPL(dcr_map_mmio);
  170. void dcr_unmap_mmio(dcr_host_mmio_t host, unsigned int dcr_c)
  171. {
  172. dcr_host_mmio_t h = host;
  173. if (h.token == NULL)
  174. return;
  175. h.token += host.base * h.stride;
  176. iounmap(h.token);
  177. h.token = NULL;
  178. }
  179. EXPORT_SYMBOL_GPL(dcr_unmap_mmio);
  180. #endif /* defined(CONFIG_PPC_DCR_MMIO) */
  181. #ifdef CONFIG_PPC_DCR_NATIVE
  182. DEFINE_SPINLOCK(dcr_ind_lock);
  183. EXPORT_SYMBOL_GPL(dcr_ind_lock);
  184. #endif /* defined(CONFIG_PPC_DCR_NATIVE) */