ehci-msm.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Qualcomm EHCI driver
  4. *
  5. * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
  6. *
  7. * Based on Linux driver
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <errno.h>
  12. #include <fdtdec.h>
  13. #include <linux/libfdt.h>
  14. #include <usb.h>
  15. #include <usb/ehci-ci.h>
  16. #include <usb/ulpi.h>
  17. #include <wait_bit.h>
  18. #include <asm/gpio.h>
  19. #include <asm/io.h>
  20. #include <linux/compat.h>
  21. #include "ehci.h"
  22. /* PHY viewport regs */
  23. #define ULPI_MISC_A_READ 0x96
  24. #define ULPI_MISC_A_SET 0x97
  25. #define ULPI_MISC_A_CLEAR 0x98
  26. #define ULPI_MISC_A_VBUSVLDEXTSEL (1 << 1)
  27. #define ULPI_MISC_A_VBUSVLDEXT (1 << 0)
  28. #define GEN2_SESS_VLD_CTRL_EN (1 << 7)
  29. #define SESS_VLD_CTRL (1 << 25)
  30. struct msm_ehci_priv {
  31. struct ehci_ctrl ctrl; /* Needed by EHCI */
  32. struct usb_ehci *ehci; /* Start of IP core*/
  33. struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
  34. };
  35. int __weak board_prepare_usb(enum usb_init_type type)
  36. {
  37. return 0;
  38. }
  39. static void setup_usb_phy(struct msm_ehci_priv *priv)
  40. {
  41. /* Select and enable external configuration with USB PHY */
  42. ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_SET,
  43. ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
  44. }
  45. static void reset_usb_phy(struct msm_ehci_priv *priv)
  46. {
  47. /* Disable VBUS mimicing in the controller. */
  48. ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,
  49. ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
  50. }
  51. static int msm_init_after_reset(struct ehci_ctrl *dev)
  52. {
  53. struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
  54. struct usb_ehci *ehci = p->ehci;
  55. /* select ULPI phy */
  56. writel(PORT_PTS_ULPI, &ehci->portsc);
  57. setup_usb_phy(p);
  58. /* Enable sess_vld */
  59. setbits_le32(&ehci->genconfig2, GEN2_SESS_VLD_CTRL_EN);
  60. /* Enable external vbus configuration in the LINK */
  61. setbits_le32(&ehci->usbcmd, SESS_VLD_CTRL);
  62. /* USB_OTG_HS_AHB_BURST */
  63. writel(0x0, &ehci->sbuscfg);
  64. /* USB_OTG_HS_AHB_MODE: HPROT_MODE */
  65. /* Bus access related config. */
  66. writel(0x08, &ehci->sbusmode);
  67. /* set mode to host controller */
  68. writel(CM_HOST, &ehci->usbmode);
  69. return 0;
  70. }
  71. static const struct ehci_ops msm_ehci_ops = {
  72. .init_after_reset = msm_init_after_reset
  73. };
  74. static int ehci_usb_probe(struct udevice *dev)
  75. {
  76. struct msm_ehci_priv *p = dev_get_priv(dev);
  77. struct usb_ehci *ehci = p->ehci;
  78. struct ehci_hccr *hccr;
  79. struct ehci_hcor *hcor;
  80. int ret;
  81. hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
  82. hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
  83. HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
  84. ret = board_prepare_usb(USB_INIT_HOST);
  85. if (ret < 0)
  86. return ret;
  87. return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, USB_INIT_HOST);
  88. }
  89. static int ehci_usb_remove(struct udevice *dev)
  90. {
  91. struct msm_ehci_priv *p = dev_get_priv(dev);
  92. struct usb_ehci *ehci = p->ehci;
  93. int ret;
  94. ret = ehci_deregister(dev);
  95. if (ret)
  96. return ret;
  97. /* Stop controller. */
  98. clrbits_le32(&ehci->usbcmd, CMD_RUN);
  99. reset_usb_phy(p);
  100. ret = board_prepare_usb(USB_INIT_DEVICE); /* Board specific hook */
  101. if (ret < 0)
  102. return ret;
  103. /* Reset controller */
  104. setbits_le32(&ehci->usbcmd, CMD_RESET);
  105. /* Wait for reset */
  106. if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
  107. printf("Stuck on USB reset.\n");
  108. return -ETIMEDOUT;
  109. }
  110. return 0;
  111. }
  112. static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
  113. {
  114. struct msm_ehci_priv *priv = dev_get_priv(dev);
  115. priv->ulpi_vp.port_num = 0;
  116. priv->ehci = (void *)devfdt_get_addr(dev);
  117. if (priv->ehci == (void *)FDT_ADDR_T_NONE)
  118. return -EINVAL;
  119. /* Warning: this will not work if viewport address is > 64 bit due to
  120. * ULPI design.
  121. */
  122. priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
  123. return 0;
  124. }
  125. static const struct udevice_id ehci_usb_ids[] = {
  126. { .compatible = "qcom,ehci-host", },
  127. { }
  128. };
  129. U_BOOT_DRIVER(usb_ehci) = {
  130. .name = "ehci_msm",
  131. .id = UCLASS_USB,
  132. .of_match = ehci_usb_ids,
  133. .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
  134. .probe = ehci_usb_probe,
  135. .remove = ehci_usb_remove,
  136. .ops = &ehci_usb_ops,
  137. .priv_auto_alloc_size = sizeof(struct msm_ehci_priv),
  138. .flags = DM_FLAG_ALLOC_PRIV_DMA,
  139. };