BIOS.UsbEhciPCI.Mod 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. (**
  2. * This module provides installation services for EHCI controllers connected with PCI.
  3. * This service was separated from the EHCI HCD to improve code reuse with EHCI controllers wired directly to CPUs, as it
  4. * is the case in several ARM systems.
  5. *)
  6. MODULE UsbEhciPCI; (** AUTHOR "Timothée Martiel"; PURPOSE "Installation of EHCI controller connected through PCI."; *)
  7. IMPORT SYSTEM, Machine, Kernel, KernelLog, PCI, Debug := UsbDebug, UsbHcdi, UsbEhci;
  8. CONST
  9. (* If TRUE, the HC driver just continues if it could not get the ownership of the HC *)
  10. OverrideHcOwnership = TRUE;
  11. (* Legacy support related constants *)
  12. bOwnedByBios * = {16};
  13. bRequestOwnership * = {24};
  14. USBCapabilityID * = 01H; (* Capability ID of USB Legacy Support Extended Capability *)
  15. TYPE
  16. EnhancedHostController = OBJECT (UsbEhci.EnhancedHostController)
  17. (* Release the HC ownership semaphore; eecp is the EHCI Extended Capability Pointer *)
  18. PROCEDURE ReleaseHcOwnerShip(bus, device, function, eecp : LONGINT);
  19. VAR register, res : LONGINT; usblegsup : SET;
  20. BEGIN
  21. (* 00H: No capability list; > 40H to maintain consistency with PCI header *)
  22. IF (eecp > 40H) THEN
  23. res := PCI.ReadConfigDword(bus, device, function, eecp, register);
  24. ASSERT(res = PCI.Done);
  25. IF (register MOD 256 = USBCapabilityID) THEN (* USB legacy support available *)
  26. usblegsup := SYSTEM.VAL(SET, register);
  27. IF usblegsup * bRequestOwnership # {} THEN
  28. IF Debug.Trace & Debug.traceInit THEN KernelLog.String("UsbEhci: Release HC ownership semaphore... "); END;
  29. res := PCI.WriteConfigByte(bus, device, function, eecp + 3, SYSTEM.VAL(LONGINT, LSH(usblegsup - bRequestOwnership, -24)));
  30. ASSERT(res = PCI.Done);
  31. END;
  32. END;
  33. END;
  34. END ReleaseHcOwnerShip;
  35. END EnhancedHostController;
  36. (*
  37. * Get the ownership of the host controller.
  38. * If the EHCI Extended Capability Pointer (EECP) in the Host Controller Capabilities Parameters register (HCCPARAM) has
  39. * a non-zero value, its value indicates the presence of EHCI Extended Capabilities Registers. At offset EECP + 0H in
  40. * the PCI configuration space, we find the USB Legacy Support Extended Capability (USBLEGSUP), which is used to coordinate
  41. * ownership of the EHCI host controller by the pre-OS software and the operating system software.
  42. * IF the USBLEGSUP register is not available, this procedure simply returns TRUE since there is no legacy support. Otherwise,
  43. * we request HC ownership and wait for the pre-OS software to acknowledge.
  44. * Note: At the time this driver was implemented, the current EHCI specification did not specify any other Extended Capabilities
  45. * than USB Legacy Support. The capability registers from, however, a linked list, so more capabilities could be added in
  46. * the future.
  47. * @param bus PCI bus number of HC
  48. * @param device PCI device number of HC
  49. * @param function PCI function number of HC
  50. * @param iobase Virtual I/O base address of the HC
  51. * @return TRUE, if system software taken over the HC, false otherwise
  52. *)
  53. PROCEDURE GetHcOwnerShip(bus, device, function: LONGINT; iobase : ADDRESS) : BOOLEAN;
  54. CONST
  55. MaxWaits = 1000; (* Timeout for pre-OS to system software HC handoff [ms], not specified by EHCIspec *)
  56. VAR
  57. timer : Kernel.Timer;
  58. usblegsup : SET;
  59. eecp, reg, res, waits : LONGINT;
  60. hcOwnedByOS : BOOLEAN;
  61. BEGIN
  62. (* Get the HC Capabilities Parameters register *)
  63. reg := SYSTEM.GET32(iobase + UsbEhci.HcCapCparams);
  64. (* Get the EHCI Extended Capabilities Pointer (EECP) *)
  65. eecp := SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, reg) * {8..15}, - 8));
  66. (* 00H: No capability list; > 40H to maintain consistency with PCI header *)
  67. IF eecp > 40H THEN
  68. (* USB Legacy Support registers are available. eecp is an offset into the PCI configuration space *)
  69. (* pointing to the USB Legacy Support Extended Capability, which we load now. *)
  70. IF Debug.Trace & Debug.traceInit THEN
  71. KernelLog.String("UsbEhci: EHCI Extended Capabilities at offset "); KernelLog.Hex(eecp, -2); KernelLog.Char("H"); KernelLog.Ln;
  72. END;
  73. res := PCI.ReadConfigDword(bus, device, function, eecp, reg);
  74. IF (res = PCI.Done) & (reg MOD 256 = USBCapabilityID) THEN (* USB legacy support available *)
  75. IF Debug.Trace & Debug.traceInit THEN KernelLog.String("UsbEhci: Legacy support capability found."); KernelLog.Ln; END;
  76. usblegsup := SYSTEM.VAL(SET, reg);
  77. IF usblegsup * bOwnedByBios # {} THEN
  78. IF Debug.Trace & Debug.traceInit THEN KernelLog.String("UsbEhci: Request ownership of host controller... "); END;
  79. (* The value of the USB Legacy Support Extented Capability keeps its value when soft booting. If we set it before, *)
  80. (* clear the bRequestOwnership bit now *)
  81. IF usblegsup * bRequestOwnership # {} THEN
  82. KernelLog.Enter; KernelLog.String("UsbEhci: Warning: controller already owns HC."); KernelLog.Exit;
  83. res := PCI.WriteConfigByte(bus, device, function, eecp + 3, SYSTEM.VAL(LONGINT, LSH(usblegsup - bRequestOwnership, -24)));
  84. ASSERT(res = PCI.Done);
  85. END;
  86. (* Set HC OS Owned Semaphore to indicate that we (want to) control the host controller... *)
  87. res := PCI.WriteConfigByte(bus, device, function, eecp + 3, SYSTEM.VAL(LONGINT, LSH(usblegsup + bRequestOwnership, -24)));
  88. hcOwnedByOS := FALSE; waits := 0; NEW(timer);
  89. WHILE ~hcOwnedByOS & (res = PCI.Done) & (waits < MaxWaits) DO
  90. (* The pre-OS software should clear the HC BIOS Owned Semaphore bit... *)
  91. res := PCI.ReadConfigDword(bus, device, function, eecp, reg);
  92. usblegsup := SYSTEM.VAL(SET, reg);
  93. IF (usblegsup * bRequestOwnership # {}) & (usblegsup * bOwnedByBios = {}) THEN
  94. hcOwnedByOS := TRUE;
  95. ELSE
  96. INC(waits, 1); timer.Sleep(1);
  97. END;
  98. END;
  99. IF ~hcOwnedByOS THEN
  100. KernelLog.Enter; KernelLog.String("UsbEhci: Pre-OS to system software handoff failed."); KernelLog.Exit;
  101. IF OverrideHcOwnership THEN
  102. KernelLog.Enter; KernelLog.String("UsbEhci: Override Pre-OS... take over HC!"); KernelLog.Exit;
  103. RETURN TRUE;
  104. ELSE
  105. RETURN FALSE;
  106. END;
  107. END;
  108. IF Debug.Trace & Debug.traceInit THEN KernelLog.String("done."); KernelLog.Ln; END;
  109. END;
  110. ELSE
  111. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbEhci: PCI error: Couldn't get USB Legacy Support register."); KernelLog.Ln; END;
  112. RETURN FALSE;
  113. END;
  114. END;
  115. RETURN TRUE;
  116. END GetHcOwnerShip;
  117. (*
  118. * Find EHCI host controllers on the PCI bus, create correspondig EHCI controller objects and register them in the
  119. * EHCI USB host controllers registry. For EHCI host controllers, this procedure also takes care of the handoff from
  120. * Pre-OS software to the host system software.
  121. *)
  122. PROCEDURE PCIFindEhci;
  123. CONST
  124. EhciClassCode = 0C0320H;
  125. PCIStatusErrorMask = {24,27,28,29,30,31};
  126. VAR
  127. hostController : EnhancedHostController;
  128. bus, device, function : LONGINT;
  129. iobasePhys, irq : LONGINT;
  130. iobaseVirt: ADDRESS;
  131. pciCmdStsReg, sbrn : LONGINT;
  132. index : LONGINT;
  133. res: WORD;
  134. BEGIN
  135. IF Debug.Trace & Debug.traceInit THEN KernelLog.String("UsbEhci: Looking for PCI Enhanced USB Host Controllers..."); KernelLog.Ln; END;
  136. (* Traverse all USB EHCI Host Controllers of all PCI busses in the system *)
  137. index := 0;
  138. WHILE PCI.FindPCIClassCode(EhciClassCode, index, bus, device, function) = PCI.Done DO
  139. res := PCI.ReadConfigDword(bus, device, function, PCI.CmdReg, pciCmdStsReg); ASSERT(res = PCI.Done);
  140. IF SYSTEM.VAL(SET, pciCmdStsReg) * PCIStatusErrorMask # {} THEN
  141. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbEhci: Warning: PCI device is in error ."); KernelLog.Ln; END;
  142. END;
  143. IF PCI.Enable(PCI.MemorySpace + PCI.BusMaster, bus, device, function) = PCI.Done THEN
  144. res := PCI.ReadConfigByte(bus, device, function, PCI.IntlReg, irq); ASSERT(res = PCI.Done);
  145. res := PCI.ReadConfigDword(bus, device, function, PCI.Adr0Reg, iobasePhys); ASSERT(res = PCI.Done);
  146. IF SYSTEM.VAL(SET, iobasePhys) * {0} # {} THEN
  147. KernelLog.String("UsbEhci: Error: Operational Register are not memory mapped"); KernelLog.Ln;
  148. ELSIF SYSTEM.VAL(SET, iobasePhys) * {1,2,3} # {} THEN
  149. KernelLog.String("UsbEhci: Error: Operational Register are not correctly mapped "); KernelLog.Ln;
  150. ELSIF irq = 0 THEN
  151. KernelLog.String("UsbEhci: Error: Please enable interrupts for all USB Host Controllers."); KernelLog.Ln;
  152. ELSE
  153. iobasePhys := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, iobasePhys) * {4..31});
  154. (* Check the Serial Bus Release Number; 20H expected *)
  155. res := PCI.ReadConfigDword(bus, device, function, 60H, sbrn); ASSERT(res = PCI.Done);
  156. IF (sbrn MOD 256) # 20H THEN
  157. KernelLog.Enter; KernelLog.String("UsbEhci: Error: Serial bus release number not supported."); KernelLog.Exit;
  158. ELSE
  159. (* Map the capabiliy registers and the operational registers to memory *)
  160. Machine.MapPhysical(iobasePhys, 4096, iobaseVirt);
  161. IF GetHcOwnerShip(bus, device, function, iobaseVirt) THEN
  162. NEW(hostController, bus, device, function);
  163. IF hostController.Init(Machine.Ensure32BitAddress (iobaseVirt), irq) THEN
  164. (* Host controller has been initialized and started successfully *)
  165. IF Debug.Verbose THEN
  166. KernelLog.Enter;
  167. KernelLog.String("UsbEhci: Initialised USB Enhanced Host Controller at base 0");
  168. KernelLog.Hex(iobasePhys, 8); KernelLog.String(", Irq: "); KernelLog.Int(irq, 0);
  169. KernelLog.Exit;
  170. END;
  171. (* Set the value for the Port Wake Capability Register *)
  172. hostController.pwcr := LSH(sbrn, -16);
  173. UsbHcdi.RegisterHostController(hostController, UsbEhci.Description);
  174. ELSE (* ERROR: host controller initialization failed *)
  175. KernelLog.Enter;
  176. KernelLog.String("UsbEhci: Cannot init USB Enhanced Host Controller at base 0");
  177. KernelLog.Hex(iobasePhys, 8); KernelLog.String(", Irq: "); KernelLog.Int(irq, 0);
  178. KernelLog.Exit;
  179. END;
  180. ELSE
  181. KernelLog.Enter; KernelLog.String("UsbEhci: Couldn't get ownership of host controller."); KernelLog.Exit;
  182. END;
  183. END;
  184. END;
  185. ELSE
  186. KernelLog.Enter; KernelLog.String("UsbEhci: Could not enable bus mastering or memory space access."); KernelLog.Exit;
  187. END;
  188. INC(index);
  189. END; (* End while loop *)
  190. END PCIFindEhci;
  191. (** Installs EHCI controllers connected through PCI. *)
  192. PROCEDURE Install*;
  193. END Install;
  194. BEGIN
  195. (* Find, init and start all compatible PCI EHCI USB host controllers and register them in the UsbHcdi.controllers registry *)
  196. PCIFindEhci;
  197. END UsbEhciPCI.