18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * core.c - DesignWare HS OTG Controller common routines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 148c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 158c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 168c2ecf20Sopenharmony_ci * 3. The names of the above-listed copyright holders may not be used 178c2ecf20Sopenharmony_ci * to endorse or promote products derived from this software without 188c2ecf20Sopenharmony_ci * specific prior written permission. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 228c2ecf20Sopenharmony_ci * Foundation; either version 2 of the License, or (at your option) any 238c2ecf20Sopenharmony_ci * later version. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 268c2ecf20Sopenharmony_ci * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 278c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 288c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 298c2ecf20Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 308c2ecf20Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 318c2ecf20Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 328c2ecf20Sopenharmony_ci * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 338c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 348c2ecf20Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 358c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * The Core code provides basic services for accessing and managing the 408c2ecf20Sopenharmony_ci * DWC_otg hardware. These services are used by both the Host Controller 418c2ecf20Sopenharmony_ci * Driver and the Peripheral Controller Driver. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci#include <linux/kernel.h> 448c2ecf20Sopenharmony_ci#include <linux/module.h> 458c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 468c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 478c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 488c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 498c2ecf20Sopenharmony_ci#include <linux/delay.h> 508c2ecf20Sopenharmony_ci#include <linux/io.h> 518c2ecf20Sopenharmony_ci#include <linux/slab.h> 528c2ecf20Sopenharmony_ci#include <linux/usb.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 558c2ecf20Sopenharmony_ci#include <linux/usb/ch11.h> 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include "core.h" 588c2ecf20Sopenharmony_ci#include "hcd.h" 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/** 618c2ecf20Sopenharmony_ci * dwc2_backup_global_registers() - Backup global controller registers. 628c2ecf20Sopenharmony_ci * When suspending usb bus, registers needs to be backuped 638c2ecf20Sopenharmony_ci * if controller power is disabled once suspended. 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ciint dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct dwc2_gregs_backup *gr; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Backup global regs */ 748c2ecf20Sopenharmony_ci gr = &hsotg->gr_backup; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci gr->gotgctl = dwc2_readl(hsotg, GOTGCTL); 778c2ecf20Sopenharmony_ci gr->gintmsk = dwc2_readl(hsotg, GINTMSK); 788c2ecf20Sopenharmony_ci gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG); 798c2ecf20Sopenharmony_ci gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG); 808c2ecf20Sopenharmony_ci gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ); 818c2ecf20Sopenharmony_ci gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ); 828c2ecf20Sopenharmony_ci gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG); 838c2ecf20Sopenharmony_ci gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); 848c2ecf20Sopenharmony_ci gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); 858c2ecf20Sopenharmony_ci gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); 868c2ecf20Sopenharmony_ci gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci gr->valid = true; 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/** 938c2ecf20Sopenharmony_ci * dwc2_restore_global_registers() - Restore controller global registers. 948c2ecf20Sopenharmony_ci * When resuming usb bus, device registers needs to be restored 958c2ecf20Sopenharmony_ci * if controller power were disabled. 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ciint dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct dwc2_gregs_backup *gr; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Restore global regs */ 1068c2ecf20Sopenharmony_ci gr = &hsotg->gr_backup; 1078c2ecf20Sopenharmony_ci if (!gr->valid) { 1088c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: no global registers to restore\n", 1098c2ecf20Sopenharmony_ci __func__); 1108c2ecf20Sopenharmony_ci return -EINVAL; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci gr->valid = false; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 1158c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gotgctl, GOTGCTL); 1168c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gintmsk, GINTMSK); 1178c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 1188c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); 1198c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); 1208c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); 1218c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); 1228c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); 1238c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); 1248c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); 1258c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/** 1318c2ecf20Sopenharmony_ci * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 1348c2ecf20Sopenharmony_ci * @restore: Controller registers need to be restored 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ciint dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci u32 pcgcctl; 1398c2ecf20Sopenharmony_ci int ret = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) 1428c2ecf20Sopenharmony_ci return -ENOTSUPP; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 1458c2ecf20Sopenharmony_ci pcgcctl &= ~PCGCTL_STOPPCLK; 1468c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 1498c2ecf20Sopenharmony_ci pcgcctl &= ~PCGCTL_PWRCLMP; 1508c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 1538c2ecf20Sopenharmony_ci pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 1548c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci udelay(100); 1578c2ecf20Sopenharmony_ci if (restore) { 1588c2ecf20Sopenharmony_ci ret = dwc2_restore_global_registers(hsotg); 1598c2ecf20Sopenharmony_ci if (ret) { 1608c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore registers\n", 1618c2ecf20Sopenharmony_ci __func__); 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) { 1658c2ecf20Sopenharmony_ci ret = dwc2_restore_host_registers(hsotg); 1668c2ecf20Sopenharmony_ci if (ret) { 1678c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore host registers\n", 1688c2ecf20Sopenharmony_ci __func__); 1698c2ecf20Sopenharmony_ci return ret; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci ret = dwc2_restore_device_registers(hsotg, 0); 1738c2ecf20Sopenharmony_ci if (ret) { 1748c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore device registers\n", 1758c2ecf20Sopenharmony_ci __func__); 1768c2ecf20Sopenharmony_ci return ret; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/** 1858c2ecf20Sopenharmony_ci * dwc2_enter_partial_power_down() - Put controller in Partial Power Down. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ciint dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci u32 pcgcctl; 1928c2ecf20Sopenharmony_ci int ret = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!hsotg->params.power_down) 1958c2ecf20Sopenharmony_ci return -ENOTSUPP; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Backup all registers */ 1988c2ecf20Sopenharmony_ci ret = dwc2_backup_global_registers(hsotg); 1998c2ecf20Sopenharmony_ci if (ret) { 2008c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup global registers\n", 2018c2ecf20Sopenharmony_ci __func__); 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) { 2068c2ecf20Sopenharmony_ci ret = dwc2_backup_host_registers(hsotg); 2078c2ecf20Sopenharmony_ci if (ret) { 2088c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup host registers\n", 2098c2ecf20Sopenharmony_ci __func__); 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci ret = dwc2_backup_device_registers(hsotg); 2148c2ecf20Sopenharmony_ci if (ret) { 2158c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup device registers\n", 2168c2ecf20Sopenharmony_ci __func__); 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * Clear any pending interrupts since dwc2 will not be able to 2238c2ecf20Sopenharmony_ci * clear them after entering partial_power_down. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Put the controller in low power state */ 2288c2ecf20Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_PWRCLMP; 2318c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 2328c2ecf20Sopenharmony_ci ndelay(20); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_RSTPDWNMODULE; 2358c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 2368c2ecf20Sopenharmony_ci ndelay(20); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_STOPPCLK; 2398c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * dwc2_restore_essential_regs() - Restore essiential regs of core. 2468c2ecf20Sopenharmony_ci * 2478c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 2488c2ecf20Sopenharmony_ci * @rmode: Restore mode, enabled in case of remote-wakeup. 2498c2ecf20Sopenharmony_ci * @is_host: Host or device mode. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, 2528c2ecf20Sopenharmony_ci int is_host) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci u32 pcgcctl; 2558c2ecf20Sopenharmony_ci struct dwc2_gregs_backup *gr; 2568c2ecf20Sopenharmony_ci struct dwc2_dregs_backup *dr; 2578c2ecf20Sopenharmony_ci struct dwc2_hregs_backup *hr; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci gr = &hsotg->gr_backup; 2608c2ecf20Sopenharmony_ci dr = &hsotg->dr_backup; 2618c2ecf20Sopenharmony_ci hr = &hsotg->hr_backup; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Load restore values for [31:14] bits */ 2668c2ecf20Sopenharmony_ci pcgcctl = (gr->pcgcctl & 0xffffc000); 2678c2ecf20Sopenharmony_ci /* If High Speed */ 2688c2ecf20Sopenharmony_ci if (is_host) { 2698c2ecf20Sopenharmony_ci if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK)) 2708c2ecf20Sopenharmony_ci pcgcctl |= BIT(17); 2718c2ecf20Sopenharmony_ci } else { 2728c2ecf20Sopenharmony_ci if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK)) 2738c2ecf20Sopenharmony_ci pcgcctl |= BIT(17); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Umnask global Interrupt in GAHBCFG and restore it */ 2788c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Clear all pending interupts */ 2818c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Unmask restore done interrupt */ 2848c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Restore GUSBCFG and HCFG/DCFG */ 2878c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (is_host) { 2908c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hr->hcfg, HCFG); 2918c2ecf20Sopenharmony_ci if (rmode) 2928c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_RESTOREMODE; 2938c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 2948c2ecf20Sopenharmony_ci udelay(10); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_ESS_REG_RESTORED; 2978c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 2988c2ecf20Sopenharmony_ci udelay(10); 2998c2ecf20Sopenharmony_ci } else { 3008c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dcfg, DCFG); 3018c2ecf20Sopenharmony_ci if (!rmode) 3028c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE; 3038c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 3048c2ecf20Sopenharmony_ci udelay(10); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci pcgcctl |= PCGCTL_ESS_REG_RESTORED; 3078c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 3088c2ecf20Sopenharmony_ci udelay(10); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/** 3138c2ecf20Sopenharmony_ci * dwc2_hib_restore_common() - Common part of restore routine. 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 3168c2ecf20Sopenharmony_ci * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 3178c2ecf20Sopenharmony_ci * @is_host: Host or device mode. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_civoid dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, 3208c2ecf20Sopenharmony_ci int is_host) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u32 gpwrdn; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Switch-on voltage to the core */ 3258c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 3268c2ecf20Sopenharmony_ci gpwrdn &= ~GPWRDN_PWRDNSWTCH; 3278c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 3288c2ecf20Sopenharmony_ci udelay(10); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Reset core */ 3318c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 3328c2ecf20Sopenharmony_ci gpwrdn &= ~GPWRDN_PWRDNRSTN; 3338c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 3348c2ecf20Sopenharmony_ci udelay(10); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Enable restore from PMU */ 3378c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 3388c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_RESTORE; 3398c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 3408c2ecf20Sopenharmony_ci udelay(10); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Disable Power Down Clamp */ 3438c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 3448c2ecf20Sopenharmony_ci gpwrdn &= ~GPWRDN_PWRDNCLMP; 3458c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 3468c2ecf20Sopenharmony_ci udelay(50); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!is_host && rem_wakeup) 3498c2ecf20Sopenharmony_ci udelay(70); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Deassert reset core */ 3528c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 3538c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_PWRDNRSTN; 3548c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 3558c2ecf20Sopenharmony_ci udelay(10); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Disable PMU interrupt */ 3588c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 3598c2ecf20Sopenharmony_ci gpwrdn &= ~GPWRDN_PMUINTSEL; 3608c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 3618c2ecf20Sopenharmony_ci udelay(10); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Set Restore Essential Regs bit in PCGCCTL register */ 3648c2ecf20Sopenharmony_ci dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* 3678c2ecf20Sopenharmony_ci * Wait For Restore_done Interrupt. This mechanism of polling the 3688c2ecf20Sopenharmony_ci * interrupt is introduced to avoid any possible race conditions 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE, 3718c2ecf20Sopenharmony_ci 20000)) { 3728c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 3738c2ecf20Sopenharmony_ci "%s: Restore Done wan't generated here\n", 3748c2ecf20Sopenharmony_ci __func__); 3758c2ecf20Sopenharmony_ci } else { 3768c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "restore done generated here\n"); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/** 3818c2ecf20Sopenharmony_ci * dwc2_wait_for_mode() - Waits for the controller mode. 3828c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller. 3838c2ecf20Sopenharmony_ci * @host_mode: If true, waits for host mode, otherwise device mode. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_cistatic void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, 3868c2ecf20Sopenharmony_ci bool host_mode) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci ktime_t start; 3898c2ecf20Sopenharmony_ci ktime_t end; 3908c2ecf20Sopenharmony_ci unsigned int timeout = 110; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "Waiting for %s mode\n", 3938c2ecf20Sopenharmony_ci host_mode ? "host" : "device"); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci start = ktime_get(); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci while (1) { 3988c2ecf20Sopenharmony_ci s64 ms; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (dwc2_is_host_mode(hsotg) == host_mode) { 4018c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s mode set\n", 4028c2ecf20Sopenharmony_ci host_mode ? "Host" : "Device"); 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci end = ktime_get(); 4078c2ecf20Sopenharmony_ci ms = ktime_to_ms(ktime_sub(end, start)); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (ms >= (s64)timeout) { 4108c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n", 4118c2ecf20Sopenharmony_ci __func__, host_mode ? "host" : "device"); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/** 4208c2ecf20Sopenharmony_ci * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce 4218c2ecf20Sopenharmony_ci * filter is enabled. 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_cistatic bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci u32 gsnpsid; 4288c2ecf20Sopenharmony_ci u32 ghwcfg4; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 4318c2ecf20Sopenharmony_ci return false; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Check if core configuration includes the IDDIG filter. */ 4348c2ecf20Sopenharmony_ci ghwcfg4 = dwc2_readl(hsotg, GHWCFG4); 4358c2ecf20Sopenharmony_ci if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN)) 4368c2ecf20Sopenharmony_ci return false; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* 4398c2ecf20Sopenharmony_ci * Check if the IDDIG debounce filter is bypassed. Available 4408c2ecf20Sopenharmony_ci * in core version >= 3.10a. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ci gsnpsid = dwc2_readl(hsotg, GSNPSID); 4438c2ecf20Sopenharmony_ci if (gsnpsid >= DWC2_CORE_REV_3_10a) { 4448c2ecf20Sopenharmony_ci u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS) 4478c2ecf20Sopenharmony_ci return false; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return true; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* 4548c2ecf20Sopenharmony_ci * dwc2_enter_hibernation() - Common function to enter hibernation. 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 4578c2ecf20Sopenharmony_ci * @is_host: True if core is in host mode. 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ciint dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION) 4648c2ecf20Sopenharmony_ci return -ENOTSUPP; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (is_host) 4678c2ecf20Sopenharmony_ci return dwc2_host_enter_hibernation(hsotg); 4688c2ecf20Sopenharmony_ci else 4698c2ecf20Sopenharmony_ci return dwc2_gadget_enter_hibernation(hsotg); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* 4738c2ecf20Sopenharmony_ci * dwc2_exit_hibernation() - Common function to exit from hibernation. 4748c2ecf20Sopenharmony_ci * 4758c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 4768c2ecf20Sopenharmony_ci * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 4778c2ecf20Sopenharmony_ci * @reset: Enabled in case of restore with reset. 4788c2ecf20Sopenharmony_ci * @is_host: True if core is in host mode. 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ciint dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, 4838c2ecf20Sopenharmony_ci int reset, int is_host) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci if (is_host) 4868c2ecf20Sopenharmony_ci return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset); 4878c2ecf20Sopenharmony_ci else 4888c2ecf20Sopenharmony_ci return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci/* 4928c2ecf20Sopenharmony_ci * Do core a soft reset of the core. Be careful with this because it 4938c2ecf20Sopenharmony_ci * resets all the internal state machines of the core. 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_ciint dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci u32 greset; 4988c2ecf20Sopenharmony_ci bool wait_for_host_mode = false; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * If the current mode is host, either due to the force mode 5048c2ecf20Sopenharmony_ci * bit being set (which persists after core reset) or the 5058c2ecf20Sopenharmony_ci * connector id pin, a core soft reset will temporarily reset 5068c2ecf20Sopenharmony_ci * the mode to device. A delay from the IDDIG debounce filter 5078c2ecf20Sopenharmony_ci * will occur before going back to host mode. 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * Determine whether we will go back into host mode after a 5108c2ecf20Sopenharmony_ci * reset and account for this delay after the reset. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci if (dwc2_iddig_filter_enabled(hsotg)) { 5138c2ecf20Sopenharmony_ci u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 5148c2ecf20Sopenharmony_ci u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (!(gotgctl & GOTGCTL_CONID_B) || 5178c2ecf20Sopenharmony_ci (gusbcfg & GUSBCFG_FORCEHOSTMODE)) { 5188c2ecf20Sopenharmony_ci wait_for_host_mode = true; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* Core Soft Reset */ 5238c2ecf20Sopenharmony_ci greset = dwc2_readl(hsotg, GRSTCTL); 5248c2ecf20Sopenharmony_ci greset |= GRSTCTL_CSFTRST; 5258c2ecf20Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) < 5288c2ecf20Sopenharmony_ci (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) { 5298c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, 5308c2ecf20Sopenharmony_ci GRSTCTL_CSFTRST, 10000)) { 5318c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n", 5328c2ecf20Sopenharmony_ci __func__); 5338c2ecf20Sopenharmony_ci return -EBUSY; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci } else { 5368c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, 5378c2ecf20Sopenharmony_ci GRSTCTL_CSFTRST_DONE, 10000)) { 5388c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n", 5398c2ecf20Sopenharmony_ci __func__); 5408c2ecf20Sopenharmony_ci return -EBUSY; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci greset = dwc2_readl(hsotg, GRSTCTL); 5438c2ecf20Sopenharmony_ci greset &= ~GRSTCTL_CSFTRST; 5448c2ecf20Sopenharmony_ci greset |= GRSTCTL_CSFTRST_DONE; 5458c2ecf20Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Wait for AHB master IDLE state */ 5498c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) { 5508c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n", 5518c2ecf20Sopenharmony_ci __func__); 5528c2ecf20Sopenharmony_ci return -EBUSY; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (wait_for_host_mode && !skip_wait) 5568c2ecf20Sopenharmony_ci dwc2_wait_for_mode(hsotg, true); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/** 5628c2ecf20Sopenharmony_ci * dwc2_force_mode() - Force the mode of the controller. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * Forcing the mode is needed for two cases: 5658c2ecf20Sopenharmony_ci * 5668c2ecf20Sopenharmony_ci * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the 5678c2ecf20Sopenharmony_ci * controller to stay in a particular mode regardless of ID pin 5688c2ecf20Sopenharmony_ci * changes. We do this once during probe. 5698c2ecf20Sopenharmony_ci * 5708c2ecf20Sopenharmony_ci * 2) During probe we want to read reset values of the hw 5718c2ecf20Sopenharmony_ci * configuration registers that are only available in either host or 5728c2ecf20Sopenharmony_ci * device mode. We may need to force the mode if the current mode does 5738c2ecf20Sopenharmony_ci * not allow us to access the register in the mode that we want. 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * In either case it only makes sense to force the mode if the 5768c2ecf20Sopenharmony_ci * controller hardware is OTG capable. 5778c2ecf20Sopenharmony_ci * 5788c2ecf20Sopenharmony_ci * Checks are done in this function to determine whether doing a force 5798c2ecf20Sopenharmony_ci * would be valid or not. 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * If a force is done, it requires a IDDIG debounce filter delay if 5828c2ecf20Sopenharmony_ci * the filter is configured and enabled. We poll the current mode of 5838c2ecf20Sopenharmony_ci * the controller to account for this delay. 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 5868c2ecf20Sopenharmony_ci * @host: Host mode flag 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_civoid dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci u32 gusbcfg; 5918c2ecf20Sopenharmony_ci u32 set; 5928c2ecf20Sopenharmony_ci u32 clear; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device"); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Force mode has no effect if the hardware is not OTG. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 6008c2ecf20Sopenharmony_ci return; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* 6038c2ecf20Sopenharmony_ci * If dr_mode is either peripheral or host only, there is no 6048c2ecf20Sopenharmony_ci * need to ever force the mode to the opposite mode. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) 6078c2ecf20Sopenharmony_ci return; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST)) 6108c2ecf20Sopenharmony_ci return; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci gusbcfg = dwc2_readl(hsotg, GUSBCFG); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE; 6158c2ecf20Sopenharmony_ci clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci gusbcfg &= ~clear; 6188c2ecf20Sopenharmony_ci gusbcfg |= set; 6198c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gusbcfg, GUSBCFG); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci dwc2_wait_for_mode(hsotg, host); 6228c2ecf20Sopenharmony_ci return; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci/** 6268c2ecf20Sopenharmony_ci * dwc2_clear_force_mode() - Clears the force mode bits. 6278c2ecf20Sopenharmony_ci * 6288c2ecf20Sopenharmony_ci * After clearing the bits, wait up to 100 ms to account for any 6298c2ecf20Sopenharmony_ci * potential IDDIG filter delay. We can't know if we expect this delay 6308c2ecf20Sopenharmony_ci * or not because the value of the connector ID status is affected by 6318c2ecf20Sopenharmony_ci * the force mode. We only need to call this once during probe if 6328c2ecf20Sopenharmony_ci * dr_mode == OTG. 6338c2ecf20Sopenharmony_ci * 6348c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_cistatic void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci u32 gusbcfg; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 6418c2ecf20Sopenharmony_ci return; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Clearing force mode bits\n"); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci gusbcfg = dwc2_readl(hsotg, GUSBCFG); 6468c2ecf20Sopenharmony_ci gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; 6478c2ecf20Sopenharmony_ci gusbcfg &= ~GUSBCFG_FORCEDEVMODE; 6488c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gusbcfg, GUSBCFG); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (dwc2_iddig_filter_enabled(hsotg)) 6518c2ecf20Sopenharmony_ci msleep(100); 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/* 6558c2ecf20Sopenharmony_ci * Sets or clears force mode based on the dr_mode parameter. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_civoid dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci switch (hsotg->dr_mode) { 6608c2ecf20Sopenharmony_ci case USB_DR_MODE_HOST: 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * NOTE: This is required for some rockchip soc based 6638c2ecf20Sopenharmony_ci * platforms on their host-only dwc2. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 6668c2ecf20Sopenharmony_ci msleep(50); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 6708c2ecf20Sopenharmony_ci dwc2_force_mode(hsotg, false); 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case USB_DR_MODE_OTG: 6738c2ecf20Sopenharmony_ci dwc2_clear_force_mode(hsotg); 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci default: 6768c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n", 6778c2ecf20Sopenharmony_ci __func__, hsotg->dr_mode); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/* 6838c2ecf20Sopenharmony_ci * dwc2_enable_acg - enable active clock gating feature 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_civoid dwc2_enable_acg(struct dwc2_hsotg *hsotg) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci if (hsotg->params.acg_enable) { 6888c2ecf20Sopenharmony_ci u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n"); 6918c2ecf20Sopenharmony_ci pcgcctl1 |= PCGCCTL1_GATEEN; 6928c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl1, PCGCCTL1); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/** 6978c2ecf20Sopenharmony_ci * dwc2_dump_host_registers() - Prints the host registers 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 7008c2ecf20Sopenharmony_ci * 7018c2ecf20Sopenharmony_ci * NOTE: This function will be removed once the peripheral controller code 7028c2ecf20Sopenharmony_ci * is integrated and the driver is stable 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_civoid dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci#ifdef DEBUG 7078c2ecf20Sopenharmony_ci u32 __iomem *addr; 7088c2ecf20Sopenharmony_ci int i; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Host Global Registers\n"); 7118c2ecf20Sopenharmony_ci addr = hsotg->regs + HCFG; 7128c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n", 7138c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCFG)); 7148c2ecf20Sopenharmony_ci addr = hsotg->regs + HFIR; 7158c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n", 7168c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HFIR)); 7178c2ecf20Sopenharmony_ci addr = hsotg->regs + HFNUM; 7188c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n", 7198c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HFNUM)); 7208c2ecf20Sopenharmony_ci addr = hsotg->regs + HPTXSTS; 7218c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n", 7228c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HPTXSTS)); 7238c2ecf20Sopenharmony_ci addr = hsotg->regs + HAINT; 7248c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n", 7258c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HAINT)); 7268c2ecf20Sopenharmony_ci addr = hsotg->regs + HAINTMSK; 7278c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", 7288c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HAINTMSK)); 7298c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 7308c2ecf20Sopenharmony_ci addr = hsotg->regs + HFLBADDR; 7318c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", 7328c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HFLBADDR)); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci addr = hsotg->regs + HPRT0; 7368c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n", 7378c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HPRT0)); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci for (i = 0; i < hsotg->params.host_channels; i++) { 7408c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i); 7418c2ecf20Sopenharmony_ci addr = hsotg->regs + HCCHAR(i); 7428c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n", 7438c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCCHAR(i))); 7448c2ecf20Sopenharmony_ci addr = hsotg->regs + HCSPLT(i); 7458c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n", 7468c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCSPLT(i))); 7478c2ecf20Sopenharmony_ci addr = hsotg->regs + HCINT(i); 7488c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n", 7498c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCINT(i))); 7508c2ecf20Sopenharmony_ci addr = hsotg->regs + HCINTMSK(i); 7518c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n", 7528c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCINTMSK(i))); 7538c2ecf20Sopenharmony_ci addr = hsotg->regs + HCTSIZ(i); 7548c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n", 7558c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCTSIZ(i))); 7568c2ecf20Sopenharmony_ci addr = hsotg->regs + HCDMA(i); 7578c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", 7588c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCDMA(i))); 7598c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 7608c2ecf20Sopenharmony_ci addr = hsotg->regs + HCDMAB(i); 7618c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", 7628c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, 7638c2ecf20Sopenharmony_ci HCDMAB(i))); 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci#endif 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci/** 7708c2ecf20Sopenharmony_ci * dwc2_dump_global_registers() - Prints the core global registers 7718c2ecf20Sopenharmony_ci * 7728c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 7738c2ecf20Sopenharmony_ci * 7748c2ecf20Sopenharmony_ci * NOTE: This function will be removed once the peripheral controller code 7758c2ecf20Sopenharmony_ci * is integrated and the driver is stable 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_civoid dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci#ifdef DEBUG 7808c2ecf20Sopenharmony_ci u32 __iomem *addr; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Core Global Registers\n"); 7838c2ecf20Sopenharmony_ci addr = hsotg->regs + GOTGCTL; 7848c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n", 7858c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GOTGCTL)); 7868c2ecf20Sopenharmony_ci addr = hsotg->regs + GOTGINT; 7878c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n", 7888c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GOTGINT)); 7898c2ecf20Sopenharmony_ci addr = hsotg->regs + GAHBCFG; 7908c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n", 7918c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GAHBCFG)); 7928c2ecf20Sopenharmony_ci addr = hsotg->regs + GUSBCFG; 7938c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n", 7948c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GUSBCFG)); 7958c2ecf20Sopenharmony_ci addr = hsotg->regs + GRSTCTL; 7968c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n", 7978c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GRSTCTL)); 7988c2ecf20Sopenharmony_ci addr = hsotg->regs + GINTSTS; 7998c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n", 8008c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GINTSTS)); 8018c2ecf20Sopenharmony_ci addr = hsotg->regs + GINTMSK; 8028c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n", 8038c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GINTMSK)); 8048c2ecf20Sopenharmony_ci addr = hsotg->regs + GRXSTSR; 8058c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n", 8068c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GRXSTSR)); 8078c2ecf20Sopenharmony_ci addr = hsotg->regs + GRXFSIZ; 8088c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n", 8098c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GRXFSIZ)); 8108c2ecf20Sopenharmony_ci addr = hsotg->regs + GNPTXFSIZ; 8118c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n", 8128c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GNPTXFSIZ)); 8138c2ecf20Sopenharmony_ci addr = hsotg->regs + GNPTXSTS; 8148c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n", 8158c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GNPTXSTS)); 8168c2ecf20Sopenharmony_ci addr = hsotg->regs + GI2CCTL; 8178c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n", 8188c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GI2CCTL)); 8198c2ecf20Sopenharmony_ci addr = hsotg->regs + GPVNDCTL; 8208c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n", 8218c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL)); 8228c2ecf20Sopenharmony_ci addr = hsotg->regs + GGPIO; 8238c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n", 8248c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GGPIO)); 8258c2ecf20Sopenharmony_ci addr = hsotg->regs + GUID; 8268c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n", 8278c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GUID)); 8288c2ecf20Sopenharmony_ci addr = hsotg->regs + GSNPSID; 8298c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n", 8308c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GSNPSID)); 8318c2ecf20Sopenharmony_ci addr = hsotg->regs + GHWCFG1; 8328c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n", 8338c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG1)); 8348c2ecf20Sopenharmony_ci addr = hsotg->regs + GHWCFG2; 8358c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n", 8368c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG2)); 8378c2ecf20Sopenharmony_ci addr = hsotg->regs + GHWCFG3; 8388c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n", 8398c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG3)); 8408c2ecf20Sopenharmony_ci addr = hsotg->regs + GHWCFG4; 8418c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n", 8428c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG4)); 8438c2ecf20Sopenharmony_ci addr = hsotg->regs + GLPMCFG; 8448c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n", 8458c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GLPMCFG)); 8468c2ecf20Sopenharmony_ci addr = hsotg->regs + GPWRDN; 8478c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n", 8488c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GPWRDN)); 8498c2ecf20Sopenharmony_ci addr = hsotg->regs + GDFIFOCFG; 8508c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n", 8518c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GDFIFOCFG)); 8528c2ecf20Sopenharmony_ci addr = hsotg->regs + HPTXFSIZ; 8538c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n", 8548c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ)); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci addr = hsotg->regs + PCGCTL; 8578c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n", 8588c2ecf20Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, PCGCTL)); 8598c2ecf20Sopenharmony_ci#endif 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/** 8638c2ecf20Sopenharmony_ci * dwc2_flush_tx_fifo() - Flushes a Tx FIFO 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 8668c2ecf20Sopenharmony_ci * @num: Tx FIFO to flush 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_civoid dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci u32 greset; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Wait for AHB master IDLE state */ 8758c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 8768c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 8778c2ecf20Sopenharmony_ci __func__); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci greset = GRSTCTL_TXFFLSH; 8808c2ecf20Sopenharmony_ci greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK; 8818c2ecf20Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000)) 8848c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n", 8858c2ecf20Sopenharmony_ci __func__); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Wait for at least 3 PHY Clocks */ 8888c2ecf20Sopenharmony_ci udelay(1); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci/** 8928c2ecf20Sopenharmony_ci * dwc2_flush_rx_fifo() - Flushes the Rx FIFO 8938c2ecf20Sopenharmony_ci * 8948c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_civoid dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci u32 greset; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Wait for AHB master IDLE state */ 9038c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 9048c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 9058c2ecf20Sopenharmony_ci __func__); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci greset = GRSTCTL_RXFFLSH; 9088c2ecf20Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Wait for RxFIFO flush done */ 9118c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000)) 9128c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n", 9138c2ecf20Sopenharmony_ci __func__); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* Wait for at least 3 PHY Clocks */ 9168c2ecf20Sopenharmony_ci udelay(1); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cibool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff) 9228c2ecf20Sopenharmony_ci return false; 9238c2ecf20Sopenharmony_ci else 9248c2ecf20Sopenharmony_ci return true; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/** 9288c2ecf20Sopenharmony_ci * dwc2_enable_global_interrupts() - Enables the controller's Global 9298c2ecf20Sopenharmony_ci * Interrupt in the AHB Config register 9308c2ecf20Sopenharmony_ci * 9318c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_civoid dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci ahbcfg |= GAHBCFG_GLBL_INTR_EN; 9388c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ahbcfg, GAHBCFG); 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci/** 9428c2ecf20Sopenharmony_ci * dwc2_disable_global_interrupts() - Disables the controller's Global 9438c2ecf20Sopenharmony_ci * Interrupt in the AHB Config register 9448c2ecf20Sopenharmony_ci * 9458c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 9468c2ecf20Sopenharmony_ci */ 9478c2ecf20Sopenharmony_civoid dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci ahbcfg &= ~GAHBCFG_GLBL_INTR_EN; 9528c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ahbcfg, GAHBCFG); 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci/* Returns the controller's GHWCFG2.OTG_MODE. */ 9568c2ecf20Sopenharmony_ciunsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci u32 ghwcfg2 = dwc2_readl(hsotg, GHWCFG2); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >> 9618c2ecf20Sopenharmony_ci GHWCFG2_OP_MODE_SHIFT; 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci/* Returns true if the controller is capable of DRD. */ 9658c2ecf20Sopenharmony_cibool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci unsigned int op_mode = dwc2_op_mode(hsotg); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || 9708c2ecf20Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || 9718c2ecf20Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE); 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci/* Returns true if the controller is host-only. */ 9758c2ecf20Sopenharmony_cibool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci unsigned int op_mode = dwc2_op_mode(hsotg); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || 9808c2ecf20Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* Returns true if the controller is device-only. */ 9848c2ecf20Sopenharmony_cibool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci unsigned int op_mode = dwc2_op_mode(hsotg); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || 9898c2ecf20Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci/** 9938c2ecf20Sopenharmony_ci * dwc2_hsotg_wait_bit_set - Waits for bit to be set. 9948c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller. 9958c2ecf20Sopenharmony_ci * @offset: Register's offset where bit/bits must be set. 9968c2ecf20Sopenharmony_ci * @mask: Mask of the bit/bits which must be set. 9978c2ecf20Sopenharmony_ci * @timeout: Timeout to wait. 9988c2ecf20Sopenharmony_ci * 9998c2ecf20Sopenharmony_ci * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_ciint dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 10028c2ecf20Sopenharmony_ci u32 timeout) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci u32 i; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 10078c2ecf20Sopenharmony_ci if (dwc2_readl(hsotg, offset) & mask) 10088c2ecf20Sopenharmony_ci return 0; 10098c2ecf20Sopenharmony_ci udelay(1); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci return -ETIMEDOUT; 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci/** 10168c2ecf20Sopenharmony_ci * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear. 10178c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller. 10188c2ecf20Sopenharmony_ci * @offset: Register's offset where bit/bits must be set. 10198c2ecf20Sopenharmony_ci * @mask: Mask of the bit/bits which must be set. 10208c2ecf20Sopenharmony_ci * @timeout: Timeout to wait. 10218c2ecf20Sopenharmony_ci * 10228c2ecf20Sopenharmony_ci * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ciint dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 10258c2ecf20Sopenharmony_ci u32 timeout) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci u32 i; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 10308c2ecf20Sopenharmony_ci if (!(dwc2_readl(hsotg, offset) & mask)) 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci udelay(1); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return -ETIMEDOUT; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/* 10398c2ecf20Sopenharmony_ci * Initializes the FSLSPClkSel field of the HCFG register depending on the 10408c2ecf20Sopenharmony_ci * PHY type 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_civoid dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci u32 hcfg, val; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 10478c2ecf20Sopenharmony_ci hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && 10488c2ecf20Sopenharmony_ci hsotg->params.ulpi_fs_ls) || 10498c2ecf20Sopenharmony_ci hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { 10508c2ecf20Sopenharmony_ci /* Full speed PHY */ 10518c2ecf20Sopenharmony_ci val = HCFG_FSLSPCLKSEL_48_MHZ; 10528c2ecf20Sopenharmony_ci } else { 10538c2ecf20Sopenharmony_ci /* High speed PHY running at full speed or high speed */ 10548c2ecf20Sopenharmony_ci val = HCFG_FSLSPCLKSEL_30_60_MHZ; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); 10588c2ecf20Sopenharmony_ci hcfg = dwc2_readl(hsotg, HCFG); 10598c2ecf20Sopenharmony_ci hcfg &= ~HCFG_FSLSPCLKSEL_MASK; 10608c2ecf20Sopenharmony_ci hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; 10618c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci u32 usbcfg, ggpio, i2cctl; 10678c2ecf20Sopenharmony_ci int retval = 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* 10708c2ecf20Sopenharmony_ci * core_init() is now called on every switch so only call the 10718c2ecf20Sopenharmony_ci * following for the first time through 10728c2ecf20Sopenharmony_ci */ 10738c2ecf20Sopenharmony_ci if (select_phy) { 10748c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "FS PHY selected\n"); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 10778c2ecf20Sopenharmony_ci if (!(usbcfg & GUSBCFG_PHYSEL)) { 10788c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_PHYSEL; 10798c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Reset after a PHY select */ 10828c2ecf20Sopenharmony_ci retval = dwc2_core_reset(hsotg, false); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (retval) { 10858c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 10868c2ecf20Sopenharmony_ci "%s: Reset failed, aborting", __func__); 10878c2ecf20Sopenharmony_ci return retval; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (hsotg->params.activate_stm_fs_transceiver) { 10928c2ecf20Sopenharmony_ci ggpio = dwc2_readl(hsotg, GGPIO); 10938c2ecf20Sopenharmony_ci if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { 10948c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Activating transceiver\n"); 10958c2ecf20Sopenharmony_ci /* 10968c2ecf20Sopenharmony_ci * STM32F4x9 uses the GGPIO register as general 10978c2ecf20Sopenharmony_ci * core configuration register. 10988c2ecf20Sopenharmony_ci */ 10998c2ecf20Sopenharmony_ci ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; 11008c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ggpio, GGPIO); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* 11068c2ecf20Sopenharmony_ci * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also 11078c2ecf20Sopenharmony_ci * do this on HNP Dev/Host mode switches (done in dev_init and 11088c2ecf20Sopenharmony_ci * host_init). 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) 11118c2ecf20Sopenharmony_ci dwc2_init_fs_ls_pclk_sel(hsotg); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (hsotg->params.i2c_enable) { 11148c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* Program GUSBCFG.OtgUtmiFsSel to I2C */ 11178c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 11188c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; 11198c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Program GI2CCTL.I2CEn */ 11228c2ecf20Sopenharmony_ci i2cctl = dwc2_readl(hsotg, GI2CCTL); 11238c2ecf20Sopenharmony_ci i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; 11248c2ecf20Sopenharmony_ci i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; 11258c2ecf20Sopenharmony_ci i2cctl &= ~GI2CCTL_I2CEN; 11268c2ecf20Sopenharmony_ci dwc2_writel(hsotg, i2cctl, GI2CCTL); 11278c2ecf20Sopenharmony_ci i2cctl |= GI2CCTL_I2CEN; 11288c2ecf20Sopenharmony_ci dwc2_writel(hsotg, i2cctl, GI2CCTL); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return retval; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci u32 usbcfg, usbcfg_old; 11378c2ecf20Sopenharmony_ci int retval = 0; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if (!select_phy) 11408c2ecf20Sopenharmony_ci return 0; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 11438c2ecf20Sopenharmony_ci usbcfg_old = usbcfg; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* 11468c2ecf20Sopenharmony_ci * HS PHY parameters. These parameters are preserved during soft reset 11478c2ecf20Sopenharmony_ci * so only program the first time. Do a soft reset immediately after 11488c2ecf20Sopenharmony_ci * setting phyif. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci switch (hsotg->params.phy_type) { 11518c2ecf20Sopenharmony_ci case DWC2_PHY_TYPE_PARAM_ULPI: 11528c2ecf20Sopenharmony_ci /* ULPI interface */ 11538c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); 11548c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_ULPI_UTMI_SEL; 11558c2ecf20Sopenharmony_ci usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); 11568c2ecf20Sopenharmony_ci if (hsotg->params.phy_ulpi_ddr) 11578c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_DDRSEL; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* Set external VBUS indicator as needed. */ 11608c2ecf20Sopenharmony_ci if (hsotg->params.oc_disable) 11618c2ecf20Sopenharmony_ci usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | 11628c2ecf20Sopenharmony_ci GUSBCFG_INDICATORPASSTHROUGH); 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci case DWC2_PHY_TYPE_PARAM_UTMI: 11658c2ecf20Sopenharmony_ci /* UTMI+ interface */ 11668c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); 11678c2ecf20Sopenharmony_ci usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); 11688c2ecf20Sopenharmony_ci if (hsotg->params.phy_utmi_width == 16) 11698c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_PHYIF16; 11708c2ecf20Sopenharmony_ci break; 11718c2ecf20Sopenharmony_ci default: 11728c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "FS PHY selected at HS!\n"); 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (usbcfg != usbcfg_old) { 11778c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Reset after setting the PHY parameters */ 11808c2ecf20Sopenharmony_ci retval = dwc2_core_reset(hsotg, false); 11818c2ecf20Sopenharmony_ci if (retval) { 11828c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 11838c2ecf20Sopenharmony_ci "%s: Reset failed, aborting", __func__); 11848c2ecf20Sopenharmony_ci return retval; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci return retval; 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci u32 usbcfg; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI) 11968c2ecf20Sopenharmony_ci return; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci usbcfg &= ~GUSBCFG_USBTRDTIM_MASK; 12018c2ecf20Sopenharmony_ci if (hsotg->params.phy_utmi_width == 16) 12028c2ecf20Sopenharmony_ci usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT; 12038c2ecf20Sopenharmony_ci else 12048c2ecf20Sopenharmony_ci usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ciint dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci u32 usbcfg; 12128c2ecf20Sopenharmony_ci int retval = 0; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || 12158c2ecf20Sopenharmony_ci hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && 12168c2ecf20Sopenharmony_ci hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { 12178c2ecf20Sopenharmony_ci /* If FS/LS mode with FS/LS PHY */ 12188c2ecf20Sopenharmony_ci retval = dwc2_fs_phy_init(hsotg, select_phy); 12198c2ecf20Sopenharmony_ci if (retval) 12208c2ecf20Sopenharmony_ci return retval; 12218c2ecf20Sopenharmony_ci } else { 12228c2ecf20Sopenharmony_ci /* High speed PHY */ 12238c2ecf20Sopenharmony_ci retval = dwc2_hs_phy_init(hsotg, select_phy); 12248c2ecf20Sopenharmony_ci if (retval) 12258c2ecf20Sopenharmony_ci return retval; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (dwc2_is_device_mode(hsotg)) 12288c2ecf20Sopenharmony_ci dwc2_set_turnaround_time(hsotg); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 12328c2ecf20Sopenharmony_ci hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && 12338c2ecf20Sopenharmony_ci hsotg->params.ulpi_fs_ls) { 12348c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); 12358c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 12368c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_ULPI_FS_LS; 12378c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; 12388c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 12398c2ecf20Sopenharmony_ci } else { 12408c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 12418c2ecf20Sopenharmony_ci usbcfg &= ~GUSBCFG_ULPI_FS_LS; 12428c2ecf20Sopenharmony_ci usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; 12438c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return retval; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); 12508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Synopsys, Inc."); 12518c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1252