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