pcie-mobiveil.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * PCIe host controller driver for Mobiveil PCIe Host controller
  4. *
  5. * Copyright (c) 2018 Mobiveil Inc.
  6. * Copyright 2019 NXP
  7. *
  8. * Author: Subrahmanya Lingappa <[email protected]>
  9. * Hou Zhiqiang <[email protected]>
  10. */
  11. #include <linux/delay.h>
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/pci.h>
  15. #include <linux/platform_device.h>
  16. #include "pcie-mobiveil.h"
  17. /*
  18. * mobiveil_pcie_sel_page - routine to access paged register
  19. *
  20. * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
  21. * for this scheme to work extracted higher 6 bits of the offset will be
  22. * written to pg_sel field of PAB_CTRL register and rest of the lower 10
  23. * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
  24. */
  25. static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
  26. {
  27. u32 val;
  28. val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
  29. val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
  30. val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
  31. writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
  32. }
  33. static void __iomem *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie,
  34. u32 off)
  35. {
  36. if (off < PAGED_ADDR_BNDRY) {
  37. /* For directly accessed registers, clear the pg_sel field */
  38. mobiveil_pcie_sel_page(pcie, 0);
  39. return pcie->csr_axi_slave_base + off;
  40. }
  41. mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
  42. return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
  43. }
  44. static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
  45. {
  46. if ((uintptr_t)addr & (size - 1)) {
  47. *val = 0;
  48. return PCIBIOS_BAD_REGISTER_NUMBER;
  49. }
  50. switch (size) {
  51. case 4:
  52. *val = readl(addr);
  53. break;
  54. case 2:
  55. *val = readw(addr);
  56. break;
  57. case 1:
  58. *val = readb(addr);
  59. break;
  60. default:
  61. *val = 0;
  62. return PCIBIOS_BAD_REGISTER_NUMBER;
  63. }
  64. return PCIBIOS_SUCCESSFUL;
  65. }
  66. static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
  67. {
  68. if ((uintptr_t)addr & (size - 1))
  69. return PCIBIOS_BAD_REGISTER_NUMBER;
  70. switch (size) {
  71. case 4:
  72. writel(val, addr);
  73. break;
  74. case 2:
  75. writew(val, addr);
  76. break;
  77. case 1:
  78. writeb(val, addr);
  79. break;
  80. default:
  81. return PCIBIOS_BAD_REGISTER_NUMBER;
  82. }
  83. return PCIBIOS_SUCCESSFUL;
  84. }
  85. u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
  86. {
  87. void __iomem *addr;
  88. u32 val;
  89. int ret;
  90. addr = mobiveil_pcie_comp_addr(pcie, off);
  91. ret = mobiveil_pcie_read(addr, size, &val);
  92. if (ret)
  93. dev_err(&pcie->pdev->dev, "read CSR address failed\n");
  94. return val;
  95. }
  96. void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off,
  97. size_t size)
  98. {
  99. void __iomem *addr;
  100. int ret;
  101. addr = mobiveil_pcie_comp_addr(pcie, off);
  102. ret = mobiveil_pcie_write(addr, size, val);
  103. if (ret)
  104. dev_err(&pcie->pdev->dev, "write CSR address failed\n");
  105. }
  106. bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
  107. {
  108. if (pcie->ops->link_up)
  109. return pcie->ops->link_up(pcie);
  110. return (mobiveil_csr_readl(pcie, LTSSM_STATUS) &
  111. LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
  112. }
  113. void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
  114. u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
  115. {
  116. u32 value;
  117. u64 size64 = ~(size - 1);
  118. if (win_num >= pcie->ppio_wins) {
  119. dev_err(&pcie->pdev->dev,
  120. "ERROR: max inbound windows reached !\n");
  121. return;
  122. }
  123. value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
  124. value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
  125. value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
  126. (lower_32_bits(size64) & WIN_SIZE_MASK);
  127. mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
  128. mobiveil_csr_writel(pcie, upper_32_bits(size64),
  129. PAB_EXT_PEX_AMAP_SIZEN(win_num));
  130. mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr),
  131. PAB_PEX_AMAP_AXI_WIN(win_num));
  132. mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
  133. PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
  134. mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
  135. PAB_PEX_AMAP_PEX_WIN_L(win_num));
  136. mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
  137. PAB_PEX_AMAP_PEX_WIN_H(win_num));
  138. pcie->ib_wins_configured++;
  139. }
  140. /*
  141. * routine to program the outbound windows
  142. */
  143. void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
  144. u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
  145. {
  146. u32 value;
  147. u64 size64 = ~(size - 1);
  148. if (win_num >= pcie->apio_wins) {
  149. dev_err(&pcie->pdev->dev,
  150. "ERROR: max outbound windows reached !\n");
  151. return;
  152. }
  153. /*
  154. * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
  155. * to 4 KB in PAB_AXI_AMAP_CTRL register
  156. */
  157. value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
  158. value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
  159. value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
  160. (lower_32_bits(size64) & WIN_SIZE_MASK);
  161. mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
  162. mobiveil_csr_writel(pcie, upper_32_bits(size64),
  163. PAB_EXT_AXI_AMAP_SIZE(win_num));
  164. /*
  165. * program AXI window base with appropriate value in
  166. * PAB_AXI_AMAP_AXI_WIN0 register
  167. */
  168. mobiveil_csr_writel(pcie,
  169. lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
  170. PAB_AXI_AMAP_AXI_WIN(win_num));
  171. mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
  172. PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
  173. mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
  174. PAB_AXI_AMAP_PEX_WIN_L(win_num));
  175. mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
  176. PAB_AXI_AMAP_PEX_WIN_H(win_num));
  177. pcie->ob_wins_configured++;
  178. }
  179. int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
  180. {
  181. int retries;
  182. /* check if the link is up or not */
  183. for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
  184. if (mobiveil_pcie_link_up(pcie))
  185. return 0;
  186. usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
  187. }
  188. dev_err(&pcie->pdev->dev, "link never came up\n");
  189. return -ETIMEDOUT;
  190. }