162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * hcd.c - DesignWare HS OTG Controller host-mode routines
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * This file contains the core HCD code, and implements the Linux hc_driver
1062306a36Sopenharmony_ci * API
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/spinlock.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/io.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/usb.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2462306a36Sopenharmony_ci#include <linux/usb/ch11.h>
2562306a36Sopenharmony_ci#include <linux/usb/of.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "core.h"
2862306a36Sopenharmony_ci#include "hcd.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * =========================================================================
3262306a36Sopenharmony_ci *  Host Core Layer Functions
3362306a36Sopenharmony_ci * =========================================================================
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/**
3762306a36Sopenharmony_ci * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
3862306a36Sopenharmony_ci * used in both device and host modes
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistatic void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	u32 intmsk;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* Clear any pending OTG Interrupts */
4762306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GOTGINT);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* Clear any pending interrupts */
5062306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* Enable the interrupts in the GINTMSK */
5362306a36Sopenharmony_ci	intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (!hsotg->params.host_dma)
5662306a36Sopenharmony_ci		intmsk |= GINTSTS_RXFLVL;
5762306a36Sopenharmony_ci	if (!hsotg->params.external_id_pin_ctl)
5862306a36Sopenharmony_ci		intmsk |= GINTSTS_CONIDSTSCHNG;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
6162306a36Sopenharmony_ci		  GINTSTS_SESSREQINT;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (dwc2_is_device_mode(hsotg) && hsotg->params.lpm)
6462306a36Sopenharmony_ci		intmsk |= GINTSTS_LPMTRANRCVD;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	dwc2_writel(hsotg, intmsk, GINTMSK);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	switch (hsotg->hw_params.arch) {
7462306a36Sopenharmony_ci	case GHWCFG2_EXT_DMA_ARCH:
7562306a36Sopenharmony_ci		dev_err(hsotg->dev, "External DMA Mode not supported\n");
7662306a36Sopenharmony_ci		return -EINVAL;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	case GHWCFG2_INT_DMA_ARCH:
7962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Internal DMA Mode\n");
8062306a36Sopenharmony_ci		if (hsotg->params.ahbcfg != -1) {
8162306a36Sopenharmony_ci			ahbcfg &= GAHBCFG_CTRL_MASK;
8262306a36Sopenharmony_ci			ahbcfg |= hsotg->params.ahbcfg &
8362306a36Sopenharmony_ci				  ~GAHBCFG_CTRL_MASK;
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci		break;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	case GHWCFG2_SLAVE_ONLY_ARCH:
8862306a36Sopenharmony_ci	default:
8962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Slave Only Mode\n");
9062306a36Sopenharmony_ci		break;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (hsotg->params.host_dma)
9462306a36Sopenharmony_ci		ahbcfg |= GAHBCFG_DMA_EN;
9562306a36Sopenharmony_ci	else
9662306a36Sopenharmony_ci		hsotg->params.dma_desc_enable = false;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	dwc2_writel(hsotg, ahbcfg, GAHBCFG);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	u32 usbcfg;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	usbcfg = dwc2_readl(hsotg, GUSBCFG);
10862306a36Sopenharmony_ci	usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	switch (hsotg->hw_params.op_mode) {
11162306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
11262306a36Sopenharmony_ci		if (hsotg->params.otg_caps.hnp_support &&
11362306a36Sopenharmony_ci		    hsotg->params.otg_caps.srp_support)
11462306a36Sopenharmony_ci			usbcfg |= GUSBCFG_HNPCAP;
11562306a36Sopenharmony_ci		fallthrough;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
11862306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
11962306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
12062306a36Sopenharmony_ci		if (hsotg->params.otg_caps.srp_support)
12162306a36Sopenharmony_ci			usbcfg |= GUSBCFG_SRPCAP;
12262306a36Sopenharmony_ci		break;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
12562306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
12662306a36Sopenharmony_ci	case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
12762306a36Sopenharmony_ci	default:
12862306a36Sopenharmony_ci		break;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	dwc2_writel(hsotg, usbcfg, GUSBCFG);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	if (hsotg->vbus_supply)
13762306a36Sopenharmony_ci		return regulator_enable(hsotg->vbus_supply);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	if (hsotg->vbus_supply)
14562306a36Sopenharmony_ci		return regulator_disable(hsotg->vbus_supply);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/**
15162306a36Sopenharmony_ci * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
15262306a36Sopenharmony_ci *
15362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_cistatic void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	u32 intmsk;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s()\n", __func__);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* Disable all interrupts */
16262306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, GINTMSK);
16362306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, HAINTMSK);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Enable the common interrupts */
16662306a36Sopenharmony_ci	dwc2_enable_common_interrupts(hsotg);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* Enable host mode interrupts without disturbing common interrupts */
16962306a36Sopenharmony_ci	intmsk = dwc2_readl(hsotg, GINTMSK);
17062306a36Sopenharmony_ci	intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
17162306a36Sopenharmony_ci	dwc2_writel(hsotg, intmsk, GINTMSK);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_cistatic void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	u32 intmsk = dwc2_readl(hsotg, GINTMSK);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Disable host mode interrupts without disturbing common interrupts */
18462306a36Sopenharmony_ci	intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
18562306a36Sopenharmony_ci		    GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | GINTSTS_DISCONNINT);
18662306a36Sopenharmony_ci	dwc2_writel(hsotg, intmsk, GINTMSK);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/*
19062306a36Sopenharmony_ci * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size
19162306a36Sopenharmony_ci * For system that have a total fifo depth that is smaller than the default
19262306a36Sopenharmony_ci * RX + TX fifo size.
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct dwc2_core_params *params = &hsotg->params;
19962306a36Sopenharmony_ci	struct dwc2_hw_params *hw = &hsotg->hw_params;
20062306a36Sopenharmony_ci	u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	total_fifo_size = hw->total_fifo_size;
20362306a36Sopenharmony_ci	rxfsiz = params->host_rx_fifo_size;
20462306a36Sopenharmony_ci	nptxfsiz = params->host_nperio_tx_fifo_size;
20562306a36Sopenharmony_ci	ptxfsiz = params->host_perio_tx_fifo_size;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/*
20862306a36Sopenharmony_ci	 * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth
20962306a36Sopenharmony_ci	 * allocation with support for high bandwidth endpoints. Synopsys
21062306a36Sopenharmony_ci	 * defines MPS(Max Packet size) for a periodic EP=1024, and for
21162306a36Sopenharmony_ci	 * non-periodic as 512.
21262306a36Sopenharmony_ci	 */
21362306a36Sopenharmony_ci	if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) {
21462306a36Sopenharmony_ci		/*
21562306a36Sopenharmony_ci		 * For Buffer DMA mode/Scatter Gather DMA mode
21662306a36Sopenharmony_ci		 * 2 * ((Largest Packet size / 4) + 1 + 1) + n
21762306a36Sopenharmony_ci		 * with n = number of host channel.
21862306a36Sopenharmony_ci		 * 2 * ((1024/4) + 2) = 516
21962306a36Sopenharmony_ci		 */
22062306a36Sopenharmony_ci		rxfsiz = 516 + hw->host_channels;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		/*
22362306a36Sopenharmony_ci		 * min non-periodic tx fifo depth
22462306a36Sopenharmony_ci		 * 2 * (largest non-periodic USB packet used / 4)
22562306a36Sopenharmony_ci		 * 2 * (512/4) = 256
22662306a36Sopenharmony_ci		 */
22762306a36Sopenharmony_ci		nptxfsiz = 256;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		/*
23062306a36Sopenharmony_ci		 * min periodic tx fifo depth
23162306a36Sopenharmony_ci		 * (largest packet size*MC)/4
23262306a36Sopenharmony_ci		 * (1024 * 3)/4 = 768
23362306a36Sopenharmony_ci		 */
23462306a36Sopenharmony_ci		ptxfsiz = 768;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		params->host_rx_fifo_size = rxfsiz;
23762306a36Sopenharmony_ci		params->host_nperio_tx_fifo_size = nptxfsiz;
23862306a36Sopenharmony_ci		params->host_perio_tx_fifo_size = ptxfsiz;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/*
24262306a36Sopenharmony_ci	 * If the summation of RX, NPTX and PTX fifo sizes is still
24362306a36Sopenharmony_ci	 * bigger than the total_fifo_size, then we have a problem.
24462306a36Sopenharmony_ci	 *
24562306a36Sopenharmony_ci	 * We won't be able to allocate as many endpoints. Right now,
24662306a36Sopenharmony_ci	 * we're just printing an error message, but ideally this FIFO
24762306a36Sopenharmony_ci	 * allocation algorithm would be improved in the future.
24862306a36Sopenharmony_ci	 *
24962306a36Sopenharmony_ci	 * FIXME improve this FIFO allocation algorithm.
25062306a36Sopenharmony_ci	 */
25162306a36Sopenharmony_ci	if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)))
25262306a36Sopenharmony_ci		dev_err(hsotg->dev, "invalid fifo sizes\n");
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct dwc2_core_params *params = &hsotg->params;
25862306a36Sopenharmony_ci	u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (!params->enable_dynamic_fifo)
26162306a36Sopenharmony_ci		return;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	dwc2_calculate_dynamic_fifo(hsotg);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Rx FIFO */
26662306a36Sopenharmony_ci	grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
26762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
26862306a36Sopenharmony_ci	grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
26962306a36Sopenharmony_ci	grxfsiz |= params->host_rx_fifo_size <<
27062306a36Sopenharmony_ci		   GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
27162306a36Sopenharmony_ci	dwc2_writel(hsotg, grxfsiz, GRXFSIZ);
27262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "new grxfsiz=%08x\n",
27362306a36Sopenharmony_ci		dwc2_readl(hsotg, GRXFSIZ));
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Non-periodic Tx FIFO */
27662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
27762306a36Sopenharmony_ci		dwc2_readl(hsotg, GNPTXFSIZ));
27862306a36Sopenharmony_ci	nptxfsiz = params->host_nperio_tx_fifo_size <<
27962306a36Sopenharmony_ci		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
28062306a36Sopenharmony_ci	nptxfsiz |= params->host_rx_fifo_size <<
28162306a36Sopenharmony_ci		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
28262306a36Sopenharmony_ci	dwc2_writel(hsotg, nptxfsiz, GNPTXFSIZ);
28362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
28462306a36Sopenharmony_ci		dwc2_readl(hsotg, GNPTXFSIZ));
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Periodic Tx FIFO */
28762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
28862306a36Sopenharmony_ci		dwc2_readl(hsotg, HPTXFSIZ));
28962306a36Sopenharmony_ci	hptxfsiz = params->host_perio_tx_fifo_size <<
29062306a36Sopenharmony_ci		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
29162306a36Sopenharmony_ci	hptxfsiz |= (params->host_rx_fifo_size +
29262306a36Sopenharmony_ci		     params->host_nperio_tx_fifo_size) <<
29362306a36Sopenharmony_ci		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
29462306a36Sopenharmony_ci	dwc2_writel(hsotg, hptxfsiz, HPTXFSIZ);
29562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
29662306a36Sopenharmony_ci		dwc2_readl(hsotg, HPTXFSIZ));
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (hsotg->params.en_multiple_tx_fifo &&
29962306a36Sopenharmony_ci	    hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_91a) {
30062306a36Sopenharmony_ci		/*
30162306a36Sopenharmony_ci		 * This feature was implemented in 2.91a version
30262306a36Sopenharmony_ci		 * Global DFIFOCFG calculation for Host mode -
30362306a36Sopenharmony_ci		 * include RxFIFO, NPTXFIFO and HPTXFIFO
30462306a36Sopenharmony_ci		 */
30562306a36Sopenharmony_ci		dfifocfg = dwc2_readl(hsotg, GDFIFOCFG);
30662306a36Sopenharmony_ci		dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
30762306a36Sopenharmony_ci		dfifocfg |= (params->host_rx_fifo_size +
30862306a36Sopenharmony_ci			     params->host_nperio_tx_fifo_size +
30962306a36Sopenharmony_ci			     params->host_perio_tx_fifo_size) <<
31062306a36Sopenharmony_ci			    GDFIFOCFG_EPINFOBASE_SHIFT &
31162306a36Sopenharmony_ci			    GDFIFOCFG_EPINFOBASE_MASK;
31262306a36Sopenharmony_ci		dwc2_writel(hsotg, dfifocfg, GDFIFOCFG);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for
31862306a36Sopenharmony_ci * the HFIR register according to PHY type and speed
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * NOTE: The caller can modify the value of the HFIR register only after the
32362306a36Sopenharmony_ci * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort)
32462306a36Sopenharmony_ci * has been set
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_ciu32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	u32 usbcfg;
32962306a36Sopenharmony_ci	u32 hprt0;
33062306a36Sopenharmony_ci	int clock = 60;	/* default value */
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	usbcfg = dwc2_readl(hsotg, GUSBCFG);
33362306a36Sopenharmony_ci	hprt0 = dwc2_readl(hsotg, HPRT0);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
33662306a36Sopenharmony_ci	    !(usbcfg & GUSBCFG_PHYIF16))
33762306a36Sopenharmony_ci		clock = 60;
33862306a36Sopenharmony_ci	if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
33962306a36Sopenharmony_ci	    GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
34062306a36Sopenharmony_ci		clock = 48;
34162306a36Sopenharmony_ci	if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
34262306a36Sopenharmony_ci	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
34362306a36Sopenharmony_ci		clock = 30;
34462306a36Sopenharmony_ci	if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
34562306a36Sopenharmony_ci	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16))
34662306a36Sopenharmony_ci		clock = 60;
34762306a36Sopenharmony_ci	if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
34862306a36Sopenharmony_ci	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
34962306a36Sopenharmony_ci		clock = 48;
35062306a36Sopenharmony_ci	if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
35162306a36Sopenharmony_ci	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
35262306a36Sopenharmony_ci		clock = 48;
35362306a36Sopenharmony_ci	if ((usbcfg & GUSBCFG_PHYSEL) &&
35462306a36Sopenharmony_ci	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
35562306a36Sopenharmony_ci		clock = 48;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
35862306a36Sopenharmony_ci		/* High speed case */
35962306a36Sopenharmony_ci		return 125 * clock - 1;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* FS/LS case */
36262306a36Sopenharmony_ci	return 1000 * clock - 1;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/**
36662306a36Sopenharmony_ci * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination
36762306a36Sopenharmony_ci * buffer
36862306a36Sopenharmony_ci *
36962306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
37062306a36Sopenharmony_ci * @dest:    Destination buffer for the packet
37162306a36Sopenharmony_ci * @bytes:   Number of bytes to copy to the destination
37262306a36Sopenharmony_ci */
37362306a36Sopenharmony_civoid dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	u32 *data_buf = (u32 *)dest;
37662306a36Sopenharmony_ci	int word_count = (bytes + 3) / 4;
37762306a36Sopenharmony_ci	int i;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * Todo: Account for the case where dest is not dword aligned. This
38162306a36Sopenharmony_ci	 * requires reading data from the FIFO into a u32 temp buffer, then
38262306a36Sopenharmony_ci	 * moving it into the data buffer.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	for (i = 0; i < word_count; i++, data_buf++)
38862306a36Sopenharmony_ci		*data_buf = dwc2_readl(hsotg, HCFIFO(0));
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/**
39262306a36Sopenharmony_ci * dwc2_dump_channel_info() - Prints the state of a host channel
39362306a36Sopenharmony_ci *
39462306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
39562306a36Sopenharmony_ci * @chan:  Pointer to the channel to dump
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
39862306a36Sopenharmony_ci *
39962306a36Sopenharmony_ci * NOTE: This function will be removed once the peripheral controller code
40062306a36Sopenharmony_ci * is integrated and the driver is stable
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_cistatic void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
40362306a36Sopenharmony_ci				   struct dwc2_host_chan *chan)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci#ifdef VERBOSE_DEBUG
40662306a36Sopenharmony_ci	int num_channels = hsotg->params.host_channels;
40762306a36Sopenharmony_ci	struct dwc2_qh *qh;
40862306a36Sopenharmony_ci	u32 hcchar;
40962306a36Sopenharmony_ci	u32 hcsplt;
41062306a36Sopenharmony_ci	u32 hctsiz;
41162306a36Sopenharmony_ci	u32 hc_dma;
41262306a36Sopenharmony_ci	int i;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (!chan)
41562306a36Sopenharmony_ci		return;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
41862306a36Sopenharmony_ci	hcsplt = dwc2_readl(hsotg, HCSPLT(chan->hc_num));
41962306a36Sopenharmony_ci	hctsiz = dwc2_readl(hsotg, HCTSIZ(chan->hc_num));
42062306a36Sopenharmony_ci	hc_dma = dwc2_readl(hsotg, HCDMA(chan->hc_num));
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  Assigned to channel %p:\n", chan);
42362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    hcchar 0x%08x, hcsplt 0x%08x\n",
42462306a36Sopenharmony_ci		hcchar, hcsplt);
42562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    hctsiz 0x%08x, hc_dma 0x%08x\n",
42662306a36Sopenharmony_ci		hctsiz, hc_dma);
42762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
42862306a36Sopenharmony_ci		chan->dev_addr, chan->ep_num, chan->ep_is_in);
42962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type);
43062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet);
43162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    data_pid_start: %d\n", chan->data_pid_start);
43262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    xfer_started: %d\n", chan->xfer_started);
43362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status);
43462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf);
43562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n",
43662306a36Sopenharmony_ci		(unsigned long)chan->xfer_dma);
43762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len);
43862306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh);
43962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  NP inactive sched:\n");
44062306a36Sopenharmony_ci	list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
44162306a36Sopenharmony_ci			    qh_list_entry)
44262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    %p\n", qh);
44362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  NP waiting sched:\n");
44462306a36Sopenharmony_ci	list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
44562306a36Sopenharmony_ci			    qh_list_entry)
44662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    %p\n", qh);
44762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  NP active sched:\n");
44862306a36Sopenharmony_ci	list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
44962306a36Sopenharmony_ci			    qh_list_entry)
45062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    %p\n", qh);
45162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  Channels:\n");
45262306a36Sopenharmony_ci	for (i = 0; i < num_channels; i++) {
45362306a36Sopenharmony_ci		struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    %2d: %p\n", i, chan);
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci#endif /* VERBOSE_DEBUG */
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int _dwc2_hcd_start(struct usb_hcd *hcd);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic void dwc2_host_start(struct dwc2_hsotg *hsotg)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	hcd->self.is_b_host = dwc2_hcd_is_b_host(hsotg);
46762306a36Sopenharmony_ci	_dwc2_hcd_start(hcd);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic void dwc2_host_disconnect(struct dwc2_hsotg *hsotg)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	hcd->self.is_b_host = 0;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
47862306a36Sopenharmony_ci			       int *hub_addr, int *hub_port)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct urb *urb = context;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (urb->dev->tt)
48362306a36Sopenharmony_ci		*hub_addr = urb->dev->tt->hub->devnum;
48462306a36Sopenharmony_ci	else
48562306a36Sopenharmony_ci		*hub_addr = 0;
48662306a36Sopenharmony_ci	*hub_port = urb->dev->ttport;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/*
49062306a36Sopenharmony_ci * =========================================================================
49162306a36Sopenharmony_ci *  Low Level Host Channel Access Functions
49262306a36Sopenharmony_ci * =========================================================================
49362306a36Sopenharmony_ci */
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
49662306a36Sopenharmony_ci				      struct dwc2_host_chan *chan)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	u32 hcintmsk = HCINTMSK_CHHLTD;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	switch (chan->ep_type) {
50162306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
50262306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
50362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "control/bulk\n");
50462306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_XFERCOMPL;
50562306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_STALL;
50662306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_XACTERR;
50762306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_DATATGLERR;
50862306a36Sopenharmony_ci		if (chan->ep_is_in) {
50962306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_BBLERR;
51062306a36Sopenharmony_ci		} else {
51162306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_NAK;
51262306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_NYET;
51362306a36Sopenharmony_ci			if (chan->do_ping)
51462306a36Sopenharmony_ci				hcintmsk |= HCINTMSK_ACK;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		if (chan->do_split) {
51862306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_NAK;
51962306a36Sopenharmony_ci			if (chan->complete_split)
52062306a36Sopenharmony_ci				hcintmsk |= HCINTMSK_NYET;
52162306a36Sopenharmony_ci			else
52262306a36Sopenharmony_ci				hcintmsk |= HCINTMSK_ACK;
52362306a36Sopenharmony_ci		}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (chan->error_state)
52662306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_ACK;
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
53062306a36Sopenharmony_ci		if (dbg_perio())
53162306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "intr\n");
53262306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_XFERCOMPL;
53362306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_NAK;
53462306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_STALL;
53562306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_XACTERR;
53662306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_DATATGLERR;
53762306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_FRMOVRUN;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		if (chan->ep_is_in)
54062306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_BBLERR;
54162306a36Sopenharmony_ci		if (chan->error_state)
54262306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_ACK;
54362306a36Sopenharmony_ci		if (chan->do_split) {
54462306a36Sopenharmony_ci			if (chan->complete_split)
54562306a36Sopenharmony_ci				hcintmsk |= HCINTMSK_NYET;
54662306a36Sopenharmony_ci			else
54762306a36Sopenharmony_ci				hcintmsk |= HCINTMSK_ACK;
54862306a36Sopenharmony_ci		}
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
55262306a36Sopenharmony_ci		if (dbg_perio())
55362306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "isoc\n");
55462306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_XFERCOMPL;
55562306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_FRMOVRUN;
55662306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_ACK;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		if (chan->ep_is_in) {
55962306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_XACTERR;
56062306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_BBLERR;
56162306a36Sopenharmony_ci		}
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	default:
56462306a36Sopenharmony_ci		dev_err(hsotg->dev, "## Unknown EP type ##\n");
56562306a36Sopenharmony_ci		break;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
56962306a36Sopenharmony_ci	if (dbg_hc(chan))
57062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
57462306a36Sopenharmony_ci				    struct dwc2_host_chan *chan)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	u32 hcintmsk = HCINTMSK_CHHLTD;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/*
57962306a36Sopenharmony_ci	 * For Descriptor DMA mode core halts the channel on AHB error.
58062306a36Sopenharmony_ci	 * Interrupt is not required.
58162306a36Sopenharmony_ci	 */
58262306a36Sopenharmony_ci	if (!hsotg->params.dma_desc_enable) {
58362306a36Sopenharmony_ci		if (dbg_hc(chan))
58462306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "desc DMA disabled\n");
58562306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_AHBERR;
58662306a36Sopenharmony_ci	} else {
58762306a36Sopenharmony_ci		if (dbg_hc(chan))
58862306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "desc DMA enabled\n");
58962306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
59062306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_XFERCOMPL;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (chan->error_state && !chan->do_split &&
59462306a36Sopenharmony_ci	    chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
59562306a36Sopenharmony_ci		if (dbg_hc(chan))
59662306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "setting ACK\n");
59762306a36Sopenharmony_ci		hcintmsk |= HCINTMSK_ACK;
59862306a36Sopenharmony_ci		if (chan->ep_is_in) {
59962306a36Sopenharmony_ci			hcintmsk |= HCINTMSK_DATATGLERR;
60062306a36Sopenharmony_ci			if (chan->ep_type != USB_ENDPOINT_XFER_INT)
60162306a36Sopenharmony_ci				hcintmsk |= HCINTMSK_NAK;
60262306a36Sopenharmony_ci		}
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
60662306a36Sopenharmony_ci	if (dbg_hc(chan))
60762306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
61162306a36Sopenharmony_ci				struct dwc2_host_chan *chan)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	u32 intmsk;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (hsotg->params.host_dma) {
61662306a36Sopenharmony_ci		if (dbg_hc(chan))
61762306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "DMA enabled\n");
61862306a36Sopenharmony_ci		dwc2_hc_enable_dma_ints(hsotg, chan);
61962306a36Sopenharmony_ci	} else {
62062306a36Sopenharmony_ci		if (dbg_hc(chan))
62162306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "DMA disabled\n");
62262306a36Sopenharmony_ci		dwc2_hc_enable_slave_ints(hsotg, chan);
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* Enable the top level host channel interrupt */
62662306a36Sopenharmony_ci	intmsk = dwc2_readl(hsotg, HAINTMSK);
62762306a36Sopenharmony_ci	intmsk |= 1 << chan->hc_num;
62862306a36Sopenharmony_ci	dwc2_writel(hsotg, intmsk, HAINTMSK);
62962306a36Sopenharmony_ci	if (dbg_hc(chan))
63062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* Make sure host channel interrupts are enabled */
63362306a36Sopenharmony_ci	intmsk = dwc2_readl(hsotg, GINTMSK);
63462306a36Sopenharmony_ci	intmsk |= GINTSTS_HCHINT;
63562306a36Sopenharmony_ci	dwc2_writel(hsotg, intmsk, GINTMSK);
63662306a36Sopenharmony_ci	if (dbg_hc(chan))
63762306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/**
64162306a36Sopenharmony_ci * dwc2_hc_init() - Prepares a host channel for transferring packets to/from
64262306a36Sopenharmony_ci * a specific endpoint
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
64562306a36Sopenharmony_ci * @chan:  Information needed to initialize the host channel
64662306a36Sopenharmony_ci *
64762306a36Sopenharmony_ci * The HCCHARn register is set up with the characteristics specified in chan.
64862306a36Sopenharmony_ci * Host channel interrupts that may need to be serviced while this transfer is
64962306a36Sopenharmony_ci * in progress are enabled.
65062306a36Sopenharmony_ci */
65162306a36Sopenharmony_cistatic void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	u8 hc_num = chan->hc_num;
65462306a36Sopenharmony_ci	u32 hcintmsk;
65562306a36Sopenharmony_ci	u32 hcchar;
65662306a36Sopenharmony_ci	u32 hcsplt = 0;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (dbg_hc(chan))
65962306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s()\n", __func__);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/* Clear old interrupt conditions for this host channel */
66262306a36Sopenharmony_ci	hcintmsk = 0xffffffff;
66362306a36Sopenharmony_ci	hcintmsk &= ~HCINTMSK_RESERVED14_31;
66462306a36Sopenharmony_ci	dwc2_writel(hsotg, hcintmsk, HCINT(hc_num));
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* Enable channel interrupts required for this transfer */
66762306a36Sopenharmony_ci	dwc2_hc_enable_ints(hsotg, chan);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/*
67062306a36Sopenharmony_ci	 * Program the HCCHARn register with the endpoint characteristics for
67162306a36Sopenharmony_ci	 * the current transfer
67262306a36Sopenharmony_ci	 */
67362306a36Sopenharmony_ci	hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK;
67462306a36Sopenharmony_ci	hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK;
67562306a36Sopenharmony_ci	if (chan->ep_is_in)
67662306a36Sopenharmony_ci		hcchar |= HCCHAR_EPDIR;
67762306a36Sopenharmony_ci	if (chan->speed == USB_SPEED_LOW)
67862306a36Sopenharmony_ci		hcchar |= HCCHAR_LSPDDEV;
67962306a36Sopenharmony_ci	hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
68062306a36Sopenharmony_ci	hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
68162306a36Sopenharmony_ci	dwc2_writel(hsotg, hcchar, HCCHAR(hc_num));
68262306a36Sopenharmony_ci	if (dbg_hc(chan)) {
68362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
68462306a36Sopenharmony_ci			 hc_num, hcchar);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s: Channel %d\n",
68762306a36Sopenharmony_ci			 __func__, hc_num);
68862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Dev Addr: %d\n",
68962306a36Sopenharmony_ci			 chan->dev_addr);
69062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Ep Num: %d\n",
69162306a36Sopenharmony_ci			 chan->ep_num);
69262306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Is In: %d\n",
69362306a36Sopenharmony_ci			 chan->ep_is_in);
69462306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Is Low Speed: %d\n",
69562306a36Sopenharmony_ci			 chan->speed == USB_SPEED_LOW);
69662306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Ep Type: %d\n",
69762306a36Sopenharmony_ci			 chan->ep_type);
69862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Max Pkt: %d\n",
69962306a36Sopenharmony_ci			 chan->max_packet);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* Program the HCSPLT register for SPLITs */
70362306a36Sopenharmony_ci	if (chan->do_split) {
70462306a36Sopenharmony_ci		if (dbg_hc(chan))
70562306a36Sopenharmony_ci			dev_vdbg(hsotg->dev,
70662306a36Sopenharmony_ci				 "Programming HC %d with split --> %s\n",
70762306a36Sopenharmony_ci				 hc_num,
70862306a36Sopenharmony_ci				 chan->complete_split ? "CSPLIT" : "SSPLIT");
70962306a36Sopenharmony_ci		if (chan->complete_split)
71062306a36Sopenharmony_ci			hcsplt |= HCSPLT_COMPSPLT;
71162306a36Sopenharmony_ci		hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT &
71262306a36Sopenharmony_ci			  HCSPLT_XACTPOS_MASK;
71362306a36Sopenharmony_ci		hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT &
71462306a36Sopenharmony_ci			  HCSPLT_HUBADDR_MASK;
71562306a36Sopenharmony_ci		hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT &
71662306a36Sopenharmony_ci			  HCSPLT_PRTADDR_MASK;
71762306a36Sopenharmony_ci		if (dbg_hc(chan)) {
71862306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  comp split %d\n",
71962306a36Sopenharmony_ci				 chan->complete_split);
72062306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  xact pos %d\n",
72162306a36Sopenharmony_ci				 chan->xact_pos);
72262306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  hub addr %d\n",
72362306a36Sopenharmony_ci				 chan->hub_addr);
72462306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  hub port %d\n",
72562306a36Sopenharmony_ci				 chan->hub_port);
72662306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  is_in %d\n",
72762306a36Sopenharmony_ci				 chan->ep_is_in);
72862306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  Max Pkt %d\n",
72962306a36Sopenharmony_ci				 chan->max_packet);
73062306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	  xferlen %d\n",
73162306a36Sopenharmony_ci				 chan->xfer_len);
73262306a36Sopenharmony_ci		}
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	dwc2_writel(hsotg, hcsplt, HCSPLT(hc_num));
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci/**
73962306a36Sopenharmony_ci * dwc2_hc_halt() - Attempts to halt a host channel
74062306a36Sopenharmony_ci *
74162306a36Sopenharmony_ci * @hsotg:       Controller register interface
74262306a36Sopenharmony_ci * @chan:        Host channel to halt
74362306a36Sopenharmony_ci * @halt_status: Reason for halting the channel
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * This function should only be called in Slave mode or to abort a transfer in
74662306a36Sopenharmony_ci * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the
74762306a36Sopenharmony_ci * controller halts the channel when the transfer is complete or a condition
74862306a36Sopenharmony_ci * occurs that requires application intervention.
74962306a36Sopenharmony_ci *
75062306a36Sopenharmony_ci * In slave mode, checks for a free request queue entry, then sets the Channel
75162306a36Sopenharmony_ci * Enable and Channel Disable bits of the Host Channel Characteristics
75262306a36Sopenharmony_ci * register of the specified channel to intiate the halt. If there is no free
75362306a36Sopenharmony_ci * request queue entry, sets only the Channel Disable bit of the HCCHARn
75462306a36Sopenharmony_ci * register to flush requests for this channel. In the latter case, sets a
75562306a36Sopenharmony_ci * flag to indicate that the host channel needs to be halted when a request
75662306a36Sopenharmony_ci * queue slot is open.
75762306a36Sopenharmony_ci *
75862306a36Sopenharmony_ci * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
75962306a36Sopenharmony_ci * HCCHARn register. The controller ensures there is space in the request
76062306a36Sopenharmony_ci * queue before submitting the halt request.
76162306a36Sopenharmony_ci *
76262306a36Sopenharmony_ci * Some time may elapse before the core flushes any posted requests for this
76362306a36Sopenharmony_ci * host channel and halts. The Channel Halted interrupt handler completes the
76462306a36Sopenharmony_ci * deactivation of the host channel.
76562306a36Sopenharmony_ci */
76662306a36Sopenharmony_civoid dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
76762306a36Sopenharmony_ci		  enum dwc2_halt_status halt_status)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	u32 nptxsts, hptxsts, hcchar;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (dbg_hc(chan))
77262306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s()\n", __func__);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/*
77562306a36Sopenharmony_ci	 * In buffer DMA or external DMA mode channel can't be halted
77662306a36Sopenharmony_ci	 * for non-split periodic channels. At the end of the next
77762306a36Sopenharmony_ci	 * uframe/frame (in the worst case), the core generates a channel
77862306a36Sopenharmony_ci	 * halted and disables the channel automatically.
77962306a36Sopenharmony_ci	 */
78062306a36Sopenharmony_ci	if ((hsotg->params.g_dma && !hsotg->params.g_dma_desc) ||
78162306a36Sopenharmony_ci	    hsotg->hw_params.arch == GHWCFG2_EXT_DMA_ARCH) {
78262306a36Sopenharmony_ci		if (!chan->do_split &&
78362306a36Sopenharmony_ci		    (chan->ep_type == USB_ENDPOINT_XFER_ISOC ||
78462306a36Sopenharmony_ci		     chan->ep_type == USB_ENDPOINT_XFER_INT)) {
78562306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s() Channel can't be halted\n",
78662306a36Sopenharmony_ci				__func__);
78762306a36Sopenharmony_ci			return;
78862306a36Sopenharmony_ci		}
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
79262306a36Sopenharmony_ci		dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
79562306a36Sopenharmony_ci	    halt_status == DWC2_HC_XFER_AHB_ERR) {
79662306a36Sopenharmony_ci		/*
79762306a36Sopenharmony_ci		 * Disable all channel interrupts except Ch Halted. The QTD
79862306a36Sopenharmony_ci		 * and QH state associated with this transfer has been cleared
79962306a36Sopenharmony_ci		 * (in the case of URB_DEQUEUE), so the channel needs to be
80062306a36Sopenharmony_ci		 * shut down carefully to prevent crashes.
80162306a36Sopenharmony_ci		 */
80262306a36Sopenharmony_ci		u32 hcintmsk = HCINTMSK_CHHLTD;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "dequeue/error\n");
80562306a36Sopenharmony_ci		dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		/*
80862306a36Sopenharmony_ci		 * Make sure no other interrupts besides halt are currently
80962306a36Sopenharmony_ci		 * pending. Handling another interrupt could cause a crash due
81062306a36Sopenharmony_ci		 * to the QTD and QH state.
81162306a36Sopenharmony_ci		 */
81262306a36Sopenharmony_ci		dwc2_writel(hsotg, ~hcintmsk, HCINT(chan->hc_num));
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		/*
81562306a36Sopenharmony_ci		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
81662306a36Sopenharmony_ci		 * even if the channel was already halted for some other
81762306a36Sopenharmony_ci		 * reason
81862306a36Sopenharmony_ci		 */
81962306a36Sopenharmony_ci		chan->halt_status = halt_status;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci		hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
82262306a36Sopenharmony_ci		if (!(hcchar & HCCHAR_CHENA)) {
82362306a36Sopenharmony_ci			/*
82462306a36Sopenharmony_ci			 * The channel is either already halted or it hasn't
82562306a36Sopenharmony_ci			 * started yet. In DMA mode, the transfer may halt if
82662306a36Sopenharmony_ci			 * it finishes normally or a condition occurs that
82762306a36Sopenharmony_ci			 * requires driver intervention. Don't want to halt
82862306a36Sopenharmony_ci			 * the channel again. In either Slave or DMA mode,
82962306a36Sopenharmony_ci			 * it's possible that the transfer has been assigned
83062306a36Sopenharmony_ci			 * to a channel, but not started yet when an URB is
83162306a36Sopenharmony_ci			 * dequeued. Don't want to halt a channel that hasn't
83262306a36Sopenharmony_ci			 * started yet.
83362306a36Sopenharmony_ci			 */
83462306a36Sopenharmony_ci			return;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	if (chan->halt_pending) {
83862306a36Sopenharmony_ci		/*
83962306a36Sopenharmony_ci		 * A halt has already been issued for this channel. This might
84062306a36Sopenharmony_ci		 * happen when a transfer is aborted by a higher level in
84162306a36Sopenharmony_ci		 * the stack.
84262306a36Sopenharmony_ci		 */
84362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
84462306a36Sopenharmony_ci			 "*** %s: Channel %d, chan->halt_pending already set ***\n",
84562306a36Sopenharmony_ci			 __func__, chan->hc_num);
84662306a36Sopenharmony_ci		return;
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* No need to set the bit in DDMA for disabling the channel */
85262306a36Sopenharmony_ci	/* TODO check it everywhere channel is disabled */
85362306a36Sopenharmony_ci	if (!hsotg->params.dma_desc_enable) {
85462306a36Sopenharmony_ci		if (dbg_hc(chan))
85562306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "desc DMA disabled\n");
85662306a36Sopenharmony_ci		hcchar |= HCCHAR_CHENA;
85762306a36Sopenharmony_ci	} else {
85862306a36Sopenharmony_ci		if (dbg_hc(chan))
85962306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "desc DMA enabled\n");
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci	hcchar |= HCCHAR_CHDIS;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (!hsotg->params.host_dma) {
86462306a36Sopenharmony_ci		if (dbg_hc(chan))
86562306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "DMA not enabled\n");
86662306a36Sopenharmony_ci		hcchar |= HCCHAR_CHENA;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		/* Check for space in the request queue to issue the halt */
86962306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
87062306a36Sopenharmony_ci		    chan->ep_type == USB_ENDPOINT_XFER_BULK) {
87162306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "control/bulk\n");
87262306a36Sopenharmony_ci			nptxsts = dwc2_readl(hsotg, GNPTXSTS);
87362306a36Sopenharmony_ci			if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
87462306a36Sopenharmony_ci				dev_vdbg(hsotg->dev, "Disabling channel\n");
87562306a36Sopenharmony_ci				hcchar &= ~HCCHAR_CHENA;
87662306a36Sopenharmony_ci			}
87762306a36Sopenharmony_ci		} else {
87862306a36Sopenharmony_ci			if (dbg_perio())
87962306a36Sopenharmony_ci				dev_vdbg(hsotg->dev, "isoc/intr\n");
88062306a36Sopenharmony_ci			hptxsts = dwc2_readl(hsotg, HPTXSTS);
88162306a36Sopenharmony_ci			if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
88262306a36Sopenharmony_ci			    hsotg->queuing_high_bandwidth) {
88362306a36Sopenharmony_ci				if (dbg_perio())
88462306a36Sopenharmony_ci					dev_vdbg(hsotg->dev, "Disabling channel\n");
88562306a36Sopenharmony_ci				hcchar &= ~HCCHAR_CHENA;
88662306a36Sopenharmony_ci			}
88762306a36Sopenharmony_ci		}
88862306a36Sopenharmony_ci	} else {
88962306a36Sopenharmony_ci		if (dbg_hc(chan))
89062306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "DMA enabled\n");
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
89462306a36Sopenharmony_ci	chan->halt_status = halt_status;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	if (hcchar & HCCHAR_CHENA) {
89762306a36Sopenharmony_ci		if (dbg_hc(chan))
89862306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "Channel enabled\n");
89962306a36Sopenharmony_ci		chan->halt_pending = 1;
90062306a36Sopenharmony_ci		chan->halt_on_queue = 0;
90162306a36Sopenharmony_ci	} else {
90262306a36Sopenharmony_ci		if (dbg_hc(chan))
90362306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "Channel disabled\n");
90462306a36Sopenharmony_ci		chan->halt_on_queue = 1;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (dbg_hc(chan)) {
90862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
90962306a36Sopenharmony_ci			 chan->hc_num);
91062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 hcchar: 0x%08x\n",
91162306a36Sopenharmony_ci			 hcchar);
91262306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 halt_pending: %d\n",
91362306a36Sopenharmony_ci			 chan->halt_pending);
91462306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 halt_on_queue: %d\n",
91562306a36Sopenharmony_ci			 chan->halt_on_queue);
91662306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 halt_status: %d\n",
91762306a36Sopenharmony_ci			 chan->halt_status);
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci/**
92262306a36Sopenharmony_ci * dwc2_hc_cleanup() - Clears the transfer state for a host channel
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
92562306a36Sopenharmony_ci * @chan:  Identifies the host channel to clean up
92662306a36Sopenharmony_ci *
92762306a36Sopenharmony_ci * This function is normally called after a transfer is done and the host
92862306a36Sopenharmony_ci * channel is being released
92962306a36Sopenharmony_ci */
93062306a36Sopenharmony_civoid dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	u32 hcintmsk;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	chan->xfer_started = 0;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	list_del_init(&chan->split_order_list_entry);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/*
93962306a36Sopenharmony_ci	 * Clear channel interrupt enables and any unhandled channel interrupt
94062306a36Sopenharmony_ci	 * conditions
94162306a36Sopenharmony_ci	 */
94262306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, HCINTMSK(chan->hc_num));
94362306a36Sopenharmony_ci	hcintmsk = 0xffffffff;
94462306a36Sopenharmony_ci	hcintmsk &= ~HCINTMSK_RESERVED14_31;
94562306a36Sopenharmony_ci	dwc2_writel(hsotg, hcintmsk, HCINT(chan->hc_num));
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci/**
94962306a36Sopenharmony_ci * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in
95062306a36Sopenharmony_ci * which frame a periodic transfer should occur
95162306a36Sopenharmony_ci *
95262306a36Sopenharmony_ci * @hsotg:  Programming view of DWC_otg controller
95362306a36Sopenharmony_ci * @chan:   Identifies the host channel to set up and its properties
95462306a36Sopenharmony_ci * @hcchar: Current value of the HCCHAR register for the specified host channel
95562306a36Sopenharmony_ci *
95662306a36Sopenharmony_ci * This function has no effect on non-periodic transfers
95762306a36Sopenharmony_ci */
95862306a36Sopenharmony_cistatic void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
95962306a36Sopenharmony_ci				       struct dwc2_host_chan *chan, u32 *hcchar)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
96262306a36Sopenharmony_ci	    chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
96362306a36Sopenharmony_ci		int host_speed;
96462306a36Sopenharmony_ci		int xfer_ns;
96562306a36Sopenharmony_ci		int xfer_us;
96662306a36Sopenharmony_ci		int bytes_in_fifo;
96762306a36Sopenharmony_ci		u16 fifo_space;
96862306a36Sopenharmony_ci		u16 frame_number;
96962306a36Sopenharmony_ci		u16 wire_frame;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		/*
97262306a36Sopenharmony_ci		 * Try to figure out if we're an even or odd frame. If we set
97362306a36Sopenharmony_ci		 * even and the current frame number is even the transfer
97462306a36Sopenharmony_ci		 * will happen immediately.  Similar if both are odd. If one is
97562306a36Sopenharmony_ci		 * even and the other is odd then the transfer will happen when
97662306a36Sopenharmony_ci		 * the frame number ticks.
97762306a36Sopenharmony_ci		 *
97862306a36Sopenharmony_ci		 * There's a bit of a balancing act to get this right.
97962306a36Sopenharmony_ci		 * Sometimes we may want to send data in the current frame (AK
98062306a36Sopenharmony_ci		 * right away).  We might want to do this if the frame number
98162306a36Sopenharmony_ci		 * _just_ ticked, but we might also want to do this in order
98262306a36Sopenharmony_ci		 * to continue a split transaction that happened late in a
98362306a36Sopenharmony_ci		 * microframe (so we didn't know to queue the next transfer
98462306a36Sopenharmony_ci		 * until the frame number had ticked).  The problem is that we
98562306a36Sopenharmony_ci		 * need a lot of knowledge to know if there's actually still
98662306a36Sopenharmony_ci		 * time to send things or if it would be better to wait until
98762306a36Sopenharmony_ci		 * the next frame.
98862306a36Sopenharmony_ci		 *
98962306a36Sopenharmony_ci		 * We can look at how much time is left in the current frame
99062306a36Sopenharmony_ci		 * and make a guess about whether we'll have time to transfer.
99162306a36Sopenharmony_ci		 * We'll do that.
99262306a36Sopenharmony_ci		 */
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		/* Get speed host is running at */
99562306a36Sopenharmony_ci		host_speed = (chan->speed != USB_SPEED_HIGH &&
99662306a36Sopenharmony_ci			      !chan->do_split) ? chan->speed : USB_SPEED_HIGH;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		/* See how many bytes are in the periodic FIFO right now */
99962306a36Sopenharmony_ci		fifo_space = (dwc2_readl(hsotg, HPTXSTS) &
100062306a36Sopenharmony_ci			      TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT;
100162306a36Sopenharmony_ci		bytes_in_fifo = sizeof(u32) *
100262306a36Sopenharmony_ci				(hsotg->params.host_perio_tx_fifo_size -
100362306a36Sopenharmony_ci				 fifo_space);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci		/*
100662306a36Sopenharmony_ci		 * Roughly estimate bus time for everything in the periodic
100762306a36Sopenharmony_ci		 * queue + our new transfer.  This is "rough" because we're
100862306a36Sopenharmony_ci		 * using a function that makes takes into account IN/OUT
100962306a36Sopenharmony_ci		 * and INT/ISO and we're just slamming in one value for all
101062306a36Sopenharmony_ci		 * transfers.  This should be an over-estimate and that should
101162306a36Sopenharmony_ci		 * be OK, but we can probably tighten it.
101262306a36Sopenharmony_ci		 */
101362306a36Sopenharmony_ci		xfer_ns = usb_calc_bus_time(host_speed, false, false,
101462306a36Sopenharmony_ci					    chan->xfer_len + bytes_in_fifo);
101562306a36Sopenharmony_ci		xfer_us = NS_TO_US(xfer_ns);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci		/* See what frame number we'll be at by the time we finish */
101862306a36Sopenharmony_ci		frame_number = dwc2_hcd_get_future_frame_number(hsotg, xfer_us);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		/* This is when we were scheduled to be on the wire */
102162306a36Sopenharmony_ci		wire_frame = dwc2_frame_num_inc(chan->qh->next_active_frame, 1);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci		/*
102462306a36Sopenharmony_ci		 * If we'd finish _after_ the frame we're scheduled in then
102562306a36Sopenharmony_ci		 * it's hopeless.  Just schedule right away and hope for the
102662306a36Sopenharmony_ci		 * best.  Note that it _might_ be wise to call back into the
102762306a36Sopenharmony_ci		 * scheduler to pick a better frame, but this is better than
102862306a36Sopenharmony_ci		 * nothing.
102962306a36Sopenharmony_ci		 */
103062306a36Sopenharmony_ci		if (dwc2_frame_num_gt(frame_number, wire_frame)) {
103162306a36Sopenharmony_ci			dwc2_sch_vdbg(hsotg,
103262306a36Sopenharmony_ci				      "QH=%p EO MISS fr=%04x=>%04x (%+d)\n",
103362306a36Sopenharmony_ci				      chan->qh, wire_frame, frame_number,
103462306a36Sopenharmony_ci				      dwc2_frame_num_dec(frame_number,
103562306a36Sopenharmony_ci							 wire_frame));
103662306a36Sopenharmony_ci			wire_frame = frame_number;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci			/*
103962306a36Sopenharmony_ci			 * We picked a different frame number; communicate this
104062306a36Sopenharmony_ci			 * back to the scheduler so it doesn't try to schedule
104162306a36Sopenharmony_ci			 * another in the same frame.
104262306a36Sopenharmony_ci			 *
104362306a36Sopenharmony_ci			 * Remember that next_active_frame is 1 before the wire
104462306a36Sopenharmony_ci			 * frame.
104562306a36Sopenharmony_ci			 */
104662306a36Sopenharmony_ci			chan->qh->next_active_frame =
104762306a36Sopenharmony_ci				dwc2_frame_num_dec(frame_number, 1);
104862306a36Sopenharmony_ci		}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		if (wire_frame & 1)
105162306a36Sopenharmony_ci			*hcchar |= HCCHAR_ODDFRM;
105262306a36Sopenharmony_ci		else
105362306a36Sopenharmony_ci			*hcchar &= ~HCCHAR_ODDFRM;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic void dwc2_set_pid_isoc(struct dwc2_host_chan *chan)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	/* Set up the initial PID for the transfer */
106062306a36Sopenharmony_ci	if (chan->speed == USB_SPEED_HIGH) {
106162306a36Sopenharmony_ci		if (chan->ep_is_in) {
106262306a36Sopenharmony_ci			if (chan->multi_count == 1)
106362306a36Sopenharmony_ci				chan->data_pid_start = DWC2_HC_PID_DATA0;
106462306a36Sopenharmony_ci			else if (chan->multi_count == 2)
106562306a36Sopenharmony_ci				chan->data_pid_start = DWC2_HC_PID_DATA1;
106662306a36Sopenharmony_ci			else
106762306a36Sopenharmony_ci				chan->data_pid_start = DWC2_HC_PID_DATA2;
106862306a36Sopenharmony_ci		} else {
106962306a36Sopenharmony_ci			if (chan->multi_count == 1)
107062306a36Sopenharmony_ci				chan->data_pid_start = DWC2_HC_PID_DATA0;
107162306a36Sopenharmony_ci			else
107262306a36Sopenharmony_ci				chan->data_pid_start = DWC2_HC_PID_MDATA;
107362306a36Sopenharmony_ci		}
107462306a36Sopenharmony_ci	} else {
107562306a36Sopenharmony_ci		chan->data_pid_start = DWC2_HC_PID_DATA0;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/**
108062306a36Sopenharmony_ci * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with
108162306a36Sopenharmony_ci * the Host Channel
108262306a36Sopenharmony_ci *
108362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
108462306a36Sopenharmony_ci * @chan:  Information needed to initialize the host channel
108562306a36Sopenharmony_ci *
108662306a36Sopenharmony_ci * This function should only be called in Slave mode. For a channel associated
108762306a36Sopenharmony_ci * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel
108862306a36Sopenharmony_ci * associated with a periodic EP, the periodic Tx FIFO is written.
108962306a36Sopenharmony_ci *
109062306a36Sopenharmony_ci * Upon return the xfer_buf and xfer_count fields in chan are incremented by
109162306a36Sopenharmony_ci * the number of bytes written to the Tx FIFO.
109262306a36Sopenharmony_ci */
109362306a36Sopenharmony_cistatic void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
109462306a36Sopenharmony_ci				 struct dwc2_host_chan *chan)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	u32 i;
109762306a36Sopenharmony_ci	u32 remaining_count;
109862306a36Sopenharmony_ci	u32 byte_count;
109962306a36Sopenharmony_ci	u32 dword_count;
110062306a36Sopenharmony_ci	u32 *data_buf = (u32 *)chan->xfer_buf;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	if (dbg_hc(chan))
110362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s()\n", __func__);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	remaining_count = chan->xfer_len - chan->xfer_count;
110662306a36Sopenharmony_ci	if (remaining_count > chan->max_packet)
110762306a36Sopenharmony_ci		byte_count = chan->max_packet;
110862306a36Sopenharmony_ci	else
110962306a36Sopenharmony_ci		byte_count = remaining_count;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	dword_count = (byte_count + 3) / 4;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (((unsigned long)data_buf & 0x3) == 0) {
111462306a36Sopenharmony_ci		/* xfer_buf is DWORD aligned */
111562306a36Sopenharmony_ci		for (i = 0; i < dword_count; i++, data_buf++)
111662306a36Sopenharmony_ci			dwc2_writel(hsotg, *data_buf, HCFIFO(chan->hc_num));
111762306a36Sopenharmony_ci	} else {
111862306a36Sopenharmony_ci		/* xfer_buf is not DWORD aligned */
111962306a36Sopenharmony_ci		for (i = 0; i < dword_count; i++, data_buf++) {
112062306a36Sopenharmony_ci			u32 data = data_buf[0] | data_buf[1] << 8 |
112162306a36Sopenharmony_ci				   data_buf[2] << 16 | data_buf[3] << 24;
112262306a36Sopenharmony_ci			dwc2_writel(hsotg, data, HCFIFO(chan->hc_num));
112362306a36Sopenharmony_ci		}
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	chan->xfer_count += byte_count;
112762306a36Sopenharmony_ci	chan->xfer_buf += byte_count;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci/**
113162306a36Sopenharmony_ci * dwc2_hc_do_ping() - Starts a PING transfer
113262306a36Sopenharmony_ci *
113362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
113462306a36Sopenharmony_ci * @chan:  Information needed to initialize the host channel
113562306a36Sopenharmony_ci *
113662306a36Sopenharmony_ci * This function should only be called in Slave mode. The Do Ping bit is set in
113762306a36Sopenharmony_ci * the HCTSIZ register, then the channel is enabled.
113862306a36Sopenharmony_ci */
113962306a36Sopenharmony_cistatic void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
114062306a36Sopenharmony_ci			    struct dwc2_host_chan *chan)
114162306a36Sopenharmony_ci{
114262306a36Sopenharmony_ci	u32 hcchar;
114362306a36Sopenharmony_ci	u32 hctsiz;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	if (dbg_hc(chan))
114662306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
114762306a36Sopenharmony_ci			 chan->hc_num);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	hctsiz = TSIZ_DOPNG;
115062306a36Sopenharmony_ci	hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
115162306a36Sopenharmony_ci	dwc2_writel(hsotg, hctsiz, HCTSIZ(chan->hc_num));
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
115462306a36Sopenharmony_ci	hcchar |= HCCHAR_CHENA;
115562306a36Sopenharmony_ci	hcchar &= ~HCCHAR_CHDIS;
115662306a36Sopenharmony_ci	dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci/**
116062306a36Sopenharmony_ci * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host
116162306a36Sopenharmony_ci * channel and starts the transfer
116262306a36Sopenharmony_ci *
116362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
116462306a36Sopenharmony_ci * @chan:  Information needed to initialize the host channel. The xfer_len value
116562306a36Sopenharmony_ci *         may be reduced to accommodate the max widths of the XferSize and
116662306a36Sopenharmony_ci *         PktCnt fields in the HCTSIZn register. The multi_count value may be
116762306a36Sopenharmony_ci *         changed to reflect the final xfer_len value.
116862306a36Sopenharmony_ci *
116962306a36Sopenharmony_ci * This function may be called in either Slave mode or DMA mode. In Slave mode,
117062306a36Sopenharmony_ci * the caller must ensure that there is sufficient space in the request queue
117162306a36Sopenharmony_ci * and Tx Data FIFO.
117262306a36Sopenharmony_ci *
117362306a36Sopenharmony_ci * For an OUT transfer in Slave mode, it loads a data packet into the
117462306a36Sopenharmony_ci * appropriate FIFO. If necessary, additional data packets are loaded in the
117562306a36Sopenharmony_ci * Host ISR.
117662306a36Sopenharmony_ci *
117762306a36Sopenharmony_ci * For an IN transfer in Slave mode, a data packet is requested. The data
117862306a36Sopenharmony_ci * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
117962306a36Sopenharmony_ci * additional data packets are requested in the Host ISR.
118062306a36Sopenharmony_ci *
118162306a36Sopenharmony_ci * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
118262306a36Sopenharmony_ci * register along with a packet count of 1 and the channel is enabled. This
118362306a36Sopenharmony_ci * causes a single PING transaction to occur. Other fields in HCTSIZ are
118462306a36Sopenharmony_ci * simply set to 0 since no data transfer occurs in this case.
118562306a36Sopenharmony_ci *
118662306a36Sopenharmony_ci * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
118762306a36Sopenharmony_ci * all the information required to perform the subsequent data transfer. In
118862306a36Sopenharmony_ci * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
118962306a36Sopenharmony_ci * controller performs the entire PING protocol, then starts the data
119062306a36Sopenharmony_ci * transfer.
119162306a36Sopenharmony_ci */
119262306a36Sopenharmony_cistatic void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
119362306a36Sopenharmony_ci				   struct dwc2_host_chan *chan)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	u32 max_hc_xfer_size = hsotg->params.max_transfer_size;
119662306a36Sopenharmony_ci	u16 max_hc_pkt_count = hsotg->params.max_packet_count;
119762306a36Sopenharmony_ci	u32 hcchar;
119862306a36Sopenharmony_ci	u32 hctsiz = 0;
119962306a36Sopenharmony_ci	u16 num_packets;
120062306a36Sopenharmony_ci	u32 ec_mc;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (dbg_hc(chan))
120362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s()\n", __func__);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (chan->do_ping) {
120662306a36Sopenharmony_ci		if (!hsotg->params.host_dma) {
120762306a36Sopenharmony_ci			if (dbg_hc(chan))
120862306a36Sopenharmony_ci				dev_vdbg(hsotg->dev, "ping, no DMA\n");
120962306a36Sopenharmony_ci			dwc2_hc_do_ping(hsotg, chan);
121062306a36Sopenharmony_ci			chan->xfer_started = 1;
121162306a36Sopenharmony_ci			return;
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		if (dbg_hc(chan))
121562306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "ping, DMA\n");
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		hctsiz |= TSIZ_DOPNG;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	if (chan->do_split) {
122162306a36Sopenharmony_ci		if (dbg_hc(chan))
122262306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "split\n");
122362306a36Sopenharmony_ci		num_packets = 1;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		if (chan->complete_split && !chan->ep_is_in)
122662306a36Sopenharmony_ci			/*
122762306a36Sopenharmony_ci			 * For CSPLIT OUT Transfer, set the size to 0 so the
122862306a36Sopenharmony_ci			 * core doesn't expect any data written to the FIFO
122962306a36Sopenharmony_ci			 */
123062306a36Sopenharmony_ci			chan->xfer_len = 0;
123162306a36Sopenharmony_ci		else if (chan->ep_is_in || chan->xfer_len > chan->max_packet)
123262306a36Sopenharmony_ci			chan->xfer_len = chan->max_packet;
123362306a36Sopenharmony_ci		else if (!chan->ep_is_in && chan->xfer_len > 188)
123462306a36Sopenharmony_ci			chan->xfer_len = 188;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
123762306a36Sopenharmony_ci			  TSIZ_XFERSIZE_MASK;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		/* For split set ec_mc for immediate retries */
124062306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
124162306a36Sopenharmony_ci		    chan->ep_type == USB_ENDPOINT_XFER_ISOC)
124262306a36Sopenharmony_ci			ec_mc = 3;
124362306a36Sopenharmony_ci		else
124462306a36Sopenharmony_ci			ec_mc = 1;
124562306a36Sopenharmony_ci	} else {
124662306a36Sopenharmony_ci		if (dbg_hc(chan))
124762306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "no split\n");
124862306a36Sopenharmony_ci		/*
124962306a36Sopenharmony_ci		 * Ensure that the transfer length and packet count will fit
125062306a36Sopenharmony_ci		 * in the widths allocated for them in the HCTSIZn register
125162306a36Sopenharmony_ci		 */
125262306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
125362306a36Sopenharmony_ci		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
125462306a36Sopenharmony_ci			/*
125562306a36Sopenharmony_ci			 * Make sure the transfer size is no larger than one
125662306a36Sopenharmony_ci			 * (micro)frame's worth of data. (A check was done
125762306a36Sopenharmony_ci			 * when the periodic transfer was accepted to ensure
125862306a36Sopenharmony_ci			 * that a (micro)frame's worth of data can be
125962306a36Sopenharmony_ci			 * programmed into a channel.)
126062306a36Sopenharmony_ci			 */
126162306a36Sopenharmony_ci			u32 max_periodic_len =
126262306a36Sopenharmony_ci				chan->multi_count * chan->max_packet;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci			if (chan->xfer_len > max_periodic_len)
126562306a36Sopenharmony_ci				chan->xfer_len = max_periodic_len;
126662306a36Sopenharmony_ci		} else if (chan->xfer_len > max_hc_xfer_size) {
126762306a36Sopenharmony_ci			/*
126862306a36Sopenharmony_ci			 * Make sure that xfer_len is a multiple of max packet
126962306a36Sopenharmony_ci			 * size
127062306a36Sopenharmony_ci			 */
127162306a36Sopenharmony_ci			chan->xfer_len =
127262306a36Sopenharmony_ci				max_hc_xfer_size - chan->max_packet + 1;
127362306a36Sopenharmony_ci		}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci		if (chan->xfer_len > 0) {
127662306a36Sopenharmony_ci			num_packets = (chan->xfer_len + chan->max_packet - 1) /
127762306a36Sopenharmony_ci					chan->max_packet;
127862306a36Sopenharmony_ci			if (num_packets > max_hc_pkt_count) {
127962306a36Sopenharmony_ci				num_packets = max_hc_pkt_count;
128062306a36Sopenharmony_ci				chan->xfer_len = num_packets * chan->max_packet;
128162306a36Sopenharmony_ci			} else if (chan->ep_is_in) {
128262306a36Sopenharmony_ci				/*
128362306a36Sopenharmony_ci				 * Always program an integral # of max packets
128462306a36Sopenharmony_ci				 * for IN transfers.
128562306a36Sopenharmony_ci				 * Note: This assumes that the input buffer is
128662306a36Sopenharmony_ci				 * aligned and sized accordingly.
128762306a36Sopenharmony_ci				 */
128862306a36Sopenharmony_ci				chan->xfer_len = num_packets * chan->max_packet;
128962306a36Sopenharmony_ci			}
129062306a36Sopenharmony_ci		} else {
129162306a36Sopenharmony_ci			/* Need 1 packet for transfer length of 0 */
129262306a36Sopenharmony_ci			num_packets = 1;
129362306a36Sopenharmony_ci		}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
129662306a36Sopenharmony_ci		    chan->ep_type == USB_ENDPOINT_XFER_ISOC)
129762306a36Sopenharmony_ci			/*
129862306a36Sopenharmony_ci			 * Make sure that the multi_count field matches the
129962306a36Sopenharmony_ci			 * actual transfer length
130062306a36Sopenharmony_ci			 */
130162306a36Sopenharmony_ci			chan->multi_count = num_packets;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
130462306a36Sopenharmony_ci			dwc2_set_pid_isoc(chan);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
130762306a36Sopenharmony_ci			  TSIZ_XFERSIZE_MASK;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci		/* The ec_mc gets the multi_count for non-split */
131062306a36Sopenharmony_ci		ec_mc = chan->multi_count;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	chan->start_pkt_count = num_packets;
131462306a36Sopenharmony_ci	hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
131562306a36Sopenharmony_ci	hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
131662306a36Sopenharmony_ci		  TSIZ_SC_MC_PID_MASK;
131762306a36Sopenharmony_ci	dwc2_writel(hsotg, hctsiz, HCTSIZ(chan->hc_num));
131862306a36Sopenharmony_ci	if (dbg_hc(chan)) {
131962306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
132062306a36Sopenharmony_ci			 hctsiz, chan->hc_num);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
132362306a36Sopenharmony_ci			 chan->hc_num);
132462306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Xfer Size: %d\n",
132562306a36Sopenharmony_ci			 (hctsiz & TSIZ_XFERSIZE_MASK) >>
132662306a36Sopenharmony_ci			 TSIZ_XFERSIZE_SHIFT);
132762306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Num Pkts: %d\n",
132862306a36Sopenharmony_ci			 (hctsiz & TSIZ_PKTCNT_MASK) >>
132962306a36Sopenharmony_ci			 TSIZ_PKTCNT_SHIFT);
133062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Start PID: %d\n",
133162306a36Sopenharmony_ci			 (hctsiz & TSIZ_SC_MC_PID_MASK) >>
133262306a36Sopenharmony_ci			 TSIZ_SC_MC_PID_SHIFT);
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (hsotg->params.host_dma) {
133662306a36Sopenharmony_ci		dma_addr_t dma_addr;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		if (chan->align_buf) {
133962306a36Sopenharmony_ci			if (dbg_hc(chan))
134062306a36Sopenharmony_ci				dev_vdbg(hsotg->dev, "align_buf\n");
134162306a36Sopenharmony_ci			dma_addr = chan->align_buf;
134262306a36Sopenharmony_ci		} else {
134362306a36Sopenharmony_ci			dma_addr = chan->xfer_dma;
134462306a36Sopenharmony_ci		}
134562306a36Sopenharmony_ci		dwc2_writel(hsotg, (u32)dma_addr, HCDMA(chan->hc_num));
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci		if (dbg_hc(chan))
134862306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
134962306a36Sopenharmony_ci				 (unsigned long)dma_addr, chan->hc_num);
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	/* Start the split */
135362306a36Sopenharmony_ci	if (chan->do_split) {
135462306a36Sopenharmony_ci		u32 hcsplt = dwc2_readl(hsotg, HCSPLT(chan->hc_num));
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci		hcsplt |= HCSPLT_SPLTENA;
135762306a36Sopenharmony_ci		dwc2_writel(hsotg, hcsplt, HCSPLT(chan->hc_num));
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
136162306a36Sopenharmony_ci	hcchar &= ~HCCHAR_MULTICNT_MASK;
136262306a36Sopenharmony_ci	hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;
136362306a36Sopenharmony_ci	dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (hcchar & HCCHAR_CHDIS)
136662306a36Sopenharmony_ci		dev_warn(hsotg->dev,
136762306a36Sopenharmony_ci			 "%s: chdis set, channel %d, hcchar 0x%08x\n",
136862306a36Sopenharmony_ci			 __func__, chan->hc_num, hcchar);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/* Set host channel enable after all other setup is complete */
137162306a36Sopenharmony_ci	hcchar |= HCCHAR_CHENA;
137262306a36Sopenharmony_ci	hcchar &= ~HCCHAR_CHDIS;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (dbg_hc(chan))
137562306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n",
137662306a36Sopenharmony_ci			 (hcchar & HCCHAR_MULTICNT_MASK) >>
137762306a36Sopenharmony_ci			 HCCHAR_MULTICNT_SHIFT);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
138062306a36Sopenharmony_ci	if (dbg_hc(chan))
138162306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
138262306a36Sopenharmony_ci			 chan->hc_num);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	chan->xfer_started = 1;
138562306a36Sopenharmony_ci	chan->requests++;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (!hsotg->params.host_dma &&
138862306a36Sopenharmony_ci	    !chan->ep_is_in && chan->xfer_len > 0)
138962306a36Sopenharmony_ci		/* Load OUT packet into the appropriate Tx FIFO */
139062306a36Sopenharmony_ci		dwc2_hc_write_packet(hsotg, chan);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci/**
139462306a36Sopenharmony_ci * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a
139562306a36Sopenharmony_ci * host channel and starts the transfer in Descriptor DMA mode
139662306a36Sopenharmony_ci *
139762306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
139862306a36Sopenharmony_ci * @chan:  Information needed to initialize the host channel
139962306a36Sopenharmony_ci *
140062306a36Sopenharmony_ci * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
140162306a36Sopenharmony_ci * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field
140262306a36Sopenharmony_ci * with micro-frame bitmap.
140362306a36Sopenharmony_ci *
140462306a36Sopenharmony_ci * Initializes HCDMA register with descriptor list address and CTD value then
140562306a36Sopenharmony_ci * starts the transfer via enabling the channel.
140662306a36Sopenharmony_ci */
140762306a36Sopenharmony_civoid dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
140862306a36Sopenharmony_ci				 struct dwc2_host_chan *chan)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	u32 hcchar;
141162306a36Sopenharmony_ci	u32 hctsiz = 0;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (chan->do_ping)
141462306a36Sopenharmony_ci		hctsiz |= TSIZ_DOPNG;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
141762306a36Sopenharmony_ci		dwc2_set_pid_isoc(chan);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	/* Packet Count and Xfer Size are not used in Descriptor DMA mode */
142062306a36Sopenharmony_ci	hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
142162306a36Sopenharmony_ci		  TSIZ_SC_MC_PID_MASK;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* 0 - 1 descriptor, 1 - 2 descriptors, etc */
142462306a36Sopenharmony_ci	hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	/* Non-zero only for high-speed interrupt endpoints */
142762306a36Sopenharmony_ci	hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if (dbg_hc(chan)) {
143062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
143162306a36Sopenharmony_ci			 chan->hc_num);
143262306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Start PID: %d\n",
143362306a36Sopenharmony_ci			 chan->data_pid_start);
143462306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 NTD: %d\n", chan->ntd - 1);
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	dwc2_writel(hsotg, hctsiz, HCTSIZ(chan->hc_num));
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	dma_sync_single_for_device(hsotg->dev, chan->desc_list_addr,
144062306a36Sopenharmony_ci				   chan->desc_list_sz, DMA_TO_DEVICE);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	dwc2_writel(hsotg, chan->desc_list_addr, HCDMA(chan->hc_num));
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (dbg_hc(chan))
144562306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n",
144662306a36Sopenharmony_ci			 &chan->desc_list_addr, chan->hc_num);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
144962306a36Sopenharmony_ci	hcchar &= ~HCCHAR_MULTICNT_MASK;
145062306a36Sopenharmony_ci	hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
145162306a36Sopenharmony_ci		  HCCHAR_MULTICNT_MASK;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (hcchar & HCCHAR_CHDIS)
145462306a36Sopenharmony_ci		dev_warn(hsotg->dev,
145562306a36Sopenharmony_ci			 "%s: chdis set, channel %d, hcchar 0x%08x\n",
145662306a36Sopenharmony_ci			 __func__, chan->hc_num, hcchar);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	/* Set host channel enable after all other setup is complete */
145962306a36Sopenharmony_ci	hcchar |= HCCHAR_CHENA;
146062306a36Sopenharmony_ci	hcchar &= ~HCCHAR_CHDIS;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (dbg_hc(chan))
146362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n",
146462306a36Sopenharmony_ci			 (hcchar & HCCHAR_MULTICNT_MASK) >>
146562306a36Sopenharmony_ci			 HCCHAR_MULTICNT_SHIFT);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
146862306a36Sopenharmony_ci	if (dbg_hc(chan))
146962306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
147062306a36Sopenharmony_ci			 chan->hc_num);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	chan->xfer_started = 1;
147362306a36Sopenharmony_ci	chan->requests++;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci/**
147762306a36Sopenharmony_ci * dwc2_hc_continue_transfer() - Continues a data transfer that was started by
147862306a36Sopenharmony_ci * a previous call to dwc2_hc_start_transfer()
147962306a36Sopenharmony_ci *
148062306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
148162306a36Sopenharmony_ci * @chan:  Information needed to initialize the host channel
148262306a36Sopenharmony_ci *
148362306a36Sopenharmony_ci * The caller must ensure there is sufficient space in the request queue and Tx
148462306a36Sopenharmony_ci * Data FIFO. This function should only be called in Slave mode. In DMA mode,
148562306a36Sopenharmony_ci * the controller acts autonomously to complete transfers programmed to a host
148662306a36Sopenharmony_ci * channel.
148762306a36Sopenharmony_ci *
148862306a36Sopenharmony_ci * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
148962306a36Sopenharmony_ci * if there is any data remaining to be queued. For an IN transfer, another
149062306a36Sopenharmony_ci * data packet is always requested. For the SETUP phase of a control transfer,
149162306a36Sopenharmony_ci * this function does nothing.
149262306a36Sopenharmony_ci *
149362306a36Sopenharmony_ci * Return: 1 if a new request is queued, 0 if no more requests are required
149462306a36Sopenharmony_ci * for this transfer
149562306a36Sopenharmony_ci */
149662306a36Sopenharmony_cistatic int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
149762306a36Sopenharmony_ci				     struct dwc2_host_chan *chan)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	if (dbg_hc(chan))
150062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
150162306a36Sopenharmony_ci			 chan->hc_num);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	if (chan->do_split)
150462306a36Sopenharmony_ci		/* SPLITs always queue just once per channel */
150562306a36Sopenharmony_ci		return 0;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	if (chan->data_pid_start == DWC2_HC_PID_SETUP)
150862306a36Sopenharmony_ci		/* SETUPs are queued only once since they can't be NAK'd */
150962306a36Sopenharmony_ci		return 0;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	if (chan->ep_is_in) {
151262306a36Sopenharmony_ci		/*
151362306a36Sopenharmony_ci		 * Always queue another request for other IN transfers. If
151462306a36Sopenharmony_ci		 * back-to-back INs are issued and NAKs are received for both,
151562306a36Sopenharmony_ci		 * the driver may still be processing the first NAK when the
151662306a36Sopenharmony_ci		 * second NAK is received. When the interrupt handler clears
151762306a36Sopenharmony_ci		 * the NAK interrupt for the first NAK, the second NAK will
151862306a36Sopenharmony_ci		 * not be seen. So we can't depend on the NAK interrupt
151962306a36Sopenharmony_ci		 * handler to requeue a NAK'd request. Instead, IN requests
152062306a36Sopenharmony_ci		 * are issued each time this function is called. When the
152162306a36Sopenharmony_ci		 * transfer completes, the extra requests for the channel will
152262306a36Sopenharmony_ci		 * be flushed.
152362306a36Sopenharmony_ci		 */
152462306a36Sopenharmony_ci		u32 hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci		dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
152762306a36Sopenharmony_ci		hcchar |= HCCHAR_CHENA;
152862306a36Sopenharmony_ci		hcchar &= ~HCCHAR_CHDIS;
152962306a36Sopenharmony_ci		if (dbg_hc(chan))
153062306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "	 IN xfer: hcchar = 0x%08x\n",
153162306a36Sopenharmony_ci				 hcchar);
153262306a36Sopenharmony_ci		dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
153362306a36Sopenharmony_ci		chan->requests++;
153462306a36Sopenharmony_ci		return 1;
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	/* OUT transfers */
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (chan->xfer_count < chan->xfer_len) {
154062306a36Sopenharmony_ci		if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
154162306a36Sopenharmony_ci		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
154262306a36Sopenharmony_ci			u32 hcchar = dwc2_readl(hsotg,
154362306a36Sopenharmony_ci						HCCHAR(chan->hc_num));
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci			dwc2_hc_set_even_odd_frame(hsotg, chan,
154662306a36Sopenharmony_ci						   &hcchar);
154762306a36Sopenharmony_ci		}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci		/* Load OUT packet into the appropriate Tx FIFO */
155062306a36Sopenharmony_ci		dwc2_hc_write_packet(hsotg, chan);
155162306a36Sopenharmony_ci		chan->requests++;
155262306a36Sopenharmony_ci		return 1;
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	return 0;
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci/*
155962306a36Sopenharmony_ci * =========================================================================
156062306a36Sopenharmony_ci *  HCD
156162306a36Sopenharmony_ci * =========================================================================
156262306a36Sopenharmony_ci */
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci/*
156562306a36Sopenharmony_ci * Processes all the URBs in a single list of QHs. Completes them with
156662306a36Sopenharmony_ci * -ETIMEDOUT and frees the QTD.
156762306a36Sopenharmony_ci *
156862306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
156962306a36Sopenharmony_ci */
157062306a36Sopenharmony_cistatic void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
157162306a36Sopenharmony_ci				      struct list_head *qh_list)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	struct dwc2_qh *qh, *qh_tmp;
157462306a36Sopenharmony_ci	struct dwc2_qtd *qtd, *qtd_tmp;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
157762306a36Sopenharmony_ci		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
157862306a36Sopenharmony_ci					 qtd_list_entry) {
157962306a36Sopenharmony_ci			dwc2_host_complete(hsotg, qtd, -ECONNRESET);
158062306a36Sopenharmony_ci			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
158162306a36Sopenharmony_ci		}
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
158662306a36Sopenharmony_ci			      struct list_head *qh_list)
158762306a36Sopenharmony_ci{
158862306a36Sopenharmony_ci	struct dwc2_qtd *qtd, *qtd_tmp;
158962306a36Sopenharmony_ci	struct dwc2_qh *qh, *qh_tmp;
159062306a36Sopenharmony_ci	unsigned long flags;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	if (!qh_list->next)
159362306a36Sopenharmony_ci		/* The list hasn't been initialized yet */
159462306a36Sopenharmony_ci		return;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	/* Ensure there are no QTDs or URBs left */
159962306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, qh_list);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
160262306a36Sopenharmony_ci		dwc2_hcd_qh_unlink(hsotg, qh);
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci		/* Free each QTD in the QH's QTD list */
160562306a36Sopenharmony_ci		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
160662306a36Sopenharmony_ci					 qtd_list_entry)
160762306a36Sopenharmony_ci			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci		if (qh->channel && qh->channel->qh == qh)
161062306a36Sopenharmony_ci			qh->channel->qh = NULL;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
161362306a36Sopenharmony_ci		dwc2_hcd_qh_free(hsotg, qh);
161462306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
161862306a36Sopenharmony_ci}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci/*
162162306a36Sopenharmony_ci * Responds with an error status of -ETIMEDOUT to all URBs in the non-periodic
162262306a36Sopenharmony_ci * and periodic schedules. The QTD associated with each URB is removed from
162362306a36Sopenharmony_ci * the schedule and freed. This function may be called when a disconnect is
162462306a36Sopenharmony_ci * detected or when the HCD is being stopped.
162562306a36Sopenharmony_ci *
162662306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
162762306a36Sopenharmony_ci */
162862306a36Sopenharmony_cistatic void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
163162306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
163262306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
163362306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
163462306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
163562306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_assigned);
163662306a36Sopenharmony_ci	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_queued);
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci/**
164062306a36Sopenharmony_ci * dwc2_hcd_start() - Starts the HCD when switching to Host mode
164162306a36Sopenharmony_ci *
164262306a36Sopenharmony_ci * @hsotg: Pointer to struct dwc2_hsotg
164362306a36Sopenharmony_ci */
164462306a36Sopenharmony_civoid dwc2_hcd_start(struct dwc2_hsotg *hsotg)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	u32 hprt0;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if (hsotg->op_state == OTG_STATE_B_HOST) {
164962306a36Sopenharmony_ci		/*
165062306a36Sopenharmony_ci		 * Reset the port. During a HNP mode switch the reset
165162306a36Sopenharmony_ci		 * needs to occur within 1ms and have a duration of at
165262306a36Sopenharmony_ci		 * least 50ms.
165362306a36Sopenharmony_ci		 */
165462306a36Sopenharmony_ci		hprt0 = dwc2_read_hprt0(hsotg);
165562306a36Sopenharmony_ci		hprt0 |= HPRT0_RST;
165662306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
166062306a36Sopenharmony_ci			   msecs_to_jiffies(50));
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci/* Must be called with interrupt disabled and spinlock held */
166462306a36Sopenharmony_cistatic void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	int num_channels = hsotg->params.host_channels;
166762306a36Sopenharmony_ci	struct dwc2_host_chan *channel;
166862306a36Sopenharmony_ci	u32 hcchar;
166962306a36Sopenharmony_ci	int i;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	if (!hsotg->params.host_dma) {
167262306a36Sopenharmony_ci		/* Flush out any channel requests in slave mode */
167362306a36Sopenharmony_ci		for (i = 0; i < num_channels; i++) {
167462306a36Sopenharmony_ci			channel = hsotg->hc_ptr_array[i];
167562306a36Sopenharmony_ci			if (!list_empty(&channel->hc_list_entry))
167662306a36Sopenharmony_ci				continue;
167762306a36Sopenharmony_ci			hcchar = dwc2_readl(hsotg, HCCHAR(i));
167862306a36Sopenharmony_ci			if (hcchar & HCCHAR_CHENA) {
167962306a36Sopenharmony_ci				hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
168062306a36Sopenharmony_ci				hcchar |= HCCHAR_CHDIS;
168162306a36Sopenharmony_ci				dwc2_writel(hsotg, hcchar, HCCHAR(i));
168262306a36Sopenharmony_ci			}
168362306a36Sopenharmony_ci		}
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	for (i = 0; i < num_channels; i++) {
168762306a36Sopenharmony_ci		channel = hsotg->hc_ptr_array[i];
168862306a36Sopenharmony_ci		if (!list_empty(&channel->hc_list_entry))
168962306a36Sopenharmony_ci			continue;
169062306a36Sopenharmony_ci		hcchar = dwc2_readl(hsotg, HCCHAR(i));
169162306a36Sopenharmony_ci		if (hcchar & HCCHAR_CHENA) {
169262306a36Sopenharmony_ci			/* Halt the channel */
169362306a36Sopenharmony_ci			hcchar |= HCCHAR_CHDIS;
169462306a36Sopenharmony_ci			dwc2_writel(hsotg, hcchar, HCCHAR(i));
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci		dwc2_hc_cleanup(hsotg, channel);
169862306a36Sopenharmony_ci		list_add_tail(&channel->hc_list_entry, &hsotg->free_hc_list);
169962306a36Sopenharmony_ci		/*
170062306a36Sopenharmony_ci		 * Added for Descriptor DMA to prevent channel double cleanup in
170162306a36Sopenharmony_ci		 * release_channel_ddma(), which is called from ep_disable when
170262306a36Sopenharmony_ci		 * device disconnects
170362306a36Sopenharmony_ci		 */
170462306a36Sopenharmony_ci		channel->qh = NULL;
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci	/* All channels have been freed, mark them available */
170762306a36Sopenharmony_ci	if (hsotg->params.uframe_sched) {
170862306a36Sopenharmony_ci		hsotg->available_host_channels =
170962306a36Sopenharmony_ci			hsotg->params.host_channels;
171062306a36Sopenharmony_ci	} else {
171162306a36Sopenharmony_ci		hsotg->non_periodic_channels = 0;
171262306a36Sopenharmony_ci		hsotg->periodic_channels = 0;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/**
171762306a36Sopenharmony_ci * dwc2_hcd_connect() - Handles connect of the HCD
171862306a36Sopenharmony_ci *
171962306a36Sopenharmony_ci * @hsotg: Pointer to struct dwc2_hsotg
172062306a36Sopenharmony_ci *
172162306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
172262306a36Sopenharmony_ci */
172362306a36Sopenharmony_civoid dwc2_hcd_connect(struct dwc2_hsotg *hsotg)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	if (hsotg->lx_state != DWC2_L0)
172662306a36Sopenharmony_ci		usb_hcd_resume_root_hub(hsotg->priv);
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	hsotg->flags.b.port_connect_status_change = 1;
172962306a36Sopenharmony_ci	hsotg->flags.b.port_connect_status = 1;
173062306a36Sopenharmony_ci}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci/**
173362306a36Sopenharmony_ci * dwc2_hcd_disconnect() - Handles disconnect of the HCD
173462306a36Sopenharmony_ci *
173562306a36Sopenharmony_ci * @hsotg: Pointer to struct dwc2_hsotg
173662306a36Sopenharmony_ci * @force: If true, we won't try to reconnect even if we see device connected.
173762306a36Sopenharmony_ci *
173862306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
173962306a36Sopenharmony_ci */
174062306a36Sopenharmony_civoid dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	u32 intr;
174362306a36Sopenharmony_ci	u32 hprt0;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	/* Set status flags for the hub driver */
174662306a36Sopenharmony_ci	hsotg->flags.b.port_connect_status_change = 1;
174762306a36Sopenharmony_ci	hsotg->flags.b.port_connect_status = 0;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	/*
175062306a36Sopenharmony_ci	 * Shutdown any transfers in process by clearing the Tx FIFO Empty
175162306a36Sopenharmony_ci	 * interrupt mask and status bits and disabling subsequent host
175262306a36Sopenharmony_ci	 * channel interrupts.
175362306a36Sopenharmony_ci	 */
175462306a36Sopenharmony_ci	intr = dwc2_readl(hsotg, GINTMSK);
175562306a36Sopenharmony_ci	intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
175662306a36Sopenharmony_ci	dwc2_writel(hsotg, intr, GINTMSK);
175762306a36Sopenharmony_ci	intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
175862306a36Sopenharmony_ci	dwc2_writel(hsotg, intr, GINTSTS);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	/*
176162306a36Sopenharmony_ci	 * Turn off the vbus power only if the core has transitioned to device
176262306a36Sopenharmony_ci	 * mode. If still in host mode, need to keep power on to detect a
176362306a36Sopenharmony_ci	 * reconnection.
176462306a36Sopenharmony_ci	 */
176562306a36Sopenharmony_ci	if (dwc2_is_device_mode(hsotg)) {
176662306a36Sopenharmony_ci		if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
176762306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
176862306a36Sopenharmony_ci			dwc2_writel(hsotg, 0, HPRT0);
176962306a36Sopenharmony_ci		}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		dwc2_disable_host_interrupts(hsotg);
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	/* Respond with an error status to all URBs in the schedule */
177562306a36Sopenharmony_ci	dwc2_kill_all_urbs(hsotg);
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (dwc2_is_host_mode(hsotg))
177862306a36Sopenharmony_ci		/* Clean up any host channels that were in use */
177962306a36Sopenharmony_ci		dwc2_hcd_cleanup_channels(hsotg);
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	dwc2_host_disconnect(hsotg);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/*
178462306a36Sopenharmony_ci	 * Add an extra check here to see if we're actually connected but
178562306a36Sopenharmony_ci	 * we don't have a detection interrupt pending.  This can happen if:
178662306a36Sopenharmony_ci	 *   1. hardware sees connect
178762306a36Sopenharmony_ci	 *   2. hardware sees disconnect
178862306a36Sopenharmony_ci	 *   3. hardware sees connect
178962306a36Sopenharmony_ci	 *   4. dwc2_port_intr() - clears connect interrupt
179062306a36Sopenharmony_ci	 *   5. dwc2_handle_common_intr() - calls here
179162306a36Sopenharmony_ci	 *
179262306a36Sopenharmony_ci	 * Without the extra check here we will end calling disconnect
179362306a36Sopenharmony_ci	 * and won't get any future interrupts to handle the connect.
179462306a36Sopenharmony_ci	 */
179562306a36Sopenharmony_ci	if (!force) {
179662306a36Sopenharmony_ci		hprt0 = dwc2_readl(hsotg, HPRT0);
179762306a36Sopenharmony_ci		if (!(hprt0 & HPRT0_CONNDET) && (hprt0 & HPRT0_CONNSTS))
179862306a36Sopenharmony_ci			dwc2_hcd_connect(hsotg);
179962306a36Sopenharmony_ci	}
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci/**
180362306a36Sopenharmony_ci * dwc2_hcd_rem_wakeup() - Handles Remote Wakeup
180462306a36Sopenharmony_ci *
180562306a36Sopenharmony_ci * @hsotg: Pointer to struct dwc2_hsotg
180662306a36Sopenharmony_ci */
180762306a36Sopenharmony_cistatic void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
180862306a36Sopenharmony_ci{
180962306a36Sopenharmony_ci	if (hsotg->bus_suspended) {
181062306a36Sopenharmony_ci		hsotg->flags.b.port_suspend_change = 1;
181162306a36Sopenharmony_ci		usb_hcd_resume_root_hub(hsotg->priv);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	if (hsotg->lx_state == DWC2_L1)
181562306a36Sopenharmony_ci		hsotg->flags.b.port_l1_change = 1;
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci/**
181962306a36Sopenharmony_ci * dwc2_hcd_stop() - Halts the DWC_otg host mode operations in a clean manner
182062306a36Sopenharmony_ci *
182162306a36Sopenharmony_ci * @hsotg: Pointer to struct dwc2_hsotg
182262306a36Sopenharmony_ci *
182362306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
182462306a36Sopenharmony_ci */
182562306a36Sopenharmony_civoid dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DWC OTG HCD STOP\n");
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	/*
183062306a36Sopenharmony_ci	 * The root hub should be disconnected before this function is called.
183162306a36Sopenharmony_ci	 * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
183262306a36Sopenharmony_ci	 * and the QH lists (via ..._hcd_endpoint_disable).
183362306a36Sopenharmony_ci	 */
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	/* Turn off all host-specific interrupts */
183662306a36Sopenharmony_ci	dwc2_disable_host_interrupts(hsotg);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/* Turn off the vbus power */
183962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "PortPower off\n");
184062306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, HPRT0);
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci/* Caller must hold driver lock */
184462306a36Sopenharmony_cistatic int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
184562306a36Sopenharmony_ci				struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
184662306a36Sopenharmony_ci				struct dwc2_qtd *qtd)
184762306a36Sopenharmony_ci{
184862306a36Sopenharmony_ci	u32 intr_mask;
184962306a36Sopenharmony_ci	int retval;
185062306a36Sopenharmony_ci	int dev_speed;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	if (!hsotg->flags.b.port_connect_status) {
185362306a36Sopenharmony_ci		/* No longer connected */
185462306a36Sopenharmony_ci		dev_err(hsotg->dev, "Not connected\n");
185562306a36Sopenharmony_ci		return -ENODEV;
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	/* Some configurations cannot support LS traffic on a FS root port */
186162306a36Sopenharmony_ci	if ((dev_speed == USB_SPEED_LOW) &&
186262306a36Sopenharmony_ci	    (hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
186362306a36Sopenharmony_ci	    (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
186462306a36Sopenharmony_ci		u32 hprt0 = dwc2_readl(hsotg, HPRT0);
186562306a36Sopenharmony_ci		u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci		if (prtspd == HPRT0_SPD_FULL_SPEED)
186862306a36Sopenharmony_ci			return -ENODEV;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (!qtd)
187262306a36Sopenharmony_ci		return -EINVAL;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	dwc2_hcd_qtd_init(qtd, urb);
187562306a36Sopenharmony_ci	retval = dwc2_hcd_qtd_add(hsotg, qtd, qh);
187662306a36Sopenharmony_ci	if (retval) {
187762306a36Sopenharmony_ci		dev_err(hsotg->dev,
187862306a36Sopenharmony_ci			"DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
187962306a36Sopenharmony_ci			retval);
188062306a36Sopenharmony_ci		return retval;
188162306a36Sopenharmony_ci	}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	intr_mask = dwc2_readl(hsotg, GINTMSK);
188462306a36Sopenharmony_ci	if (!(intr_mask & GINTSTS_SOF)) {
188562306a36Sopenharmony_ci		enum dwc2_transaction_type tr_type;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci		if (qtd->qh->ep_type == USB_ENDPOINT_XFER_BULK &&
188862306a36Sopenharmony_ci		    !(qtd->urb->flags & URB_GIVEBACK_ASAP))
188962306a36Sopenharmony_ci			/*
189062306a36Sopenharmony_ci			 * Do not schedule SG transactions until qtd has
189162306a36Sopenharmony_ci			 * URB_GIVEBACK_ASAP set
189262306a36Sopenharmony_ci			 */
189362306a36Sopenharmony_ci			return 0;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci		tr_type = dwc2_hcd_select_transactions(hsotg);
189662306a36Sopenharmony_ci		if (tr_type != DWC2_TRANSACTION_NONE)
189762306a36Sopenharmony_ci			dwc2_hcd_queue_transactions(hsotg, tr_type);
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	return 0;
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci/* Must be called with interrupt disabled and spinlock held */
190462306a36Sopenharmony_cistatic int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg,
190562306a36Sopenharmony_ci				struct dwc2_hcd_urb *urb)
190662306a36Sopenharmony_ci{
190762306a36Sopenharmony_ci	struct dwc2_qh *qh;
190862306a36Sopenharmony_ci	struct dwc2_qtd *urb_qtd;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	urb_qtd = urb->qtd;
191162306a36Sopenharmony_ci	if (!urb_qtd) {
191262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "## Urb QTD is NULL ##\n");
191362306a36Sopenharmony_ci		return -EINVAL;
191462306a36Sopenharmony_ci	}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	qh = urb_qtd->qh;
191762306a36Sopenharmony_ci	if (!qh) {
191862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "## Urb QTD QH is NULL ##\n");
191962306a36Sopenharmony_ci		return -EINVAL;
192062306a36Sopenharmony_ci	}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	urb->priv = NULL;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	if (urb_qtd->in_process && qh->channel) {
192562306a36Sopenharmony_ci		dwc2_dump_channel_info(hsotg, qh->channel);
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci		/* The QTD is in process (it has been assigned to a channel) */
192862306a36Sopenharmony_ci		if (hsotg->flags.b.port_connect_status)
192962306a36Sopenharmony_ci			/*
193062306a36Sopenharmony_ci			 * If still connected (i.e. in host mode), halt the
193162306a36Sopenharmony_ci			 * channel so it can be used for other transfers. If
193262306a36Sopenharmony_ci			 * no longer connected, the host registers can't be
193362306a36Sopenharmony_ci			 * written to halt the channel since the core is in
193462306a36Sopenharmony_ci			 * device mode.
193562306a36Sopenharmony_ci			 */
193662306a36Sopenharmony_ci			dwc2_hc_halt(hsotg, qh->channel,
193762306a36Sopenharmony_ci				     DWC2_HC_XFER_URB_DEQUEUE);
193862306a36Sopenharmony_ci	}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	/*
194162306a36Sopenharmony_ci	 * Free the QTD and clean up the associated QH. Leave the QH in the
194262306a36Sopenharmony_ci	 * schedule if it has any remaining QTDs.
194362306a36Sopenharmony_ci	 */
194462306a36Sopenharmony_ci	if (!hsotg->params.dma_desc_enable) {
194562306a36Sopenharmony_ci		u8 in_process = urb_qtd->in_process;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
194862306a36Sopenharmony_ci		if (in_process) {
194962306a36Sopenharmony_ci			dwc2_hcd_qh_deactivate(hsotg, qh, 0);
195062306a36Sopenharmony_ci			qh->channel = NULL;
195162306a36Sopenharmony_ci		} else if (list_empty(&qh->qtd_list)) {
195262306a36Sopenharmony_ci			dwc2_hcd_qh_unlink(hsotg, qh);
195362306a36Sopenharmony_ci		}
195462306a36Sopenharmony_ci	} else {
195562306a36Sopenharmony_ci		dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	return 0;
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci/* Must NOT be called with interrupt disabled or spinlock held */
196262306a36Sopenharmony_cistatic int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg,
196362306a36Sopenharmony_ci				     struct usb_host_endpoint *ep, int retry)
196462306a36Sopenharmony_ci{
196562306a36Sopenharmony_ci	struct dwc2_qtd *qtd, *qtd_tmp;
196662306a36Sopenharmony_ci	struct dwc2_qh *qh;
196762306a36Sopenharmony_ci	unsigned long flags;
196862306a36Sopenharmony_ci	int rc;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	qh = ep->hcpriv;
197362306a36Sopenharmony_ci	if (!qh) {
197462306a36Sopenharmony_ci		rc = -EINVAL;
197562306a36Sopenharmony_ci		goto err;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	while (!list_empty(&qh->qtd_list) && retry--) {
197962306a36Sopenharmony_ci		if (retry == 0) {
198062306a36Sopenharmony_ci			dev_err(hsotg->dev,
198162306a36Sopenharmony_ci				"## timeout in dwc2_hcd_endpoint_disable() ##\n");
198262306a36Sopenharmony_ci			rc = -EBUSY;
198362306a36Sopenharmony_ci			goto err;
198462306a36Sopenharmony_ci		}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
198762306a36Sopenharmony_ci		msleep(20);
198862306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
198962306a36Sopenharmony_ci		qh = ep->hcpriv;
199062306a36Sopenharmony_ci		if (!qh) {
199162306a36Sopenharmony_ci			rc = -EINVAL;
199262306a36Sopenharmony_ci			goto err;
199362306a36Sopenharmony_ci		}
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	dwc2_hcd_qh_unlink(hsotg, qh);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	/* Free each QTD in the QH's QTD list */
199962306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry)
200062306a36Sopenharmony_ci		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	ep->hcpriv = NULL;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (qh->channel && qh->channel->qh == qh)
200562306a36Sopenharmony_ci		qh->channel->qh = NULL;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	dwc2_hcd_qh_free(hsotg, qh);
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	return 0;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cierr:
201462306a36Sopenharmony_ci	ep->hcpriv = NULL;
201562306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	return rc;
201862306a36Sopenharmony_ci}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci/* Must be called with interrupt disabled and spinlock held */
202162306a36Sopenharmony_cistatic int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
202262306a36Sopenharmony_ci				   struct usb_host_endpoint *ep)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	struct dwc2_qh *qh = ep->hcpriv;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	if (!qh)
202762306a36Sopenharmony_ci		return -EINVAL;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	qh->data_toggle = DWC2_HC_PID_DATA0;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	return 0;
203262306a36Sopenharmony_ci}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci/**
203562306a36Sopenharmony_ci * dwc2_core_init() - Initializes the DWC_otg controller registers and
203662306a36Sopenharmony_ci * prepares the core for device mode or host mode operation
203762306a36Sopenharmony_ci *
203862306a36Sopenharmony_ci * @hsotg:         Programming view of the DWC_otg controller
203962306a36Sopenharmony_ci * @initial_setup: If true then this is the first init for this instance.
204062306a36Sopenharmony_ci */
204162306a36Sopenharmony_ciint dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	u32 usbcfg, otgctl;
204462306a36Sopenharmony_ci	int retval;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	usbcfg = dwc2_readl(hsotg, GUSBCFG);
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	/* Set ULPI External VBUS bit if needed */
205162306a36Sopenharmony_ci	usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
205262306a36Sopenharmony_ci	if (hsotg->params.phy_ulpi_ext_vbus)
205362306a36Sopenharmony_ci		usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	/* Set external TS Dline pulsing bit if needed */
205662306a36Sopenharmony_ci	usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
205762306a36Sopenharmony_ci	if (hsotg->params.ts_dline)
205862306a36Sopenharmony_ci		usbcfg |= GUSBCFG_TERMSELDLPULSE;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	dwc2_writel(hsotg, usbcfg, GUSBCFG);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	/*
206362306a36Sopenharmony_ci	 * Reset the Controller
206462306a36Sopenharmony_ci	 *
206562306a36Sopenharmony_ci	 * We only need to reset the controller if this is a re-init.
206662306a36Sopenharmony_ci	 * For the first init we know for sure that earlier code reset us (it
206762306a36Sopenharmony_ci	 * needed to in order to properly detect various parameters).
206862306a36Sopenharmony_ci	 */
206962306a36Sopenharmony_ci	if (!initial_setup) {
207062306a36Sopenharmony_ci		retval = dwc2_core_reset(hsotg, false);
207162306a36Sopenharmony_ci		if (retval) {
207262306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
207362306a36Sopenharmony_ci				__func__);
207462306a36Sopenharmony_ci			return retval;
207562306a36Sopenharmony_ci		}
207662306a36Sopenharmony_ci	}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	/*
207962306a36Sopenharmony_ci	 * This needs to happen in FS mode before any other programming occurs
208062306a36Sopenharmony_ci	 */
208162306a36Sopenharmony_ci	retval = dwc2_phy_init(hsotg, initial_setup);
208262306a36Sopenharmony_ci	if (retval)
208362306a36Sopenharmony_ci		return retval;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	/* Program the GAHBCFG Register */
208662306a36Sopenharmony_ci	retval = dwc2_gahbcfg_init(hsotg);
208762306a36Sopenharmony_ci	if (retval)
208862306a36Sopenharmony_ci		return retval;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	/* Program the GUSBCFG register */
209162306a36Sopenharmony_ci	dwc2_gusbcfg_init(hsotg);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	/* Program the GOTGCTL register */
209462306a36Sopenharmony_ci	otgctl = dwc2_readl(hsotg, GOTGCTL);
209562306a36Sopenharmony_ci	otgctl &= ~GOTGCTL_OTGVER;
209662306a36Sopenharmony_ci	dwc2_writel(hsotg, otgctl, GOTGCTL);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	/* Clear the SRP success bit for FS-I2c */
209962306a36Sopenharmony_ci	hsotg->srp_success = 0;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	/* Enable common interrupts */
210262306a36Sopenharmony_ci	dwc2_enable_common_interrupts(hsotg);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	/*
210562306a36Sopenharmony_ci	 * Do device or host initialization based on mode during PCD and
210662306a36Sopenharmony_ci	 * HCD initialization
210762306a36Sopenharmony_ci	 */
210862306a36Sopenharmony_ci	if (dwc2_is_host_mode(hsotg)) {
210962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Host Mode\n");
211062306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_A_HOST;
211162306a36Sopenharmony_ci	} else {
211262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Device Mode\n");
211362306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	return 0;
211762306a36Sopenharmony_ci}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci/**
212062306a36Sopenharmony_ci * dwc2_core_host_init() - Initializes the DWC_otg controller registers for
212162306a36Sopenharmony_ci * Host mode
212262306a36Sopenharmony_ci *
212362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
212462306a36Sopenharmony_ci *
212562306a36Sopenharmony_ci * This function flushes the Tx and Rx FIFOs and flushes any entries in the
212662306a36Sopenharmony_ci * request queues. Host channels are reset to ensure that they are ready for
212762306a36Sopenharmony_ci * performing transfers.
212862306a36Sopenharmony_ci */
212962306a36Sopenharmony_cistatic void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	u32 hcfg, hfir, otgctl, usbcfg;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/* Set HS/FS Timeout Calibration to 7 (max available value).
213662306a36Sopenharmony_ci	 * The number of PHY clocks that the application programs in
213762306a36Sopenharmony_ci	 * this field is added to the high/full speed interpacket timeout
213862306a36Sopenharmony_ci	 * duration in the core to account for any additional delays
213962306a36Sopenharmony_ci	 * introduced by the PHY. This can be required, because the delay
214062306a36Sopenharmony_ci	 * introduced by the PHY in generating the linestate condition
214162306a36Sopenharmony_ci	 * can vary from one PHY to another.
214262306a36Sopenharmony_ci	 */
214362306a36Sopenharmony_ci	usbcfg = dwc2_readl(hsotg, GUSBCFG);
214462306a36Sopenharmony_ci	usbcfg |= GUSBCFG_TOUTCAL(7);
214562306a36Sopenharmony_ci	dwc2_writel(hsotg, usbcfg, GUSBCFG);
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	/* Restart the Phy Clock */
214862306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, PCGCTL);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	/* Initialize Host Configuration Register */
215162306a36Sopenharmony_ci	dwc2_init_fs_ls_pclk_sel(hsotg);
215262306a36Sopenharmony_ci	if (hsotg->params.speed == DWC2_SPEED_PARAM_FULL ||
215362306a36Sopenharmony_ci	    hsotg->params.speed == DWC2_SPEED_PARAM_LOW) {
215462306a36Sopenharmony_ci		hcfg = dwc2_readl(hsotg, HCFG);
215562306a36Sopenharmony_ci		hcfg |= HCFG_FSLSSUPP;
215662306a36Sopenharmony_ci		dwc2_writel(hsotg, hcfg, HCFG);
215762306a36Sopenharmony_ci	}
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	/*
216062306a36Sopenharmony_ci	 * This bit allows dynamic reloading of the HFIR register during
216162306a36Sopenharmony_ci	 * runtime. This bit needs to be programmed during initial configuration
216262306a36Sopenharmony_ci	 * and its value must not be changed during runtime.
216362306a36Sopenharmony_ci	 */
216462306a36Sopenharmony_ci	if (hsotg->params.reload_ctl) {
216562306a36Sopenharmony_ci		hfir = dwc2_readl(hsotg, HFIR);
216662306a36Sopenharmony_ci		hfir |= HFIR_RLDCTRL;
216762306a36Sopenharmony_ci		dwc2_writel(hsotg, hfir, HFIR);
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	if (hsotg->params.dma_desc_enable) {
217162306a36Sopenharmony_ci		u32 op_mode = hsotg->hw_params.op_mode;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci		if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
217462306a36Sopenharmony_ci		    !hsotg->hw_params.dma_desc_enable ||
217562306a36Sopenharmony_ci		    op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
217662306a36Sopenharmony_ci		    op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
217762306a36Sopenharmony_ci		    op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
217862306a36Sopenharmony_ci			dev_err(hsotg->dev,
217962306a36Sopenharmony_ci				"Hardware does not support descriptor DMA mode -\n");
218062306a36Sopenharmony_ci			dev_err(hsotg->dev,
218162306a36Sopenharmony_ci				"falling back to buffer DMA mode.\n");
218262306a36Sopenharmony_ci			hsotg->params.dma_desc_enable = false;
218362306a36Sopenharmony_ci		} else {
218462306a36Sopenharmony_ci			hcfg = dwc2_readl(hsotg, HCFG);
218562306a36Sopenharmony_ci			hcfg |= HCFG_DESCDMA;
218662306a36Sopenharmony_ci			dwc2_writel(hsotg, hcfg, HCFG);
218762306a36Sopenharmony_ci		}
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	/* Configure data FIFO sizes */
219162306a36Sopenharmony_ci	dwc2_config_fifos(hsotg);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	/* TODO - check this */
219462306a36Sopenharmony_ci	/* Clear Host Set HNP Enable in the OTG Control Register */
219562306a36Sopenharmony_ci	otgctl = dwc2_readl(hsotg, GOTGCTL);
219662306a36Sopenharmony_ci	otgctl &= ~GOTGCTL_HSTSETHNPEN;
219762306a36Sopenharmony_ci	dwc2_writel(hsotg, otgctl, GOTGCTL);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	/* Make sure the FIFOs are flushed */
220062306a36Sopenharmony_ci	dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
220162306a36Sopenharmony_ci	dwc2_flush_rx_fifo(hsotg);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	/* Clear Host Set HNP Enable in the OTG Control Register */
220462306a36Sopenharmony_ci	otgctl = dwc2_readl(hsotg, GOTGCTL);
220562306a36Sopenharmony_ci	otgctl &= ~GOTGCTL_HSTSETHNPEN;
220662306a36Sopenharmony_ci	dwc2_writel(hsotg, otgctl, GOTGCTL);
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	if (!hsotg->params.dma_desc_enable) {
220962306a36Sopenharmony_ci		int num_channels, i;
221062306a36Sopenharmony_ci		u32 hcchar;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci		/* Flush out any leftover queued requests */
221362306a36Sopenharmony_ci		num_channels = hsotg->params.host_channels;
221462306a36Sopenharmony_ci		for (i = 0; i < num_channels; i++) {
221562306a36Sopenharmony_ci			hcchar = dwc2_readl(hsotg, HCCHAR(i));
221662306a36Sopenharmony_ci			if (hcchar & HCCHAR_CHENA) {
221762306a36Sopenharmony_ci				hcchar &= ~HCCHAR_CHENA;
221862306a36Sopenharmony_ci				hcchar |= HCCHAR_CHDIS;
221962306a36Sopenharmony_ci				hcchar &= ~HCCHAR_EPDIR;
222062306a36Sopenharmony_ci				dwc2_writel(hsotg, hcchar, HCCHAR(i));
222162306a36Sopenharmony_ci			}
222262306a36Sopenharmony_ci		}
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci		/* Halt all channels to put them into a known state */
222562306a36Sopenharmony_ci		for (i = 0; i < num_channels; i++) {
222662306a36Sopenharmony_ci			hcchar = dwc2_readl(hsotg, HCCHAR(i));
222762306a36Sopenharmony_ci			if (hcchar & HCCHAR_CHENA) {
222862306a36Sopenharmony_ci				hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
222962306a36Sopenharmony_ci				hcchar &= ~HCCHAR_EPDIR;
223062306a36Sopenharmony_ci				dwc2_writel(hsotg, hcchar, HCCHAR(i));
223162306a36Sopenharmony_ci				dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
223262306a36Sopenharmony_ci					__func__, i);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci				if (dwc2_hsotg_wait_bit_clear(hsotg, HCCHAR(i),
223562306a36Sopenharmony_ci							      HCCHAR_CHENA,
223662306a36Sopenharmony_ci							      1000)) {
223762306a36Sopenharmony_ci					dev_warn(hsotg->dev,
223862306a36Sopenharmony_ci						 "Unable to clear enable on channel %d\n",
223962306a36Sopenharmony_ci						 i);
224062306a36Sopenharmony_ci				}
224162306a36Sopenharmony_ci			}
224262306a36Sopenharmony_ci		}
224362306a36Sopenharmony_ci	}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	/* Enable ACG feature in host mode, if supported */
224662306a36Sopenharmony_ci	dwc2_enable_acg(hsotg);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	/* Turn on the vbus power */
224962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
225062306a36Sopenharmony_ci	if (hsotg->op_state == OTG_STATE_A_HOST) {
225162306a36Sopenharmony_ci		u32 hprt0 = dwc2_read_hprt0(hsotg);
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Init: Power Port (%d)\n",
225462306a36Sopenharmony_ci			!!(hprt0 & HPRT0_PWR));
225562306a36Sopenharmony_ci		if (!(hprt0 & HPRT0_PWR)) {
225662306a36Sopenharmony_ci			hprt0 |= HPRT0_PWR;
225762306a36Sopenharmony_ci			dwc2_writel(hsotg, hprt0, HPRT0);
225862306a36Sopenharmony_ci		}
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	dwc2_enable_host_interrupts(hsotg);
226262306a36Sopenharmony_ci}
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci/*
226562306a36Sopenharmony_ci * Initializes dynamic portions of the DWC_otg HCD state
226662306a36Sopenharmony_ci *
226762306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
226862306a36Sopenharmony_ci */
226962306a36Sopenharmony_cistatic void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	struct dwc2_host_chan *chan, *chan_tmp;
227262306a36Sopenharmony_ci	int num_channels;
227362306a36Sopenharmony_ci	int i;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	hsotg->flags.d32 = 0;
227662306a36Sopenharmony_ci	hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	if (hsotg->params.uframe_sched) {
227962306a36Sopenharmony_ci		hsotg->available_host_channels =
228062306a36Sopenharmony_ci			hsotg->params.host_channels;
228162306a36Sopenharmony_ci	} else {
228262306a36Sopenharmony_ci		hsotg->non_periodic_channels = 0;
228362306a36Sopenharmony_ci		hsotg->periodic_channels = 0;
228462306a36Sopenharmony_ci	}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	/*
228762306a36Sopenharmony_ci	 * Put all channels in the free channel list and clean up channel
228862306a36Sopenharmony_ci	 * states
228962306a36Sopenharmony_ci	 */
229062306a36Sopenharmony_ci	list_for_each_entry_safe(chan, chan_tmp, &hsotg->free_hc_list,
229162306a36Sopenharmony_ci				 hc_list_entry)
229262306a36Sopenharmony_ci		list_del_init(&chan->hc_list_entry);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	num_channels = hsotg->params.host_channels;
229562306a36Sopenharmony_ci	for (i = 0; i < num_channels; i++) {
229662306a36Sopenharmony_ci		chan = hsotg->hc_ptr_array[i];
229762306a36Sopenharmony_ci		list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
229862306a36Sopenharmony_ci		dwc2_hc_cleanup(hsotg, chan);
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	/* Initialize the DWC core for host mode operation */
230262306a36Sopenharmony_ci	dwc2_core_host_init(hsotg);
230362306a36Sopenharmony_ci}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_cistatic void dwc2_hc_init_split(struct dwc2_hsotg *hsotg,
230662306a36Sopenharmony_ci			       struct dwc2_host_chan *chan,
230762306a36Sopenharmony_ci			       struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
230862306a36Sopenharmony_ci{
230962306a36Sopenharmony_ci	int hub_addr, hub_port;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	chan->do_split = 1;
231262306a36Sopenharmony_ci	chan->xact_pos = qtd->isoc_split_pos;
231362306a36Sopenharmony_ci	chan->complete_split = qtd->complete_split;
231462306a36Sopenharmony_ci	dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
231562306a36Sopenharmony_ci	chan->hub_addr = (u8)hub_addr;
231662306a36Sopenharmony_ci	chan->hub_port = (u8)hub_port;
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
232062306a36Sopenharmony_ci			      struct dwc2_host_chan *chan,
232162306a36Sopenharmony_ci			      struct dwc2_qtd *qtd)
232262306a36Sopenharmony_ci{
232362306a36Sopenharmony_ci	struct dwc2_hcd_urb *urb = qtd->urb;
232462306a36Sopenharmony_ci	struct dwc2_hcd_iso_packet_desc *frame_desc;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
232762306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
232862306a36Sopenharmony_ci		chan->ep_type = USB_ENDPOINT_XFER_CONTROL;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci		switch (qtd->control_phase) {
233162306a36Sopenharmony_ci		case DWC2_CONTROL_SETUP:
233262306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "  Control setup transaction\n");
233362306a36Sopenharmony_ci			chan->do_ping = 0;
233462306a36Sopenharmony_ci			chan->ep_is_in = 0;
233562306a36Sopenharmony_ci			chan->data_pid_start = DWC2_HC_PID_SETUP;
233662306a36Sopenharmony_ci			if (hsotg->params.host_dma)
233762306a36Sopenharmony_ci				chan->xfer_dma = urb->setup_dma;
233862306a36Sopenharmony_ci			else
233962306a36Sopenharmony_ci				chan->xfer_buf = urb->setup_packet;
234062306a36Sopenharmony_ci			chan->xfer_len = 8;
234162306a36Sopenharmony_ci			break;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci		case DWC2_CONTROL_DATA:
234462306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "  Control data transaction\n");
234562306a36Sopenharmony_ci			chan->data_pid_start = qtd->data_toggle;
234662306a36Sopenharmony_ci			break;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci		case DWC2_CONTROL_STATUS:
234962306a36Sopenharmony_ci			/*
235062306a36Sopenharmony_ci			 * Direction is opposite of data direction or IN if no
235162306a36Sopenharmony_ci			 * data
235262306a36Sopenharmony_ci			 */
235362306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "  Control status transaction\n");
235462306a36Sopenharmony_ci			if (urb->length == 0)
235562306a36Sopenharmony_ci				chan->ep_is_in = 1;
235662306a36Sopenharmony_ci			else
235762306a36Sopenharmony_ci				chan->ep_is_in =
235862306a36Sopenharmony_ci					dwc2_hcd_is_pipe_out(&urb->pipe_info);
235962306a36Sopenharmony_ci			if (chan->ep_is_in)
236062306a36Sopenharmony_ci				chan->do_ping = 0;
236162306a36Sopenharmony_ci			chan->data_pid_start = DWC2_HC_PID_DATA1;
236262306a36Sopenharmony_ci			chan->xfer_len = 0;
236362306a36Sopenharmony_ci			if (hsotg->params.host_dma)
236462306a36Sopenharmony_ci				chan->xfer_dma = hsotg->status_buf_dma;
236562306a36Sopenharmony_ci			else
236662306a36Sopenharmony_ci				chan->xfer_buf = hsotg->status_buf;
236762306a36Sopenharmony_ci			break;
236862306a36Sopenharmony_ci		}
236962306a36Sopenharmony_ci		break;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
237262306a36Sopenharmony_ci		chan->ep_type = USB_ENDPOINT_XFER_BULK;
237362306a36Sopenharmony_ci		break;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
237662306a36Sopenharmony_ci		chan->ep_type = USB_ENDPOINT_XFER_INT;
237762306a36Sopenharmony_ci		break;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
238062306a36Sopenharmony_ci		chan->ep_type = USB_ENDPOINT_XFER_ISOC;
238162306a36Sopenharmony_ci		if (hsotg->params.dma_desc_enable)
238262306a36Sopenharmony_ci			break;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci		frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
238562306a36Sopenharmony_ci		frame_desc->status = 0;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci		if (hsotg->params.host_dma) {
238862306a36Sopenharmony_ci			chan->xfer_dma = urb->dma;
238962306a36Sopenharmony_ci			chan->xfer_dma += frame_desc->offset +
239062306a36Sopenharmony_ci					qtd->isoc_split_offset;
239162306a36Sopenharmony_ci		} else {
239262306a36Sopenharmony_ci			chan->xfer_buf = urb->buf;
239362306a36Sopenharmony_ci			chan->xfer_buf += frame_desc->offset +
239462306a36Sopenharmony_ci					qtd->isoc_split_offset;
239562306a36Sopenharmony_ci		}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci		chan->xfer_len = frame_desc->length - qtd->isoc_split_offset;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci		if (chan->xact_pos == DWC2_HCSPLT_XACTPOS_ALL) {
240062306a36Sopenharmony_ci			if (chan->xfer_len <= 188)
240162306a36Sopenharmony_ci				chan->xact_pos = DWC2_HCSPLT_XACTPOS_ALL;
240262306a36Sopenharmony_ci			else
240362306a36Sopenharmony_ci				chan->xact_pos = DWC2_HCSPLT_XACTPOS_BEGIN;
240462306a36Sopenharmony_ci		}
240562306a36Sopenharmony_ci		break;
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_cistatic int dwc2_alloc_split_dma_aligned_buf(struct dwc2_hsotg *hsotg,
241062306a36Sopenharmony_ci					    struct dwc2_qh *qh,
241162306a36Sopenharmony_ci					    struct dwc2_host_chan *chan)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	if (!hsotg->unaligned_cache ||
241462306a36Sopenharmony_ci	    chan->max_packet > DWC2_KMEM_UNALIGNED_BUF_SIZE)
241562306a36Sopenharmony_ci		return -ENOMEM;
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	if (!qh->dw_align_buf) {
241862306a36Sopenharmony_ci		qh->dw_align_buf = kmem_cache_alloc(hsotg->unaligned_cache,
241962306a36Sopenharmony_ci						    GFP_ATOMIC | GFP_DMA);
242062306a36Sopenharmony_ci		if (!qh->dw_align_buf)
242162306a36Sopenharmony_ci			return -ENOMEM;
242262306a36Sopenharmony_ci	}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	qh->dw_align_buf_dma = dma_map_single(hsotg->dev, qh->dw_align_buf,
242562306a36Sopenharmony_ci					      DWC2_KMEM_UNALIGNED_BUF_SIZE,
242662306a36Sopenharmony_ci					      DMA_FROM_DEVICE);
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) {
242962306a36Sopenharmony_ci		dev_err(hsotg->dev, "can't map align_buf\n");
243062306a36Sopenharmony_ci		chan->align_buf = 0;
243162306a36Sopenharmony_ci		return -EINVAL;
243262306a36Sopenharmony_ci	}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	chan->align_buf = qh->dw_align_buf_dma;
243562306a36Sopenharmony_ci	return 0;
243662306a36Sopenharmony_ci}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci#define DWC2_USB_DMA_ALIGN 4
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_cistatic void dwc2_free_dma_aligned_buffer(struct urb *urb)
244162306a36Sopenharmony_ci{
244262306a36Sopenharmony_ci	void *stored_xfer_buffer;
244362306a36Sopenharmony_ci	size_t length;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
244662306a36Sopenharmony_ci		return;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	/* Restore urb->transfer_buffer from the end of the allocated area */
244962306a36Sopenharmony_ci	memcpy(&stored_xfer_buffer,
245062306a36Sopenharmony_ci	       PTR_ALIGN(urb->transfer_buffer + urb->transfer_buffer_length,
245162306a36Sopenharmony_ci			 dma_get_cache_alignment()),
245262306a36Sopenharmony_ci	       sizeof(urb->transfer_buffer));
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	if (usb_urb_dir_in(urb)) {
245562306a36Sopenharmony_ci		if (usb_pipeisoc(urb->pipe))
245662306a36Sopenharmony_ci			length = urb->transfer_buffer_length;
245762306a36Sopenharmony_ci		else
245862306a36Sopenharmony_ci			length = urb->actual_length;
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci		memcpy(stored_xfer_buffer, urb->transfer_buffer, length);
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci	kfree(urb->transfer_buffer);
246362306a36Sopenharmony_ci	urb->transfer_buffer = stored_xfer_buffer;
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
246662306a36Sopenharmony_ci}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_cistatic int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
246962306a36Sopenharmony_ci{
247062306a36Sopenharmony_ci	void *kmalloc_ptr;
247162306a36Sopenharmony_ci	size_t kmalloc_size;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	if (urb->num_sgs || urb->sg ||
247462306a36Sopenharmony_ci	    urb->transfer_buffer_length == 0 ||
247562306a36Sopenharmony_ci	    !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1)))
247662306a36Sopenharmony_ci		return 0;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	/*
247962306a36Sopenharmony_ci	 * Allocate a buffer with enough padding for original transfer_buffer
248062306a36Sopenharmony_ci	 * pointer. This allocation is guaranteed to be aligned properly for
248162306a36Sopenharmony_ci	 * DMA
248262306a36Sopenharmony_ci	 */
248362306a36Sopenharmony_ci	kmalloc_size = urb->transfer_buffer_length +
248462306a36Sopenharmony_ci		(dma_get_cache_alignment() - 1) +
248562306a36Sopenharmony_ci		sizeof(urb->transfer_buffer);
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
248862306a36Sopenharmony_ci	if (!kmalloc_ptr)
248962306a36Sopenharmony_ci		return -ENOMEM;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	/*
249262306a36Sopenharmony_ci	 * Position value of original urb->transfer_buffer pointer to the end
249362306a36Sopenharmony_ci	 * of allocation for later referencing
249462306a36Sopenharmony_ci	 */
249562306a36Sopenharmony_ci	memcpy(PTR_ALIGN(kmalloc_ptr + urb->transfer_buffer_length,
249662306a36Sopenharmony_ci			 dma_get_cache_alignment()),
249762306a36Sopenharmony_ci	       &urb->transfer_buffer, sizeof(urb->transfer_buffer));
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	if (usb_urb_dir_out(urb))
250062306a36Sopenharmony_ci		memcpy(kmalloc_ptr, urb->transfer_buffer,
250162306a36Sopenharmony_ci		       urb->transfer_buffer_length);
250262306a36Sopenharmony_ci	urb->transfer_buffer = kmalloc_ptr;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	return 0;
250762306a36Sopenharmony_ci}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_cistatic int dwc2_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
251062306a36Sopenharmony_ci				gfp_t mem_flags)
251162306a36Sopenharmony_ci{
251262306a36Sopenharmony_ci	int ret;
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	/* We assume setup_dma is always aligned; warn if not */
251562306a36Sopenharmony_ci	WARN_ON_ONCE(urb->setup_dma &&
251662306a36Sopenharmony_ci		     (urb->setup_dma & (DWC2_USB_DMA_ALIGN - 1)));
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	ret = dwc2_alloc_dma_aligned_buffer(urb, mem_flags);
251962306a36Sopenharmony_ci	if (ret)
252062306a36Sopenharmony_ci		return ret;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
252362306a36Sopenharmony_ci	if (ret)
252462306a36Sopenharmony_ci		dwc2_free_dma_aligned_buffer(urb);
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	return ret;
252762306a36Sopenharmony_ci}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_cistatic void dwc2_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
253062306a36Sopenharmony_ci{
253162306a36Sopenharmony_ci	usb_hcd_unmap_urb_for_dma(hcd, urb);
253262306a36Sopenharmony_ci	dwc2_free_dma_aligned_buffer(urb);
253362306a36Sopenharmony_ci}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci/**
253662306a36Sopenharmony_ci * dwc2_assign_and_init_hc() - Assigns transactions from a QTD to a free host
253762306a36Sopenharmony_ci * channel and initializes the host channel to perform the transactions. The
253862306a36Sopenharmony_ci * host channel is removed from the free list.
253962306a36Sopenharmony_ci *
254062306a36Sopenharmony_ci * @hsotg: The HCD state structure
254162306a36Sopenharmony_ci * @qh:    Transactions from the first QTD for this QH are selected and assigned
254262306a36Sopenharmony_ci *         to a free host channel
254362306a36Sopenharmony_ci */
254462306a36Sopenharmony_cistatic int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
254562306a36Sopenharmony_ci{
254662306a36Sopenharmony_ci	struct dwc2_host_chan *chan;
254762306a36Sopenharmony_ci	struct dwc2_hcd_urb *urb;
254862306a36Sopenharmony_ci	struct dwc2_qtd *qtd;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	if (dbg_qh(qh))
255162306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s(%p,%p)\n", __func__, hsotg, qh);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	if (list_empty(&qh->qtd_list)) {
255462306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "No QTDs in QH list\n");
255562306a36Sopenharmony_ci		return -ENOMEM;
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	if (list_empty(&hsotg->free_hc_list)) {
255962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "No free channel to assign\n");
256062306a36Sopenharmony_ci		return -ENOMEM;
256162306a36Sopenharmony_ci	}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan,
256462306a36Sopenharmony_ci				hc_list_entry);
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	/* Remove host channel from free list */
256762306a36Sopenharmony_ci	list_del_init(&chan->hc_list_entry);
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
257062306a36Sopenharmony_ci	urb = qtd->urb;
257162306a36Sopenharmony_ci	qh->channel = chan;
257262306a36Sopenharmony_ci	qtd->in_process = 1;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	/*
257562306a36Sopenharmony_ci	 * Use usb_pipedevice to determine device address. This address is
257662306a36Sopenharmony_ci	 * 0 before the SET_ADDRESS command and the correct address afterward.
257762306a36Sopenharmony_ci	 */
257862306a36Sopenharmony_ci	chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info);
257962306a36Sopenharmony_ci	chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info);
258062306a36Sopenharmony_ci	chan->speed = qh->dev_speed;
258162306a36Sopenharmony_ci	chan->max_packet = qh->maxp;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	chan->xfer_started = 0;
258462306a36Sopenharmony_ci	chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
258562306a36Sopenharmony_ci	chan->error_state = (qtd->error_count > 0);
258662306a36Sopenharmony_ci	chan->halt_on_queue = 0;
258762306a36Sopenharmony_ci	chan->halt_pending = 0;
258862306a36Sopenharmony_ci	chan->requests = 0;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	/*
259162306a36Sopenharmony_ci	 * The following values may be modified in the transfer type section
259262306a36Sopenharmony_ci	 * below. The xfer_len value may be reduced when the transfer is
259362306a36Sopenharmony_ci	 * started to accommodate the max widths of the XferSize and PktCnt
259462306a36Sopenharmony_ci	 * fields in the HCTSIZn register.
259562306a36Sopenharmony_ci	 */
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	chan->ep_is_in = (dwc2_hcd_is_pipe_in(&urb->pipe_info) != 0);
259862306a36Sopenharmony_ci	if (chan->ep_is_in)
259962306a36Sopenharmony_ci		chan->do_ping = 0;
260062306a36Sopenharmony_ci	else
260162306a36Sopenharmony_ci		chan->do_ping = qh->ping_state;
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	chan->data_pid_start = qh->data_toggle;
260462306a36Sopenharmony_ci	chan->multi_count = 1;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	if (urb->actual_length > urb->length &&
260762306a36Sopenharmony_ci	    !dwc2_hcd_is_pipe_in(&urb->pipe_info))
260862306a36Sopenharmony_ci		urb->actual_length = urb->length;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	if (hsotg->params.host_dma)
261162306a36Sopenharmony_ci		chan->xfer_dma = urb->dma + urb->actual_length;
261262306a36Sopenharmony_ci	else
261362306a36Sopenharmony_ci		chan->xfer_buf = (u8 *)urb->buf + urb->actual_length;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	chan->xfer_len = urb->length - urb->actual_length;
261662306a36Sopenharmony_ci	chan->xfer_count = 0;
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	/* Set the split attributes if required */
261962306a36Sopenharmony_ci	if (qh->do_split)
262062306a36Sopenharmony_ci		dwc2_hc_init_split(hsotg, chan, qtd, urb);
262162306a36Sopenharmony_ci	else
262262306a36Sopenharmony_ci		chan->do_split = 0;
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	/* Set the transfer attributes */
262562306a36Sopenharmony_ci	dwc2_hc_init_xfer(hsotg, chan, qtd);
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	/* For non-dword aligned buffers */
262862306a36Sopenharmony_ci	if (hsotg->params.host_dma && qh->do_split &&
262962306a36Sopenharmony_ci	    chan->ep_is_in && (chan->xfer_dma & 0x3)) {
263062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "Non-aligned buffer\n");
263162306a36Sopenharmony_ci		if (dwc2_alloc_split_dma_aligned_buf(hsotg, qh, chan)) {
263262306a36Sopenharmony_ci			dev_err(hsotg->dev,
263362306a36Sopenharmony_ci				"Failed to allocate memory to handle non-aligned buffer\n");
263462306a36Sopenharmony_ci			/* Add channel back to free list */
263562306a36Sopenharmony_ci			chan->align_buf = 0;
263662306a36Sopenharmony_ci			chan->multi_count = 0;
263762306a36Sopenharmony_ci			list_add_tail(&chan->hc_list_entry,
263862306a36Sopenharmony_ci				      &hsotg->free_hc_list);
263962306a36Sopenharmony_ci			qtd->in_process = 0;
264062306a36Sopenharmony_ci			qh->channel = NULL;
264162306a36Sopenharmony_ci			return -ENOMEM;
264262306a36Sopenharmony_ci		}
264362306a36Sopenharmony_ci	} else {
264462306a36Sopenharmony_ci		/*
264562306a36Sopenharmony_ci		 * We assume that DMA is always aligned in non-split
264662306a36Sopenharmony_ci		 * case or split out case. Warn if not.
264762306a36Sopenharmony_ci		 */
264862306a36Sopenharmony_ci		WARN_ON_ONCE(hsotg->params.host_dma &&
264962306a36Sopenharmony_ci			     (chan->xfer_dma & 0x3));
265062306a36Sopenharmony_ci		chan->align_buf = 0;
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
265462306a36Sopenharmony_ci	    chan->ep_type == USB_ENDPOINT_XFER_ISOC)
265562306a36Sopenharmony_ci		/*
265662306a36Sopenharmony_ci		 * This value may be modified when the transfer is started
265762306a36Sopenharmony_ci		 * to reflect the actual transfer length
265862306a36Sopenharmony_ci		 */
265962306a36Sopenharmony_ci		chan->multi_count = qh->maxp_mult;
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	if (hsotg->params.dma_desc_enable) {
266262306a36Sopenharmony_ci		chan->desc_list_addr = qh->desc_list_dma;
266362306a36Sopenharmony_ci		chan->desc_list_sz = qh->desc_list_sz;
266462306a36Sopenharmony_ci	}
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	dwc2_hc_init(hsotg, chan);
266762306a36Sopenharmony_ci	chan->qh = qh;
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	return 0;
267062306a36Sopenharmony_ci}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci/**
267362306a36Sopenharmony_ci * dwc2_hcd_select_transactions() - Selects transactions from the HCD transfer
267462306a36Sopenharmony_ci * schedule and assigns them to available host channels. Called from the HCD
267562306a36Sopenharmony_ci * interrupt handler functions.
267662306a36Sopenharmony_ci *
267762306a36Sopenharmony_ci * @hsotg: The HCD state structure
267862306a36Sopenharmony_ci *
267962306a36Sopenharmony_ci * Return: The types of new transactions that were assigned to host channels
268062306a36Sopenharmony_ci */
268162306a36Sopenharmony_cienum dwc2_transaction_type dwc2_hcd_select_transactions(
268262306a36Sopenharmony_ci		struct dwc2_hsotg *hsotg)
268362306a36Sopenharmony_ci{
268462306a36Sopenharmony_ci	enum dwc2_transaction_type ret_val = DWC2_TRANSACTION_NONE;
268562306a36Sopenharmony_ci	struct list_head *qh_ptr;
268662306a36Sopenharmony_ci	struct dwc2_qh *qh;
268762306a36Sopenharmony_ci	int num_channels;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci#ifdef DWC2_DEBUG_SOF
269062306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Select Transactions\n");
269162306a36Sopenharmony_ci#endif
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	/* Process entries in the periodic ready list */
269462306a36Sopenharmony_ci	qh_ptr = hsotg->periodic_sched_ready.next;
269562306a36Sopenharmony_ci	while (qh_ptr != &hsotg->periodic_sched_ready) {
269662306a36Sopenharmony_ci		if (list_empty(&hsotg->free_hc_list))
269762306a36Sopenharmony_ci			break;
269862306a36Sopenharmony_ci		if (hsotg->params.uframe_sched) {
269962306a36Sopenharmony_ci			if (hsotg->available_host_channels <= 1)
270062306a36Sopenharmony_ci				break;
270162306a36Sopenharmony_ci			hsotg->available_host_channels--;
270262306a36Sopenharmony_ci		}
270362306a36Sopenharmony_ci		qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
270462306a36Sopenharmony_ci		if (dwc2_assign_and_init_hc(hsotg, qh))
270562306a36Sopenharmony_ci			break;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci		/*
270862306a36Sopenharmony_ci		 * Move the QH from the periodic ready schedule to the
270962306a36Sopenharmony_ci		 * periodic assigned schedule
271062306a36Sopenharmony_ci		 */
271162306a36Sopenharmony_ci		qh_ptr = qh_ptr->next;
271262306a36Sopenharmony_ci		list_move_tail(&qh->qh_list_entry,
271362306a36Sopenharmony_ci			       &hsotg->periodic_sched_assigned);
271462306a36Sopenharmony_ci		ret_val = DWC2_TRANSACTION_PERIODIC;
271562306a36Sopenharmony_ci	}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	/*
271862306a36Sopenharmony_ci	 * Process entries in the inactive portion of the non-periodic
271962306a36Sopenharmony_ci	 * schedule. Some free host channels may not be used if they are
272062306a36Sopenharmony_ci	 * reserved for periodic transfers.
272162306a36Sopenharmony_ci	 */
272262306a36Sopenharmony_ci	num_channels = hsotg->params.host_channels;
272362306a36Sopenharmony_ci	qh_ptr = hsotg->non_periodic_sched_inactive.next;
272462306a36Sopenharmony_ci	while (qh_ptr != &hsotg->non_periodic_sched_inactive) {
272562306a36Sopenharmony_ci		if (!hsotg->params.uframe_sched &&
272662306a36Sopenharmony_ci		    hsotg->non_periodic_channels >= num_channels -
272762306a36Sopenharmony_ci						hsotg->periodic_channels)
272862306a36Sopenharmony_ci			break;
272962306a36Sopenharmony_ci		if (list_empty(&hsotg->free_hc_list))
273062306a36Sopenharmony_ci			break;
273162306a36Sopenharmony_ci		qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
273262306a36Sopenharmony_ci		if (hsotg->params.uframe_sched) {
273362306a36Sopenharmony_ci			if (hsotg->available_host_channels < 1)
273462306a36Sopenharmony_ci				break;
273562306a36Sopenharmony_ci			hsotg->available_host_channels--;
273662306a36Sopenharmony_ci		}
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci		if (dwc2_assign_and_init_hc(hsotg, qh))
273962306a36Sopenharmony_ci			break;
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci		/*
274262306a36Sopenharmony_ci		 * Move the QH from the non-periodic inactive schedule to the
274362306a36Sopenharmony_ci		 * non-periodic active schedule
274462306a36Sopenharmony_ci		 */
274562306a36Sopenharmony_ci		qh_ptr = qh_ptr->next;
274662306a36Sopenharmony_ci		list_move_tail(&qh->qh_list_entry,
274762306a36Sopenharmony_ci			       &hsotg->non_periodic_sched_active);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci		if (ret_val == DWC2_TRANSACTION_NONE)
275062306a36Sopenharmony_ci			ret_val = DWC2_TRANSACTION_NON_PERIODIC;
275162306a36Sopenharmony_ci		else
275262306a36Sopenharmony_ci			ret_val = DWC2_TRANSACTION_ALL;
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci		if (!hsotg->params.uframe_sched)
275562306a36Sopenharmony_ci			hsotg->non_periodic_channels++;
275662306a36Sopenharmony_ci	}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	return ret_val;
275962306a36Sopenharmony_ci}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci/**
276262306a36Sopenharmony_ci * dwc2_queue_transaction() - Attempts to queue a single transaction request for
276362306a36Sopenharmony_ci * a host channel associated with either a periodic or non-periodic transfer
276462306a36Sopenharmony_ci *
276562306a36Sopenharmony_ci * @hsotg: The HCD state structure
276662306a36Sopenharmony_ci * @chan:  Host channel descriptor associated with either a periodic or
276762306a36Sopenharmony_ci *         non-periodic transfer
276862306a36Sopenharmony_ci * @fifo_dwords_avail: Number of DWORDs available in the periodic Tx FIFO
276962306a36Sopenharmony_ci *                     for periodic transfers or the non-periodic Tx FIFO
277062306a36Sopenharmony_ci *                     for non-periodic transfers
277162306a36Sopenharmony_ci *
277262306a36Sopenharmony_ci * Return: 1 if a request is queued and more requests may be needed to
277362306a36Sopenharmony_ci * complete the transfer, 0 if no more requests are required for this
277462306a36Sopenharmony_ci * transfer, -1 if there is insufficient space in the Tx FIFO
277562306a36Sopenharmony_ci *
277662306a36Sopenharmony_ci * This function assumes that there is space available in the appropriate
277762306a36Sopenharmony_ci * request queue. For an OUT transfer or SETUP transaction in Slave mode,
277862306a36Sopenharmony_ci * it checks whether space is available in the appropriate Tx FIFO.
277962306a36Sopenharmony_ci *
278062306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
278162306a36Sopenharmony_ci */
278262306a36Sopenharmony_cistatic int dwc2_queue_transaction(struct dwc2_hsotg *hsotg,
278362306a36Sopenharmony_ci				  struct dwc2_host_chan *chan,
278462306a36Sopenharmony_ci				  u16 fifo_dwords_avail)
278562306a36Sopenharmony_ci{
278662306a36Sopenharmony_ci	int retval = 0;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	if (chan->do_split)
278962306a36Sopenharmony_ci		/* Put ourselves on the list to keep order straight */
279062306a36Sopenharmony_ci		list_move_tail(&chan->split_order_list_entry,
279162306a36Sopenharmony_ci			       &hsotg->split_order);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	if (hsotg->params.host_dma && chan->qh) {
279462306a36Sopenharmony_ci		if (hsotg->params.dma_desc_enable) {
279562306a36Sopenharmony_ci			if (!chan->xfer_started ||
279662306a36Sopenharmony_ci			    chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
279762306a36Sopenharmony_ci				dwc2_hcd_start_xfer_ddma(hsotg, chan->qh);
279862306a36Sopenharmony_ci				chan->qh->ping_state = 0;
279962306a36Sopenharmony_ci			}
280062306a36Sopenharmony_ci		} else if (!chan->xfer_started) {
280162306a36Sopenharmony_ci			dwc2_hc_start_transfer(hsotg, chan);
280262306a36Sopenharmony_ci			chan->qh->ping_state = 0;
280362306a36Sopenharmony_ci		}
280462306a36Sopenharmony_ci	} else if (chan->halt_pending) {
280562306a36Sopenharmony_ci		/* Don't queue a request if the channel has been halted */
280662306a36Sopenharmony_ci	} else if (chan->halt_on_queue) {
280762306a36Sopenharmony_ci		dwc2_hc_halt(hsotg, chan, chan->halt_status);
280862306a36Sopenharmony_ci	} else if (chan->do_ping) {
280962306a36Sopenharmony_ci		if (!chan->xfer_started)
281062306a36Sopenharmony_ci			dwc2_hc_start_transfer(hsotg, chan);
281162306a36Sopenharmony_ci	} else if (!chan->ep_is_in ||
281262306a36Sopenharmony_ci		   chan->data_pid_start == DWC2_HC_PID_SETUP) {
281362306a36Sopenharmony_ci		if ((fifo_dwords_avail * 4) >= chan->max_packet) {
281462306a36Sopenharmony_ci			if (!chan->xfer_started) {
281562306a36Sopenharmony_ci				dwc2_hc_start_transfer(hsotg, chan);
281662306a36Sopenharmony_ci				retval = 1;
281762306a36Sopenharmony_ci			} else {
281862306a36Sopenharmony_ci				retval = dwc2_hc_continue_transfer(hsotg, chan);
281962306a36Sopenharmony_ci			}
282062306a36Sopenharmony_ci		} else {
282162306a36Sopenharmony_ci			retval = -1;
282262306a36Sopenharmony_ci		}
282362306a36Sopenharmony_ci	} else {
282462306a36Sopenharmony_ci		if (!chan->xfer_started) {
282562306a36Sopenharmony_ci			dwc2_hc_start_transfer(hsotg, chan);
282662306a36Sopenharmony_ci			retval = 1;
282762306a36Sopenharmony_ci		} else {
282862306a36Sopenharmony_ci			retval = dwc2_hc_continue_transfer(hsotg, chan);
282962306a36Sopenharmony_ci		}
283062306a36Sopenharmony_ci	}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	return retval;
283362306a36Sopenharmony_ci}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci/*
283662306a36Sopenharmony_ci * Processes periodic channels for the next frame and queues transactions for
283762306a36Sopenharmony_ci * these channels to the DWC_otg controller. After queueing transactions, the
283862306a36Sopenharmony_ci * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
283962306a36Sopenharmony_ci * to queue as Periodic Tx FIFO or request queue space becomes available.
284062306a36Sopenharmony_ci * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
284162306a36Sopenharmony_ci *
284262306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
284362306a36Sopenharmony_ci */
284462306a36Sopenharmony_cistatic void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
284562306a36Sopenharmony_ci{
284662306a36Sopenharmony_ci	struct list_head *qh_ptr;
284762306a36Sopenharmony_ci	struct dwc2_qh *qh;
284862306a36Sopenharmony_ci	u32 tx_status;
284962306a36Sopenharmony_ci	u32 fspcavail;
285062306a36Sopenharmony_ci	u32 gintmsk;
285162306a36Sopenharmony_ci	int status;
285262306a36Sopenharmony_ci	bool no_queue_space = false;
285362306a36Sopenharmony_ci	bool no_fifo_space = false;
285462306a36Sopenharmony_ci	u32 qspcavail;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/* If empty list then just adjust interrupt enables */
285762306a36Sopenharmony_ci	if (list_empty(&hsotg->periodic_sched_assigned))
285862306a36Sopenharmony_ci		goto exit;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	if (dbg_perio())
286162306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	tx_status = dwc2_readl(hsotg, HPTXSTS);
286462306a36Sopenharmony_ci	qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
286562306a36Sopenharmony_ci		    TXSTS_QSPCAVAIL_SHIFT;
286662306a36Sopenharmony_ci	fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
286762306a36Sopenharmony_ci		    TXSTS_FSPCAVAIL_SHIFT;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	if (dbg_perio()) {
287062306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "  P Tx Req Queue Space Avail (before queue): %d\n",
287162306a36Sopenharmony_ci			 qspcavail);
287262306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "  P Tx FIFO Space Avail (before queue): %d\n",
287362306a36Sopenharmony_ci			 fspcavail);
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	qh_ptr = hsotg->periodic_sched_assigned.next;
287762306a36Sopenharmony_ci	while (qh_ptr != &hsotg->periodic_sched_assigned) {
287862306a36Sopenharmony_ci		tx_status = dwc2_readl(hsotg, HPTXSTS);
287962306a36Sopenharmony_ci		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
288062306a36Sopenharmony_ci			    TXSTS_QSPCAVAIL_SHIFT;
288162306a36Sopenharmony_ci		if (qspcavail == 0) {
288262306a36Sopenharmony_ci			no_queue_space = true;
288362306a36Sopenharmony_ci			break;
288462306a36Sopenharmony_ci		}
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci		qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
288762306a36Sopenharmony_ci		if (!qh->channel) {
288862306a36Sopenharmony_ci			qh_ptr = qh_ptr->next;
288962306a36Sopenharmony_ci			continue;
289062306a36Sopenharmony_ci		}
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci		/* Make sure EP's TT buffer is clean before queueing qtds */
289362306a36Sopenharmony_ci		if (qh->tt_buffer_dirty) {
289462306a36Sopenharmony_ci			qh_ptr = qh_ptr->next;
289562306a36Sopenharmony_ci			continue;
289662306a36Sopenharmony_ci		}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci		/*
289962306a36Sopenharmony_ci		 * Set a flag if we're queuing high-bandwidth in slave mode.
290062306a36Sopenharmony_ci		 * The flag prevents any halts to get into the request queue in
290162306a36Sopenharmony_ci		 * the middle of multiple high-bandwidth packets getting queued.
290262306a36Sopenharmony_ci		 */
290362306a36Sopenharmony_ci		if (!hsotg->params.host_dma &&
290462306a36Sopenharmony_ci		    qh->channel->multi_count > 1)
290562306a36Sopenharmony_ci			hsotg->queuing_high_bandwidth = 1;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
290862306a36Sopenharmony_ci			    TXSTS_FSPCAVAIL_SHIFT;
290962306a36Sopenharmony_ci		status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
291062306a36Sopenharmony_ci		if (status < 0) {
291162306a36Sopenharmony_ci			no_fifo_space = true;
291262306a36Sopenharmony_ci			break;
291362306a36Sopenharmony_ci		}
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci		/*
291662306a36Sopenharmony_ci		 * In Slave mode, stay on the current transfer until there is
291762306a36Sopenharmony_ci		 * nothing more to do or the high-bandwidth request count is
291862306a36Sopenharmony_ci		 * reached. In DMA mode, only need to queue one request. The
291962306a36Sopenharmony_ci		 * controller automatically handles multiple packets for
292062306a36Sopenharmony_ci		 * high-bandwidth transfers.
292162306a36Sopenharmony_ci		 */
292262306a36Sopenharmony_ci		if (hsotg->params.host_dma || status == 0 ||
292362306a36Sopenharmony_ci		    qh->channel->requests == qh->channel->multi_count) {
292462306a36Sopenharmony_ci			qh_ptr = qh_ptr->next;
292562306a36Sopenharmony_ci			/*
292662306a36Sopenharmony_ci			 * Move the QH from the periodic assigned schedule to
292762306a36Sopenharmony_ci			 * the periodic queued schedule
292862306a36Sopenharmony_ci			 */
292962306a36Sopenharmony_ci			list_move_tail(&qh->qh_list_entry,
293062306a36Sopenharmony_ci				       &hsotg->periodic_sched_queued);
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ci			/* done queuing high bandwidth */
293362306a36Sopenharmony_ci			hsotg->queuing_high_bandwidth = 0;
293462306a36Sopenharmony_ci		}
293562306a36Sopenharmony_ci	}
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ciexit:
293862306a36Sopenharmony_ci	if (no_queue_space || no_fifo_space ||
293962306a36Sopenharmony_ci	    (!hsotg->params.host_dma &&
294062306a36Sopenharmony_ci	     !list_empty(&hsotg->periodic_sched_assigned))) {
294162306a36Sopenharmony_ci		/*
294262306a36Sopenharmony_ci		 * May need to queue more transactions as the request
294362306a36Sopenharmony_ci		 * queue or Tx FIFO empties. Enable the periodic Tx
294462306a36Sopenharmony_ci		 * FIFO empty interrupt. (Always use the half-empty
294562306a36Sopenharmony_ci		 * level to ensure that new requests are loaded as
294662306a36Sopenharmony_ci		 * soon as possible.)
294762306a36Sopenharmony_ci		 */
294862306a36Sopenharmony_ci		gintmsk = dwc2_readl(hsotg, GINTMSK);
294962306a36Sopenharmony_ci		if (!(gintmsk & GINTSTS_PTXFEMP)) {
295062306a36Sopenharmony_ci			gintmsk |= GINTSTS_PTXFEMP;
295162306a36Sopenharmony_ci			dwc2_writel(hsotg, gintmsk, GINTMSK);
295262306a36Sopenharmony_ci		}
295362306a36Sopenharmony_ci	} else {
295462306a36Sopenharmony_ci		/*
295562306a36Sopenharmony_ci		 * Disable the Tx FIFO empty interrupt since there are
295662306a36Sopenharmony_ci		 * no more transactions that need to be queued right
295762306a36Sopenharmony_ci		 * now. This function is called from interrupt
295862306a36Sopenharmony_ci		 * handlers to queue more transactions as transfer
295962306a36Sopenharmony_ci		 * states change.
296062306a36Sopenharmony_ci		 */
296162306a36Sopenharmony_ci		gintmsk = dwc2_readl(hsotg, GINTMSK);
296262306a36Sopenharmony_ci		if (gintmsk & GINTSTS_PTXFEMP) {
296362306a36Sopenharmony_ci			gintmsk &= ~GINTSTS_PTXFEMP;
296462306a36Sopenharmony_ci			dwc2_writel(hsotg, gintmsk, GINTMSK);
296562306a36Sopenharmony_ci		}
296662306a36Sopenharmony_ci	}
296762306a36Sopenharmony_ci}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci/*
297062306a36Sopenharmony_ci * Processes active non-periodic channels and queues transactions for these
297162306a36Sopenharmony_ci * channels to the DWC_otg controller. After queueing transactions, the NP Tx
297262306a36Sopenharmony_ci * FIFO Empty interrupt is enabled if there are more transactions to queue as
297362306a36Sopenharmony_ci * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
297462306a36Sopenharmony_ci * FIFO Empty interrupt is disabled.
297562306a36Sopenharmony_ci *
297662306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
297762306a36Sopenharmony_ci */
297862306a36Sopenharmony_cistatic void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
297962306a36Sopenharmony_ci{
298062306a36Sopenharmony_ci	struct list_head *orig_qh_ptr;
298162306a36Sopenharmony_ci	struct dwc2_qh *qh;
298262306a36Sopenharmony_ci	u32 tx_status;
298362306a36Sopenharmony_ci	u32 qspcavail;
298462306a36Sopenharmony_ci	u32 fspcavail;
298562306a36Sopenharmony_ci	u32 gintmsk;
298662306a36Sopenharmony_ci	int status;
298762306a36Sopenharmony_ci	int no_queue_space = 0;
298862306a36Sopenharmony_ci	int no_fifo_space = 0;
298962306a36Sopenharmony_ci	int more_to_do = 0;
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	tx_status = dwc2_readl(hsotg, GNPTXSTS);
299462306a36Sopenharmony_ci	qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
299562306a36Sopenharmony_ci		    TXSTS_QSPCAVAIL_SHIFT;
299662306a36Sopenharmony_ci	fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
299762306a36Sopenharmony_ci		    TXSTS_FSPCAVAIL_SHIFT;
299862306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  NP Tx Req Queue Space Avail (before queue): %d\n",
299962306a36Sopenharmony_ci		 qspcavail);
300062306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  NP Tx FIFO Space Avail (before queue): %d\n",
300162306a36Sopenharmony_ci		 fspcavail);
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	/*
300462306a36Sopenharmony_ci	 * Keep track of the starting point. Skip over the start-of-list
300562306a36Sopenharmony_ci	 * entry.
300662306a36Sopenharmony_ci	 */
300762306a36Sopenharmony_ci	if (hsotg->non_periodic_qh_ptr == &hsotg->non_periodic_sched_active)
300862306a36Sopenharmony_ci		hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
300962306a36Sopenharmony_ci	orig_qh_ptr = hsotg->non_periodic_qh_ptr;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	/*
301262306a36Sopenharmony_ci	 * Process once through the active list or until no more space is
301362306a36Sopenharmony_ci	 * available in the request queue or the Tx FIFO
301462306a36Sopenharmony_ci	 */
301562306a36Sopenharmony_ci	do {
301662306a36Sopenharmony_ci		tx_status = dwc2_readl(hsotg, GNPTXSTS);
301762306a36Sopenharmony_ci		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
301862306a36Sopenharmony_ci			    TXSTS_QSPCAVAIL_SHIFT;
301962306a36Sopenharmony_ci		if (!hsotg->params.host_dma && qspcavail == 0) {
302062306a36Sopenharmony_ci			no_queue_space = 1;
302162306a36Sopenharmony_ci			break;
302262306a36Sopenharmony_ci		}
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci		qh = list_entry(hsotg->non_periodic_qh_ptr, struct dwc2_qh,
302562306a36Sopenharmony_ci				qh_list_entry);
302662306a36Sopenharmony_ci		if (!qh->channel)
302762306a36Sopenharmony_ci			goto next;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci		/* Make sure EP's TT buffer is clean before queueing qtds */
303062306a36Sopenharmony_ci		if (qh->tt_buffer_dirty)
303162306a36Sopenharmony_ci			goto next;
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
303462306a36Sopenharmony_ci			    TXSTS_FSPCAVAIL_SHIFT;
303562306a36Sopenharmony_ci		status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci		if (status > 0) {
303862306a36Sopenharmony_ci			more_to_do = 1;
303962306a36Sopenharmony_ci		} else if (status < 0) {
304062306a36Sopenharmony_ci			no_fifo_space = 1;
304162306a36Sopenharmony_ci			break;
304262306a36Sopenharmony_ci		}
304362306a36Sopenharmony_cinext:
304462306a36Sopenharmony_ci		/* Advance to next QH, skipping start-of-list entry */
304562306a36Sopenharmony_ci		hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
304662306a36Sopenharmony_ci		if (hsotg->non_periodic_qh_ptr ==
304762306a36Sopenharmony_ci				&hsotg->non_periodic_sched_active)
304862306a36Sopenharmony_ci			hsotg->non_periodic_qh_ptr =
304962306a36Sopenharmony_ci					hsotg->non_periodic_qh_ptr->next;
305062306a36Sopenharmony_ci	} while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	if (!hsotg->params.host_dma) {
305362306a36Sopenharmony_ci		tx_status = dwc2_readl(hsotg, GNPTXSTS);
305462306a36Sopenharmony_ci		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
305562306a36Sopenharmony_ci			    TXSTS_QSPCAVAIL_SHIFT;
305662306a36Sopenharmony_ci		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
305762306a36Sopenharmony_ci			    TXSTS_FSPCAVAIL_SHIFT;
305862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
305962306a36Sopenharmony_ci			 "  NP Tx Req Queue Space Avail (after queue): %d\n",
306062306a36Sopenharmony_ci			 qspcavail);
306162306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
306262306a36Sopenharmony_ci			 "  NP Tx FIFO Space Avail (after queue): %d\n",
306362306a36Sopenharmony_ci			 fspcavail);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci		if (more_to_do || no_queue_space || no_fifo_space) {
306662306a36Sopenharmony_ci			/*
306762306a36Sopenharmony_ci			 * May need to queue more transactions as the request
306862306a36Sopenharmony_ci			 * queue or Tx FIFO empties. Enable the non-periodic
306962306a36Sopenharmony_ci			 * Tx FIFO empty interrupt. (Always use the half-empty
307062306a36Sopenharmony_ci			 * level to ensure that new requests are loaded as
307162306a36Sopenharmony_ci			 * soon as possible.)
307262306a36Sopenharmony_ci			 */
307362306a36Sopenharmony_ci			gintmsk = dwc2_readl(hsotg, GINTMSK);
307462306a36Sopenharmony_ci			gintmsk |= GINTSTS_NPTXFEMP;
307562306a36Sopenharmony_ci			dwc2_writel(hsotg, gintmsk, GINTMSK);
307662306a36Sopenharmony_ci		} else {
307762306a36Sopenharmony_ci			/*
307862306a36Sopenharmony_ci			 * Disable the Tx FIFO empty interrupt since there are
307962306a36Sopenharmony_ci			 * no more transactions that need to be queued right
308062306a36Sopenharmony_ci			 * now. This function is called from interrupt
308162306a36Sopenharmony_ci			 * handlers to queue more transactions as transfer
308262306a36Sopenharmony_ci			 * states change.
308362306a36Sopenharmony_ci			 */
308462306a36Sopenharmony_ci			gintmsk = dwc2_readl(hsotg, GINTMSK);
308562306a36Sopenharmony_ci			gintmsk &= ~GINTSTS_NPTXFEMP;
308662306a36Sopenharmony_ci			dwc2_writel(hsotg, gintmsk, GINTMSK);
308762306a36Sopenharmony_ci		}
308862306a36Sopenharmony_ci	}
308962306a36Sopenharmony_ci}
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci/**
309262306a36Sopenharmony_ci * dwc2_hcd_queue_transactions() - Processes the currently active host channels
309362306a36Sopenharmony_ci * and queues transactions for these channels to the DWC_otg controller. Called
309462306a36Sopenharmony_ci * from the HCD interrupt handler functions.
309562306a36Sopenharmony_ci *
309662306a36Sopenharmony_ci * @hsotg:   The HCD state structure
309762306a36Sopenharmony_ci * @tr_type: The type(s) of transactions to queue (non-periodic, periodic,
309862306a36Sopenharmony_ci *           or both)
309962306a36Sopenharmony_ci *
310062306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
310162306a36Sopenharmony_ci */
310262306a36Sopenharmony_civoid dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
310362306a36Sopenharmony_ci				 enum dwc2_transaction_type tr_type)
310462306a36Sopenharmony_ci{
310562306a36Sopenharmony_ci#ifdef DWC2_DEBUG_SOF
310662306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "Queue Transactions\n");
310762306a36Sopenharmony_ci#endif
310862306a36Sopenharmony_ci	/* Process host channels associated with periodic transfers */
310962306a36Sopenharmony_ci	if (tr_type == DWC2_TRANSACTION_PERIODIC ||
311062306a36Sopenharmony_ci	    tr_type == DWC2_TRANSACTION_ALL)
311162306a36Sopenharmony_ci		dwc2_process_periodic_channels(hsotg);
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	/* Process host channels associated with non-periodic transfers */
311462306a36Sopenharmony_ci	if (tr_type == DWC2_TRANSACTION_NON_PERIODIC ||
311562306a36Sopenharmony_ci	    tr_type == DWC2_TRANSACTION_ALL) {
311662306a36Sopenharmony_ci		if (!list_empty(&hsotg->non_periodic_sched_active)) {
311762306a36Sopenharmony_ci			dwc2_process_non_periodic_channels(hsotg);
311862306a36Sopenharmony_ci		} else {
311962306a36Sopenharmony_ci			/*
312062306a36Sopenharmony_ci			 * Ensure NP Tx FIFO empty interrupt is disabled when
312162306a36Sopenharmony_ci			 * there are no non-periodic transfers to process
312262306a36Sopenharmony_ci			 */
312362306a36Sopenharmony_ci			u32 gintmsk = dwc2_readl(hsotg, GINTMSK);
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci			gintmsk &= ~GINTSTS_NPTXFEMP;
312662306a36Sopenharmony_ci			dwc2_writel(hsotg, gintmsk, GINTMSK);
312762306a36Sopenharmony_ci		}
312862306a36Sopenharmony_ci	}
312962306a36Sopenharmony_ci}
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_cistatic void dwc2_conn_id_status_change(struct work_struct *work)
313262306a36Sopenharmony_ci{
313362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
313462306a36Sopenharmony_ci						wf_otg);
313562306a36Sopenharmony_ci	u32 count = 0;
313662306a36Sopenharmony_ci	u32 gotgctl;
313762306a36Sopenharmony_ci	unsigned long flags;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s()\n", __func__);
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	gotgctl = dwc2_readl(hsotg, GOTGCTL);
314262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
314362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
314462306a36Sopenharmony_ci		!!(gotgctl & GOTGCTL_CONID_B));
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	/* B-Device connector (Device Mode) */
314762306a36Sopenharmony_ci	if (gotgctl & GOTGCTL_CONID_B) {
314862306a36Sopenharmony_ci		dwc2_vbus_supply_exit(hsotg);
314962306a36Sopenharmony_ci		/* Wait for switch to device mode */
315062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "connId B\n");
315162306a36Sopenharmony_ci		if (hsotg->bus_suspended) {
315262306a36Sopenharmony_ci			dev_info(hsotg->dev,
315362306a36Sopenharmony_ci				 "Do port resume before switching to device mode\n");
315462306a36Sopenharmony_ci			dwc2_port_resume(hsotg);
315562306a36Sopenharmony_ci		}
315662306a36Sopenharmony_ci		while (!dwc2_is_device_mode(hsotg)) {
315762306a36Sopenharmony_ci			dev_info(hsotg->dev,
315862306a36Sopenharmony_ci				 "Waiting for Peripheral Mode, Mode=%s\n",
315962306a36Sopenharmony_ci				 dwc2_is_host_mode(hsotg) ? "Host" :
316062306a36Sopenharmony_ci				 "Peripheral");
316162306a36Sopenharmony_ci			msleep(20);
316262306a36Sopenharmony_ci			/*
316362306a36Sopenharmony_ci			 * Sometimes the initial GOTGCTRL read is wrong, so
316462306a36Sopenharmony_ci			 * check it again and jump to host mode if that was
316562306a36Sopenharmony_ci			 * the case.
316662306a36Sopenharmony_ci			 */
316762306a36Sopenharmony_ci			gotgctl = dwc2_readl(hsotg, GOTGCTL);
316862306a36Sopenharmony_ci			if (!(gotgctl & GOTGCTL_CONID_B))
316962306a36Sopenharmony_ci				goto host;
317062306a36Sopenharmony_ci			if (++count > 250)
317162306a36Sopenharmony_ci				break;
317262306a36Sopenharmony_ci		}
317362306a36Sopenharmony_ci		if (count > 250)
317462306a36Sopenharmony_ci			dev_err(hsotg->dev,
317562306a36Sopenharmony_ci				"Connection id status change timed out\n");
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci		/*
317862306a36Sopenharmony_ci		 * Exit Partial Power Down without restoring registers.
317962306a36Sopenharmony_ci		 * No need to check the return value as registers
318062306a36Sopenharmony_ci		 * are not being restored.
318162306a36Sopenharmony_ci		 */
318262306a36Sopenharmony_ci		if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
318362306a36Sopenharmony_ci			dwc2_exit_partial_power_down(hsotg, 0, false);
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
318662306a36Sopenharmony_ci		dwc2_core_init(hsotg, false);
318762306a36Sopenharmony_ci		dwc2_enable_global_interrupts(hsotg);
318862306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
318962306a36Sopenharmony_ci		dwc2_hsotg_core_init_disconnected(hsotg, false);
319062306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
319162306a36Sopenharmony_ci		/* Enable ACG feature in device mode,if supported */
319262306a36Sopenharmony_ci		dwc2_enable_acg(hsotg);
319362306a36Sopenharmony_ci		dwc2_hsotg_core_connect(hsotg);
319462306a36Sopenharmony_ci	} else {
319562306a36Sopenharmony_cihost:
319662306a36Sopenharmony_ci		/* A-Device connector (Host Mode) */
319762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "connId A\n");
319862306a36Sopenharmony_ci		while (!dwc2_is_host_mode(hsotg)) {
319962306a36Sopenharmony_ci			dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n",
320062306a36Sopenharmony_ci				 dwc2_is_host_mode(hsotg) ?
320162306a36Sopenharmony_ci				 "Host" : "Peripheral");
320262306a36Sopenharmony_ci			msleep(20);
320362306a36Sopenharmony_ci			if (++count > 250)
320462306a36Sopenharmony_ci				break;
320562306a36Sopenharmony_ci		}
320662306a36Sopenharmony_ci		if (count > 250)
320762306a36Sopenharmony_ci			dev_err(hsotg->dev,
320862306a36Sopenharmony_ci				"Connection id status change timed out\n");
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
321162306a36Sopenharmony_ci		dwc2_hsotg_disconnect(hsotg);
321262306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_A_HOST;
321562306a36Sopenharmony_ci		/* Initialize the Core for Host mode */
321662306a36Sopenharmony_ci		dwc2_core_init(hsotg, false);
321762306a36Sopenharmony_ci		dwc2_enable_global_interrupts(hsotg);
321862306a36Sopenharmony_ci		dwc2_hcd_start(hsotg);
321962306a36Sopenharmony_ci	}
322062306a36Sopenharmony_ci}
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_cistatic void dwc2_wakeup_detected(struct timer_list *t)
322362306a36Sopenharmony_ci{
322462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = from_timer(hsotg, t, wkp_timer);
322562306a36Sopenharmony_ci	u32 hprt0;
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s()\n", __func__);
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci	/*
323062306a36Sopenharmony_ci	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
323162306a36Sopenharmony_ci	 * so that OPT tests pass with all PHYs.)
323262306a36Sopenharmony_ci	 */
323362306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
323462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
323562306a36Sopenharmony_ci	hprt0 &= ~HPRT0_RES;
323662306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
323762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
323862306a36Sopenharmony_ci		dwc2_readl(hsotg, HPRT0));
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci	dwc2_hcd_rem_wakeup(hsotg);
324162306a36Sopenharmony_ci	hsotg->bus_suspended = false;
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ci	/* Change to L0 state */
324462306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
324562306a36Sopenharmony_ci}
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_cistatic int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg)
324862306a36Sopenharmony_ci{
324962306a36Sopenharmony_ci	struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	return hcd->self.b_hnp_enable;
325262306a36Sopenharmony_ci}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci/**
325562306a36Sopenharmony_ci * dwc2_port_suspend() - Put controller in suspend mode for host.
325662306a36Sopenharmony_ci *
325762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
325862306a36Sopenharmony_ci * @windex: The control request wIndex field
325962306a36Sopenharmony_ci *
326062306a36Sopenharmony_ci * Return: non-zero if failed to enter suspend mode for host.
326162306a36Sopenharmony_ci *
326262306a36Sopenharmony_ci * This function is for entering Host mode suspend.
326362306a36Sopenharmony_ci * Must NOT be called with interrupt disabled or spinlock held.
326462306a36Sopenharmony_ci */
326562306a36Sopenharmony_ciint dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
326662306a36Sopenharmony_ci{
326762306a36Sopenharmony_ci	unsigned long flags;
326862306a36Sopenharmony_ci	u32 pcgctl;
326962306a36Sopenharmony_ci	u32 gotgctl;
327062306a36Sopenharmony_ci	int ret = 0;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s()\n", __func__);
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
327762306a36Sopenharmony_ci		gotgctl = dwc2_readl(hsotg, GOTGCTL);
327862306a36Sopenharmony_ci		gotgctl |= GOTGCTL_HSTSETHNPEN;
327962306a36Sopenharmony_ci		dwc2_writel(hsotg, gotgctl, GOTGCTL);
328062306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_A_SUSPEND;
328162306a36Sopenharmony_ci	}
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	switch (hsotg->params.power_down) {
328462306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_PARTIAL:
328562306a36Sopenharmony_ci		ret = dwc2_enter_partial_power_down(hsotg);
328662306a36Sopenharmony_ci		if (ret)
328762306a36Sopenharmony_ci			dev_err(hsotg->dev,
328862306a36Sopenharmony_ci				"enter partial_power_down failed.\n");
328962306a36Sopenharmony_ci		break;
329062306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_HIBERNATION:
329162306a36Sopenharmony_ci		/*
329262306a36Sopenharmony_ci		 * Perform spin unlock and lock because in
329362306a36Sopenharmony_ci		 * "dwc2_host_enter_hibernation()" function there is a spinlock
329462306a36Sopenharmony_ci		 * logic which prevents servicing of any IRQ during entering
329562306a36Sopenharmony_ci		 * hibernation.
329662306a36Sopenharmony_ci		 */
329762306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
329862306a36Sopenharmony_ci		ret = dwc2_enter_hibernation(hsotg, 1);
329962306a36Sopenharmony_ci		if (ret)
330062306a36Sopenharmony_ci			dev_err(hsotg->dev, "enter hibernation failed.\n");
330162306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
330262306a36Sopenharmony_ci		break;
330362306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_NONE:
330462306a36Sopenharmony_ci		/*
330562306a36Sopenharmony_ci		 * If not hibernation nor partial power down are supported,
330662306a36Sopenharmony_ci		 * clock gating is used to save power.
330762306a36Sopenharmony_ci		 */
330862306a36Sopenharmony_ci		if (!hsotg->params.no_clock_gating)
330962306a36Sopenharmony_ci			dwc2_host_enter_clock_gating(hsotg);
331062306a36Sopenharmony_ci		break;
331162306a36Sopenharmony_ci	}
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	/* For HNP the bus must be suspended for at least 200ms */
331462306a36Sopenharmony_ci	if (dwc2_host_is_b_hnp_enabled(hsotg)) {
331562306a36Sopenharmony_ci		pcgctl = dwc2_readl(hsotg, PCGCTL);
331662306a36Sopenharmony_ci		pcgctl &= ~PCGCTL_STOPPCLK;
331762306a36Sopenharmony_ci		dwc2_writel(hsotg, pcgctl, PCGCTL);
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci		msleep(200);
332262306a36Sopenharmony_ci	} else {
332362306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
332462306a36Sopenharmony_ci	}
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci	return ret;
332762306a36Sopenharmony_ci}
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci/**
333062306a36Sopenharmony_ci * dwc2_port_resume() - Exit controller from suspend mode for host.
333162306a36Sopenharmony_ci *
333262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
333362306a36Sopenharmony_ci *
333462306a36Sopenharmony_ci * Return: non-zero if failed to exit suspend mode for host.
333562306a36Sopenharmony_ci *
333662306a36Sopenharmony_ci * This function is for exiting Host mode suspend.
333762306a36Sopenharmony_ci * Must NOT be called with interrupt disabled or spinlock held.
333862306a36Sopenharmony_ci */
333962306a36Sopenharmony_ciint dwc2_port_resume(struct dwc2_hsotg *hsotg)
334062306a36Sopenharmony_ci{
334162306a36Sopenharmony_ci	unsigned long flags;
334262306a36Sopenharmony_ci	int ret = 0;
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	switch (hsotg->params.power_down) {
334762306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_PARTIAL:
334862306a36Sopenharmony_ci		ret = dwc2_exit_partial_power_down(hsotg, 0, true);
334962306a36Sopenharmony_ci		if (ret)
335062306a36Sopenharmony_ci			dev_err(hsotg->dev,
335162306a36Sopenharmony_ci				"exit partial_power_down failed.\n");
335262306a36Sopenharmony_ci		break;
335362306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_HIBERNATION:
335462306a36Sopenharmony_ci		/* Exit host hibernation. */
335562306a36Sopenharmony_ci		ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
335662306a36Sopenharmony_ci		if (ret)
335762306a36Sopenharmony_ci			dev_err(hsotg->dev, "exit hibernation failed.\n");
335862306a36Sopenharmony_ci		break;
335962306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_NONE:
336062306a36Sopenharmony_ci		/*
336162306a36Sopenharmony_ci		 * If not hibernation nor partial power down are supported,
336262306a36Sopenharmony_ci		 * port resume is done using the clock gating programming flow.
336362306a36Sopenharmony_ci		 */
336462306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
336562306a36Sopenharmony_ci		dwc2_host_exit_clock_gating(hsotg, 0);
336662306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
336762306a36Sopenharmony_ci		break;
336862306a36Sopenharmony_ci	}
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	return ret;
337362306a36Sopenharmony_ci}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci/* Handles hub class-specific requests */
337662306a36Sopenharmony_cistatic int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
337762306a36Sopenharmony_ci				u16 wvalue, u16 windex, char *buf, u16 wlength)
337862306a36Sopenharmony_ci{
337962306a36Sopenharmony_ci	struct usb_hub_descriptor *hub_desc;
338062306a36Sopenharmony_ci	int retval = 0;
338162306a36Sopenharmony_ci	u32 hprt0;
338262306a36Sopenharmony_ci	u32 port_status;
338362306a36Sopenharmony_ci	u32 speed;
338462306a36Sopenharmony_ci	u32 pcgctl;
338562306a36Sopenharmony_ci	u32 pwr;
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	switch (typereq) {
338862306a36Sopenharmony_ci	case ClearHubFeature:
338962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "ClearHubFeature %1xh\n", wvalue);
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci		switch (wvalue) {
339262306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
339362306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
339462306a36Sopenharmony_ci			/* Nothing required here */
339562306a36Sopenharmony_ci			break;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci		default:
339862306a36Sopenharmony_ci			retval = -EINVAL;
339962306a36Sopenharmony_ci			dev_err(hsotg->dev,
340062306a36Sopenharmony_ci				"ClearHubFeature request %1xh unknown\n",
340162306a36Sopenharmony_ci				wvalue);
340262306a36Sopenharmony_ci		}
340362306a36Sopenharmony_ci		break;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	case ClearPortFeature:
340662306a36Sopenharmony_ci		if (wvalue != USB_PORT_FEAT_L1)
340762306a36Sopenharmony_ci			if (!windex || windex > 1)
340862306a36Sopenharmony_ci				goto error;
340962306a36Sopenharmony_ci		switch (wvalue) {
341062306a36Sopenharmony_ci		case USB_PORT_FEAT_ENABLE:
341162306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
341262306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_ENABLE\n");
341362306a36Sopenharmony_ci			hprt0 = dwc2_read_hprt0(hsotg);
341462306a36Sopenharmony_ci			hprt0 |= HPRT0_ENA;
341562306a36Sopenharmony_ci			dwc2_writel(hsotg, hprt0, HPRT0);
341662306a36Sopenharmony_ci			break;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
341962306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
342062306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci			if (hsotg->bus_suspended)
342362306a36Sopenharmony_ci				retval = dwc2_port_resume(hsotg);
342462306a36Sopenharmony_ci			break;
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
342762306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
342862306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_POWER\n");
342962306a36Sopenharmony_ci			hprt0 = dwc2_read_hprt0(hsotg);
343062306a36Sopenharmony_ci			pwr = hprt0 & HPRT0_PWR;
343162306a36Sopenharmony_ci			hprt0 &= ~HPRT0_PWR;
343262306a36Sopenharmony_ci			dwc2_writel(hsotg, hprt0, HPRT0);
343362306a36Sopenharmony_ci			if (pwr)
343462306a36Sopenharmony_ci				dwc2_vbus_supply_exit(hsotg);
343562306a36Sopenharmony_ci			break;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci		case USB_PORT_FEAT_INDICATOR:
343862306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
343962306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
344062306a36Sopenharmony_ci			/* Port indicator not supported */
344162306a36Sopenharmony_ci			break;
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci		case USB_PORT_FEAT_C_CONNECTION:
344462306a36Sopenharmony_ci			/*
344562306a36Sopenharmony_ci			 * Clears driver's internal Connect Status Change flag
344662306a36Sopenharmony_ci			 */
344762306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
344862306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
344962306a36Sopenharmony_ci			hsotg->flags.b.port_connect_status_change = 0;
345062306a36Sopenharmony_ci			break;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci		case USB_PORT_FEAT_C_RESET:
345362306a36Sopenharmony_ci			/* Clears driver's internal Port Reset Change flag */
345462306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
345562306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_C_RESET\n");
345662306a36Sopenharmony_ci			hsotg->flags.b.port_reset_change = 0;
345762306a36Sopenharmony_ci			break;
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci		case USB_PORT_FEAT_C_ENABLE:
346062306a36Sopenharmony_ci			/*
346162306a36Sopenharmony_ci			 * Clears the driver's internal Port Enable/Disable
346262306a36Sopenharmony_ci			 * Change flag
346362306a36Sopenharmony_ci			 */
346462306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
346562306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
346662306a36Sopenharmony_ci			hsotg->flags.b.port_enable_change = 0;
346762306a36Sopenharmony_ci			break;
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci		case USB_PORT_FEAT_C_SUSPEND:
347062306a36Sopenharmony_ci			/*
347162306a36Sopenharmony_ci			 * Clears the driver's internal Port Suspend Change
347262306a36Sopenharmony_ci			 * flag, which is set when resume signaling on the host
347362306a36Sopenharmony_ci			 * port is complete
347462306a36Sopenharmony_ci			 */
347562306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
347662306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
347762306a36Sopenharmony_ci			hsotg->flags.b.port_suspend_change = 0;
347862306a36Sopenharmony_ci			break;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci		case USB_PORT_FEAT_C_PORT_L1:
348162306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
348262306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_C_PORT_L1\n");
348362306a36Sopenharmony_ci			hsotg->flags.b.port_l1_change = 0;
348462306a36Sopenharmony_ci			break;
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci		case USB_PORT_FEAT_C_OVER_CURRENT:
348762306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
348862306a36Sopenharmony_ci				"ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
348962306a36Sopenharmony_ci			hsotg->flags.b.port_over_current_change = 0;
349062306a36Sopenharmony_ci			break;
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci		default:
349362306a36Sopenharmony_ci			retval = -EINVAL;
349462306a36Sopenharmony_ci			dev_err(hsotg->dev,
349562306a36Sopenharmony_ci				"ClearPortFeature request %1xh unknown or unsupported\n",
349662306a36Sopenharmony_ci				wvalue);
349762306a36Sopenharmony_ci		}
349862306a36Sopenharmony_ci		break;
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	case GetHubDescriptor:
350162306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "GetHubDescriptor\n");
350262306a36Sopenharmony_ci		hub_desc = (struct usb_hub_descriptor *)buf;
350362306a36Sopenharmony_ci		hub_desc->bDescLength = 9;
350462306a36Sopenharmony_ci		hub_desc->bDescriptorType = USB_DT_HUB;
350562306a36Sopenharmony_ci		hub_desc->bNbrPorts = 1;
350662306a36Sopenharmony_ci		hub_desc->wHubCharacteristics =
350762306a36Sopenharmony_ci			cpu_to_le16(HUB_CHAR_COMMON_LPSM |
350862306a36Sopenharmony_ci				    HUB_CHAR_INDV_PORT_OCPM);
350962306a36Sopenharmony_ci		hub_desc->bPwrOn2PwrGood = 1;
351062306a36Sopenharmony_ci		hub_desc->bHubContrCurrent = 0;
351162306a36Sopenharmony_ci		hub_desc->u.hs.DeviceRemovable[0] = 0;
351262306a36Sopenharmony_ci		hub_desc->u.hs.DeviceRemovable[1] = 0xff;
351362306a36Sopenharmony_ci		break;
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	case GetHubStatus:
351662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "GetHubStatus\n");
351762306a36Sopenharmony_ci		memset(buf, 0, 4);
351862306a36Sopenharmony_ci		break;
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	case GetPortStatus:
352162306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
352262306a36Sopenharmony_ci			 "GetPortStatus wIndex=0x%04x flags=0x%08x\n", windex,
352362306a36Sopenharmony_ci			 hsotg->flags.d32);
352462306a36Sopenharmony_ci		if (!windex || windex > 1)
352562306a36Sopenharmony_ci			goto error;
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci		port_status = 0;
352862306a36Sopenharmony_ci		if (hsotg->flags.b.port_connect_status_change)
352962306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_C_CONNECTION << 16;
353062306a36Sopenharmony_ci		if (hsotg->flags.b.port_enable_change)
353162306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_C_ENABLE << 16;
353262306a36Sopenharmony_ci		if (hsotg->flags.b.port_suspend_change)
353362306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_C_SUSPEND << 16;
353462306a36Sopenharmony_ci		if (hsotg->flags.b.port_l1_change)
353562306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_C_L1 << 16;
353662306a36Sopenharmony_ci		if (hsotg->flags.b.port_reset_change)
353762306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_C_RESET << 16;
353862306a36Sopenharmony_ci		if (hsotg->flags.b.port_over_current_change) {
353962306a36Sopenharmony_ci			dev_warn(hsotg->dev, "Overcurrent change detected\n");
354062306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_C_OVERCURRENT << 16;
354162306a36Sopenharmony_ci		}
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci		if (!hsotg->flags.b.port_connect_status) {
354462306a36Sopenharmony_ci			/*
354562306a36Sopenharmony_ci			 * The port is disconnected, which means the core is
354662306a36Sopenharmony_ci			 * either in device mode or it soon will be. Just
354762306a36Sopenharmony_ci			 * return 0's for the remainder of the port status
354862306a36Sopenharmony_ci			 * since the port register can't be read if the core
354962306a36Sopenharmony_ci			 * is in device mode.
355062306a36Sopenharmony_ci			 */
355162306a36Sopenharmony_ci			*(__le32 *)buf = cpu_to_le32(port_status);
355262306a36Sopenharmony_ci			break;
355362306a36Sopenharmony_ci		}
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci		hprt0 = dwc2_readl(hsotg, HPRT0);
355662306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "  HPRT0: 0x%08x\n", hprt0);
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci		if (hprt0 & HPRT0_CONNSTS)
355962306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_CONNECTION;
356062306a36Sopenharmony_ci		if (hprt0 & HPRT0_ENA)
356162306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_ENABLE;
356262306a36Sopenharmony_ci		if (hprt0 & HPRT0_SUSP)
356362306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_SUSPEND;
356462306a36Sopenharmony_ci		if (hprt0 & HPRT0_OVRCURRACT)
356562306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_OVERCURRENT;
356662306a36Sopenharmony_ci		if (hprt0 & HPRT0_RST)
356762306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_RESET;
356862306a36Sopenharmony_ci		if (hprt0 & HPRT0_PWR)
356962306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_POWER;
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci		speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
357262306a36Sopenharmony_ci		if (speed == HPRT0_SPD_HIGH_SPEED)
357362306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_HIGH_SPEED;
357462306a36Sopenharmony_ci		else if (speed == HPRT0_SPD_LOW_SPEED)
357562306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_LOW_SPEED;
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci		if (hprt0 & HPRT0_TSTCTL_MASK)
357862306a36Sopenharmony_ci			port_status |= USB_PORT_STAT_TEST;
357962306a36Sopenharmony_ci		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci		if (hsotg->params.dma_desc_fs_enable) {
358262306a36Sopenharmony_ci			/*
358362306a36Sopenharmony_ci			 * Enable descriptor DMA only if a full speed
358462306a36Sopenharmony_ci			 * device is connected.
358562306a36Sopenharmony_ci			 */
358662306a36Sopenharmony_ci			if (hsotg->new_connection &&
358762306a36Sopenharmony_ci			    ((port_status &
358862306a36Sopenharmony_ci			      (USB_PORT_STAT_CONNECTION |
358962306a36Sopenharmony_ci			       USB_PORT_STAT_HIGH_SPEED |
359062306a36Sopenharmony_ci			       USB_PORT_STAT_LOW_SPEED)) ==
359162306a36Sopenharmony_ci			       USB_PORT_STAT_CONNECTION)) {
359262306a36Sopenharmony_ci				u32 hcfg;
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci				dev_info(hsotg->dev, "Enabling descriptor DMA mode\n");
359562306a36Sopenharmony_ci				hsotg->params.dma_desc_enable = true;
359662306a36Sopenharmony_ci				hcfg = dwc2_readl(hsotg, HCFG);
359762306a36Sopenharmony_ci				hcfg |= HCFG_DESCDMA;
359862306a36Sopenharmony_ci				dwc2_writel(hsotg, hcfg, HCFG);
359962306a36Sopenharmony_ci				hsotg->new_connection = false;
360062306a36Sopenharmony_ci			}
360162306a36Sopenharmony_ci		}
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "port_status=%08x\n", port_status);
360462306a36Sopenharmony_ci		*(__le32 *)buf = cpu_to_le32(port_status);
360562306a36Sopenharmony_ci		break;
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci	case SetHubFeature:
360862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "SetHubFeature\n");
360962306a36Sopenharmony_ci		/* No HUB features supported */
361062306a36Sopenharmony_ci		break;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	case SetPortFeature:
361362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "SetPortFeature\n");
361462306a36Sopenharmony_ci		if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1))
361562306a36Sopenharmony_ci			goto error;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci		if (!hsotg->flags.b.port_connect_status) {
361862306a36Sopenharmony_ci			/*
361962306a36Sopenharmony_ci			 * The port is disconnected, which means the core is
362062306a36Sopenharmony_ci			 * either in device mode or it soon will be. Just
362162306a36Sopenharmony_ci			 * return without doing anything since the port
362262306a36Sopenharmony_ci			 * register can't be written if the core is in device
362362306a36Sopenharmony_ci			 * mode.
362462306a36Sopenharmony_ci			 */
362562306a36Sopenharmony_ci			break;
362662306a36Sopenharmony_ci		}
362762306a36Sopenharmony_ci
362862306a36Sopenharmony_ci		switch (wvalue) {
362962306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
363062306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
363162306a36Sopenharmony_ci				"SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
363262306a36Sopenharmony_ci			if (windex != hsotg->otg_port)
363362306a36Sopenharmony_ci				goto error;
363462306a36Sopenharmony_ci			if (!hsotg->bus_suspended)
363562306a36Sopenharmony_ci				retval = dwc2_port_suspend(hsotg, windex);
363662306a36Sopenharmony_ci			break;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
363962306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
364062306a36Sopenharmony_ci				"SetPortFeature - USB_PORT_FEAT_POWER\n");
364162306a36Sopenharmony_ci			hprt0 = dwc2_read_hprt0(hsotg);
364262306a36Sopenharmony_ci			pwr = hprt0 & HPRT0_PWR;
364362306a36Sopenharmony_ci			hprt0 |= HPRT0_PWR;
364462306a36Sopenharmony_ci			dwc2_writel(hsotg, hprt0, HPRT0);
364562306a36Sopenharmony_ci			if (!pwr)
364662306a36Sopenharmony_ci				dwc2_vbus_supply_init(hsotg);
364762306a36Sopenharmony_ci			break;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci		case USB_PORT_FEAT_RESET:
365062306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
365162306a36Sopenharmony_ci				"SetPortFeature - USB_PORT_FEAT_RESET\n");
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci			hprt0 = dwc2_read_hprt0(hsotg);
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci			if (hsotg->hibernated) {
365662306a36Sopenharmony_ci				retval = dwc2_exit_hibernation(hsotg, 0, 1, 1);
365762306a36Sopenharmony_ci				if (retval)
365862306a36Sopenharmony_ci					dev_err(hsotg->dev,
365962306a36Sopenharmony_ci						"exit hibernation failed\n");
366062306a36Sopenharmony_ci			}
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci			if (hsotg->in_ppd) {
366362306a36Sopenharmony_ci				retval = dwc2_exit_partial_power_down(hsotg, 1,
366462306a36Sopenharmony_ci								      true);
366562306a36Sopenharmony_ci				if (retval)
366662306a36Sopenharmony_ci					dev_err(hsotg->dev,
366762306a36Sopenharmony_ci						"exit partial_power_down failed\n");
366862306a36Sopenharmony_ci			}
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci			if (hsotg->params.power_down ==
367162306a36Sopenharmony_ci			    DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
367262306a36Sopenharmony_ci				dwc2_host_exit_clock_gating(hsotg, 0);
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci			pcgctl = dwc2_readl(hsotg, PCGCTL);
367562306a36Sopenharmony_ci			pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
367662306a36Sopenharmony_ci			dwc2_writel(hsotg, pcgctl, PCGCTL);
367762306a36Sopenharmony_ci			/* ??? Original driver does this */
367862306a36Sopenharmony_ci			dwc2_writel(hsotg, 0, PCGCTL);
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci			hprt0 = dwc2_read_hprt0(hsotg);
368162306a36Sopenharmony_ci			pwr = hprt0 & HPRT0_PWR;
368262306a36Sopenharmony_ci			/* Clear suspend bit if resetting from suspend state */
368362306a36Sopenharmony_ci			hprt0 &= ~HPRT0_SUSP;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci			/*
368662306a36Sopenharmony_ci			 * When B-Host the Port reset bit is set in the Start
368762306a36Sopenharmony_ci			 * HCD Callback function, so that the reset is started
368862306a36Sopenharmony_ci			 * within 1ms of the HNP success interrupt
368962306a36Sopenharmony_ci			 */
369062306a36Sopenharmony_ci			if (!dwc2_hcd_is_b_host(hsotg)) {
369162306a36Sopenharmony_ci				hprt0 |= HPRT0_PWR | HPRT0_RST;
369262306a36Sopenharmony_ci				dev_dbg(hsotg->dev,
369362306a36Sopenharmony_ci					"In host mode, hprt0=%08x\n", hprt0);
369462306a36Sopenharmony_ci				dwc2_writel(hsotg, hprt0, HPRT0);
369562306a36Sopenharmony_ci				if (!pwr)
369662306a36Sopenharmony_ci					dwc2_vbus_supply_init(hsotg);
369762306a36Sopenharmony_ci			}
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci			/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
370062306a36Sopenharmony_ci			msleep(50);
370162306a36Sopenharmony_ci			hprt0 &= ~HPRT0_RST;
370262306a36Sopenharmony_ci			dwc2_writel(hsotg, hprt0, HPRT0);
370362306a36Sopenharmony_ci			hsotg->lx_state = DWC2_L0; /* Now back to On state */
370462306a36Sopenharmony_ci			break;
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_ci		case USB_PORT_FEAT_INDICATOR:
370762306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
370862306a36Sopenharmony_ci				"SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
370962306a36Sopenharmony_ci			/* Not supported */
371062306a36Sopenharmony_ci			break;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci		case USB_PORT_FEAT_TEST:
371362306a36Sopenharmony_ci			hprt0 = dwc2_read_hprt0(hsotg);
371462306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
371562306a36Sopenharmony_ci				"SetPortFeature - USB_PORT_FEAT_TEST\n");
371662306a36Sopenharmony_ci			hprt0 &= ~HPRT0_TSTCTL_MASK;
371762306a36Sopenharmony_ci			hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
371862306a36Sopenharmony_ci			dwc2_writel(hsotg, hprt0, HPRT0);
371962306a36Sopenharmony_ci			break;
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci		default:
372262306a36Sopenharmony_ci			retval = -EINVAL;
372362306a36Sopenharmony_ci			dev_err(hsotg->dev,
372462306a36Sopenharmony_ci				"SetPortFeature %1xh unknown or unsupported\n",
372562306a36Sopenharmony_ci				wvalue);
372662306a36Sopenharmony_ci			break;
372762306a36Sopenharmony_ci		}
372862306a36Sopenharmony_ci		break;
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	default:
373162306a36Sopenharmony_cierror:
373262306a36Sopenharmony_ci		retval = -EINVAL;
373362306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
373462306a36Sopenharmony_ci			"Unknown hub control request: %1xh wIndex: %1xh wValue: %1xh\n",
373562306a36Sopenharmony_ci			typereq, windex, wvalue);
373662306a36Sopenharmony_ci		break;
373762306a36Sopenharmony_ci	}
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci	return retval;
374062306a36Sopenharmony_ci}
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_cistatic int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
374362306a36Sopenharmony_ci{
374462306a36Sopenharmony_ci	int retval;
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci	if (port != 1)
374762306a36Sopenharmony_ci		return -EINVAL;
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci	retval = (hsotg->flags.b.port_connect_status_change ||
375062306a36Sopenharmony_ci		  hsotg->flags.b.port_reset_change ||
375162306a36Sopenharmony_ci		  hsotg->flags.b.port_enable_change ||
375262306a36Sopenharmony_ci		  hsotg->flags.b.port_suspend_change ||
375362306a36Sopenharmony_ci		  hsotg->flags.b.port_over_current_change);
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci	if (retval) {
375662306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
375762306a36Sopenharmony_ci			"DWC OTG HCD HUB STATUS DATA: Root port status changed\n");
375862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "  port_connect_status_change: %d\n",
375962306a36Sopenharmony_ci			hsotg->flags.b.port_connect_status_change);
376062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "  port_reset_change: %d\n",
376162306a36Sopenharmony_ci			hsotg->flags.b.port_reset_change);
376262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "  port_enable_change: %d\n",
376362306a36Sopenharmony_ci			hsotg->flags.b.port_enable_change);
376462306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "  port_suspend_change: %d\n",
376562306a36Sopenharmony_ci			hsotg->flags.b.port_suspend_change);
376662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "  port_over_current_change: %d\n",
376762306a36Sopenharmony_ci			hsotg->flags.b.port_over_current_change);
376862306a36Sopenharmony_ci	}
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci	return retval;
377162306a36Sopenharmony_ci}
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ciint dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
377462306a36Sopenharmony_ci{
377562306a36Sopenharmony_ci	u32 hfnum = dwc2_readl(hsotg, HFNUM);
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci#ifdef DWC2_DEBUG_SOF
377862306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
377962306a36Sopenharmony_ci		 (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT);
378062306a36Sopenharmony_ci#endif
378162306a36Sopenharmony_ci	return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
378262306a36Sopenharmony_ci}
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ciint dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us)
378562306a36Sopenharmony_ci{
378662306a36Sopenharmony_ci	u32 hprt = dwc2_readl(hsotg, HPRT0);
378762306a36Sopenharmony_ci	u32 hfir = dwc2_readl(hsotg, HFIR);
378862306a36Sopenharmony_ci	u32 hfnum = dwc2_readl(hsotg, HFNUM);
378962306a36Sopenharmony_ci	unsigned int us_per_frame;
379062306a36Sopenharmony_ci	unsigned int frame_number;
379162306a36Sopenharmony_ci	unsigned int remaining;
379262306a36Sopenharmony_ci	unsigned int interval;
379362306a36Sopenharmony_ci	unsigned int phy_clks;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	/* High speed has 125 us per (micro) frame; others are 1 ms per */
379662306a36Sopenharmony_ci	us_per_frame = (hprt & HPRT0_SPD_MASK) ? 1000 : 125;
379762306a36Sopenharmony_ci
379862306a36Sopenharmony_ci	/* Extract fields */
379962306a36Sopenharmony_ci	frame_number = (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
380062306a36Sopenharmony_ci	remaining = (hfnum & HFNUM_FRREM_MASK) >> HFNUM_FRREM_SHIFT;
380162306a36Sopenharmony_ci	interval = (hfir & HFIR_FRINT_MASK) >> HFIR_FRINT_SHIFT;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	/*
380462306a36Sopenharmony_ci	 * Number of phy clocks since the last tick of the frame number after
380562306a36Sopenharmony_ci	 * "us" has passed.
380662306a36Sopenharmony_ci	 */
380762306a36Sopenharmony_ci	phy_clks = (interval - remaining) +
380862306a36Sopenharmony_ci		   DIV_ROUND_UP(interval * us, us_per_frame);
380962306a36Sopenharmony_ci
381062306a36Sopenharmony_ci	return dwc2_frame_num_inc(frame_number, phy_clks / interval);
381162306a36Sopenharmony_ci}
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_ciint dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
381462306a36Sopenharmony_ci{
381562306a36Sopenharmony_ci	return hsotg->op_state == OTG_STATE_B_HOST;
381662306a36Sopenharmony_ci}
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_cistatic struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg,
381962306a36Sopenharmony_ci					       int iso_desc_count,
382062306a36Sopenharmony_ci					       gfp_t mem_flags)
382162306a36Sopenharmony_ci{
382262306a36Sopenharmony_ci	struct dwc2_hcd_urb *urb;
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	urb = kzalloc(struct_size(urb, iso_descs, iso_desc_count), mem_flags);
382562306a36Sopenharmony_ci	if (urb)
382662306a36Sopenharmony_ci		urb->packet_count = iso_desc_count;
382762306a36Sopenharmony_ci	return urb;
382862306a36Sopenharmony_ci}
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_cistatic void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg,
383162306a36Sopenharmony_ci				      struct dwc2_hcd_urb *urb, u8 dev_addr,
383262306a36Sopenharmony_ci				      u8 ep_num, u8 ep_type, u8 ep_dir,
383362306a36Sopenharmony_ci				      u16 maxp, u16 maxp_mult)
383462306a36Sopenharmony_ci{
383562306a36Sopenharmony_ci	if (dbg_perio() ||
383662306a36Sopenharmony_ci	    ep_type == USB_ENDPOINT_XFER_BULK ||
383762306a36Sopenharmony_ci	    ep_type == USB_ENDPOINT_XFER_CONTROL)
383862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
383962306a36Sopenharmony_ci			 "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, maxp=%d (%d mult)\n",
384062306a36Sopenharmony_ci			 dev_addr, ep_num, ep_dir, ep_type, maxp, maxp_mult);
384162306a36Sopenharmony_ci	urb->pipe_info.dev_addr = dev_addr;
384262306a36Sopenharmony_ci	urb->pipe_info.ep_num = ep_num;
384362306a36Sopenharmony_ci	urb->pipe_info.pipe_type = ep_type;
384462306a36Sopenharmony_ci	urb->pipe_info.pipe_dir = ep_dir;
384562306a36Sopenharmony_ci	urb->pipe_info.maxp = maxp;
384662306a36Sopenharmony_ci	urb->pipe_info.maxp_mult = maxp_mult;
384762306a36Sopenharmony_ci}
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci/*
385062306a36Sopenharmony_ci * NOTE: This function will be removed once the peripheral controller code
385162306a36Sopenharmony_ci * is integrated and the driver is stable
385262306a36Sopenharmony_ci */
385362306a36Sopenharmony_civoid dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
385462306a36Sopenharmony_ci{
385562306a36Sopenharmony_ci#ifdef DEBUG
385662306a36Sopenharmony_ci	struct dwc2_host_chan *chan;
385762306a36Sopenharmony_ci	struct dwc2_hcd_urb *urb;
385862306a36Sopenharmony_ci	struct dwc2_qtd *qtd;
385962306a36Sopenharmony_ci	int num_channels;
386062306a36Sopenharmony_ci	u32 np_tx_status;
386162306a36Sopenharmony_ci	u32 p_tx_status;
386262306a36Sopenharmony_ci	int i;
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_ci	num_channels = hsotg->params.host_channels;
386562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "\n");
386662306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
386762306a36Sopenharmony_ci		"************************************************************\n");
386862306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "HCD State:\n");
386962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  Num channels: %d\n", num_channels);
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	for (i = 0; i < num_channels; i++) {
387262306a36Sopenharmony_ci		chan = hsotg->hc_ptr_array[i];
387362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "  Channel %d:\n", i);
387462306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
387562306a36Sopenharmony_ci			"    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
387662306a36Sopenharmony_ci			chan->dev_addr, chan->ep_num, chan->ep_is_in);
387762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    speed: %d\n", chan->speed);
387862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type);
387962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet);
388062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    data_pid_start: %d\n",
388162306a36Sopenharmony_ci			chan->data_pid_start);
388262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    multi_count: %d\n", chan->multi_count);
388362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    xfer_started: %d\n",
388462306a36Sopenharmony_ci			chan->xfer_started);
388562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf);
388662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n",
388762306a36Sopenharmony_ci			(unsigned long)chan->xfer_dma);
388862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len);
388962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    xfer_count: %d\n", chan->xfer_count);
389062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    halt_on_queue: %d\n",
389162306a36Sopenharmony_ci			chan->halt_on_queue);
389262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    halt_pending: %d\n",
389362306a36Sopenharmony_ci			chan->halt_pending);
389462306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status);
389562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    do_split: %d\n", chan->do_split);
389662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    complete_split: %d\n",
389762306a36Sopenharmony_ci			chan->complete_split);
389862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    hub_addr: %d\n", chan->hub_addr);
389962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    hub_port: %d\n", chan->hub_port);
390062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    xact_pos: %d\n", chan->xact_pos);
390162306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    requests: %d\n", chan->requests);
390262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh);
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_ci		if (chan->xfer_started) {
390562306a36Sopenharmony_ci			u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci			hfnum = dwc2_readl(hsotg, HFNUM);
390862306a36Sopenharmony_ci			hcchar = dwc2_readl(hsotg, HCCHAR(i));
390962306a36Sopenharmony_ci			hctsiz = dwc2_readl(hsotg, HCTSIZ(i));
391062306a36Sopenharmony_ci			hcint = dwc2_readl(hsotg, HCINT(i));
391162306a36Sopenharmony_ci			hcintmsk = dwc2_readl(hsotg, HCINTMSK(i));
391262306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "    hfnum: 0x%08x\n", hfnum);
391362306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "    hcchar: 0x%08x\n", hcchar);
391462306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "    hctsiz: 0x%08x\n", hctsiz);
391562306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "    hcint: 0x%08x\n", hcint);
391662306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "    hcintmsk: 0x%08x\n", hcintmsk);
391762306a36Sopenharmony_ci		}
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci		if (!(chan->xfer_started && chan->qh))
392062306a36Sopenharmony_ci			continue;
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci		list_for_each_entry(qtd, &chan->qh->qtd_list, qtd_list_entry) {
392362306a36Sopenharmony_ci			if (!qtd->in_process)
392462306a36Sopenharmony_ci				break;
392562306a36Sopenharmony_ci			urb = qtd->urb;
392662306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "    URB Info:\n");
392762306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "      qtd: %p, urb: %p\n",
392862306a36Sopenharmony_ci				qtd, urb);
392962306a36Sopenharmony_ci			if (urb) {
393062306a36Sopenharmony_ci				dev_dbg(hsotg->dev,
393162306a36Sopenharmony_ci					"      Dev: %d, EP: %d %s\n",
393262306a36Sopenharmony_ci					dwc2_hcd_get_dev_addr(&urb->pipe_info),
393362306a36Sopenharmony_ci					dwc2_hcd_get_ep_num(&urb->pipe_info),
393462306a36Sopenharmony_ci					dwc2_hcd_is_pipe_in(&urb->pipe_info) ?
393562306a36Sopenharmony_ci					"IN" : "OUT");
393662306a36Sopenharmony_ci				dev_dbg(hsotg->dev,
393762306a36Sopenharmony_ci					"      Max packet size: %d (%d mult)\n",
393862306a36Sopenharmony_ci					dwc2_hcd_get_maxp(&urb->pipe_info),
393962306a36Sopenharmony_ci					dwc2_hcd_get_maxp_mult(&urb->pipe_info));
394062306a36Sopenharmony_ci				dev_dbg(hsotg->dev,
394162306a36Sopenharmony_ci					"      transfer_buffer: %p\n",
394262306a36Sopenharmony_ci					urb->buf);
394362306a36Sopenharmony_ci				dev_dbg(hsotg->dev,
394462306a36Sopenharmony_ci					"      transfer_dma: %08lx\n",
394562306a36Sopenharmony_ci					(unsigned long)urb->dma);
394662306a36Sopenharmony_ci				dev_dbg(hsotg->dev,
394762306a36Sopenharmony_ci					"      transfer_buffer_length: %d\n",
394862306a36Sopenharmony_ci					urb->length);
394962306a36Sopenharmony_ci				dev_dbg(hsotg->dev, "      actual_length: %d\n",
395062306a36Sopenharmony_ci					urb->actual_length);
395162306a36Sopenharmony_ci			}
395262306a36Sopenharmony_ci		}
395362306a36Sopenharmony_ci	}
395462306a36Sopenharmony_ci
395562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  non_periodic_channels: %d\n",
395662306a36Sopenharmony_ci		hsotg->non_periodic_channels);
395762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  periodic_channels: %d\n",
395862306a36Sopenharmony_ci		hsotg->periodic_channels);
395962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  periodic_usecs: %d\n", hsotg->periodic_usecs);
396062306a36Sopenharmony_ci	np_tx_status = dwc2_readl(hsotg, GNPTXSTS);
396162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  NP Tx Req Queue Space Avail: %d\n",
396262306a36Sopenharmony_ci		(np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
396362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  NP Tx FIFO Space Avail: %d\n",
396462306a36Sopenharmony_ci		(np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
396562306a36Sopenharmony_ci	p_tx_status = dwc2_readl(hsotg, HPTXSTS);
396662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  P Tx Req Queue Space Avail: %d\n",
396762306a36Sopenharmony_ci		(p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
396862306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  P Tx FIFO Space Avail: %d\n",
396962306a36Sopenharmony_ci		(p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
397062306a36Sopenharmony_ci	dwc2_dump_global_registers(hsotg);
397162306a36Sopenharmony_ci	dwc2_dump_host_registers(hsotg);
397262306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
397362306a36Sopenharmony_ci		"************************************************************\n");
397462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "\n");
397562306a36Sopenharmony_ci#endif
397662306a36Sopenharmony_ci}
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_cistruct wrapper_priv_data {
397962306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg;
398062306a36Sopenharmony_ci};
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci/* Gets the dwc2_hsotg from a usb_hcd */
398362306a36Sopenharmony_cistatic struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd)
398462306a36Sopenharmony_ci{
398562306a36Sopenharmony_ci	struct wrapper_priv_data *p;
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci	p = (struct wrapper_priv_data *)&hcd->hcd_priv;
398862306a36Sopenharmony_ci	return p->hsotg;
398962306a36Sopenharmony_ci}
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci/**
399262306a36Sopenharmony_ci * dwc2_host_get_tt_info() - Get the dwc2_tt associated with context
399362306a36Sopenharmony_ci *
399462306a36Sopenharmony_ci * This will get the dwc2_tt structure (and ttport) associated with the given
399562306a36Sopenharmony_ci * context (which is really just a struct urb pointer).
399662306a36Sopenharmony_ci *
399762306a36Sopenharmony_ci * The first time this is called for a given TT we allocate memory for our
399862306a36Sopenharmony_ci * structure.  When everyone is done and has called dwc2_host_put_tt_info()
399962306a36Sopenharmony_ci * then the refcount for the structure will go to 0 and we'll free it.
400062306a36Sopenharmony_ci *
400162306a36Sopenharmony_ci * @hsotg:     The HCD state structure for the DWC OTG controller.
400262306a36Sopenharmony_ci * @context:   The priv pointer from a struct dwc2_hcd_urb.
400362306a36Sopenharmony_ci * @mem_flags: Flags for allocating memory.
400462306a36Sopenharmony_ci * @ttport:    We'll return this device's port number here.  That's used to
400562306a36Sopenharmony_ci *             reference into the bitmap if we're on a multi_tt hub.
400662306a36Sopenharmony_ci *
400762306a36Sopenharmony_ci * Return: a pointer to a struct dwc2_tt.  Don't forget to call
400862306a36Sopenharmony_ci *         dwc2_host_put_tt_info()!  Returns NULL upon memory alloc failure.
400962306a36Sopenharmony_ci */
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_cistruct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context,
401262306a36Sopenharmony_ci				      gfp_t mem_flags, int *ttport)
401362306a36Sopenharmony_ci{
401462306a36Sopenharmony_ci	struct urb *urb = context;
401562306a36Sopenharmony_ci	struct dwc2_tt *dwc_tt = NULL;
401662306a36Sopenharmony_ci
401762306a36Sopenharmony_ci	if (urb->dev->tt) {
401862306a36Sopenharmony_ci		*ttport = urb->dev->ttport;
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci		dwc_tt = urb->dev->tt->hcpriv;
402162306a36Sopenharmony_ci		if (!dwc_tt) {
402262306a36Sopenharmony_ci			size_t bitmap_size;
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci			/*
402562306a36Sopenharmony_ci			 * For single_tt we need one schedule.  For multi_tt
402662306a36Sopenharmony_ci			 * we need one per port.
402762306a36Sopenharmony_ci			 */
402862306a36Sopenharmony_ci			bitmap_size = DWC2_ELEMENTS_PER_LS_BITMAP *
402962306a36Sopenharmony_ci				      sizeof(dwc_tt->periodic_bitmaps[0]);
403062306a36Sopenharmony_ci			if (urb->dev->tt->multi)
403162306a36Sopenharmony_ci				bitmap_size *= urb->dev->tt->hub->maxchild;
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci			dwc_tt = kzalloc(sizeof(*dwc_tt) + bitmap_size,
403462306a36Sopenharmony_ci					 mem_flags);
403562306a36Sopenharmony_ci			if (!dwc_tt)
403662306a36Sopenharmony_ci				return NULL;
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_ci			dwc_tt->usb_tt = urb->dev->tt;
403962306a36Sopenharmony_ci			dwc_tt->usb_tt->hcpriv = dwc_tt;
404062306a36Sopenharmony_ci		}
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci		dwc_tt->refcount++;
404362306a36Sopenharmony_ci	}
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_ci	return dwc_tt;
404662306a36Sopenharmony_ci}
404762306a36Sopenharmony_ci
404862306a36Sopenharmony_ci/**
404962306a36Sopenharmony_ci * dwc2_host_put_tt_info() - Put the dwc2_tt from dwc2_host_get_tt_info()
405062306a36Sopenharmony_ci *
405162306a36Sopenharmony_ci * Frees resources allocated by dwc2_host_get_tt_info() if all current holders
405262306a36Sopenharmony_ci * of the structure are done.
405362306a36Sopenharmony_ci *
405462306a36Sopenharmony_ci * It's OK to call this with NULL.
405562306a36Sopenharmony_ci *
405662306a36Sopenharmony_ci * @hsotg:     The HCD state structure for the DWC OTG controller.
405762306a36Sopenharmony_ci * @dwc_tt:    The pointer returned by dwc2_host_get_tt_info.
405862306a36Sopenharmony_ci */
405962306a36Sopenharmony_civoid dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, struct dwc2_tt *dwc_tt)
406062306a36Sopenharmony_ci{
406162306a36Sopenharmony_ci	/* Model kfree and make put of NULL a no-op */
406262306a36Sopenharmony_ci	if (!dwc_tt)
406362306a36Sopenharmony_ci		return;
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci	WARN_ON(dwc_tt->refcount < 1);
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci	dwc_tt->refcount--;
406862306a36Sopenharmony_ci	if (!dwc_tt->refcount) {
406962306a36Sopenharmony_ci		dwc_tt->usb_tt->hcpriv = NULL;
407062306a36Sopenharmony_ci		kfree(dwc_tt);
407162306a36Sopenharmony_ci	}
407262306a36Sopenharmony_ci}
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ciint dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context)
407562306a36Sopenharmony_ci{
407662306a36Sopenharmony_ci	struct urb *urb = context;
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci	return urb->dev->speed;
407962306a36Sopenharmony_ci}
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_cistatic void dwc2_allocate_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
408262306a36Sopenharmony_ci					struct urb *urb)
408362306a36Sopenharmony_ci{
408462306a36Sopenharmony_ci	struct usb_bus *bus = hcd_to_bus(hcd);
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	if (urb->interval)
408762306a36Sopenharmony_ci		bus->bandwidth_allocated += bw / urb->interval;
408862306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
408962306a36Sopenharmony_ci		bus->bandwidth_isoc_reqs++;
409062306a36Sopenharmony_ci	else
409162306a36Sopenharmony_ci		bus->bandwidth_int_reqs++;
409262306a36Sopenharmony_ci}
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_cistatic void dwc2_free_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
409562306a36Sopenharmony_ci				    struct urb *urb)
409662306a36Sopenharmony_ci{
409762306a36Sopenharmony_ci	struct usb_bus *bus = hcd_to_bus(hcd);
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	if (urb->interval)
410062306a36Sopenharmony_ci		bus->bandwidth_allocated -= bw / urb->interval;
410162306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
410262306a36Sopenharmony_ci		bus->bandwidth_isoc_reqs--;
410362306a36Sopenharmony_ci	else
410462306a36Sopenharmony_ci		bus->bandwidth_int_reqs--;
410562306a36Sopenharmony_ci}
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_ci/*
410862306a36Sopenharmony_ci * Sets the final status of an URB and returns it to the upper layer. Any
410962306a36Sopenharmony_ci * required cleanup of the URB is performed.
411062306a36Sopenharmony_ci *
411162306a36Sopenharmony_ci * Must be called with interrupt disabled and spinlock held
411262306a36Sopenharmony_ci */
411362306a36Sopenharmony_civoid dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
411462306a36Sopenharmony_ci			int status)
411562306a36Sopenharmony_ci{
411662306a36Sopenharmony_ci	struct urb *urb;
411762306a36Sopenharmony_ci	int i;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	if (!qtd) {
412062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "## %s: qtd is NULL ##\n", __func__);
412162306a36Sopenharmony_ci		return;
412262306a36Sopenharmony_ci	}
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	if (!qtd->urb) {
412562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__);
412662306a36Sopenharmony_ci		return;
412762306a36Sopenharmony_ci	}
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	urb = qtd->urb->priv;
413062306a36Sopenharmony_ci	if (!urb) {
413162306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__);
413262306a36Sopenharmony_ci		return;
413362306a36Sopenharmony_ci	}
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	urb->actual_length = dwc2_hcd_urb_get_actual_length(qtd->urb);
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci	if (dbg_urb(urb))
413862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
413962306a36Sopenharmony_ci			 "%s: urb %p device %d ep %d-%s status %d actual %d\n",
414062306a36Sopenharmony_ci			 __func__, urb, usb_pipedevice(urb->pipe),
414162306a36Sopenharmony_ci			 usb_pipeendpoint(urb->pipe),
414262306a36Sopenharmony_ci			 usb_pipein(urb->pipe) ? "IN" : "OUT", status,
414362306a36Sopenharmony_ci			 urb->actual_length);
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
414662306a36Sopenharmony_ci		urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
414762306a36Sopenharmony_ci		for (i = 0; i < urb->number_of_packets; ++i) {
414862306a36Sopenharmony_ci			urb->iso_frame_desc[i].actual_length =
414962306a36Sopenharmony_ci				dwc2_hcd_urb_get_iso_desc_actual_length(
415062306a36Sopenharmony_ci						qtd->urb, i);
415162306a36Sopenharmony_ci			urb->iso_frame_desc[i].status =
415262306a36Sopenharmony_ci				dwc2_hcd_urb_get_iso_desc_status(qtd->urb, i);
415362306a36Sopenharmony_ci		}
415462306a36Sopenharmony_ci	}
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
415762306a36Sopenharmony_ci		for (i = 0; i < urb->number_of_packets; i++)
415862306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
415962306a36Sopenharmony_ci				 i, urb->iso_frame_desc[i].status);
416062306a36Sopenharmony_ci	}
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci	urb->status = status;
416362306a36Sopenharmony_ci	if (!status) {
416462306a36Sopenharmony_ci		if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
416562306a36Sopenharmony_ci		    urb->actual_length < urb->transfer_buffer_length)
416662306a36Sopenharmony_ci			urb->status = -EREMOTEIO;
416762306a36Sopenharmony_ci	}
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
417062306a36Sopenharmony_ci	    usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
417162306a36Sopenharmony_ci		struct usb_host_endpoint *ep = urb->ep;
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_ci		if (ep)
417462306a36Sopenharmony_ci			dwc2_free_bus_bandwidth(dwc2_hsotg_to_hcd(hsotg),
417562306a36Sopenharmony_ci					dwc2_hcd_get_ep_bandwidth(hsotg, ep),
417662306a36Sopenharmony_ci					urb);
417762306a36Sopenharmony_ci	}
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(dwc2_hsotg_to_hcd(hsotg), urb);
418062306a36Sopenharmony_ci	urb->hcpriv = NULL;
418162306a36Sopenharmony_ci	kfree(qtd->urb);
418262306a36Sopenharmony_ci	qtd->urb = NULL;
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_ci	usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
418562306a36Sopenharmony_ci}
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci/*
418862306a36Sopenharmony_ci * Work queue function for starting the HCD when A-Cable is connected
418962306a36Sopenharmony_ci */
419062306a36Sopenharmony_cistatic void dwc2_hcd_start_func(struct work_struct *work)
419162306a36Sopenharmony_ci{
419262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
419362306a36Sopenharmony_ci						start_work.work);
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s() %p\n", __func__, hsotg);
419662306a36Sopenharmony_ci	dwc2_host_start(hsotg);
419762306a36Sopenharmony_ci}
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci/*
420062306a36Sopenharmony_ci * Reset work queue function
420162306a36Sopenharmony_ci */
420262306a36Sopenharmony_cistatic void dwc2_hcd_reset_func(struct work_struct *work)
420362306a36Sopenharmony_ci{
420462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
420562306a36Sopenharmony_ci						reset_work.work);
420662306a36Sopenharmony_ci	unsigned long flags;
420762306a36Sopenharmony_ci	u32 hprt0;
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "USB RESET function called\n");
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
421462306a36Sopenharmony_ci	hprt0 &= ~HPRT0_RST;
421562306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
421662306a36Sopenharmony_ci	hsotg->flags.b.port_reset_change = 1;
421762306a36Sopenharmony_ci
421862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
421962306a36Sopenharmony_ci}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_cistatic void dwc2_hcd_phy_reset_func(struct work_struct *work)
422262306a36Sopenharmony_ci{
422362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
422462306a36Sopenharmony_ci						phy_reset_work);
422562306a36Sopenharmony_ci	int ret;
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	ret = phy_reset(hsotg->phy);
422862306a36Sopenharmony_ci	if (ret)
422962306a36Sopenharmony_ci		dev_warn(hsotg->dev, "PHY reset failed\n");
423062306a36Sopenharmony_ci}
423162306a36Sopenharmony_ci
423262306a36Sopenharmony_ci/*
423362306a36Sopenharmony_ci * =========================================================================
423462306a36Sopenharmony_ci *  Linux HC Driver Functions
423562306a36Sopenharmony_ci * =========================================================================
423662306a36Sopenharmony_ci */
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_ci/*
423962306a36Sopenharmony_ci * Initializes the DWC_otg controller and its root hub and prepares it for host
424062306a36Sopenharmony_ci * mode operation. Activates the root port. Returns 0 on success and a negative
424162306a36Sopenharmony_ci * error code on failure.
424262306a36Sopenharmony_ci */
424362306a36Sopenharmony_cistatic int _dwc2_hcd_start(struct usb_hcd *hcd)
424462306a36Sopenharmony_ci{
424562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
424662306a36Sopenharmony_ci	struct usb_bus *bus = hcd_to_bus(hcd);
424762306a36Sopenharmony_ci	unsigned long flags;
424862306a36Sopenharmony_ci	u32 hprt0;
424962306a36Sopenharmony_ci	int ret;
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
425262306a36Sopenharmony_ci
425362306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
425462306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
425562306a36Sopenharmony_ci	hcd->state = HC_STATE_RUNNING;
425662306a36Sopenharmony_ci	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	if (dwc2_is_device_mode(hsotg)) {
425962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
426062306a36Sopenharmony_ci		return 0;	/* why 0 ?? */
426162306a36Sopenharmony_ci	}
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci	dwc2_hcd_reinit(hsotg);
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
426662306a36Sopenharmony_ci	/* Has vbus power been turned on in dwc2_core_host_init ? */
426762306a36Sopenharmony_ci	if (hprt0 & HPRT0_PWR) {
426862306a36Sopenharmony_ci		/* Enable external vbus supply before resuming root hub */
426962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
427062306a36Sopenharmony_ci		ret = dwc2_vbus_supply_init(hsotg);
427162306a36Sopenharmony_ci		if (ret)
427262306a36Sopenharmony_ci			return ret;
427362306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
427462306a36Sopenharmony_ci	}
427562306a36Sopenharmony_ci
427662306a36Sopenharmony_ci	/* Initialize and connect root hub if one is not already attached */
427762306a36Sopenharmony_ci	if (bus->root_hub) {
427862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
427962306a36Sopenharmony_ci		/* Inform the HUB driver to resume */
428062306a36Sopenharmony_ci		usb_hcd_resume_root_hub(hcd);
428162306a36Sopenharmony_ci	}
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci	return 0;
428662306a36Sopenharmony_ci}
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci/*
428962306a36Sopenharmony_ci * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
429062306a36Sopenharmony_ci * stopped.
429162306a36Sopenharmony_ci */
429262306a36Sopenharmony_cistatic void _dwc2_hcd_stop(struct usb_hcd *hcd)
429362306a36Sopenharmony_ci{
429462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
429562306a36Sopenharmony_ci	unsigned long flags;
429662306a36Sopenharmony_ci	u32 hprt0;
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci	/* Turn off all host-specific interrupts */
429962306a36Sopenharmony_ci	dwc2_disable_host_interrupts(hsotg);
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_ci	/* Wait for interrupt processing to finish */
430262306a36Sopenharmony_ci	synchronize_irq(hcd->irq);
430362306a36Sopenharmony_ci
430462306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
430562306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
430662306a36Sopenharmony_ci	/* Ensure hcd is disconnected */
430762306a36Sopenharmony_ci	dwc2_hcd_disconnect(hsotg, true);
430862306a36Sopenharmony_ci	dwc2_hcd_stop(hsotg);
430962306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L3;
431062306a36Sopenharmony_ci	hcd->state = HC_STATE_HALT;
431162306a36Sopenharmony_ci	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
431262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci	/* keep balanced supply init/exit by checking HPRT0_PWR */
431562306a36Sopenharmony_ci	if (hprt0 & HPRT0_PWR)
431662306a36Sopenharmony_ci		dwc2_vbus_supply_exit(hsotg);
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	usleep_range(1000, 3000);
431962306a36Sopenharmony_ci}
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_cistatic int _dwc2_hcd_suspend(struct usb_hcd *hcd)
432262306a36Sopenharmony_ci{
432362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
432462306a36Sopenharmony_ci	unsigned long flags;
432562306a36Sopenharmony_ci	int ret = 0;
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	if (dwc2_is_device_mode(hsotg))
433062306a36Sopenharmony_ci		goto unlock;
433162306a36Sopenharmony_ci
433262306a36Sopenharmony_ci	if (hsotg->lx_state != DWC2_L0)
433362306a36Sopenharmony_ci		goto unlock;
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_ci	if (!HCD_HW_ACCESSIBLE(hcd))
433662306a36Sopenharmony_ci		goto unlock;
433762306a36Sopenharmony_ci
433862306a36Sopenharmony_ci	if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
433962306a36Sopenharmony_ci		goto unlock;
434062306a36Sopenharmony_ci
434162306a36Sopenharmony_ci	if (hsotg->bus_suspended)
434262306a36Sopenharmony_ci		goto skip_power_saving;
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_ci	if (hsotg->flags.b.port_connect_status == 0)
434562306a36Sopenharmony_ci		goto skip_power_saving;
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci	switch (hsotg->params.power_down) {
434862306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_PARTIAL:
434962306a36Sopenharmony_ci		/* Enter partial_power_down */
435062306a36Sopenharmony_ci		ret = dwc2_enter_partial_power_down(hsotg);
435162306a36Sopenharmony_ci		if (ret)
435262306a36Sopenharmony_ci			dev_err(hsotg->dev,
435362306a36Sopenharmony_ci				"enter partial_power_down failed\n");
435462306a36Sopenharmony_ci		/* After entering suspend, hardware is not accessible */
435562306a36Sopenharmony_ci		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
435662306a36Sopenharmony_ci		break;
435762306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_HIBERNATION:
435862306a36Sopenharmony_ci		/* Enter hibernation */
435962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
436062306a36Sopenharmony_ci		ret = dwc2_enter_hibernation(hsotg, 1);
436162306a36Sopenharmony_ci		if (ret)
436262306a36Sopenharmony_ci			dev_err(hsotg->dev, "enter hibernation failed\n");
436362306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci		/* After entering suspend, hardware is not accessible */
436662306a36Sopenharmony_ci		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
436762306a36Sopenharmony_ci		break;
436862306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_NONE:
436962306a36Sopenharmony_ci		/*
437062306a36Sopenharmony_ci		 * If not hibernation nor partial power down are supported,
437162306a36Sopenharmony_ci		 * clock gating is used to save power.
437262306a36Sopenharmony_ci		 */
437362306a36Sopenharmony_ci		if (!hsotg->params.no_clock_gating) {
437462306a36Sopenharmony_ci			dwc2_host_enter_clock_gating(hsotg);
437562306a36Sopenharmony_ci
437662306a36Sopenharmony_ci			/* After entering suspend, hardware is not accessible */
437762306a36Sopenharmony_ci			clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
437862306a36Sopenharmony_ci		}
437962306a36Sopenharmony_ci		break;
438062306a36Sopenharmony_ci	default:
438162306a36Sopenharmony_ci		goto skip_power_saving;
438262306a36Sopenharmony_ci	}
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
438562306a36Sopenharmony_ci	dwc2_vbus_supply_exit(hsotg);
438662306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
438762306a36Sopenharmony_ci
438862306a36Sopenharmony_ci	/* Ask phy to be suspended */
438962306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hsotg->uphy)) {
439062306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
439162306a36Sopenharmony_ci		usb_phy_set_suspend(hsotg->uphy, true);
439262306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
439362306a36Sopenharmony_ci	}
439462306a36Sopenharmony_ci
439562306a36Sopenharmony_ciskip_power_saving:
439662306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
439762306a36Sopenharmony_ciunlock:
439862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	return ret;
440162306a36Sopenharmony_ci}
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_cistatic int _dwc2_hcd_resume(struct usb_hcd *hcd)
440462306a36Sopenharmony_ci{
440562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
440662306a36Sopenharmony_ci	unsigned long flags;
440762306a36Sopenharmony_ci	u32 hprt0;
440862306a36Sopenharmony_ci	int ret = 0;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci	if (dwc2_is_device_mode(hsotg))
441362306a36Sopenharmony_ci		goto unlock;
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	if (hsotg->lx_state != DWC2_L2)
441662306a36Sopenharmony_ci		goto unlock;
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci	/*
442162306a36Sopenharmony_ci	 * Added port connection status checking which prevents exiting from
442262306a36Sopenharmony_ci	 * Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
442362306a36Sopenharmony_ci	 * Power Down mode.
442462306a36Sopenharmony_ci	 */
442562306a36Sopenharmony_ci	if (hprt0 & HPRT0_CONNSTS) {
442662306a36Sopenharmony_ci		hsotg->lx_state = DWC2_L0;
442762306a36Sopenharmony_ci		goto unlock;
442862306a36Sopenharmony_ci	}
442962306a36Sopenharmony_ci
443062306a36Sopenharmony_ci	switch (hsotg->params.power_down) {
443162306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_PARTIAL:
443262306a36Sopenharmony_ci		ret = dwc2_exit_partial_power_down(hsotg, 0, true);
443362306a36Sopenharmony_ci		if (ret)
443462306a36Sopenharmony_ci			dev_err(hsotg->dev,
443562306a36Sopenharmony_ci				"exit partial_power_down failed\n");
443662306a36Sopenharmony_ci		/*
443762306a36Sopenharmony_ci		 * Set HW accessible bit before powering on the controller
443862306a36Sopenharmony_ci		 * since an interrupt may rise.
443962306a36Sopenharmony_ci		 */
444062306a36Sopenharmony_ci		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
444162306a36Sopenharmony_ci		break;
444262306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_HIBERNATION:
444362306a36Sopenharmony_ci		ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
444462306a36Sopenharmony_ci		if (ret)
444562306a36Sopenharmony_ci			dev_err(hsotg->dev, "exit hibernation failed.\n");
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci		/*
444862306a36Sopenharmony_ci		 * Set HW accessible bit before powering on the controller
444962306a36Sopenharmony_ci		 * since an interrupt may rise.
445062306a36Sopenharmony_ci		 */
445162306a36Sopenharmony_ci		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
445262306a36Sopenharmony_ci		break;
445362306a36Sopenharmony_ci	case DWC2_POWER_DOWN_PARAM_NONE:
445462306a36Sopenharmony_ci		/*
445562306a36Sopenharmony_ci		 * If not hibernation nor partial power down are supported,
445662306a36Sopenharmony_ci		 * port resume is done using the clock gating programming flow.
445762306a36Sopenharmony_ci		 */
445862306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
445962306a36Sopenharmony_ci		dwc2_host_exit_clock_gating(hsotg, 0);
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci		/*
446262306a36Sopenharmony_ci		 * Initialize the Core for Host mode, as after system resume
446362306a36Sopenharmony_ci		 * the global interrupts are disabled.
446462306a36Sopenharmony_ci		 */
446562306a36Sopenharmony_ci		dwc2_core_init(hsotg, false);
446662306a36Sopenharmony_ci		dwc2_enable_global_interrupts(hsotg);
446762306a36Sopenharmony_ci		dwc2_hcd_reinit(hsotg);
446862306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci		/*
447162306a36Sopenharmony_ci		 * Set HW accessible bit before powering on the controller
447262306a36Sopenharmony_ci		 * since an interrupt may rise.
447362306a36Sopenharmony_ci		 */
447462306a36Sopenharmony_ci		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
447562306a36Sopenharmony_ci		break;
447662306a36Sopenharmony_ci	default:
447762306a36Sopenharmony_ci		hsotg->lx_state = DWC2_L0;
447862306a36Sopenharmony_ci		goto unlock;
447962306a36Sopenharmony_ci	}
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci	/* Change Root port status, as port status change occurred after resume.*/
448262306a36Sopenharmony_ci	hsotg->flags.b.port_suspend_change = 1;
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci	/*
448562306a36Sopenharmony_ci	 * Enable power if not already done.
448662306a36Sopenharmony_ci	 * This must not be spinlocked since duration
448762306a36Sopenharmony_ci	 * of this call is unknown.
448862306a36Sopenharmony_ci	 */
448962306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hsotg->uphy)) {
449062306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
449162306a36Sopenharmony_ci		usb_phy_set_suspend(hsotg->uphy, false);
449262306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
449362306a36Sopenharmony_ci	}
449462306a36Sopenharmony_ci
449562306a36Sopenharmony_ci	/* Enable external vbus supply after resuming the port. */
449662306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
449762306a36Sopenharmony_ci	dwc2_vbus_supply_init(hsotg);
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	/* Wait for controller to correctly update D+/D- level */
450062306a36Sopenharmony_ci	usleep_range(3000, 5000);
450162306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
450262306a36Sopenharmony_ci
450362306a36Sopenharmony_ci	/*
450462306a36Sopenharmony_ci	 * Clear Port Enable and Port Status changes.
450562306a36Sopenharmony_ci	 * Enable Port Power.
450662306a36Sopenharmony_ci	 */
450762306a36Sopenharmony_ci	dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET |
450862306a36Sopenharmony_ci			HPRT0_ENACHG, HPRT0);
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci	/* Wait for controller to detect Port Connect */
451162306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
451262306a36Sopenharmony_ci	usleep_range(5000, 7000);
451362306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
451462306a36Sopenharmony_ciunlock:
451562306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_ci	return ret;
451862306a36Sopenharmony_ci}
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci/* Returns the current frame number */
452162306a36Sopenharmony_cistatic int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
452262306a36Sopenharmony_ci{
452362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci	return dwc2_hcd_get_frame_number(hsotg);
452662306a36Sopenharmony_ci}
452762306a36Sopenharmony_ci
452862306a36Sopenharmony_cistatic void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb,
452962306a36Sopenharmony_ci			       char *fn_name)
453062306a36Sopenharmony_ci{
453162306a36Sopenharmony_ci#ifdef VERBOSE_DEBUG
453262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
453362306a36Sopenharmony_ci	char *pipetype = NULL;
453462306a36Sopenharmony_ci	char *speed = NULL;
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb);
453762306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Device address: %d\n",
453862306a36Sopenharmony_ci		 usb_pipedevice(urb->pipe));
453962306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Endpoint: %d, %s\n",
454062306a36Sopenharmony_ci		 usb_pipeendpoint(urb->pipe),
454162306a36Sopenharmony_ci		 usb_pipein(urb->pipe) ? "IN" : "OUT");
454262306a36Sopenharmony_ci
454362306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
454462306a36Sopenharmony_ci	case PIPE_CONTROL:
454562306a36Sopenharmony_ci		pipetype = "CONTROL";
454662306a36Sopenharmony_ci		break;
454762306a36Sopenharmony_ci	case PIPE_BULK:
454862306a36Sopenharmony_ci		pipetype = "BULK";
454962306a36Sopenharmony_ci		break;
455062306a36Sopenharmony_ci	case PIPE_INTERRUPT:
455162306a36Sopenharmony_ci		pipetype = "INTERRUPT";
455262306a36Sopenharmony_ci		break;
455362306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
455462306a36Sopenharmony_ci		pipetype = "ISOCHRONOUS";
455562306a36Sopenharmony_ci		break;
455662306a36Sopenharmony_ci	}
455762306a36Sopenharmony_ci
455862306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Endpoint type: %s %s (%s)\n", pipetype,
455962306a36Sopenharmony_ci		 usb_urb_dir_in(urb) ? "IN" : "OUT", usb_pipein(urb->pipe) ?
456062306a36Sopenharmony_ci		 "IN" : "OUT");
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	switch (urb->dev->speed) {
456362306a36Sopenharmony_ci	case USB_SPEED_HIGH:
456462306a36Sopenharmony_ci		speed = "HIGH";
456562306a36Sopenharmony_ci		break;
456662306a36Sopenharmony_ci	case USB_SPEED_FULL:
456762306a36Sopenharmony_ci		speed = "FULL";
456862306a36Sopenharmony_ci		break;
456962306a36Sopenharmony_ci	case USB_SPEED_LOW:
457062306a36Sopenharmony_ci		speed = "LOW";
457162306a36Sopenharmony_ci		break;
457262306a36Sopenharmony_ci	default:
457362306a36Sopenharmony_ci		speed = "UNKNOWN";
457462306a36Sopenharmony_ci		break;
457562306a36Sopenharmony_ci	}
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Speed: %s\n", speed);
457862306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Max packet size: %d (%d mult)\n",
457962306a36Sopenharmony_ci		 usb_endpoint_maxp(&urb->ep->desc),
458062306a36Sopenharmony_ci		 usb_endpoint_maxp_mult(&urb->ep->desc));
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Data buffer length: %d\n",
458362306a36Sopenharmony_ci		 urb->transfer_buffer_length);
458462306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n",
458562306a36Sopenharmony_ci		 urb->transfer_buffer, (unsigned long)urb->transfer_dma);
458662306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n",
458762306a36Sopenharmony_ci		 urb->setup_packet, (unsigned long)urb->setup_dma);
458862306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "  Interval: %d\n", urb->interval);
458962306a36Sopenharmony_ci
459062306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
459162306a36Sopenharmony_ci		int i;
459262306a36Sopenharmony_ci
459362306a36Sopenharmony_ci		for (i = 0; i < urb->number_of_packets; i++) {
459462306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "  ISO Desc %d:\n", i);
459562306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "    offset: %d, length %d\n",
459662306a36Sopenharmony_ci				 urb->iso_frame_desc[i].offset,
459762306a36Sopenharmony_ci				 urb->iso_frame_desc[i].length);
459862306a36Sopenharmony_ci		}
459962306a36Sopenharmony_ci	}
460062306a36Sopenharmony_ci#endif
460162306a36Sopenharmony_ci}
460262306a36Sopenharmony_ci
460362306a36Sopenharmony_ci/*
460462306a36Sopenharmony_ci * Starts processing a USB transfer request specified by a USB Request Block
460562306a36Sopenharmony_ci * (URB). mem_flags indicates the type of memory allocation to use while
460662306a36Sopenharmony_ci * processing this URB.
460762306a36Sopenharmony_ci */
460862306a36Sopenharmony_cistatic int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
460962306a36Sopenharmony_ci				 gfp_t mem_flags)
461062306a36Sopenharmony_ci{
461162306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
461262306a36Sopenharmony_ci	struct usb_host_endpoint *ep = urb->ep;
461362306a36Sopenharmony_ci	struct dwc2_hcd_urb *dwc2_urb;
461462306a36Sopenharmony_ci	int i;
461562306a36Sopenharmony_ci	int retval;
461662306a36Sopenharmony_ci	int alloc_bandwidth = 0;
461762306a36Sopenharmony_ci	u8 ep_type = 0;
461862306a36Sopenharmony_ci	u32 tflags = 0;
461962306a36Sopenharmony_ci	void *buf;
462062306a36Sopenharmony_ci	unsigned long flags;
462162306a36Sopenharmony_ci	struct dwc2_qh *qh;
462262306a36Sopenharmony_ci	bool qh_allocated = false;
462362306a36Sopenharmony_ci	struct dwc2_qtd *qtd;
462462306a36Sopenharmony_ci	struct dwc2_gregs_backup *gr;
462562306a36Sopenharmony_ci
462662306a36Sopenharmony_ci	gr = &hsotg->gr_backup;
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ci	if (dbg_urb(urb)) {
462962306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
463062306a36Sopenharmony_ci		dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
463162306a36Sopenharmony_ci	}
463262306a36Sopenharmony_ci
463362306a36Sopenharmony_ci	if (hsotg->hibernated) {
463462306a36Sopenharmony_ci		if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
463562306a36Sopenharmony_ci			retval = dwc2_exit_hibernation(hsotg, 0, 0, 1);
463662306a36Sopenharmony_ci		else
463762306a36Sopenharmony_ci			retval = dwc2_exit_hibernation(hsotg, 0, 0, 0);
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci		if (retval)
464062306a36Sopenharmony_ci			dev_err(hsotg->dev,
464162306a36Sopenharmony_ci				"exit hibernation failed.\n");
464262306a36Sopenharmony_ci	}
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_ci	if (hsotg->in_ppd) {
464562306a36Sopenharmony_ci		retval = dwc2_exit_partial_power_down(hsotg, 0, true);
464662306a36Sopenharmony_ci		if (retval)
464762306a36Sopenharmony_ci			dev_err(hsotg->dev,
464862306a36Sopenharmony_ci				"exit partial_power_down failed\n");
464962306a36Sopenharmony_ci	}
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_ci	if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
465262306a36Sopenharmony_ci	    hsotg->bus_suspended) {
465362306a36Sopenharmony_ci		if (dwc2_is_device_mode(hsotg))
465462306a36Sopenharmony_ci			dwc2_gadget_exit_clock_gating(hsotg, 0);
465562306a36Sopenharmony_ci		else
465662306a36Sopenharmony_ci			dwc2_host_exit_clock_gating(hsotg, 0);
465762306a36Sopenharmony_ci	}
465862306a36Sopenharmony_ci
465962306a36Sopenharmony_ci	if (!ep)
466062306a36Sopenharmony_ci		return -EINVAL;
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
466362306a36Sopenharmony_ci	    usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
466462306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
466562306a36Sopenharmony_ci		if (!dwc2_hcd_is_bandwidth_allocated(hsotg, ep))
466662306a36Sopenharmony_ci			alloc_bandwidth = 1;
466762306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
466862306a36Sopenharmony_ci	}
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
467162306a36Sopenharmony_ci	case PIPE_CONTROL:
467262306a36Sopenharmony_ci		ep_type = USB_ENDPOINT_XFER_CONTROL;
467362306a36Sopenharmony_ci		break;
467462306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
467562306a36Sopenharmony_ci		ep_type = USB_ENDPOINT_XFER_ISOC;
467662306a36Sopenharmony_ci		break;
467762306a36Sopenharmony_ci	case PIPE_BULK:
467862306a36Sopenharmony_ci		ep_type = USB_ENDPOINT_XFER_BULK;
467962306a36Sopenharmony_ci		break;
468062306a36Sopenharmony_ci	case PIPE_INTERRUPT:
468162306a36Sopenharmony_ci		ep_type = USB_ENDPOINT_XFER_INT;
468262306a36Sopenharmony_ci		break;
468362306a36Sopenharmony_ci	}
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci	dwc2_urb = dwc2_hcd_urb_alloc(hsotg, urb->number_of_packets,
468662306a36Sopenharmony_ci				      mem_flags);
468762306a36Sopenharmony_ci	if (!dwc2_urb)
468862306a36Sopenharmony_ci		return -ENOMEM;
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_ci	dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe),
469162306a36Sopenharmony_ci				  usb_pipeendpoint(urb->pipe), ep_type,
469262306a36Sopenharmony_ci				  usb_pipein(urb->pipe),
469362306a36Sopenharmony_ci				  usb_endpoint_maxp(&ep->desc),
469462306a36Sopenharmony_ci				  usb_endpoint_maxp_mult(&ep->desc));
469562306a36Sopenharmony_ci
469662306a36Sopenharmony_ci	buf = urb->transfer_buffer;
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_ci	if (hcd_uses_dma(hcd)) {
469962306a36Sopenharmony_ci		if (!buf && (urb->transfer_dma & 3)) {
470062306a36Sopenharmony_ci			dev_err(hsotg->dev,
470162306a36Sopenharmony_ci				"%s: unaligned transfer with no transfer_buffer",
470262306a36Sopenharmony_ci				__func__);
470362306a36Sopenharmony_ci			retval = -EINVAL;
470462306a36Sopenharmony_ci			goto fail0;
470562306a36Sopenharmony_ci		}
470662306a36Sopenharmony_ci	}
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci	if (!(urb->transfer_flags & URB_NO_INTERRUPT))
470962306a36Sopenharmony_ci		tflags |= URB_GIVEBACK_ASAP;
471062306a36Sopenharmony_ci	if (urb->transfer_flags & URB_ZERO_PACKET)
471162306a36Sopenharmony_ci		tflags |= URB_SEND_ZERO_PACKET;
471262306a36Sopenharmony_ci
471362306a36Sopenharmony_ci	dwc2_urb->priv = urb;
471462306a36Sopenharmony_ci	dwc2_urb->buf = buf;
471562306a36Sopenharmony_ci	dwc2_urb->dma = urb->transfer_dma;
471662306a36Sopenharmony_ci	dwc2_urb->length = urb->transfer_buffer_length;
471762306a36Sopenharmony_ci	dwc2_urb->setup_packet = urb->setup_packet;
471862306a36Sopenharmony_ci	dwc2_urb->setup_dma = urb->setup_dma;
471962306a36Sopenharmony_ci	dwc2_urb->flags = tflags;
472062306a36Sopenharmony_ci	dwc2_urb->interval = urb->interval;
472162306a36Sopenharmony_ci	dwc2_urb->status = -EINPROGRESS;
472262306a36Sopenharmony_ci
472362306a36Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; ++i)
472462306a36Sopenharmony_ci		dwc2_hcd_urb_set_iso_desc_params(dwc2_urb, i,
472562306a36Sopenharmony_ci						 urb->iso_frame_desc[i].offset,
472662306a36Sopenharmony_ci						 urb->iso_frame_desc[i].length);
472762306a36Sopenharmony_ci
472862306a36Sopenharmony_ci	urb->hcpriv = dwc2_urb;
472962306a36Sopenharmony_ci	qh = (struct dwc2_qh *)ep->hcpriv;
473062306a36Sopenharmony_ci	/* Create QH for the endpoint if it doesn't exist */
473162306a36Sopenharmony_ci	if (!qh) {
473262306a36Sopenharmony_ci		qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags);
473362306a36Sopenharmony_ci		if (!qh) {
473462306a36Sopenharmony_ci			retval = -ENOMEM;
473562306a36Sopenharmony_ci			goto fail0;
473662306a36Sopenharmony_ci		}
473762306a36Sopenharmony_ci		ep->hcpriv = qh;
473862306a36Sopenharmony_ci		qh_allocated = true;
473962306a36Sopenharmony_ci	}
474062306a36Sopenharmony_ci
474162306a36Sopenharmony_ci	qtd = kzalloc(sizeof(*qtd), mem_flags);
474262306a36Sopenharmony_ci	if (!qtd) {
474362306a36Sopenharmony_ci		retval = -ENOMEM;
474462306a36Sopenharmony_ci		goto fail1;
474562306a36Sopenharmony_ci	}
474662306a36Sopenharmony_ci
474762306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
474862306a36Sopenharmony_ci	retval = usb_hcd_link_urb_to_ep(hcd, urb);
474962306a36Sopenharmony_ci	if (retval)
475062306a36Sopenharmony_ci		goto fail2;
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd);
475362306a36Sopenharmony_ci	if (retval)
475462306a36Sopenharmony_ci		goto fail3;
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	if (alloc_bandwidth) {
475762306a36Sopenharmony_ci		dwc2_allocate_bus_bandwidth(hcd,
475862306a36Sopenharmony_ci				dwc2_hcd_get_ep_bandwidth(hsotg, ep),
475962306a36Sopenharmony_ci				urb);
476062306a36Sopenharmony_ci	}
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
476362306a36Sopenharmony_ci
476462306a36Sopenharmony_ci	return 0;
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_cifail3:
476762306a36Sopenharmony_ci	dwc2_urb->priv = NULL;
476862306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(hcd, urb);
476962306a36Sopenharmony_ci	if (qh_allocated && qh->channel && qh->channel->qh == qh)
477062306a36Sopenharmony_ci		qh->channel->qh = NULL;
477162306a36Sopenharmony_cifail2:
477262306a36Sopenharmony_ci	urb->hcpriv = NULL;
477362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
477462306a36Sopenharmony_ci	kfree(qtd);
477562306a36Sopenharmony_cifail1:
477662306a36Sopenharmony_ci	if (qh_allocated) {
477762306a36Sopenharmony_ci		struct dwc2_qtd *qtd2, *qtd2_tmp;
477862306a36Sopenharmony_ci
477962306a36Sopenharmony_ci		ep->hcpriv = NULL;
478062306a36Sopenharmony_ci		dwc2_hcd_qh_unlink(hsotg, qh);
478162306a36Sopenharmony_ci		/* Free each QTD in the QH's QTD list */
478262306a36Sopenharmony_ci		list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list,
478362306a36Sopenharmony_ci					 qtd_list_entry)
478462306a36Sopenharmony_ci			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh);
478562306a36Sopenharmony_ci		dwc2_hcd_qh_free(hsotg, qh);
478662306a36Sopenharmony_ci	}
478762306a36Sopenharmony_cifail0:
478862306a36Sopenharmony_ci	kfree(dwc2_urb);
478962306a36Sopenharmony_ci
479062306a36Sopenharmony_ci	return retval;
479162306a36Sopenharmony_ci}
479262306a36Sopenharmony_ci
479362306a36Sopenharmony_ci/*
479462306a36Sopenharmony_ci * Aborts/cancels a USB transfer request. Always returns 0 to indicate success.
479562306a36Sopenharmony_ci */
479662306a36Sopenharmony_cistatic int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
479762306a36Sopenharmony_ci				 int status)
479862306a36Sopenharmony_ci{
479962306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
480062306a36Sopenharmony_ci	int rc;
480162306a36Sopenharmony_ci	unsigned long flags;
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n");
480462306a36Sopenharmony_ci	dwc2_dump_urb_info(hcd, urb, "urb_dequeue");
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
480762306a36Sopenharmony_ci
480862306a36Sopenharmony_ci	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
480962306a36Sopenharmony_ci	if (rc)
481062306a36Sopenharmony_ci		goto out;
481162306a36Sopenharmony_ci
481262306a36Sopenharmony_ci	if (!urb->hcpriv) {
481362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n");
481462306a36Sopenharmony_ci		goto out;
481562306a36Sopenharmony_ci	}
481662306a36Sopenharmony_ci
481762306a36Sopenharmony_ci	rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv);
481862306a36Sopenharmony_ci
481962306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(hcd, urb);
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci	kfree(urb->hcpriv);
482262306a36Sopenharmony_ci	urb->hcpriv = NULL;
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_ci	/* Higher layer software sets URB status */
482562306a36Sopenharmony_ci	spin_unlock(&hsotg->lock);
482662306a36Sopenharmony_ci	usb_hcd_giveback_urb(hcd, urb, status);
482762306a36Sopenharmony_ci	spin_lock(&hsotg->lock);
482862306a36Sopenharmony_ci
482962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Called usb_hcd_giveback_urb()\n");
483062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "  urb->status = %d\n", urb->status);
483162306a36Sopenharmony_ciout:
483262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
483362306a36Sopenharmony_ci
483462306a36Sopenharmony_ci	return rc;
483562306a36Sopenharmony_ci}
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci/*
483862306a36Sopenharmony_ci * Frees resources in the DWC_otg controller related to a given endpoint. Also
483962306a36Sopenharmony_ci * clears state in the HCD related to the endpoint. Any URBs for the endpoint
484062306a36Sopenharmony_ci * must already be dequeued.
484162306a36Sopenharmony_ci */
484262306a36Sopenharmony_cistatic void _dwc2_hcd_endpoint_disable(struct usb_hcd *hcd,
484362306a36Sopenharmony_ci				       struct usb_host_endpoint *ep)
484462306a36Sopenharmony_ci{
484562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
484662306a36Sopenharmony_ci
484762306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
484862306a36Sopenharmony_ci		"DWC OTG HCD EP DISABLE: bEndpointAddress=0x%02x, ep->hcpriv=%p\n",
484962306a36Sopenharmony_ci		ep->desc.bEndpointAddress, ep->hcpriv);
485062306a36Sopenharmony_ci	dwc2_hcd_endpoint_disable(hsotg, ep, 250);
485162306a36Sopenharmony_ci}
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci/*
485462306a36Sopenharmony_ci * Resets endpoint specific parameter values, in current version used to reset
485562306a36Sopenharmony_ci * the data toggle (as a WA). This function can be called from usb_clear_halt
485662306a36Sopenharmony_ci * routine.
485762306a36Sopenharmony_ci */
485862306a36Sopenharmony_cistatic void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd,
485962306a36Sopenharmony_ci				     struct usb_host_endpoint *ep)
486062306a36Sopenharmony_ci{
486162306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
486262306a36Sopenharmony_ci	unsigned long flags;
486362306a36Sopenharmony_ci
486462306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
486562306a36Sopenharmony_ci		"DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n",
486662306a36Sopenharmony_ci		ep->desc.bEndpointAddress);
486762306a36Sopenharmony_ci
486862306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
486962306a36Sopenharmony_ci	dwc2_hcd_endpoint_reset(hsotg, ep);
487062306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
487162306a36Sopenharmony_ci}
487262306a36Sopenharmony_ci
487362306a36Sopenharmony_ci/*
487462306a36Sopenharmony_ci * Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
487562306a36Sopenharmony_ci * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
487662306a36Sopenharmony_ci * interrupt.
487762306a36Sopenharmony_ci *
487862306a36Sopenharmony_ci * This function is called by the USB core when an interrupt occurs
487962306a36Sopenharmony_ci */
488062306a36Sopenharmony_cistatic irqreturn_t _dwc2_hcd_irq(struct usb_hcd *hcd)
488162306a36Sopenharmony_ci{
488262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
488362306a36Sopenharmony_ci
488462306a36Sopenharmony_ci	return dwc2_handle_hcd_intr(hsotg);
488562306a36Sopenharmony_ci}
488662306a36Sopenharmony_ci
488762306a36Sopenharmony_ci/*
488862306a36Sopenharmony_ci * Creates Status Change bitmap for the root hub and root port. The bitmap is
488962306a36Sopenharmony_ci * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
489062306a36Sopenharmony_ci * is the status change indicator for the single root port. Returns 1 if either
489162306a36Sopenharmony_ci * change indicator is 1, otherwise returns 0.
489262306a36Sopenharmony_ci */
489362306a36Sopenharmony_cistatic int _dwc2_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
489462306a36Sopenharmony_ci{
489562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	buf[0] = dwc2_hcd_is_status_changed(hsotg, 1) << 1;
489862306a36Sopenharmony_ci	return buf[0] != 0;
489962306a36Sopenharmony_ci}
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci/* Handles hub class-specific requests */
490262306a36Sopenharmony_cistatic int _dwc2_hcd_hub_control(struct usb_hcd *hcd, u16 typereq, u16 wvalue,
490362306a36Sopenharmony_ci				 u16 windex, char *buf, u16 wlength)
490462306a36Sopenharmony_ci{
490562306a36Sopenharmony_ci	int retval = dwc2_hcd_hub_control(dwc2_hcd_to_hsotg(hcd), typereq,
490662306a36Sopenharmony_ci					  wvalue, windex, buf, wlength);
490762306a36Sopenharmony_ci	return retval;
490862306a36Sopenharmony_ci}
490962306a36Sopenharmony_ci
491062306a36Sopenharmony_ci/* Handles hub TT buffer clear completions */
491162306a36Sopenharmony_cistatic void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd,
491262306a36Sopenharmony_ci					       struct usb_host_endpoint *ep)
491362306a36Sopenharmony_ci{
491462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
491562306a36Sopenharmony_ci	struct dwc2_qh *qh;
491662306a36Sopenharmony_ci	unsigned long flags;
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	qh = ep->hcpriv;
491962306a36Sopenharmony_ci	if (!qh)
492062306a36Sopenharmony_ci		return;
492162306a36Sopenharmony_ci
492262306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
492362306a36Sopenharmony_ci	qh->tt_buffer_dirty = 0;
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_ci	if (hsotg->flags.b.port_connect_status)
492662306a36Sopenharmony_ci		dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_ALL);
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
492962306a36Sopenharmony_ci}
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci/*
493262306a36Sopenharmony_ci * HPRT0_SPD_HIGH_SPEED: high speed
493362306a36Sopenharmony_ci * HPRT0_SPD_FULL_SPEED: full speed
493462306a36Sopenharmony_ci */
493562306a36Sopenharmony_cistatic void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
493662306a36Sopenharmony_ci{
493762306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
493862306a36Sopenharmony_ci
493962306a36Sopenharmony_ci	if (hsotg->params.speed == speed)
494062306a36Sopenharmony_ci		return;
494162306a36Sopenharmony_ci
494262306a36Sopenharmony_ci	hsotg->params.speed = speed;
494362306a36Sopenharmony_ci	queue_work(hsotg->wq_otg, &hsotg->wf_otg);
494462306a36Sopenharmony_ci}
494562306a36Sopenharmony_ci
494662306a36Sopenharmony_cistatic void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
494762306a36Sopenharmony_ci{
494862306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
494962306a36Sopenharmony_ci
495062306a36Sopenharmony_ci	if (!hsotg->params.change_speed_quirk)
495162306a36Sopenharmony_ci		return;
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_ci	/*
495462306a36Sopenharmony_ci	 * On removal, set speed to default high-speed.
495562306a36Sopenharmony_ci	 */
495662306a36Sopenharmony_ci	if (udev->parent && udev->parent->speed > USB_SPEED_UNKNOWN &&
495762306a36Sopenharmony_ci	    udev->parent->speed < USB_SPEED_HIGH) {
495862306a36Sopenharmony_ci		dev_info(hsotg->dev, "Set speed to default high-speed\n");
495962306a36Sopenharmony_ci		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
496062306a36Sopenharmony_ci	}
496162306a36Sopenharmony_ci}
496262306a36Sopenharmony_ci
496362306a36Sopenharmony_cistatic int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
496462306a36Sopenharmony_ci{
496562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci	if (!hsotg->params.change_speed_quirk)
496862306a36Sopenharmony_ci		return 0;
496962306a36Sopenharmony_ci
497062306a36Sopenharmony_ci	if (udev->speed == USB_SPEED_HIGH) {
497162306a36Sopenharmony_ci		dev_info(hsotg->dev, "Set speed to high-speed\n");
497262306a36Sopenharmony_ci		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
497362306a36Sopenharmony_ci	} else if ((udev->speed == USB_SPEED_FULL ||
497462306a36Sopenharmony_ci				udev->speed == USB_SPEED_LOW)) {
497562306a36Sopenharmony_ci		/*
497662306a36Sopenharmony_ci		 * Change speed setting to full-speed if there's
497762306a36Sopenharmony_ci		 * a full-speed or low-speed device plugged in.
497862306a36Sopenharmony_ci		 */
497962306a36Sopenharmony_ci		dev_info(hsotg->dev, "Set speed to full-speed\n");
498062306a36Sopenharmony_ci		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
498162306a36Sopenharmony_ci	}
498262306a36Sopenharmony_ci
498362306a36Sopenharmony_ci	return 0;
498462306a36Sopenharmony_ci}
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_cistatic struct hc_driver dwc2_hc_driver = {
498762306a36Sopenharmony_ci	.description = "dwc2_hsotg",
498862306a36Sopenharmony_ci	.product_desc = "DWC OTG Controller",
498962306a36Sopenharmony_ci	.hcd_priv_size = sizeof(struct wrapper_priv_data),
499062306a36Sopenharmony_ci
499162306a36Sopenharmony_ci	.irq = _dwc2_hcd_irq,
499262306a36Sopenharmony_ci	.flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
499362306a36Sopenharmony_ci
499462306a36Sopenharmony_ci	.start = _dwc2_hcd_start,
499562306a36Sopenharmony_ci	.stop = _dwc2_hcd_stop,
499662306a36Sopenharmony_ci	.urb_enqueue = _dwc2_hcd_urb_enqueue,
499762306a36Sopenharmony_ci	.urb_dequeue = _dwc2_hcd_urb_dequeue,
499862306a36Sopenharmony_ci	.endpoint_disable = _dwc2_hcd_endpoint_disable,
499962306a36Sopenharmony_ci	.endpoint_reset = _dwc2_hcd_endpoint_reset,
500062306a36Sopenharmony_ci	.get_frame_number = _dwc2_hcd_get_frame_number,
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci	.hub_status_data = _dwc2_hcd_hub_status_data,
500362306a36Sopenharmony_ci	.hub_control = _dwc2_hcd_hub_control,
500462306a36Sopenharmony_ci	.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
500562306a36Sopenharmony_ci
500662306a36Sopenharmony_ci	.bus_suspend = _dwc2_hcd_suspend,
500762306a36Sopenharmony_ci	.bus_resume = _dwc2_hcd_resume,
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_ci	.map_urb_for_dma	= dwc2_map_urb_for_dma,
501062306a36Sopenharmony_ci	.unmap_urb_for_dma	= dwc2_unmap_urb_for_dma,
501162306a36Sopenharmony_ci};
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_ci/*
501462306a36Sopenharmony_ci * Frees secondary storage associated with the dwc2_hsotg structure contained
501562306a36Sopenharmony_ci * in the struct usb_hcd field
501662306a36Sopenharmony_ci */
501762306a36Sopenharmony_cistatic void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
501862306a36Sopenharmony_ci{
501962306a36Sopenharmony_ci	u32 ahbcfg;
502062306a36Sopenharmony_ci	u32 dctl;
502162306a36Sopenharmony_ci	int i;
502262306a36Sopenharmony_ci
502362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DWC OTG HCD FREE\n");
502462306a36Sopenharmony_ci
502562306a36Sopenharmony_ci	/* Free memory for QH/QTD lists */
502662306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
502762306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
502862306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
502962306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
503062306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
503162306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_assigned);
503262306a36Sopenharmony_ci	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_queued);
503362306a36Sopenharmony_ci
503462306a36Sopenharmony_ci	/* Free memory for the host channels */
503562306a36Sopenharmony_ci	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
503662306a36Sopenharmony_ci		struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
503762306a36Sopenharmony_ci
503862306a36Sopenharmony_ci		if (chan) {
503962306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n",
504062306a36Sopenharmony_ci				i, chan);
504162306a36Sopenharmony_ci			hsotg->hc_ptr_array[i] = NULL;
504262306a36Sopenharmony_ci			kfree(chan);
504362306a36Sopenharmony_ci		}
504462306a36Sopenharmony_ci	}
504562306a36Sopenharmony_ci
504662306a36Sopenharmony_ci	if (hsotg->params.host_dma) {
504762306a36Sopenharmony_ci		if (hsotg->status_buf) {
504862306a36Sopenharmony_ci			dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE,
504962306a36Sopenharmony_ci					  hsotg->status_buf,
505062306a36Sopenharmony_ci					  hsotg->status_buf_dma);
505162306a36Sopenharmony_ci			hsotg->status_buf = NULL;
505262306a36Sopenharmony_ci		}
505362306a36Sopenharmony_ci	} else {
505462306a36Sopenharmony_ci		kfree(hsotg->status_buf);
505562306a36Sopenharmony_ci		hsotg->status_buf = NULL;
505662306a36Sopenharmony_ci	}
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	ahbcfg = dwc2_readl(hsotg, GAHBCFG);
505962306a36Sopenharmony_ci
506062306a36Sopenharmony_ci	/* Disable all interrupts */
506162306a36Sopenharmony_ci	ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
506262306a36Sopenharmony_ci	dwc2_writel(hsotg, ahbcfg, GAHBCFG);
506362306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, GINTMSK);
506462306a36Sopenharmony_ci
506562306a36Sopenharmony_ci	if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
506662306a36Sopenharmony_ci		dctl = dwc2_readl(hsotg, DCTL);
506762306a36Sopenharmony_ci		dctl |= DCTL_SFTDISCON;
506862306a36Sopenharmony_ci		dwc2_writel(hsotg, dctl, DCTL);
506962306a36Sopenharmony_ci	}
507062306a36Sopenharmony_ci
507162306a36Sopenharmony_ci	if (hsotg->wq_otg) {
507262306a36Sopenharmony_ci		if (!cancel_work_sync(&hsotg->wf_otg))
507362306a36Sopenharmony_ci			flush_workqueue(hsotg->wq_otg);
507462306a36Sopenharmony_ci		destroy_workqueue(hsotg->wq_otg);
507562306a36Sopenharmony_ci	}
507662306a36Sopenharmony_ci
507762306a36Sopenharmony_ci	cancel_work_sync(&hsotg->phy_reset_work);
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_ci	del_timer(&hsotg->wkp_timer);
508062306a36Sopenharmony_ci}
508162306a36Sopenharmony_ci
508262306a36Sopenharmony_cistatic void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
508362306a36Sopenharmony_ci{
508462306a36Sopenharmony_ci	/* Turn off all host-specific interrupts */
508562306a36Sopenharmony_ci	dwc2_disable_host_interrupts(hsotg);
508662306a36Sopenharmony_ci
508762306a36Sopenharmony_ci	dwc2_hcd_free(hsotg);
508862306a36Sopenharmony_ci}
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_ci/*
509162306a36Sopenharmony_ci * Initializes the HCD. This function allocates memory for and initializes the
509262306a36Sopenharmony_ci * static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
509362306a36Sopenharmony_ci * USB bus with the core and calls the hc_driver->start() function. It returns
509462306a36Sopenharmony_ci * a negative error on failure.
509562306a36Sopenharmony_ci */
509662306a36Sopenharmony_ciint dwc2_hcd_init(struct dwc2_hsotg *hsotg)
509762306a36Sopenharmony_ci{
509862306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(hsotg->dev);
509962306a36Sopenharmony_ci	struct resource *res;
510062306a36Sopenharmony_ci	struct usb_hcd *hcd;
510162306a36Sopenharmony_ci	struct dwc2_host_chan *channel;
510262306a36Sopenharmony_ci	u32 hcfg;
510362306a36Sopenharmony_ci	int i, num_channels;
510462306a36Sopenharmony_ci	int retval;
510562306a36Sopenharmony_ci
510662306a36Sopenharmony_ci	if (usb_disabled())
510762306a36Sopenharmony_ci		return -ENODEV;
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
511062306a36Sopenharmony_ci
511162306a36Sopenharmony_ci	retval = -ENOMEM;
511262306a36Sopenharmony_ci
511362306a36Sopenharmony_ci	hcfg = dwc2_readl(hsotg, HCFG);
511462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
511562306a36Sopenharmony_ci
511662306a36Sopenharmony_ci#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
511762306a36Sopenharmony_ci	hsotg->frame_num_array = kcalloc(FRAME_NUM_ARRAY_SIZE,
511862306a36Sopenharmony_ci					 sizeof(*hsotg->frame_num_array),
511962306a36Sopenharmony_ci					 GFP_KERNEL);
512062306a36Sopenharmony_ci	if (!hsotg->frame_num_array)
512162306a36Sopenharmony_ci		goto error1;
512262306a36Sopenharmony_ci	hsotg->last_frame_num_array =
512362306a36Sopenharmony_ci		kcalloc(FRAME_NUM_ARRAY_SIZE,
512462306a36Sopenharmony_ci			sizeof(*hsotg->last_frame_num_array), GFP_KERNEL);
512562306a36Sopenharmony_ci	if (!hsotg->last_frame_num_array)
512662306a36Sopenharmony_ci		goto error1;
512762306a36Sopenharmony_ci#endif
512862306a36Sopenharmony_ci	hsotg->last_frame_num = HFNUM_MAX_FRNUM;
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_ci	/* Check if the bus driver or platform code has setup a dma_mask */
513162306a36Sopenharmony_ci	if (hsotg->params.host_dma &&
513262306a36Sopenharmony_ci	    !hsotg->dev->dma_mask) {
513362306a36Sopenharmony_ci		dev_warn(hsotg->dev,
513462306a36Sopenharmony_ci			 "dma_mask not set, disabling DMA\n");
513562306a36Sopenharmony_ci		hsotg->params.host_dma = false;
513662306a36Sopenharmony_ci		hsotg->params.dma_desc_enable = false;
513762306a36Sopenharmony_ci	}
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci	/* Set device flags indicating whether the HCD supports DMA */
514062306a36Sopenharmony_ci	if (hsotg->params.host_dma) {
514162306a36Sopenharmony_ci		if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
514262306a36Sopenharmony_ci			dev_warn(hsotg->dev, "can't set DMA mask\n");
514362306a36Sopenharmony_ci		if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
514462306a36Sopenharmony_ci			dev_warn(hsotg->dev, "can't set coherent DMA mask\n");
514562306a36Sopenharmony_ci	}
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_ci	if (hsotg->params.change_speed_quirk) {
514862306a36Sopenharmony_ci		dwc2_hc_driver.free_dev = dwc2_free_dev;
514962306a36Sopenharmony_ci		dwc2_hc_driver.reset_device = dwc2_reset_device;
515062306a36Sopenharmony_ci	}
515162306a36Sopenharmony_ci
515262306a36Sopenharmony_ci	if (hsotg->params.host_dma)
515362306a36Sopenharmony_ci		dwc2_hc_driver.flags |= HCD_DMA;
515462306a36Sopenharmony_ci
515562306a36Sopenharmony_ci	hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
515662306a36Sopenharmony_ci	if (!hcd)
515762306a36Sopenharmony_ci		goto error1;
515862306a36Sopenharmony_ci
515962306a36Sopenharmony_ci	hcd->has_tt = 1;
516062306a36Sopenharmony_ci
516162306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
516262306a36Sopenharmony_ci	if (!res) {
516362306a36Sopenharmony_ci		retval = -EINVAL;
516462306a36Sopenharmony_ci		goto error2;
516562306a36Sopenharmony_ci	}
516662306a36Sopenharmony_ci	hcd->rsrc_start = res->start;
516762306a36Sopenharmony_ci	hcd->rsrc_len = resource_size(res);
516862306a36Sopenharmony_ci
516962306a36Sopenharmony_ci	((struct wrapper_priv_data *)&hcd->hcd_priv)->hsotg = hsotg;
517062306a36Sopenharmony_ci	hsotg->priv = hcd;
517162306a36Sopenharmony_ci
517262306a36Sopenharmony_ci	/*
517362306a36Sopenharmony_ci	 * Disable the global interrupt until all the interrupt handlers are
517462306a36Sopenharmony_ci	 * installed
517562306a36Sopenharmony_ci	 */
517662306a36Sopenharmony_ci	dwc2_disable_global_interrupts(hsotg);
517762306a36Sopenharmony_ci
517862306a36Sopenharmony_ci	/* Initialize the DWC_otg core, and select the Phy type */
517962306a36Sopenharmony_ci	retval = dwc2_core_init(hsotg, true);
518062306a36Sopenharmony_ci	if (retval)
518162306a36Sopenharmony_ci		goto error2;
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	/* Create new workqueue and init work */
518462306a36Sopenharmony_ci	retval = -ENOMEM;
518562306a36Sopenharmony_ci	hsotg->wq_otg = alloc_ordered_workqueue("dwc2", 0);
518662306a36Sopenharmony_ci	if (!hsotg->wq_otg) {
518762306a36Sopenharmony_ci		dev_err(hsotg->dev, "Failed to create workqueue\n");
518862306a36Sopenharmony_ci		goto error2;
518962306a36Sopenharmony_ci	}
519062306a36Sopenharmony_ci	INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change);
519162306a36Sopenharmony_ci
519262306a36Sopenharmony_ci	timer_setup(&hsotg->wkp_timer, dwc2_wakeup_detected, 0);
519362306a36Sopenharmony_ci
519462306a36Sopenharmony_ci	/* Initialize the non-periodic schedule */
519562306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
519662306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
519762306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
519862306a36Sopenharmony_ci
519962306a36Sopenharmony_ci	/* Initialize the periodic schedule */
520062306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->periodic_sched_inactive);
520162306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->periodic_sched_ready);
520262306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->periodic_sched_assigned);
520362306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->periodic_sched_queued);
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->split_order);
520662306a36Sopenharmony_ci
520762306a36Sopenharmony_ci	/*
520862306a36Sopenharmony_ci	 * Create a host channel descriptor for each host channel implemented
520962306a36Sopenharmony_ci	 * in the controller. Initialize the channel descriptor array.
521062306a36Sopenharmony_ci	 */
521162306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->free_hc_list);
521262306a36Sopenharmony_ci	num_channels = hsotg->params.host_channels;
521362306a36Sopenharmony_ci	memset(&hsotg->hc_ptr_array[0], 0, sizeof(hsotg->hc_ptr_array));
521462306a36Sopenharmony_ci
521562306a36Sopenharmony_ci	for (i = 0; i < num_channels; i++) {
521662306a36Sopenharmony_ci		channel = kzalloc(sizeof(*channel), GFP_KERNEL);
521762306a36Sopenharmony_ci		if (!channel)
521862306a36Sopenharmony_ci			goto error3;
521962306a36Sopenharmony_ci		channel->hc_num = i;
522062306a36Sopenharmony_ci		INIT_LIST_HEAD(&channel->split_order_list_entry);
522162306a36Sopenharmony_ci		hsotg->hc_ptr_array[i] = channel;
522262306a36Sopenharmony_ci	}
522362306a36Sopenharmony_ci
522462306a36Sopenharmony_ci	/* Initialize work */
522562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
522662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
522762306a36Sopenharmony_ci	INIT_WORK(&hsotg->phy_reset_work, dwc2_hcd_phy_reset_func);
522862306a36Sopenharmony_ci
522962306a36Sopenharmony_ci	/*
523062306a36Sopenharmony_ci	 * Allocate space for storing data on status transactions. Normally no
523162306a36Sopenharmony_ci	 * data is sent, but this space acts as a bit bucket. This must be
523262306a36Sopenharmony_ci	 * done after usb_add_hcd since that function allocates the DMA buffer
523362306a36Sopenharmony_ci	 * pool.
523462306a36Sopenharmony_ci	 */
523562306a36Sopenharmony_ci	if (hsotg->params.host_dma)
523662306a36Sopenharmony_ci		hsotg->status_buf = dma_alloc_coherent(hsotg->dev,
523762306a36Sopenharmony_ci					DWC2_HCD_STATUS_BUF_SIZE,
523862306a36Sopenharmony_ci					&hsotg->status_buf_dma, GFP_KERNEL);
523962306a36Sopenharmony_ci	else
524062306a36Sopenharmony_ci		hsotg->status_buf = kzalloc(DWC2_HCD_STATUS_BUF_SIZE,
524162306a36Sopenharmony_ci					  GFP_KERNEL);
524262306a36Sopenharmony_ci
524362306a36Sopenharmony_ci	if (!hsotg->status_buf)
524462306a36Sopenharmony_ci		goto error3;
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_ci	/*
524762306a36Sopenharmony_ci	 * Create kmem caches to handle descriptor buffers in descriptor
524862306a36Sopenharmony_ci	 * DMA mode.
524962306a36Sopenharmony_ci	 * Alignment must be set to 512 bytes.
525062306a36Sopenharmony_ci	 */
525162306a36Sopenharmony_ci	if (hsotg->params.dma_desc_enable ||
525262306a36Sopenharmony_ci	    hsotg->params.dma_desc_fs_enable) {
525362306a36Sopenharmony_ci		hsotg->desc_gen_cache = kmem_cache_create("dwc2-gen-desc",
525462306a36Sopenharmony_ci				sizeof(struct dwc2_dma_desc) *
525562306a36Sopenharmony_ci				MAX_DMA_DESC_NUM_GENERIC, 512, SLAB_CACHE_DMA,
525662306a36Sopenharmony_ci				NULL);
525762306a36Sopenharmony_ci		if (!hsotg->desc_gen_cache) {
525862306a36Sopenharmony_ci			dev_err(hsotg->dev,
525962306a36Sopenharmony_ci				"unable to create dwc2 generic desc cache\n");
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_ci			/*
526262306a36Sopenharmony_ci			 * Disable descriptor dma mode since it will not be
526362306a36Sopenharmony_ci			 * usable.
526462306a36Sopenharmony_ci			 */
526562306a36Sopenharmony_ci			hsotg->params.dma_desc_enable = false;
526662306a36Sopenharmony_ci			hsotg->params.dma_desc_fs_enable = false;
526762306a36Sopenharmony_ci		}
526862306a36Sopenharmony_ci
526962306a36Sopenharmony_ci		hsotg->desc_hsisoc_cache = kmem_cache_create("dwc2-hsisoc-desc",
527062306a36Sopenharmony_ci				sizeof(struct dwc2_dma_desc) *
527162306a36Sopenharmony_ci				MAX_DMA_DESC_NUM_HS_ISOC, 512, 0, NULL);
527262306a36Sopenharmony_ci		if (!hsotg->desc_hsisoc_cache) {
527362306a36Sopenharmony_ci			dev_err(hsotg->dev,
527462306a36Sopenharmony_ci				"unable to create dwc2 hs isoc desc cache\n");
527562306a36Sopenharmony_ci
527662306a36Sopenharmony_ci			kmem_cache_destroy(hsotg->desc_gen_cache);
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci			/*
527962306a36Sopenharmony_ci			 * Disable descriptor dma mode since it will not be
528062306a36Sopenharmony_ci			 * usable.
528162306a36Sopenharmony_ci			 */
528262306a36Sopenharmony_ci			hsotg->params.dma_desc_enable = false;
528362306a36Sopenharmony_ci			hsotg->params.dma_desc_fs_enable = false;
528462306a36Sopenharmony_ci		}
528562306a36Sopenharmony_ci	}
528662306a36Sopenharmony_ci
528762306a36Sopenharmony_ci	if (hsotg->params.host_dma) {
528862306a36Sopenharmony_ci		/*
528962306a36Sopenharmony_ci		 * Create kmem caches to handle non-aligned buffer
529062306a36Sopenharmony_ci		 * in Buffer DMA mode.
529162306a36Sopenharmony_ci		 */
529262306a36Sopenharmony_ci		hsotg->unaligned_cache = kmem_cache_create("dwc2-unaligned-dma",
529362306a36Sopenharmony_ci						DWC2_KMEM_UNALIGNED_BUF_SIZE, 4,
529462306a36Sopenharmony_ci						SLAB_CACHE_DMA, NULL);
529562306a36Sopenharmony_ci		if (!hsotg->unaligned_cache)
529662306a36Sopenharmony_ci			dev_err(hsotg->dev,
529762306a36Sopenharmony_ci				"unable to create dwc2 unaligned cache\n");
529862306a36Sopenharmony_ci	}
529962306a36Sopenharmony_ci
530062306a36Sopenharmony_ci	hsotg->otg_port = 1;
530162306a36Sopenharmony_ci	hsotg->frame_list = NULL;
530262306a36Sopenharmony_ci	hsotg->frame_list_dma = 0;
530362306a36Sopenharmony_ci	hsotg->periodic_qh_count = 0;
530462306a36Sopenharmony_ci
530562306a36Sopenharmony_ci	/* Initiate lx_state to L3 disconnected state */
530662306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L3;
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci	hcd->self.otg_port = hsotg->otg_port;
530962306a36Sopenharmony_ci
531062306a36Sopenharmony_ci	/* Don't support SG list at this point */
531162306a36Sopenharmony_ci	hcd->self.sg_tablesize = 0;
531262306a36Sopenharmony_ci
531362306a36Sopenharmony_ci	hcd->tpl_support = of_usb_host_tpl_support(hsotg->dev->of_node);
531462306a36Sopenharmony_ci
531562306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hsotg->uphy))
531662306a36Sopenharmony_ci		otg_set_host(hsotg->uphy->otg, &hcd->self);
531762306a36Sopenharmony_ci
531862306a36Sopenharmony_ci	/*
531962306a36Sopenharmony_ci	 * Finish generic HCD initialization and start the HCD. This function
532062306a36Sopenharmony_ci	 * allocates the DMA buffer pool, registers the USB bus, requests the
532162306a36Sopenharmony_ci	 * IRQ line, and calls hcd_start method.
532262306a36Sopenharmony_ci	 */
532362306a36Sopenharmony_ci	retval = usb_add_hcd(hcd, hsotg->irq, IRQF_SHARED);
532462306a36Sopenharmony_ci	if (retval < 0)
532562306a36Sopenharmony_ci		goto error4;
532662306a36Sopenharmony_ci
532762306a36Sopenharmony_ci	device_wakeup_enable(hcd->self.controller);
532862306a36Sopenharmony_ci
532962306a36Sopenharmony_ci	dwc2_hcd_dump_state(hsotg);
533062306a36Sopenharmony_ci
533162306a36Sopenharmony_ci	dwc2_enable_global_interrupts(hsotg);
533262306a36Sopenharmony_ci
533362306a36Sopenharmony_ci	return 0;
533462306a36Sopenharmony_ci
533562306a36Sopenharmony_cierror4:
533662306a36Sopenharmony_ci	kmem_cache_destroy(hsotg->unaligned_cache);
533762306a36Sopenharmony_ci	kmem_cache_destroy(hsotg->desc_hsisoc_cache);
533862306a36Sopenharmony_ci	kmem_cache_destroy(hsotg->desc_gen_cache);
533962306a36Sopenharmony_cierror3:
534062306a36Sopenharmony_ci	dwc2_hcd_release(hsotg);
534162306a36Sopenharmony_cierror2:
534262306a36Sopenharmony_ci	usb_put_hcd(hcd);
534362306a36Sopenharmony_cierror1:
534462306a36Sopenharmony_ci
534562306a36Sopenharmony_ci#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
534662306a36Sopenharmony_ci	kfree(hsotg->last_frame_num_array);
534762306a36Sopenharmony_ci	kfree(hsotg->frame_num_array);
534862306a36Sopenharmony_ci#endif
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_ci	dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
535162306a36Sopenharmony_ci	return retval;
535262306a36Sopenharmony_ci}
535362306a36Sopenharmony_ci
535462306a36Sopenharmony_ci/*
535562306a36Sopenharmony_ci * Removes the HCD.
535662306a36Sopenharmony_ci * Frees memory and resources associated with the HCD and deregisters the bus.
535762306a36Sopenharmony_ci */
535862306a36Sopenharmony_civoid dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
535962306a36Sopenharmony_ci{
536062306a36Sopenharmony_ci	struct usb_hcd *hcd;
536162306a36Sopenharmony_ci
536262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DWC OTG HCD REMOVE\n");
536362306a36Sopenharmony_ci
536462306a36Sopenharmony_ci	hcd = dwc2_hsotg_to_hcd(hsotg);
536562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "hsotg->hcd = %p\n", hcd);
536662306a36Sopenharmony_ci
536762306a36Sopenharmony_ci	if (!hcd) {
536862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: dwc2_hsotg_to_hcd(hsotg) NULL!\n",
536962306a36Sopenharmony_ci			__func__);
537062306a36Sopenharmony_ci		return;
537162306a36Sopenharmony_ci	}
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hsotg->uphy))
537462306a36Sopenharmony_ci		otg_set_host(hsotg->uphy->otg, NULL);
537562306a36Sopenharmony_ci
537662306a36Sopenharmony_ci	usb_remove_hcd(hcd);
537762306a36Sopenharmony_ci	hsotg->priv = NULL;
537862306a36Sopenharmony_ci
537962306a36Sopenharmony_ci	kmem_cache_destroy(hsotg->unaligned_cache);
538062306a36Sopenharmony_ci	kmem_cache_destroy(hsotg->desc_hsisoc_cache);
538162306a36Sopenharmony_ci	kmem_cache_destroy(hsotg->desc_gen_cache);
538262306a36Sopenharmony_ci
538362306a36Sopenharmony_ci	dwc2_hcd_release(hsotg);
538462306a36Sopenharmony_ci	usb_put_hcd(hcd);
538562306a36Sopenharmony_ci
538662306a36Sopenharmony_ci#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
538762306a36Sopenharmony_ci	kfree(hsotg->last_frame_num_array);
538862306a36Sopenharmony_ci	kfree(hsotg->frame_num_array);
538962306a36Sopenharmony_ci#endif
539062306a36Sopenharmony_ci}
539162306a36Sopenharmony_ci
539262306a36Sopenharmony_ci/**
539362306a36Sopenharmony_ci * dwc2_backup_host_registers() - Backup controller host registers.
539462306a36Sopenharmony_ci * When suspending usb bus, registers needs to be backuped
539562306a36Sopenharmony_ci * if controller power is disabled once suspended.
539662306a36Sopenharmony_ci *
539762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
539862306a36Sopenharmony_ci */
539962306a36Sopenharmony_ciint dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
540062306a36Sopenharmony_ci{
540162306a36Sopenharmony_ci	struct dwc2_hregs_backup *hr;
540262306a36Sopenharmony_ci	int i;
540362306a36Sopenharmony_ci
540462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s\n", __func__);
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ci	/* Backup Host regs */
540762306a36Sopenharmony_ci	hr = &hsotg->hr_backup;
540862306a36Sopenharmony_ci	hr->hcfg = dwc2_readl(hsotg, HCFG);
540962306a36Sopenharmony_ci	hr->haintmsk = dwc2_readl(hsotg, HAINTMSK);
541062306a36Sopenharmony_ci	for (i = 0; i < hsotg->params.host_channels; ++i)
541162306a36Sopenharmony_ci		hr->hcintmsk[i] = dwc2_readl(hsotg, HCINTMSK(i));
541262306a36Sopenharmony_ci
541362306a36Sopenharmony_ci	hr->hprt0 = dwc2_read_hprt0(hsotg);
541462306a36Sopenharmony_ci	hr->hfir = dwc2_readl(hsotg, HFIR);
541562306a36Sopenharmony_ci	hr->hptxfsiz = dwc2_readl(hsotg, HPTXFSIZ);
541662306a36Sopenharmony_ci	hr->valid = true;
541762306a36Sopenharmony_ci
541862306a36Sopenharmony_ci	return 0;
541962306a36Sopenharmony_ci}
542062306a36Sopenharmony_ci
542162306a36Sopenharmony_ci/**
542262306a36Sopenharmony_ci * dwc2_restore_host_registers() - Restore controller host registers.
542362306a36Sopenharmony_ci * When resuming usb bus, device registers needs to be restored
542462306a36Sopenharmony_ci * if controller power were disabled.
542562306a36Sopenharmony_ci *
542662306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
542762306a36Sopenharmony_ci */
542862306a36Sopenharmony_ciint dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
542962306a36Sopenharmony_ci{
543062306a36Sopenharmony_ci	struct dwc2_hregs_backup *hr;
543162306a36Sopenharmony_ci	int i;
543262306a36Sopenharmony_ci
543362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s\n", __func__);
543462306a36Sopenharmony_ci
543562306a36Sopenharmony_ci	/* Restore host regs */
543662306a36Sopenharmony_ci	hr = &hsotg->hr_backup;
543762306a36Sopenharmony_ci	if (!hr->valid) {
543862306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: no host registers to restore\n",
543962306a36Sopenharmony_ci			__func__);
544062306a36Sopenharmony_ci		return -EINVAL;
544162306a36Sopenharmony_ci	}
544262306a36Sopenharmony_ci	hr->valid = false;
544362306a36Sopenharmony_ci
544462306a36Sopenharmony_ci	dwc2_writel(hsotg, hr->hcfg, HCFG);
544562306a36Sopenharmony_ci	dwc2_writel(hsotg, hr->haintmsk, HAINTMSK);
544662306a36Sopenharmony_ci
544762306a36Sopenharmony_ci	for (i = 0; i < hsotg->params.host_channels; ++i)
544862306a36Sopenharmony_ci		dwc2_writel(hsotg, hr->hcintmsk[i], HCINTMSK(i));
544962306a36Sopenharmony_ci
545062306a36Sopenharmony_ci	dwc2_writel(hsotg, hr->hprt0, HPRT0);
545162306a36Sopenharmony_ci	dwc2_writel(hsotg, hr->hfir, HFIR);
545262306a36Sopenharmony_ci	dwc2_writel(hsotg, hr->hptxfsiz, HPTXFSIZ);
545362306a36Sopenharmony_ci	hsotg->frame_number = 0;
545462306a36Sopenharmony_ci
545562306a36Sopenharmony_ci	return 0;
545662306a36Sopenharmony_ci}
545762306a36Sopenharmony_ci
545862306a36Sopenharmony_ci/**
545962306a36Sopenharmony_ci * dwc2_host_enter_hibernation() - Put controller in Hibernation.
546062306a36Sopenharmony_ci *
546162306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
546262306a36Sopenharmony_ci */
546362306a36Sopenharmony_ciint dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
546462306a36Sopenharmony_ci{
546562306a36Sopenharmony_ci	unsigned long flags;
546662306a36Sopenharmony_ci	int ret = 0;
546762306a36Sopenharmony_ci	u32 hprt0;
546862306a36Sopenharmony_ci	u32 pcgcctl;
546962306a36Sopenharmony_ci	u32 gusbcfg;
547062306a36Sopenharmony_ci	u32 gpwrdn;
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Preparing host for hibernation\n");
547362306a36Sopenharmony_ci	ret = dwc2_backup_global_registers(hsotg);
547462306a36Sopenharmony_ci	if (ret) {
547562306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup global registers\n",
547662306a36Sopenharmony_ci			__func__);
547762306a36Sopenharmony_ci		return ret;
547862306a36Sopenharmony_ci	}
547962306a36Sopenharmony_ci	ret = dwc2_backup_host_registers(hsotg);
548062306a36Sopenharmony_ci	if (ret) {
548162306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup host registers\n",
548262306a36Sopenharmony_ci			__func__);
548362306a36Sopenharmony_ci		return ret;
548462306a36Sopenharmony_ci	}
548562306a36Sopenharmony_ci
548662306a36Sopenharmony_ci	/* Enter USB Suspend Mode */
548762306a36Sopenharmony_ci	hprt0 = dwc2_readl(hsotg, HPRT0);
548862306a36Sopenharmony_ci	hprt0 |= HPRT0_SUSP;
548962306a36Sopenharmony_ci	hprt0 &= ~HPRT0_ENA;
549062306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
549162306a36Sopenharmony_ci
549262306a36Sopenharmony_ci	/* Wait for the HPRT0.PrtSusp register field to be set */
549362306a36Sopenharmony_ci	if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 5000))
549462306a36Sopenharmony_ci		dev_warn(hsotg->dev, "Suspend wasn't generated\n");
549562306a36Sopenharmony_ci
549662306a36Sopenharmony_ci	/*
549762306a36Sopenharmony_ci	 * We need to disable interrupts to prevent servicing of any IRQ
549862306a36Sopenharmony_ci	 * during going to hibernation
549962306a36Sopenharmony_ci	 */
550062306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
550162306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
550262306a36Sopenharmony_ci
550362306a36Sopenharmony_ci	gusbcfg = dwc2_readl(hsotg, GUSBCFG);
550462306a36Sopenharmony_ci	if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) {
550562306a36Sopenharmony_ci		/* ULPI interface */
550662306a36Sopenharmony_ci		/* Suspend the Phy Clock */
550762306a36Sopenharmony_ci		pcgcctl = dwc2_readl(hsotg, PCGCTL);
550862306a36Sopenharmony_ci		pcgcctl |= PCGCTL_STOPPCLK;
550962306a36Sopenharmony_ci		dwc2_writel(hsotg, pcgcctl, PCGCTL);
551062306a36Sopenharmony_ci		udelay(10);
551162306a36Sopenharmony_ci
551262306a36Sopenharmony_ci		gpwrdn = dwc2_readl(hsotg, GPWRDN);
551362306a36Sopenharmony_ci		gpwrdn |= GPWRDN_PMUACTV;
551462306a36Sopenharmony_ci		dwc2_writel(hsotg, gpwrdn, GPWRDN);
551562306a36Sopenharmony_ci		udelay(10);
551662306a36Sopenharmony_ci	} else {
551762306a36Sopenharmony_ci		/* UTMI+ Interface */
551862306a36Sopenharmony_ci		gpwrdn = dwc2_readl(hsotg, GPWRDN);
551962306a36Sopenharmony_ci		gpwrdn |= GPWRDN_PMUACTV;
552062306a36Sopenharmony_ci		dwc2_writel(hsotg, gpwrdn, GPWRDN);
552162306a36Sopenharmony_ci		udelay(10);
552262306a36Sopenharmony_ci
552362306a36Sopenharmony_ci		pcgcctl = dwc2_readl(hsotg, PCGCTL);
552462306a36Sopenharmony_ci		pcgcctl |= PCGCTL_STOPPCLK;
552562306a36Sopenharmony_ci		dwc2_writel(hsotg, pcgcctl, PCGCTL);
552662306a36Sopenharmony_ci		udelay(10);
552762306a36Sopenharmony_ci	}
552862306a36Sopenharmony_ci
552962306a36Sopenharmony_ci	/* Enable interrupts from wake up logic */
553062306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
553162306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PMUINTSEL;
553262306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
553362306a36Sopenharmony_ci	udelay(10);
553462306a36Sopenharmony_ci
553562306a36Sopenharmony_ci	/* Unmask host mode interrupts in GPWRDN */
553662306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
553762306a36Sopenharmony_ci	gpwrdn |= GPWRDN_DISCONN_DET_MSK;
553862306a36Sopenharmony_ci	gpwrdn |= GPWRDN_LNSTSCHG_MSK;
553962306a36Sopenharmony_ci	gpwrdn |= GPWRDN_STS_CHGINT_MSK;
554062306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
554162306a36Sopenharmony_ci	udelay(10);
554262306a36Sopenharmony_ci
554362306a36Sopenharmony_ci	/* Enable Power Down Clamp */
554462306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
554562306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PWRDNCLMP;
554662306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
554762306a36Sopenharmony_ci	udelay(10);
554862306a36Sopenharmony_ci
554962306a36Sopenharmony_ci	/* Switch off VDD */
555062306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
555162306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PWRDNSWTCH;
555262306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
555362306a36Sopenharmony_ci
555462306a36Sopenharmony_ci	hsotg->hibernated = 1;
555562306a36Sopenharmony_ci	hsotg->bus_suspended = 1;
555662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Host hibernation completed\n");
555762306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
555862306a36Sopenharmony_ci	return ret;
555962306a36Sopenharmony_ci}
556062306a36Sopenharmony_ci
556162306a36Sopenharmony_ci/*
556262306a36Sopenharmony_ci * dwc2_host_exit_hibernation()
556362306a36Sopenharmony_ci *
556462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
556562306a36Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by Device or Host.
556662306a36Sopenharmony_ci * @param reset: indicates whether resume is initiated by Reset.
556762306a36Sopenharmony_ci *
556862306a36Sopenharmony_ci * Return: non-zero if failed to enter to hibernation.
556962306a36Sopenharmony_ci *
557062306a36Sopenharmony_ci * This function is for exiting from Host mode hibernation by
557162306a36Sopenharmony_ci * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
557262306a36Sopenharmony_ci */
557362306a36Sopenharmony_ciint dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
557462306a36Sopenharmony_ci			       int reset)
557562306a36Sopenharmony_ci{
557662306a36Sopenharmony_ci	u32 gpwrdn;
557762306a36Sopenharmony_ci	u32 hprt0;
557862306a36Sopenharmony_ci	int ret = 0;
557962306a36Sopenharmony_ci	struct dwc2_gregs_backup *gr;
558062306a36Sopenharmony_ci	struct dwc2_hregs_backup *hr;
558162306a36Sopenharmony_ci
558262306a36Sopenharmony_ci	gr = &hsotg->gr_backup;
558362306a36Sopenharmony_ci	hr = &hsotg->hr_backup;
558462306a36Sopenharmony_ci
558562306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
558662306a36Sopenharmony_ci		"%s: called with rem_wakeup = %d reset = %d\n",
558762306a36Sopenharmony_ci		__func__, rem_wakeup, reset);
558862306a36Sopenharmony_ci
558962306a36Sopenharmony_ci	dwc2_hib_restore_common(hsotg, rem_wakeup, 1);
559062306a36Sopenharmony_ci	hsotg->hibernated = 0;
559162306a36Sopenharmony_ci
559262306a36Sopenharmony_ci	/*
559362306a36Sopenharmony_ci	 * This step is not described in functional spec but if not wait for
559462306a36Sopenharmony_ci	 * this delay, mismatch interrupts occurred because just after restore
559562306a36Sopenharmony_ci	 * core is in Device mode(gintsts.curmode == 0)
559662306a36Sopenharmony_ci	 */
559762306a36Sopenharmony_ci	mdelay(100);
559862306a36Sopenharmony_ci
559962306a36Sopenharmony_ci	/* Clear all pending interupts */
560062306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
560162306a36Sopenharmony_ci
560262306a36Sopenharmony_ci	/* De-assert Restore */
560362306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
560462306a36Sopenharmony_ci	gpwrdn &= ~GPWRDN_RESTORE;
560562306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
560662306a36Sopenharmony_ci	udelay(10);
560762306a36Sopenharmony_ci
560862306a36Sopenharmony_ci	/* Restore GUSBCFG, HCFG */
560962306a36Sopenharmony_ci	dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
561062306a36Sopenharmony_ci	dwc2_writel(hsotg, hr->hcfg, HCFG);
561162306a36Sopenharmony_ci
561262306a36Sopenharmony_ci	/* De-assert Wakeup Logic */
561362306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
561462306a36Sopenharmony_ci	gpwrdn &= ~GPWRDN_PMUACTV;
561562306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
561662306a36Sopenharmony_ci	udelay(10);
561762306a36Sopenharmony_ci
561862306a36Sopenharmony_ci	hprt0 = hr->hprt0;
561962306a36Sopenharmony_ci	hprt0 |= HPRT0_PWR;
562062306a36Sopenharmony_ci	hprt0 &= ~HPRT0_ENA;
562162306a36Sopenharmony_ci	hprt0 &= ~HPRT0_SUSP;
562262306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
562362306a36Sopenharmony_ci
562462306a36Sopenharmony_ci	hprt0 = hr->hprt0;
562562306a36Sopenharmony_ci	hprt0 |= HPRT0_PWR;
562662306a36Sopenharmony_ci	hprt0 &= ~HPRT0_ENA;
562762306a36Sopenharmony_ci	hprt0 &= ~HPRT0_SUSP;
562862306a36Sopenharmony_ci
562962306a36Sopenharmony_ci	if (reset) {
563062306a36Sopenharmony_ci		hprt0 |= HPRT0_RST;
563162306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
563262306a36Sopenharmony_ci
563362306a36Sopenharmony_ci		/* Wait for Resume time and then program HPRT again */
563462306a36Sopenharmony_ci		mdelay(60);
563562306a36Sopenharmony_ci		hprt0 &= ~HPRT0_RST;
563662306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
563762306a36Sopenharmony_ci	} else {
563862306a36Sopenharmony_ci		hprt0 |= HPRT0_RES;
563962306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
564062306a36Sopenharmony_ci
564162306a36Sopenharmony_ci		/* Wait for Resume time and then program HPRT again */
564262306a36Sopenharmony_ci		mdelay(100);
564362306a36Sopenharmony_ci		hprt0 &= ~HPRT0_RES;
564462306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
564562306a36Sopenharmony_ci	}
564662306a36Sopenharmony_ci	/* Clear all interrupt status */
564762306a36Sopenharmony_ci	hprt0 = dwc2_readl(hsotg, HPRT0);
564862306a36Sopenharmony_ci	hprt0 |= HPRT0_CONNDET;
564962306a36Sopenharmony_ci	hprt0 |= HPRT0_ENACHG;
565062306a36Sopenharmony_ci	hprt0 &= ~HPRT0_ENA;
565162306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
565262306a36Sopenharmony_ci
565362306a36Sopenharmony_ci	hprt0 = dwc2_readl(hsotg, HPRT0);
565462306a36Sopenharmony_ci
565562306a36Sopenharmony_ci	/* Clear all pending interupts */
565662306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
565762306a36Sopenharmony_ci
565862306a36Sopenharmony_ci	/* Restore global registers */
565962306a36Sopenharmony_ci	ret = dwc2_restore_global_registers(hsotg);
566062306a36Sopenharmony_ci	if (ret) {
566162306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to restore registers\n",
566262306a36Sopenharmony_ci			__func__);
566362306a36Sopenharmony_ci		return ret;
566462306a36Sopenharmony_ci	}
566562306a36Sopenharmony_ci
566662306a36Sopenharmony_ci	/* Restore host registers */
566762306a36Sopenharmony_ci	ret = dwc2_restore_host_registers(hsotg);
566862306a36Sopenharmony_ci	if (ret) {
566962306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to restore host registers\n",
567062306a36Sopenharmony_ci			__func__);
567162306a36Sopenharmony_ci		return ret;
567262306a36Sopenharmony_ci	}
567362306a36Sopenharmony_ci
567462306a36Sopenharmony_ci	if (rem_wakeup) {
567562306a36Sopenharmony_ci		dwc2_hcd_rem_wakeup(hsotg);
567662306a36Sopenharmony_ci		/*
567762306a36Sopenharmony_ci		 * Change "port_connect_status_change" flag to re-enumerate,
567862306a36Sopenharmony_ci		 * because after exit from hibernation port connection status
567962306a36Sopenharmony_ci		 * is not detected.
568062306a36Sopenharmony_ci		 */
568162306a36Sopenharmony_ci		hsotg->flags.b.port_connect_status_change = 1;
568262306a36Sopenharmony_ci	}
568362306a36Sopenharmony_ci
568462306a36Sopenharmony_ci	hsotg->hibernated = 0;
568562306a36Sopenharmony_ci	hsotg->bus_suspended = 0;
568662306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
568762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
568862306a36Sopenharmony_ci	return ret;
568962306a36Sopenharmony_ci}
569062306a36Sopenharmony_ci
569162306a36Sopenharmony_cibool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
569262306a36Sopenharmony_ci{
569362306a36Sopenharmony_ci	struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
569462306a36Sopenharmony_ci
569562306a36Sopenharmony_ci	/* If the controller isn't allowed to wakeup then we can power off. */
569662306a36Sopenharmony_ci	if (!device_may_wakeup(dwc2->dev))
569762306a36Sopenharmony_ci		return true;
569862306a36Sopenharmony_ci
569962306a36Sopenharmony_ci	/*
570062306a36Sopenharmony_ci	 * We don't want to power off the PHY if something under the
570162306a36Sopenharmony_ci	 * root hub has wakeup enabled.
570262306a36Sopenharmony_ci	 */
570362306a36Sopenharmony_ci	if (usb_wakeup_enabled_descendants(root_hub))
570462306a36Sopenharmony_ci		return false;
570562306a36Sopenharmony_ci
570662306a36Sopenharmony_ci	/* No reason to keep the PHY powered, so allow poweroff */
570762306a36Sopenharmony_ci	return true;
570862306a36Sopenharmony_ci}
570962306a36Sopenharmony_ci
571062306a36Sopenharmony_ci/**
571162306a36Sopenharmony_ci * dwc2_host_enter_partial_power_down() - Put controller in partial
571262306a36Sopenharmony_ci * power down.
571362306a36Sopenharmony_ci *
571462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
571562306a36Sopenharmony_ci *
571662306a36Sopenharmony_ci * Return: non-zero if failed to enter host partial power down.
571762306a36Sopenharmony_ci *
571862306a36Sopenharmony_ci * This function is for entering Host mode partial power down.
571962306a36Sopenharmony_ci */
572062306a36Sopenharmony_ciint dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
572162306a36Sopenharmony_ci{
572262306a36Sopenharmony_ci	u32 pcgcctl;
572362306a36Sopenharmony_ci	u32 hprt0;
572462306a36Sopenharmony_ci	int ret = 0;
572562306a36Sopenharmony_ci
572662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Entering host partial power down started.\n");
572762306a36Sopenharmony_ci
572862306a36Sopenharmony_ci	/* Put this port in suspend mode. */
572962306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
573062306a36Sopenharmony_ci	hprt0 |= HPRT0_SUSP;
573162306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
573262306a36Sopenharmony_ci	udelay(5);
573362306a36Sopenharmony_ci
573462306a36Sopenharmony_ci	/* Wait for the HPRT0.PrtSusp register field to be set */
573562306a36Sopenharmony_ci	if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000))
573662306a36Sopenharmony_ci		dev_warn(hsotg->dev, "Suspend wasn't generated\n");
573762306a36Sopenharmony_ci
573862306a36Sopenharmony_ci	/* Backup all registers */
573962306a36Sopenharmony_ci	ret = dwc2_backup_global_registers(hsotg);
574062306a36Sopenharmony_ci	if (ret) {
574162306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup global registers\n",
574262306a36Sopenharmony_ci			__func__);
574362306a36Sopenharmony_ci		return ret;
574462306a36Sopenharmony_ci	}
574562306a36Sopenharmony_ci
574662306a36Sopenharmony_ci	ret = dwc2_backup_host_registers(hsotg);
574762306a36Sopenharmony_ci	if (ret) {
574862306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup host registers\n",
574962306a36Sopenharmony_ci			__func__);
575062306a36Sopenharmony_ci		return ret;
575162306a36Sopenharmony_ci	}
575262306a36Sopenharmony_ci
575362306a36Sopenharmony_ci	/*
575462306a36Sopenharmony_ci	 * Clear any pending interrupts since dwc2 will not be able to
575562306a36Sopenharmony_ci	 * clear them after entering partial_power_down.
575662306a36Sopenharmony_ci	 */
575762306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
575862306a36Sopenharmony_ci
575962306a36Sopenharmony_ci	/* Put the controller in low power state */
576062306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
576162306a36Sopenharmony_ci
576262306a36Sopenharmony_ci	pcgcctl |= PCGCTL_PWRCLMP;
576362306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
576462306a36Sopenharmony_ci	udelay(5);
576562306a36Sopenharmony_ci
576662306a36Sopenharmony_ci	pcgcctl |= PCGCTL_RSTPDWNMODULE;
576762306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
576862306a36Sopenharmony_ci	udelay(5);
576962306a36Sopenharmony_ci
577062306a36Sopenharmony_ci	pcgcctl |= PCGCTL_STOPPCLK;
577162306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
577262306a36Sopenharmony_ci
577362306a36Sopenharmony_ci	/* Set in_ppd flag to 1 as here core enters suspend. */
577462306a36Sopenharmony_ci	hsotg->in_ppd = 1;
577562306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
577662306a36Sopenharmony_ci	hsotg->bus_suspended = true;
577762306a36Sopenharmony_ci
577862306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Entering host partial power down completed.\n");
577962306a36Sopenharmony_ci
578062306a36Sopenharmony_ci	return ret;
578162306a36Sopenharmony_ci}
578262306a36Sopenharmony_ci
578362306a36Sopenharmony_ci/*
578462306a36Sopenharmony_ci * dwc2_host_exit_partial_power_down() - Exit controller from host partial
578562306a36Sopenharmony_ci * power down.
578662306a36Sopenharmony_ci *
578762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
578862306a36Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by Reset.
578962306a36Sopenharmony_ci * @restore: indicates whether need to restore the registers or not.
579062306a36Sopenharmony_ci *
579162306a36Sopenharmony_ci * Return: non-zero if failed to exit host partial power down.
579262306a36Sopenharmony_ci *
579362306a36Sopenharmony_ci * This function is for exiting from Host mode partial power down.
579462306a36Sopenharmony_ci */
579562306a36Sopenharmony_ciint dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
579662306a36Sopenharmony_ci				      int rem_wakeup, bool restore)
579762306a36Sopenharmony_ci{
579862306a36Sopenharmony_ci	u32 pcgcctl;
579962306a36Sopenharmony_ci	int ret = 0;
580062306a36Sopenharmony_ci	u32 hprt0;
580162306a36Sopenharmony_ci
580262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Exiting host partial power down started.\n");
580362306a36Sopenharmony_ci
580462306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
580562306a36Sopenharmony_ci	pcgcctl &= ~PCGCTL_STOPPCLK;
580662306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
580762306a36Sopenharmony_ci	udelay(5);
580862306a36Sopenharmony_ci
580962306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
581062306a36Sopenharmony_ci	pcgcctl &= ~PCGCTL_PWRCLMP;
581162306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
581262306a36Sopenharmony_ci	udelay(5);
581362306a36Sopenharmony_ci
581462306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
581562306a36Sopenharmony_ci	pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
581662306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
581762306a36Sopenharmony_ci
581862306a36Sopenharmony_ci	udelay(100);
581962306a36Sopenharmony_ci	if (restore) {
582062306a36Sopenharmony_ci		ret = dwc2_restore_global_registers(hsotg);
582162306a36Sopenharmony_ci		if (ret) {
582262306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s: failed to restore registers\n",
582362306a36Sopenharmony_ci				__func__);
582462306a36Sopenharmony_ci			return ret;
582562306a36Sopenharmony_ci		}
582662306a36Sopenharmony_ci
582762306a36Sopenharmony_ci		ret = dwc2_restore_host_registers(hsotg);
582862306a36Sopenharmony_ci		if (ret) {
582962306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s: failed to restore host registers\n",
583062306a36Sopenharmony_ci				__func__);
583162306a36Sopenharmony_ci			return ret;
583262306a36Sopenharmony_ci		}
583362306a36Sopenharmony_ci	}
583462306a36Sopenharmony_ci
583562306a36Sopenharmony_ci	/* Drive resume signaling and exit suspend mode on the port. */
583662306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
583762306a36Sopenharmony_ci	hprt0 |= HPRT0_RES;
583862306a36Sopenharmony_ci	hprt0 &= ~HPRT0_SUSP;
583962306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
584062306a36Sopenharmony_ci	udelay(5);
584162306a36Sopenharmony_ci
584262306a36Sopenharmony_ci	if (!rem_wakeup) {
584362306a36Sopenharmony_ci		/* Stop driveing resume signaling on the port. */
584462306a36Sopenharmony_ci		hprt0 = dwc2_read_hprt0(hsotg);
584562306a36Sopenharmony_ci		hprt0 &= ~HPRT0_RES;
584662306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
584762306a36Sopenharmony_ci
584862306a36Sopenharmony_ci		hsotg->bus_suspended = false;
584962306a36Sopenharmony_ci	} else {
585062306a36Sopenharmony_ci		/* Turn on the port power bit. */
585162306a36Sopenharmony_ci		hprt0 = dwc2_read_hprt0(hsotg);
585262306a36Sopenharmony_ci		hprt0 |= HPRT0_PWR;
585362306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
585462306a36Sopenharmony_ci
585562306a36Sopenharmony_ci		/* Connect hcd. */
585662306a36Sopenharmony_ci		dwc2_hcd_connect(hsotg);
585762306a36Sopenharmony_ci
585862306a36Sopenharmony_ci		mod_timer(&hsotg->wkp_timer,
585962306a36Sopenharmony_ci			  jiffies + msecs_to_jiffies(71));
586062306a36Sopenharmony_ci	}
586162306a36Sopenharmony_ci
586262306a36Sopenharmony_ci	/* Set lx_state to and in_ppd to 0 as here core exits from suspend. */
586362306a36Sopenharmony_ci	hsotg->in_ppd = 0;
586462306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
586562306a36Sopenharmony_ci
586662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Exiting host partial power down completed.\n");
586762306a36Sopenharmony_ci	return ret;
586862306a36Sopenharmony_ci}
586962306a36Sopenharmony_ci
587062306a36Sopenharmony_ci/**
587162306a36Sopenharmony_ci * dwc2_host_enter_clock_gating() - Put controller in clock gating.
587262306a36Sopenharmony_ci *
587362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
587462306a36Sopenharmony_ci *
587562306a36Sopenharmony_ci * This function is for entering Host mode clock gating.
587662306a36Sopenharmony_ci */
587762306a36Sopenharmony_civoid dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg)
587862306a36Sopenharmony_ci{
587962306a36Sopenharmony_ci	u32 hprt0;
588062306a36Sopenharmony_ci	u32 pcgctl;
588162306a36Sopenharmony_ci
588262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Entering host clock gating.\n");
588362306a36Sopenharmony_ci
588462306a36Sopenharmony_ci	/* Put this port in suspend mode. */
588562306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
588662306a36Sopenharmony_ci	hprt0 |= HPRT0_SUSP;
588762306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
588862306a36Sopenharmony_ci
588962306a36Sopenharmony_ci	/* Set the Phy Clock bit as suspend is received. */
589062306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
589162306a36Sopenharmony_ci	pcgctl |= PCGCTL_STOPPCLK;
589262306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
589362306a36Sopenharmony_ci	udelay(5);
589462306a36Sopenharmony_ci
589562306a36Sopenharmony_ci	/* Set the Gate hclk as suspend is received. */
589662306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
589762306a36Sopenharmony_ci	pcgctl |= PCGCTL_GATEHCLK;
589862306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
589962306a36Sopenharmony_ci	udelay(5);
590062306a36Sopenharmony_ci
590162306a36Sopenharmony_ci	hsotg->bus_suspended = true;
590262306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
590362306a36Sopenharmony_ci}
590462306a36Sopenharmony_ci
590562306a36Sopenharmony_ci/**
590662306a36Sopenharmony_ci * dwc2_host_exit_clock_gating() - Exit controller from clock gating.
590762306a36Sopenharmony_ci *
590862306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
590962306a36Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by remote wakeup
591062306a36Sopenharmony_ci *
591162306a36Sopenharmony_ci * This function is for exiting Host mode clock gating.
591262306a36Sopenharmony_ci */
591362306a36Sopenharmony_civoid dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup)
591462306a36Sopenharmony_ci{
591562306a36Sopenharmony_ci	u32 hprt0;
591662306a36Sopenharmony_ci	u32 pcgctl;
591762306a36Sopenharmony_ci
591862306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Exiting host clock gating.\n");
591962306a36Sopenharmony_ci
592062306a36Sopenharmony_ci	/* Clear the Gate hclk. */
592162306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
592262306a36Sopenharmony_ci	pcgctl &= ~PCGCTL_GATEHCLK;
592362306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
592462306a36Sopenharmony_ci	udelay(5);
592562306a36Sopenharmony_ci
592662306a36Sopenharmony_ci	/* Phy Clock bit. */
592762306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
592862306a36Sopenharmony_ci	pcgctl &= ~PCGCTL_STOPPCLK;
592962306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
593062306a36Sopenharmony_ci	udelay(5);
593162306a36Sopenharmony_ci
593262306a36Sopenharmony_ci	/* Drive resume signaling and exit suspend mode on the port. */
593362306a36Sopenharmony_ci	hprt0 = dwc2_read_hprt0(hsotg);
593462306a36Sopenharmony_ci	hprt0 |= HPRT0_RES;
593562306a36Sopenharmony_ci	hprt0 &= ~HPRT0_SUSP;
593662306a36Sopenharmony_ci	dwc2_writel(hsotg, hprt0, HPRT0);
593762306a36Sopenharmony_ci	udelay(5);
593862306a36Sopenharmony_ci
593962306a36Sopenharmony_ci	if (!rem_wakeup) {
594062306a36Sopenharmony_ci		/* In case of port resume need to wait for 40 ms */
594162306a36Sopenharmony_ci		msleep(USB_RESUME_TIMEOUT);
594262306a36Sopenharmony_ci
594362306a36Sopenharmony_ci		/* Stop driveing resume signaling on the port. */
594462306a36Sopenharmony_ci		hprt0 = dwc2_read_hprt0(hsotg);
594562306a36Sopenharmony_ci		hprt0 &= ~HPRT0_RES;
594662306a36Sopenharmony_ci		dwc2_writel(hsotg, hprt0, HPRT0);
594762306a36Sopenharmony_ci
594862306a36Sopenharmony_ci		hsotg->bus_suspended = false;
594962306a36Sopenharmony_ci		hsotg->lx_state = DWC2_L0;
595062306a36Sopenharmony_ci	} else {
595162306a36Sopenharmony_ci		mod_timer(&hsotg->wkp_timer,
595262306a36Sopenharmony_ci			  jiffies + msecs_to_jiffies(71));
595362306a36Sopenharmony_ci	}
595462306a36Sopenharmony_ci}
5955