mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-17 16:14:25 +08:00
9af21dd6fa
Synopsys introduces a new controller DWC_usb32. It supports dual-lane and speed up to 20 Gbps, and the DWC3 driver will drive this controller. Currently the driver uses a single field dwc->revision to ID both DWC_usb3 and DWC_usb31 and their version number. This was sufficient for two IPs, but this method doesn't work with additional IPs. As a result, let's separate the dwc->revision field to 2 separate fields: ip and revision. The ip field now stores the ID of the controller's IP while the revision field stores the controller's version number. This new scheme enforces DWC3 to compare the revision within the same IP only. As a result, we must update all the revision check of the controller to check its corresponding IP. To help with this enforcement, we create a few macros to help with the common version checks: DWC3_IP_IS(IP) DWC3_VER_IS(IP, VERSION) DWC3_VER_IS_PRIOR(IP, VERSION) DWC3_VER_IS_WITHIN(IP, LOWER_VERSION, UPPER_VERSION) DWC3_VER_TYPE_IS_WITHIN(IP, VERSION, LOWER_VERSION_TYPE, UPPER_VERSION_TYPE) The DWC_usb32 controller operates using the same programming model and with very similar configurations as its previous controllers. Please note that the various IP and revision checks in this patch match the current checks for DWC_usb31 version 1.90a. Additional configurations that are unique to DWC_usb32 are applied separately. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
134 lines
2.9 KiB
C
134 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* host.c - DesignWare USB3 DRD Controller Host Glue
|
|
*
|
|
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
|
|
*
|
|
* Authors: Felipe Balbi <balbi@ti.com>,
|
|
*/
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include "core.h"
|
|
|
|
static int dwc3_host_get_irq(struct dwc3 *dwc)
|
|
{
|
|
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
|
|
int irq;
|
|
|
|
irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
|
|
if (irq > 0)
|
|
goto out;
|
|
|
|
if (irq == -EPROBE_DEFER)
|
|
goto out;
|
|
|
|
irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
|
|
if (irq > 0)
|
|
goto out;
|
|
|
|
if (irq == -EPROBE_DEFER)
|
|
goto out;
|
|
|
|
irq = platform_get_irq(dwc3_pdev, 0);
|
|
if (irq > 0)
|
|
goto out;
|
|
|
|
if (!irq)
|
|
irq = -EINVAL;
|
|
|
|
out:
|
|
return irq;
|
|
}
|
|
|
|
int dwc3_host_init(struct dwc3 *dwc)
|
|
{
|
|
struct property_entry props[4];
|
|
struct platform_device *xhci;
|
|
int ret, irq;
|
|
struct resource *res;
|
|
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
|
|
int prop_idx = 0;
|
|
|
|
irq = dwc3_host_get_irq(dwc);
|
|
if (irq < 0)
|
|
return irq;
|
|
|
|
res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host");
|
|
if (!res)
|
|
res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
|
|
"dwc_usb3");
|
|
if (!res)
|
|
res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0);
|
|
if (!res)
|
|
return -ENOMEM;
|
|
|
|
dwc->xhci_resources[1].start = irq;
|
|
dwc->xhci_resources[1].end = irq;
|
|
dwc->xhci_resources[1].flags = res->flags;
|
|
dwc->xhci_resources[1].name = res->name;
|
|
|
|
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
|
|
if (!xhci) {
|
|
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
xhci->dev.parent = dwc->dev;
|
|
ACPI_COMPANION_SET(&xhci->dev, ACPI_COMPANION(dwc->dev));
|
|
|
|
dwc->xhci = xhci;
|
|
|
|
ret = platform_device_add_resources(xhci, dwc->xhci_resources,
|
|
DWC3_XHCI_RESOURCES_NUM);
|
|
if (ret) {
|
|
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
|
|
goto err;
|
|
}
|
|
|
|
memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
|
|
|
|
if (dwc->usb3_lpm_capable)
|
|
props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable");
|
|
|
|
if (dwc->usb2_lpm_disable)
|
|
props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb2-lpm-disable");
|
|
|
|
/**
|
|
* WORKAROUND: dwc3 revisions <=3.00a have a limitation
|
|
* where Port Disable command doesn't work.
|
|
*
|
|
* The suggested workaround is that we avoid Port Disable
|
|
* completely.
|
|
*
|
|
* This following flag tells XHCI to do just that.
|
|
*/
|
|
if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A))
|
|
props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
|
|
|
|
if (prop_idx) {
|
|
ret = platform_device_add_properties(xhci, props);
|
|
if (ret) {
|
|
dev_err(dwc->dev, "failed to add properties to xHCI\n");
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
ret = platform_device_add(xhci);
|
|
if (ret) {
|
|
dev_err(dwc->dev, "failed to register xHCI device\n");
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
platform_device_put(xhci);
|
|
return ret;
|
|
}
|
|
|
|
void dwc3_host_exit(struct dwc3 *dwc)
|
|
{
|
|
platform_device_unregister(dwc->xhci);
|
|
}
|