pcie_layerscape_fixup.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright 2014-2015 Freescale Semiconductor, Inc.
  3. * Layerscape PCIe driver
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <pci.h>
  9. #include <asm/arch/fsl_serdes.h>
  10. #include <asm/io.h>
  11. #include <errno.h>
  12. #ifdef CONFIG_OF_BOARD_SETUP
  13. #include <libfdt.h>
  14. #include <fdt_support.h>
  15. #include "pcie_layerscape.h"
  16. #if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
  17. /*
  18. * Return next available LUT index.
  19. */
  20. static int ls_pcie_next_lut_index(struct ls_pcie *pcie)
  21. {
  22. if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
  23. return pcie->next_lut_index++;
  24. else
  25. return -ENOSPC; /* LUT is full */
  26. }
  27. /* returns the next available streamid for pcie, -errno if failed */
  28. static int ls_pcie_next_streamid(void)
  29. {
  30. static int next_stream_id = FSL_PEX_STREAM_ID_START;
  31. if (next_stream_id > FSL_PEX_STREAM_ID_END)
  32. return -EINVAL;
  33. return next_stream_id++;
  34. }
  35. static void lut_writel(struct ls_pcie *pcie, unsigned int value,
  36. unsigned int offset)
  37. {
  38. if (pcie->big_endian)
  39. out_be32(pcie->lut + offset, value);
  40. else
  41. out_le32(pcie->lut + offset, value);
  42. }
  43. /*
  44. * Program a single LUT entry
  45. */
  46. static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid,
  47. u32 streamid)
  48. {
  49. /* leave mask as all zeroes, want to match all bits */
  50. lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
  51. lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
  52. }
  53. /*
  54. * An msi-map is a property to be added to the pci controller
  55. * node. It is a table, where each entry consists of 4 fields
  56. * e.g.:
  57. *
  58. * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
  59. * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
  60. */
  61. static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie,
  62. u32 devid, u32 streamid)
  63. {
  64. u32 *prop;
  65. u32 phandle;
  66. int nodeoffset;
  67. uint svr;
  68. char *compat = NULL;
  69. /* find pci controller node */
  70. nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
  71. pcie->dbi_res.start);
  72. if (nodeoffset < 0) {
  73. #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
  74. svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
  75. if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
  76. svr == SVR_LS2048A || svr == SVR_LS2044A)
  77. compat = "fsl,ls2088a-pcie";
  78. else
  79. compat = CONFIG_FSL_PCIE_COMPAT;
  80. if (compat)
  81. nodeoffset = fdt_node_offset_by_compat_reg(blob,
  82. compat, pcie->dbi_res.start);
  83. #endif
  84. if (nodeoffset < 0)
  85. return;
  86. }
  87. /* get phandle to MSI controller */
  88. prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0);
  89. if (prop == NULL) {
  90. debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
  91. __func__, pcie->idx);
  92. return;
  93. }
  94. phandle = fdt32_to_cpu(*prop);
  95. /* set one msi-map row */
  96. fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid);
  97. fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle);
  98. fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid);
  99. fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1);
  100. }
  101. /*
  102. * An iommu-map is a property to be added to the pci controller
  103. * node. It is a table, where each entry consists of 4 fields
  104. * e.g.:
  105. *
  106. * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
  107. * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
  108. */
  109. static void fdt_pcie_set_iommu_map_entry(void *blob, struct ls_pcie *pcie,
  110. u32 devid, u32 streamid)
  111. {
  112. u32 *prop;
  113. u32 iommu_map[4];
  114. int nodeoffset;
  115. int lenp;
  116. /* find pci controller node */
  117. nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
  118. pcie->dbi_res.start);
  119. if (nodeoffset < 0) {
  120. #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
  121. nodeoffset = fdt_node_offset_by_compat_reg(blob,
  122. CONFIG_FSL_PCIE_COMPAT, pcie->dbi_res.start);
  123. if (nodeoffset < 0)
  124. return;
  125. #else
  126. return;
  127. #endif
  128. }
  129. /* get phandle to iommu controller */
  130. prop = fdt_getprop_w(blob, nodeoffset, "iommu-map", &lenp);
  131. if (prop == NULL) {
  132. debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
  133. __func__, pcie->idx);
  134. return;
  135. }
  136. /* set iommu-map row */
  137. iommu_map[0] = cpu_to_fdt32(devid);
  138. iommu_map[1] = *++prop;
  139. iommu_map[2] = cpu_to_fdt32(streamid);
  140. iommu_map[3] = cpu_to_fdt32(1);
  141. if (devid == 0) {
  142. fdt_setprop_inplace(blob, nodeoffset, "iommu-map",
  143. iommu_map, 16);
  144. } else {
  145. fdt_appendprop(blob, nodeoffset, "iommu-map", iommu_map, 16);
  146. }
  147. }
  148. static void fdt_fixup_pcie(void *blob)
  149. {
  150. struct udevice *dev, *bus;
  151. struct ls_pcie *pcie;
  152. int streamid;
  153. int index;
  154. pci_dev_t bdf;
  155. /* Scan all known buses */
  156. for (pci_find_first_device(&dev);
  157. dev;
  158. pci_find_next_device(&dev)) {
  159. for (bus = dev; device_is_on_pci_bus(bus);)
  160. bus = bus->parent;
  161. pcie = dev_get_priv(bus);
  162. streamid = ls_pcie_next_streamid();
  163. if (streamid < 0) {
  164. debug("ERROR: no stream ids free\n");
  165. continue;
  166. }
  167. index = ls_pcie_next_lut_index(pcie);
  168. if (index < 0) {
  169. debug("ERROR: no LUT indexes free\n");
  170. continue;
  171. }
  172. /* the DT fixup must be relative to the hose first_busno */
  173. bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0);
  174. /* map PCI b.d.f to streamID in LUT */
  175. ls_pcie_lut_set_mapping(pcie, index, bdf >> 8,
  176. streamid);
  177. /* update msi-map in device tree */
  178. fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8,
  179. streamid);
  180. /* update iommu-map in device tree */
  181. fdt_pcie_set_iommu_map_entry(blob, pcie, bdf >> 8,
  182. streamid);
  183. }
  184. }
  185. #endif
  186. static void ft_pcie_ls_setup(void *blob, struct ls_pcie *pcie)
  187. {
  188. int off;
  189. uint svr;
  190. char *compat = NULL;
  191. off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
  192. pcie->dbi_res.start);
  193. if (off < 0) {
  194. #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
  195. svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
  196. if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
  197. svr == SVR_LS2048A || svr == SVR_LS2044A)
  198. compat = "fsl,ls2088a-pcie";
  199. else
  200. compat = CONFIG_FSL_PCIE_COMPAT;
  201. if (compat)
  202. off = fdt_node_offset_by_compat_reg(blob,
  203. compat, pcie->dbi_res.start);
  204. #endif
  205. if (off < 0)
  206. return;
  207. }
  208. if (pcie->enabled)
  209. fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
  210. else
  211. fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
  212. }
  213. /* Fixup Kernel DT for PCIe */
  214. void ft_pci_setup(void *blob, bd_t *bd)
  215. {
  216. struct ls_pcie *pcie;
  217. list_for_each_entry(pcie, &ls_pcie_list, list)
  218. ft_pcie_ls_setup(blob, pcie);
  219. #if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
  220. fdt_fixup_pcie(blob);
  221. #endif
  222. }
  223. #else /* !CONFIG_OF_BOARD_SETUP */
  224. void ft_pci_setup(void *blob, bd_t *bd)
  225. {
  226. }
  227. #endif