UsbEhciZynq.Mod 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. MODULE UsbEhciZynq; (** AUTHOR "Timothée Martiel"; PURPOSE "Instal EHCI driver on Zynq systems."; *)
  2. (**
  3. * The main purpose of this module is to install the EHCI driver on Zynq SoCs.
  4. * Call
  5. * UsbEhciZynq.Install ~
  6. * to install the driver and unload this module ro remove it.
  7. *
  8. * This module also patches the behavior of the EHCI driver to the Zynq host controller. The host controller is
  9. * not fully compliant with the EHCI specifications and has On-The-Go features that require additional steps in
  10. * the initialization. These differences are accounted for in the EnhancedHostController object provided here.
  11. *)
  12. IMPORT SYSTEM, Platform, BootConfig, Machine, Objects, Kernel, KernelLog, Debug := UsbDebug, Usbdi, Usb, UsbHcdi, UsbEhci, UsbEhciPhy;
  13. CONST
  14. HcUlpiViewport = 30H;
  15. HcOtgSc = 64H;
  16. HcUsbMode = 68H;
  17. TTCtrl * = 1CH;
  18. (* HcUsbMode bits *)
  19. ModeHost = {0, 1};
  20. ModeDevice = {1};
  21. ModeIdle = {};
  22. (* HcOtgSc bits *)
  23. OtgScId = 8;
  24. OtgScIdPu = 5;
  25. (* HcPortSc bits *)
  26. PortScPortSpeed = {26, 27};
  27. PortScPortSpeedLow = {26};
  28. PortScPortSpeedFull = {};
  29. PortScPortSpeedHigh = {27};
  30. TYPE
  31. (** Zynq-specific EHCI driver. Uses the main implementation and adds Zynq-specific initialization code where needed. *)
  32. EnhancedHostController = OBJECT (UsbEhci.EnhancedHostController)
  33. VAR
  34. phyResetGpio: LONGINT;
  35. PROCEDURE GetPortStatus * (port : LONGINT; ack : BOOLEAN) : SET;
  36. VAR
  37. status, dword: SET;
  38. BEGIN
  39. status := GetPortStatus^(port, ack);
  40. dword := SYSTEM.VAL(SET, SYSTEM.GET32(ports[port]));
  41. IF UsbHcdi.PortStatusEnabled * status # {} THEN
  42. IF dword * PortScPortSpeed = PortScPortSpeedHigh THEN
  43. status := status + UsbHcdi.PortStatusHighSpeed
  44. ELSIF dword * PortScPortSpeed = PortScPortSpeedLow THEN
  45. status := status + UsbHcdi.PortStatusLowSpeed
  46. ELSIF dword * PortScPortSpeed = PortScPortSpeedFull THEN
  47. status := status + UsbHcdi.PortStatusFullSpeed
  48. END
  49. END;
  50. RETURN status
  51. END GetPortStatus;
  52. PROCEDURE HasCompanion * (): BOOLEAN;
  53. BEGIN
  54. RETURN FALSE
  55. END HasCompanion;
  56. PROCEDURE ResetAndEnablePort (port: LONGINT): BOOLEAN;
  57. VAR
  58. dword: SET;
  59. res: BOOLEAN;
  60. BEGIN
  61. res := ResetAndEnablePort^(port);
  62. IF res THEN
  63. dword := SYSTEM.VAL(SET, SYSTEM.GET32(iobase + HcUsbMode));
  64. dword := dword + ModeHost;
  65. SYSTEM.PUT32(iobase + HcUsbMode, dword);
  66. END;
  67. RETURN res
  68. END ResetAndEnablePort;
  69. (* Reset the host controller. Note: This will NOT assert reset on the USB downstream ports. *)
  70. PROCEDURE HardwareReset() : BOOLEAN;
  71. VAR
  72. viewportInit: ARRAY 32 OF CHAR;
  73. viewport: LONGINT;
  74. dword: SET;
  75. res: BOOLEAN;
  76. BEGIN
  77. (* Set mode to host *)
  78. SYSTEM.GET(iobase + HcUsbMode, dword);
  79. SYSTEM.PUT(iobase + HcUsbMode, dword + ModeHost);
  80. res := HardwareReset^();
  81. IF res THEN
  82. (* Set mode to host *)
  83. SYSTEM.GET(iobase + HcUsbMode, dword);
  84. SYSTEM.PUT(iobase + HcUsbMode, dword + ModeHost);
  85. SYSTEM.GET(iobase + HcOtgSc, dword);
  86. INCL(dword, 7);
  87. INCL(dword, 5);
  88. SYSTEM.PUT(iobase + HcOtgSc, dword);
  89. (* Try putting port in full-speed mode *)
  90. SYSTEM.PUT(iobase + UsbEhci.HcPortSc, {8});
  91. END;
  92. IF ~res THEN
  93. RETURN FALSE
  94. END;
  95. Machine.GetConfig('UsbViewportInit', viewportInit);
  96. IF viewportInit = '0' THEN
  97. viewport := 0
  98. ELSE
  99. viewport := iobase + HcUlpiViewport
  100. END;
  101. RETURN UsbEhciPhy.Init(viewport, phyResetGpio)
  102. END HardwareReset;
  103. (*
  104. * Start the host controller.
  105. * This will:
  106. * - enable interrupts for the host controller and install a interrupt handler
  107. * - set the addresses for the periodic and asynchronous lists
  108. * - turn the host controller on
  109. * - route all ports to the EHCI controller
  110. * - power on all ports of the root hub
  111. *)
  112. PROCEDURE Start():BOOLEAN;
  113. VAR dword : SET;
  114. res: BOOLEAN;
  115. BEGIN
  116. res := Start^();
  117. IF ~res THEN RETURN FALSE END;
  118. (* Clear interrupts *)
  119. SYSTEM.PUT32(iobase + UsbEhci.HcUsbSts, 0);
  120. (* Enable all interrupts except the frame list rollover interrupt *)
  121. dword := SYSTEM.VAL(SET, SYSTEM.GET32(iobase + UsbEhci.HcUsbIntr));
  122. interruptsEnabled := dword + {0 .. 5} - UsbEhci.StsFrameListRollover + {19} (* UPI: triggered by iTD IOC *);
  123. SYSTEM.PUT32(iobase + UsbEhci.HcUsbIntr, interruptsEnabled);
  124. (* Set the TT HubAddress to 7FH *)
  125. (*SYSTEM.PUT32(iobase + 1CH, SYSTEM.VAL(SET, SYSTEM.GET32(iobase + (* TTCTRL *)1CH)) + {24 .. 30});*)
  126. RETURN TRUE
  127. END Start;
  128. PROCEDURE Schedule * (transfer: UsbHcdi.TransferToken);
  129. VAR
  130. address: LONGINT;
  131. BEGIN
  132. IF (transfer.pipe.speed = UsbHcdi.LowSpeed) OR (transfer.pipe.speed = UsbHcdi.FullSpeed) THEN
  133. address := transfer.pipe.device(Usb.UsbDevice).ttAddress;
  134. IF address = 0 THEN
  135. address := transfer.pipe.address
  136. END;
  137. END;
  138. SYSTEM.PUT32(iobase + TTCtrl, LSH(address, 24));
  139. Schedule^(transfer);
  140. END Schedule;
  141. END EnhancedHostController;
  142. VAR
  143. i: LONGINT;
  144. (**
  145. * Initializes and install the EHCI host controller driver on the host controller mapped at address iobase
  146. * and using interrupt number irq.
  147. *)
  148. PROCEDURE Init(irq, phyResetGpio: LONGINT; iobase: ADDRESS);
  149. CONST
  150. (* Some part of the EHCI driver is PCI-related. These are dummy values for it. *)
  151. bus = 0;
  152. device = 0;
  153. function = 0;
  154. VAR
  155. hostController: EnhancedHostController;
  156. BEGIN
  157. NEW(hostController, bus, device, function);
  158. hostController.phyResetGpio := phyResetGpio;
  159. IF hostController.Init(iobase, irq) THEN
  160. KernelLog.String("UsbEhci: Initialised USB Enhanced Host Controller."); KernelLog.Ln;
  161. UsbHcdi.RegisterHostController(hostController, UsbEhci.Description);
  162. ELSE
  163. KernelLog.String("UsbEhci: Cannot init USB Enhanced Host Controller."); KernelLog.Ln;
  164. END;
  165. END Init;
  166. PROCEDURE Install*;
  167. (* Load module *)
  168. END Install;
  169. BEGIN
  170. IF BootConfig.GetBoolValue("UsbEnable0") THEN
  171. KernelLog.Enter; KernelLog.String("Initializing USB"); KernelLog.Int(0, 0); KernelLog.String(", Address = "); KernelLog.Address(Platform.UsbBase[0]); KernelLog.String(", IRQ = "); KernelLog.Int(Platform.UsbIrq[0], 0); KernelLog.String(", PHY Reset = "); KernelLog.Int(BootConfig.GetIntValue("UsbPhyRstGpio0"), 0); KernelLog.Exit;
  172. Init(Platform.UsbIrq[0], BootConfig.GetIntValue("UsbPhyRstGpio0"), Platform.UsbBase[0])
  173. END;
  174. IF BootConfig.GetBoolValue("UsbEnable1") THEN
  175. KernelLog.Enter; KernelLog.String("Initializing USB"); KernelLog.Int(1, 0); KernelLog.String(", Address = "); KernelLog.Address(Platform.UsbBase[1]); KernelLog.String(", IRQ = "); KernelLog.Int(Platform.UsbIrq[1], 0); KernelLog.String(", PHY Reset = "); KernelLog.Int(BootConfig.GetIntValue("UsbPhyRstGpio1"), 0); KernelLog.Exit;
  176. Init(Platform.UsbIrq[1], BootConfig.GetIntValue("UsbPhyRstGpio1"), Platform.UsbBase[1])
  177. END
  178. END UsbEhciZynq.