TestUsbEhci.Mod 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. (**
  2. Test driver for USB controller for the ZedBoard.
  3. Here we just try to configure the EHCI controller in order to get the PortChangeInterrupt.
  4. Written by Timothée Martiel, 2014.
  5. *)
  6. MODULE UsbEhci;
  7. IMPORT SYSTEM, Trace, Kernel, Objects, Machine;
  8. CONST
  9. (* Base address of the controller *)
  10. BaseAddress = 0E0002140H;
  11. (* Interrupt *)
  12. IRQ = 53;
  13. (* Host Controller Capability Registers *)
  14. HcCapLength = 00H;
  15. HcCapHciVersion = 02H;
  16. HcCapSparams = 04H;
  17. HcCapCparams = 08H;
  18. HcCapPortroute = 0CH;
  19. (* Host Controller Operational Registers *)
  20. HcUsbCmd = 00H;
  21. HcUsbSts = 04H;
  22. HcUsbIntr = 08H;
  23. HcFrIndex = 0CH;
  24. (*HcCtrlDsSegment = 10H;*)
  25. HcPeriodicListBase = 14H;
  26. HcAsyncListAddr = 18H;
  27. HcUlpiViewport = 30H;
  28. HcConfigFlag = 40H;
  29. HcPortSc = 44H;
  30. HcUsbMode = 68H;
  31. HcOtgSc = 64H;
  32. (* HcUsbCmd register fields *)
  33. CmdInterruptThreshold = {16..23};
  34. CmdAsyncSchedParkMode = {11};
  35. CmdAsyncSchedParkCount = {8..9};
  36. CmdLightHcReset = {7}; (* Note: optional *)
  37. CmdAsyncAdvDoorbell = {6};
  38. CmdAsyncSchedEnable = {5};
  39. CmdPeriodicSchedEnable = {4};
  40. CmdFrameListSize = {2..3};
  41. CmdHcReset = {1};
  42. CmdRunStop = {0};
  43. CmdReserved = {10} + {12..15} + {24..31};
  44. (* HcUsbSts register fields *)
  45. StsAsyncSchedule = {15};
  46. StsPeriodicSchedule = {14};
  47. StsReclamation = {13};
  48. StsHcHalted = {12};
  49. (* HcUsbSts & HcUsbIntr common fields *)
  50. StsAsyncAdvance= {5};
  51. StsHostSystemError = {4};
  52. StsFrameListRollover = {3};
  53. StsPortChange = {2};
  54. StsUsbError = {1};
  55. StsUsbInterrupt = {0};
  56. (* Port Status & Control register, EHCIspec p. 26-30 *)
  57. PscWakeOnOvercurrent = {22};
  58. PscWakeOnDisconnect = {21};
  59. PscWakeOnConnect = {20};
  60. PscTestControl = {16..19};
  61. PscIndicatorControl = {14..15};
  62. PscPortOwner = {13};
  63. PscPortPower = {12};
  64. PscLineStatus = {10..11};
  65. PscPortReset = {8};
  66. PscSuspend = {7};
  67. PscForcePortResume = {6};
  68. PscOvercurrentChange = {5};
  69. PscOvercurrentActive = {4};
  70. PscPortEnableChange = {3};
  71. PscPortEnable = {2};
  72. PscConnectStatusChange = {1};
  73. PscCurrentConnectStatus = {0};
  74. PscReserved = {9} + {23..31};
  75. PscChangeMask = {1, 3, 5};
  76. (* HcUsbMode bits *)
  77. ModeHost = {0, 1};
  78. ModeDevice = {1};
  79. ModeIdle = {};
  80. (* HcOtgSc bits *)
  81. OtgScId = 8;
  82. OtgScIdPu = 5;
  83. (* Timeout in milliseconds the HC must have completed the reset command *)
  84. MaxWaits = 1000;
  85. (* GPIO Registers & Pins *)
  86. Pin = 15;
  87. GpioData = ADDRESS(0E000A040H);
  88. GpioDir = ADDRESS(0E000A204H);
  89. GpioOen = ADDRESS(0E000A208H);
  90. VAR
  91. reg: SET;
  92. i: LONGINT;
  93. t: Kernel.Timer;
  94. irqCounter: LONGINT;
  95. (** Reports USB Interrupts *)
  96. PROCEDURE InterruptHandler;
  97. VAR s : SET;
  98. BEGIN (* Works without being exclusive *)
  99. SYSTEM.GET(BaseAddress + HcUsbSts, s);
  100. s := s * ({0 .. 5} - StsFrameListRollover);
  101. IF s # {} THEN
  102. (* Reset interrupt status register (Write clear)*)
  103. SYSTEM.PUT32(BaseAddress + HcUsbSts, s * {0..5});
  104. IF s * StsAsyncAdvance # {} THEN
  105. Trace.StringLn("INTERRUPT: AsyncAdvance")
  106. END;
  107. IF s * StsHostSystemError # {} THEN
  108. Trace.StringLn("INTERRUPT: HostSystemError")
  109. END;
  110. IF s * StsFrameListRollover # {} THEN
  111. Trace.StringLn("INTERRUPT: FrameListRollover")
  112. END;
  113. IF s * StsPortChange # {} THEN
  114. Trace.StringLn("INTERRUPT: PortChange")
  115. END;
  116. IF s * (StsUsbError + StsUsbInterrupt) # {} THEN
  117. Trace.StringLn("INTERRUPT: UsbError or UsbInterrupt")
  118. END;
  119. END;
  120. Trace.String('IRQ Counter: '); Trace.Int(irqCounter, 0); Trace.Ln;
  121. INC(irqCounter)
  122. END InterruptHandler;
  123. (** Write to ULPI register *)
  124. PROCEDURE UlpiWrite(address: ADDRESS; value: SET);
  125. VAR
  126. viewport: ADDRESS;
  127. reg: SET;
  128. BEGIN
  129. viewport := SYSTEM.VAL(ADDRESS, value);
  130. INC(viewport, address * 10000H);
  131. INC(viewport, 60000000H);
  132. UlpiWakeup;
  133. SYSTEM.PUT(BaseAddress + HcUlpiViewport, viewport);
  134. Trace.String('ULPI Viewport: '); Trace.Address(SYSTEM.GET32(BaseAddress + HcUlpiViewport));
  135. REPEAT
  136. SYSTEM.GET(BaseAddress + HcUlpiViewport, reg);
  137. Trace.Ln; Trace.String(" "); Trace.Address(SYSTEM.VAL(ADDRESS, reg));
  138. UNTIL ~(30 IN reg);
  139. Trace.StringLn(" -- Transaction finished")
  140. END UlpiWrite;
  141. (** Wakeup ULPI *)
  142. PROCEDURE UlpiWakeup;
  143. VAR
  144. reg: SET;
  145. BEGIN
  146. SYSTEM.PUT(BaseAddress + HcUlpiViewport, {31});
  147. REPEAT
  148. SYSTEM.GET(BaseAddress + HcUlpiViewport, reg)
  149. UNTIL ~(31 IN reg);
  150. END UlpiWakeup;
  151. BEGIN
  152. Trace.StringLn("Starting EHCI configuration");
  153. NEW(t);
  154. (* Install handler *)
  155. Objects.InstallHandler(InterruptHandler, Machine.IRQ0 + IRQ);
  156. (*
  157. (* Configure Pin 15 (USB0 Reset) as output *)
  158. SYSTEM.PUT(GpioDir, {Pin});
  159. SYSTEM.PUT(GpioOen, {Pin});
  160. (* Hold low state for at least 200ns *)
  161. SYSTEM.GET(GpioData, reg);
  162. SYSTEM.PUT(GpioData, reg - {Pin});
  163. t.Sleep(1000);
  164. SYSTEM.PUT(GpioData, reg + {Pin});
  165. SYSTEM.PUT32(0F8000210H, 1);
  166. t.Sleep(1000);
  167. SYSTEM.PUT32(0F8000210H, 0);
  168. t.Sleep(1000);
  169. SYSTEM.PUT32(0F8000210H, 1);
  170. *)
  171. (* Reset PHY.
  172. see: http://www.zedboard.org/content/bare-metal-usb-device-code
  173. C code:
  174. Xil_Out32(0xe000a204, 0x80);
  175. Xil_Out32(0xe000a208, 0x80);
  176. Xil_Out32(0xe000a040, 0x80);
  177. Xil_Out32(0xe000a040, 0x00);
  178. Xil_Out32(0xe000a040, 0x80);
  179. *)
  180. (*
  181. (* Setting MIO 8 as output *)
  182. SYSTEM.PUT32(0E000A204H, ADDRESS(0FFFFFFFFH));
  183. (* Setting MIO 8 enable output *)
  184. SYSTEM.PUT32(0E000A208H, ADDRESS(0FFFFFFFFH));
  185. (* set state of MIO 8 to 1, 0 and then 1 again *)
  186. SYSTEM.PUT32(0E000A040H, ADDRESS(0FFFFFFFFH));
  187. t.Sleep(100);
  188. SYSTEM.PUT32(0E000A040H, {});
  189. t.Sleep(100);
  190. SYSTEM.PUT32(0E000A040H, ADDRESS(0FFFFFFFFH));
  191. t.Sleep(100);
  192. *)
  193. (*
  194. (* Select ULPI clock source *)
  195. SYSTEM.GET(0F8000130H, reg);
  196. SYSTEM.PUT32(0F8000130H, reg + {6});
  197. *)
  198. (*
  199. (* USB0 reset *)
  200. SYSTEM.GET(0F8000210H, reg);
  201. SYSTEM.PUT32(0F8000210H, reg + {0});
  202. t.Sleep(20);
  203. SYSTEM.GET(0F8000210H, reg);
  204. SYSTEM.PUT32(0F8000210H, reg - {0});
  205. *)
  206. (* Get MIO pins 28 to 39 in USB mode *)
  207. SYSTEM.GET(0F8000770H, reg);
  208. Trace.String("MIO 28 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  209. SYSTEM.GET(0F8000774H, reg);
  210. Trace.String("MIO 29 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  211. SYSTEM.GET(0F8000778H, reg);
  212. Trace.String("MIO 30 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  213. SYSTEM.GET(0F800077CH, reg);
  214. Trace.String("MIO 31 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  215. SYSTEM.GET(0F8000780H, reg);
  216. Trace.String("MIO 32 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  217. SYSTEM.GET(0F8000784H, reg);
  218. Trace.String("MIO 33 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  219. SYSTEM.GET(0F8000788H, reg);
  220. Trace.String("MIO 34 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  221. SYSTEM.GET(0F800078CH, reg);
  222. Trace.String("MIO 35 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  223. SYSTEM.GET(0F8000790H, reg);
  224. Trace.String("MIO 36 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  225. SYSTEM.GET(0F8000794H, reg);
  226. Trace.String("MIO 37 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  227. SYSTEM.GET(0F8000798H, reg);
  228. Trace.String("MIO 38 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  229. SYSTEM.GET(0F800079CH, reg);
  230. Trace.String("MIO 39 state: "); Trace.Address(SYSTEM.VAL(ADDRESS, reg)); Trace.Ln;
  231. (* Set mode to host *)
  232. SYSTEM.GET(BaseAddress + HcUsbMode, reg);
  233. SYSTEM.PUT(BaseAddress + HcUsbMode, reg + ModeHost);
  234. (* Stop *)
  235. SYSTEM.GET(BaseAddress + HcUsbCmd, reg);
  236. SYSTEM.PUT(BaseAddress + HcUsbCmd, reg - CmdRunStop);
  237. i := 1;
  238. SYSTEM.GET(BaseAddress + HcUsbSts, reg);
  239. WHILE (reg * StsHcHalted = {}) & (i <= MaxWaits) DO
  240. SYSTEM.GET(BaseAddress + HcUsbSts, reg);
  241. INC(i);
  242. t.Sleep(1);
  243. END;
  244. IF reg * StsHcHalted = {} THEN
  245. Trace.StringLn("ERROR: Controller did not stop");
  246. LOOP END
  247. ELSE
  248. Trace.StringLn("EHCI stopped")
  249. END;
  250. (* Reset *)
  251. SYSTEM.GET(BaseAddress + HcUsbCmd, reg);
  252. SYSTEM.PUT(BaseAddress + HcUsbCmd, reg + CmdHcReset);
  253. i := 1;
  254. SYSTEM.GET(BaseAddress + HcUsbCmd, reg);
  255. WHILE (i <= MaxWaits) & (reg * CmdHcReset # {}) DO
  256. SYSTEM.GET(BaseAddress + HcUsbCmd, reg);
  257. t.Sleep(1);
  258. END;
  259. IF i = MaxWaits THEN
  260. Trace.StringLn("ERROR: Reset timeout");
  261. LOOP END
  262. ELSE
  263. Trace.StringLn("EHCI reset")
  264. END;
  265. (* Clear interrupts *)
  266. SYSTEM.PUT32(BaseAddress + HcUsbSts, 0);
  267. (* Enable all interrupts except the frame list rollover interrupt *)
  268. SYSTEM.GET(BaseAddress + HcUsbIntr, reg);
  269. SYSTEM.PUT32(BaseAddress + HcUsbIntr, reg + {0 .. 5} - StsFrameListRollover);
  270. (* Port power in OTGSC *)
  271. SYSTEM.GET(BaseAddress + HcOtgSc, reg);
  272. INCL(reg, 1); EXCL(reg, 0);
  273. SYSTEM.PUT(BaseAddress + HcOtgSc, reg);
  274. (* Set mode to host *)
  275. SYSTEM.GET(BaseAddress + HcUsbMode, reg);
  276. SYSTEM.PUT(BaseAddress + HcUsbMode, reg + ModeHost);
  277. (* Port power in PortSc *)
  278. SYSTEM.GET(BaseAddress + HcPortSc, reg);
  279. SYSTEM.PUT32(BaseAddress + HcPortSc, reg + PscPortPower);
  280. t.Sleep(20); (* wait 20 ms for stable power *)
  281. (* Start EHCI *)
  282. SYSTEM.GET(BaseAddress + HcUsbCmd, reg);
  283. SYSTEM.PUT32(BaseAddress + HcUsbCmd, reg + CmdRunStop);
  284. (* Initialize ULPI. See linux_ehci.c *)
  285. (* Reset *)
  286. UlpiWrite(5H, {5});
  287. (* Set DRVVBUSEXTERNAL, DMPULLDOWN & DPPULLDOWN *)
  288. UlpiWrite(0BH, {1, 2});
  289. (* Set FULLSPEED, OPMODE NORMAL & SUSPENDM *)
  290. UlpiWrite(5H, {6});
  291. (* Set DRVVBUS & DRVVBUSEXT *)
  292. UlpiWrite(0BH, {5, 6});
  293. Trace.StringLn("END EHCI Configuration")
  294. END UsbEhci.