151-PCI-iproc-Add-PAXC-interface-support.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. From a13fc4733b25d6dad6ec1826f09225c69ee21e3a Mon Sep 17 00:00:00 2001
  2. From: Ray Jui <rjui@broadcom.com>
  3. Date: Mon, 16 Nov 2015 17:41:43 -0800
  4. Subject: [PATCH 151/154] PCI: iproc: Add PAXC interface support
  5. Traditionally, all iProc PCIe root complexes use PAXB based wrapper,
  6. with an integrated on-chip Serdes to support external endpoint devices.
  7. On newer iProc platforms, a PAXC based wrapper is introduced, for
  8. connection with internally emulated PCIe endpoint devices in the ASIC
  9. This patch adds support for PAXC based iProc PCIe root complex in the
  10. iProc PCIe core driver. This change fators out common logic between
  11. PAXB and PAXC, and use tables to store register offsets that are
  12. different between PAXB and PAXC. This allows the driver to be scaled to
  13. support subsequent PAXC revisions in the future
  14. Signed-off-by: Ray Jui <rjui@broadcom.com>
  15. Reviewed-by: Scott Branden <sbranden@broadcom.com>
  16. ---
  17. drivers/pci/host/pcie-iproc-platform.c | 24 +++-
  18. drivers/pci/host/pcie-iproc.c | 202 +++++++++++++++++++++++++++------
  19. drivers/pci/host/pcie-iproc.h | 19 ++++
  20. 3 files changed, 205 insertions(+), 40 deletions(-)
  21. --- a/drivers/pci/host/pcie-iproc-platform.c
  22. +++ b/drivers/pci/host/pcie-iproc-platform.c
  23. @@ -26,8 +26,21 @@
  24. #include "pcie-iproc.h"
  25. +static const struct of_device_id iproc_pcie_of_match_table[] = {
  26. + {
  27. + .compatible = "brcm,iproc-pcie",
  28. + .data = (int *)IPROC_PCIE_PAXB,
  29. + }, {
  30. + .compatible = "brcm,iproc-pcie-paxc",
  31. + .data = (int *)IPROC_PCIE_PAXC,
  32. + },
  33. + { /* sentinel */ }
  34. +};
  35. +MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table);
  36. +
  37. static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
  38. {
  39. + const struct of_device_id *of_id;
  40. struct iproc_pcie *pcie;
  41. struct device_node *np = pdev->dev.of_node;
  42. struct resource reg;
  43. @@ -35,11 +48,16 @@ static int iproc_pcie_pltfm_probe(struct
  44. LIST_HEAD(res);
  45. int ret;
  46. + of_id = of_match_device(iproc_pcie_of_match_table, &pdev->dev);
  47. + if (!of_id)
  48. + return -EINVAL;
  49. +
  50. pcie = devm_kzalloc(&pdev->dev, sizeof(struct iproc_pcie), GFP_KERNEL);
  51. if (!pcie)
  52. return -ENOMEM;
  53. pcie->dev = &pdev->dev;
  54. + pcie->type = (enum iproc_pcie_type)of_id->data;
  55. platform_set_drvdata(pdev, pcie);
  56. ret = of_address_to_resource(np, 0, &reg);
  57. @@ -114,12 +132,6 @@ static int iproc_pcie_pltfm_remove(struc
  58. return iproc_pcie_remove(pcie);
  59. }
  60. -static const struct of_device_id iproc_pcie_of_match_table[] = {
  61. - { .compatible = "brcm,iproc-pcie", },
  62. - { /* sentinel */ }
  63. -};
  64. -MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table);
  65. -
  66. static struct platform_driver iproc_pcie_pltfm_driver = {
  67. .driver = {
  68. .name = "iproc-pcie",
  69. --- a/drivers/pci/host/pcie-iproc.c
  70. +++ b/drivers/pci/host/pcie-iproc.c
  71. @@ -30,20 +30,16 @@
  72. #include "pcie-iproc.h"
  73. -#define CLK_CONTROL_OFFSET 0x000
  74. #define EP_PERST_SOURCE_SELECT_SHIFT 2
  75. #define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
  76. #define EP_MODE_SURVIVE_PERST_SHIFT 1
  77. #define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
  78. #define RC_PCIE_RST_OUTPUT_SHIFT 0
  79. #define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT)
  80. +#define PAXC_RESET_MASK 0x7f
  81. -#define CFG_IND_ADDR_OFFSET 0x120
  82. #define CFG_IND_ADDR_MASK 0x00001ffc
  83. -#define CFG_IND_DATA_OFFSET 0x124
  84. -
  85. -#define CFG_ADDR_OFFSET 0x1f8
  86. #define CFG_ADDR_BUS_NUM_SHIFT 20
  87. #define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
  88. #define CFG_ADDR_DEV_NUM_SHIFT 15
  89. @@ -55,12 +51,8 @@
  90. #define CFG_ADDR_CFG_TYPE_SHIFT 0
  91. #define CFG_ADDR_CFG_TYPE_MASK 0x00000003
  92. -#define CFG_DATA_OFFSET 0x1fc
  93. -
  94. -#define SYS_RC_INTX_EN 0x330
  95. #define SYS_RC_INTX_MASK 0xf
  96. -#define PCIE_LINK_STATUS_OFFSET 0xf0c
  97. #define PCIE_PHYLINKUP_SHIFT 3
  98. #define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
  99. #define PCIE_DL_ACTIVE_SHIFT 2
  100. @@ -71,12 +63,54 @@
  101. #define OARR_SIZE_CFG_SHIFT 1
  102. #define OARR_SIZE_CFG BIT(OARR_SIZE_CFG_SHIFT)
  103. -#define OARR_LO(window) (0xd20 + (window) * 8)
  104. -#define OARR_HI(window) (0xd24 + (window) * 8)
  105. -#define OMAP_LO(window) (0xd40 + (window) * 8)
  106. -#define OMAP_HI(window) (0xd44 + (window) * 8)
  107. -
  108. #define MAX_NUM_OB_WINDOWS 2
  109. +#define MAX_NUM_PAXC_PF 4
  110. +
  111. +#define IPROC_PCIE_REG_INVALID 0xffff
  112. +
  113. +enum iproc_pcie_reg {
  114. + IPROC_PCIE_CLK_CTRL = 0,
  115. + IPROC_PCIE_CFG_IND_ADDR,
  116. + IPROC_PCIE_CFG_IND_DATA,
  117. + IPROC_PCIE_CFG_ADDR,
  118. + IPROC_PCIE_CFG_DATA,
  119. + IPROC_PCIE_INTX_EN,
  120. + IPROC_PCIE_OARR_LO,
  121. + IPROC_PCIE_OARR_HI,
  122. + IPROC_PCIE_OMAP_LO,
  123. + IPROC_PCIE_OMAP_HI,
  124. + IPROC_PCIE_LINK_STATUS,
  125. +};
  126. +
  127. +/* iProc PCIe PAXB registers */
  128. +static const u16 iproc_pcie_reg_paxb[] = {
  129. + [IPROC_PCIE_CLK_CTRL] = 0x000,
  130. + [IPROC_PCIE_CFG_IND_ADDR] = 0x120,
  131. + [IPROC_PCIE_CFG_IND_DATA] = 0x124,
  132. + [IPROC_PCIE_CFG_ADDR] = 0x1f8,
  133. + [IPROC_PCIE_CFG_DATA] = 0x1fc,
  134. + [IPROC_PCIE_INTX_EN] = 0x330,
  135. + [IPROC_PCIE_OARR_LO] = 0xd20,
  136. + [IPROC_PCIE_OARR_HI] = 0xd24,
  137. + [IPROC_PCIE_OMAP_LO] = 0xd40,
  138. + [IPROC_PCIE_OMAP_HI] = 0xd44,
  139. + [IPROC_PCIE_LINK_STATUS] = 0xf0c,
  140. +};
  141. +
  142. +/* iProc PCIe PAXC v1 registers */
  143. +static const u16 iproc_pcie_reg_paxc[] = {
  144. + [IPROC_PCIE_CLK_CTRL] = 0x000,
  145. + [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
  146. + [IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
  147. + [IPROC_PCIE_CFG_ADDR] = 0x1f8,
  148. + [IPROC_PCIE_CFG_DATA] = 0x1fc,
  149. + [IPROC_PCIE_INTX_EN] = IPROC_PCIE_REG_INVALID,
  150. + [IPROC_PCIE_OARR_LO] = IPROC_PCIE_REG_INVALID,
  151. + [IPROC_PCIE_OARR_HI] = IPROC_PCIE_REG_INVALID,
  152. + [IPROC_PCIE_OMAP_LO] = IPROC_PCIE_REG_INVALID,
  153. + [IPROC_PCIE_OMAP_HI] = IPROC_PCIE_REG_INVALID,
  154. + [IPROC_PCIE_LINK_STATUS] = IPROC_PCIE_REG_INVALID,
  155. +};
  156. static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
  157. {
  158. @@ -91,6 +125,65 @@ static inline struct iproc_pcie *iproc_d
  159. return pcie;
  160. }
  161. +static inline bool iproc_pcie_reg_is_invalid(u16 reg_offset)
  162. +{
  163. + return !!(reg_offset == IPROC_PCIE_REG_INVALID);
  164. +}
  165. +
  166. +static inline u16 iproc_pcie_reg_offset(struct iproc_pcie *pcie,
  167. + enum iproc_pcie_reg reg)
  168. +{
  169. + return pcie->reg_offsets[reg];
  170. +}
  171. +
  172. +static inline u32 iproc_pcie_read_reg(struct iproc_pcie *pcie,
  173. + enum iproc_pcie_reg reg)
  174. +{
  175. + u16 offset = iproc_pcie_reg_offset(pcie, reg);
  176. +
  177. + if (iproc_pcie_reg_is_invalid(offset))
  178. + return 0;
  179. +
  180. + return readl(pcie->base + offset);
  181. +}
  182. +
  183. +static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie,
  184. + enum iproc_pcie_reg reg, u32 val)
  185. +{
  186. + u16 offset = iproc_pcie_reg_offset(pcie, reg);
  187. +
  188. + if (iproc_pcie_reg_is_invalid(offset))
  189. + return;
  190. +
  191. + writel(val, pcie->base + offset);
  192. +}
  193. +
  194. +static inline void iproc_pcie_ob_write(struct iproc_pcie *pcie,
  195. + enum iproc_pcie_reg reg,
  196. + unsigned window, u32 val)
  197. +{
  198. + u16 offset = iproc_pcie_reg_offset(pcie, reg);
  199. +
  200. + if (iproc_pcie_reg_is_invalid(offset))
  201. + return;
  202. +
  203. + writel(val, pcie->base + offset + (window * 8));
  204. +}
  205. +
  206. +static inline bool iproc_pcie_device_is_valid(struct iproc_pcie *pcie,
  207. + unsigned int slot,
  208. + unsigned int fn)
  209. +{
  210. + if (slot > 0)
  211. + return false;
  212. +
  213. + /* PAXC can only support limited number of functions */
  214. + if (pcie->type == IPROC_PCIE_PAXC && fn >= MAX_NUM_PAXC_PF)
  215. + return false;
  216. +
  217. + return true;
  218. +}
  219. +
  220. /**
  221. * Note access to the configuration registers are protected at the higher layer
  222. * by 'pci_lock' in drivers/pci/access.c
  223. @@ -104,28 +197,34 @@ static void __iomem *iproc_pcie_map_cfg_
  224. unsigned fn = PCI_FUNC(devfn);
  225. unsigned busno = bus->number;
  226. u32 val;
  227. + u16 offset;
  228. +
  229. + if (!iproc_pcie_device_is_valid(pcie, slot, fn))
  230. + return NULL;
  231. /* root complex access */
  232. if (busno == 0) {
  233. - if (slot >= 1)
  234. + iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR,
  235. + where & CFG_IND_ADDR_MASK);
  236. + offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_IND_DATA);
  237. + if (iproc_pcie_reg_is_invalid(offset))
  238. return NULL;
  239. - writel(where & CFG_IND_ADDR_MASK,
  240. - pcie->base + CFG_IND_ADDR_OFFSET);
  241. - return (pcie->base + CFG_IND_DATA_OFFSET);
  242. + else
  243. + return (pcie->base + offset);
  244. }
  245. - if (fn > 1)
  246. - return NULL;
  247. -
  248. /* EP device access */
  249. val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
  250. (slot << CFG_ADDR_DEV_NUM_SHIFT) |
  251. (fn << CFG_ADDR_FUNC_NUM_SHIFT) |
  252. (where & CFG_ADDR_REG_NUM_MASK) |
  253. (1 & CFG_ADDR_CFG_TYPE_MASK);
  254. - writel(val, pcie->base + CFG_ADDR_OFFSET);
  255. -
  256. - return (pcie->base + CFG_DATA_OFFSET);
  257. + iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val);
  258. + offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
  259. + if (iproc_pcie_reg_is_invalid(offset))
  260. + return NULL;
  261. + else
  262. + return (pcie->base + offset);
  263. }
  264. static struct pci_ops iproc_pcie_ops = {
  265. @@ -138,18 +237,29 @@ static void iproc_pcie_reset(struct ipro
  266. {
  267. u32 val;
  268. + if (pcie->type == IPROC_PCIE_PAXC) {
  269. + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL);
  270. + val &= ~PAXC_RESET_MASK;
  271. + iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
  272. + udelay(100);
  273. + val |= PAXC_RESET_MASK;
  274. + iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
  275. + udelay(100);
  276. + return;
  277. + }
  278. +
  279. /*
  280. * Select perst_b signal as reset source. Put the device into reset,
  281. * and then bring it out of reset
  282. */
  283. - val = readl(pcie->base + CLK_CONTROL_OFFSET);
  284. + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL);
  285. val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
  286. ~RC_PCIE_RST_OUTPUT;
  287. - writel(val, pcie->base + CLK_CONTROL_OFFSET);
  288. + iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
  289. udelay(250);
  290. val |= RC_PCIE_RST_OUTPUT;
  291. - writel(val, pcie->base + CLK_CONTROL_OFFSET);
  292. + iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
  293. msleep(100);
  294. }
  295. @@ -160,7 +270,14 @@ static int iproc_pcie_check_link(struct
  296. u16 pos, link_status;
  297. bool link_is_active = false;
  298. - val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET);
  299. + /*
  300. + * PAXC connects to emulated endpoint devices directly and does not
  301. + * have a Serdes. Therefore skip the link detection logic here
  302. + */
  303. + if (pcie->type == IPROC_PCIE_PAXC)
  304. + return 0;
  305. +
  306. + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS);
  307. if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) {
  308. dev_err(pcie->dev, "PHY or data link is INACTIVE!\n");
  309. return -ENODEV;
  310. @@ -221,7 +338,7 @@ static int iproc_pcie_check_link(struct
  311. static void iproc_pcie_enable(struct iproc_pcie *pcie)
  312. {
  313. - writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN);
  314. + iproc_pcie_write_reg(pcie, IPROC_PCIE_INTX_EN, SYS_RC_INTX_MASK);
  315. }
  316. /**
  317. @@ -272,11 +389,15 @@ static int iproc_pcie_setup_ob(struct ip
  318. axi_addr -= ob->axi_offset;
  319. for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) {
  320. - writel(lower_32_bits(axi_addr) | OARR_VALID |
  321. - (ob->set_oarr_size ? 1 : 0), pcie->base + OARR_LO(i));
  322. - writel(upper_32_bits(axi_addr), pcie->base + OARR_HI(i));
  323. - writel(lower_32_bits(pci_addr), pcie->base + OMAP_LO(i));
  324. - writel(upper_32_bits(pci_addr), pcie->base + OMAP_HI(i));
  325. + iproc_pcie_ob_write(pcie, IPROC_PCIE_OARR_LO, i,
  326. + lower_32_bits(axi_addr) | OARR_VALID |
  327. + (ob->set_oarr_size ? 1 : 0));
  328. + iproc_pcie_ob_write(pcie, IPROC_PCIE_OARR_HI, i,
  329. + upper_32_bits(axi_addr));
  330. + iproc_pcie_ob_write(pcie, IPROC_PCIE_OMAP_LO, i,
  331. + lower_32_bits(pci_addr));
  332. + iproc_pcie_ob_write(pcie, IPROC_PCIE_OMAP_HI, i,
  333. + upper_32_bits(pci_addr));
  334. size -= ob->window_size;
  335. if (size == 0)
  336. @@ -340,6 +461,19 @@ int iproc_pcie_setup(struct iproc_pcie *
  337. goto err_exit_phy;
  338. }
  339. + switch (pcie->type) {
  340. + case IPROC_PCIE_PAXB:
  341. + pcie->reg_offsets = iproc_pcie_reg_paxb;
  342. + break;
  343. + case IPROC_PCIE_PAXC:
  344. + pcie->reg_offsets = iproc_pcie_reg_paxc;
  345. + break;
  346. + default:
  347. + dev_err(pcie->dev, "incompatible iProc PCIe interface\n");
  348. + ret = -EINVAL;
  349. + goto err_power_off_phy;
  350. + }
  351. +
  352. iproc_pcie_reset(pcie);
  353. if (pcie->need_ob_cfg) {
  354. --- a/drivers/pci/host/pcie-iproc.h
  355. +++ b/drivers/pci/host/pcie-iproc.h
  356. @@ -15,6 +15,20 @@
  357. #define _PCIE_IPROC_H
  358. /**
  359. + * iProc PCIe interface type
  360. + *
  361. + * PAXB is the wrapper used in root complex that can be connected to an
  362. + * external endpoint device
  363. + *
  364. + * PAXC is the wrapper used in root complex dedicated for internal emulated
  365. + * endpoint devices
  366. + */
  367. +enum iproc_pcie_type {
  368. + IPROC_PCIE_PAXB = 0,
  369. + IPROC_PCIE_PAXC,
  370. +};
  371. +
  372. +/**
  373. * iProc PCIe outbound mapping
  374. * @set_oarr_size: indicates the OARR size bit needs to be set
  375. * @axi_offset: offset from the AXI address to the internal address used by
  376. @@ -29,7 +43,10 @@ struct iproc_pcie_ob {
  377. /**
  378. * iProc PCIe device
  379. + *
  380. * @dev: pointer to device data structure
  381. + * @type: iProc PCIe interface type
  382. + * @reg_offsets: register offsets
  383. * @base: PCIe host controller I/O register base
  384. * @sysdata: Per PCI controller data (ARM-specific)
  385. * @root_bus: pointer to root bus
  386. @@ -41,6 +58,8 @@ struct iproc_pcie_ob {
  387. */
  388. struct iproc_pcie {
  389. struct device *dev;
  390. + enum iproc_pcie_type type;
  391. + const u16 *reg_offsets;
  392. void __iomem *base;
  393. #ifdef CONFIG_ARM
  394. struct pci_sys_data sysdata;