036-0007-PCI-iproc-Add-outbound-mapping-support.patch 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. From e99a187b5c5f60fe55ca586f82ac1a3557fb166a Mon Sep 17 00:00:00 2001
  2. From: Ray Jui <rjui@broadcom.com>
  3. Date: Fri, 16 Oct 2015 08:18:24 -0500
  4. Subject: [PATCH 7/7] PCI: iproc: Add outbound mapping support
  5. Certain SoCs require the PCIe outbound mapping to be configured in
  6. software. Add support for those chips.
  7. [jonmason: Use %pap format when printing size_t to avoid warnings in 32-bit
  8. build.]
  9. [arnd: Use div64_u64() instead of "%" to avoid __aeabi_uldivmod link error
  10. in 32-bit build.]
  11. Signed-off-by: Ray Jui <rjui@broadcom.com>
  12. Signed-off-by: Jon Mason <jonmason@broadcom.com>
  13. Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  14. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  15. ---
  16. drivers/pci/host/pcie-iproc-platform.c | 27 ++++++++
  17. drivers/pci/host/pcie-iproc.c | 115 +++++++++++++++++++++++++++++++++
  18. drivers/pci/host/pcie-iproc.h | 17 +++++
  19. 3 files changed, 159 insertions(+)
  20. --- a/drivers/pci/host/pcie-iproc-platform.c
  21. +++ b/drivers/pci/host/pcie-iproc-platform.c
  22. @@ -54,6 +54,33 @@ static int iproc_pcie_pltfm_probe(struct
  23. return -ENOMEM;
  24. }
  25. + if (of_property_read_bool(np, "brcm,pcie-ob")) {
  26. + u32 val;
  27. +
  28. + ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset",
  29. + &val);
  30. + if (ret) {
  31. + dev_err(pcie->dev,
  32. + "missing brcm,pcie-ob-axi-offset property\n");
  33. + return ret;
  34. + }
  35. + pcie->ob.axi_offset = val;
  36. +
  37. + ret = of_property_read_u32(np, "brcm,pcie-ob-window-size",
  38. + &val);
  39. + if (ret) {
  40. + dev_err(pcie->dev,
  41. + "missing brcm,pcie-ob-window-size property\n");
  42. + return ret;
  43. + }
  44. + pcie->ob.window_size = (resource_size_t)val * SZ_1M;
  45. +
  46. + if (of_property_read_bool(np, "brcm,pcie-ob-oarr-size"))
  47. + pcie->ob.set_oarr_size = true;
  48. +
  49. + pcie->need_ob_cfg = true;
  50. + }
  51. +
  52. /* PHY use is optional */
  53. pcie->phy = devm_phy_get(&pdev->dev, "pcie-phy");
  54. if (IS_ERR(pcie->phy)) {
  55. --- a/drivers/pci/host/pcie-iproc.c
  56. +++ b/drivers/pci/host/pcie-iproc.c
  57. @@ -66,6 +66,18 @@
  58. #define PCIE_DL_ACTIVE_SHIFT 2
  59. #define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
  60. +#define OARR_VALID_SHIFT 0
  61. +#define OARR_VALID BIT(OARR_VALID_SHIFT)
  62. +#define OARR_SIZE_CFG_SHIFT 1
  63. +#define OARR_SIZE_CFG BIT(OARR_SIZE_CFG_SHIFT)
  64. +
  65. +#define OARR_LO(window) (0xd20 + (window) * 8)
  66. +#define OARR_HI(window) (0xd24 + (window) * 8)
  67. +#define OMAP_LO(window) (0xd40 + (window) * 8)
  68. +#define OMAP_HI(window) (0xd44 + (window) * 8)
  69. +
  70. +#define MAX_NUM_OB_WINDOWS 2
  71. +
  72. static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
  73. {
  74. struct iproc_pcie *pcie;
  75. @@ -212,6 +224,101 @@ static void iproc_pcie_enable(struct ipr
  76. writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN);
  77. }
  78. +/**
  79. + * Some iProc SoCs require the SW to configure the outbound address mapping
  80. + *
  81. + * Outbound address translation:
  82. + *
  83. + * iproc_pcie_address = axi_address - axi_offset
  84. + * OARR = iproc_pcie_address
  85. + * OMAP = pci_addr
  86. + *
  87. + * axi_addr -> iproc_pcie_address -> OARR -> OMAP -> pci_address
  88. + */
  89. +static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr,
  90. + u64 pci_addr, resource_size_t size)
  91. +{
  92. + struct iproc_pcie_ob *ob = &pcie->ob;
  93. + unsigned i;
  94. + u64 max_size = (u64)ob->window_size * MAX_NUM_OB_WINDOWS;
  95. + u64 remainder;
  96. +
  97. + if (size > max_size) {
  98. + dev_err(pcie->dev,
  99. + "res size 0x%pap exceeds max supported size 0x%llx\n",
  100. + &size, max_size);
  101. + return -EINVAL;
  102. + }
  103. +
  104. + div64_u64_rem(size, ob->window_size, &remainder);
  105. + if (remainder) {
  106. + dev_err(pcie->dev,
  107. + "res size %pap needs to be multiple of window size %pap\n",
  108. + &size, &ob->window_size);
  109. + return -EINVAL;
  110. + }
  111. +
  112. + if (axi_addr < ob->axi_offset) {
  113. + dev_err(pcie->dev,
  114. + "axi address %pap less than offset %pap\n",
  115. + &axi_addr, &ob->axi_offset);
  116. + return -EINVAL;
  117. + }
  118. +
  119. + /*
  120. + * Translate the AXI address to the internal address used by the iProc
  121. + * PCIe core before programming the OARR
  122. + */
  123. + axi_addr -= ob->axi_offset;
  124. +
  125. + for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) {
  126. + writel(lower_32_bits(axi_addr) | OARR_VALID |
  127. + (ob->set_oarr_size ? 1 : 0), pcie->base + OARR_LO(i));
  128. + writel(upper_32_bits(axi_addr), pcie->base + OARR_HI(i));
  129. + writel(lower_32_bits(pci_addr), pcie->base + OMAP_LO(i));
  130. + writel(upper_32_bits(pci_addr), pcie->base + OMAP_HI(i));
  131. +
  132. + size -= ob->window_size;
  133. + if (size == 0)
  134. + break;
  135. +
  136. + axi_addr += ob->window_size;
  137. + pci_addr += ob->window_size;
  138. + }
  139. +
  140. + return 0;
  141. +}
  142. +
  143. +static int iproc_pcie_map_ranges(struct iproc_pcie *pcie,
  144. + struct list_head *resources)
  145. +{
  146. + struct resource_entry *window;
  147. + int ret;
  148. +
  149. + resource_list_for_each_entry(window, resources) {
  150. + struct resource *res = window->res;
  151. + u64 res_type = resource_type(res);
  152. +
  153. + switch (res_type) {
  154. + case IORESOURCE_IO:
  155. + case IORESOURCE_BUS:
  156. + break;
  157. + case IORESOURCE_MEM:
  158. + ret = iproc_pcie_setup_ob(pcie, res->start,
  159. + res->start - window->offset,
  160. + resource_size(res));
  161. + if (ret)
  162. + return ret;
  163. + break;
  164. + default:
  165. + dev_err(pcie->dev, "invalid resource %pR\n", res);
  166. + return -EINVAL;
  167. + }
  168. + }
  169. +
  170. + return 0;
  171. +}
  172. +
  173. int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
  174. {
  175. int ret;
  176. @@ -235,6 +342,14 @@ int iproc_pcie_setup(struct iproc_pcie *
  177. iproc_pcie_reset(pcie);
  178. + if (pcie->need_ob_cfg) {
  179. + ret = iproc_pcie_map_ranges(pcie, res);
  180. + if (ret) {
  181. + dev_err(pcie->dev, "map failed\n");
  182. + goto err_power_off_phy;
  183. + }
  184. + }
  185. +
  186. #ifdef CONFIG_ARM
  187. pcie->sysdata.private_data = pcie;
  188. sysdata = &pcie->sysdata;
  189. --- a/drivers/pci/host/pcie-iproc.h
  190. +++ b/drivers/pci/host/pcie-iproc.h
  191. @@ -15,6 +15,19 @@
  192. #define _PCIE_IPROC_H
  193. /**
  194. + * iProc PCIe outbound mapping
  195. + * @set_oarr_size: indicates the OARR size bit needs to be set
  196. + * @axi_offset: offset from the AXI address to the internal address used by
  197. + * the iProc PCIe core
  198. + * @window_size: outbound window size
  199. + */
  200. +struct iproc_pcie_ob {
  201. + bool set_oarr_size;
  202. + resource_size_t axi_offset;
  203. + resource_size_t window_size;
  204. +};
  205. +
  206. +/**
  207. * iProc PCIe device
  208. * @dev: pointer to device data structure
  209. * @base: PCIe host controller I/O register base
  210. @@ -23,6 +36,8 @@
  211. * @phy: optional PHY device that controls the Serdes
  212. * @irqs: interrupt IDs
  213. * @map_irq: function callback to map interrupts
  214. + * @need_ob_cfg: indidates SW needs to configure the outbound mapping window
  215. + * @ob: outbound mapping parameters
  216. */
  217. struct iproc_pcie {
  218. struct device *dev;
  219. @@ -33,6 +48,8 @@ struct iproc_pcie {
  220. struct pci_bus *root_bus;
  221. struct phy *phy;
  222. int (*map_irq)(const struct pci_dev *, u8, u8);
  223. + bool need_ob_cfg;
  224. + struct iproc_pcie_ob ob;
  225. };
  226. int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);