ehci-sunxi.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /**
  2. * drivers/usb/host/ehci_sunxi.c
  3. * (C) Copyright 2010-2015
  4. * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
  5. * yangnaitian, 2011-5-24, create this file
  6. * javen, 2011-6-26, add suspend and resume
  7. * javen, 2011-7-18, move clock and power operations out from driver
  8. *
  9. * SoftWinner EHCI Driver
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License as
  13. * published by the Free Software Foundation; either version 2 of
  14. * the License, or (at your option) any later version.
  15. *
  16. */
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <usb_gen_hcd.h>
  20. #include "sunxi-hci.h"
  21. #include "platform_usb.h"
  22. #include "ehci.h"
  23. #include "hal_gpio.h"
  24. #include "hal_cfg.h"
  25. #if USB_MAX_CONTROLLER_COUNT
  26. static struct sunxi_hci_hcd g_sunxi_ehci[USB_MAX_CONTROLLER_COUNT];
  27. #else
  28. static struct sunxi_hci_hcd *g_sunxi_ehci = 0;
  29. #endif
  30. static unsigned char g_sunxi_insmod_cnt = 0;
  31. static void sunxi_ehci_insmod_count(void)
  32. {
  33. g_sunxi_insmod_cnt++;
  34. }
  35. static void sunxi_ehci_rmmod_count(void)
  36. {
  37. if (g_sunxi_insmod_cnt > 0)
  38. {
  39. g_sunxi_insmod_cnt--;
  40. }
  41. else
  42. {
  43. hal_log_err("ERR: g_sunxi_insmod_cnt = %d", g_sunxi_insmod_cnt);
  44. }
  45. }
  46. static unsigned char sunxi_ehci_count(void)
  47. {
  48. return g_sunxi_insmod_cnt;
  49. }
  50. static void sunxi_hcd_board_set_vbus(
  51. struct sunxi_hci_hcd *sunxi_ehci, int is_on)
  52. {
  53. sunxi_ehci->set_power(sunxi_ehci, is_on);
  54. }
  55. static void sunxi_hcd_board_set_passby(struct sunxi_hci_hcd *sunxi_ehci,
  56. int is_on)
  57. {
  58. sunxi_ehci->usb_passby(sunxi_ehci, is_on);
  59. }
  60. static int open_ehci_clock(struct sunxi_hci_hcd *sunxi_ehci)
  61. {
  62. return sunxi_ehci->open_clock(sunxi_ehci, 0);
  63. }
  64. static int close_ehci_clock(struct sunxi_hci_hcd *sunxi_ehci)
  65. {
  66. return sunxi_ehci->close_clock(sunxi_ehci, 0);
  67. }
  68. static void sunxi_start_ehci(struct sunxi_hci_hcd *sunxi_ehci)
  69. {
  70. open_ehci_clock(sunxi_ehci);
  71. sunxi_hcd_board_set_passby(sunxi_ehci, 1);
  72. sunxi_hcd_board_set_vbus(sunxi_ehci, 1);
  73. #if defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_SOC_SUN20IW1)
  74. sunxi_ehci_insmod_count();
  75. #endif
  76. }
  77. static void sunxi_stop_ehci(struct sunxi_hci_hcd *sunxi_ehci)
  78. {
  79. #if defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_SOC_SUN20IW1)
  80. sunxi_ehci_rmmod_count();
  81. if (sunxi_ehci_count() == 0)
  82. #endif
  83. {
  84. sunxi_hcd_board_set_vbus(sunxi_ehci, 0);
  85. }
  86. sunxi_hcd_board_set_passby(sunxi_ehci, 0);
  87. close_ehci_clock(sunxi_ehci);
  88. }
  89. static int sunxi_ehci_setup(struct hc_gen_dev *hcd)
  90. {
  91. struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  92. int ret = ehci_init(hcd);
  93. //ehci->need_io_watchdog = 0;
  94. return ret;
  95. }
  96. static const struct hc_driver sunxi_ehci_hc_driver = {
  97. .description = "ehci_hcd",
  98. .product_desc = "SW USB2.0 'Enhanced' Host Controller (EHCI) Driver",
  99. .hcd_priv_size = sizeof(struct ehci_hcd),
  100. /**
  101. * generic hardware linkage
  102. */
  103. .irq = NULL,
  104. //.flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
  105. .flags = HC_DRIVER_FLAG_HCD_USB2,
  106. /**
  107. * basic lifecycle operations
  108. *
  109. * FIXME -- ehci_init() doesn't do enough here.
  110. * See ehci-ppc-soc for a complete implementation.
  111. */
  112. .reset = sunxi_ehci_setup,
  113. .start = ehci_run,
  114. .stop = ehci_stop,
  115. // .shutdown = ehci_shutdown,
  116. /**
  117. * managing i/o requests and associated device resources
  118. */
  119. .urb_enqueue = ehci_urb_enqueue,
  120. .urb_dequeue = ehci_urb_dequeue,
  121. .endpoint_disable = ehci_endpoint_disable,
  122. // .endpoint_reset = ehci_endpoint_reset,
  123. /**
  124. * scheduling support
  125. */
  126. .get_frame_number = ehci_get_frame,
  127. /**
  128. * root hub support
  129. */
  130. .hub_status_data = ehci_hub_status_data,
  131. .hub_control = ehci_hub_control,
  132. .hub_suspend = ehci_bus_suspend,
  133. .hub_resume = ehci_bus_resume,
  134. // .relinquish_port = ehci_relinquish_port,
  135. // .port_handed_over = ehci_port_handed_over,
  136. // .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
  137. };
  138. int sunxi_insmod_ehci(struct sunxi_hci_hcd * sunxi_ehci)
  139. {
  140. /*
  141. * hc_gen_dev----------usb_hcd
  142. * hc_private----------ehci_hcd
  143. * usb_host_virt_dev--------usb_device
  144. * */
  145. //struct usb_hcd *hcd = NULL;
  146. struct hc_gen_dev *hcd = NULL;
  147. struct ehci_hcd *ehci = NULL;
  148. int mask;
  149. int port;
  150. int ret = 0;
  151. hal_log_info("[%s%d]: probe, sunxi_ehci: 0x%p, 0x:%p, irq_no:%d\n",
  152. sunxi_ehci->hci_name, sunxi_ehci->usbc_no, sunxi_ehci,
  153. sunxi_ehci->usb_vbase, sunxi_ehci->irq_no);
  154. sunxi_ehci->ehci_base = sunxi_ehci->usb_vbase;
  155. sunxi_ehci->ehci_reg_length = SUNXI_USB_EHCI_LEN;
  156. /* creat a usb_hcd for the ehci controller*/
  157. hcd = usb_create_hc_gen_dev(&sunxi_ehci_hc_driver, sunxi_ehci->hci_name);
  158. //hcd = usb_create_hcd(&sunxi_ehci_hc_driver, sunxi_ehci->hci_name);
  159. sunxi_ehci->hcd = hcd;
  160. /* request irq */
  161. if (request_irq(sunxi_ehci->irq_no, ehci_irq_handler, sunxi_ehci->usb_irq_flag, "ehci", hcd) < 0) {
  162. hal_log_err("request irq error\n");
  163. return -1;
  164. }
  165. enable_irq(sunxi_ehci->irq_no);
  166. /* echi start to work */
  167. sunxi_start_ehci(sunxi_ehci);
  168. ehci = hcd_to_ehci(hcd);
  169. ehci->caps = (struct ehci_caps *)(long)sunxi_ehci->ehci_base;
  170. ehci->regs = (struct ehci_regs *)((long)ehci->caps +
  171. HC_LENGTH(ehci, hal_readl(&ehci->caps->hc_capbase)));
  172. /* cache this readonly data, minimize chip reads */
  173. ehci->hcs_params = hal_readl(&ehci->caps->hcs_params);
  174. hcd->state = HC_GEN_DEV_STATE_RUNNING;
  175. /*melis original func: usb_add_hc_gen_dev()*/
  176. ret = usb_add_hc_gen_dev(hcd, sunxi_ehci->irq_no, IRQF_SHARED);
  177. if (ret != 0) {
  178. hal_log_err("ERR: usb_add_hcd failed\n");
  179. ret = -ENOMEM;
  180. goto ERR3;
  181. }
  182. /* ehci_bus_suspend */
  183. //port = HCS_N_PORTS(ehci->hcs_params);
  184. //while (port--) {
  185. // uint32_t *reg = &ehci->regs->port_status [port];
  186. // uint32_t t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
  187. // uint32_t t2 = t1 & ~PORT_WAKE_BITS;
  188. // t2 |= PORT_WKOC_E | PORT_WKCONN_E;
  189. // ehci_writel(ehci, t2, reg);
  190. //}
  191. /* Do not halt the controller since the PM ops not supported yet. */
  192. //ehci_halt (ehci);
  193. /* allow remote wakeup */
  194. mask = INTR_MASK;
  195. //if (!hcd->self.root_hub->do_remote_wakeup)
  196. // mask &= ~STS_PCD;
  197. ehci_writel(ehci, mask, &ehci->regs->intr_enable);
  198. ehci_readl(ehci, &ehci->regs->intr_enable);
  199. return 0;
  200. ERR3:
  201. sunxi_stop_ehci(sunxi_ehci);
  202. //usb_put_hcd(hcd);
  203. ERR2:
  204. sunxi_ehci->hcd = NULL;
  205. //g_sunxi_ehci[sunxi_ehci->usbc_no] = NULL;
  206. ERR1:
  207. return ret;
  208. }
  209. int sunxi_rmmod_ehci(struct sunxi_hci_hcd * sunxi_ehci)
  210. {
  211. hal_log_info("[%s%d]: remove, sunxi_ehci: 0x%p, 0x:%p, irq_no:%d\n",
  212. sunxi_ehci->hci_name, sunxi_ehci->usbc_no, sunxi_ehci,
  213. sunxi_ehci->usb_vbase, sunxi_ehci->irq_no);
  214. //usb_remove_hcd(hcd);
  215. if (sunxi_ehci->irq_no > 0)
  216. {
  217. free_irq(sunxi_ehci->irq_no, sunxi_ehci->hcd);
  218. }
  219. //usb_put_hcd(hcd);
  220. //#if defined(CONFIG_SUNXI_REGULATOR_DT)
  221. // if (sunxi_ehci->supply)
  222. // regulator_put(sunxi_ehci->supply);
  223. //#endif
  224. //
  225. sunxi_stop_ehci(sunxi_ehci);
  226. sunxi_ehci->hcd = NULL;
  227. return 0;
  228. }
  229. int sunxi_ehci_hcd_init(int hci_num)
  230. {
  231. int value = 0;
  232. char ehci_name[10] = {0};
  233. sprintf(ehci_name, "usbc%1d", hci_num);
  234. if (Hal_Cfg_GetKeyValue(ehci_name, KEY_USB_ENABLE, (int32_t *)&value, 1) == 0) {
  235. if (value == SUNXI_USB_DISABLE) {
  236. hal_log_err("ERR: ehci%d disable", hci_num);
  237. return -1;
  238. }
  239. }
  240. if(g_sunxi_ehci == 0) {
  241. hal_log_err("ERR: ehci%d NULL!", hci_num);
  242. return -1;
  243. }
  244. if (hci_num >= USB_MAX_CONTROLLER_COUNT) {
  245. hal_log_err("ERR: ehci%d oversize!", hci_num);
  246. return -1;
  247. }
  248. int ret = 0;
  249. struct sunxi_hci_hcd *sunxi_ehci = &g_sunxi_ehci[hci_num];
  250. if(!sunxi_ehci->hcd)
  251. {
  252. struct platform_usb_config *hci_table = platform_get_hci_table();
  253. struct platform_usb_config *otg_table = platform_get_otg_table();
  254. sunxi_ehci->usbc_no = hci_num;
  255. sunxi_ehci->usb_vbase = hci_table[hci_num].pbase;
  256. sunxi_ehci->irq_no = hci_table[hci_num].irq;
  257. sunxi_ehci->otg_vbase = otg_table->pbase;
  258. sprintf(sunxi_ehci->hci_name, "%s", hci_table[hci_num].name);
  259. hci_clock_init(sunxi_ehci);
  260. sunxi_hci_get_config_param(sunxi_ehci);
  261. sunxi_ehci->open_clock = open_clock;
  262. sunxi_ehci->close_clock = close_clock;
  263. sunxi_ehci->set_power = sunxi_set_vbus;
  264. sunxi_ehci->usb_passby = usb_passby;
  265. sunxi_insmod_ehci(sunxi_ehci);
  266. return 0;
  267. }
  268. else
  269. {
  270. hal_log_err("ERR: ehci%d already exist!", hci_num);
  271. }
  272. return -1;
  273. }
  274. int sunxi_ehci_hcd_deinit(int hci_num)
  275. {
  276. struct sunxi_hci_hcd *sunxi_ehci = &g_sunxi_ehci[hci_num];
  277. #if 0
  278. /* TODO */
  279. struct sunxi_hci_hcd *sunxi_ehci = NULL;
  280. int ret = 0;
  281. if (sunxi_ehci->probe == 1) {
  282. ret = sunxi_rmmod_ehci(pdev);
  283. if (ret == 0)
  284. exit_sunxi_hci(sunxi_ehci);
  285. return ret;
  286. } else
  287. return 0;
  288. #endif
  289. if(sunxi_ehci->hcd)
  290. return sunxi_rmmod_ehci(sunxi_ehci);
  291. else
  292. hal_log_err("ERR: ehci%d is NULL!", hci_num);
  293. return 0;
  294. }
  295. static void ehci_set_interrupt_enable(const struct ehci_hcd *ehci,
  296. uint32_t regs, u32 enable)
  297. {
  298. USBC_Writel(enable & 0x3f, (regs + EHCI_OPR_USBINTR));
  299. }
  300. static void ehci_disable_periodic_schedule(const struct ehci_hcd *ehci,
  301. uint32_t regs)
  302. {
  303. u32 reg_val = 0;
  304. reg_val = USBC_Readl(regs + EHCI_OPR_USBCMD);
  305. reg_val &= ~(0x1<<4);
  306. USBC_Writel(reg_val, (regs + EHCI_OPR_USBCMD));
  307. }
  308. static void ehci_disable_async_schedule(const struct ehci_hcd *ehci,
  309. uint32_t regs)
  310. {
  311. unsigned int reg_val = 0;
  312. reg_val = USBC_Readl(regs + EHCI_OPR_USBCMD);
  313. reg_val &= ~(0x1<<5);
  314. USBC_Writel(reg_val, (regs + EHCI_OPR_USBCMD));
  315. }
  316. static void ehci_set_config_flag(const struct ehci_hcd *ehci,
  317. uint32_t regs)
  318. {
  319. USBC_Writel(0x1, (regs + EHCI_OPR_CFGFLAG));
  320. }
  321. static void ehci_test_stop(const struct ehci_hcd *ehci,
  322. uint32_t regs)
  323. {
  324. unsigned int reg_val = 0;
  325. reg_val = USBC_Readl(regs + EHCI_OPR_USBCMD);
  326. reg_val &= (~0x1);
  327. USBC_Writel(reg_val, (regs + EHCI_OPR_USBCMD));
  328. }
  329. static void ehci_test_reset(const struct ehci_hcd *ehci,
  330. uint32_t regs)
  331. {
  332. u32 reg_val = 0;
  333. reg_val = USBC_Readl(regs + EHCI_OPR_USBCMD);
  334. reg_val |= (0x1<<1);
  335. USBC_Writel(reg_val, (regs + EHCI_OPR_USBCMD));
  336. }
  337. static unsigned int ehci_test_reset_complete(const struct ehci_hcd *ehci,
  338. uint32_t regs)
  339. {
  340. unsigned int reg_val = 0;
  341. reg_val = USBC_Readl(regs + EHCI_OPR_USBCMD);
  342. reg_val &= (0x1<<1);
  343. return !reg_val;
  344. }
  345. static void ehci_start(const struct ehci_hcd *ehci, uint32_t regs)
  346. {
  347. unsigned int reg_val = 0;
  348. reg_val = USBC_Readl(regs + EHCI_OPR_USBCMD);
  349. reg_val |= 0x1;
  350. USBC_Writel(reg_val, (regs + EHCI_OPR_USBCMD));
  351. }
  352. static unsigned int ehci_is_halt(const struct ehci_hcd *ehci,
  353. uint32_t regs)
  354. {
  355. unsigned int reg_val = 0;
  356. reg_val = USBC_Readl(regs + EHCI_OPR_USBSTS) >> 12;
  357. reg_val &= 0x1;
  358. return reg_val;
  359. }
  360. static void ehci_port_control(const struct ehci_hcd *ehci,
  361. uint32_t regs, u32 port_no, u32 control)
  362. {
  363. USBC_Writel(control, (regs + EHCI_OPR_USBCMD + (port_no<<2)));
  364. }
  365. static void ehci_put_port_suspend(const struct ehci_hcd *ehci,
  366. uint32_t regs)
  367. {
  368. unsigned int reg_val = 0;
  369. reg_val = USBC_Readl(regs + EHCI_OPR_PORTSC);
  370. reg_val |= (0x01<<7);
  371. USBC_Writel(reg_val, (regs + EHCI_OPR_PORTSC));
  372. }
  373. static void ehci_test_mode(const struct ehci_hcd *ehci,
  374. uint32_t regs, u32 test_mode)
  375. {
  376. unsigned int reg_val = 0;
  377. reg_val = USBC_Readl(regs + EHCI_OPR_PORTSC);
  378. reg_val &= ~(0x0f<<16);
  379. reg_val |= test_mode;
  380. USBC_Writel(reg_val, (regs + EHCI_OPR_PORTSC));
  381. }
  382. static void __ehci_ed_test(const struct ehci_hcd *ehci,
  383. uint32_t regs, __u32 test_mode)
  384. {
  385. printf("regs: 0x%x\n", regs);
  386. ehci_set_interrupt_enable(ehci, regs, 0x00);
  387. ehci_disable_periodic_schedule(ehci, regs);
  388. ehci_disable_async_schedule(ehci, regs);
  389. ehci_set_config_flag(ehci, regs);
  390. ehci_test_stop(ehci, regs);
  391. ehci_test_reset(ehci, regs);
  392. /* Wait until EHCI reset complete. */
  393. while (!ehci_test_reset_complete(ehci, regs))
  394. ;
  395. if (!ehci_is_halt(ehci, regs)) {
  396. DMSG_ERR("%s_%d\n", __func__, __LINE__);
  397. }
  398. ehci_start(ehci, regs);
  399. /* Wait until EHCI to be not halt. */
  400. while (ehci_is_halt(ehci, regs))
  401. DMSG_ERR("%s_%d\n", __func__, __LINE__);
  402. ;
  403. /* Ehci start, config to test. */
  404. ehci_set_config_flag(ehci, regs);
  405. ehci_port_control(ehci, regs, 0, EHCI_PORTSC_POWER);
  406. ehci_disable_periodic_schedule(ehci, regs);
  407. ehci_disable_async_schedule(ehci, regs);
  408. /* Put port suspend. */
  409. ehci_put_port_suspend(ehci, regs);
  410. ehci_test_stop(ehci, regs);
  411. while ((!ehci_is_halt(ehci, regs)))
  412. DMSG_ERR("%s_%d\n", __func__, __LINE__);
  413. ;
  414. /* Test pack. */
  415. DMSG_INFO("Start Host Test,mode:0x%x!\n", test_mode);
  416. ehci_test_mode(ehci, regs, test_mode);
  417. DMSG_INFO("End Host Test,mode:0x%x!\n", test_mode);
  418. }
  419. unsigned int ehci_ed_test(int hci_num, const char *buf, unsigned int count)
  420. {
  421. __u32 test_mode = 0;
  422. struct sunxi_hci_hcd *sunxi_ehci = &g_sunxi_ehci[hci_num];
  423. struct hc_gen_dev *hcd = sunxi_ehci->hcd;
  424. struct ehci_hcd *ehci = NULL;
  425. ehci = hcd_to_ehci(hcd);
  426. if (ehci == NULL) {
  427. DMSG_PANIC("ERR: ehci is null\n");
  428. return 0;
  429. }
  430. DMSG_INFO("ehci_ed_test:%s\n", buf);
  431. if (!strncmp(buf, "test_not_operating", 18)) {
  432. test_mode = EHCI_PORTSC_PTC_DIS;
  433. DMSG_INFO("test_mode:0x%x\n", test_mode);
  434. } else if (!strncmp(buf, "test_j_state", 12)) {
  435. test_mode = EHCI_PORTSC_PTC_J;
  436. DMSG_INFO("test_mode:0x%x\n", test_mode);
  437. } else if (!strncmp(buf, "test_k_state", 12)) {
  438. test_mode = EHCI_PORTSC_PTC_K;
  439. DMSG_INFO("test_mode:0x%x\n", test_mode);
  440. } else if (!strncmp(buf, "test_se0_nak", 12)) {
  441. test_mode = EHCI_PORTSC_PTC_SE0NAK;
  442. DMSG_INFO("test_mode:0x%x\n", test_mode);
  443. } else if (!strncmp(buf, "test_pack", 9)) {
  444. test_mode = EHCI_PORTSC_PTC_PACKET;
  445. DMSG_INFO("test_mode:0x%x\n", test_mode);
  446. } else if (!strncmp(buf, "test_force_enable", 17)) {
  447. test_mode = EHCI_PORTSC_PTC_FORCE;
  448. DMSG_INFO("test_mode:0x%x\n", test_mode);
  449. } else if (!strncmp(buf, "test_mask", 9)) {
  450. test_mode = EHCI_PORTSC_PTC_MASK;
  451. DMSG_INFO("test_mode:0x%x\n", test_mode);
  452. } else {
  453. DMSG_PANIC("ERR: test_mode Argment is invalid\n");
  454. return count;
  455. }
  456. printf("regs: 0x%x\n", sunxi_ehci->usb_vbase);
  457. __ehci_ed_test(ehci, sunxi_ehci->usb_vbase, test_mode);
  458. return count;
  459. }
  460. unsigned int ehci_usb_driverlevel_adjust(int hci_num, int driverlevel)
  461. {
  462. struct sunxi_hci_hcd *sunxi_ehci = &g_sunxi_ehci[hci_num];
  463. usb_new_phy_adjust(sunxi_ehci, driverlevel);
  464. return 0;
  465. }