usb_hc_ohci.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. * Copyright (c) 2024, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usb_hc_ohci.h"
  7. /* Frame Interval / Periodic Start.
  8. *
  9. * At 12Mbps, there are 12000 bit time in each 1Msec frame.
  10. */
  11. #define OHCI_FMINTERVAL_FI (12000 - 1)
  12. #define OHCI_FMINTERVAL_FSMPS ((6 * (OHCI_FMINTERVAL_FI - 210)) / 7)
  13. #define DEFAULT_FMINTERVAL ((OHCI_FMINTERVAL_FSMPS << OHCI_FMINT_FSMPS_SHIFT) | OHCI_FMINTERVAL_FI)
  14. #define DEFAULT_PERSTART ((OHCI_FMINTERVAL_FI * 9) / 10)
  15. struct ohci_hcd g_ohci_hcd[CONFIG_USBHOST_MAX_BUS];
  16. USB_NOCACHE_RAM_SECTION struct ohci_ed_hw g_ohci_ed_pool[CONFIG_USBHOST_MAX_BUS][CONFIG_USB_OHCI_ED_NUM];
  17. USB_NOCACHE_RAM_SECTION struct ohci_hcca ohci_hcca[CONFIG_USBHOST_MAX_BUS];
  18. int ohci_init(struct usbh_bus *bus)
  19. {
  20. volatile uint32_t timeout = 0;
  21. uint32_t regval;
  22. struct ohci_ed_hw *ed;
  23. memset(&g_ohci_hcd[bus->hcd.hcd_id], 0, sizeof(struct ohci_hcd));
  24. memset(g_ohci_ed_pool[bus->hcd.hcd_id], 0, sizeof(struct ohci_ed_hw) * CONFIG_USB_OHCI_ED_NUM);
  25. for (uint32_t i = 0; i < 32; i++) {
  26. ohci_hcca[bus->hcd.hcd_id].inttbl[i] = 0;
  27. }
  28. for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
  29. ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
  30. if ((uint32_t)&ed->hw % 32) {
  31. USB_LOG_ERR("struct ohci_ed_hw is not align 32\r\n");
  32. return -USB_ERR_INVAL;
  33. }
  34. for (uint8_t i = 0; i < CONFIG_USB_OHCI_TD_NUM; i++) {
  35. if ((uint32_t)&ed->td_pool[i] % 32) {
  36. USB_LOG_ERR("struct ohci_td_hw is not align 32\r\n");
  37. return -USB_ERR_INVAL;
  38. }
  39. }
  40. }
  41. for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
  42. ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
  43. ed->waitsem = usb_osal_sem_create(0);
  44. }
  45. USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision);
  46. OHCI_HCOR->hcintdis = OHCI_INT_MIE;
  47. OHCI_HCOR->hccontrol = 0;
  48. OHCI_HCOR->hccmdsts = OHCI_CMDST_HCR;
  49. while (OHCI_HCOR->hccmdsts & OHCI_CMDST_HCR) {
  50. usb_osal_msleep(1);
  51. timeout++;
  52. if (timeout > 100) {
  53. return -USB_ERR_TIMEOUT;
  54. }
  55. }
  56. OHCI_HCOR->hcfminterval = DEFAULT_FMINTERVAL;
  57. OHCI_HCOR->hcperiodicstart = DEFAULT_PERSTART;
  58. OHCI_HCOR->hclsthreshold = 0x628;
  59. OHCI_HCOR->hccontrolheaded = 0;
  60. OHCI_HCOR->hcbulkheaded = 0;
  61. OHCI_HCOR->hchcca = (uintptr_t)&ohci_hcca[bus->hcd.hcd_id];
  62. /* Clear pending interrupts */
  63. regval = OHCI_HCOR->hcintsts;
  64. OHCI_HCOR->hcintsts = regval;
  65. /* Put HC in operational state */
  66. regval = OHCI_HCOR->hccontrol;
  67. regval &= ~OHCI_CTRL_CBSR;
  68. regval &= ~OHCI_CTRL_HCFS_MASK;
  69. regval |= OHCI_CTRL_HCFS_OPER;
  70. regval |= OHCI_CTRL_CBSR;
  71. regval |= OHCI_CTRL_CLE;
  72. OHCI_HCOR->hccontrol = regval;
  73. g_ohci_hcd[bus->hcd.hcd_id].n_ports = OHCI_HCOR->hcrhdescriptora & OHCI_RHDESCA_NDP_MASK;
  74. USB_LOG_INFO("OHCI n_ports:%d\r\n", g_ohci_hcd[bus->hcd.hcd_id].n_ports);
  75. OHCI_HCOR->hcrhdescriptora &= ~OHCI_RHDESCA_PSM;
  76. OHCI_HCOR->hcrhdescriptora &= ~OHCI_RHDESCA_NPS;
  77. /* Set global power in HcRhStatus */
  78. OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP;
  79. usb_osal_msleep(20);
  80. /* Enable OHCI interrupts */
  81. OHCI_HCOR->hcinten = OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
  82. return 0;
  83. }
  84. int ohci_deinit(struct usbh_bus *bus)
  85. {
  86. uint32_t regval;
  87. struct ohci_ed_hw *ed;
  88. /* Disable OHCI interrupts */
  89. OHCI_HCOR->hcintdis = OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
  90. /* Clear pending interrupts */
  91. regval = OHCI_HCOR->hcintsts;
  92. OHCI_HCOR->hcintsts = regval;
  93. OHCI_HCOR->hcrhsts &= ~OHCI_RHSTATUS_SGP;
  94. regval = OHCI_HCOR->hccontrol;
  95. regval &= ~OHCI_CTRL_HCFS_MASK;
  96. regval |= OHCI_CTRL_HCFS_SUSPEND;
  97. OHCI_HCOR->hccontrol = regval;
  98. for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
  99. ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
  100. usb_osal_sem_delete(ed->waitsem);
  101. }
  102. return 0;
  103. }
  104. uint16_t ohci_get_frame_number(struct usbh_bus *bus)
  105. {
  106. return OHCI_HCOR->hcfmnumber;
  107. }
  108. int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
  109. {
  110. uint8_t nports;
  111. uint8_t port;
  112. uint32_t temp;
  113. nports = g_ohci_hcd[bus->hcd.hcd_id].n_ports;
  114. port = setup->wIndex;
  115. if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
  116. switch (setup->bRequest) {
  117. case HUB_REQUEST_CLEAR_FEATURE:
  118. switch (setup->wValue) {
  119. case HUB_FEATURE_HUB_C_LOCALPOWER:
  120. break;
  121. case HUB_FEATURE_HUB_C_OVERCURRENT:
  122. break;
  123. default:
  124. return -USB_ERR_NOTSUPP;
  125. }
  126. break;
  127. case HUB_REQUEST_SET_FEATURE:
  128. switch (setup->wValue) {
  129. case HUB_FEATURE_HUB_C_LOCALPOWER:
  130. break;
  131. case HUB_FEATURE_HUB_C_OVERCURRENT:
  132. break;
  133. default:
  134. return -USB_ERR_NOTSUPP;
  135. }
  136. break;
  137. case HUB_REQUEST_GET_DESCRIPTOR:
  138. break;
  139. case HUB_REQUEST_GET_STATUS:
  140. memset(buf, 0, 4);
  141. break;
  142. default:
  143. break;
  144. }
  145. } else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) {
  146. switch (setup->bRequest) {
  147. case HUB_REQUEST_CLEAR_FEATURE:
  148. if (!port || port > nports) {
  149. return -USB_ERR_INVAL;
  150. }
  151. switch (setup->wValue) {
  152. case HUB_PORT_FEATURE_ENABLE:
  153. temp = OHCI_RHPORTST_CCS;
  154. break;
  155. case HUB_PORT_FEATURE_SUSPEND:
  156. temp = OHCI_HCOR->hccontrol;
  157. temp &= ~OHCI_CTRL_HCFS_MASK;
  158. temp |= OHCI_CTRL_HCFS_RESUME;
  159. OHCI_HCOR->hccontrol = temp;
  160. usb_osal_msleep(20);
  161. temp = OHCI_HCOR->hccontrol;
  162. temp &= ~OHCI_CTRL_HCFS_MASK;
  163. temp |= OHCI_CTRL_HCFS_OPER;
  164. OHCI_HCOR->hccontrol = temp;
  165. temp = OHCI_RHPORTST_POCI;
  166. break;
  167. case HUB_PORT_FEATURE_C_SUSPEND:
  168. temp = OHCI_RHPORTST_PSSC;
  169. break;
  170. case HUB_PORT_FEATURE_POWER:
  171. OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_CGP;
  172. temp = OHCI_RHPORTST_LSDA;
  173. break;
  174. case HUB_PORT_FEATURE_C_CONNECTION:
  175. temp = OHCI_RHPORTST_CSC;
  176. break;
  177. case HUB_PORT_FEATURE_C_ENABLE:
  178. temp = OHCI_RHPORTST_PESC;
  179. break;
  180. case HUB_PORT_FEATURE_C_OVER_CURREN:
  181. temp = OHCI_RHPORTST_OCIC;
  182. break;
  183. case HUB_PORT_FEATURE_C_RESET:
  184. temp = OHCI_RHPORTST_PRSC;
  185. break;
  186. default:
  187. return -USB_ERR_NOTSUPP;
  188. }
  189. OHCI_HCOR->hcrhportsts[port - 1] = temp;
  190. break;
  191. case HUB_REQUEST_SET_FEATURE:
  192. if (!port || port > nports) {
  193. return -USB_ERR_INVAL;
  194. }
  195. switch (setup->wValue) {
  196. case HUB_PORT_FEATURE_SUSPEND:
  197. temp = OHCI_HCOR->hccontrol;
  198. temp &= ~OHCI_CTRL_HCFS_MASK;
  199. temp |= OHCI_CTRL_HCFS_SUSPEND;
  200. OHCI_HCOR->hccontrol = temp;
  201. break;
  202. case HUB_PORT_FEATURE_POWER:
  203. OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP;
  204. break;
  205. case HUB_PORT_FEATURE_RESET:
  206. OHCI_HCOR->hcrhportsts[port - 1] = OHCI_RHPORTST_PRS;
  207. while (OHCI_HCOR->hcrhportsts[port - 1] & OHCI_RHPORTST_PRS) {
  208. }
  209. break;
  210. default:
  211. return -USB_ERR_NOTSUPP;
  212. }
  213. break;
  214. case HUB_REQUEST_GET_STATUS:
  215. if (!port || port > nports) {
  216. return -USB_ERR_INVAL;
  217. }
  218. temp = OHCI_HCOR->hcrhportsts[port - 1];
  219. memcpy(buf, &temp, 4);
  220. break;
  221. default:
  222. break;
  223. }
  224. }
  225. return 0;
  226. }
  227. int ohci_submit_urb(struct usbh_urb *urb)
  228. {
  229. return -USB_ERR_NOTSUPP;
  230. }
  231. int ohci_kill_urb(struct usbh_urb *urb)
  232. {
  233. return -USB_ERR_NOTSUPP;
  234. }
  235. void OHCI_IRQHandler(uint8_t busid)
  236. {
  237. uint32_t usbsts;
  238. struct usbh_bus *bus;
  239. bus = &g_usbhost_bus[busid];
  240. usbsts = OHCI_HCOR->hcintsts & OHCI_HCOR->hcinten;
  241. if (usbsts & OHCI_INT_RHSC) {
  242. OHCI_HCOR->hcintsts = OHCI_INT_RHSC;
  243. for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) {
  244. uint32_t portsc = OHCI_HCOR->hcrhportsts[port];
  245. if (portsc & OHCI_RHPORTST_CSC) {
  246. if (OHCI_HCOR->hcrhsts & OHCI_RHSTATUS_DRWE) {
  247. /* If DRWE is set, Connect Status Change indicates a remote wake-up event */
  248. } else {
  249. if (portsc & OHCI_RHPORTST_CCS) {
  250. } else {
  251. }
  252. bus->hcd.roothub.int_buffer[0] |= (1 << (port + 1));
  253. usbh_hub_thread_wakeup(&bus->hcd.roothub);
  254. }
  255. }
  256. }
  257. }
  258. if (usbsts & OHCI_INT_WDH) {
  259. OHCI_HCOR->hcintsts = OHCI_INT_WDH;
  260. }
  261. }
  262. #ifndef CONFIG_USB_EHCI_WITH_OHCI
  263. __WEAK void usb_hc_low_level_init(struct usbh_bus *bus)
  264. {
  265. (void)bus;
  266. }
  267. __WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus)
  268. {
  269. (void)bus;
  270. }
  271. int usb_hc_init(struct usbh_bus *bus)
  272. {
  273. usb_hc_low_level_init(bus);
  274. return ohci_init(bus);
  275. }
  276. int usb_hc_deinit(struct usbh_bus *bus)
  277. {
  278. ohci_deinit(bus);
  279. usb_hc_low_level_deinit(bus);
  280. return 0;
  281. }
  282. int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
  283. {
  284. return ohci_roothub_control(bus, setup, buf);
  285. }
  286. int usbh_submit_urb(struct usbh_urb *urb)
  287. {
  288. return ohci_submit_urb(urb);
  289. }
  290. int usbh_kill_urb(struct usbh_urb *urb)
  291. {
  292. return ohci_kill_urb(urb);
  293. }
  294. void USBH_IRQHandler(uint8_t busid)
  295. {
  296. OHCI_IRQHandler(busid);
  297. }
  298. #endif