mt_musb_qmu.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. * Copyright (c) 2013 MediaTek Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files
  6. * (the "Software"), to deal in the Software without restriction,
  7. * including without limitation the rights to use, copy, modify, merge,
  8. * publish, distribute, sublicense, and/or sell copies of the Software,
  9. * and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <sys/types.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <platform/errno.h>
  27. #include <platform/mt_typedefs.h>
  28. #include <arch/ops.h>
  29. #include <mt_musb_qmu.h>
  30. #include <mt_musb.h>
  31. /* USB DEBUG */
  32. #ifdef DBG_USB_QMU
  33. #define DBG_C(x...) dprintf(CRITICAL, "[USB][QMU] " x)
  34. #define DBG_I(x...) dprintf(INFO, "[USB][QMU] " x)
  35. #define DBG_S(x...) dprintf(SPEW, "[USB][QMU] " x)
  36. #else
  37. #define DBG_C(x...) do {} while (0)
  38. #define DBG_I(x...) do {} while (0)
  39. #define DBG_S(x...) do {} while (0)
  40. #endif
  41. /*
  42. * get_bd - get a null gpd
  43. * @args - arg1: dir, arg2: ep number
  44. */
  45. struct tgpd *get_gpd(u8 dir, u32 num)
  46. {
  47. struct tgpd *ptr;
  48. DBG_I("%s\n", __func__);
  49. if (dir == USB_DIR_OUT) {
  50. ptr = (struct tgpd *)rx_gpd_list[num].pnext;
  51. DBG_I("(rx_gpd_list[%d].pnext: %p)\n", num, (void *)(rx_gpd_list[num].pnext));
  52. if ((rx_gpd_list[num].pnext +1) < rx_gpd_list[num].pend)
  53. rx_gpd_list[num].pnext++;
  54. else
  55. rx_gpd_list[num].pnext = rx_gpd_list[num].pstart;
  56. } else {
  57. ptr = (struct tgpd *)tx_gpd_list[num].pnext;
  58. DBG_I("(tx_gpd_list[%d].pnext: %p)\n", num, (void *)(tx_gpd_list[num].pnext));
  59. tx_gpd_list[num].pnext++;
  60. if (tx_gpd_list[num].pnext >= tx_gpd_list[num].pend) {
  61. tx_gpd_list[num].pnext = tx_gpd_list[num].pstart;
  62. }
  63. }
  64. return ptr;
  65. }
  66. /*
  67. * get_bd - align gpd ptr to target ptr
  68. * @args - arg1: dir, arg2: ep number, arg3: target ptr
  69. */
  70. void gpd_ptr_align(u8 dir, u32 num, struct tgpd *ptr)
  71. {
  72. u32 run_next;
  73. run_next = true;
  74. while (run_next) {
  75. if (ptr == get_gpd(dir, num)) {
  76. run_next = false;
  77. }
  78. }
  79. }
  80. /*
  81. * init_gpd_list - initialize gpd management list
  82. * @args - arg1: dir, arg2: ep number, arg3: gpd virtual addr, arg4: gpd ioremap addr, arg5: gpd number
  83. */
  84. void init_gpd_list(u8 dir, int num, struct tgpd *ptr, struct tgpd *io_ptr, u32 size)
  85. {
  86. if (dir == USB_DIR_OUT) {
  87. rx_gpd_list[num].pstart = (struct tbd *)io_ptr;
  88. rx_gpd_list[num].pend = (struct tbd *)(io_ptr + size);
  89. rx_gpd_offset[num] = (u32)io_ptr - (u32)ptr;
  90. io_ptr++;
  91. rx_gpd_list[num].pnext = (struct tbd *)io_ptr;
  92. #if 0
  93. DBG_I("rx_gpd_list[%d].pstart: %p\n", num, rx_gpd_list[num].pstart);
  94. DBG_I("rx_gpd_list[%d].pnext: %p\n", num, rx_gpd_list[num].pnext);
  95. DBG_I("rx_gpd_list[%d].pend: %p\n", num, rx_gpd_list[num].pend);
  96. DBG_I("rx_gpd_offset[%d]: %p\n", num, (void *)rx_gpd_offset[num]);
  97. DBG_I("phy: %p\n", ptr);
  98. DBG_I("phy end: %p\n", ptr + size);
  99. DBG_I("io_ptr: %p\n", io_ptr);
  100. DBG_I("io_ptr end: %p\n", io_ptr + size);
  101. #endif
  102. } else {
  103. tx_gpd_list[num].pstart = (struct tbd *)io_ptr;
  104. tx_gpd_list[num].pend = (struct tbd *)((u8 *)(io_ptr + size));
  105. tx_gpd_offset[num] = (u32)io_ptr - (u32)ptr;
  106. io_ptr++;
  107. tx_gpd_list[num].pnext = (struct tbd *)((u8 *)io_ptr);
  108. #if 0
  109. DBG_I("tx_gpd_list[%d].pstart: %p\n", num, tx_gpd_list[num].pstart);
  110. DBG_I("tx_gpd_list[%d].pnext: %p\n", num, tx_gpd_list[num].pnext);
  111. DBG_I("tx_gpd_list[%d].pend: %p\n", num, tx_gpd_list[num].pend);
  112. DBG_I("tx_gpd_offset[%d]: %p\n", num, (void *)tx_gpd_offset[num]);
  113. DBG_I("phy: %p\n", ptr);
  114. DBG_I("phy end: %p\n", ptr); /* no need to add size? */
  115. DBG_I("io_ptr: %p\n", io_ptr);
  116. DBG_I("io_ptr end: %p\n", io_ptr+size);
  117. #endif
  118. }
  119. }
  120. /*
  121. * free_gpd - free gpd management list
  122. * @args - arg1: dir, arg2: ep number
  123. */
  124. void free_gpd(u8 dir, int num)
  125. {
  126. if (dir == USB_DIR_OUT) {
  127. memset(rx_gpd_list[num].pstart, 0, MAX_GPD_NUM * sizeof(struct tgpd));
  128. } else {
  129. memset(tx_gpd_list[num].pstart, 0, MAX_GPD_NUM * sizeof(struct tgpd));
  130. }
  131. }
  132. /*
  133. * mu3d_hal_alloc_qmu_mem - allocate gpd and bd memory for all ep
  134. *
  135. */
  136. void mu3d_hal_alloc_qmu_mem(void) {
  137. u32 i, size;
  138. struct tgpd *ptr, *io_ptr;
  139. for (i = 1; i <= MAX_QMU_EP; i++) {
  140. /* alloc RX */
  141. size = sizeof(struct tgpd);
  142. size *= MAX_GPD_NUM;
  143. ptr = (struct tgpd*)memalign(32, size);
  144. if (!ptr)
  145. panic("%s: cannot allocate RX QMU memory\n", __func__);
  146. memset(ptr, 0 , size);
  147. io_ptr = (struct tgpd*)ptr;
  148. init_gpd_list(USB_DIR_OUT, i, ptr, io_ptr, MAX_GPD_NUM);
  149. rx_gpd_end[i] = io_ptr;
  150. memset(rx_gpd_end[i], 0 , sizeof(struct tgpd));
  151. TGPD_CLR_FLAGS_HWO(rx_gpd_end[i]);
  152. rx_gpd_head[i] = rx_gpd_last[i] = rx_gpd_end[i];
  153. DBG_I("RQSAR[%d]: %p\n", i, rx_gpd_end[i]);
  154. /* alloc TX */
  155. size = sizeof(struct tgpd);
  156. size *= MAX_GPD_NUM;
  157. ptr = (struct tgpd*)memalign(32, size);
  158. if (!ptr)
  159. panic("%s: cannot allocate TX QMU memory\n", __func__);
  160. memset(ptr, 0, size);
  161. io_ptr = (struct tgpd*)ptr;
  162. init_gpd_list(USB_DIR_IN, i, ptr, io_ptr, MAX_GPD_NUM);
  163. tx_gpd_end[i] = io_ptr;
  164. memset(tx_gpd_end[i], 0 , sizeof(struct tgpd));
  165. TGPD_CLR_FLAGS_HWO(tx_gpd_end[i]);
  166. tx_gpd_head[i] = tx_gpd_last[i] = tx_gpd_end[i];
  167. DBG_I("TQSAR[%d]: %p\n", i, tx_gpd_end[i]);
  168. }
  169. }
  170. /*
  171. * mu3d_hal_init_qmu - initialize qmu
  172. *
  173. */
  174. void mu3d_hal_init_qmu(void)
  175. {
  176. DBG_I("%s\n", __func__);
  177. u32 i;
  178. /* Initialize QMU Tx/Rx start address. */
  179. for (i = 1; i <= MAX_QMU_EP; i++) {
  180. DBG_I("U3D_RXQSAR%d: %p, val: %x\n", i, (void *)MGC_O_QMU_RQSAR(i), MGC_ReadQMU32(MGC_O_QMU_RQSAR(i)));
  181. MGC_WriteQMU32(MGC_O_QMU_RQSAR(i), (u32)rx_gpd_head[i]);
  182. MGC_WriteQMU32(MGC_O_QMU_TQSAR(i), (u32)tx_gpd_head[i]);
  183. DBG_I("U3D_RXQSAR%d: %p, val: %x\n", i, (void *)MGC_O_QMU_RQSAR(i), MGC_ReadQMU32(MGC_O_QMU_RQSAR(i)));
  184. DBG_I("U3D_TXQSAR%d: %p, val: %x\n", i, (void *)MGC_O_QMU_TQSAR(i), MGC_ReadQMU32(MGC_O_QMU_TQSAR(i)));
  185. arch_clean_invalidate_cache_range((addr_t) tx_gpd_head[i], MAX_GPD_NUM * sizeof(struct tgpd));
  186. arch_clean_invalidate_cache_range((addr_t) rx_gpd_head[i], MAX_GPD_NUM * sizeof(struct tgpd));
  187. tx_gpd_end[i] = tx_gpd_last[i] = tx_gpd_head[i];
  188. rx_gpd_end[i] = rx_gpd_last[i] = rx_gpd_head[i];
  189. gpd_ptr_align(USB_DIR_OUT, i, rx_gpd_end[i]);
  190. gpd_ptr_align(USB_DIR_IN, i, tx_gpd_end[i]);
  191. /* Enable QMU Tx/Rx. */
  192. MGC_WriteQUCS32(MGC_O_QUCS_USBGCSR, MGC_ReadQUCS32(MGC_O_QUCS_USBGCSR)|USB_QMU_Rx_EN(i));
  193. MGC_WriteQUCS32(MGC_O_QUCS_USBGCSR, MGC_ReadQUCS32(MGC_O_QUCS_USBGCSR)|USB_QMU_Tx_EN(i));
  194. }
  195. DBG_I("MGC_O_QUCS_USBGCSR %x\n", MGC_ReadQUCS32(MGC_O_QUCS_USBGCSR));
  196. }
  197. /*
  198. * mu3d_hal_cal_checksum - calculate check sum
  199. * @args - arg1: data buffer, arg2: data length
  200. */
  201. u8 mu3d_hal_cal_checksum(u8 *data, int len)
  202. {
  203. u8 *pdata, cksum;
  204. int i;
  205. *(data + 1) = 0x0;
  206. pdata = data;
  207. cksum = 0;
  208. for (i = 0; i < len; i++) {
  209. cksum += *(pdata + i);
  210. }
  211. return 0xFF - cksum;
  212. }
  213. /*
  214. * mu3d_hal_resume_qmu - resume qmu function
  215. * @args - arg1: ep number, arg2: dir
  216. */
  217. void mu3d_hal_resume_qmu(int q_ep_num, u8 dir) {
  218. DBG_I("%s\n", __func__);
  219. if(dir == USB_DIR_OUT) {
  220. //DBG_I("USB_QMU_Resume USB_RX %x \n", (USB_HW_QMU_OFF + MGC_O_QMU_RQCSR(ep_num)));
  221. MGC_WriteQMU32(MGC_O_QMU_RQCSR(q_ep_num), DQMU_QUE_RESUME);
  222. if(!MGC_ReadQMU32(MGC_O_QMU_RQCSR(q_ep_num))){
  223. DBG_I("%s: RXQCSR1 val: %x\n", __func__, MGC_ReadQMU32(MGC_O_QMU_RQCSR(q_ep_num)));
  224. MGC_WriteQMU32(MGC_O_QMU_RQCSR(q_ep_num), DQMU_QUE_RESUME);
  225. }
  226. } else {
  227. //DBG_I("USB_QMU_Resume USB_TX %x \n", (USB_HW_QMU_OFF + MGC_O_QMU_TQCSR(ep_num)));
  228. MGC_WriteQMU32(MGC_O_QMU_TQCSR(q_ep_num), DQMU_QUE_RESUME);
  229. if (!MGC_ReadQMU32(MGC_O_QMU_TQCSR(q_ep_num))) { //judge if Queue is still inactive
  230. DBG_I("%s: TXQCSR1 val: %x\n", __func__, MGC_ReadQMU32(MGC_O_QMU_TQCSR(q_ep_num)));
  231. MGC_WriteQMU32(MGC_O_QMU_TQCSR(q_ep_num), DQMU_QUE_RESUME);
  232. }
  233. }
  234. }
  235. /*
  236. * mu3d_hal_prepare_tx_gpd - prepare tx gpd/bd
  237. * @args - arg1: gpd address, arg2: data buffer address, arg3: data length, arg4: ep number, arg5: with bd or not, arg6: write hwo bit or not, arg7: write ioc bit or not
  238. */
  239. struct tgpd* mu3d_hal_prepare_tx_gpd(struct tgpd *gpd, u8 *pbuf, u32 data_len, u8 ep_num, u8 _is_bdp, u8 ishwo, u8 ioc, u8 bps, u8 zlp) {
  240. #if defined(SUPPORT_VA)
  241. u8 *vbuffer;
  242. #endif
  243. DBG_I("%s: ep_num: %d, pbuf: %x, data_len: %x, zlp: %x\n", __func__, (int)ep_num, (u32)pbuf, data_len, (u32)zlp);
  244. arch_clean_invalidate_cache_range((addr_t) gpd, sizeof(struct tgpd));
  245. if (!_is_bdp) {
  246. TGPD_SET_DATA(gpd, pbuf);
  247. TGPD_CLR_FORMAT_BDP(gpd);
  248. } else {
  249. DBG_I("_is_bdp error\n");
  250. }
  251. TGPD_SET_BUF_LEN(gpd, data_len);
  252. TGPD_SET_EXT_LEN(gpd, 0);
  253. if (zlp) {
  254. TGPD_SET_FORMAT_ZLP(gpd);
  255. } else {
  256. TGPD_CLR_FORMAT_ZLP(gpd);
  257. }
  258. if (bps) {
  259. TGPD_SET_FORMAT_BPS(gpd);
  260. } else {
  261. TGPD_CLR_FORMAT_BPS(gpd);
  262. }
  263. if (ioc) {
  264. TGPD_SET_FORMAT_IOC(gpd);
  265. } else {
  266. TGPD_CLR_FORMAT_IOC(gpd);
  267. }
  268. /* Create next GPD */
  269. tx_gpd_end[ep_num] = get_gpd(USB_DIR_IN, ep_num);
  270. DBG_I("Malloc Tx 01 (GPD+EXT) (tx_gpd_end): 0x%x\n", (u32)tx_gpd_end[ep_num]);
  271. arch_clean_invalidate_cache_range((addr_t) tx_gpd_end[ep_num], sizeof(struct tgpd));
  272. memset(tx_gpd_end[ep_num], 0 , sizeof(struct tgpd));
  273. TGPD_CLR_FLAGS_HWO(tx_gpd_end[ep_num]);
  274. TGPD_SET_NEXT(gpd, tx_gpd_end[ep_num]);
  275. if (ishwo) {
  276. TGPD_SET_CHKSUM(gpd, CHECKSUM_LENGTH);
  277. TGPD_SET_FLAGS_HWO(gpd);
  278. } else {
  279. TGPD_CLR_FLAGS_HWO(gpd);
  280. TGPD_SET_CHKSUM_HWO(gpd, CHECKSUM_LENGTH);
  281. }
  282. /* gpd end */
  283. arch_clean_invalidate_cache_range((addr_t) gpd, sizeof(struct tgpd));
  284. return gpd;
  285. }
  286. /*
  287. * mu3d_hal_prepare_rx_gpd - prepare rx gpd/bd
  288. * @args - arg1: gpd address, arg2: data buffer address, arg3: data length, arg4: ep number, arg5: with bd or not, arg6: write hwo bit or not, arg7: write ioc bit or not
  289. */
  290. struct tgpd* mu3d_hal_prepare_rx_gpd(struct tgpd *gpd, u8 *pbuf, u32 data_len, u8 ep_num, u8 _is_bdp, u8 ishwo, u8 ioc, u8 bps, u32 max_pkt_size) {
  291. DBG_I("%s: GPD: %p, ep_num: %d, pbuf: %x, data_len: %x, _is_bdp: %d, ishwo: %d, ioc: %d, bps: %d\n", __func__, gpd, (int)ep_num, (u32)pbuf, data_len, _is_bdp, ishwo, ioc, bps);
  292. arch_clean_invalidate_cache_range((addr_t) gpd, sizeof(struct tgpd));
  293. if (!_is_bdp) {
  294. TGPD_SET_DATA(gpd, pbuf);
  295. TGPD_CLR_FORMAT_BDP(gpd);
  296. } else {
  297. DBG_I("_is_bdp error\n");
  298. }
  299. if (data_len < gpd_buf_size)
  300. TGPD_SET_DATABUF_LEN(gpd, data_len); /* or length?? */
  301. else
  302. TGPD_SET_DATABUF_LEN(gpd, gpd_buf_size);
  303. TGPD_SET_BUF_LEN(gpd, 0);
  304. if (bps) {
  305. TGPD_SET_FORMAT_BPS(gpd);
  306. } else {
  307. TGPD_CLR_FORMAT_BPS(gpd);
  308. }
  309. if (ioc) {
  310. TGPD_SET_FORMAT_IOC(gpd);
  311. } else {
  312. TGPD_CLR_FORMAT_IOC(gpd);
  313. }
  314. rx_gpd_end[ep_num] = get_gpd(USB_DIR_OUT, ep_num);
  315. memset(rx_gpd_end[ep_num], 0, sizeof(struct tgpd));
  316. DBG_I("Rx Next GPD 0x%x\n", (u32)rx_gpd_end[ep_num]);
  317. TGPD_CLR_FLAGS_HWO(rx_gpd_end[ep_num]);
  318. TGPD_SET_NEXT(gpd, rx_gpd_end[ep_num]);
  319. if (ishwo) {
  320. TGPD_SET_CHKSUM(gpd, CHECKSUM_LENGTH);
  321. TGPD_SET_FLAGS_HWO(gpd);
  322. } else {
  323. TGPD_CLR_FLAGS_HWO(gpd);
  324. TGPD_SET_CHKSUM_HWO(gpd, CHECKSUM_LENGTH);
  325. }
  326. DBG_I("Rx gpd info { HWO %d, Next_GPD %x ,databuf_length %d, DataBuffer %x, Recived Len %d, Endpoint %d, TGL %d, ZLP %d}\n",
  327. (u32)TGPD_GET_FLAG(gpd), (u32)TGPD_GET_NEXT(gpd),
  328. (u32)TGPD_GET_DATABUF_LEN(gpd), (u32)TGPD_GET_DATA(gpd),
  329. (u32)TGPD_GET_BUF_LEN(gpd), (u32)TGPD_GET_EPaddr(gpd),
  330. (u32)TGPD_GET_TGL(gpd), (u32)TGPD_GET_ZLP(gpd));
  331. arch_clean_invalidate_cache_range((addr_t) gpd, sizeof(struct tgpd));
  332. return gpd;
  333. }
  334. /*
  335. * mu3d_hal_insert_transfer_gpd - insert new gpd/bd
  336. * @args - arg1: ep number, arg2: dir, arg3: data buffer, arg4: data length, arg5: write hwo bit or not, arg6: write ioc bit or not
  337. */
  338. void mu3d_hal_insert_transfer_gpd(int ep_num, u8 dir, u8* buf, u32 count, u8 ishwo, u8 ioc, u8 bps, u8 zlp, u32 max_pkt_size) {
  339. struct tgpd* gpd;
  340. DBG_I("%s: ep_num: %d, dir: %d, buf: %x, count: %x, ishwo: %d, ioc: :%d, bps: %d, zlp: %x, maxp: %x\n", __func__, (int)ep_num, dir, (u32)buf, count, ishwo, ioc, bps, (u32)zlp, (u32)max_pkt_size);
  341. if (dir == USB_DIR_IN) {
  342. gpd = tx_gpd_end[ep_num];
  343. DBG_I("TX gpd: %x\n", (unsigned int)gpd);
  344. /* is_bdp = 0; We need to use BD because for mass storage, the largest data > GPD limitation */
  345. mu3d_hal_prepare_tx_gpd(gpd, buf, count, ep_num, 0, ishwo, ioc, bps, zlp);
  346. } else if (dir == USB_DIR_OUT) {
  347. gpd = rx_gpd_end[ep_num];
  348. DBG_I("RX gpd: %x\n", (unsigned int)gpd);
  349. /* is_bdp = 0; We need to use BD because for mass storage, the largest data > GPD limitation */
  350. mu3d_hal_prepare_rx_gpd(gpd, buf, count, ep_num, 0, ishwo, ioc, bps, max_pkt_size);
  351. }
  352. }
  353. /*
  354. * mu3d_hal_start_qmu - start qmu function (QMU flow : mu3d_hal_init_qmu ->mu3d_hal_start_qmu -> mu3d_hal_insert_transfer_gpd -> mu3d_hal_resume_qmu)
  355. * @args - arg1: ep number, arg2: dir
  356. */
  357. void usb_start_qmu(int q_ep_num, u8 dir)
  358. {
  359. u32 qcr;
  360. u32 txZLP, rxZLP;
  361. u32 isEmptyCheck = 0;
  362. DBG_I("%s: dir: %x\n", __func__, dir);
  363. #ifdef CFG_RX_ZLP_EN
  364. rxZLP = 1;
  365. #else
  366. rxZLP = 0;
  367. #endif
  368. #if (TXZLP == HW_MODE)
  369. txZLP = 1;
  370. //qcr = readl(U3D_QCR1);
  371. //writel(qcr &~ QMU_TX_ZLP(q_ep_num), U3D_QCR1);
  372. //qcr = readl(U3D_QCR2);
  373. //writel(qcr | QMU_TX_ZLP(q_ep_num), U3D_QCR2);
  374. #elif (TXZLP == GPD_MODE)
  375. txZLP = 0;
  376. //qcr = readl(U3D_QCR1);
  377. //writel(qcr | QMU_TX_ZLP(q_ep_num), U3D_QCR1);
  378. #endif
  379. if (dir == USB_DIR_IN) {
  380. qcr= MGC_ReadQMU32(MGC_O_QMU_QCR0);
  381. MGC_WriteQMU32(MGC_O_QMU_QCR0, qcr|DQMU_TQCS_EN(q_ep_num));
  382. if(txZLP){
  383. qcr = MGC_ReadQMU32(MGC_O_QMU_QCR2);
  384. MGC_WriteQMU32(MGC_O_QMU_QCR2, qcr|DQMU_TX_ZLP(q_ep_num));
  385. }
  386. MGC_WriteQIRQ32(MGC_O_QIRQ_QIMCR, DQMU_M_TX_DONE(q_ep_num)|DQMU_M_TQ_EMPTY|DQMU_M_TXQ_ERR|DQMU_M_TXEP_ERR);
  387. if(isEmptyCheck){
  388. MGC_WriteQIRQ32(MGC_O_QIRQ_TEPEMPMCR, DQMU_M_TX_EMPTY(q_ep_num));
  389. }else{
  390. MGC_WriteQIRQ32(MGC_O_QIRQ_QIMSR, DQMU_M_TQ_EMPTY);
  391. }
  392. qcr = DQMU_M_TX_LEN_ERR(q_ep_num);
  393. qcr |= DQMU_M_TX_GPDCS_ERR(q_ep_num) | DQMU_M_TX_BDCS_ERR(q_ep_num);
  394. MGC_WriteQIRQ32(MGC_O_QIRQ_TQEIMCR, qcr);
  395. MGC_WriteQIRQ32(MGC_O_QIRQ_TEPEIMCR, DQMU_M_TX_EP_ERR(q_ep_num));
  396. if(MGC_ReadQMU16(MGC_O_QMU_TQCSR(q_ep_num)) & DQMU_QUE_ACTIVE) {
  397. DBG_I("Tx %d Active Now!\n", q_ep_num);
  398. return;
  399. }
  400. MGC_WriteQMU32(MGC_O_QMU_TQCSR(q_ep_num), DQMU_QUE_START);
  401. } else if (dir == USB_DIR_OUT) {
  402. qcr = MGC_ReadQMU32(MGC_O_QMU_QCR0);
  403. MGC_WriteQMU32(MGC_O_QMU_QCR0, qcr | DQMU_RQCS_EN(q_ep_num));
  404. #if 0
  405. if (rxZLP)
  406. {
  407. qcr = MGC_ReadQMU32(MGC_O_QMU_QCR3);
  408. MGC_WriteQMU32(MGC_O_QMU_QCR3, qcr | DQMU_RX_ZLP(q_ep_num));
  409. } else {
  410. qcr = MGC_ReadQMU32(MGC_O_QMU_QCR3);
  411. MGC_WriteQMU32(MGC_O_QMU_QCR3, qcr &~ DQMU_RX_ZLP(q_ep_num));
  412. }
  413. #endif
  414. MGC_WriteQIRQ32(MGC_O_QIRQ_QIMCR, DQMU_M_RX_DONE(q_ep_num)|DQMU_M_RQ_EMPTY|DQMU_M_RXQ_ERR|DQMU_M_RXEP_ERR);
  415. if(isEmptyCheck){
  416. MGC_WriteQIRQ32(MGC_O_QIRQ_REPEMPMCR, DQMU_M_RX_EMPTY(q_ep_num));
  417. }else{
  418. MGC_WriteQIRQ32(MGC_O_QIRQ_QIMSR, DQMU_M_RQ_EMPTY);
  419. }
  420. qcr = DQMU_M_RX_LEN_ERR(q_ep_num);
  421. qcr |= DQMU_M_RX_GPDCS_ERR(q_ep_num);
  422. qcr |= rxZLP ? DQMU_M_RX_ZLP_ERR(q_ep_num) : 0;
  423. MGC_WriteQIRQ32(MGC_O_QIRQ_RQEIMCR, qcr);
  424. MGC_WriteQIRQ32(MGC_O_QIRQ_REPEIMCR, DQMU_M_RX_EP_ERR(q_ep_num));
  425. if (MGC_ReadQMU16(MGC_O_QMU_RQCSR(q_ep_num)) & DQMU_QUE_ACTIVE) {
  426. DBG_I("Rx %d Active Now!\n", q_ep_num);
  427. return;
  428. }
  429. MGC_WriteQMU32(MGC_O_QMU_RQCSR(q_ep_num), DQMU_QUE_START);
  430. }
  431. }
  432. /*
  433. * mu3d_hal_stop_qmu - stop qmu function (after qmu stop, fifo should be flushed)
  434. * @args - arg1: ep number, arg2: dir
  435. */
  436. void mu3d_hal_stop_qmu(int q_ep_num, u8 dir) {
  437. DBG_I("%s\n", __func__);
  438. if(dir == USB_DIR_IN){
  439. if(MGC_ReadQMU16(MGC_O_QMU_TQCSR(q_ep_num))&DQMU_QUE_ACTIVE){
  440. MGC_WriteQMU32(MGC_O_QMU_TQCSR(q_ep_num), DQMU_QUE_STOP);
  441. while(MGC_ReadQMU16(MGC_O_QMU_TQCSR(q_ep_num))&DQMU_QUE_ACTIVE);
  442. DBG_I("Stop Tx Queue %d!\n", q_ep_num);
  443. }else{
  444. DBG_I("Tx Queue %d InActive Now, Don't need to stop!\n", q_ep_num);
  445. }
  446. } else {
  447. if(MGC_ReadQMU16(MGC_O_QMU_RQCSR(q_ep_num))&DQMU_QUE_ACTIVE){
  448. MGC_WriteQMU32(MGC_O_QMU_RQCSR(q_ep_num), DQMU_QUE_STOP);
  449. while(MGC_ReadQMU16(MGC_O_QMU_RQCSR(q_ep_num))&DQMU_QUE_ACTIVE);
  450. DBG_I("Stop Rx Queue %d!\n", q_ep_num);
  451. }else{
  452. DBG_I("Rx Queue %d InActive Now, Don't need to stop!\n", q_ep_num);
  453. }
  454. }
  455. }
  456. /*
  457. * flush_qmu - stop qmu and align qmu start ptr t0 current ptr
  458. * @args - arg1: ep number, arg2: dir
  459. */
  460. void mu3d_hal_flush_qmu(int q_ep_num, u8 dir) {
  461. struct tgpd *gpd_current;
  462. struct udc_endpoint *ept;
  463. struct urb *urb;
  464. //struct USB_REQ *req = mu3d_hal_get_req(q_ep_num, dir);
  465. ept = mt_find_ep(q_ep_num, dir);
  466. DBG_I("%s\n", __func__);
  467. if (dir == USB_DIR_IN) {
  468. DBG_I("flush_qmu USB_DIR_IN\n");
  469. urb = ept->tx_urb;
  470. mu3d_hal_stop_qmu(q_ep_num, USB_DIR_IN);
  471. gpd_current = (struct tgpd*)(MGC_ReadQMU32(MGC_O_QMU_TQCPR(q_ep_num)));
  472. DBG_I("(MGC_O_QMU_TQCPR gpd_current: %p)\n", gpd_current);
  473. if (!gpd_current) {
  474. gpd_current = (struct tgpd*)(MGC_ReadQMU32(MGC_O_QMU_TQSAR(q_ep_num)));
  475. }
  476. DBG_I("(MGC_O_QMU_TQSAR gpd_current: %p)\n", gpd_current);
  477. tx_gpd_end[q_ep_num] = tx_gpd_last[q_ep_num] = gpd_current;
  478. gpd_ptr_align(dir, q_ep_num, tx_gpd_end[q_ep_num]);
  479. free_gpd(dir, q_ep_num);
  480. arch_clean_invalidate_cache_range((addr_t) tx_gpd_list[q_ep_num].pstart, MAX_GPD_NUM * sizeof(struct tgpd));
  481. MGC_WriteQMU32(MGC_O_QMU_TQSAR(q_ep_num), (u32)tx_gpd_last[q_ep_num]);
  482. urb->qmu_complete = true;
  483. DBG_I("TxQ %d Flush Now!\n", q_ep_num);
  484. } else if (dir == USB_DIR_OUT) {
  485. urb = ept->rcv_urb;
  486. mu3d_hal_stop_qmu(q_ep_num, USB_DIR_OUT);
  487. gpd_current = (struct tgpd *)(MGC_ReadQMU32(MGC_O_QMU_RQCPR(q_ep_num)));
  488. if (!gpd_current) {
  489. gpd_current = (struct tgpd *)(MGC_ReadQMU32(MGC_O_QMU_RQSAR(q_ep_num)));
  490. }
  491. rx_gpd_end[q_ep_num] = rx_gpd_last[q_ep_num] = gpd_current;
  492. gpd_ptr_align(dir, q_ep_num, rx_gpd_end[q_ep_num]);
  493. free_gpd(dir, q_ep_num);
  494. arch_clean_invalidate_cache_range((addr_t) rx_gpd_list[q_ep_num].pstart, MAX_GPD_NUM * sizeof(struct tgpd));
  495. MGC_WriteQMU32(MGC_O_QMU_RQSAR(q_ep_num), (u32)rx_gpd_end[q_ep_num]);
  496. urb->qmu_complete = true;
  497. DBG_I("RxQ %d Flush Now!\n", q_ep_num);
  498. }
  499. }