host.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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 <[email protected]>
  9. * Pawel Laszczak <[email protected]>
  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. #define XECP_PORT_CAP_REG 0x8000
  20. #define XECP_AUX_CTRL_REG1 0x8120
  21. #define CFG_RXDET_P3_EN BIT(15)
  22. #define LPM_2_STB_SWITCH_EN BIT(25)
  23. static void xhci_cdns3_plat_start(struct usb_hcd *hcd)
  24. {
  25. struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  26. u32 value;
  27. /* set usbcmd.EU3S */
  28. value = readl(&xhci->op_regs->command);
  29. value |= CMD_PM_INDEX;
  30. writel(value, &xhci->op_regs->command);
  31. if (hcd->regs) {
  32. value = readl(hcd->regs + XECP_AUX_CTRL_REG1);
  33. value |= CFG_RXDET_P3_EN;
  34. writel(value, hcd->regs + XECP_AUX_CTRL_REG1);
  35. value = readl(hcd->regs + XECP_PORT_CAP_REG);
  36. value |= LPM_2_STB_SWITCH_EN;
  37. writel(value, hcd->regs + XECP_PORT_CAP_REG);
  38. }
  39. }
  40. static int xhci_cdns3_resume_quirk(struct usb_hcd *hcd)
  41. {
  42. xhci_cdns3_plat_start(hcd);
  43. return 0;
  44. }
  45. static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
  46. .quirks = XHCI_SKIP_PHY_INIT | XHCI_AVOID_BEI,
  47. .plat_start = xhci_cdns3_plat_start,
  48. .resume_quirk = xhci_cdns3_resume_quirk,
  49. };
  50. static int __cdns_host_init(struct cdns *cdns)
  51. {
  52. struct platform_device *xhci;
  53. int ret;
  54. struct usb_hcd *hcd;
  55. cdns_drd_host_on(cdns);
  56. xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
  57. if (!xhci) {
  58. dev_err(cdns->dev, "couldn't allocate xHCI device\n");
  59. return -ENOMEM;
  60. }
  61. xhci->dev.parent = cdns->dev;
  62. cdns->host_dev = xhci;
  63. ret = platform_device_add_resources(xhci, cdns->xhci_res,
  64. CDNS_XHCI_RESOURCES_NUM);
  65. if (ret) {
  66. dev_err(cdns->dev, "couldn't add resources to xHCI device\n");
  67. goto err1;
  68. }
  69. cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
  70. sizeof(struct xhci_plat_priv), GFP_KERNEL);
  71. if (!cdns->xhci_plat_data) {
  72. ret = -ENOMEM;
  73. goto err1;
  74. }
  75. if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))
  76. cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
  77. ret = platform_device_add_data(xhci, cdns->xhci_plat_data,
  78. sizeof(struct xhci_plat_priv));
  79. if (ret)
  80. goto free_memory;
  81. ret = platform_device_add(xhci);
  82. if (ret) {
  83. dev_err(cdns->dev, "failed to register xHCI device\n");
  84. goto free_memory;
  85. }
  86. /* Glue needs to access xHCI region register for Power management */
  87. hcd = platform_get_drvdata(xhci);
  88. if (hcd)
  89. cdns->xhci_regs = hcd->regs;
  90. return 0;
  91. free_memory:
  92. kfree(cdns->xhci_plat_data);
  93. err1:
  94. platform_device_put(xhci);
  95. return ret;
  96. }
  97. static void cdns_host_exit(struct cdns *cdns)
  98. {
  99. kfree(cdns->xhci_plat_data);
  100. platform_device_unregister(cdns->host_dev);
  101. cdns->host_dev = NULL;
  102. cdns_drd_host_off(cdns);
  103. }
  104. int cdns_host_init(struct cdns *cdns)
  105. {
  106. struct cdns_role_driver *rdrv;
  107. rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
  108. if (!rdrv)
  109. return -ENOMEM;
  110. rdrv->start = __cdns_host_init;
  111. rdrv->stop = cdns_host_exit;
  112. rdrv->state = CDNS_ROLE_STATE_INACTIVE;
  113. rdrv->name = "host";
  114. cdns->roles[USB_ROLE_HOST] = rdrv;
  115. return 0;
  116. }