^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) * host.c - DesignWare USB3 DRD Controller Host Glue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Authors: Felipe Balbi <balbi@ti.com>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) static int dwc3_host_get_irq(struct dwc3 *dwc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) if (irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (irq == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) if (irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (irq == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) irq = platform_get_irq(dwc3_pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) irq = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return irq;
^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) int dwc3_host_init(struct dwc3 *dwc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct property_entry props[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct platform_device *xhci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int ret, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int prop_idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) irq = dwc3_host_get_irq(dwc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) "dwc_usb3");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) dwc->xhci_resources[1].start = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) dwc->xhci_resources[1].end = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) dwc->xhci_resources[1].flags = res->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) dwc->xhci_resources[1].name = res->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (!xhci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) dev_err(dwc->dev, "couldn't allocate xHCI device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) xhci->dev.parent = dwc->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ACPI_COMPANION_SET(&xhci->dev, ACPI_COMPANION(dwc->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) dwc->xhci = xhci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ret = platform_device_add_resources(xhci, dwc->xhci_resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) DWC3_XHCI_RESOURCES_NUM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) goto err;
^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) memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (dwc->usb3_lpm_capable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (dwc->usb2_lpm_disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb2-lpm-disable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * WORKAROUND: dwc3 revisions <=3.00a have a limitation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * where Port Disable command doesn't work.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * The suggested workaround is that we avoid Port Disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * completely.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * This following flag tells XHCI to do just that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!dwc->dis_u2_susphy_quirk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-u2-broken-suspend");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (prop_idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ret = platform_device_add_properties(xhci, props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) dev_err(dwc->dev, "failed to add properties to xHCI\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ret = platform_device_add(xhci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) dev_err(dwc->dev, "failed to register xHCI device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) platform_device_put(xhci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) void dwc3_host_exit(struct dwc3 *dwc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) platform_device_unregister(dwc->xhci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }