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