host.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Cadence USBSS and USBSSP DRD Driver - host side
  4. *
  5. * Copyright (C) 2018-2019 Cadence Design Systems.
  6. * Copyright (C) 2017-2018 NXP
  7. *
  8. * Authors: Peter Chen <peter.chen@nxp.com>
  9. * Pawel Laszczak <pawell@cadence.com>
  10. */
  11. #include <linux/platform_device.h>
  12. #include <linux/slab.h>
  13. #include "core.h"
  14. #include "drd.h"
  15. #include "host-export.h"
  16. #include <linux/usb/hcd.h>
  17. #include "../host/xhci.h"
  18. #include "../host/xhci-plat.h"
  19. /*
  20. * The XECP_PORT_CAP_REG and XECP_AUX_CTRL_REG1 exist only
  21. * in Cadence USB3 dual-role controller, so it can't be used
  22. * with Cadence CDNSP dual-role controller.
  23. */
  24. #define XECP_PORT_CAP_REG 0x8000
  25. #define XECP_AUX_CTRL_REG1 0x8120
  26. #define CFG_RXDET_P3_EN BIT(15)
  27. #define LPM_2_STB_SWITCH_EN BIT(25)
  28. static void xhci_cdns3_plat_start(struct usb_hcd *hcd)
  29. {
  30. struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  31. u32 value;
  32. /* set usbcmd.EU3S */
  33. value = readl(&xhci->op_regs->command);
  34. value |= CMD_PM_INDEX;
  35. writel(value, &xhci->op_regs->command);
  36. if (hcd->regs) {
  37. value = readl(hcd->regs + XECP_AUX_CTRL_REG1);
  38. value |= CFG_RXDET_P3_EN;
  39. writel(value, hcd->regs + XECP_AUX_CTRL_REG1);
  40. value = readl(hcd->regs + XECP_PORT_CAP_REG);
  41. value |= LPM_2_STB_SWITCH_EN;
  42. writel(value, hcd->regs + XECP_PORT_CAP_REG);
  43. }
  44. }
  45. static int xhci_cdns3_resume_quirk(struct usb_hcd *hcd)
  46. {
  47. xhci_cdns3_plat_start(hcd);
  48. return 0;
  49. }
  50. static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
  51. .quirks = XHCI_SKIP_PHY_INIT | XHCI_AVOID_BEI,
  52. .plat_start = xhci_cdns3_plat_start,
  53. .resume_quirk = xhci_cdns3_resume_quirk,
  54. };
  55. static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
  56. .quirks = XHCI_CDNS_SCTX_QUIRK,
  57. };
  58. static int __cdns_host_init(struct cdns *cdns)
  59. {
  60. struct platform_device *xhci;
  61. int ret;
  62. struct usb_hcd *hcd;
  63. cdns_drd_host_on(cdns);
  64. xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
  65. if (!xhci) {
  66. dev_err(cdns->dev, "couldn't allocate xHCI device\n");
  67. return -ENOMEM;
  68. }
  69. xhci->dev.parent = cdns->dev;
  70. cdns->host_dev = xhci;
  71. ret = platform_device_add_resources(xhci, cdns->xhci_res,
  72. CDNS_XHCI_RESOURCES_NUM);
  73. if (ret) {
  74. dev_err(cdns->dev, "couldn't add resources to xHCI device\n");
  75. goto err1;
  76. }
  77. if (cdns->version < CDNSP_CONTROLLER_V2)
  78. cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
  79. sizeof(struct xhci_plat_priv), GFP_KERNEL);
  80. else
  81. cdns->xhci_plat_data = kmemdup(&xhci_plat_cdnsp_xhci,
  82. sizeof(struct xhci_plat_priv), GFP_KERNEL);
  83. if (!cdns->xhci_plat_data) {
  84. ret = -ENOMEM;
  85. goto err1;
  86. }
  87. if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))
  88. cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
  89. ret = platform_device_add_data(xhci, cdns->xhci_plat_data,
  90. sizeof(struct xhci_plat_priv));
  91. if (ret)
  92. goto free_memory;
  93. ret = platform_device_add(xhci);
  94. if (ret) {
  95. dev_err(cdns->dev, "failed to register xHCI device\n");
  96. goto free_memory;
  97. }
  98. /* Glue needs to access xHCI region register for Power management */
  99. hcd = platform_get_drvdata(xhci);
  100. if (hcd)
  101. cdns->xhci_regs = hcd->regs;
  102. return 0;
  103. free_memory:
  104. kfree(cdns->xhci_plat_data);
  105. err1:
  106. platform_device_put(xhci);
  107. return ret;
  108. }
  109. static void cdns_host_exit(struct cdns *cdns)
  110. {
  111. kfree(cdns->xhci_plat_data);
  112. platform_device_unregister(cdns->host_dev);
  113. cdns->host_dev = NULL;
  114. cdns_drd_host_off(cdns);
  115. }
  116. int cdns_host_init(struct cdns *cdns)
  117. {
  118. struct cdns_role_driver *rdrv;
  119. rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
  120. if (!rdrv)
  121. return -ENOMEM;
  122. rdrv->start = __cdns_host_init;
  123. rdrv->stop = cdns_host_exit;
  124. rdrv->state = CDNS_ROLE_STATE_INACTIVE;
  125. rdrv->name = "host";
  126. cdns->roles[USB_ROLE_HOST] = rdrv;
  127. return 0;
  128. }