ehci-brcm.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2020, Broadcom */
  3. #include <linux/clk.h>
  4. #include <linux/dma-mapping.h>
  5. #include <linux/err.h>
  6. #include <linux/kernel.h>
  7. #include <linux/io.h>
  8. #include <linux/module.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/usb.h>
  11. #include <linux/usb/hcd.h>
  12. #include <linux/iopoll.h>
  13. #include "ehci.h"
  14. #define hcd_to_ehci_priv(h) ((struct brcm_priv *)hcd_to_ehci(h)->priv)
  15. struct brcm_priv {
  16. struct clk *clk;
  17. };
  18. /*
  19. * ehci_brcm_wait_for_sof
  20. * Wait for start of next microframe, then wait extra delay microseconds
  21. */
  22. static inline void ehci_brcm_wait_for_sof(struct ehci_hcd *ehci, u32 delay)
  23. {
  24. u32 frame_idx = ehci_readl(ehci, &ehci->regs->frame_index);
  25. u32 val;
  26. int res;
  27. /* Wait for next microframe (every 125 usecs) */
  28. res = readl_relaxed_poll_timeout(&ehci->regs->frame_index, val,
  29. val != frame_idx, 1, 130);
  30. if (res)
  31. ehci_err(ehci, "Error waiting for SOF\n");
  32. udelay(delay);
  33. }
  34. /*
  35. * ehci_brcm_hub_control
  36. * The EHCI controller has a bug where it can violate the SOF
  37. * interval between the first two SOF's transmitted after resume
  38. * if the resume occurs near the end of the microframe. This causees
  39. * the controller to detect babble on the suspended port and
  40. * will eventually cause the controller to reset the port.
  41. * The fix is to Intercept the echi-hcd request to complete RESUME and
  42. * align it to the start of the next microframe.
  43. * See SWLINUX-1909 for more details
  44. */
  45. static int ehci_brcm_hub_control(
  46. struct usb_hcd *hcd,
  47. u16 typeReq,
  48. u16 wValue,
  49. u16 wIndex,
  50. char *buf,
  51. u16 wLength)
  52. {
  53. struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  54. int ports = HCS_N_PORTS(ehci->hcs_params);
  55. u32 __iomem *status_reg;
  56. unsigned long flags;
  57. int retval, irq_disabled = 0;
  58. u32 temp;
  59. temp = (wIndex & 0xff) - 1;
  60. if (temp >= HCS_N_PORTS_MAX) /* Avoid index-out-of-bounds warning */
  61. temp = 0;
  62. status_reg = &ehci->regs->port_status[temp];
  63. /*
  64. * RESUME is cleared when GetPortStatus() is called 20ms after start
  65. * of RESUME
  66. */
  67. if ((typeReq == GetPortStatus) &&
  68. (wIndex && wIndex <= ports) &&
  69. ehci->reset_done[wIndex-1] &&
  70. time_after_eq(jiffies, ehci->reset_done[wIndex-1]) &&
  71. (ehci_readl(ehci, status_reg) & PORT_RESUME)) {
  72. /*
  73. * to make sure we are not interrupted until RESUME bit
  74. * is cleared, disable interrupts on current CPU
  75. */
  76. ehci_dbg(ehci, "SOF alignment workaround\n");
  77. irq_disabled = 1;
  78. local_irq_save(flags);
  79. ehci_brcm_wait_for_sof(ehci, 5);
  80. }
  81. retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
  82. if (irq_disabled)
  83. local_irq_restore(flags);
  84. return retval;
  85. }
  86. static int ehci_brcm_reset(struct usb_hcd *hcd)
  87. {
  88. struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  89. int len;
  90. ehci->big_endian_mmio = 1;
  91. ehci->caps = (void __iomem *)hcd->regs;
  92. len = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
  93. ehci->regs = (void __iomem *)(hcd->regs + len);
  94. /* This fixes the lockup during reboot due to prior interrupts */
  95. ehci_writel(ehci, CMD_RESET, &ehci->regs->command);
  96. mdelay(10);
  97. /*
  98. * SWLINUX-1705: Avoid OUT packet underflows during high memory
  99. * bus usage
  100. */
  101. ehci_writel(ehci, 0x00800040, &ehci->regs->brcm_insnreg[1]);
  102. ehci_writel(ehci, 0x00000001, &ehci->regs->brcm_insnreg[3]);
  103. return ehci_setup(hcd);
  104. }
  105. static struct hc_driver __read_mostly ehci_brcm_hc_driver;
  106. static const struct ehci_driver_overrides brcm_overrides __initconst = {
  107. .reset = ehci_brcm_reset,
  108. .extra_priv_size = sizeof(struct brcm_priv),
  109. };
  110. static int ehci_brcm_probe(struct platform_device *pdev)
  111. {
  112. struct device *dev = &pdev->dev;
  113. struct resource *res_mem;
  114. struct brcm_priv *priv;
  115. struct usb_hcd *hcd;
  116. int irq;
  117. int err;
  118. err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
  119. if (err)
  120. return err;
  121. irq = platform_get_irq(pdev, 0);
  122. if (irq <= 0)
  123. return irq ? irq : -EINVAL;
  124. /* Hook the hub control routine to work around a bug */
  125. ehci_brcm_hc_driver.hub_control = ehci_brcm_hub_control;
  126. /* initialize hcd */
  127. hcd = usb_create_hcd(&ehci_brcm_hc_driver, dev, dev_name(dev));
  128. if (!hcd)
  129. return -ENOMEM;
  130. platform_set_drvdata(pdev, hcd);
  131. priv = hcd_to_ehci_priv(hcd);
  132. priv->clk = devm_clk_get_optional(dev, NULL);
  133. if (IS_ERR(priv->clk)) {
  134. err = PTR_ERR(priv->clk);
  135. goto err_hcd;
  136. }
  137. err = clk_prepare_enable(priv->clk);
  138. if (err)
  139. goto err_hcd;
  140. hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res_mem);
  141. if (IS_ERR(hcd->regs)) {
  142. err = PTR_ERR(hcd->regs);
  143. goto err_clk;
  144. }
  145. hcd->rsrc_start = res_mem->start;
  146. hcd->rsrc_len = resource_size(res_mem);
  147. err = usb_add_hcd(hcd, irq, IRQF_SHARED);
  148. if (err)
  149. goto err_clk;
  150. device_wakeup_enable(hcd->self.controller);
  151. device_enable_async_suspend(hcd->self.controller);
  152. return 0;
  153. err_clk:
  154. clk_disable_unprepare(priv->clk);
  155. err_hcd:
  156. usb_put_hcd(hcd);
  157. return err;
  158. }
  159. static int ehci_brcm_remove(struct platform_device *dev)
  160. {
  161. struct usb_hcd *hcd = platform_get_drvdata(dev);
  162. struct brcm_priv *priv = hcd_to_ehci_priv(hcd);
  163. usb_remove_hcd(hcd);
  164. clk_disable_unprepare(priv->clk);
  165. usb_put_hcd(hcd);
  166. return 0;
  167. }
  168. static int __maybe_unused ehci_brcm_suspend(struct device *dev)
  169. {
  170. int ret;
  171. struct usb_hcd *hcd = dev_get_drvdata(dev);
  172. struct brcm_priv *priv = hcd_to_ehci_priv(hcd);
  173. bool do_wakeup = device_may_wakeup(dev);
  174. ret = ehci_suspend(hcd, do_wakeup);
  175. if (ret)
  176. return ret;
  177. clk_disable_unprepare(priv->clk);
  178. return 0;
  179. }
  180. static int __maybe_unused ehci_brcm_resume(struct device *dev)
  181. {
  182. struct usb_hcd *hcd = dev_get_drvdata(dev);
  183. struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  184. struct brcm_priv *priv = hcd_to_ehci_priv(hcd);
  185. int err;
  186. err = clk_prepare_enable(priv->clk);
  187. if (err)
  188. return err;
  189. /*
  190. * SWLINUX-1705: Avoid OUT packet underflows during high memory
  191. * bus usage
  192. */
  193. ehci_writel(ehci, 0x00800040, &ehci->regs->brcm_insnreg[1]);
  194. ehci_writel(ehci, 0x00000001, &ehci->regs->brcm_insnreg[3]);
  195. ehci_resume(hcd, false);
  196. pm_runtime_disable(dev);
  197. pm_runtime_set_active(dev);
  198. pm_runtime_enable(dev);
  199. return 0;
  200. }
  201. static SIMPLE_DEV_PM_OPS(ehci_brcm_pm_ops, ehci_brcm_suspend,
  202. ehci_brcm_resume);
  203. static const struct of_device_id brcm_ehci_of_match[] = {
  204. { .compatible = "brcm,ehci-brcm-v2", },
  205. { .compatible = "brcm,bcm7445-ehci", },
  206. {}
  207. };
  208. static struct platform_driver ehci_brcm_driver = {
  209. .probe = ehci_brcm_probe,
  210. .remove = ehci_brcm_remove,
  211. .shutdown = usb_hcd_platform_shutdown,
  212. .driver = {
  213. .name = "ehci-brcm",
  214. .pm = &ehci_brcm_pm_ops,
  215. .of_match_table = brcm_ehci_of_match,
  216. }
  217. };
  218. static int __init ehci_brcm_init(void)
  219. {
  220. if (usb_disabled())
  221. return -ENODEV;
  222. ehci_init_driver(&ehci_brcm_hc_driver, &brcm_overrides);
  223. return platform_driver_register(&ehci_brcm_driver);
  224. }
  225. module_init(ehci_brcm_init);
  226. static void __exit ehci_brcm_exit(void)
  227. {
  228. platform_driver_unregister(&ehci_brcm_driver);
  229. }
  230. module_exit(ehci_brcm_exit);
  231. MODULE_ALIAS("platform:ehci-brcm");
  232. MODULE_DESCRIPTION("EHCI Broadcom STB driver");
  233. MODULE_AUTHOR("Al Cooper");
  234. MODULE_LICENSE("GPL");