18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * host.c - DesignWare USB3 DRD Controller Host Glue 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Felipe Balbi <balbi@ti.com>, 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/acpi.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "core.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int dwc3_host_get_irq(struct dwc3 *dwc) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); 188c2ecf20Sopenharmony_ci int irq; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci irq = platform_get_irq_byname_optional(dwc3_pdev, "host"); 218c2ecf20Sopenharmony_ci if (irq > 0) 228c2ecf20Sopenharmony_ci goto out; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (irq == -EPROBE_DEFER) 258c2ecf20Sopenharmony_ci goto out; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3"); 288c2ecf20Sopenharmony_ci if (irq > 0) 298c2ecf20Sopenharmony_ci goto out; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (irq == -EPROBE_DEFER) 328c2ecf20Sopenharmony_ci goto out; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci irq = platform_get_irq(dwc3_pdev, 0); 358c2ecf20Sopenharmony_ci if (irq > 0) 368c2ecf20Sopenharmony_ci goto out; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (!irq) 398c2ecf20Sopenharmony_ci irq = -EINVAL; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciout: 428c2ecf20Sopenharmony_ci return irq; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint dwc3_host_init(struct dwc3 *dwc) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct property_entry props[4]; 488c2ecf20Sopenharmony_ci struct platform_device *xhci; 498c2ecf20Sopenharmony_ci int ret, irq; 508c2ecf20Sopenharmony_ci struct resource *res; 518c2ecf20Sopenharmony_ci struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); 528c2ecf20Sopenharmony_ci int prop_idx = 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci irq = dwc3_host_get_irq(dwc); 558c2ecf20Sopenharmony_ci if (irq < 0) 568c2ecf20Sopenharmony_ci return irq; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host"); 598c2ecf20Sopenharmony_ci if (!res) 608c2ecf20Sopenharmony_ci res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, 618c2ecf20Sopenharmony_ci "dwc_usb3"); 628c2ecf20Sopenharmony_ci if (!res) 638c2ecf20Sopenharmony_ci res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0); 648c2ecf20Sopenharmony_ci if (!res) 658c2ecf20Sopenharmony_ci return -ENOMEM; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci dwc->xhci_resources[1].start = irq; 688c2ecf20Sopenharmony_ci dwc->xhci_resources[1].end = irq; 698c2ecf20Sopenharmony_ci dwc->xhci_resources[1].flags = res->flags; 708c2ecf20Sopenharmony_ci dwc->xhci_resources[1].name = res->name; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); 738c2ecf20Sopenharmony_ci if (!xhci) { 748c2ecf20Sopenharmony_ci dev_err(dwc->dev, "couldn't allocate xHCI device\n"); 758c2ecf20Sopenharmony_ci return -ENOMEM; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci xhci->dev.parent = dwc->dev; 798c2ecf20Sopenharmony_ci ACPI_COMPANION_SET(&xhci->dev, ACPI_COMPANION(dwc->dev)); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci dwc->xhci = xhci; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ret = platform_device_add_resources(xhci, dwc->xhci_resources, 848c2ecf20Sopenharmony_ci DWC3_XHCI_RESOURCES_NUM); 858c2ecf20Sopenharmony_ci if (ret) { 868c2ecf20Sopenharmony_ci dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); 878c2ecf20Sopenharmony_ci goto err; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (dwc->usb3_lpm_capable) 938c2ecf20Sopenharmony_ci props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable"); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (dwc->usb2_lpm_disable) 968c2ecf20Sopenharmony_ci props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb2-lpm-disable"); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /** 998c2ecf20Sopenharmony_ci * WORKAROUND: dwc3 revisions <=3.00a have a limitation 1008c2ecf20Sopenharmony_ci * where Port Disable command doesn't work. 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * The suggested workaround is that we avoid Port Disable 1038c2ecf20Sopenharmony_ci * completely. 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * This following flag tells XHCI to do just that. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A)) 1088c2ecf20Sopenharmony_ci props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped"); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (prop_idx) { 1118c2ecf20Sopenharmony_ci ret = platform_device_add_properties(xhci, props); 1128c2ecf20Sopenharmony_ci if (ret) { 1138c2ecf20Sopenharmony_ci dev_err(dwc->dev, "failed to add properties to xHCI\n"); 1148c2ecf20Sopenharmony_ci goto err; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ret = platform_device_add(xhci); 1198c2ecf20Sopenharmony_ci if (ret) { 1208c2ecf20Sopenharmony_ci dev_err(dwc->dev, "failed to register xHCI device\n"); 1218c2ecf20Sopenharmony_ci goto err; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_cierr: 1268c2ecf20Sopenharmony_ci platform_device_put(xhci); 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_civoid dwc3_host_exit(struct dwc3 *dwc) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci platform_device_unregister(dwc->xhci); 1338c2ecf20Sopenharmony_ci dwc->xhci = NULL; 1348c2ecf20Sopenharmony_ci} 135