1
0

dwc_usb.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /* Copyright (C) 2013 by John Cronin <jncronin@tysos.org>
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. * The above copyright notice and this permission notice shall be included in
  10. * all copies or substantial portions of the Software.
  11. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. * THE SOFTWARE.
  18. */
  19. /* RPi USB host controller driver
  20. *
  21. * The controller is a Synopsys DWC USB 2 OTG
  22. *
  23. * References:
  24. * Altera cv_54018-1.2, chapter 12, USB 2.0 OTG controller
  25. * Raspberry Pi - USB Controller ver 1.03 by Luke Robertson
  26. * BCM2835 Peripherals Guide
  27. * Chadderz USB driver - https://github.com/Chadderz121/csud
  28. */
  29. #include <stdint.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include "mmio.h"
  34. #include "mbox.h"
  35. #include "usb.h"
  36. #include "dwc_usb.h"
  37. #include "timer.h"
  38. #define SYNOPSYS_ID 0x4f54280a
  39. #define USER_ID 0x2708a000
  40. #ifdef DEBUG2
  41. #define DWC_USB_DEBUG
  42. #endif
  43. struct dwc_usb_hcd
  44. {
  45. struct usb_hcd b;
  46. uint32_t base;
  47. uint32_t config1;
  48. uint32_t config2;
  49. uint32_t config3;
  50. uint32_t config4;
  51. };
  52. static int hcd_id = 0;
  53. static char driver_name[] = "dwc_usb";
  54. static int dwc_usb_reset(struct usb_hcd *dev);
  55. static int dwc_usb_send_req(struct usb_hcd *dev, struct usb_request *req);
  56. static int dwc_usb_post_reset_init(struct dwc_usb_hcd *d);
  57. int dwc_usb_init(struct usb_hcd **dev, uint32_t base)
  58. {
  59. // First check we have a valid controller
  60. uint32_t vendor = mmio_read(base + DWC_USB_SYNOPSYS_ID);
  61. uint32_t userid = mmio_read(base + DWC_USB_USER_ID);
  62. if(vendor != SYNOPSYS_ID)
  63. {
  64. printf("DWC_USB: invalid vendor id %08x\n", vendor);
  65. return -1;
  66. }
  67. if(userid != USER_ID)
  68. {
  69. printf("DWC_USB: invalid used id %08x\n", userid);
  70. return -1;
  71. }
  72. // Build the device structure
  73. int cur_hcd_id = hcd_id++;
  74. // Limit driver interfaces to 1 currently as we use fixed FIFO addresses
  75. if(cur_hcd_id >= 1)
  76. {
  77. printf("DWC_USB: too many host controllers registered\n");
  78. return -1;
  79. }
  80. struct dwc_usb_hcd *ret =
  81. (struct dwc_usb_hcd *)malloc(sizeof(struct dwc_usb_hcd));
  82. ret->b.driver_name = driver_name;
  83. char *device_name = malloc(strlen(driver_name) + 2);
  84. strncpy(device_name, driver_name, strlen(driver_name));
  85. device_name[strlen(driver_name)] = '0' + cur_hcd_id;
  86. device_name[strlen(driver_name) + 1] = '\0';
  87. ret->b.device_name = device_name;
  88. ret->base = base;
  89. ret->config1 = mmio_read(base + DWC_USB_CONFIG_1);
  90. ret->config2 = mmio_read(base + DWC_USB_CONFIG_2);
  91. ret->config3 = mmio_read(base + DWC_USB_CONFIG_3);
  92. ret->config4 = mmio_read(base + DWC_USB_CONFIG_4);
  93. ret->b.reset = dwc_usb_reset;
  94. ret->b.send_req = dwc_usb_send_req;
  95. // Mask the interrupt line to the ARM
  96. uint32_t ahb_conf = mmio_read(base + DWC_USB_AHB_CONF);
  97. ahb_conf &= ~0x1;
  98. usleep(2000);
  99. mmio_write(base + DWC_USB_AHB_CONF, ahb_conf);
  100. // Enable all interrupts
  101. usleep(2000);
  102. mmio_write(base + DWC_USB_CORE_IRPT_MASK, 0xffffffff);
  103. // Power on the USB via the mailbox interface (undocumented - from csud)
  104. mbox_write(0, 0x80);
  105. if(mbox_read(0) != 0x80)
  106. {
  107. printf("DWC_USB: unable to power up USB\n");
  108. return -1;
  109. }
  110. // Reset the controller
  111. if(dwc_usb_reset((struct usb_hcd *)ret) != 0)
  112. {
  113. printf("DWC_USB: usb_reset() failed\n");
  114. return -1;
  115. }
  116. // Return success
  117. printf("DWC_USB: Initialized host controller %s\n", ret->b.device_name);
  118. *dev = (struct usb_hcd *)ret;
  119. #ifdef DWC_USB_DEBUG
  120. usleep(2000000); // Pause so we can see the screen
  121. #endif
  122. return 0;
  123. }
  124. int dwc_usb_post_reset_init(struct dwc_usb_hcd *d)
  125. {
  126. #ifdef DWC_USB_DEBUG
  127. printf("DWC_USB: beginning post reset init\n");
  128. #endif
  129. // Clear all interrupts
  130. usleep(2000);
  131. mmio_write(d->base + DWC_USB_CORE_IRPT, 0xffffffff);
  132. // Clear the power register (write StopPClock - csud does this)
  133. usleep(2000);
  134. mmio_write(d->base + DWC_USB_POWER, 0);
  135. // Initialize the FIFOs
  136. usleep(2000);
  137. mmio_write(d->base + DWC_USB_RECV_FIFO_SIZE, DWC_USB_FIFO_SIZE << 16);
  138. usleep(2000);
  139. mmio_write(d->base + DWC_USB_NON_PERIODIC_FIFO_SIZE,
  140. (DWC_USB_FIFO_START & 0xffff) | (DWC_USB_FIFO_SIZE << 16));
  141. usleep(2000);
  142. mmio_write(d->base + DWC_USB_PERIODIC_FIFO_SIZE,
  143. ((DWC_USB_FIFO_START + DWC_USB_FIFO_SIZE) & 0xffff) |
  144. (DWC_USB_FIFO_SIZE << 16));
  145. // Power on the host port
  146. usleep(2000);
  147. uint32_t ctrl_status = mmio_read(d->base + DWC_USB_HOST_PORT_CTRL_STATUS);
  148. ctrl_status |= DWC_USB_HPCS_PRTPWR;
  149. mmio_write(d->base + DWC_USB_HOST_PORT_CTRL_STATUS, ctrl_status);
  150. #ifdef DWC_USB_DEBUG
  151. printf("DWC_USB: completed post reset init\n");
  152. #endif
  153. return 0;
  154. }
  155. int dwc_usb_reset(struct usb_hcd *dev)
  156. {
  157. struct dwc_usb_hcd *d = (struct dwc_usb_hcd *)dev;
  158. #ifdef DWC_USB_DEBUG
  159. printf("DWC_USB: beginning core reset\n");
  160. #endif
  161. // Wait for the AHB IDLE state
  162. TIMEOUT_WAIT(mmio_read(d->base + DWC_USB_CORE_RESET) & (1 << 31), 500000);
  163. if((mmio_read(d->base + DWC_USB_CORE_RESET) & (1 << 31)) == 0)
  164. {
  165. printf("DWC_USB: reset(): timeout waiting for AHB IDLE state\n");
  166. return -1;
  167. }
  168. // Raise the core soft reset bit high
  169. uint32_t reset = mmio_read(d->base + DWC_USB_CORE_RESET);
  170. reset |= 0x1;
  171. mmio_write(d->base + DWC_USB_CORE_RESET, reset);
  172. usleep(2000);
  173. // Wait for core reset to go low and AHB IDLE high
  174. int success = 0;
  175. struct timer_wait *tw = register_timer(500000);
  176. do
  177. {
  178. reset = mmio_read(d->base + DWC_USB_CORE_RESET);
  179. if(((reset & 0x1) == 0) && ((reset & (1 << 31)) != 0))
  180. {
  181. success = 1;
  182. break;
  183. }
  184. } while(!compare_timer(tw));
  185. free(tw);
  186. if(!success)
  187. {
  188. printf("DWC_USB: reset(): timeout waiting for reset (%08x)\n", reset);
  189. return -1;
  190. }
  191. #ifdef DWC_USB_DEBUG
  192. printf("DWC_USB: core reset complete\n");
  193. #endif
  194. dwc_usb_post_reset_init(d);
  195. return 0;
  196. }
  197. int dwc_usb_send_req(struct usb_hcd *dev, struct usb_request *req)
  198. {
  199. // TODO
  200. (void)dev;
  201. (void)req;
  202. printf("DWC_USB: usb_send_req(): unimplemented\n");
  203. while(1);
  204. return 0;
  205. }