18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * core.c - DesignWare USB3 DRD Controller Core file 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Felipe Balbi <balbi@ti.com>, 88c2ecf20Sopenharmony_ci * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/version.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/ioport.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/list.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 258c2ecf20Sopenharmony_ci#include <linux/of.h> 268c2ecf20Sopenharmony_ci#include <linux/acpi.h> 278c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 288c2ecf20Sopenharmony_ci#include <linux/reset.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h> 318c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h> 328c2ecf20Sopenharmony_ci#include <linux/usb/of.h> 338c2ecf20Sopenharmony_ci#include <linux/usb/otg.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "core.h" 368c2ecf20Sopenharmony_ci#include "gadget.h" 378c2ecf20Sopenharmony_ci#include "io.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "debug.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * dwc3_get_dr_mode - Validates and sets dr_mode 458c2ecf20Sopenharmony_ci * @dwc: pointer to our context structure 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic int dwc3_get_dr_mode(struct dwc3 *dwc) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci enum usb_dr_mode mode; 508c2ecf20Sopenharmony_ci struct device *dev = dwc->dev; 518c2ecf20Sopenharmony_ci unsigned int hw_mode; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) 548c2ecf20Sopenharmony_ci dwc->dr_mode = USB_DR_MODE_OTG; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci mode = dwc->dr_mode; 578c2ecf20Sopenharmony_ci hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci switch (hw_mode) { 608c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS0_MODE_GADGET: 618c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) { 628c2ecf20Sopenharmony_ci dev_err(dev, 638c2ecf20Sopenharmony_ci "Controller does not support host mode.\n"); 648c2ecf20Sopenharmony_ci return -EINVAL; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci mode = USB_DR_MODE_PERIPHERAL; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS0_MODE_HOST: 698c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { 708c2ecf20Sopenharmony_ci dev_err(dev, 718c2ecf20Sopenharmony_ci "Controller does not support device mode.\n"); 728c2ecf20Sopenharmony_ci return -EINVAL; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci mode = USB_DR_MODE_HOST; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci default: 778c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) 788c2ecf20Sopenharmony_ci mode = USB_DR_MODE_HOST; 798c2ecf20Sopenharmony_ci else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) 808c2ecf20Sopenharmony_ci mode = USB_DR_MODE_PERIPHERAL; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * DWC_usb31 and DWC_usb3 v3.30a and higher do not support OTG 848c2ecf20Sopenharmony_ci * mode. If the controller supports DRD but the dr_mode is not 858c2ecf20Sopenharmony_ci * specified or set to OTG, then set the mode to peripheral. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci if (mode == USB_DR_MODE_OTG && 888c2ecf20Sopenharmony_ci (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) || 898c2ecf20Sopenharmony_ci !device_property_read_bool(dwc->dev, "usb-role-switch")) && 908c2ecf20Sopenharmony_ci !DWC3_VER_IS_PRIOR(DWC3, 330A)) 918c2ecf20Sopenharmony_ci mode = USB_DR_MODE_PERIPHERAL; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (mode != dwc->dr_mode) { 958c2ecf20Sopenharmony_ci dev_warn(dev, 968c2ecf20Sopenharmony_ci "Configuration mismatch. dr_mode forced to %s\n", 978c2ecf20Sopenharmony_ci mode == USB_DR_MODE_HOST ? "host" : "gadget"); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dwc->dr_mode = mode; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_civoid dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci u32 reg; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GCTL); 1108c2ecf20Sopenharmony_ci reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); 1118c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_PRTCAPDIR(mode); 1128c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GCTL, reg); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci dwc->current_dr_role = mode; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void __dwc3_set_mode(struct work_struct *work) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct dwc3 *dwc = work_to_dwc(work); 1208c2ecf20Sopenharmony_ci unsigned long flags; 1218c2ecf20Sopenharmony_ci int ret; 1228c2ecf20Sopenharmony_ci u32 reg; 1238c2ecf20Sopenharmony_ci u32 desired_dr_role; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci mutex_lock(&dwc->mutex); 1268c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 1278c2ecf20Sopenharmony_ci desired_dr_role = dwc->desired_dr_role; 1288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci pm_runtime_get_sync(dwc->dev); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) 1338c2ecf20Sopenharmony_ci dwc3_otg_update(dwc, 0); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!desired_dr_role) 1368c2ecf20Sopenharmony_ci goto out; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (desired_dr_role == dwc->current_dr_role) 1398c2ecf20Sopenharmony_ci goto out; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) 1428c2ecf20Sopenharmony_ci goto out; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci switch (dwc->current_dr_role) { 1458c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 1468c2ecf20Sopenharmony_ci dwc3_host_exit(dwc); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 1498c2ecf20Sopenharmony_ci dwc3_gadget_exit(dwc); 1508c2ecf20Sopenharmony_ci dwc3_event_buffers_cleanup(dwc); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_OTG: 1538c2ecf20Sopenharmony_ci dwc3_otg_exit(dwc); 1548c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 1558c2ecf20Sopenharmony_ci dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE; 1568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 1578c2ecf20Sopenharmony_ci dwc3_otg_update(dwc, 1); 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci default: 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* 1648c2ecf20Sopenharmony_ci * When current_dr_role is not set, there's no role switching. 1658c2ecf20Sopenharmony_ci * Only perform GCTL.CoreSoftReset when there's DRD role switching. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) || 1688c2ecf20Sopenharmony_ci DWC3_VER_IS_PRIOR(DWC31, 190A)) && 1698c2ecf20Sopenharmony_ci desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) { 1708c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GCTL); 1718c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_CORESOFTRESET; 1728c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GCTL, reg); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * Wait for internal clocks to synchronized. DWC_usb31 and 1768c2ecf20Sopenharmony_ci * DWC_usb32 may need at least 50ms (less for DWC_usb3). To 1778c2ecf20Sopenharmony_ci * keep it consistent across different IPs, let's wait up to 1788c2ecf20Sopenharmony_ci * 100ms before clearing GCTL.CORESOFTRESET. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci msleep(100); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GCTL); 1838c2ecf20Sopenharmony_ci reg &= ~DWC3_GCTL_CORESOFTRESET; 1848c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GCTL, reg); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, desired_dr_role); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci switch (desired_dr_role) { 1948c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 1958c2ecf20Sopenharmony_ci ret = dwc3_host_init(dwc); 1968c2ecf20Sopenharmony_ci if (ret) { 1978c2ecf20Sopenharmony_ci dev_err(dwc->dev, "failed to initialize host\n"); 1988c2ecf20Sopenharmony_ci } else { 1998c2ecf20Sopenharmony_ci if (dwc->usb2_phy) 2008c2ecf20Sopenharmony_ci otg_set_vbus(dwc->usb2_phy->otg, true); 2018c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); 2028c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); 2038c2ecf20Sopenharmony_ci if (dwc->dis_split_quirk) { 2048c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); 2058c2ecf20Sopenharmony_ci reg |= DWC3_GUCTL3_SPLITDISABLE; 2068c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 2118c2ecf20Sopenharmony_ci dwc3_core_soft_reset(dwc); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci dwc3_event_buffers_setup(dwc); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (dwc->usb2_phy) 2168c2ecf20Sopenharmony_ci otg_set_vbus(dwc->usb2_phy->otg, false); 2178c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); 2188c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = dwc3_gadget_init(dwc); 2218c2ecf20Sopenharmony_ci if (ret) 2228c2ecf20Sopenharmony_ci dev_err(dwc->dev, "failed to initialize peripheral\n"); 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_OTG: 2258c2ecf20Sopenharmony_ci dwc3_otg_init(dwc); 2268c2ecf20Sopenharmony_ci dwc3_otg_update(dwc, 0); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci default: 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ciout: 2338c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dwc->dev); 2348c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dwc->dev); 2358c2ecf20Sopenharmony_ci mutex_unlock(&dwc->mutex); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_civoid dwc3_set_mode(struct dwc3 *dwc, u32 mode) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci unsigned long flags; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (dwc->dr_mode != USB_DR_MODE_OTG) 2438c2ecf20Sopenharmony_ci return; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 2468c2ecf20Sopenharmony_ci dwc->desired_dr_role = mode; 2478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci queue_work(system_freezable_wq, &dwc->drd_work); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciu32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 2558c2ecf20Sopenharmony_ci u32 reg; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, 2588c2ecf20Sopenharmony_ci DWC3_GDBGFIFOSPACE_NUM(dep->number) | 2598c2ecf20Sopenharmony_ci DWC3_GDBGFIFOSPACE_TYPE(type)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/** 2678c2ecf20Sopenharmony_ci * dwc3_core_soft_reset - Issues core soft reset and PHY reset 2688c2ecf20Sopenharmony_ci * @dwc: pointer to our context structure 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ciint dwc3_core_soft_reset(struct dwc3 *dwc) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci u32 reg; 2738c2ecf20Sopenharmony_ci int retries = 1000; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * We're resetting only the device side because, if we're in host mode, 2778c2ecf20Sopenharmony_ci * XHCI driver will reset the host block. If dwc3 was configured for 2788c2ecf20Sopenharmony_ci * host-only mode, then we can return early. 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2848c2ecf20Sopenharmony_ci reg |= DWC3_DCTL_CSFTRST; 2858c2ecf20Sopenharmony_ci reg &= ~DWC3_DCTL_RUN_STOP; 2868c2ecf20Sopenharmony_ci dwc3_gadget_dctl_write_safe(dwc, reg); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit 2908c2ecf20Sopenharmony_ci * is cleared only after all the clocks are synchronized. This can 2918c2ecf20Sopenharmony_ci * take a little more than 50ms. Set the polling rate at 20ms 2928c2ecf20Sopenharmony_ci * for 10 times instead. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32)) 2958c2ecf20Sopenharmony_ci retries = 10; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci do { 2988c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2998c2ecf20Sopenharmony_ci if (!(reg & DWC3_DCTL_CSFTRST)) 3008c2ecf20Sopenharmony_ci goto done; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32)) 3038c2ecf20Sopenharmony_ci msleep(20); 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci udelay(1); 3068c2ecf20Sopenharmony_ci } while (--retries); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cidone: 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * For DWC_usb31 controller 1.80a and prior, once DCTL.CSFRST bit 3138c2ecf20Sopenharmony_ci * is cleared, we must wait at least 50ms before accessing the PHY 3148c2ecf20Sopenharmony_ci * domain (synchronization delay). 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A)) 3178c2ecf20Sopenharmony_ci msleep(50); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* 3238c2ecf20Sopenharmony_ci * dwc3_frame_length_adjustment - Adjusts frame length if required 3248c2ecf20Sopenharmony_ci * @dwc3: Pointer to our controller context structure 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic void dwc3_frame_length_adjustment(struct dwc3 *dwc) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci u32 reg; 3298c2ecf20Sopenharmony_ci u32 dft; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (DWC3_VER_IS_PRIOR(DWC3, 250A)) 3328c2ecf20Sopenharmony_ci return; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (dwc->fladj == 0) 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); 3388c2ecf20Sopenharmony_ci dft = reg & DWC3_GFLADJ_30MHZ_MASK; 3398c2ecf20Sopenharmony_ci if (dft != dwc->fladj) { 3408c2ecf20Sopenharmony_ci reg &= ~DWC3_GFLADJ_30MHZ_MASK; 3418c2ecf20Sopenharmony_ci reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; 3428c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/** 3478c2ecf20Sopenharmony_ci * dwc3_free_one_event_buffer - Frees one event buffer 3488c2ecf20Sopenharmony_ci * @dwc: Pointer to our controller context structure 3498c2ecf20Sopenharmony_ci * @evt: Pointer to event buffer to be freed 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_cistatic void dwc3_free_one_event_buffer(struct dwc3 *dwc, 3528c2ecf20Sopenharmony_ci struct dwc3_event_buffer *evt) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/** 3588c2ecf20Sopenharmony_ci * dwc3_alloc_one_event_buffer - Allocates one event buffer structure 3598c2ecf20Sopenharmony_ci * @dwc: Pointer to our controller context structure 3608c2ecf20Sopenharmony_ci * @length: size of the event buffer 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * Returns a pointer to the allocated event buffer structure on success 3638c2ecf20Sopenharmony_ci * otherwise ERR_PTR(errno). 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_cistatic struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, 3668c2ecf20Sopenharmony_ci unsigned length) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct dwc3_event_buffer *evt; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL); 3718c2ecf20Sopenharmony_ci if (!evt) 3728c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci evt->dwc = dwc; 3758c2ecf20Sopenharmony_ci evt->length = length; 3768c2ecf20Sopenharmony_ci evt->cache = devm_kzalloc(dwc->dev, length, GFP_KERNEL); 3778c2ecf20Sopenharmony_ci if (!evt->cache) 3788c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci evt->buf = dma_alloc_coherent(dwc->sysdev, length, 3818c2ecf20Sopenharmony_ci &evt->dma, GFP_KERNEL); 3828c2ecf20Sopenharmony_ci if (!evt->buf) 3838c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return evt; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/** 3898c2ecf20Sopenharmony_ci * dwc3_free_event_buffers - frees all allocated event buffers 3908c2ecf20Sopenharmony_ci * @dwc: Pointer to our controller context structure 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic void dwc3_free_event_buffers(struct dwc3 *dwc) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct dwc3_event_buffer *evt; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci evt = dwc->ev_buf; 3978c2ecf20Sopenharmony_ci if (evt) 3988c2ecf20Sopenharmony_ci dwc3_free_one_event_buffer(dwc, evt); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/** 4028c2ecf20Sopenharmony_ci * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length 4038c2ecf20Sopenharmony_ci * @dwc: pointer to our controller context structure 4048c2ecf20Sopenharmony_ci * @length: size of event buffer 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci * Returns 0 on success otherwise negative errno. In the error case, dwc 4078c2ecf20Sopenharmony_ci * may contain some buffers allocated but not all which were requested. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_cistatic int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct dwc3_event_buffer *evt; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci evt = dwc3_alloc_one_event_buffer(dwc, length); 4148c2ecf20Sopenharmony_ci if (IS_ERR(evt)) { 4158c2ecf20Sopenharmony_ci dev_err(dwc->dev, "can't allocate event buffer\n"); 4168c2ecf20Sopenharmony_ci return PTR_ERR(evt); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci dwc->ev_buf = evt; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/** 4248c2ecf20Sopenharmony_ci * dwc3_event_buffers_setup - setup our allocated event buffers 4258c2ecf20Sopenharmony_ci * @dwc: pointer to our controller context structure 4268c2ecf20Sopenharmony_ci * 4278c2ecf20Sopenharmony_ci * Returns 0 on success otherwise negative errno. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ciint dwc3_event_buffers_setup(struct dwc3 *dwc) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct dwc3_event_buffer *evt; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci evt = dwc->ev_buf; 4348c2ecf20Sopenharmony_ci evt->lpos = 0; 4358c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 4368c2ecf20Sopenharmony_ci lower_32_bits(evt->dma)); 4378c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 4388c2ecf20Sopenharmony_ci upper_32_bits(evt->dma)); 4398c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), 4408c2ecf20Sopenharmony_ci DWC3_GEVNTSIZ_SIZE(evt->length)); 4418c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_civoid dwc3_event_buffers_cleanup(struct dwc3 *dwc) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct dwc3_event_buffer *evt; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci evt = dwc->ev_buf; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci evt->lpos = 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0); 4558c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0); 4568c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK 4578c2ecf20Sopenharmony_ci | DWC3_GEVNTSIZ_SIZE(0)); 4588c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci if (!dwc->has_hibernation) 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!dwc->nr_scratch) 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, 4708c2ecf20Sopenharmony_ci DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); 4718c2ecf20Sopenharmony_ci if (!dwc->scratchbuf) 4728c2ecf20Sopenharmony_ci return -ENOMEM; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int dwc3_setup_scratch_buffers(struct dwc3 *dwc) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci dma_addr_t scratch_addr; 4808c2ecf20Sopenharmony_ci u32 param; 4818c2ecf20Sopenharmony_ci int ret; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!dwc->has_hibernation) 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (!dwc->nr_scratch) 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* should never fall here */ 4908c2ecf20Sopenharmony_ci if (!WARN_ON(dwc->scratchbuf)) 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf, 4948c2ecf20Sopenharmony_ci dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, 4958c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 4968c2ecf20Sopenharmony_ci if (dma_mapping_error(dwc->sysdev, scratch_addr)) { 4978c2ecf20Sopenharmony_ci dev_err(dwc->sysdev, "failed to map scratch buffer\n"); 4988c2ecf20Sopenharmony_ci ret = -EFAULT; 4998c2ecf20Sopenharmony_ci goto err0; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci dwc->scratch_addr = scratch_addr; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci param = lower_32_bits(scratch_addr); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci ret = dwc3_send_gadget_generic_command(dwc, 5078c2ecf20Sopenharmony_ci DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); 5088c2ecf20Sopenharmony_ci if (ret < 0) 5098c2ecf20Sopenharmony_ci goto err1; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci param = upper_32_bits(scratch_addr); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ret = dwc3_send_gadget_generic_command(dwc, 5148c2ecf20Sopenharmony_ci DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); 5158c2ecf20Sopenharmony_ci if (ret < 0) 5168c2ecf20Sopenharmony_ci goto err1; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cierr1: 5218c2ecf20Sopenharmony_ci dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * 5228c2ecf20Sopenharmony_ci DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cierr0: 5258c2ecf20Sopenharmony_ci return ret; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic void dwc3_free_scratch_buffers(struct dwc3 *dwc) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci if (!dwc->has_hibernation) 5318c2ecf20Sopenharmony_ci return; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (!dwc->nr_scratch) 5348c2ecf20Sopenharmony_ci return; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* should never fall here */ 5378c2ecf20Sopenharmony_ci if (!WARN_ON(dwc->scratchbuf)) 5388c2ecf20Sopenharmony_ci return; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * 5418c2ecf20Sopenharmony_ci DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 5428c2ecf20Sopenharmony_ci kfree(dwc->scratchbuf); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic void dwc3_core_num_eps(struct dwc3 *dwc) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct dwc3_hwparams *parms = &dwc->hwparams; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dwc->num_eps = DWC3_NUM_EPS(parms); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void dwc3_cache_hwparams(struct dwc3 *dwc) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct dwc3_hwparams *parms = &dwc->hwparams; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); 5578c2ecf20Sopenharmony_ci parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); 5588c2ecf20Sopenharmony_ci parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); 5598c2ecf20Sopenharmony_ci parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); 5608c2ecf20Sopenharmony_ci parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); 5618c2ecf20Sopenharmony_ci parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); 5628c2ecf20Sopenharmony_ci parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); 5638c2ecf20Sopenharmony_ci parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); 5648c2ecf20Sopenharmony_ci parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int dwc3_core_ulpi_init(struct dwc3 *dwc) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci int intf; 5708c2ecf20Sopenharmony_ci int ret = 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI || 5758c2ecf20Sopenharmony_ci (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI && 5768c2ecf20Sopenharmony_ci dwc->hsphy_interface && 5778c2ecf20Sopenharmony_ci !strncmp(dwc->hsphy_interface, "ulpi", 4))) 5788c2ecf20Sopenharmony_ci ret = dwc3_ulpi_init(dwc); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/** 5848c2ecf20Sopenharmony_ci * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core 5858c2ecf20Sopenharmony_ci * @dwc: Pointer to our controller context structure 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * Returns 0 on success. The USB PHY interfaces are configured but not 5888c2ecf20Sopenharmony_ci * initialized. The PHY interfaces and the PHYs get initialized together with 5898c2ecf20Sopenharmony_ci * the core in dwc3_core_init. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_cistatic int dwc3_phy_setup(struct dwc3 *dwc) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci unsigned int hw_mode; 5948c2ecf20Sopenharmony_ci u32 reg; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* 6018c2ecf20Sopenharmony_ci * Make sure UX_EXIT_PX is cleared as that causes issues with some 6028c2ecf20Sopenharmony_ci * PHYs. Also, this bit is not supposed to be used in normal operation. 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* 6078c2ecf20Sopenharmony_ci * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY 6088c2ecf20Sopenharmony_ci * to '0' during coreConsultant configuration. So default value 6098c2ecf20Sopenharmony_ci * will be '0' when the core is reset. Application needs to set it 6108c2ecf20Sopenharmony_ci * to '1' after the core initialization is completed. 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) 6138c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_SUSPHY; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after 6178c2ecf20Sopenharmony_ci * power-on reset, and it can be set after core initialization, which is 6188c2ecf20Sopenharmony_ci * after device soft-reset during initialization. 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_ci if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) 6218c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (dwc->u2ss_inp3_quirk) 6248c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (dwc->dis_rxdet_inp3_quirk) 6278c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (dwc->req_p1p2p3_quirk) 6308c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (dwc->del_p1p2p3_quirk) 6338c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (dwc->del_phy_power_chg_quirk) 6368c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (dwc->lfps_filter_quirk) 6398c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_LFPSFILT; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (dwc->rx_detect_poll_quirk) 6428c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (dwc->tx_de_emphasis_quirk) 6458c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (dwc->dis_u3_susphy_quirk) 6488c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (dwc->dis_del_phy_power_chg_quirk) 6518c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Select the HS PHY interface */ 6588c2ecf20Sopenharmony_ci switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { 6598c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI: 6608c2ecf20Sopenharmony_ci if (dwc->hsphy_interface && 6618c2ecf20Sopenharmony_ci !strncmp(dwc->hsphy_interface, "utmi", 4)) { 6628c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI; 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci } else if (dwc->hsphy_interface && 6658c2ecf20Sopenharmony_ci !strncmp(dwc->hsphy_interface, "ulpi", 4)) { 6668c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; 6678c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 6688c2ecf20Sopenharmony_ci } else { 6698c2ecf20Sopenharmony_ci /* Relying on default value. */ 6708c2ecf20Sopenharmony_ci if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci fallthrough; 6748c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: 6758c2ecf20Sopenharmony_ci default: 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci switch (dwc->hsphy_mode) { 6808c2ecf20Sopenharmony_ci case USBPHY_INTERFACE_MODE_UTMI: 6818c2ecf20Sopenharmony_ci reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 6828c2ecf20Sopenharmony_ci DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 6838c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | 6848c2ecf20Sopenharmony_ci DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT); 6858c2ecf20Sopenharmony_ci break; 6868c2ecf20Sopenharmony_ci case USBPHY_INTERFACE_MODE_UTMIW: 6878c2ecf20Sopenharmony_ci reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 6888c2ecf20Sopenharmony_ci DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 6898c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) | 6908c2ecf20Sopenharmony_ci DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); 6918c2ecf20Sopenharmony_ci break; 6928c2ecf20Sopenharmony_ci default: 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* 6978c2ecf20Sopenharmony_ci * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to 6988c2ecf20Sopenharmony_ci * '0' during coreConsultant configuration. So default value will 6998c2ecf20Sopenharmony_ci * be '0' when the core is reset. Application needs to set it to 7008c2ecf20Sopenharmony_ci * '1' after the core initialization is completed. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) 7038c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_SUSPHY; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* 7068c2ecf20Sopenharmony_ci * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after 7078c2ecf20Sopenharmony_ci * power-on reset, and it can be set after core initialization, which is 7088c2ecf20Sopenharmony_ci * after device soft-reset during initialization. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) 7118c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (dwc->dis_u2_susphy_quirk) 7148c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (dwc->dis_enblslpm_quirk) 7178c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; 7188c2ecf20Sopenharmony_ci else 7198c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (dwc->dis_u2_freeclk_exists_quirk) 7228c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void dwc3_core_exit(struct dwc3 *dwc) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci dwc3_event_buffers_cleanup(dwc); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb2_phy, 1); 7348c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb3_phy, 1); 7358c2ecf20Sopenharmony_ci phy_power_off(dwc->usb2_generic_phy); 7368c2ecf20Sopenharmony_ci phy_power_off(dwc->usb3_generic_phy); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci usb_phy_shutdown(dwc->usb2_phy); 7398c2ecf20Sopenharmony_ci usb_phy_shutdown(dwc->usb3_phy); 7408c2ecf20Sopenharmony_ci phy_exit(dwc->usb2_generic_phy); 7418c2ecf20Sopenharmony_ci phy_exit(dwc->usb3_generic_phy); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); 7448c2ecf20Sopenharmony_ci reset_control_assert(dwc->reset); 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic bool dwc3_core_is_valid(struct dwc3 *dwc) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci u32 reg; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); 7528c2ecf20Sopenharmony_ci dwc->ip = DWC3_GSNPS_ID(reg); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* This should read as U3 followed by revision number */ 7558c2ecf20Sopenharmony_ci if (DWC3_IP_IS(DWC3)) { 7568c2ecf20Sopenharmony_ci dwc->revision = reg; 7578c2ecf20Sopenharmony_ci } else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) { 7588c2ecf20Sopenharmony_ci dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); 7598c2ecf20Sopenharmony_ci dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE); 7608c2ecf20Sopenharmony_ci } else { 7618c2ecf20Sopenharmony_ci return false; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return true; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic void dwc3_core_setup_global_control(struct dwc3 *dwc) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci u32 hwparams4 = dwc->hwparams.hwparams4; 7708c2ecf20Sopenharmony_ci u32 reg; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GCTL); 7738c2ecf20Sopenharmony_ci reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { 7768c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 7778c2ecf20Sopenharmony_ci /** 7788c2ecf20Sopenharmony_ci * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an 7798c2ecf20Sopenharmony_ci * issue which would cause xHCI compliance tests to fail. 7808c2ecf20Sopenharmony_ci * 7818c2ecf20Sopenharmony_ci * Because of that we cannot enable clock gating on such 7828c2ecf20Sopenharmony_ci * configurations. 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * Refers to: 7858c2ecf20Sopenharmony_ci * 7868c2ecf20Sopenharmony_ci * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based 7878c2ecf20Sopenharmony_ci * SOF/ITP Mode Used 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci if ((dwc->dr_mode == USB_DR_MODE_HOST || 7908c2ecf20Sopenharmony_ci dwc->dr_mode == USB_DR_MODE_OTG) && 7918c2ecf20Sopenharmony_ci DWC3_VER_IS_WITHIN(DWC3, 210A, 250A)) 7928c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; 7938c2ecf20Sopenharmony_ci else 7948c2ecf20Sopenharmony_ci reg &= ~DWC3_GCTL_DSBLCLKGTNG; 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS1_EN_PWROPT_HIB: 7978c2ecf20Sopenharmony_ci /* enable hibernation here */ 7988c2ecf20Sopenharmony_ci dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* 8018c2ecf20Sopenharmony_ci * REVISIT Enabling this bit so that host-mode hibernation 8028c2ecf20Sopenharmony_ci * will work. Device-mode hibernation is not yet implemented. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_GBLHIBERNATIONEN; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci default: 8078c2ecf20Sopenharmony_ci /* nothing */ 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* check if current dwc3 is on simulation board */ 8128c2ecf20Sopenharmony_ci if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { 8138c2ecf20Sopenharmony_ci dev_info(dwc->dev, "Running with FPGA optimizations\n"); 8148c2ecf20Sopenharmony_ci dwc->is_fpga = true; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga, 8188c2ecf20Sopenharmony_ci "disable_scramble cannot be used on non-FPGA builds\n"); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (dwc->disable_scramble_quirk && dwc->is_fpga) 8218c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_DISSCRAMBLE; 8228c2ecf20Sopenharmony_ci else 8238c2ecf20Sopenharmony_ci reg &= ~DWC3_GCTL_DISSCRAMBLE; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (dwc->u2exit_lfps_quirk) 8268c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_U2EXIT_LFPS; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* 8298c2ecf20Sopenharmony_ci * WORKAROUND: DWC3 revisions <1.90a have a bug 8308c2ecf20Sopenharmony_ci * where the device can fail to connect at SuperSpeed 8318c2ecf20Sopenharmony_ci * and falls back to high-speed mode which causes 8328c2ecf20Sopenharmony_ci * the device to enter a Connect/Disconnect loop 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_ci if (DWC3_VER_IS_PRIOR(DWC3, 190A)) 8358c2ecf20Sopenharmony_ci reg |= DWC3_GCTL_U2RSTECN; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GCTL, reg); 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int dwc3_core_get_phy(struct dwc3 *dwc); 8418c2ecf20Sopenharmony_cistatic int dwc3_core_ulpi_init(struct dwc3 *dwc); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/* set global incr burst type configuration registers */ 8448c2ecf20Sopenharmony_cistatic void dwc3_set_incr_burst_type(struct dwc3 *dwc) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct device *dev = dwc->dev; 8478c2ecf20Sopenharmony_ci /* incrx_mode : for INCR burst type. */ 8488c2ecf20Sopenharmony_ci bool incrx_mode; 8498c2ecf20Sopenharmony_ci /* incrx_size : for size of INCRX burst. */ 8508c2ecf20Sopenharmony_ci u32 incrx_size; 8518c2ecf20Sopenharmony_ci u32 *vals; 8528c2ecf20Sopenharmony_ci u32 cfg; 8538c2ecf20Sopenharmony_ci int ntype; 8548c2ecf20Sopenharmony_ci int ret; 8558c2ecf20Sopenharmony_ci int i; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* 8608c2ecf20Sopenharmony_ci * Handle property "snps,incr-burst-type-adjustment". 8618c2ecf20Sopenharmony_ci * Get the number of value from this property: 8628c2ecf20Sopenharmony_ci * result <= 0, means this property is not supported. 8638c2ecf20Sopenharmony_ci * result = 1, means INCRx burst mode supported. 8648c2ecf20Sopenharmony_ci * result > 1, means undefined length burst mode supported. 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_ci ntype = device_property_count_u32(dev, "snps,incr-burst-type-adjustment"); 8678c2ecf20Sopenharmony_ci if (ntype <= 0) 8688c2ecf20Sopenharmony_ci return; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL); 8718c2ecf20Sopenharmony_ci if (!vals) { 8728c2ecf20Sopenharmony_ci dev_err(dev, "Error to get memory\n"); 8738c2ecf20Sopenharmony_ci return; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Get INCR burst type, and parse it */ 8778c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(dev, 8788c2ecf20Sopenharmony_ci "snps,incr-burst-type-adjustment", vals, ntype); 8798c2ecf20Sopenharmony_ci if (ret) { 8808c2ecf20Sopenharmony_ci kfree(vals); 8818c2ecf20Sopenharmony_ci dev_err(dev, "Error to get property\n"); 8828c2ecf20Sopenharmony_ci return; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci incrx_size = *vals; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (ntype > 1) { 8888c2ecf20Sopenharmony_ci /* INCRX (undefined length) burst mode */ 8898c2ecf20Sopenharmony_ci incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE; 8908c2ecf20Sopenharmony_ci for (i = 1; i < ntype; i++) { 8918c2ecf20Sopenharmony_ci if (vals[i] > incrx_size) 8928c2ecf20Sopenharmony_ci incrx_size = vals[i]; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci } else { 8958c2ecf20Sopenharmony_ci /* INCRX burst mode */ 8968c2ecf20Sopenharmony_ci incrx_mode = INCRX_BURST_MODE; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci kfree(vals); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Enable Undefined Length INCR Burst and Enable INCRx Burst */ 9028c2ecf20Sopenharmony_ci cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK; 9038c2ecf20Sopenharmony_ci if (incrx_mode) 9048c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCRBRSTENA; 9058c2ecf20Sopenharmony_ci switch (incrx_size) { 9068c2ecf20Sopenharmony_ci case 256: 9078c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA; 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci case 128: 9108c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA; 9118c2ecf20Sopenharmony_ci break; 9128c2ecf20Sopenharmony_ci case 64: 9138c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci case 32: 9168c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA; 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci case 16: 9198c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA; 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci case 8: 9228c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA; 9238c2ecf20Sopenharmony_ci break; 9248c2ecf20Sopenharmony_ci case 4: 9258c2ecf20Sopenharmony_ci cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA; 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci case 1: 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci default: 9308c2ecf20Sopenharmony_ci dev_err(dev, "Invalid property\n"); 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci/** 9388c2ecf20Sopenharmony_ci * dwc3_core_init - Low-level initialization of DWC3 Core 9398c2ecf20Sopenharmony_ci * @dwc: Pointer to our controller context structure 9408c2ecf20Sopenharmony_ci * 9418c2ecf20Sopenharmony_ci * Returns 0 on success otherwise negative errno. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_cistatic int dwc3_core_init(struct dwc3 *dwc) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci unsigned int hw_mode; 9468c2ecf20Sopenharmony_ci u32 reg; 9478c2ecf20Sopenharmony_ci int ret; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* 9528c2ecf20Sopenharmony_ci * Write Linux Version Code to our GUID register so it's easy to figure 9538c2ecf20Sopenharmony_ci * out which kernel version a bug was found. 9548c2ecf20Sopenharmony_ci */ 9558c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci ret = dwc3_phy_setup(dwc); 9588c2ecf20Sopenharmony_ci if (ret) 9598c2ecf20Sopenharmony_ci goto err0; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (!dwc->ulpi_ready) { 9628c2ecf20Sopenharmony_ci ret = dwc3_core_ulpi_init(dwc); 9638c2ecf20Sopenharmony_ci if (ret) { 9648c2ecf20Sopenharmony_ci if (ret == -ETIMEDOUT) { 9658c2ecf20Sopenharmony_ci dwc3_core_soft_reset(dwc); 9668c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci goto err0; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci dwc->ulpi_ready = true; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!dwc->phys_ready) { 9748c2ecf20Sopenharmony_ci ret = dwc3_core_get_phy(dwc); 9758c2ecf20Sopenharmony_ci if (ret) 9768c2ecf20Sopenharmony_ci goto err0a; 9778c2ecf20Sopenharmony_ci dwc->phys_ready = true; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci usb_phy_init(dwc->usb2_phy); 9818c2ecf20Sopenharmony_ci usb_phy_init(dwc->usb3_phy); 9828c2ecf20Sopenharmony_ci ret = phy_init(dwc->usb2_generic_phy); 9838c2ecf20Sopenharmony_ci if (ret < 0) 9848c2ecf20Sopenharmony_ci goto err0a; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci ret = phy_init(dwc->usb3_generic_phy); 9878c2ecf20Sopenharmony_ci if (ret < 0) { 9888c2ecf20Sopenharmony_ci phy_exit(dwc->usb2_generic_phy); 9898c2ecf20Sopenharmony_ci goto err0a; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ret = dwc3_core_soft_reset(dwc); 9938c2ecf20Sopenharmony_ci if (ret) 9948c2ecf20Sopenharmony_ci goto err1; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && 9978c2ecf20Sopenharmony_ci !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { 9988c2ecf20Sopenharmony_ci if (!dwc->dis_u3_susphy_quirk) { 9998c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 10008c2ecf20Sopenharmony_ci reg |= DWC3_GUSB3PIPECTL_SUSPHY; 10018c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (!dwc->dis_u2_susphy_quirk) { 10058c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 10068c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_SUSPHY; 10078c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci dwc3_core_setup_global_control(dwc); 10128c2ecf20Sopenharmony_ci dwc3_core_num_eps(dwc); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci ret = dwc3_setup_scratch_buffers(dwc); 10158c2ecf20Sopenharmony_ci if (ret) 10168c2ecf20Sopenharmony_ci goto err1; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* Adjust Frame Length */ 10198c2ecf20Sopenharmony_ci dwc3_frame_length_adjustment(dwc); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci dwc3_set_incr_burst_type(dwc); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb2_phy, 0); 10248c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb3_phy, 0); 10258c2ecf20Sopenharmony_ci ret = phy_power_on(dwc->usb2_generic_phy); 10268c2ecf20Sopenharmony_ci if (ret < 0) 10278c2ecf20Sopenharmony_ci goto err2; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci ret = phy_power_on(dwc->usb3_generic_phy); 10308c2ecf20Sopenharmony_ci if (ret < 0) 10318c2ecf20Sopenharmony_ci goto err3; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci ret = dwc3_event_buffers_setup(dwc); 10348c2ecf20Sopenharmony_ci if (ret) { 10358c2ecf20Sopenharmony_ci dev_err(dwc->dev, "failed to setup event buffers\n"); 10368c2ecf20Sopenharmony_ci goto err4; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* 10408c2ecf20Sopenharmony_ci * ENDXFER polling is available on version 3.10a and later of 10418c2ecf20Sopenharmony_ci * the DWC_usb3 controller. It is NOT available in the 10428c2ecf20Sopenharmony_ci * DWC_usb31 controller. 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_ci if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) { 10458c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); 10468c2ecf20Sopenharmony_ci reg |= DWC3_GUCTL2_RST_ACTBITLATER; 10478c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) { 10518c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* 10548c2ecf20Sopenharmony_ci * Enable hardware control of sending remote wakeup 10558c2ecf20Sopenharmony_ci * in HS when the device is in the L1 state. 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci if (!DWC3_VER_IS_PRIOR(DWC3, 290A)) 10588c2ecf20Sopenharmony_ci reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (dwc->dis_tx_ipgap_linecheck_quirk) 10618c2ecf20Sopenharmony_ci reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (dwc->parkmode_disable_ss_quirk) 10648c2ecf20Sopenharmony_ci reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* 10708c2ecf20Sopenharmony_ci * Must config both number of packets and max burst settings to enable 10718c2ecf20Sopenharmony_ci * RX and/or TX threshold. 10728c2ecf20Sopenharmony_ci */ 10738c2ecf20Sopenharmony_ci if (!DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) { 10748c2ecf20Sopenharmony_ci u8 rx_thr_num = dwc->rx_thr_num_pkt_prd; 10758c2ecf20Sopenharmony_ci u8 rx_maxburst = dwc->rx_max_burst_prd; 10768c2ecf20Sopenharmony_ci u8 tx_thr_num = dwc->tx_thr_num_pkt_prd; 10778c2ecf20Sopenharmony_ci u8 tx_maxburst = dwc->tx_max_burst_prd; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (rx_thr_num && rx_maxburst) { 10808c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); 10818c2ecf20Sopenharmony_ci reg |= DWC31_RXTHRNUMPKTSEL_PRD; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci reg &= ~DWC31_RXTHRNUMPKT_PRD(~0); 10848c2ecf20Sopenharmony_ci reg |= DWC31_RXTHRNUMPKT_PRD(rx_thr_num); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0); 10878c2ecf20Sopenharmony_ci reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (tx_thr_num && tx_maxburst) { 10938c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG); 10948c2ecf20Sopenharmony_ci reg |= DWC31_TXTHRNUMPKTSEL_PRD; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci reg &= ~DWC31_TXTHRNUMPKT_PRD(~0); 10978c2ecf20Sopenharmony_ci reg |= DWC31_TXTHRNUMPKT_PRD(tx_thr_num); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0); 11008c2ecf20Sopenharmony_ci reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg); 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci return 0; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cierr4: 11098c2ecf20Sopenharmony_ci phy_power_off(dwc->usb3_generic_phy); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cierr3: 11128c2ecf20Sopenharmony_ci phy_power_off(dwc->usb2_generic_phy); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cierr2: 11158c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb2_phy, 1); 11168c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb3_phy, 1); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cierr1: 11198c2ecf20Sopenharmony_ci usb_phy_shutdown(dwc->usb2_phy); 11208c2ecf20Sopenharmony_ci usb_phy_shutdown(dwc->usb3_phy); 11218c2ecf20Sopenharmony_ci phy_exit(dwc->usb2_generic_phy); 11228c2ecf20Sopenharmony_ci phy_exit(dwc->usb3_generic_phy); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cierr0a: 11258c2ecf20Sopenharmony_ci dwc3_ulpi_exit(dwc); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cierr0: 11288c2ecf20Sopenharmony_ci return ret; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int dwc3_core_get_phy(struct dwc3 *dwc) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci struct device *dev = dwc->dev; 11348c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 11358c2ecf20Sopenharmony_ci int ret; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (node) { 11388c2ecf20Sopenharmony_ci dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); 11398c2ecf20Sopenharmony_ci dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); 11408c2ecf20Sopenharmony_ci } else { 11418c2ecf20Sopenharmony_ci dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 11428c2ecf20Sopenharmony_ci dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (IS_ERR(dwc->usb2_phy)) { 11468c2ecf20Sopenharmony_ci ret = PTR_ERR(dwc->usb2_phy); 11478c2ecf20Sopenharmony_ci if (ret == -ENXIO || ret == -ENODEV) { 11488c2ecf20Sopenharmony_ci dwc->usb2_phy = NULL; 11498c2ecf20Sopenharmony_ci } else if (ret == -EPROBE_DEFER) { 11508c2ecf20Sopenharmony_ci return ret; 11518c2ecf20Sopenharmony_ci } else { 11528c2ecf20Sopenharmony_ci dev_err(dev, "no usb2 phy configured\n"); 11538c2ecf20Sopenharmony_ci return ret; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci if (IS_ERR(dwc->usb3_phy)) { 11588c2ecf20Sopenharmony_ci ret = PTR_ERR(dwc->usb3_phy); 11598c2ecf20Sopenharmony_ci if (ret == -ENXIO || ret == -ENODEV) { 11608c2ecf20Sopenharmony_ci dwc->usb3_phy = NULL; 11618c2ecf20Sopenharmony_ci } else if (ret == -EPROBE_DEFER) { 11628c2ecf20Sopenharmony_ci return ret; 11638c2ecf20Sopenharmony_ci } else { 11648c2ecf20Sopenharmony_ci dev_err(dev, "no usb3 phy configured\n"); 11658c2ecf20Sopenharmony_ci return ret; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); 11708c2ecf20Sopenharmony_ci if (IS_ERR(dwc->usb2_generic_phy)) { 11718c2ecf20Sopenharmony_ci ret = PTR_ERR(dwc->usb2_generic_phy); 11728c2ecf20Sopenharmony_ci if (ret == -ENOSYS || ret == -ENODEV) { 11738c2ecf20Sopenharmony_ci dwc->usb2_generic_phy = NULL; 11748c2ecf20Sopenharmony_ci } else if (ret == -EPROBE_DEFER) { 11758c2ecf20Sopenharmony_ci return ret; 11768c2ecf20Sopenharmony_ci } else { 11778c2ecf20Sopenharmony_ci dev_err(dev, "no usb2 phy configured\n"); 11788c2ecf20Sopenharmony_ci return ret; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); 11838c2ecf20Sopenharmony_ci if (IS_ERR(dwc->usb3_generic_phy)) { 11848c2ecf20Sopenharmony_ci ret = PTR_ERR(dwc->usb3_generic_phy); 11858c2ecf20Sopenharmony_ci if (ret == -ENOSYS || ret == -ENODEV) { 11868c2ecf20Sopenharmony_ci dwc->usb3_generic_phy = NULL; 11878c2ecf20Sopenharmony_ci } else if (ret == -EPROBE_DEFER) { 11888c2ecf20Sopenharmony_ci return ret; 11898c2ecf20Sopenharmony_ci } else { 11908c2ecf20Sopenharmony_ci dev_err(dev, "no usb3 phy configured\n"); 11918c2ecf20Sopenharmony_ci return ret; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci return 0; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int dwc3_core_init_mode(struct dwc3 *dwc) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct device *dev = dwc->dev; 12018c2ecf20Sopenharmony_ci int ret; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci switch (dwc->dr_mode) { 12048c2ecf20Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 12058c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (dwc->usb2_phy) 12088c2ecf20Sopenharmony_ci otg_set_vbus(dwc->usb2_phy->otg, false); 12098c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); 12108c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci ret = dwc3_gadget_init(dwc); 12138c2ecf20Sopenharmony_ci if (ret) { 12148c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 12158c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize gadget\n"); 12168c2ecf20Sopenharmony_ci return ret; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci case USB_DR_MODE_HOST: 12208c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (dwc->usb2_phy) 12238c2ecf20Sopenharmony_ci otg_set_vbus(dwc->usb2_phy->otg, true); 12248c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); 12258c2ecf20Sopenharmony_ci phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci ret = dwc3_host_init(dwc); 12288c2ecf20Sopenharmony_ci if (ret) { 12298c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 12308c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize host\n"); 12318c2ecf20Sopenharmony_ci return ret; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci case USB_DR_MODE_OTG: 12358c2ecf20Sopenharmony_ci INIT_WORK(&dwc->drd_work, __dwc3_set_mode); 12368c2ecf20Sopenharmony_ci ret = dwc3_drd_init(dwc); 12378c2ecf20Sopenharmony_ci if (ret) { 12388c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 12398c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize dual-role\n"); 12408c2ecf20Sopenharmony_ci return ret; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci break; 12438c2ecf20Sopenharmony_ci default: 12448c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); 12458c2ecf20Sopenharmony_ci return -EINVAL; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci return 0; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic void dwc3_core_exit_mode(struct dwc3 *dwc) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci switch (dwc->dr_mode) { 12548c2ecf20Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 12558c2ecf20Sopenharmony_ci dwc3_gadget_exit(dwc); 12568c2ecf20Sopenharmony_ci break; 12578c2ecf20Sopenharmony_ci case USB_DR_MODE_HOST: 12588c2ecf20Sopenharmony_ci dwc3_host_exit(dwc); 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci case USB_DR_MODE_OTG: 12618c2ecf20Sopenharmony_ci dwc3_drd_exit(dwc); 12628c2ecf20Sopenharmony_ci break; 12638c2ecf20Sopenharmony_ci default: 12648c2ecf20Sopenharmony_ci /* do nothing */ 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* de-assert DRVVBUS for HOST and OTG mode */ 12698c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic void dwc3_get_properties(struct dwc3 *dwc) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci struct device *dev = dwc->dev; 12758c2ecf20Sopenharmony_ci u8 lpm_nyet_threshold; 12768c2ecf20Sopenharmony_ci u8 tx_de_emphasis; 12778c2ecf20Sopenharmony_ci u8 hird_threshold; 12788c2ecf20Sopenharmony_ci u8 rx_thr_num_pkt_prd = 0; 12798c2ecf20Sopenharmony_ci u8 rx_max_burst_prd = 0; 12808c2ecf20Sopenharmony_ci u8 tx_thr_num_pkt_prd = 0; 12818c2ecf20Sopenharmony_ci u8 tx_max_burst_prd = 0; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* default to highest possible threshold */ 12848c2ecf20Sopenharmony_ci lpm_nyet_threshold = 0xf; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* default to -3.5dB de-emphasis */ 12878c2ecf20Sopenharmony_ci tx_de_emphasis = 1; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* 12908c2ecf20Sopenharmony_ci * default to assert utmi_sleep_n and use maximum allowed HIRD 12918c2ecf20Sopenharmony_ci * threshold value of 0b1100 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci hird_threshold = 12; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci dwc->maximum_speed = usb_get_maximum_speed(dev); 12968c2ecf20Sopenharmony_ci dwc->dr_mode = usb_get_dr_mode(dev); 12978c2ecf20Sopenharmony_ci dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci dwc->sysdev_is_parent = device_property_read_bool(dev, 13008c2ecf20Sopenharmony_ci "linux,sysdev_is_parent"); 13018c2ecf20Sopenharmony_ci if (dwc->sysdev_is_parent) 13028c2ecf20Sopenharmony_ci dwc->sysdev = dwc->dev->parent; 13038c2ecf20Sopenharmony_ci else 13048c2ecf20Sopenharmony_ci dwc->sysdev = dwc->dev; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci dwc->has_lpm_erratum = device_property_read_bool(dev, 13078c2ecf20Sopenharmony_ci "snps,has-lpm-erratum"); 13088c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,lpm-nyet-threshold", 13098c2ecf20Sopenharmony_ci &lpm_nyet_threshold); 13108c2ecf20Sopenharmony_ci dwc->is_utmi_l1_suspend = device_property_read_bool(dev, 13118c2ecf20Sopenharmony_ci "snps,is-utmi-l1-suspend"); 13128c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,hird-threshold", 13138c2ecf20Sopenharmony_ci &hird_threshold); 13148c2ecf20Sopenharmony_ci dwc->dis_start_transfer_quirk = device_property_read_bool(dev, 13158c2ecf20Sopenharmony_ci "snps,dis-start-transfer-quirk"); 13168c2ecf20Sopenharmony_ci dwc->usb3_lpm_capable = device_property_read_bool(dev, 13178c2ecf20Sopenharmony_ci "snps,usb3_lpm_capable"); 13188c2ecf20Sopenharmony_ci dwc->usb2_lpm_disable = device_property_read_bool(dev, 13198c2ecf20Sopenharmony_ci "snps,usb2-lpm-disable"); 13208c2ecf20Sopenharmony_ci dwc->usb2_gadget_lpm_disable = device_property_read_bool(dev, 13218c2ecf20Sopenharmony_ci "snps,usb2-gadget-lpm-disable"); 13228c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd", 13238c2ecf20Sopenharmony_ci &rx_thr_num_pkt_prd); 13248c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,rx-max-burst-prd", 13258c2ecf20Sopenharmony_ci &rx_max_burst_prd); 13268c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,tx-thr-num-pkt-prd", 13278c2ecf20Sopenharmony_ci &tx_thr_num_pkt_prd); 13288c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,tx-max-burst-prd", 13298c2ecf20Sopenharmony_ci &tx_max_burst_prd); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci dwc->disable_scramble_quirk = device_property_read_bool(dev, 13328c2ecf20Sopenharmony_ci "snps,disable_scramble_quirk"); 13338c2ecf20Sopenharmony_ci dwc->u2exit_lfps_quirk = device_property_read_bool(dev, 13348c2ecf20Sopenharmony_ci "snps,u2exit_lfps_quirk"); 13358c2ecf20Sopenharmony_ci dwc->u2ss_inp3_quirk = device_property_read_bool(dev, 13368c2ecf20Sopenharmony_ci "snps,u2ss_inp3_quirk"); 13378c2ecf20Sopenharmony_ci dwc->req_p1p2p3_quirk = device_property_read_bool(dev, 13388c2ecf20Sopenharmony_ci "snps,req_p1p2p3_quirk"); 13398c2ecf20Sopenharmony_ci dwc->del_p1p2p3_quirk = device_property_read_bool(dev, 13408c2ecf20Sopenharmony_ci "snps,del_p1p2p3_quirk"); 13418c2ecf20Sopenharmony_ci dwc->del_phy_power_chg_quirk = device_property_read_bool(dev, 13428c2ecf20Sopenharmony_ci "snps,del_phy_power_chg_quirk"); 13438c2ecf20Sopenharmony_ci dwc->lfps_filter_quirk = device_property_read_bool(dev, 13448c2ecf20Sopenharmony_ci "snps,lfps_filter_quirk"); 13458c2ecf20Sopenharmony_ci dwc->rx_detect_poll_quirk = device_property_read_bool(dev, 13468c2ecf20Sopenharmony_ci "snps,rx_detect_poll_quirk"); 13478c2ecf20Sopenharmony_ci dwc->dis_u3_susphy_quirk = device_property_read_bool(dev, 13488c2ecf20Sopenharmony_ci "snps,dis_u3_susphy_quirk"); 13498c2ecf20Sopenharmony_ci dwc->dis_u2_susphy_quirk = device_property_read_bool(dev, 13508c2ecf20Sopenharmony_ci "snps,dis_u2_susphy_quirk"); 13518c2ecf20Sopenharmony_ci dwc->dis_enblslpm_quirk = device_property_read_bool(dev, 13528c2ecf20Sopenharmony_ci "snps,dis_enblslpm_quirk"); 13538c2ecf20Sopenharmony_ci dwc->dis_u1_entry_quirk = device_property_read_bool(dev, 13548c2ecf20Sopenharmony_ci "snps,dis-u1-entry-quirk"); 13558c2ecf20Sopenharmony_ci dwc->dis_u2_entry_quirk = device_property_read_bool(dev, 13568c2ecf20Sopenharmony_ci "snps,dis-u2-entry-quirk"); 13578c2ecf20Sopenharmony_ci dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, 13588c2ecf20Sopenharmony_ci "snps,dis_rxdet_inp3_quirk"); 13598c2ecf20Sopenharmony_ci dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev, 13608c2ecf20Sopenharmony_ci "snps,dis-u2-freeclk-exists-quirk"); 13618c2ecf20Sopenharmony_ci dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev, 13628c2ecf20Sopenharmony_ci "snps,dis-del-phy-power-chg-quirk"); 13638c2ecf20Sopenharmony_ci dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev, 13648c2ecf20Sopenharmony_ci "snps,dis-tx-ipgap-linecheck-quirk"); 13658c2ecf20Sopenharmony_ci dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, 13668c2ecf20Sopenharmony_ci "snps,parkmode-disable-ss-quirk"); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, 13698c2ecf20Sopenharmony_ci "snps,tx_de_emphasis_quirk"); 13708c2ecf20Sopenharmony_ci device_property_read_u8(dev, "snps,tx_de_emphasis", 13718c2ecf20Sopenharmony_ci &tx_de_emphasis); 13728c2ecf20Sopenharmony_ci device_property_read_string(dev, "snps,hsphy_interface", 13738c2ecf20Sopenharmony_ci &dwc->hsphy_interface); 13748c2ecf20Sopenharmony_ci device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", 13758c2ecf20Sopenharmony_ci &dwc->fladj); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci dwc->dis_metastability_quirk = device_property_read_bool(dev, 13788c2ecf20Sopenharmony_ci "snps,dis_metastability_quirk"); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci dwc->dis_split_quirk = device_property_read_bool(dev, 13818c2ecf20Sopenharmony_ci "snps,dis-split-quirk"); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci dwc->lpm_nyet_threshold = lpm_nyet_threshold; 13848c2ecf20Sopenharmony_ci dwc->tx_de_emphasis = tx_de_emphasis; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci dwc->hird_threshold = hird_threshold; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd; 13898c2ecf20Sopenharmony_ci dwc->rx_max_burst_prd = rx_max_burst_prd; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; 13928c2ecf20Sopenharmony_ci dwc->tx_max_burst_prd = tx_max_burst_prd; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci dwc->imod_interval = 0; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci/* check whether the core supports IMOD */ 13988c2ecf20Sopenharmony_cibool dwc3_has_imod(struct dwc3 *dwc) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci return DWC3_VER_IS_WITHIN(DWC3, 300A, ANY) || 14018c2ecf20Sopenharmony_ci DWC3_VER_IS_WITHIN(DWC31, 120A, ANY) || 14028c2ecf20Sopenharmony_ci DWC3_IP_IS(DWC32); 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic void dwc3_check_params(struct dwc3 *dwc) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci struct device *dev = dwc->dev; 14088c2ecf20Sopenharmony_ci unsigned int hwparam_gen = 14098c2ecf20Sopenharmony_ci DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci /* Check for proper value of imod_interval */ 14128c2ecf20Sopenharmony_ci if (dwc->imod_interval && !dwc3_has_imod(dwc)) { 14138c2ecf20Sopenharmony_ci dev_warn(dwc->dev, "Interrupt moderation not supported\n"); 14148c2ecf20Sopenharmony_ci dwc->imod_interval = 0; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* 14188c2ecf20Sopenharmony_ci * Workaround for STAR 9000961433 which affects only version 14198c2ecf20Sopenharmony_ci * 3.00a of the DWC_usb3 core. This prevents the controller 14208c2ecf20Sopenharmony_ci * interrupt from being masked while handling events. IMOD 14218c2ecf20Sopenharmony_ci * allows us to work around this issue. Enable it for the 14228c2ecf20Sopenharmony_ci * affected version. 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ci if (!dwc->imod_interval && 14258c2ecf20Sopenharmony_ci DWC3_VER_IS(DWC3, 300A)) 14268c2ecf20Sopenharmony_ci dwc->imod_interval = 1; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* Check the maximum_speed parameter */ 14298c2ecf20Sopenharmony_ci switch (dwc->maximum_speed) { 14308c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 14318c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 14328c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 14338c2ecf20Sopenharmony_ci break; 14348c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 14358c2ecf20Sopenharmony_ci if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) 14368c2ecf20Sopenharmony_ci dev_warn(dev, "UDC doesn't support Gen 1\n"); 14378c2ecf20Sopenharmony_ci break; 14388c2ecf20Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 14398c2ecf20Sopenharmony_ci if ((DWC3_IP_IS(DWC32) && 14408c2ecf20Sopenharmony_ci hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) || 14418c2ecf20Sopenharmony_ci (!DWC3_IP_IS(DWC32) && 14428c2ecf20Sopenharmony_ci hwparam_gen != DWC3_GHWPARAMS3_SSPHY_IFC_GEN2)) 14438c2ecf20Sopenharmony_ci dev_warn(dev, "UDC doesn't support SSP\n"); 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci default: 14468c2ecf20Sopenharmony_ci dev_err(dev, "invalid maximum_speed parameter %d\n", 14478c2ecf20Sopenharmony_ci dwc->maximum_speed); 14488c2ecf20Sopenharmony_ci fallthrough; 14498c2ecf20Sopenharmony_ci case USB_SPEED_UNKNOWN: 14508c2ecf20Sopenharmony_ci switch (hwparam_gen) { 14518c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2: 14528c2ecf20Sopenharmony_ci dwc->maximum_speed = USB_SPEED_SUPER_PLUS; 14538c2ecf20Sopenharmony_ci break; 14548c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1: 14558c2ecf20Sopenharmony_ci if (DWC3_IP_IS(DWC32)) 14568c2ecf20Sopenharmony_ci dwc->maximum_speed = USB_SPEED_SUPER_PLUS; 14578c2ecf20Sopenharmony_ci else 14588c2ecf20Sopenharmony_ci dwc->maximum_speed = USB_SPEED_SUPER; 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci case DWC3_GHWPARAMS3_SSPHY_IFC_DIS: 14618c2ecf20Sopenharmony_ci dwc->maximum_speed = USB_SPEED_HIGH; 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci default: 14648c2ecf20Sopenharmony_ci dwc->maximum_speed = USB_SPEED_SUPER; 14658c2ecf20Sopenharmony_ci break; 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci break; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic int dwc3_probe(struct platform_device *pdev) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 14748c2ecf20Sopenharmony_ci struct resource *res, dwc_res; 14758c2ecf20Sopenharmony_ci struct dwc3 *dwc; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci int ret; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci void __iomem *regs; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); 14828c2ecf20Sopenharmony_ci if (!dwc) 14838c2ecf20Sopenharmony_ci return -ENOMEM; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci dwc->dev = dev; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 14888c2ecf20Sopenharmony_ci if (!res) { 14898c2ecf20Sopenharmony_ci dev_err(dev, "missing memory resource\n"); 14908c2ecf20Sopenharmony_ci return -ENODEV; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci dwc->xhci_resources[0].start = res->start; 14948c2ecf20Sopenharmony_ci dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + 14958c2ecf20Sopenharmony_ci DWC3_XHCI_REGS_END; 14968c2ecf20Sopenharmony_ci dwc->xhci_resources[0].flags = res->flags; 14978c2ecf20Sopenharmony_ci dwc->xhci_resources[0].name = res->name; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* 15008c2ecf20Sopenharmony_ci * Request memory region but exclude xHCI regs, 15018c2ecf20Sopenharmony_ci * since it will be requested by the xhci-plat driver. 15028c2ecf20Sopenharmony_ci */ 15038c2ecf20Sopenharmony_ci dwc_res = *res; 15048c2ecf20Sopenharmony_ci dwc_res.start += DWC3_GLOBALS_REGS_START; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci regs = devm_ioremap_resource(dev, &dwc_res); 15078c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 15088c2ecf20Sopenharmony_ci return PTR_ERR(regs); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci dwc->regs = regs; 15118c2ecf20Sopenharmony_ci dwc->regs_size = resource_size(&dwc_res); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci dwc3_get_properties(dwc); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci dwc->reset = devm_reset_control_array_get(dev, true, true); 15168c2ecf20Sopenharmony_ci if (IS_ERR(dwc->reset)) 15178c2ecf20Sopenharmony_ci return PTR_ERR(dwc->reset); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (dev->of_node) { 15208c2ecf20Sopenharmony_ci ret = devm_clk_bulk_get_all(dev, &dwc->clks); 15218c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 15228c2ecf20Sopenharmony_ci return ret; 15238c2ecf20Sopenharmony_ci /* 15248c2ecf20Sopenharmony_ci * Clocks are optional, but new DT platforms should support all 15258c2ecf20Sopenharmony_ci * clocks as required by the DT-binding. 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ci if (ret < 0) 15288c2ecf20Sopenharmony_ci dwc->num_clks = 0; 15298c2ecf20Sopenharmony_ci else 15308c2ecf20Sopenharmony_ci dwc->num_clks = ret; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci ret = reset_control_deassert(dwc->reset); 15358c2ecf20Sopenharmony_ci if (ret) 15368c2ecf20Sopenharmony_ci return ret; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks); 15398c2ecf20Sopenharmony_ci if (ret) 15408c2ecf20Sopenharmony_ci goto assert_reset; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (!dwc3_core_is_valid(dwc)) { 15438c2ecf20Sopenharmony_ci dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); 15448c2ecf20Sopenharmony_ci ret = -ENODEV; 15458c2ecf20Sopenharmony_ci goto disable_clks; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dwc); 15498c2ecf20Sopenharmony_ci dwc3_cache_hwparams(dwc); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci spin_lock_init(&dwc->lock); 15528c2ecf20Sopenharmony_ci mutex_init(&dwc->mutex); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci pm_runtime_get_noresume(dev); 15558c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 15568c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 15578c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); 15588c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci pm_runtime_forbid(dev); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 15638c2ecf20Sopenharmony_ci if (ret) { 15648c2ecf20Sopenharmony_ci dev_err(dwc->dev, "failed to allocate event buffers\n"); 15658c2ecf20Sopenharmony_ci ret = -ENOMEM; 15668c2ecf20Sopenharmony_ci goto err2; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci ret = dwc3_get_dr_mode(dwc); 15708c2ecf20Sopenharmony_ci if (ret) 15718c2ecf20Sopenharmony_ci goto err3; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci ret = dwc3_alloc_scratch_buffers(dwc); 15748c2ecf20Sopenharmony_ci if (ret) 15758c2ecf20Sopenharmony_ci goto err3; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci ret = dwc3_core_init(dwc); 15788c2ecf20Sopenharmony_ci if (ret) { 15798c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 15808c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize core: %d\n", ret); 15818c2ecf20Sopenharmony_ci goto err4; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci dwc3_check_params(dwc); 15858c2ecf20Sopenharmony_ci dwc3_debugfs_init(dwc); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci ret = dwc3_core_init_mode(dwc); 15888c2ecf20Sopenharmony_ci if (ret) 15898c2ecf20Sopenharmony_ci goto err5; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci pm_runtime_put(dev); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci dma_set_max_seg_size(dev, UINT_MAX); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci return 0; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cierr5: 15988c2ecf20Sopenharmony_ci dwc3_debugfs_exit(dwc); 15998c2ecf20Sopenharmony_ci dwc3_event_buffers_cleanup(dwc); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb2_phy, 1); 16028c2ecf20Sopenharmony_ci usb_phy_set_suspend(dwc->usb3_phy, 1); 16038c2ecf20Sopenharmony_ci phy_power_off(dwc->usb2_generic_phy); 16048c2ecf20Sopenharmony_ci phy_power_off(dwc->usb3_generic_phy); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci usb_phy_shutdown(dwc->usb2_phy); 16078c2ecf20Sopenharmony_ci usb_phy_shutdown(dwc->usb3_phy); 16088c2ecf20Sopenharmony_ci phy_exit(dwc->usb2_generic_phy); 16098c2ecf20Sopenharmony_ci phy_exit(dwc->usb3_generic_phy); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci dwc3_ulpi_exit(dwc); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cierr4: 16148c2ecf20Sopenharmony_ci dwc3_free_scratch_buffers(dwc); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_cierr3: 16178c2ecf20Sopenharmony_ci dwc3_free_event_buffers(dwc); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cierr2: 16208c2ecf20Sopenharmony_ci pm_runtime_allow(dev); 16218c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 16228c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 16238c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 16248c2ecf20Sopenharmony_cidisable_clks: 16258c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); 16268c2ecf20Sopenharmony_ciassert_reset: 16278c2ecf20Sopenharmony_ci reset_control_assert(dwc->reset); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return ret; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic int dwc3_remove(struct platform_device *pdev) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct dwc3 *dwc = platform_get_drvdata(pdev); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci dwc3_core_exit_mode(dwc); 16398c2ecf20Sopenharmony_ci dwc3_debugfs_exit(dwc); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci dwc3_core_exit(dwc); 16428c2ecf20Sopenharmony_ci dwc3_ulpi_exit(dwc); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci pm_runtime_allow(&pdev->dev); 16458c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 16468c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 16478c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci dwc3_free_event_buffers(dwc); 16508c2ecf20Sopenharmony_ci dwc3_free_scratch_buffers(dwc); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci return 0; 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16568c2ecf20Sopenharmony_cistatic int dwc3_core_init_for_resume(struct dwc3 *dwc) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci int ret; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci ret = reset_control_deassert(dwc->reset); 16618c2ecf20Sopenharmony_ci if (ret) 16628c2ecf20Sopenharmony_ci return ret; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks); 16658c2ecf20Sopenharmony_ci if (ret) 16668c2ecf20Sopenharmony_ci goto assert_reset; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci ret = dwc3_core_init(dwc); 16698c2ecf20Sopenharmony_ci if (ret) 16708c2ecf20Sopenharmony_ci goto disable_clks; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci return 0; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_cidisable_clks: 16758c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); 16768c2ecf20Sopenharmony_ciassert_reset: 16778c2ecf20Sopenharmony_ci reset_control_assert(dwc->reset); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci return ret; 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci unsigned long flags; 16858c2ecf20Sopenharmony_ci u32 reg; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci switch (dwc->current_dr_role) { 16888c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 16898c2ecf20Sopenharmony_ci if (pm_runtime_suspended(dwc->dev)) 16908c2ecf20Sopenharmony_ci break; 16918c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 16928c2ecf20Sopenharmony_ci dwc3_gadget_suspend(dwc); 16938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 16948c2ecf20Sopenharmony_ci synchronize_irq(dwc->irq_gadget); 16958c2ecf20Sopenharmony_ci dwc3_core_exit(dwc); 16968c2ecf20Sopenharmony_ci break; 16978c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 16988c2ecf20Sopenharmony_ci if (!PMSG_IS_AUTO(msg)) { 16998c2ecf20Sopenharmony_ci dwc3_core_exit(dwc); 17008c2ecf20Sopenharmony_ci break; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci /* Let controller to suspend HSPHY before PHY driver suspends */ 17048c2ecf20Sopenharmony_ci if (dwc->dis_u2_susphy_quirk || 17058c2ecf20Sopenharmony_ci dwc->dis_enblslpm_quirk) { 17068c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 17078c2ecf20Sopenharmony_ci reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | 17088c2ecf20Sopenharmony_ci DWC3_GUSB2PHYCFG_SUSPHY; 17098c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci /* Give some time for USB2 PHY to suspend */ 17128c2ecf20Sopenharmony_ci usleep_range(5000, 6000); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci phy_pm_runtime_put_sync(dwc->usb2_generic_phy); 17168c2ecf20Sopenharmony_ci phy_pm_runtime_put_sync(dwc->usb3_generic_phy); 17178c2ecf20Sopenharmony_ci break; 17188c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_OTG: 17198c2ecf20Sopenharmony_ci /* do nothing during runtime_suspend */ 17208c2ecf20Sopenharmony_ci if (PMSG_IS_AUTO(msg)) 17218c2ecf20Sopenharmony_ci break; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) { 17248c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 17258c2ecf20Sopenharmony_ci dwc3_gadget_suspend(dwc); 17268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 17278c2ecf20Sopenharmony_ci synchronize_irq(dwc->irq_gadget); 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci dwc3_otg_exit(dwc); 17318c2ecf20Sopenharmony_ci dwc3_core_exit(dwc); 17328c2ecf20Sopenharmony_ci break; 17338c2ecf20Sopenharmony_ci default: 17348c2ecf20Sopenharmony_ci /* do nothing */ 17358c2ecf20Sopenharmony_ci break; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci return 0; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_cistatic int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) 17428c2ecf20Sopenharmony_ci{ 17438c2ecf20Sopenharmony_ci unsigned long flags; 17448c2ecf20Sopenharmony_ci int ret; 17458c2ecf20Sopenharmony_ci u32 reg; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci switch (dwc->current_dr_role) { 17488c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 17498c2ecf20Sopenharmony_ci ret = dwc3_core_init_for_resume(dwc); 17508c2ecf20Sopenharmony_ci if (ret) 17518c2ecf20Sopenharmony_ci return ret; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); 17548c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 17558c2ecf20Sopenharmony_ci dwc3_gadget_resume(dwc); 17568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 17578c2ecf20Sopenharmony_ci break; 17588c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 17598c2ecf20Sopenharmony_ci if (!PMSG_IS_AUTO(msg)) { 17608c2ecf20Sopenharmony_ci ret = dwc3_core_init_for_resume(dwc); 17618c2ecf20Sopenharmony_ci if (ret) 17628c2ecf20Sopenharmony_ci return ret; 17638c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci /* Restore GUSB2PHYCFG bits that were modified in suspend */ 17678c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 17688c2ecf20Sopenharmony_ci if (dwc->dis_u2_susphy_quirk) 17698c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci if (dwc->dis_enblslpm_quirk) 17728c2ecf20Sopenharmony_ci reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci phy_pm_runtime_get_sync(dwc->usb2_generic_phy); 17778c2ecf20Sopenharmony_ci phy_pm_runtime_get_sync(dwc->usb3_generic_phy); 17788c2ecf20Sopenharmony_ci break; 17798c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_OTG: 17808c2ecf20Sopenharmony_ci /* nothing to do on runtime_resume */ 17818c2ecf20Sopenharmony_ci if (PMSG_IS_AUTO(msg)) 17828c2ecf20Sopenharmony_ci break; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci ret = dwc3_core_init_for_resume(dwc); 17858c2ecf20Sopenharmony_ci if (ret) 17868c2ecf20Sopenharmony_ci return ret; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci dwc3_set_prtcap(dwc, dwc->current_dr_role); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci dwc3_otg_init(dwc); 17918c2ecf20Sopenharmony_ci if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) { 17928c2ecf20Sopenharmony_ci dwc3_otg_host_init(dwc); 17938c2ecf20Sopenharmony_ci } else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) { 17948c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 17958c2ecf20Sopenharmony_ci dwc3_gadget_resume(dwc); 17968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci default: 18018c2ecf20Sopenharmony_ci /* do nothing */ 18028c2ecf20Sopenharmony_ci break; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci return 0; 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cistatic int dwc3_runtime_checks(struct dwc3 *dwc) 18098c2ecf20Sopenharmony_ci{ 18108c2ecf20Sopenharmony_ci switch (dwc->current_dr_role) { 18118c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 18128c2ecf20Sopenharmony_ci if (dwc->connected) 18138c2ecf20Sopenharmony_ci return -EBUSY; 18148c2ecf20Sopenharmony_ci break; 18158c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 18168c2ecf20Sopenharmony_ci default: 18178c2ecf20Sopenharmony_ci /* do nothing */ 18188c2ecf20Sopenharmony_ci break; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci return 0; 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic int dwc3_runtime_suspend(struct device *dev) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci struct dwc3 *dwc = dev_get_drvdata(dev); 18278c2ecf20Sopenharmony_ci int ret; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (dwc3_runtime_checks(dwc)) 18308c2ecf20Sopenharmony_ci return -EBUSY; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND); 18338c2ecf20Sopenharmony_ci if (ret) 18348c2ecf20Sopenharmony_ci return ret; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci device_init_wakeup(dev, true); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci return 0; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic int dwc3_runtime_resume(struct device *dev) 18428c2ecf20Sopenharmony_ci{ 18438c2ecf20Sopenharmony_ci struct dwc3 *dwc = dev_get_drvdata(dev); 18448c2ecf20Sopenharmony_ci int ret; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci device_init_wakeup(dev, false); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); 18498c2ecf20Sopenharmony_ci if (ret) 18508c2ecf20Sopenharmony_ci return ret; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci switch (dwc->current_dr_role) { 18538c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 18548c2ecf20Sopenharmony_ci dwc3_gadget_process_pending_events(dwc); 18558c2ecf20Sopenharmony_ci break; 18568c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 18578c2ecf20Sopenharmony_ci default: 18588c2ecf20Sopenharmony_ci /* do nothing */ 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci return 0; 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int dwc3_runtime_idle(struct device *dev) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci struct dwc3 *dwc = dev_get_drvdata(dev); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci switch (dwc->current_dr_role) { 18728c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_DEVICE: 18738c2ecf20Sopenharmony_ci if (dwc3_runtime_checks(dwc)) 18748c2ecf20Sopenharmony_ci return -EBUSY; 18758c2ecf20Sopenharmony_ci break; 18768c2ecf20Sopenharmony_ci case DWC3_GCTL_PRTCAP_HOST: 18778c2ecf20Sopenharmony_ci default: 18788c2ecf20Sopenharmony_ci /* do nothing */ 18798c2ecf20Sopenharmony_ci break; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 18838c2ecf20Sopenharmony_ci pm_runtime_autosuspend(dev); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci return 0; 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 18908c2ecf20Sopenharmony_cistatic int dwc3_suspend(struct device *dev) 18918c2ecf20Sopenharmony_ci{ 18928c2ecf20Sopenharmony_ci struct dwc3 *dwc = dev_get_drvdata(dev); 18938c2ecf20Sopenharmony_ci int ret; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); 18968c2ecf20Sopenharmony_ci if (ret) 18978c2ecf20Sopenharmony_ci return ret; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci return 0; 19028c2ecf20Sopenharmony_ci} 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_cistatic int dwc3_resume(struct device *dev) 19058c2ecf20Sopenharmony_ci{ 19068c2ecf20Sopenharmony_ci struct dwc3 *dwc = dev_get_drvdata(dev); 19078c2ecf20Sopenharmony_ci int ret; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci ret = dwc3_resume_common(dwc, PMSG_RESUME); 19128c2ecf20Sopenharmony_ci if (ret) 19138c2ecf20Sopenharmony_ci return ret; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 19168c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 19178c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci return 0; 19208c2ecf20Sopenharmony_ci} 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_cistatic void dwc3_complete(struct device *dev) 19238c2ecf20Sopenharmony_ci{ 19248c2ecf20Sopenharmony_ci struct dwc3 *dwc = dev_get_drvdata(dev); 19258c2ecf20Sopenharmony_ci u32 reg; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST && 19288c2ecf20Sopenharmony_ci dwc->dis_split_quirk) { 19298c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); 19308c2ecf20Sopenharmony_ci reg |= DWC3_GUCTL3_SPLITDISABLE; 19318c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_ci#else 19358c2ecf20Sopenharmony_ci#define dwc3_complete NULL 19368c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dwc3_dev_pm_ops = { 19398c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) 19408c2ecf20Sopenharmony_ci .complete = dwc3_complete, 19418c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume, 19428c2ecf20Sopenharmony_ci dwc3_runtime_idle) 19438c2ecf20Sopenharmony_ci}; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 19468c2ecf20Sopenharmony_cistatic const struct of_device_id of_dwc3_match[] = { 19478c2ecf20Sopenharmony_ci { 19488c2ecf20Sopenharmony_ci .compatible = "snps,dwc3" 19498c2ecf20Sopenharmony_ci }, 19508c2ecf20Sopenharmony_ci { 19518c2ecf20Sopenharmony_ci .compatible = "synopsys,dwc3" 19528c2ecf20Sopenharmony_ci }, 19538c2ecf20Sopenharmony_ci { }, 19548c2ecf20Sopenharmony_ci}; 19558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_dwc3_match); 19568c2ecf20Sopenharmony_ci#endif 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci#define ACPI_ID_INTEL_BSW "808622B7" 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_cistatic const struct acpi_device_id dwc3_acpi_match[] = { 19638c2ecf20Sopenharmony_ci { ACPI_ID_INTEL_BSW, 0 }, 19648c2ecf20Sopenharmony_ci { }, 19658c2ecf20Sopenharmony_ci}; 19668c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); 19678c2ecf20Sopenharmony_ci#endif 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cistatic struct platform_driver dwc3_driver = { 19708c2ecf20Sopenharmony_ci .probe = dwc3_probe, 19718c2ecf20Sopenharmony_ci .remove = dwc3_remove, 19728c2ecf20Sopenharmony_ci .driver = { 19738c2ecf20Sopenharmony_ci .name = "dwc3", 19748c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(of_dwc3_match), 19758c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(dwc3_acpi_match), 19768c2ecf20Sopenharmony_ci .pm = &dwc3_dev_pm_ops, 19778c2ecf20Sopenharmony_ci }, 19788c2ecf20Sopenharmony_ci}; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cimodule_platform_driver(dwc3_driver); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:dwc3"); 19838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 19848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 19858c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); 1986