Bcm2711PciHostBridgeLibConstructor.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /** @file
  2. *
  3. * PCI Host Bridge Library instance for Bcm2711 ARM SOC
  4. *
  5. * Copyright (c) 2019, Jeremy Linton
  6. * Copyright (c) 2017, Linaro Ltd. All rights reserved.
  7. *
  8. * SPDX-License-Identifier: BSD-2-Clause-Patent
  9. *
  10. * This module initializes the Pci as close to a standard
  11. * PCI root complex as possible. The general information
  12. * for this driver was sourced from.
  13. *
  14. * See https://github.com/raspberrypi/linux/blob/rpi-5.3.y/drivers/pci/controller/pcie-brcmstb.c
  15. * and https://github.com/raspberrypi/linux/blob/rpi-5.3.y/arch/arm/boot/dts/bcm2838.dtsi
  16. *
  17. **/
  18. #include <IndustryStandard/Bcm2711.h>
  19. #include <IndustryStandard/Pci22.h>
  20. #include <Library/ArmLib.h>
  21. #include <Library/DebugLib.h>
  22. #include <Library/IoLib.h>
  23. #include <Library/PcdLib.h>
  24. #include <Library/PciHostBridgeLib.h>
  25. #include <Library/UefiBootServicesTableLib.h>
  26. #include <PiDxe.h>
  27. #include <Protocol/PciHostBridgeResourceAllocation.h>
  28. STATIC
  29. UINT32
  30. RdRegister (
  31. UINT32 Offset
  32. )
  33. {
  34. ArmDataMemoryBarrier ();
  35. return MmioRead32 (PCIE_REG_BASE + Offset);
  36. }
  37. STATIC
  38. VOID
  39. RMWRegister (
  40. UINT32 Offset,
  41. UINT32 Mask,
  42. UINT32 In
  43. )
  44. {
  45. EFI_PHYSICAL_ADDRESS Addr;
  46. UINT32 Data;
  47. UINT32 Shift;
  48. Addr = PCIE_REG_BASE + Offset;
  49. Shift = 1;
  50. if (In) {
  51. while (!(Mask & Shift))
  52. Shift <<= 1;
  53. Data = (MmioRead32 (Addr) & ~Mask) | ((In * Shift) & Mask);
  54. } else {
  55. Data = MmioRead32 (Addr) & ~Mask;
  56. }
  57. MmioWrite32 (Addr, Data);
  58. ArmDataMemoryBarrier ();
  59. }
  60. STATIC
  61. VOID
  62. WdRegister (
  63. UINT32 Offset,
  64. UINT32 In
  65. )
  66. {
  67. MmioWrite32 (PCIE_REG_BASE + Offset, In);
  68. ArmDataMemoryBarrier ();
  69. }
  70. EFI_STATUS
  71. EFIAPI
  72. Bcm2711PciHostBridgeLibConstructor (
  73. IN EFI_HANDLE ImageHandle,
  74. IN EFI_SYSTEM_TABLE *SystemTable
  75. )
  76. {
  77. INTN Timeout;
  78. UINT32 Data;
  79. EFI_PHYSICAL_ADDRESS TopOfPciMap;
  80. DEBUG ((DEBUG_VERBOSE, "PCIe RootBridge constructor\n"));
  81. Timeout = 100;
  82. // Reset controller
  83. RMWRegister (PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK, 1);
  84. // PERST
  85. RMWRegister (PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST_MASK, 1);
  86. gBS->Stall (1000);
  87. // take the bridge out of reset
  88. RMWRegister (PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK, 0);
  89. RMWRegister (PCIE_MISC_HARD_PCIE_HARD_DEBUG,
  90. PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK, 0);
  91. RdRegister (PCIE_MISC_HARD_PCIE_HARD_DEBUG);
  92. // Wait for SerDes to be stable
  93. gBS->Stall (1000);
  94. // Read revision
  95. Data = RdRegister (PCIE_MISC_REVISION);
  96. DEBUG ((DEBUG_INFO, "RootBridge: Revision %x\n", Data & PCIE_MISC_REVISION_MAJMIN_MASK));
  97. RMWRegister (PCIE_MISC_MISC_CTRL, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK, 1);
  98. RMWRegister (PCIE_MISC_MISC_CTRL, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK, 1);
  99. RMWRegister (PCIE_MISC_MISC_CTRL, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK, BURST_SIZE_128);
  100. //
  101. // "RC_BAR2" is the inbound TLP window.
  102. // Having non RAM regions in the window is ok (and encouraged? for PtP?)
  103. // so lets just map the entire address space.
  104. //
  105. // For regions > 64K then the pci->mem window size = log2(size)-15
  106. // which is dumped into the low bits of the offset and written to
  107. // the "LO" register with the high bits of the offset written into
  108. // the "HI" part. The Linux driver makes the point that the offset
  109. // must be aligned to its size aka a 1G region must start on a 1G
  110. // boundary. The size parms are 1GB=0xf=log2(size)-15), or 4G=0x11
  111. //
  112. DEBUG ((DEBUG_VERBOSE, "RootBridge: Program bottom 4G of ram\n"));
  113. // lets assume a start addr of 0, size 4G
  114. WdRegister (PCIE_MISC_RC_BAR2_CONFIG_LO, 0x11); /* Size = 4G */
  115. WdRegister (PCIE_MISC_RC_BAR2_CONFIG_HI, 0); /* Start at addr0 */
  116. RMWRegister (PCIE_MISC_MISC_CTRL, PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK, 0x11);
  117. // RC_BAR1 pcie->gisb disable
  118. WdRegister (PCIE_MISC_RC_BAR1_CONFIG_LO, 0);
  119. // RC_BAR3 pcie->scb disable
  120. WdRegister (PCIE_MISC_RC_BAR3_CONFIG_LO, 0);
  121. TopOfPciMap = PCIE_TOP_OF_MEM_WIN;
  122. DEBUG ((DEBUG_VERBOSE, "RootBridge: MMIO PCIe addr %llx\n", TopOfPciMap));
  123. //
  124. // Setup the PCI side of the MMIO window.
  125. //
  126. // All the _WIN0_ values make one think there can be more than one
  127. // mapping, which might mean it's possible to program a prefetchable
  128. // window, or a PIO window...
  129. //
  130. WdRegister (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO, TopOfPciMap);
  131. WdRegister (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI, TopOfPciMap >> 32);
  132. //
  133. // Set up the CPU MMIO addresses. The BASE_LIMIT register holds the
  134. // bottom part of the start and end addresses in a 16-bit field (64k)
  135. // aligned on a 1M boundary (aka only 12 bit active) the top 32-bits
  136. // are then in their own registers. Further these address ranges are
  137. // setup to match the Linux driver and seem less than ideal on the RPi
  138. //
  139. // The mapping should be 1:1 if possible
  140. //
  141. EFI_PHYSICAL_ADDRESS CpuAddrStart = PCIE_CPU_MMIO_WINDOW;
  142. EFI_PHYSICAL_ADDRESS CpuAddrEnd = CpuAddrStart + PCIE_BRIDGE_MMIO_LEN;
  143. DEBUG ((DEBUG_VERBOSE, "RootBridge: MMIO CPU addr %llx\n", CpuAddrStart));
  144. RMWRegister (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
  145. PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK, CpuAddrStart >> 20);
  146. RMWRegister (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
  147. PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK, CpuAddrEnd >> 20);
  148. RMWRegister (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
  149. PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK, CpuAddrStart >> 32);
  150. RMWRegister (PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
  151. PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK, CpuAddrEnd >> 32);
  152. //
  153. // Consider MSI setup here, not that it matters much its likely the legacy intX
  154. // is as fast or faster...
  155. //
  156. // Clear and mask interrupts.
  157. WdRegister (PCIE_INTR2_CPU_MASK_CLR, 0xffffffff);
  158. WdRegister (PCIE_INTR2_CPU_MASK_SET, 0xffffffff);
  159. // Set link cap & link ctl?
  160. //RMWRegister (BRCM_PCIE_CAP_REGS+PCI_LNKCAP, LNKCAP, pen);
  161. //RMWRegister (BRCM_PCIE_CTL_REGS+PCI_LNKCAP, LNKCAP, pen);
  162. // De-assert PERST
  163. RMWRegister (PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST_MASK, 0);
  164. DEBUG ((DEBUG_VERBOSE, "RootBridge: Reset done\n"));
  165. // Wait for linkup
  166. do {
  167. Data = RdRegister (PCIE_MISC_PCIE_STATUS);
  168. gBS->Stall (1000);
  169. Timeout --;
  170. } while (((Data & 0x30) != 0x030) && (Timeout));
  171. DEBUG ((DEBUG_VERBOSE, "PCIe link ready (status=%x) Timeout=%d\n", Data, Timeout));
  172. if ((Data & 0x80) != 0x80) {
  173. DEBUG ((DEBUG_ERROR, "PCIe link not in RC mode (status=%x)\n", Data));
  174. return EFI_UNSUPPORTED;
  175. }
  176. // Change class code of the root port
  177. RMWRegister(BRCM_PCIE_CLASS, PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK, 0x60400);
  178. //
  179. // PCIe->SCB endian mode for BAR
  180. // field ENDIAN_MODE_BAR2 = little endian = 0
  181. //
  182. RMWRegister (PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
  183. PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK, 0);
  184. RMWRegister (PCIE_MISC_HARD_PCIE_HARD_DEBUG,
  185. PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK, 1);
  186. return EFI_SUCCESS;
  187. }