162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2011 Samsung Electronics Co., Ltd.
462306a36Sopenharmony_ci *		http://www.samsung.com
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2008 Openmoko, Inc.
762306a36Sopenharmony_ci * Copyright 2008 Simtec Electronics
862306a36Sopenharmony_ci *      Ben Dooks <ben@simtec.co.uk>
962306a36Sopenharmony_ci *      http://armlinux.simtec.co.uk/
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * S3C USB2.0 High-speed / OtG driver
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/spinlock.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2062306a36Sopenharmony_ci#include <linux/mutex.h>
2162306a36Sopenharmony_ci#include <linux/seq_file.h>
2262306a36Sopenharmony_ci#include <linux/delay.h>
2362306a36Sopenharmony_ci#include <linux/io.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/usb/ch9.h>
2762306a36Sopenharmony_ci#include <linux/usb/gadget.h>
2862306a36Sopenharmony_ci#include <linux/usb/phy.h>
2962306a36Sopenharmony_ci#include <linux/usb/composite.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "core.h"
3362306a36Sopenharmony_ci#include "hw.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* conversion functions */
3662306a36Sopenharmony_cistatic inline struct dwc2_hsotg_req *our_req(struct usb_request *req)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	return container_of(req, struct dwc2_hsotg_req, req);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	return container_of(ep, struct dwc2_hsotg_ep, ep);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return container_of(gadget, struct dwc2_hsotg, gadget);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic inline void dwc2_set_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	dwc2_writel(hsotg, dwc2_readl(hsotg, offset) | val, offset);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic inline void dwc2_clear_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	dwc2_writel(hsotg, dwc2_readl(hsotg, offset) & ~val, offset);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg,
6262306a36Sopenharmony_ci						u32 ep_index, u32 dir_in)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	if (dir_in)
6562306a36Sopenharmony_ci		return hsotg->eps_in[ep_index];
6662306a36Sopenharmony_ci	else
6762306a36Sopenharmony_ci		return hsotg->eps_out[ep_index];
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* forward declaration of functions */
7162306a36Sopenharmony_cistatic void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * using_dma - return the DMA status of the driver.
7562306a36Sopenharmony_ci * @hsotg: The driver state.
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * Return true if we're using DMA.
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * Currently, we have the DMA support code worked into everywhere
8062306a36Sopenharmony_ci * that needs it, but the AMBA DMA implementation in the hardware can
8162306a36Sopenharmony_ci * only DMA from 32bit aligned addresses. This means that gadgets such
8262306a36Sopenharmony_ci * as the CDC Ethernet cannot work as they often pass packets which are
8362306a36Sopenharmony_ci * not 32bit aligned.
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * Unfortunately the choice to use DMA or not is global to the controller
8662306a36Sopenharmony_ci * and seems to be only settable when the controller is being put through
8762306a36Sopenharmony_ci * a core reset. This means we either need to fix the gadgets to take
8862306a36Sopenharmony_ci * account of DMA alignment, or add bounce buffers (yuerk).
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * g_using_dma is set depending on dts flag.
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_cistatic inline bool using_dma(struct dwc2_hsotg *hsotg)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return hsotg->params.g_dma;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci * using_desc_dma - return the descriptor DMA status of the driver.
9962306a36Sopenharmony_ci * @hsotg: The driver state.
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * Return true if we're using descriptor DMA.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistatic inline bool using_desc_dma(struct dwc2_hsotg *hsotg)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	return hsotg->params.g_dma_desc;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/**
10962306a36Sopenharmony_ci * dwc2_gadget_incr_frame_num - Increments the targeted frame number.
11062306a36Sopenharmony_ci * @hs_ep: The endpoint
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT.
11362306a36Sopenharmony_ci * If an overrun occurs it will wrap the value and set the frame_overrun flag.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_cistatic inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
11862306a36Sopenharmony_ci	u16 limit = DSTS_SOFFN_LIMIT;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (hsotg->gadget.speed != USB_SPEED_HIGH)
12162306a36Sopenharmony_ci		limit >>= 3;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	hs_ep->target_frame += hs_ep->interval;
12462306a36Sopenharmony_ci	if (hs_ep->target_frame > limit) {
12562306a36Sopenharmony_ci		hs_ep->frame_overrun = true;
12662306a36Sopenharmony_ci		hs_ep->target_frame &= limit;
12762306a36Sopenharmony_ci	} else {
12862306a36Sopenharmony_ci		hs_ep->frame_overrun = false;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/**
13362306a36Sopenharmony_ci * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number
13462306a36Sopenharmony_ci *                                    by one.
13562306a36Sopenharmony_ci * @hs_ep: The endpoint.
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * This function used in service interval based scheduling flow to calculate
13862306a36Sopenharmony_ci * descriptor frame number filed value. For service interval mode frame
13962306a36Sopenharmony_ci * number in descriptor should point to last (u)frame in the interval.
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
14562306a36Sopenharmony_ci	u16 limit = DSTS_SOFFN_LIMIT;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (hsotg->gadget.speed != USB_SPEED_HIGH)
14862306a36Sopenharmony_ci		limit >>= 3;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (hs_ep->target_frame)
15162306a36Sopenharmony_ci		hs_ep->target_frame -= 1;
15262306a36Sopenharmony_ci	else
15362306a36Sopenharmony_ci		hs_ep->target_frame = limit;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/**
15762306a36Sopenharmony_ci * dwc2_hsotg_en_gsint - enable one or more of the general interrupt
15862306a36Sopenharmony_ci * @hsotg: The device state
15962306a36Sopenharmony_ci * @ints: A bitmask of the interrupts to enable
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cistatic void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	u32 gsintmsk = dwc2_readl(hsotg, GINTMSK);
16462306a36Sopenharmony_ci	u32 new_gsintmsk;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	new_gsintmsk = gsintmsk | ints;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (new_gsintmsk != gsintmsk) {
16962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
17062306a36Sopenharmony_ci		dwc2_writel(hsotg, new_gsintmsk, GINTMSK);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt
17662306a36Sopenharmony_ci * @hsotg: The device state
17762306a36Sopenharmony_ci * @ints: A bitmask of the interrupts to enable
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_cistatic void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	u32 gsintmsk = dwc2_readl(hsotg, GINTMSK);
18262306a36Sopenharmony_ci	u32 new_gsintmsk;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	new_gsintmsk = gsintmsk & ~ints;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (new_gsintmsk != gsintmsk)
18762306a36Sopenharmony_ci		dwc2_writel(hsotg, new_gsintmsk, GINTMSK);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/**
19162306a36Sopenharmony_ci * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq
19262306a36Sopenharmony_ci * @hsotg: The device state
19362306a36Sopenharmony_ci * @ep: The endpoint index
19462306a36Sopenharmony_ci * @dir_in: True if direction is in.
19562306a36Sopenharmony_ci * @en: The enable value, true to enable
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * Set or clear the mask for an individual endpoint's interrupt
19862306a36Sopenharmony_ci * request.
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_cistatic void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg,
20162306a36Sopenharmony_ci				  unsigned int ep, unsigned int dir_in,
20262306a36Sopenharmony_ci				 unsigned int en)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	unsigned long flags;
20562306a36Sopenharmony_ci	u32 bit = 1 << ep;
20662306a36Sopenharmony_ci	u32 daint;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (!dir_in)
20962306a36Sopenharmony_ci		bit <<= 16;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	local_irq_save(flags);
21262306a36Sopenharmony_ci	daint = dwc2_readl(hsotg, DAINTMSK);
21362306a36Sopenharmony_ci	if (en)
21462306a36Sopenharmony_ci		daint |= bit;
21562306a36Sopenharmony_ci	else
21662306a36Sopenharmony_ci		daint &= ~bit;
21762306a36Sopenharmony_ci	dwc2_writel(hsotg, daint, DAINTMSK);
21862306a36Sopenharmony_ci	local_irq_restore(flags);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/**
22262306a36Sopenharmony_ci * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_ciint dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	if (hsotg->hw_params.en_multiple_tx_fifo)
22962306a36Sopenharmony_ci		/* In dedicated FIFO mode we need count of IN EPs */
23062306a36Sopenharmony_ci		return hsotg->hw_params.num_dev_in_eps;
23162306a36Sopenharmony_ci	else
23262306a36Sopenharmony_ci		/* In shared FIFO mode we need count of Periodic IN EPs */
23362306a36Sopenharmony_ci		return hsotg->hw_params.num_dev_perio_in_ep;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/**
23762306a36Sopenharmony_ci * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for
23862306a36Sopenharmony_ci * device mode TX FIFOs
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
24162306a36Sopenharmony_ci */
24262306a36Sopenharmony_ciint dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	int addr;
24562306a36Sopenharmony_ci	int tx_addr_max;
24662306a36Sopenharmony_ci	u32 np_tx_fifo_size;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size,
24962306a36Sopenharmony_ci				hsotg->params.g_np_tx_fifo_size);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Get Endpoint Info Control block size in DWORDs. */
25262306a36Sopenharmony_ci	tx_addr_max = hsotg->hw_params.total_fifo_size;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size;
25562306a36Sopenharmony_ci	if (tx_addr_max <= addr)
25662306a36Sopenharmony_ci		return 0;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return tx_addr_max - addr;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/**
26262306a36Sopenharmony_ci * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_cistatic void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	u32 gintsts2;
27062306a36Sopenharmony_ci	u32 gintmsk2;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	gintsts2 = dwc2_readl(hsotg, GINTSTS2);
27362306a36Sopenharmony_ci	gintmsk2 = dwc2_readl(hsotg, GINTMSK2);
27462306a36Sopenharmony_ci	gintsts2 &= gintmsk2;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) {
27762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__);
27862306a36Sopenharmony_ci		dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT);
27962306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG);
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/**
28462306a36Sopenharmony_ci * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode
28562306a36Sopenharmony_ci * TX FIFOs
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_ciint dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	int tx_fifo_count;
29262306a36Sopenharmony_ci	int tx_fifo_depth;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (!tx_fifo_count)
29962306a36Sopenharmony_ci		return tx_fifo_depth;
30062306a36Sopenharmony_ci	else
30162306a36Sopenharmony_ci		return tx_fifo_depth / tx_fifo_count;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/**
30562306a36Sopenharmony_ci * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs
30662306a36Sopenharmony_ci * @hsotg: The device instance.
30762306a36Sopenharmony_ci */
30862306a36Sopenharmony_cistatic void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	unsigned int ep;
31162306a36Sopenharmony_ci	unsigned int addr;
31262306a36Sopenharmony_ci	int timeout;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	u32 val;
31562306a36Sopenharmony_ci	u32 *txfsz = hsotg->params.g_tx_fifo_size;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Reset fifo map if not correctly cleared during previous session */
31862306a36Sopenharmony_ci	WARN_ON(hsotg->fifo_map);
31962306a36Sopenharmony_ci	hsotg->fifo_map = 0;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* set RX/NPTX FIFO sizes */
32262306a36Sopenharmony_ci	dwc2_writel(hsotg, hsotg->params.g_rx_fifo_size, GRXFSIZ);
32362306a36Sopenharmony_ci	dwc2_writel(hsotg, (hsotg->params.g_rx_fifo_size <<
32462306a36Sopenharmony_ci		    FIFOSIZE_STARTADDR_SHIFT) |
32562306a36Sopenharmony_ci		    (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT),
32662306a36Sopenharmony_ci		    GNPTXFSIZ);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/*
32962306a36Sopenharmony_ci	 * arange all the rest of the TX FIFOs, as some versions of this
33062306a36Sopenharmony_ci	 * block have overlapping default addresses. This also ensures
33162306a36Sopenharmony_ci	 * that if the settings have been changed, then they are set to
33262306a36Sopenharmony_ci	 * known values.
33362306a36Sopenharmony_ci	 */
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* start at the end of the GNPTXFSIZ, rounded up */
33662306a36Sopenharmony_ci	addr = hsotg->params.g_rx_fifo_size + hsotg->params.g_np_tx_fifo_size;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/*
33962306a36Sopenharmony_ci	 * Configure fifos sizes from provided configuration and assign
34062306a36Sopenharmony_ci	 * them to endpoints dynamically according to maxpacket size value of
34162306a36Sopenharmony_ci	 * given endpoint.
34262306a36Sopenharmony_ci	 */
34362306a36Sopenharmony_ci	for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
34462306a36Sopenharmony_ci		if (!txfsz[ep])
34562306a36Sopenharmony_ci			continue;
34662306a36Sopenharmony_ci		val = addr;
34762306a36Sopenharmony_ci		val |= txfsz[ep] << FIFOSIZE_DEPTH_SHIFT;
34862306a36Sopenharmony_ci		WARN_ONCE(addr + txfsz[ep] > hsotg->fifo_mem,
34962306a36Sopenharmony_ci			  "insufficient fifo memory");
35062306a36Sopenharmony_ci		addr += txfsz[ep];
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		dwc2_writel(hsotg, val, DPTXFSIZN(ep));
35362306a36Sopenharmony_ci		val = dwc2_readl(hsotg, DPTXFSIZN(ep));
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	dwc2_writel(hsotg, hsotg->hw_params.total_fifo_size |
35762306a36Sopenharmony_ci		    addr << GDFIFOCFG_EPINFOBASE_SHIFT,
35862306a36Sopenharmony_ci		    GDFIFOCFG);
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * according to p428 of the design guide, we need to ensure that
36162306a36Sopenharmony_ci	 * all fifos are flushed before continuing
36262306a36Sopenharmony_ci	 */
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	dwc2_writel(hsotg, GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH |
36562306a36Sopenharmony_ci	       GRSTCTL_RXFFLSH, GRSTCTL);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* wait until the fifos are both flushed */
36862306a36Sopenharmony_ci	timeout = 100;
36962306a36Sopenharmony_ci	while (1) {
37062306a36Sopenharmony_ci		val = dwc2_readl(hsotg, GRSTCTL);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0)
37362306a36Sopenharmony_ci			break;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		if (--timeout == 0) {
37662306a36Sopenharmony_ci			dev_err(hsotg->dev,
37762306a36Sopenharmony_ci				"%s: timeout flushing fifos (GRSTCTL=%08x)\n",
37862306a36Sopenharmony_ci				__func__, val);
37962306a36Sopenharmony_ci			break;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		udelay(1);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci/**
38962306a36Sopenharmony_ci * dwc2_hsotg_ep_alloc_request - allocate USB rerequest structure
39062306a36Sopenharmony_ci * @ep: USB endpoint to allocate request for.
39162306a36Sopenharmony_ci * @flags: Allocation flags
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * Allocate a new USB request structure appropriate for the specified endpoint
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_cistatic struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep,
39662306a36Sopenharmony_ci						       gfp_t flags)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct dwc2_hsotg_req *req;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), flags);
40162306a36Sopenharmony_ci	if (!req)
40262306a36Sopenharmony_ci		return NULL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	INIT_LIST_HEAD(&req->queue);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return &req->req;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci/**
41062306a36Sopenharmony_ci * is_ep_periodic - return true if the endpoint is in periodic mode.
41162306a36Sopenharmony_ci * @hs_ep: The endpoint to query.
41262306a36Sopenharmony_ci *
41362306a36Sopenharmony_ci * Returns true if the endpoint is in periodic mode, meaning it is being
41462306a36Sopenharmony_ci * used for an Interrupt or ISO transfer.
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	return hs_ep->periodic;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/**
42262306a36Sopenharmony_ci * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request
42362306a36Sopenharmony_ci * @hsotg: The device state.
42462306a36Sopenharmony_ci * @hs_ep: The endpoint for the request
42562306a36Sopenharmony_ci * @hs_req: The request being processed.
42662306a36Sopenharmony_ci *
42762306a36Sopenharmony_ci * This is the reverse of dwc2_hsotg_map_dma(), called for the completion
42862306a36Sopenharmony_ci * of a request to ensure the buffer is ready for access by the caller.
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_cistatic void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg,
43162306a36Sopenharmony_ci				 struct dwc2_hsotg_ep *hs_ep,
43262306a36Sopenharmony_ci				struct dwc2_hsotg_req *hs_req)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct usb_request *req = &hs_req->req;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->map_dir);
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/*
44062306a36Sopenharmony_ci * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains
44162306a36Sopenharmony_ci * for Control endpoint
44262306a36Sopenharmony_ci * @hsotg: The device state.
44362306a36Sopenharmony_ci *
44462306a36Sopenharmony_ci * This function will allocate 4 descriptor chains for EP 0: 2 for
44562306a36Sopenharmony_ci * Setup stage, per one for IN and OUT data/status transactions.
44662306a36Sopenharmony_ci */
44762306a36Sopenharmony_cistatic int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	hsotg->setup_desc[0] =
45062306a36Sopenharmony_ci		dmam_alloc_coherent(hsotg->dev,
45162306a36Sopenharmony_ci				    sizeof(struct dwc2_dma_desc),
45262306a36Sopenharmony_ci				    &hsotg->setup_desc_dma[0],
45362306a36Sopenharmony_ci				    GFP_KERNEL);
45462306a36Sopenharmony_ci	if (!hsotg->setup_desc[0])
45562306a36Sopenharmony_ci		goto fail;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	hsotg->setup_desc[1] =
45862306a36Sopenharmony_ci		dmam_alloc_coherent(hsotg->dev,
45962306a36Sopenharmony_ci				    sizeof(struct dwc2_dma_desc),
46062306a36Sopenharmony_ci				    &hsotg->setup_desc_dma[1],
46162306a36Sopenharmony_ci				    GFP_KERNEL);
46262306a36Sopenharmony_ci	if (!hsotg->setup_desc[1])
46362306a36Sopenharmony_ci		goto fail;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	hsotg->ctrl_in_desc =
46662306a36Sopenharmony_ci		dmam_alloc_coherent(hsotg->dev,
46762306a36Sopenharmony_ci				    sizeof(struct dwc2_dma_desc),
46862306a36Sopenharmony_ci				    &hsotg->ctrl_in_desc_dma,
46962306a36Sopenharmony_ci				    GFP_KERNEL);
47062306a36Sopenharmony_ci	if (!hsotg->ctrl_in_desc)
47162306a36Sopenharmony_ci		goto fail;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	hsotg->ctrl_out_desc =
47462306a36Sopenharmony_ci		dmam_alloc_coherent(hsotg->dev,
47562306a36Sopenharmony_ci				    sizeof(struct dwc2_dma_desc),
47662306a36Sopenharmony_ci				    &hsotg->ctrl_out_desc_dma,
47762306a36Sopenharmony_ci				    GFP_KERNEL);
47862306a36Sopenharmony_ci	if (!hsotg->ctrl_out_desc)
47962306a36Sopenharmony_ci		goto fail;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	return 0;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cifail:
48462306a36Sopenharmony_ci	return -ENOMEM;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/**
48862306a36Sopenharmony_ci * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO
48962306a36Sopenharmony_ci * @hsotg: The controller state.
49062306a36Sopenharmony_ci * @hs_ep: The endpoint we're going to write for.
49162306a36Sopenharmony_ci * @hs_req: The request to write data for.
49262306a36Sopenharmony_ci *
49362306a36Sopenharmony_ci * This is called when the TxFIFO has some space in it to hold a new
49462306a36Sopenharmony_ci * transmission and we have something to give it. The actual setup of
49562306a36Sopenharmony_ci * the data size is done elsewhere, so all we have to do is to actually
49662306a36Sopenharmony_ci * write the data.
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * The return value is zero if there is more space (or nothing was done)
49962306a36Sopenharmony_ci * otherwise -ENOSPC is returned if the FIFO space was used up.
50062306a36Sopenharmony_ci *
50162306a36Sopenharmony_ci * This routine is only needed for PIO
50262306a36Sopenharmony_ci */
50362306a36Sopenharmony_cistatic int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
50462306a36Sopenharmony_ci				 struct dwc2_hsotg_ep *hs_ep,
50562306a36Sopenharmony_ci				struct dwc2_hsotg_req *hs_req)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	bool periodic = is_ep_periodic(hs_ep);
50862306a36Sopenharmony_ci	u32 gnptxsts = dwc2_readl(hsotg, GNPTXSTS);
50962306a36Sopenharmony_ci	int buf_pos = hs_req->req.actual;
51062306a36Sopenharmony_ci	int to_write = hs_ep->size_loaded;
51162306a36Sopenharmony_ci	void *data;
51262306a36Sopenharmony_ci	int can_write;
51362306a36Sopenharmony_ci	int pkt_round;
51462306a36Sopenharmony_ci	int max_transfer;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	to_write -= (buf_pos - hs_ep->last_load);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* if there's nothing to write, get out early */
51962306a36Sopenharmony_ci	if (to_write == 0)
52062306a36Sopenharmony_ci		return 0;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (periodic && !hsotg->dedicated_fifos) {
52362306a36Sopenharmony_ci		u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index));
52462306a36Sopenharmony_ci		int size_left;
52562306a36Sopenharmony_ci		int size_done;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		/*
52862306a36Sopenharmony_ci		 * work out how much data was loaded so we can calculate
52962306a36Sopenharmony_ci		 * how much data is left in the fifo.
53062306a36Sopenharmony_ci		 */
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		/*
53562306a36Sopenharmony_ci		 * if shared fifo, we cannot write anything until the
53662306a36Sopenharmony_ci		 * previous data has been completely sent.
53762306a36Sopenharmony_ci		 */
53862306a36Sopenharmony_ci		if (hs_ep->fifo_load != 0) {
53962306a36Sopenharmony_ci			dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP);
54062306a36Sopenharmony_ci			return -ENOSPC;
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n",
54462306a36Sopenharmony_ci			__func__, size_left,
54562306a36Sopenharmony_ci			hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/* how much of the data has moved */
54862306a36Sopenharmony_ci		size_done = hs_ep->size_loaded - size_left;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		/* how much data is left in the fifo */
55162306a36Sopenharmony_ci		can_write = hs_ep->fifo_load - size_done;
55262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: => can_write1=%d\n",
55362306a36Sopenharmony_ci			__func__, can_write);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		can_write = hs_ep->fifo_size - can_write;
55662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: => can_write2=%d\n",
55762306a36Sopenharmony_ci			__func__, can_write);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		if (can_write <= 0) {
56062306a36Sopenharmony_ci			dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP);
56162306a36Sopenharmony_ci			return -ENOSPC;
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci	} else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
56462306a36Sopenharmony_ci		can_write = dwc2_readl(hsotg,
56562306a36Sopenharmony_ci				       DTXFSTS(hs_ep->fifo_index));
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		can_write &= 0xffff;
56862306a36Sopenharmony_ci		can_write *= 4;
56962306a36Sopenharmony_ci	} else {
57062306a36Sopenharmony_ci		if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) {
57162306a36Sopenharmony_ci			dev_dbg(hsotg->dev,
57262306a36Sopenharmony_ci				"%s: no queue slots available (0x%08x)\n",
57362306a36Sopenharmony_ci				__func__, gnptxsts);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci			dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP);
57662306a36Sopenharmony_ci			return -ENOSPC;
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts);
58062306a36Sopenharmony_ci		can_write *= 4;	/* fifo size is in 32bit quantities. */
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	max_transfer = hs_ep->ep.maxpacket * hs_ep->mc;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n",
58662306a36Sopenharmony_ci		__func__, gnptxsts, can_write, to_write, max_transfer);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/*
58962306a36Sopenharmony_ci	 * limit to 512 bytes of data, it seems at least on the non-periodic
59062306a36Sopenharmony_ci	 * FIFO, requests of >512 cause the endpoint to get stuck with a
59162306a36Sopenharmony_ci	 * fragment of the end of the transfer in it.
59262306a36Sopenharmony_ci	 */
59362306a36Sopenharmony_ci	if (can_write > 512 && !periodic)
59462306a36Sopenharmony_ci		can_write = 512;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/*
59762306a36Sopenharmony_ci	 * limit the write to one max-packet size worth of data, but allow
59862306a36Sopenharmony_ci	 * the transfer to return that it did not run out of fifo space
59962306a36Sopenharmony_ci	 * doing it.
60062306a36Sopenharmony_ci	 */
60162306a36Sopenharmony_ci	if (to_write > max_transfer) {
60262306a36Sopenharmony_ci		to_write = max_transfer;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci		/* it's needed only when we do not use dedicated fifos */
60562306a36Sopenharmony_ci		if (!hsotg->dedicated_fifos)
60662306a36Sopenharmony_ci			dwc2_hsotg_en_gsint(hsotg,
60762306a36Sopenharmony_ci					    periodic ? GINTSTS_PTXFEMP :
60862306a36Sopenharmony_ci					   GINTSTS_NPTXFEMP);
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/* see if we can write data */
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (to_write > can_write) {
61462306a36Sopenharmony_ci		to_write = can_write;
61562306a36Sopenharmony_ci		pkt_round = to_write % max_transfer;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		/*
61862306a36Sopenharmony_ci		 * Round the write down to an
61962306a36Sopenharmony_ci		 * exact number of packets.
62062306a36Sopenharmony_ci		 *
62162306a36Sopenharmony_ci		 * Note, we do not currently check to see if we can ever
62262306a36Sopenharmony_ci		 * write a full packet or not to the FIFO.
62362306a36Sopenharmony_ci		 */
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		if (pkt_round)
62662306a36Sopenharmony_ci			to_write -= pkt_round;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci		/*
62962306a36Sopenharmony_ci		 * enable correct FIFO interrupt to alert us when there
63062306a36Sopenharmony_ci		 * is more room left.
63162306a36Sopenharmony_ci		 */
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		/* it's needed only when we do not use dedicated fifos */
63462306a36Sopenharmony_ci		if (!hsotg->dedicated_fifos)
63562306a36Sopenharmony_ci			dwc2_hsotg_en_gsint(hsotg,
63662306a36Sopenharmony_ci					    periodic ? GINTSTS_PTXFEMP :
63762306a36Sopenharmony_ci					   GINTSTS_NPTXFEMP);
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n",
64162306a36Sopenharmony_ci		to_write, hs_req->req.length, can_write, buf_pos);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (to_write <= 0)
64462306a36Sopenharmony_ci		return -ENOSPC;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	hs_req->req.actual = buf_pos + to_write;
64762306a36Sopenharmony_ci	hs_ep->total_data += to_write;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (periodic)
65062306a36Sopenharmony_ci		hs_ep->fifo_load += to_write;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	to_write = DIV_ROUND_UP(to_write, 4);
65362306a36Sopenharmony_ci	data = hs_req->req.buf + buf_pos;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	dwc2_writel_rep(hsotg, EPFIFO(hs_ep->index), data, to_write);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	return (to_write >= can_write) ? -ENOSPC : 0;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci/**
66162306a36Sopenharmony_ci * get_ep_limit - get the maximum data legnth for this endpoint
66262306a36Sopenharmony_ci * @hs_ep: The endpoint
66362306a36Sopenharmony_ci *
66462306a36Sopenharmony_ci * Return the maximum data that can be queued in one go on a given endpoint
66562306a36Sopenharmony_ci * so that transfers that are too long can be split.
66662306a36Sopenharmony_ci */
66762306a36Sopenharmony_cistatic unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	int index = hs_ep->index;
67062306a36Sopenharmony_ci	unsigned int maxsize;
67162306a36Sopenharmony_ci	unsigned int maxpkt;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (index != 0) {
67462306a36Sopenharmony_ci		maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1;
67562306a36Sopenharmony_ci		maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1;
67662306a36Sopenharmony_ci	} else {
67762306a36Sopenharmony_ci		maxsize = 64 + 64;
67862306a36Sopenharmony_ci		if (hs_ep->dir_in)
67962306a36Sopenharmony_ci			maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1;
68062306a36Sopenharmony_ci		else
68162306a36Sopenharmony_ci			maxpkt = 2;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* we made the constant loading easier above by using +1 */
68562306a36Sopenharmony_ci	maxpkt--;
68662306a36Sopenharmony_ci	maxsize--;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/*
68962306a36Sopenharmony_ci	 * constrain by packet count if maxpkts*pktsize is greater
69062306a36Sopenharmony_ci	 * than the length register size.
69162306a36Sopenharmony_ci	 */
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if ((maxpkt * hs_ep->ep.maxpacket) < maxsize)
69462306a36Sopenharmony_ci		maxsize = maxpkt * hs_ep->ep.maxpacket;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	return maxsize;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci/**
70062306a36Sopenharmony_ci * dwc2_hsotg_read_frameno - read current frame number
70162306a36Sopenharmony_ci * @hsotg: The device instance
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * Return the current frame number
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_cistatic u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	u32 dsts;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	dsts = dwc2_readl(hsotg, DSTS);
71062306a36Sopenharmony_ci	dsts &= DSTS_SOFFN_MASK;
71162306a36Sopenharmony_ci	dsts >>= DSTS_SOFFN_SHIFT;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	return dsts;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci/**
71762306a36Sopenharmony_ci * dwc2_gadget_get_chain_limit - get the maximum data payload value of the
71862306a36Sopenharmony_ci * DMA descriptor chain prepared for specific endpoint
71962306a36Sopenharmony_ci * @hs_ep: The endpoint
72062306a36Sopenharmony_ci *
72162306a36Sopenharmony_ci * Return the maximum data that can be queued in one go on a given endpoint
72262306a36Sopenharmony_ci * depending on its descriptor chain capacity so that transfers that
72362306a36Sopenharmony_ci * are too long can be split.
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_cistatic unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc;
72862306a36Sopenharmony_ci	int is_isoc = hs_ep->isochronous;
72962306a36Sopenharmony_ci	unsigned int maxsize;
73062306a36Sopenharmony_ci	u32 mps = hs_ep->ep.maxpacket;
73162306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (is_isoc)
73462306a36Sopenharmony_ci		maxsize = (hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT :
73562306a36Sopenharmony_ci					   DEV_DMA_ISOC_RX_NBYTES_LIMIT) *
73662306a36Sopenharmony_ci					   MAX_DMA_DESC_NUM_HS_ISOC;
73762306a36Sopenharmony_ci	else
73862306a36Sopenharmony_ci		maxsize = DEV_DMA_NBYTES_LIMIT * MAX_DMA_DESC_NUM_GENERIC;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* Interrupt OUT EP with mps not multiple of 4 */
74162306a36Sopenharmony_ci	if (hs_ep->index)
74262306a36Sopenharmony_ci		if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4))
74362306a36Sopenharmony_ci			maxsize = mps * MAX_DMA_DESC_NUM_GENERIC;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return maxsize;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/*
74962306a36Sopenharmony_ci * dwc2_gadget_get_desc_params - get DMA descriptor parameters.
75062306a36Sopenharmony_ci * @hs_ep: The endpoint
75162306a36Sopenharmony_ci * @mask: RX/TX bytes mask to be defined
75262306a36Sopenharmony_ci *
75362306a36Sopenharmony_ci * Returns maximum data payload for one descriptor after analyzing endpoint
75462306a36Sopenharmony_ci * characteristics.
75562306a36Sopenharmony_ci * DMA descriptor transfer bytes limit depends on EP type:
75662306a36Sopenharmony_ci * Control out - MPS,
75762306a36Sopenharmony_ci * Isochronous - descriptor rx/tx bytes bitfield limit,
75862306a36Sopenharmony_ci * Control In/Bulk/Interrupt - multiple of mps. This will allow to not
75962306a36Sopenharmony_ci * have concatenations from various descriptors within one packet.
76062306a36Sopenharmony_ci * Interrupt OUT - if mps not multiple of 4 then a single packet corresponds
76162306a36Sopenharmony_ci * to a single descriptor.
76262306a36Sopenharmony_ci *
76362306a36Sopenharmony_ci * Selects corresponding mask for RX/TX bytes as well.
76462306a36Sopenharmony_ci */
76562306a36Sopenharmony_cistatic u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc;
76862306a36Sopenharmony_ci	u32 mps = hs_ep->ep.maxpacket;
76962306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
77062306a36Sopenharmony_ci	u32 desc_size = 0;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (!hs_ep->index && !dir_in) {
77362306a36Sopenharmony_ci		desc_size = mps;
77462306a36Sopenharmony_ci		*mask = DEV_DMA_NBYTES_MASK;
77562306a36Sopenharmony_ci	} else if (hs_ep->isochronous) {
77662306a36Sopenharmony_ci		if (dir_in) {
77762306a36Sopenharmony_ci			desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT;
77862306a36Sopenharmony_ci			*mask = DEV_DMA_ISOC_TX_NBYTES_MASK;
77962306a36Sopenharmony_ci		} else {
78062306a36Sopenharmony_ci			desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT;
78162306a36Sopenharmony_ci			*mask = DEV_DMA_ISOC_RX_NBYTES_MASK;
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	} else {
78462306a36Sopenharmony_ci		desc_size = DEV_DMA_NBYTES_LIMIT;
78562306a36Sopenharmony_ci		*mask = DEV_DMA_NBYTES_MASK;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		/* Round down desc_size to be mps multiple */
78862306a36Sopenharmony_ci		desc_size -= desc_size % mps;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/* Interrupt OUT EP with mps not multiple of 4 */
79262306a36Sopenharmony_ci	if (hs_ep->index)
79362306a36Sopenharmony_ci		if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) {
79462306a36Sopenharmony_ci			desc_size = mps;
79562306a36Sopenharmony_ci			*mask = DEV_DMA_NBYTES_MASK;
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	return desc_size;
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep,
80262306a36Sopenharmony_ci						 struct dwc2_dma_desc **desc,
80362306a36Sopenharmony_ci						 dma_addr_t dma_buff,
80462306a36Sopenharmony_ci						 unsigned int len,
80562306a36Sopenharmony_ci						 bool true_last)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
80862306a36Sopenharmony_ci	u32 mps = hs_ep->ep.maxpacket;
80962306a36Sopenharmony_ci	u32 maxsize = 0;
81062306a36Sopenharmony_ci	u32 offset = 0;
81162306a36Sopenharmony_ci	u32 mask = 0;
81262306a36Sopenharmony_ci	int i;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	hs_ep->desc_count = (len / maxsize) +
81762306a36Sopenharmony_ci				((len % maxsize) ? 1 : 0);
81862306a36Sopenharmony_ci	if (len == 0)
81962306a36Sopenharmony_ci		hs_ep->desc_count = 1;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	for (i = 0; i < hs_ep->desc_count; ++i) {
82262306a36Sopenharmony_ci		(*desc)->status = 0;
82362306a36Sopenharmony_ci		(*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY
82462306a36Sopenharmony_ci				 << DEV_DMA_BUFF_STS_SHIFT);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		if (len > maxsize) {
82762306a36Sopenharmony_ci			if (!hs_ep->index && !dir_in)
82862306a36Sopenharmony_ci				(*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci			(*desc)->status |=
83162306a36Sopenharmony_ci				maxsize << DEV_DMA_NBYTES_SHIFT & mask;
83262306a36Sopenharmony_ci			(*desc)->buf = dma_buff + offset;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci			len -= maxsize;
83562306a36Sopenharmony_ci			offset += maxsize;
83662306a36Sopenharmony_ci		} else {
83762306a36Sopenharmony_ci			if (true_last)
83862306a36Sopenharmony_ci				(*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci			if (dir_in)
84162306a36Sopenharmony_ci				(*desc)->status |= (len % mps) ? DEV_DMA_SHORT :
84262306a36Sopenharmony_ci					((hs_ep->send_zlp && true_last) ?
84362306a36Sopenharmony_ci					DEV_DMA_SHORT : 0);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci			(*desc)->status |=
84662306a36Sopenharmony_ci				len << DEV_DMA_NBYTES_SHIFT & mask;
84762306a36Sopenharmony_ci			(*desc)->buf = dma_buff + offset;
84862306a36Sopenharmony_ci		}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		(*desc)->status &= ~DEV_DMA_BUFF_STS_MASK;
85162306a36Sopenharmony_ci		(*desc)->status |= (DEV_DMA_BUFF_STS_HREADY
85262306a36Sopenharmony_ci				 << DEV_DMA_BUFF_STS_SHIFT);
85362306a36Sopenharmony_ci		(*desc)++;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci/*
85862306a36Sopenharmony_ci * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain.
85962306a36Sopenharmony_ci * @hs_ep: The endpoint
86062306a36Sopenharmony_ci * @ureq: Request to transfer
86162306a36Sopenharmony_ci * @offset: offset in bytes
86262306a36Sopenharmony_ci * @len: Length of the transfer
86362306a36Sopenharmony_ci *
86462306a36Sopenharmony_ci * This function will iterate over descriptor chain and fill its entries
86562306a36Sopenharmony_ci * with corresponding information based on transfer data.
86662306a36Sopenharmony_ci */
86762306a36Sopenharmony_cistatic void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
86862306a36Sopenharmony_ci						 dma_addr_t dma_buff,
86962306a36Sopenharmony_ci						 unsigned int len)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct usb_request *ureq = NULL;
87262306a36Sopenharmony_ci	struct dwc2_dma_desc *desc = hs_ep->desc_list;
87362306a36Sopenharmony_ci	struct scatterlist *sg;
87462306a36Sopenharmony_ci	int i;
87562306a36Sopenharmony_ci	u8 desc_count = 0;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (hs_ep->req)
87862306a36Sopenharmony_ci		ureq = &hs_ep->req->req;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* non-DMA sg buffer */
88162306a36Sopenharmony_ci	if (!ureq || !ureq->num_sgs) {
88262306a36Sopenharmony_ci		dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc,
88362306a36Sopenharmony_ci			dma_buff, len, true);
88462306a36Sopenharmony_ci		return;
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* DMA sg buffer */
88862306a36Sopenharmony_ci	for_each_sg(ureq->sg, sg, ureq->num_sgs, i) {
88962306a36Sopenharmony_ci		dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc,
89062306a36Sopenharmony_ci			sg_dma_address(sg) + sg->offset, sg_dma_len(sg),
89162306a36Sopenharmony_ci			sg_is_last(sg));
89262306a36Sopenharmony_ci		desc_count += hs_ep->desc_count;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	hs_ep->desc_count = desc_count;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci/*
89962306a36Sopenharmony_ci * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain.
90062306a36Sopenharmony_ci * @hs_ep: The isochronous endpoint.
90162306a36Sopenharmony_ci * @dma_buff: usb requests dma buffer.
90262306a36Sopenharmony_ci * @len: usb request transfer length.
90362306a36Sopenharmony_ci *
90462306a36Sopenharmony_ci * Fills next free descriptor with the data of the arrived usb request,
90562306a36Sopenharmony_ci * frame info, sets Last and IOC bits increments next_desc. If filled
90662306a36Sopenharmony_ci * descriptor is not the first one, removes L bit from the previous descriptor
90762306a36Sopenharmony_ci * status.
90862306a36Sopenharmony_ci */
90962306a36Sopenharmony_cistatic int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep,
91062306a36Sopenharmony_ci				      dma_addr_t dma_buff, unsigned int len)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	struct dwc2_dma_desc *desc;
91362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
91462306a36Sopenharmony_ci	u32 index;
91562306a36Sopenharmony_ci	u32 mask = 0;
91662306a36Sopenharmony_ci	u8 pid = 0;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	dwc2_gadget_get_desc_params(hs_ep, &mask);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	index = hs_ep->next_desc;
92162306a36Sopenharmony_ci	desc = &hs_ep->desc_list[index];
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	/* Check if descriptor chain full */
92462306a36Sopenharmony_ci	if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) ==
92562306a36Sopenharmony_ci	    DEV_DMA_BUFF_STS_HREADY) {
92662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__);
92762306a36Sopenharmony_ci		return 1;
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/* Clear L bit of previous desc if more than one entries in the chain */
93162306a36Sopenharmony_ci	if (hs_ep->next_desc)
93262306a36Sopenharmony_ci		hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n",
93562306a36Sopenharmony_ci		__func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	desc->status = 0;
93862306a36Sopenharmony_ci	desc->status |= (DEV_DMA_BUFF_STS_HBUSY	<< DEV_DMA_BUFF_STS_SHIFT);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	desc->buf = dma_buff;
94162306a36Sopenharmony_ci	desc->status |= (DEV_DMA_L | DEV_DMA_IOC |
94262306a36Sopenharmony_ci			 ((len << DEV_DMA_NBYTES_SHIFT) & mask));
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	if (hs_ep->dir_in) {
94562306a36Sopenharmony_ci		if (len)
94662306a36Sopenharmony_ci			pid = DIV_ROUND_UP(len, hs_ep->ep.maxpacket);
94762306a36Sopenharmony_ci		else
94862306a36Sopenharmony_ci			pid = 1;
94962306a36Sopenharmony_ci		desc->status |= ((pid << DEV_DMA_ISOC_PID_SHIFT) &
95062306a36Sopenharmony_ci				 DEV_DMA_ISOC_PID_MASK) |
95162306a36Sopenharmony_ci				((len % hs_ep->ep.maxpacket) ?
95262306a36Sopenharmony_ci				 DEV_DMA_SHORT : 0) |
95362306a36Sopenharmony_ci				((hs_ep->target_frame <<
95462306a36Sopenharmony_ci				  DEV_DMA_ISOC_FRNUM_SHIFT) &
95562306a36Sopenharmony_ci				 DEV_DMA_ISOC_FRNUM_MASK);
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	desc->status &= ~DEV_DMA_BUFF_STS_MASK;
95962306a36Sopenharmony_ci	desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* Increment frame number by interval for IN */
96262306a36Sopenharmony_ci	if (hs_ep->dir_in)
96362306a36Sopenharmony_ci		dwc2_gadget_incr_frame_num(hs_ep);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Update index of last configured entry in the chain */
96662306a36Sopenharmony_ci	hs_ep->next_desc++;
96762306a36Sopenharmony_ci	if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_HS_ISOC)
96862306a36Sopenharmony_ci		hs_ep->next_desc = 0;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	return 0;
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci/*
97462306a36Sopenharmony_ci * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA
97562306a36Sopenharmony_ci * @hs_ep: The isochronous endpoint.
97662306a36Sopenharmony_ci *
97762306a36Sopenharmony_ci * Prepare descriptor chain for isochronous endpoints. Afterwards
97862306a36Sopenharmony_ci * write DMA address to HW and enable the endpoint.
97962306a36Sopenharmony_ci */
98062306a36Sopenharmony_cistatic void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
98362306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req, *treq;
98462306a36Sopenharmony_ci	int index = hs_ep->index;
98562306a36Sopenharmony_ci	int ret;
98662306a36Sopenharmony_ci	int i;
98762306a36Sopenharmony_ci	u32 dma_reg;
98862306a36Sopenharmony_ci	u32 depctl;
98962306a36Sopenharmony_ci	u32 ctrl;
99062306a36Sopenharmony_ci	struct dwc2_dma_desc *desc;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (list_empty(&hs_ep->queue)) {
99362306a36Sopenharmony_ci		hs_ep->target_frame = TARGET_FRAME_INITIAL;
99462306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__);
99562306a36Sopenharmony_ci		return;
99662306a36Sopenharmony_ci	}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	/* Initialize descriptor chain by Host Busy status */
99962306a36Sopenharmony_ci	for (i = 0; i < MAX_DMA_DESC_NUM_HS_ISOC; i++) {
100062306a36Sopenharmony_ci		desc = &hs_ep->desc_list[i];
100162306a36Sopenharmony_ci		desc->status = 0;
100262306a36Sopenharmony_ci		desc->status |= (DEV_DMA_BUFF_STS_HBUSY
100362306a36Sopenharmony_ci				    << DEV_DMA_BUFF_STS_SHIFT);
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	hs_ep->next_desc = 0;
100762306a36Sopenharmony_ci	list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) {
100862306a36Sopenharmony_ci		dma_addr_t dma_addr = hs_req->req.dma;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci		if (hs_req->req.num_sgs) {
101162306a36Sopenharmony_ci			WARN_ON(hs_req->req.num_sgs > 1);
101262306a36Sopenharmony_ci			dma_addr = sg_dma_address(hs_req->req.sg);
101362306a36Sopenharmony_ci		}
101462306a36Sopenharmony_ci		ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr,
101562306a36Sopenharmony_ci						 hs_req->req.length);
101662306a36Sopenharmony_ci		if (ret)
101762306a36Sopenharmony_ci			break;
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	hs_ep->compl_desc = 0;
102162306a36Sopenharmony_ci	depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
102262306a36Sopenharmony_ci	dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/* write descriptor chain address to control register */
102562306a36Sopenharmony_ci	dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	ctrl = dwc2_readl(hsotg, depctl);
102862306a36Sopenharmony_ci	ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
102962306a36Sopenharmony_ci	dwc2_writel(hsotg, ctrl, depctl);
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep);
103362306a36Sopenharmony_cistatic void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
103462306a36Sopenharmony_ci					struct dwc2_hsotg_ep *hs_ep,
103562306a36Sopenharmony_ci				       struct dwc2_hsotg_req *hs_req,
103662306a36Sopenharmony_ci				       int result);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci/**
103962306a36Sopenharmony_ci * dwc2_hsotg_start_req - start a USB request from an endpoint's queue
104062306a36Sopenharmony_ci * @hsotg: The controller state.
104162306a36Sopenharmony_ci * @hs_ep: The endpoint to process a request for
104262306a36Sopenharmony_ci * @hs_req: The request to start.
104362306a36Sopenharmony_ci * @continuing: True if we are doing more for the current request.
104462306a36Sopenharmony_ci *
104562306a36Sopenharmony_ci * Start the given request running by setting the endpoint registers
104662306a36Sopenharmony_ci * appropriately, and writing any data to the FIFOs.
104762306a36Sopenharmony_ci */
104862306a36Sopenharmony_cistatic void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
104962306a36Sopenharmony_ci				 struct dwc2_hsotg_ep *hs_ep,
105062306a36Sopenharmony_ci				struct dwc2_hsotg_req *hs_req,
105162306a36Sopenharmony_ci				bool continuing)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct usb_request *ureq = &hs_req->req;
105462306a36Sopenharmony_ci	int index = hs_ep->index;
105562306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
105662306a36Sopenharmony_ci	u32 epctrl_reg;
105762306a36Sopenharmony_ci	u32 epsize_reg;
105862306a36Sopenharmony_ci	u32 epsize;
105962306a36Sopenharmony_ci	u32 ctrl;
106062306a36Sopenharmony_ci	unsigned int length;
106162306a36Sopenharmony_ci	unsigned int packets;
106262306a36Sopenharmony_ci	unsigned int maxreq;
106362306a36Sopenharmony_ci	unsigned int dma_reg;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (index != 0) {
106662306a36Sopenharmony_ci		if (hs_ep->req && !continuing) {
106762306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s: active request\n", __func__);
106862306a36Sopenharmony_ci			WARN_ON(1);
106962306a36Sopenharmony_ci			return;
107062306a36Sopenharmony_ci		} else if (hs_ep->req != hs_req && continuing) {
107162306a36Sopenharmony_ci			dev_err(hsotg->dev,
107262306a36Sopenharmony_ci				"%s: continue different req\n", __func__);
107362306a36Sopenharmony_ci			WARN_ON(1);
107462306a36Sopenharmony_ci			return;
107562306a36Sopenharmony_ci		}
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
107962306a36Sopenharmony_ci	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
108062306a36Sopenharmony_ci	epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n",
108362306a36Sopenharmony_ci		__func__, dwc2_readl(hsotg, epctrl_reg), index,
108462306a36Sopenharmony_ci		hs_ep->dir_in ? "in" : "out");
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	/* If endpoint is stalled, we will restart request later */
108762306a36Sopenharmony_ci	ctrl = dwc2_readl(hsotg, epctrl_reg);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (index && ctrl & DXEPCTL_STALL) {
109062306a36Sopenharmony_ci		dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
109162306a36Sopenharmony_ci		return;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	length = ureq->length - ureq->actual;
109562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
109662306a36Sopenharmony_ci		ureq->length, ureq->actual);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (!using_desc_dma(hsotg))
109962306a36Sopenharmony_ci		maxreq = get_ep_limit(hs_ep);
110062306a36Sopenharmony_ci	else
110162306a36Sopenharmony_ci		maxreq = dwc2_gadget_get_chain_limit(hs_ep);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if (length > maxreq) {
110462306a36Sopenharmony_ci		int round = maxreq % hs_ep->ep.maxpacket;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n",
110762306a36Sopenharmony_ci			__func__, length, maxreq, round);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci		/* round down to multiple of packets */
111062306a36Sopenharmony_ci		if (round)
111162306a36Sopenharmony_ci			maxreq -= round;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci		length = maxreq;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (length)
111762306a36Sopenharmony_ci		packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket);
111862306a36Sopenharmony_ci	else
111962306a36Sopenharmony_ci		packets = 1;	/* send one packet if length is zero. */
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	if (dir_in && index != 0)
112262306a36Sopenharmony_ci		if (hs_ep->isochronous)
112362306a36Sopenharmony_ci			epsize = DXEPTSIZ_MC(packets);
112462306a36Sopenharmony_ci		else
112562306a36Sopenharmony_ci			epsize = DXEPTSIZ_MC(1);
112662306a36Sopenharmony_ci	else
112762306a36Sopenharmony_ci		epsize = 0;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/*
113062306a36Sopenharmony_ci	 * zero length packet should be programmed on its own and should not
113162306a36Sopenharmony_ci	 * be counted in DIEPTSIZ.PktCnt with other packets.
113262306a36Sopenharmony_ci	 */
113362306a36Sopenharmony_ci	if (dir_in && ureq->zero && !continuing) {
113462306a36Sopenharmony_ci		/* Test if zlp is actually required. */
113562306a36Sopenharmony_ci		if ((ureq->length >= hs_ep->ep.maxpacket) &&
113662306a36Sopenharmony_ci		    !(ureq->length % hs_ep->ep.maxpacket))
113762306a36Sopenharmony_ci			hs_ep->send_zlp = 1;
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	epsize |= DXEPTSIZ_PKTCNT(packets);
114162306a36Sopenharmony_ci	epsize |= DXEPTSIZ_XFERSIZE(length);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n",
114462306a36Sopenharmony_ci		__func__, packets, length, ureq->length, epsize, epsize_reg);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	/* store the request as the current one we're doing */
114762306a36Sopenharmony_ci	hs_ep->req = hs_req;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if (using_desc_dma(hsotg)) {
115062306a36Sopenharmony_ci		u32 offset = 0;
115162306a36Sopenharmony_ci		u32 mps = hs_ep->ep.maxpacket;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		/* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */
115462306a36Sopenharmony_ci		if (!dir_in) {
115562306a36Sopenharmony_ci			if (!index)
115662306a36Sopenharmony_ci				length = mps;
115762306a36Sopenharmony_ci			else if (length % mps)
115862306a36Sopenharmony_ci				length += (mps - (length % mps));
115962306a36Sopenharmony_ci		}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		if (continuing)
116262306a36Sopenharmony_ci			offset = ureq->actual;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		/* Fill DDMA chain entries */
116562306a36Sopenharmony_ci		dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset,
116662306a36Sopenharmony_ci						     length);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci		/* write descriptor chain address to control register */
116962306a36Sopenharmony_ci		dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n",
117262306a36Sopenharmony_ci			__func__, (u32)hs_ep->desc_list_dma, dma_reg);
117362306a36Sopenharmony_ci	} else {
117462306a36Sopenharmony_ci		/* write size / packets */
117562306a36Sopenharmony_ci		dwc2_writel(hsotg, epsize, epsize_reg);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		if (using_dma(hsotg) && !continuing && (length != 0)) {
117862306a36Sopenharmony_ci			/*
117962306a36Sopenharmony_ci			 * write DMA address to control register, buffer
118062306a36Sopenharmony_ci			 * already synced by dwc2_hsotg_ep_queue().
118162306a36Sopenharmony_ci			 */
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci			dwc2_writel(hsotg, ureq->dma, dma_reg);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n",
118662306a36Sopenharmony_ci				__func__, &ureq->dma, dma_reg);
118762306a36Sopenharmony_ci		}
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (hs_ep->isochronous) {
119162306a36Sopenharmony_ci		if (!dwc2_gadget_target_frame_elapsed(hs_ep)) {
119262306a36Sopenharmony_ci			if (hs_ep->interval == 1) {
119362306a36Sopenharmony_ci				if (hs_ep->target_frame & 0x1)
119462306a36Sopenharmony_ci					ctrl |= DXEPCTL_SETODDFR;
119562306a36Sopenharmony_ci				else
119662306a36Sopenharmony_ci					ctrl |= DXEPCTL_SETEVENFR;
119762306a36Sopenharmony_ci			}
119862306a36Sopenharmony_ci			ctrl |= DXEPCTL_CNAK;
119962306a36Sopenharmony_ci		} else {
120062306a36Sopenharmony_ci			hs_req->req.frame_number = hs_ep->target_frame;
120162306a36Sopenharmony_ci			hs_req->req.actual = 0;
120262306a36Sopenharmony_ci			dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA);
120362306a36Sopenharmony_ci			return;
120462306a36Sopenharmony_ci		}
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	ctrl |= DXEPCTL_EPENA;	/* ensure ep enabled */
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/* For Setup request do not clear NAK */
121262306a36Sopenharmony_ci	if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP))
121362306a36Sopenharmony_ci		ctrl |= DXEPCTL_CNAK;	/* clear NAK set by core */
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
121662306a36Sopenharmony_ci	dwc2_writel(hsotg, ctrl, epctrl_reg);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	/*
121962306a36Sopenharmony_ci	 * set these, it seems that DMA support increments past the end
122062306a36Sopenharmony_ci	 * of the packet buffer so we need to calculate the length from
122162306a36Sopenharmony_ci	 * this information.
122262306a36Sopenharmony_ci	 */
122362306a36Sopenharmony_ci	hs_ep->size_loaded = length;
122462306a36Sopenharmony_ci	hs_ep->last_load = ureq->actual;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (dir_in && !using_dma(hsotg)) {
122762306a36Sopenharmony_ci		/* set these anyway, we may need them for non-periodic in */
122862306a36Sopenharmony_ci		hs_ep->fifo_load = 0;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req);
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/*
123462306a36Sopenharmony_ci	 * Note, trying to clear the NAK here causes problems with transmit
123562306a36Sopenharmony_ci	 * on the S3C6400 ending up with the TXFIFO becoming full.
123662306a36Sopenharmony_ci	 */
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	/* check ep is enabled */
123962306a36Sopenharmony_ci	if (!(dwc2_readl(hsotg, epctrl_reg) & DXEPCTL_EPENA))
124062306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
124162306a36Sopenharmony_ci			"ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n",
124262306a36Sopenharmony_ci			 index, dwc2_readl(hsotg, epctrl_reg));
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n",
124562306a36Sopenharmony_ci		__func__, dwc2_readl(hsotg, epctrl_reg));
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* enable ep interrupts */
124862306a36Sopenharmony_ci	dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci/**
125262306a36Sopenharmony_ci * dwc2_hsotg_map_dma - map the DMA memory being used for the request
125362306a36Sopenharmony_ci * @hsotg: The device state.
125462306a36Sopenharmony_ci * @hs_ep: The endpoint the request is on.
125562306a36Sopenharmony_ci * @req: The request being processed.
125662306a36Sopenharmony_ci *
125762306a36Sopenharmony_ci * We've been asked to queue a request, so ensure that the memory buffer
125862306a36Sopenharmony_ci * is correctly setup for DMA. If we've been passed an extant DMA address
125962306a36Sopenharmony_ci * then ensure the buffer has been synced to memory. If our buffer has no
126062306a36Sopenharmony_ci * DMA memory, then we map the memory and mark our request to allow us to
126162306a36Sopenharmony_ci * cleanup on completion.
126262306a36Sopenharmony_ci */
126362306a36Sopenharmony_cistatic int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg,
126462306a36Sopenharmony_ci			      struct dwc2_hsotg_ep *hs_ep,
126562306a36Sopenharmony_ci			     struct usb_request *req)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	int ret;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	hs_ep->map_dir = hs_ep->dir_in;
127062306a36Sopenharmony_ci	ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
127162306a36Sopenharmony_ci	if (ret)
127262306a36Sopenharmony_ci		goto dma_error;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	return 0;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cidma_error:
127762306a36Sopenharmony_ci	dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n",
127862306a36Sopenharmony_ci		__func__, req->buf, req->length);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return -EIO;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg,
128462306a36Sopenharmony_ci						 struct dwc2_hsotg_ep *hs_ep,
128562306a36Sopenharmony_ci						 struct dwc2_hsotg_req *hs_req)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	void *req_buf = hs_req->req.buf;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	/* If dma is not being used or buffer is aligned */
129062306a36Sopenharmony_ci	if (!using_dma(hsotg) || !((long)req_buf & 3))
129162306a36Sopenharmony_ci		return 0;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	WARN_ON(hs_req->saved_req_buf);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__,
129662306a36Sopenharmony_ci		hs_ep->ep.name, req_buf, hs_req->req.length);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC);
129962306a36Sopenharmony_ci	if (!hs_req->req.buf) {
130062306a36Sopenharmony_ci		hs_req->req.buf = req_buf;
130162306a36Sopenharmony_ci		dev_err(hsotg->dev,
130262306a36Sopenharmony_ci			"%s: unable to allocate memory for bounce buffer\n",
130362306a36Sopenharmony_ci			__func__);
130462306a36Sopenharmony_ci		return -ENOMEM;
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	/* Save actual buffer */
130862306a36Sopenharmony_ci	hs_req->saved_req_buf = req_buf;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (hs_ep->dir_in)
131162306a36Sopenharmony_ci		memcpy(hs_req->req.buf, req_buf, hs_req->req.length);
131262306a36Sopenharmony_ci	return 0;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic void
131662306a36Sopenharmony_cidwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg,
131762306a36Sopenharmony_ci					 struct dwc2_hsotg_ep *hs_ep,
131862306a36Sopenharmony_ci					 struct dwc2_hsotg_req *hs_req)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	/* If dma is not being used or buffer was aligned */
132162306a36Sopenharmony_ci	if (!using_dma(hsotg) || !hs_req->saved_req_buf)
132262306a36Sopenharmony_ci		return;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__,
132562306a36Sopenharmony_ci		hs_ep->ep.name, hs_req->req.status, hs_req->req.actual);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	/* Copy data from bounce buffer on successful out transfer */
132862306a36Sopenharmony_ci	if (!hs_ep->dir_in && !hs_req->req.status)
132962306a36Sopenharmony_ci		memcpy(hs_req->saved_req_buf, hs_req->req.buf,
133062306a36Sopenharmony_ci		       hs_req->req.actual);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* Free bounce buffer */
133362306a36Sopenharmony_ci	kfree(hs_req->req.buf);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	hs_req->req.buf = hs_req->saved_req_buf;
133662306a36Sopenharmony_ci	hs_req->saved_req_buf = NULL;
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci/**
134062306a36Sopenharmony_ci * dwc2_gadget_target_frame_elapsed - Checks target frame
134162306a36Sopenharmony_ci * @hs_ep: The driver endpoint to check
134262306a36Sopenharmony_ci *
134362306a36Sopenharmony_ci * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop
134462306a36Sopenharmony_ci * corresponding transfer.
134562306a36Sopenharmony_ci */
134662306a36Sopenharmony_cistatic bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep)
134762306a36Sopenharmony_ci{
134862306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
134962306a36Sopenharmony_ci	u32 target_frame = hs_ep->target_frame;
135062306a36Sopenharmony_ci	u32 current_frame = hsotg->frame_number;
135162306a36Sopenharmony_ci	bool frame_overrun = hs_ep->frame_overrun;
135262306a36Sopenharmony_ci	u16 limit = DSTS_SOFFN_LIMIT;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	if (hsotg->gadget.speed != USB_SPEED_HIGH)
135562306a36Sopenharmony_ci		limit >>= 3;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	if (!frame_overrun && current_frame >= target_frame)
135862306a36Sopenharmony_ci		return true;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	if (frame_overrun && current_frame >= target_frame &&
136162306a36Sopenharmony_ci	    ((current_frame - target_frame) < limit / 2))
136262306a36Sopenharmony_ci		return true;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	return false;
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci/*
136862306a36Sopenharmony_ci * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers
136962306a36Sopenharmony_ci * @hsotg: The driver state
137062306a36Sopenharmony_ci * @hs_ep: the ep descriptor chain is for
137162306a36Sopenharmony_ci *
137262306a36Sopenharmony_ci * Called to update EP0 structure's pointers depend on stage of
137362306a36Sopenharmony_ci * control transfer.
137462306a36Sopenharmony_ci */
137562306a36Sopenharmony_cistatic int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg,
137662306a36Sopenharmony_ci					  struct dwc2_hsotg_ep *hs_ep)
137762306a36Sopenharmony_ci{
137862306a36Sopenharmony_ci	switch (hsotg->ep0_state) {
137962306a36Sopenharmony_ci	case DWC2_EP0_SETUP:
138062306a36Sopenharmony_ci	case DWC2_EP0_STATUS_OUT:
138162306a36Sopenharmony_ci		hs_ep->desc_list = hsotg->setup_desc[0];
138262306a36Sopenharmony_ci		hs_ep->desc_list_dma = hsotg->setup_desc_dma[0];
138362306a36Sopenharmony_ci		break;
138462306a36Sopenharmony_ci	case DWC2_EP0_DATA_IN:
138562306a36Sopenharmony_ci	case DWC2_EP0_STATUS_IN:
138662306a36Sopenharmony_ci		hs_ep->desc_list = hsotg->ctrl_in_desc;
138762306a36Sopenharmony_ci		hs_ep->desc_list_dma = hsotg->ctrl_in_desc_dma;
138862306a36Sopenharmony_ci		break;
138962306a36Sopenharmony_ci	case DWC2_EP0_DATA_OUT:
139062306a36Sopenharmony_ci		hs_ep->desc_list = hsotg->ctrl_out_desc;
139162306a36Sopenharmony_ci		hs_ep->desc_list_dma = hsotg->ctrl_out_desc_dma;
139262306a36Sopenharmony_ci		break;
139362306a36Sopenharmony_ci	default:
139462306a36Sopenharmony_ci		dev_err(hsotg->dev, "invalid EP 0 state in queue %d\n",
139562306a36Sopenharmony_ci			hsotg->ep0_state);
139662306a36Sopenharmony_ci		return -EINVAL;
139762306a36Sopenharmony_ci	}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	return 0;
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
140362306a36Sopenharmony_ci			       gfp_t gfp_flags)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = our_req(req);
140662306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
140762306a36Sopenharmony_ci	struct dwc2_hsotg *hs = hs_ep->parent;
140862306a36Sopenharmony_ci	bool first;
140962306a36Sopenharmony_ci	int ret;
141062306a36Sopenharmony_ci	u32 maxsize = 0;
141162306a36Sopenharmony_ci	u32 mask = 0;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
141562306a36Sopenharmony_ci		ep->name, req, req->length, req->buf, req->no_interrupt,
141662306a36Sopenharmony_ci		req->zero, req->short_not_ok);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/* Prevent new request submission when controller is suspended */
141962306a36Sopenharmony_ci	if (hs->lx_state != DWC2_L0) {
142062306a36Sopenharmony_ci		dev_dbg(hs->dev, "%s: submit request only in active state\n",
142162306a36Sopenharmony_ci			__func__);
142262306a36Sopenharmony_ci		return -EAGAIN;
142362306a36Sopenharmony_ci	}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	/* initialise status of the request */
142662306a36Sopenharmony_ci	INIT_LIST_HEAD(&hs_req->queue);
142762306a36Sopenharmony_ci	req->actual = 0;
142862306a36Sopenharmony_ci	req->status = -EINPROGRESS;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	/* Don't queue ISOC request if length greater than mps*mc */
143162306a36Sopenharmony_ci	if (hs_ep->isochronous &&
143262306a36Sopenharmony_ci	    req->length > (hs_ep->mc * hs_ep->ep.maxpacket)) {
143362306a36Sopenharmony_ci		dev_err(hs->dev, "req length > maxpacket*mc\n");
143462306a36Sopenharmony_ci		return -EINVAL;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* In DDMA mode for ISOC's don't queue request if length greater
143862306a36Sopenharmony_ci	 * than descriptor limits.
143962306a36Sopenharmony_ci	 */
144062306a36Sopenharmony_ci	if (using_desc_dma(hs) && hs_ep->isochronous) {
144162306a36Sopenharmony_ci		maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
144262306a36Sopenharmony_ci		if (hs_ep->dir_in && req->length > maxsize) {
144362306a36Sopenharmony_ci			dev_err(hs->dev, "wrong length %d (maxsize=%d)\n",
144462306a36Sopenharmony_ci				req->length, maxsize);
144562306a36Sopenharmony_ci			return -EINVAL;
144662306a36Sopenharmony_ci		}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci		if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) {
144962306a36Sopenharmony_ci			dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n",
145062306a36Sopenharmony_ci				req->length, hs_ep->ep.maxpacket);
145162306a36Sopenharmony_ci			return -EINVAL;
145262306a36Sopenharmony_ci		}
145362306a36Sopenharmony_ci	}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req);
145662306a36Sopenharmony_ci	if (ret)
145762306a36Sopenharmony_ci		return ret;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	/* if we're using DMA, sync the buffers as necessary */
146062306a36Sopenharmony_ci	if (using_dma(hs)) {
146162306a36Sopenharmony_ci		ret = dwc2_hsotg_map_dma(hs, hs_ep, req);
146262306a36Sopenharmony_ci		if (ret)
146362306a36Sopenharmony_ci			return ret;
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci	/* If using descriptor DMA configure EP0 descriptor chain pointers */
146662306a36Sopenharmony_ci	if (using_desc_dma(hs) && !hs_ep->index) {
146762306a36Sopenharmony_ci		ret = dwc2_gadget_set_ep0_desc_chain(hs, hs_ep);
146862306a36Sopenharmony_ci		if (ret)
146962306a36Sopenharmony_ci			return ret;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	first = list_empty(&hs_ep->queue);
147362306a36Sopenharmony_ci	list_add_tail(&hs_req->queue, &hs_ep->queue);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	/*
147662306a36Sopenharmony_ci	 * Handle DDMA isochronous transfers separately - just add new entry
147762306a36Sopenharmony_ci	 * to the descriptor chain.
147862306a36Sopenharmony_ci	 * Transfer will be started once SW gets either one of NAK or
147962306a36Sopenharmony_ci	 * OutTknEpDis interrupts.
148062306a36Sopenharmony_ci	 */
148162306a36Sopenharmony_ci	if (using_desc_dma(hs) && hs_ep->isochronous) {
148262306a36Sopenharmony_ci		if (hs_ep->target_frame != TARGET_FRAME_INITIAL) {
148362306a36Sopenharmony_ci			dma_addr_t dma_addr = hs_req->req.dma;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci			if (hs_req->req.num_sgs) {
148662306a36Sopenharmony_ci				WARN_ON(hs_req->req.num_sgs > 1);
148762306a36Sopenharmony_ci				dma_addr = sg_dma_address(hs_req->req.sg);
148862306a36Sopenharmony_ci			}
148962306a36Sopenharmony_ci			dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr,
149062306a36Sopenharmony_ci						   hs_req->req.length);
149162306a36Sopenharmony_ci		}
149262306a36Sopenharmony_ci		return 0;
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	/* Change EP direction if status phase request is after data out */
149662306a36Sopenharmony_ci	if (!hs_ep->index && !req->length && !hs_ep->dir_in &&
149762306a36Sopenharmony_ci	    hs->ep0_state == DWC2_EP0_DATA_OUT)
149862306a36Sopenharmony_ci		hs_ep->dir_in = 1;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (first) {
150162306a36Sopenharmony_ci		if (!hs_ep->isochronous) {
150262306a36Sopenharmony_ci			dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
150362306a36Sopenharmony_ci			return 0;
150462306a36Sopenharmony_ci		}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci		/* Update current frame number value. */
150762306a36Sopenharmony_ci		hs->frame_number = dwc2_hsotg_read_frameno(hs);
150862306a36Sopenharmony_ci		while (dwc2_gadget_target_frame_elapsed(hs_ep)) {
150962306a36Sopenharmony_ci			dwc2_gadget_incr_frame_num(hs_ep);
151062306a36Sopenharmony_ci			/* Update current frame number value once more as it
151162306a36Sopenharmony_ci			 * changes here.
151262306a36Sopenharmony_ci			 */
151362306a36Sopenharmony_ci			hs->frame_number = dwc2_hsotg_read_frameno(hs);
151462306a36Sopenharmony_ci		}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		if (hs_ep->target_frame != TARGET_FRAME_INITIAL)
151762306a36Sopenharmony_ci			dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
151862306a36Sopenharmony_ci	}
151962306a36Sopenharmony_ci	return 0;
152062306a36Sopenharmony_ci}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req,
152362306a36Sopenharmony_ci				    gfp_t gfp_flags)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
152662306a36Sopenharmony_ci	struct dwc2_hsotg *hs = hs_ep->parent;
152762306a36Sopenharmony_ci	unsigned long flags;
152862306a36Sopenharmony_ci	int ret;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	spin_lock_irqsave(&hs->lock, flags);
153162306a36Sopenharmony_ci	ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags);
153262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hs->lock, flags);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	return ret;
153562306a36Sopenharmony_ci}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_cistatic void dwc2_hsotg_ep_free_request(struct usb_ep *ep,
153862306a36Sopenharmony_ci				       struct usb_request *req)
153962306a36Sopenharmony_ci{
154062306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = our_req(req);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	kfree(hs_req);
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci/**
154662306a36Sopenharmony_ci * dwc2_hsotg_complete_oursetup - setup completion callback
154762306a36Sopenharmony_ci * @ep: The endpoint the request was on.
154862306a36Sopenharmony_ci * @req: The request completed.
154962306a36Sopenharmony_ci *
155062306a36Sopenharmony_ci * Called on completion of any requests the driver itself
155162306a36Sopenharmony_ci * submitted that need cleaning up.
155262306a36Sopenharmony_ci */
155362306a36Sopenharmony_cistatic void dwc2_hsotg_complete_oursetup(struct usb_ep *ep,
155462306a36Sopenharmony_ci					 struct usb_request *req)
155562306a36Sopenharmony_ci{
155662306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
155762306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	dwc2_hsotg_ep_free_request(ep, req);
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci/**
156562306a36Sopenharmony_ci * ep_from_windex - convert control wIndex value to endpoint
156662306a36Sopenharmony_ci * @hsotg: The driver state.
156762306a36Sopenharmony_ci * @windex: The control request wIndex field (in host order).
156862306a36Sopenharmony_ci *
156962306a36Sopenharmony_ci * Convert the given wIndex into a pointer to an driver endpoint
157062306a36Sopenharmony_ci * structure, or return NULL if it is not a valid endpoint.
157162306a36Sopenharmony_ci */
157262306a36Sopenharmony_cistatic struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
157362306a36Sopenharmony_ci					    u32 windex)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	int dir = (windex & USB_DIR_IN) ? 1 : 0;
157662306a36Sopenharmony_ci	int idx = windex & 0x7F;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	if (windex >= 0x100)
157962306a36Sopenharmony_ci		return NULL;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (idx > hsotg->num_of_eps)
158262306a36Sopenharmony_ci		return NULL;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	return index_to_ep(hsotg, idx, dir);
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci/**
158862306a36Sopenharmony_ci * dwc2_hsotg_set_test_mode - Enable usb Test Modes
158962306a36Sopenharmony_ci * @hsotg: The driver state.
159062306a36Sopenharmony_ci * @testmode: requested usb test mode
159162306a36Sopenharmony_ci * Enable usb Test Mode requested by the Host.
159262306a36Sopenharmony_ci */
159362306a36Sopenharmony_ciint dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	int dctl = dwc2_readl(hsotg, DCTL);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	dctl &= ~DCTL_TSTCTL_MASK;
159862306a36Sopenharmony_ci	switch (testmode) {
159962306a36Sopenharmony_ci	case USB_TEST_J:
160062306a36Sopenharmony_ci	case USB_TEST_K:
160162306a36Sopenharmony_ci	case USB_TEST_SE0_NAK:
160262306a36Sopenharmony_ci	case USB_TEST_PACKET:
160362306a36Sopenharmony_ci	case USB_TEST_FORCE_ENABLE:
160462306a36Sopenharmony_ci		dctl |= testmode << DCTL_TSTCTL_SHIFT;
160562306a36Sopenharmony_ci		break;
160662306a36Sopenharmony_ci	default:
160762306a36Sopenharmony_ci		return -EINVAL;
160862306a36Sopenharmony_ci	}
160962306a36Sopenharmony_ci	dwc2_writel(hsotg, dctl, DCTL);
161062306a36Sopenharmony_ci	return 0;
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci/**
161462306a36Sopenharmony_ci * dwc2_hsotg_send_reply - send reply to control request
161562306a36Sopenharmony_ci * @hsotg: The device state
161662306a36Sopenharmony_ci * @ep: Endpoint 0
161762306a36Sopenharmony_ci * @buff: Buffer for request
161862306a36Sopenharmony_ci * @length: Length of reply.
161962306a36Sopenharmony_ci *
162062306a36Sopenharmony_ci * Create a request and queue it on the given endpoint. This is useful as
162162306a36Sopenharmony_ci * an internal method of sending replies to certain control requests, etc.
162262306a36Sopenharmony_ci */
162362306a36Sopenharmony_cistatic int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg,
162462306a36Sopenharmony_ci				 struct dwc2_hsotg_ep *ep,
162562306a36Sopenharmony_ci				void *buff,
162662306a36Sopenharmony_ci				int length)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	struct usb_request *req;
162962306a36Sopenharmony_ci	int ret;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC);
163462306a36Sopenharmony_ci	hsotg->ep0_reply = req;
163562306a36Sopenharmony_ci	if (!req) {
163662306a36Sopenharmony_ci		dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__);
163762306a36Sopenharmony_ci		return -ENOMEM;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	req->buf = hsotg->ep0_buff;
164162306a36Sopenharmony_ci	req->length = length;
164262306a36Sopenharmony_ci	/*
164362306a36Sopenharmony_ci	 * zero flag is for sending zlp in DATA IN stage. It has no impact on
164462306a36Sopenharmony_ci	 * STATUS stage.
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	req->zero = 0;
164762306a36Sopenharmony_ci	req->complete = dwc2_hsotg_complete_oursetup;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (length)
165062306a36Sopenharmony_ci		memcpy(req->buf, buff, length);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC);
165362306a36Sopenharmony_ci	if (ret) {
165462306a36Sopenharmony_ci		dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__);
165562306a36Sopenharmony_ci		return ret;
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	return 0;
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci/**
166262306a36Sopenharmony_ci * dwc2_hsotg_process_req_status - process request GET_STATUS
166362306a36Sopenharmony_ci * @hsotg: The device state
166462306a36Sopenharmony_ci * @ctrl: USB control request
166562306a36Sopenharmony_ci */
166662306a36Sopenharmony_cistatic int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
166762306a36Sopenharmony_ci					 struct usb_ctrlrequest *ctrl)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
167062306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep;
167162306a36Sopenharmony_ci	__le16 reply;
167262306a36Sopenharmony_ci	u16 status;
167362306a36Sopenharmony_ci	int ret;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (!ep0->dir_in) {
167862306a36Sopenharmony_ci		dev_warn(hsotg->dev, "%s: direction out?\n", __func__);
167962306a36Sopenharmony_ci		return -EINVAL;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	switch (ctrl->bRequestType & USB_RECIP_MASK) {
168362306a36Sopenharmony_ci	case USB_RECIP_DEVICE:
168462306a36Sopenharmony_ci		status = hsotg->gadget.is_selfpowered <<
168562306a36Sopenharmony_ci			 USB_DEVICE_SELF_POWERED;
168662306a36Sopenharmony_ci		status |= hsotg->remote_wakeup_allowed <<
168762306a36Sopenharmony_ci			  USB_DEVICE_REMOTE_WAKEUP;
168862306a36Sopenharmony_ci		reply = cpu_to_le16(status);
168962306a36Sopenharmony_ci		break;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	case USB_RECIP_INTERFACE:
169262306a36Sopenharmony_ci		/* currently, the data result should be zero */
169362306a36Sopenharmony_ci		reply = cpu_to_le16(0);
169462306a36Sopenharmony_ci		break;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	case USB_RECIP_ENDPOINT:
169762306a36Sopenharmony_ci		ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
169862306a36Sopenharmony_ci		if (!ep)
169962306a36Sopenharmony_ci			return -ENOENT;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci		reply = cpu_to_le16(ep->halted ? 1 : 0);
170262306a36Sopenharmony_ci		break;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	default:
170562306a36Sopenharmony_ci		return 0;
170662306a36Sopenharmony_ci	}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	if (le16_to_cpu(ctrl->wLength) != 2)
170962306a36Sopenharmony_ci		return -EINVAL;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2);
171262306a36Sopenharmony_ci	if (ret) {
171362306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to send reply\n", __func__);
171462306a36Sopenharmony_ci		return ret;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	return 1;
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci/**
172362306a36Sopenharmony_ci * get_ep_head - return the first request on the endpoint
172462306a36Sopenharmony_ci * @hs_ep: The controller endpoint to get
172562306a36Sopenharmony_ci *
172662306a36Sopenharmony_ci * Get the first request on the endpoint.
172762306a36Sopenharmony_ci */
172862306a36Sopenharmony_cistatic struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req,
173162306a36Sopenharmony_ci					queue);
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci/**
173562306a36Sopenharmony_ci * dwc2_gadget_start_next_request - Starts next request from ep queue
173662306a36Sopenharmony_ci * @hs_ep: Endpoint structure
173762306a36Sopenharmony_ci *
173862306a36Sopenharmony_ci * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked
173962306a36Sopenharmony_ci * in its handler. Hence we need to unmask it here to be able to do
174062306a36Sopenharmony_ci * resynchronization.
174162306a36Sopenharmony_ci */
174262306a36Sopenharmony_cistatic void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
174562306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
174662306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	if (!list_empty(&hs_ep->queue)) {
174962306a36Sopenharmony_ci		hs_req = get_ep_head(hs_ep);
175062306a36Sopenharmony_ci		dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false);
175162306a36Sopenharmony_ci		return;
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci	if (!hs_ep->isochronous)
175462306a36Sopenharmony_ci		return;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	if (dir_in) {
175762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n",
175862306a36Sopenharmony_ci			__func__);
175962306a36Sopenharmony_ci	} else {
176062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n",
176162306a36Sopenharmony_ci			__func__);
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci/**
176662306a36Sopenharmony_ci * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE
176762306a36Sopenharmony_ci * @hsotg: The device state
176862306a36Sopenharmony_ci * @ctrl: USB control request
176962306a36Sopenharmony_ci */
177062306a36Sopenharmony_cistatic int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
177162306a36Sopenharmony_ci					  struct usb_ctrlrequest *ctrl)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
177462306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req;
177562306a36Sopenharmony_ci	bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
177662306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep;
177762306a36Sopenharmony_ci	int ret;
177862306a36Sopenharmony_ci	bool halted;
177962306a36Sopenharmony_ci	u32 recip;
178062306a36Sopenharmony_ci	u32 wValue;
178162306a36Sopenharmony_ci	u32 wIndex;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
178462306a36Sopenharmony_ci		__func__, set ? "SET" : "CLEAR");
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	wValue = le16_to_cpu(ctrl->wValue);
178762306a36Sopenharmony_ci	wIndex = le16_to_cpu(ctrl->wIndex);
178862306a36Sopenharmony_ci	recip = ctrl->bRequestType & USB_RECIP_MASK;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	switch (recip) {
179162306a36Sopenharmony_ci	case USB_RECIP_DEVICE:
179262306a36Sopenharmony_ci		switch (wValue) {
179362306a36Sopenharmony_ci		case USB_DEVICE_REMOTE_WAKEUP:
179462306a36Sopenharmony_ci			if (set)
179562306a36Sopenharmony_ci				hsotg->remote_wakeup_allowed = 1;
179662306a36Sopenharmony_ci			else
179762306a36Sopenharmony_ci				hsotg->remote_wakeup_allowed = 0;
179862306a36Sopenharmony_ci			break;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci		case USB_DEVICE_TEST_MODE:
180162306a36Sopenharmony_ci			if ((wIndex & 0xff) != 0)
180262306a36Sopenharmony_ci				return -EINVAL;
180362306a36Sopenharmony_ci			if (!set)
180462306a36Sopenharmony_ci				return -EINVAL;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci			hsotg->test_mode = wIndex >> 8;
180762306a36Sopenharmony_ci			break;
180862306a36Sopenharmony_ci		default:
180962306a36Sopenharmony_ci			return -ENOENT;
181062306a36Sopenharmony_ci		}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci		ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
181362306a36Sopenharmony_ci		if (ret) {
181462306a36Sopenharmony_ci			dev_err(hsotg->dev,
181562306a36Sopenharmony_ci				"%s: failed to send reply\n", __func__);
181662306a36Sopenharmony_ci			return ret;
181762306a36Sopenharmony_ci		}
181862306a36Sopenharmony_ci		break;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	case USB_RECIP_ENDPOINT:
182162306a36Sopenharmony_ci		ep = ep_from_windex(hsotg, wIndex);
182262306a36Sopenharmony_ci		if (!ep) {
182362306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
182462306a36Sopenharmony_ci				__func__, wIndex);
182562306a36Sopenharmony_ci			return -ENOENT;
182662306a36Sopenharmony_ci		}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci		switch (wValue) {
182962306a36Sopenharmony_ci		case USB_ENDPOINT_HALT:
183062306a36Sopenharmony_ci			halted = ep->halted;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci			if (!ep->wedged)
183362306a36Sopenharmony_ci				dwc2_hsotg_ep_sethalt(&ep->ep, set, true);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci			ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
183662306a36Sopenharmony_ci			if (ret) {
183762306a36Sopenharmony_ci				dev_err(hsotg->dev,
183862306a36Sopenharmony_ci					"%s: failed to send reply\n", __func__);
183962306a36Sopenharmony_ci				return ret;
184062306a36Sopenharmony_ci			}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci			/*
184362306a36Sopenharmony_ci			 * we have to complete all requests for ep if it was
184462306a36Sopenharmony_ci			 * halted, and the halt was cleared by CLEAR_FEATURE
184562306a36Sopenharmony_ci			 */
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci			if (!set && halted) {
184862306a36Sopenharmony_ci				/*
184962306a36Sopenharmony_ci				 * If we have request in progress,
185062306a36Sopenharmony_ci				 * then complete it
185162306a36Sopenharmony_ci				 */
185262306a36Sopenharmony_ci				if (ep->req) {
185362306a36Sopenharmony_ci					hs_req = ep->req;
185462306a36Sopenharmony_ci					ep->req = NULL;
185562306a36Sopenharmony_ci					list_del_init(&hs_req->queue);
185662306a36Sopenharmony_ci					if (hs_req->req.complete) {
185762306a36Sopenharmony_ci						spin_unlock(&hsotg->lock);
185862306a36Sopenharmony_ci						usb_gadget_giveback_request(
185962306a36Sopenharmony_ci							&ep->ep, &hs_req->req);
186062306a36Sopenharmony_ci						spin_lock(&hsotg->lock);
186162306a36Sopenharmony_ci					}
186262306a36Sopenharmony_ci				}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci				/* If we have pending request, then start it */
186562306a36Sopenharmony_ci				if (!ep->req)
186662306a36Sopenharmony_ci					dwc2_gadget_start_next_request(ep);
186762306a36Sopenharmony_ci			}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci			break;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci		default:
187262306a36Sopenharmony_ci			return -ENOENT;
187362306a36Sopenharmony_ci		}
187462306a36Sopenharmony_ci		break;
187562306a36Sopenharmony_ci	default:
187662306a36Sopenharmony_ci		return -ENOENT;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci	return 1;
187962306a36Sopenharmony_ci}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_cistatic void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci/**
188462306a36Sopenharmony_ci * dwc2_hsotg_stall_ep0 - stall ep0
188562306a36Sopenharmony_ci * @hsotg: The device state
188662306a36Sopenharmony_ci *
188762306a36Sopenharmony_ci * Set stall for ep0 as response for setup request.
188862306a36Sopenharmony_ci */
188962306a36Sopenharmony_cistatic void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
189262306a36Sopenharmony_ci	u32 reg;
189362306a36Sopenharmony_ci	u32 ctrl;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
189662306a36Sopenharmony_ci	reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	/*
189962306a36Sopenharmony_ci	 * DxEPCTL_Stall will be cleared by EP once it has
190062306a36Sopenharmony_ci	 * taken effect, so no need to clear later.
190162306a36Sopenharmony_ci	 */
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	ctrl = dwc2_readl(hsotg, reg);
190462306a36Sopenharmony_ci	ctrl |= DXEPCTL_STALL;
190562306a36Sopenharmony_ci	ctrl |= DXEPCTL_CNAK;
190662306a36Sopenharmony_ci	dwc2_writel(hsotg, ctrl, reg);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
190962306a36Sopenharmony_ci		"written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n",
191062306a36Sopenharmony_ci		ctrl, reg, dwc2_readl(hsotg, reg));
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	 /*
191362306a36Sopenharmony_ci	  * complete won't be called, so we enqueue
191462306a36Sopenharmony_ci	  * setup request here
191562306a36Sopenharmony_ci	  */
191662306a36Sopenharmony_ci	 dwc2_hsotg_enqueue_setup(hsotg);
191762306a36Sopenharmony_ci}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci/**
192062306a36Sopenharmony_ci * dwc2_hsotg_process_control - process a control request
192162306a36Sopenharmony_ci * @hsotg: The device state
192262306a36Sopenharmony_ci * @ctrl: The control request received
192362306a36Sopenharmony_ci *
192462306a36Sopenharmony_ci * The controller has received the SETUP phase of a control request, and
192562306a36Sopenharmony_ci * needs to work out what to do next (and whether to pass it on to the
192662306a36Sopenharmony_ci * gadget driver).
192762306a36Sopenharmony_ci */
192862306a36Sopenharmony_cistatic void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg,
192962306a36Sopenharmony_ci				       struct usb_ctrlrequest *ctrl)
193062306a36Sopenharmony_ci{
193162306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
193262306a36Sopenharmony_ci	int ret = 0;
193362306a36Sopenharmony_ci	u32 dcfg;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
193662306a36Sopenharmony_ci		"ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n",
193762306a36Sopenharmony_ci		ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
193862306a36Sopenharmony_ci		ctrl->wIndex, ctrl->wLength);
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	if (ctrl->wLength == 0) {
194162306a36Sopenharmony_ci		ep0->dir_in = 1;
194262306a36Sopenharmony_ci		hsotg->ep0_state = DWC2_EP0_STATUS_IN;
194362306a36Sopenharmony_ci	} else if (ctrl->bRequestType & USB_DIR_IN) {
194462306a36Sopenharmony_ci		ep0->dir_in = 1;
194562306a36Sopenharmony_ci		hsotg->ep0_state = DWC2_EP0_DATA_IN;
194662306a36Sopenharmony_ci	} else {
194762306a36Sopenharmony_ci		ep0->dir_in = 0;
194862306a36Sopenharmony_ci		hsotg->ep0_state = DWC2_EP0_DATA_OUT;
194962306a36Sopenharmony_ci	}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
195262306a36Sopenharmony_ci		switch (ctrl->bRequest) {
195362306a36Sopenharmony_ci		case USB_REQ_SET_ADDRESS:
195462306a36Sopenharmony_ci			hsotg->connected = 1;
195562306a36Sopenharmony_ci			dcfg = dwc2_readl(hsotg, DCFG);
195662306a36Sopenharmony_ci			dcfg &= ~DCFG_DEVADDR_MASK;
195762306a36Sopenharmony_ci			dcfg |= (le16_to_cpu(ctrl->wValue) <<
195862306a36Sopenharmony_ci				 DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK;
195962306a36Sopenharmony_ci			dwc2_writel(hsotg, dcfg, DCFG);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci			dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci			ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
196462306a36Sopenharmony_ci			return;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci		case USB_REQ_GET_STATUS:
196762306a36Sopenharmony_ci			ret = dwc2_hsotg_process_req_status(hsotg, ctrl);
196862306a36Sopenharmony_ci			break;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		case USB_REQ_CLEAR_FEATURE:
197162306a36Sopenharmony_ci		case USB_REQ_SET_FEATURE:
197262306a36Sopenharmony_ci			ret = dwc2_hsotg_process_req_feature(hsotg, ctrl);
197362306a36Sopenharmony_ci			break;
197462306a36Sopenharmony_ci		}
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	/* as a fallback, try delivering it to the driver to deal with */
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	if (ret == 0 && hsotg->driver) {
198062306a36Sopenharmony_ci		spin_unlock(&hsotg->lock);
198162306a36Sopenharmony_ci		ret = hsotg->driver->setup(&hsotg->gadget, ctrl);
198262306a36Sopenharmony_ci		spin_lock(&hsotg->lock);
198362306a36Sopenharmony_ci		if (ret < 0)
198462306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	hsotg->delayed_status = false;
198862306a36Sopenharmony_ci	if (ret == USB_GADGET_DELAYED_STATUS)
198962306a36Sopenharmony_ci		hsotg->delayed_status = true;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	/*
199262306a36Sopenharmony_ci	 * the request is either unhandlable, or is not formatted correctly
199362306a36Sopenharmony_ci	 * so respond with a STALL for the status stage to indicate failure.
199462306a36Sopenharmony_ci	 */
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (ret < 0)
199762306a36Sopenharmony_ci		dwc2_hsotg_stall_ep0(hsotg);
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci/**
200162306a36Sopenharmony_ci * dwc2_hsotg_complete_setup - completion of a setup transfer
200262306a36Sopenharmony_ci * @ep: The endpoint the request was on.
200362306a36Sopenharmony_ci * @req: The request completed.
200462306a36Sopenharmony_ci *
200562306a36Sopenharmony_ci * Called on completion of any requests the driver itself submitted for
200662306a36Sopenharmony_ci * EP0 setup packets
200762306a36Sopenharmony_ci */
200862306a36Sopenharmony_cistatic void dwc2_hsotg_complete_setup(struct usb_ep *ep,
200962306a36Sopenharmony_ci				      struct usb_request *req)
201062306a36Sopenharmony_ci{
201162306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
201262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	if (req->status < 0) {
201562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status);
201662306a36Sopenharmony_ci		return;
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	spin_lock(&hsotg->lock);
202062306a36Sopenharmony_ci	if (req->actual == 0)
202162306a36Sopenharmony_ci		dwc2_hsotg_enqueue_setup(hsotg);
202262306a36Sopenharmony_ci	else
202362306a36Sopenharmony_ci		dwc2_hsotg_process_control(hsotg, req->buf);
202462306a36Sopenharmony_ci	spin_unlock(&hsotg->lock);
202562306a36Sopenharmony_ci}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci/**
202862306a36Sopenharmony_ci * dwc2_hsotg_enqueue_setup - start a request for EP0 packets
202962306a36Sopenharmony_ci * @hsotg: The device state.
203062306a36Sopenharmony_ci *
203162306a36Sopenharmony_ci * Enqueue a request on EP0 if necessary to received any SETUP packets
203262306a36Sopenharmony_ci * received from the host.
203362306a36Sopenharmony_ci */
203462306a36Sopenharmony_cistatic void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	struct usb_request *req = hsotg->ctrl_req;
203762306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = our_req(req);
203862306a36Sopenharmony_ci	int ret;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	req->zero = 0;
204362306a36Sopenharmony_ci	req->length = 8;
204462306a36Sopenharmony_ci	req->buf = hsotg->ctrl_buff;
204562306a36Sopenharmony_ci	req->complete = dwc2_hsotg_complete_setup;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	if (!list_empty(&hs_req->queue)) {
204862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s already queued???\n", __func__);
204962306a36Sopenharmony_ci		return;
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	hsotg->eps_out[0]->dir_in = 0;
205362306a36Sopenharmony_ci	hsotg->eps_out[0]->send_zlp = 0;
205462306a36Sopenharmony_ci	hsotg->ep0_state = DWC2_EP0_SETUP;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC);
205762306a36Sopenharmony_ci	if (ret < 0) {
205862306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
205962306a36Sopenharmony_ci		/*
206062306a36Sopenharmony_ci		 * Don't think there's much we can do other than watch the
206162306a36Sopenharmony_ci		 * driver fail.
206262306a36Sopenharmony_ci		 */
206362306a36Sopenharmony_ci	}
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
206762306a36Sopenharmony_ci				   struct dwc2_hsotg_ep *hs_ep)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	u32 ctrl;
207062306a36Sopenharmony_ci	u8 index = hs_ep->index;
207162306a36Sopenharmony_ci	u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
207262306a36Sopenharmony_ci	u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	if (hs_ep->dir_in)
207562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n",
207662306a36Sopenharmony_ci			index);
207762306a36Sopenharmony_ci	else
207862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n",
207962306a36Sopenharmony_ci			index);
208062306a36Sopenharmony_ci	if (using_desc_dma(hsotg)) {
208162306a36Sopenharmony_ci		/* Not specific buffer needed for ep0 ZLP */
208262306a36Sopenharmony_ci		dma_addr_t dma = hs_ep->desc_list_dma;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci		if (!index)
208562306a36Sopenharmony_ci			dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0);
208862306a36Sopenharmony_ci	} else {
208962306a36Sopenharmony_ci		dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
209062306a36Sopenharmony_ci			    DXEPTSIZ_XFERSIZE(0),
209162306a36Sopenharmony_ci			    epsiz_reg);
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	ctrl = dwc2_readl(hsotg, epctl_reg);
209562306a36Sopenharmony_ci	ctrl |= DXEPCTL_CNAK;  /* clear NAK set by core */
209662306a36Sopenharmony_ci	ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
209762306a36Sopenharmony_ci	ctrl |= DXEPCTL_USBACTEP;
209862306a36Sopenharmony_ci	dwc2_writel(hsotg, ctrl, epctl_reg);
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci/**
210262306a36Sopenharmony_ci * dwc2_hsotg_complete_request - complete a request given to us
210362306a36Sopenharmony_ci * @hsotg: The device state.
210462306a36Sopenharmony_ci * @hs_ep: The endpoint the request was on.
210562306a36Sopenharmony_ci * @hs_req: The request to complete.
210662306a36Sopenharmony_ci * @result: The result code (0 => Ok, otherwise errno)
210762306a36Sopenharmony_ci *
210862306a36Sopenharmony_ci * The given request has finished, so call the necessary completion
210962306a36Sopenharmony_ci * if it has one and then look to see if we can start a new request
211062306a36Sopenharmony_ci * on the endpoint.
211162306a36Sopenharmony_ci *
211262306a36Sopenharmony_ci * Note, expects the ep to already be locked as appropriate.
211362306a36Sopenharmony_ci */
211462306a36Sopenharmony_cistatic void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
211562306a36Sopenharmony_ci					struct dwc2_hsotg_ep *hs_ep,
211662306a36Sopenharmony_ci				       struct dwc2_hsotg_req *hs_req,
211762306a36Sopenharmony_ci				       int result)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	if (!hs_req) {
212062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__);
212162306a36Sopenharmony_ci		return;
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n",
212562306a36Sopenharmony_ci		hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete);
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	/*
212862306a36Sopenharmony_ci	 * only replace the status if we've not already set an error
212962306a36Sopenharmony_ci	 * from a previous transaction
213062306a36Sopenharmony_ci	 */
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	if (hs_req->req.status == -EINPROGRESS)
213362306a36Sopenharmony_ci		hs_req->req.status = result;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	if (using_dma(hsotg))
213662306a36Sopenharmony_ci		dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req);
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	hs_ep->req = NULL;
214162306a36Sopenharmony_ci	list_del_init(&hs_req->queue);
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	/*
214462306a36Sopenharmony_ci	 * call the complete request with the locks off, just in case the
214562306a36Sopenharmony_ci	 * request tries to queue more work for this endpoint.
214662306a36Sopenharmony_ci	 */
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	if (hs_req->req.complete) {
214962306a36Sopenharmony_ci		spin_unlock(&hsotg->lock);
215062306a36Sopenharmony_ci		usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req);
215162306a36Sopenharmony_ci		spin_lock(&hsotg->lock);
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	/* In DDMA don't need to proceed to starting of next ISOC request */
215562306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && hs_ep->isochronous)
215662306a36Sopenharmony_ci		return;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	/*
215962306a36Sopenharmony_ci	 * Look to see if there is anything else to do. Note, the completion
216062306a36Sopenharmony_ci	 * of the previous request may have caused a new request to be started
216162306a36Sopenharmony_ci	 * so be careful when doing this.
216262306a36Sopenharmony_ci	 */
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	if (!hs_ep->req && result >= 0)
216562306a36Sopenharmony_ci		dwc2_gadget_start_next_request(hs_ep);
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci/*
216962306a36Sopenharmony_ci * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA
217062306a36Sopenharmony_ci * @hs_ep: The endpoint the request was on.
217162306a36Sopenharmony_ci *
217262306a36Sopenharmony_ci * Get first request from the ep queue, determine descriptor on which complete
217362306a36Sopenharmony_ci * happened. SW discovers which descriptor currently in use by HW, adjusts
217462306a36Sopenharmony_ci * dma_address and calculates index of completed descriptor based on the value
217562306a36Sopenharmony_ci * of DEPDMA register. Update actual length of request, giveback to gadget.
217662306a36Sopenharmony_ci */
217762306a36Sopenharmony_cistatic void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep)
217862306a36Sopenharmony_ci{
217962306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
218062306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req;
218162306a36Sopenharmony_ci	struct usb_request *ureq;
218262306a36Sopenharmony_ci	u32 desc_sts;
218362306a36Sopenharmony_ci	u32 mask;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	/* Process only descriptors with buffer status set to DMA done */
218862306a36Sopenharmony_ci	while ((desc_sts & DEV_DMA_BUFF_STS_MASK) >>
218962306a36Sopenharmony_ci		DEV_DMA_BUFF_STS_SHIFT == DEV_DMA_BUFF_STS_DMADONE) {
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		hs_req = get_ep_head(hs_ep);
219262306a36Sopenharmony_ci		if (!hs_req) {
219362306a36Sopenharmony_ci			dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__);
219462306a36Sopenharmony_ci			return;
219562306a36Sopenharmony_ci		}
219662306a36Sopenharmony_ci		ureq = &hs_req->req;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci		/* Check completion status */
219962306a36Sopenharmony_ci		if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT ==
220062306a36Sopenharmony_ci			DEV_DMA_STS_SUCC) {
220162306a36Sopenharmony_ci			mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK :
220262306a36Sopenharmony_ci				DEV_DMA_ISOC_RX_NBYTES_MASK;
220362306a36Sopenharmony_ci			ureq->actual = ureq->length - ((desc_sts & mask) >>
220462306a36Sopenharmony_ci				DEV_DMA_ISOC_NBYTES_SHIFT);
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci			/* Adjust actual len for ISOC Out if len is
220762306a36Sopenharmony_ci			 * not align of 4
220862306a36Sopenharmony_ci			 */
220962306a36Sopenharmony_ci			if (!hs_ep->dir_in && ureq->length & 0x3)
221062306a36Sopenharmony_ci				ureq->actual += 4 - (ureq->length & 0x3);
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci			/* Set actual frame number for completed transfers */
221362306a36Sopenharmony_ci			ureq->frame_number =
221462306a36Sopenharmony_ci				(desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >>
221562306a36Sopenharmony_ci				DEV_DMA_ISOC_FRNUM_SHIFT;
221662306a36Sopenharmony_ci		}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci		hs_ep->compl_desc++;
222162306a36Sopenharmony_ci		if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_HS_ISOC - 1))
222262306a36Sopenharmony_ci			hs_ep->compl_desc = 0;
222362306a36Sopenharmony_ci		desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status;
222462306a36Sopenharmony_ci	}
222562306a36Sopenharmony_ci}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci/*
222862306a36Sopenharmony_ci * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC.
222962306a36Sopenharmony_ci * @hs_ep: The isochronous endpoint.
223062306a36Sopenharmony_ci *
223162306a36Sopenharmony_ci * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA
223262306a36Sopenharmony_ci * interrupt. Reset target frame and next_desc to allow to start
223362306a36Sopenharmony_ci * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS
223462306a36Sopenharmony_ci * interrupt for OUT direction.
223562306a36Sopenharmony_ci */
223662306a36Sopenharmony_cistatic void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	if (!hs_ep->dir_in)
224162306a36Sopenharmony_ci		dwc2_flush_rx_fifo(hsotg);
224262306a36Sopenharmony_ci	dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep), 0);
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	hs_ep->target_frame = TARGET_FRAME_INITIAL;
224562306a36Sopenharmony_ci	hs_ep->next_desc = 0;
224662306a36Sopenharmony_ci	hs_ep->compl_desc = 0;
224762306a36Sopenharmony_ci}
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci/**
225062306a36Sopenharmony_ci * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint
225162306a36Sopenharmony_ci * @hsotg: The device state.
225262306a36Sopenharmony_ci * @ep_idx: The endpoint index for the data
225362306a36Sopenharmony_ci * @size: The size of data in the fifo, in bytes
225462306a36Sopenharmony_ci *
225562306a36Sopenharmony_ci * The FIFO status shows there is data to read from the FIFO for a given
225662306a36Sopenharmony_ci * endpoint, so sort out whether we need to read the data into a request
225762306a36Sopenharmony_ci * that has been made for that endpoint.
225862306a36Sopenharmony_ci */
225962306a36Sopenharmony_cistatic void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
226062306a36Sopenharmony_ci{
226162306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx];
226262306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = hs_ep->req;
226362306a36Sopenharmony_ci	int to_read;
226462306a36Sopenharmony_ci	int max_req;
226562306a36Sopenharmony_ci	int read_ptr;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	if (!hs_req) {
226862306a36Sopenharmony_ci		u32 epctl = dwc2_readl(hsotg, DOEPCTL(ep_idx));
226962306a36Sopenharmony_ci		int ptr;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
227262306a36Sopenharmony_ci			"%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n",
227362306a36Sopenharmony_ci			 __func__, size, ep_idx, epctl);
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		/* dump the data from the FIFO, we've nothing we can do */
227662306a36Sopenharmony_ci		for (ptr = 0; ptr < size; ptr += 4)
227762306a36Sopenharmony_ci			(void)dwc2_readl(hsotg, EPFIFO(ep_idx));
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci		return;
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	to_read = size;
228362306a36Sopenharmony_ci	read_ptr = hs_req->req.actual;
228462306a36Sopenharmony_ci	max_req = hs_req->req.length - read_ptr;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n",
228762306a36Sopenharmony_ci		__func__, to_read, max_req, read_ptr, hs_req->req.length);
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	if (to_read > max_req) {
229062306a36Sopenharmony_ci		/*
229162306a36Sopenharmony_ci		 * more data appeared than we where willing
229262306a36Sopenharmony_ci		 * to deal with in this request.
229362306a36Sopenharmony_ci		 */
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci		/* currently we don't deal this */
229662306a36Sopenharmony_ci		WARN_ON_ONCE(1);
229762306a36Sopenharmony_ci	}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	hs_ep->total_data += to_read;
230062306a36Sopenharmony_ci	hs_req->req.actual += to_read;
230162306a36Sopenharmony_ci	to_read = DIV_ROUND_UP(to_read, 4);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	/*
230462306a36Sopenharmony_ci	 * note, we might over-write the buffer end by 3 bytes depending on
230562306a36Sopenharmony_ci	 * alignment of the data.
230662306a36Sopenharmony_ci	 */
230762306a36Sopenharmony_ci	dwc2_readl_rep(hsotg, EPFIFO(ep_idx),
230862306a36Sopenharmony_ci		       hs_req->req.buf + read_ptr, to_read);
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci/**
231262306a36Sopenharmony_ci * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint
231362306a36Sopenharmony_ci * @hsotg: The device instance
231462306a36Sopenharmony_ci * @dir_in: If IN zlp
231562306a36Sopenharmony_ci *
231662306a36Sopenharmony_ci * Generate a zero-length IN packet request for terminating a SETUP
231762306a36Sopenharmony_ci * transaction.
231862306a36Sopenharmony_ci *
231962306a36Sopenharmony_ci * Note, since we don't write any data to the TxFIFO, then it is
232062306a36Sopenharmony_ci * currently believed that we do not need to wait for any space in
232162306a36Sopenharmony_ci * the TxFIFO.
232262306a36Sopenharmony_ci */
232362306a36Sopenharmony_cistatic void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in)
232462306a36Sopenharmony_ci{
232562306a36Sopenharmony_ci	/* eps_out[0] is used in both directions */
232662306a36Sopenharmony_ci	hsotg->eps_out[0]->dir_in = dir_in;
232762306a36Sopenharmony_ci	hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]);
233062306a36Sopenharmony_ci}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci/*
233362306a36Sopenharmony_ci * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc
233462306a36Sopenharmony_ci * @hs_ep - The endpoint on which transfer went
233562306a36Sopenharmony_ci *
233662306a36Sopenharmony_ci * Iterate over endpoints descriptor chain and get info on bytes remained
233762306a36Sopenharmony_ci * in DMA descriptors after transfer has completed. Used for non isoc EPs.
233862306a36Sopenharmony_ci */
233962306a36Sopenharmony_cistatic unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep)
234062306a36Sopenharmony_ci{
234162306a36Sopenharmony_ci	const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc;
234262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
234362306a36Sopenharmony_ci	unsigned int bytes_rem = 0;
234462306a36Sopenharmony_ci	unsigned int bytes_rem_correction = 0;
234562306a36Sopenharmony_ci	struct dwc2_dma_desc *desc = hs_ep->desc_list;
234662306a36Sopenharmony_ci	int i;
234762306a36Sopenharmony_ci	u32 status;
234862306a36Sopenharmony_ci	u32 mps = hs_ep->ep.maxpacket;
234962306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	if (!desc)
235262306a36Sopenharmony_ci		return -EINVAL;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	/* Interrupt OUT EP with mps not multiple of 4 */
235562306a36Sopenharmony_ci	if (hs_ep->index)
235662306a36Sopenharmony_ci		if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4))
235762306a36Sopenharmony_ci			bytes_rem_correction = 4 - (mps % 4);
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	for (i = 0; i < hs_ep->desc_count; ++i) {
236062306a36Sopenharmony_ci		status = desc->status;
236162306a36Sopenharmony_ci		bytes_rem += status & DEV_DMA_NBYTES_MASK;
236262306a36Sopenharmony_ci		bytes_rem -= bytes_rem_correction;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci		if (status & DEV_DMA_STS_MASK)
236562306a36Sopenharmony_ci			dev_err(hsotg->dev, "descriptor %d closed with %x\n",
236662306a36Sopenharmony_ci				i, status & DEV_DMA_STS_MASK);
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci		if (status & DEV_DMA_L)
236962306a36Sopenharmony_ci			break;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci		desc++;
237262306a36Sopenharmony_ci	}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	return bytes_rem;
237562306a36Sopenharmony_ci}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci/**
237862306a36Sopenharmony_ci * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
237962306a36Sopenharmony_ci * @hsotg: The device instance
238062306a36Sopenharmony_ci * @epnum: The endpoint received from
238162306a36Sopenharmony_ci *
238262306a36Sopenharmony_ci * The RXFIFO has delivered an OutDone event, which means that the data
238362306a36Sopenharmony_ci * transfer for an OUT endpoint has been completed, either by a short
238462306a36Sopenharmony_ci * packet or by the finish of a transfer.
238562306a36Sopenharmony_ci */
238662306a36Sopenharmony_cistatic void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
238762306a36Sopenharmony_ci{
238862306a36Sopenharmony_ci	u32 epsize = dwc2_readl(hsotg, DOEPTSIZ(epnum));
238962306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum];
239062306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = hs_ep->req;
239162306a36Sopenharmony_ci	struct usb_request *req = &hs_req->req;
239262306a36Sopenharmony_ci	unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
239362306a36Sopenharmony_ci	int result = 0;
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	if (!hs_req) {
239662306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: no request active\n", __func__);
239762306a36Sopenharmony_ci		return;
239862306a36Sopenharmony_ci	}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) {
240162306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "zlp packet received\n");
240262306a36Sopenharmony_ci		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
240362306a36Sopenharmony_ci		dwc2_hsotg_enqueue_setup(hsotg);
240462306a36Sopenharmony_ci		return;
240562306a36Sopenharmony_ci	}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	if (using_desc_dma(hsotg))
240862306a36Sopenharmony_ci		size_left = dwc2_gadget_get_xfersize_ddma(hs_ep);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	if (using_dma(hsotg)) {
241162306a36Sopenharmony_ci		unsigned int size_done;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci		/*
241462306a36Sopenharmony_ci		 * Calculate the size of the transfer by checking how much
241562306a36Sopenharmony_ci		 * is left in the endpoint size register and then working it
241662306a36Sopenharmony_ci		 * out from the amount we loaded for the transfer.
241762306a36Sopenharmony_ci		 *
241862306a36Sopenharmony_ci		 * We need to do this as DMA pointers are always 32bit aligned
241962306a36Sopenharmony_ci		 * so may overshoot/undershoot the transfer.
242062306a36Sopenharmony_ci		 */
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci		size_done = hs_ep->size_loaded - size_left;
242362306a36Sopenharmony_ci		size_done += hs_ep->last_load;
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci		req->actual = size_done;
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	/* if there is more request to do, schedule new transfer */
242962306a36Sopenharmony_ci	if (req->actual < req->length && size_left == 0) {
243062306a36Sopenharmony_ci		dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true);
243162306a36Sopenharmony_ci		return;
243262306a36Sopenharmony_ci	}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	if (req->actual < req->length && req->short_not_ok) {
243562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
243662306a36Sopenharmony_ci			__func__, req->actual, req->length);
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci		/*
243962306a36Sopenharmony_ci		 * todo - what should we return here? there's no one else
244062306a36Sopenharmony_ci		 * even bothering to check the status.
244162306a36Sopenharmony_ci		 */
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	/* DDMA IN status phase will start from StsPhseRcvd interrupt */
244562306a36Sopenharmony_ci	if (!using_desc_dma(hsotg) && epnum == 0 &&
244662306a36Sopenharmony_ci	    hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
244762306a36Sopenharmony_ci		/* Move to STATUS IN */
244862306a36Sopenharmony_ci		if (!hsotg->delayed_status)
244962306a36Sopenharmony_ci			dwc2_hsotg_ep0_zlp(hsotg, true);
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	/* Set actual frame number for completed transfers */
245362306a36Sopenharmony_ci	if (!using_desc_dma(hsotg) && hs_ep->isochronous) {
245462306a36Sopenharmony_ci		req->frame_number = hs_ep->target_frame;
245562306a36Sopenharmony_ci		dwc2_gadget_incr_frame_num(hs_ep);
245662306a36Sopenharmony_ci	}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci/**
246262306a36Sopenharmony_ci * dwc2_hsotg_handle_rx - RX FIFO has data
246362306a36Sopenharmony_ci * @hsotg: The device instance
246462306a36Sopenharmony_ci *
246562306a36Sopenharmony_ci * The IRQ handler has detected that the RX FIFO has some data in it
246662306a36Sopenharmony_ci * that requires processing, so find out what is in there and do the
246762306a36Sopenharmony_ci * appropriate read.
246862306a36Sopenharmony_ci *
246962306a36Sopenharmony_ci * The RXFIFO is a true FIFO, the packets coming out are still in packet
247062306a36Sopenharmony_ci * chunks, so if you have x packets received on an endpoint you'll get x
247162306a36Sopenharmony_ci * FIFO events delivered, each with a packet's worth of data in it.
247262306a36Sopenharmony_ci *
247362306a36Sopenharmony_ci * When using DMA, we should not be processing events from the RXFIFO
247462306a36Sopenharmony_ci * as the actual data should be sent to the memory directly and we turn
247562306a36Sopenharmony_ci * on the completion interrupts to get notifications of transfer completion.
247662306a36Sopenharmony_ci */
247762306a36Sopenharmony_cistatic void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
247862306a36Sopenharmony_ci{
247962306a36Sopenharmony_ci	u32 grxstsr = dwc2_readl(hsotg, GRXSTSP);
248062306a36Sopenharmony_ci	u32 epnum, status, size;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	WARN_ON(using_dma(hsotg));
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	epnum = grxstsr & GRXSTS_EPNUM_MASK;
248562306a36Sopenharmony_ci	status = grxstsr & GRXSTS_PKTSTS_MASK;
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	size = grxstsr & GRXSTS_BYTECNT_MASK;
248862306a36Sopenharmony_ci	size >>= GRXSTS_BYTECNT_SHIFT;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
249162306a36Sopenharmony_ci		__func__, grxstsr, size, epnum);
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) {
249462306a36Sopenharmony_ci	case GRXSTS_PKTSTS_GLOBALOUTNAK:
249562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "GLOBALOUTNAK\n");
249662306a36Sopenharmony_ci		break;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	case GRXSTS_PKTSTS_OUTDONE:
249962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",
250062306a36Sopenharmony_ci			dwc2_hsotg_read_frameno(hsotg));
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci		if (!using_dma(hsotg))
250362306a36Sopenharmony_ci			dwc2_hsotg_handle_outdone(hsotg, epnum);
250462306a36Sopenharmony_ci		break;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	case GRXSTS_PKTSTS_SETUPDONE:
250762306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
250862306a36Sopenharmony_ci			"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
250962306a36Sopenharmony_ci			dwc2_hsotg_read_frameno(hsotg),
251062306a36Sopenharmony_ci			dwc2_readl(hsotg, DOEPCTL(0)));
251162306a36Sopenharmony_ci		/*
251262306a36Sopenharmony_ci		 * Call dwc2_hsotg_handle_outdone here if it was not called from
251362306a36Sopenharmony_ci		 * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't
251462306a36Sopenharmony_ci		 * generate GRXSTS_PKTSTS_OUTDONE for setup packet.
251562306a36Sopenharmony_ci		 */
251662306a36Sopenharmony_ci		if (hsotg->ep0_state == DWC2_EP0_SETUP)
251762306a36Sopenharmony_ci			dwc2_hsotg_handle_outdone(hsotg, epnum);
251862306a36Sopenharmony_ci		break;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	case GRXSTS_PKTSTS_OUTRX:
252162306a36Sopenharmony_ci		dwc2_hsotg_rx_data(hsotg, epnum, size);
252262306a36Sopenharmony_ci		break;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	case GRXSTS_PKTSTS_SETUPRX:
252562306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
252662306a36Sopenharmony_ci			"SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
252762306a36Sopenharmony_ci			dwc2_hsotg_read_frameno(hsotg),
252862306a36Sopenharmony_ci			dwc2_readl(hsotg, DOEPCTL(0)));
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci		WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP);
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci		dwc2_hsotg_rx_data(hsotg, epnum, size);
253362306a36Sopenharmony_ci		break;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	default:
253662306a36Sopenharmony_ci		dev_warn(hsotg->dev, "%s: unknown status %08x\n",
253762306a36Sopenharmony_ci			 __func__, grxstsr);
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci		dwc2_hsotg_dump(hsotg);
254062306a36Sopenharmony_ci		break;
254162306a36Sopenharmony_ci	}
254262306a36Sopenharmony_ci}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci/**
254562306a36Sopenharmony_ci * dwc2_hsotg_ep0_mps - turn max packet size into register setting
254662306a36Sopenharmony_ci * @mps: The maximum packet size in bytes.
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_cistatic u32 dwc2_hsotg_ep0_mps(unsigned int mps)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	switch (mps) {
255162306a36Sopenharmony_ci	case 64:
255262306a36Sopenharmony_ci		return D0EPCTL_MPS_64;
255362306a36Sopenharmony_ci	case 32:
255462306a36Sopenharmony_ci		return D0EPCTL_MPS_32;
255562306a36Sopenharmony_ci	case 16:
255662306a36Sopenharmony_ci		return D0EPCTL_MPS_16;
255762306a36Sopenharmony_ci	case 8:
255862306a36Sopenharmony_ci		return D0EPCTL_MPS_8;
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	/* bad max packet size, warn and return invalid result */
256262306a36Sopenharmony_ci	WARN_ON(1);
256362306a36Sopenharmony_ci	return (u32)-1;
256462306a36Sopenharmony_ci}
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci/**
256762306a36Sopenharmony_ci * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field
256862306a36Sopenharmony_ci * @hsotg: The driver state.
256962306a36Sopenharmony_ci * @ep: The index number of the endpoint
257062306a36Sopenharmony_ci * @mps: The maximum packet size in bytes
257162306a36Sopenharmony_ci * @mc: The multicount value
257262306a36Sopenharmony_ci * @dir_in: True if direction is in.
257362306a36Sopenharmony_ci *
257462306a36Sopenharmony_ci * Configure the maximum packet size for the given endpoint, updating
257562306a36Sopenharmony_ci * the hardware control registers to reflect this.
257662306a36Sopenharmony_ci */
257762306a36Sopenharmony_cistatic void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
257862306a36Sopenharmony_ci					unsigned int ep, unsigned int mps,
257962306a36Sopenharmony_ci					unsigned int mc, unsigned int dir_in)
258062306a36Sopenharmony_ci{
258162306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep;
258262306a36Sopenharmony_ci	u32 reg;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	hs_ep = index_to_ep(hsotg, ep, dir_in);
258562306a36Sopenharmony_ci	if (!hs_ep)
258662306a36Sopenharmony_ci		return;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	if (ep == 0) {
258962306a36Sopenharmony_ci		u32 mps_bytes = mps;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci		/* EP0 is a special case */
259262306a36Sopenharmony_ci		mps = dwc2_hsotg_ep0_mps(mps_bytes);
259362306a36Sopenharmony_ci		if (mps > 3)
259462306a36Sopenharmony_ci			goto bad_mps;
259562306a36Sopenharmony_ci		hs_ep->ep.maxpacket = mps_bytes;
259662306a36Sopenharmony_ci		hs_ep->mc = 1;
259762306a36Sopenharmony_ci	} else {
259862306a36Sopenharmony_ci		if (mps > 1024)
259962306a36Sopenharmony_ci			goto bad_mps;
260062306a36Sopenharmony_ci		hs_ep->mc = mc;
260162306a36Sopenharmony_ci		if (mc > 3)
260262306a36Sopenharmony_ci			goto bad_mps;
260362306a36Sopenharmony_ci		hs_ep->ep.maxpacket = mps;
260462306a36Sopenharmony_ci	}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	if (dir_in) {
260762306a36Sopenharmony_ci		reg = dwc2_readl(hsotg, DIEPCTL(ep));
260862306a36Sopenharmony_ci		reg &= ~DXEPCTL_MPS_MASK;
260962306a36Sopenharmony_ci		reg |= mps;
261062306a36Sopenharmony_ci		dwc2_writel(hsotg, reg, DIEPCTL(ep));
261162306a36Sopenharmony_ci	} else {
261262306a36Sopenharmony_ci		reg = dwc2_readl(hsotg, DOEPCTL(ep));
261362306a36Sopenharmony_ci		reg &= ~DXEPCTL_MPS_MASK;
261462306a36Sopenharmony_ci		reg |= mps;
261562306a36Sopenharmony_ci		dwc2_writel(hsotg, reg, DOEPCTL(ep));
261662306a36Sopenharmony_ci	}
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	return;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_cibad_mps:
262162306a36Sopenharmony_ci	dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps);
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci/**
262562306a36Sopenharmony_ci * dwc2_hsotg_txfifo_flush - flush Tx FIFO
262662306a36Sopenharmony_ci * @hsotg: The driver state
262762306a36Sopenharmony_ci * @idx: The index for the endpoint (0..15)
262862306a36Sopenharmony_ci */
262962306a36Sopenharmony_cistatic void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx)
263062306a36Sopenharmony_ci{
263162306a36Sopenharmony_ci	dwc2_writel(hsotg, GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH,
263262306a36Sopenharmony_ci		    GRSTCTL);
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	/* wait until the fifo is flushed */
263562306a36Sopenharmony_ci	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100))
263662306a36Sopenharmony_ci		dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n",
263762306a36Sopenharmony_ci			 __func__);
263862306a36Sopenharmony_ci}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci/**
264162306a36Sopenharmony_ci * dwc2_hsotg_trytx - check to see if anything needs transmitting
264262306a36Sopenharmony_ci * @hsotg: The driver state
264362306a36Sopenharmony_ci * @hs_ep: The driver endpoint to check.
264462306a36Sopenharmony_ci *
264562306a36Sopenharmony_ci * Check to see if there is a request that has data to send, and if so
264662306a36Sopenharmony_ci * make an attempt to write data into the FIFO.
264762306a36Sopenharmony_ci */
264862306a36Sopenharmony_cistatic int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg,
264962306a36Sopenharmony_ci			    struct dwc2_hsotg_ep *hs_ep)
265062306a36Sopenharmony_ci{
265162306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = hs_ep->req;
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	if (!hs_ep->dir_in || !hs_req) {
265462306a36Sopenharmony_ci		/**
265562306a36Sopenharmony_ci		 * if request is not enqueued, we disable interrupts
265662306a36Sopenharmony_ci		 * for endpoints, excepting ep0
265762306a36Sopenharmony_ci		 */
265862306a36Sopenharmony_ci		if (hs_ep->index != 0)
265962306a36Sopenharmony_ci			dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index,
266062306a36Sopenharmony_ci					      hs_ep->dir_in, 0);
266162306a36Sopenharmony_ci		return 0;
266262306a36Sopenharmony_ci	}
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	if (hs_req->req.actual < hs_req->req.length) {
266562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "trying to write more for ep%d\n",
266662306a36Sopenharmony_ci			hs_ep->index);
266762306a36Sopenharmony_ci		return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req);
266862306a36Sopenharmony_ci	}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	return 0;
267162306a36Sopenharmony_ci}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci/**
267462306a36Sopenharmony_ci * dwc2_hsotg_complete_in - complete IN transfer
267562306a36Sopenharmony_ci * @hsotg: The device state.
267662306a36Sopenharmony_ci * @hs_ep: The endpoint that has just completed.
267762306a36Sopenharmony_ci *
267862306a36Sopenharmony_ci * An IN transfer has been completed, update the transfer's state and then
267962306a36Sopenharmony_ci * call the relevant completion routines.
268062306a36Sopenharmony_ci */
268162306a36Sopenharmony_cistatic void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg,
268262306a36Sopenharmony_ci				   struct dwc2_hsotg_ep *hs_ep)
268362306a36Sopenharmony_ci{
268462306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = hs_ep->req;
268562306a36Sopenharmony_ci	u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index));
268662306a36Sopenharmony_ci	int size_left, size_done;
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	if (!hs_req) {
268962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "XferCompl but no req\n");
269062306a36Sopenharmony_ci		return;
269162306a36Sopenharmony_ci	}
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	/* Finish ZLP handling for IN EP0 transactions */
269462306a36Sopenharmony_ci	if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) {
269562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "zlp packet sent\n");
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci		/*
269862306a36Sopenharmony_ci		 * While send zlp for DWC2_EP0_STATUS_IN EP direction was
269962306a36Sopenharmony_ci		 * changed to IN. Change back to complete OUT transfer request
270062306a36Sopenharmony_ci		 */
270162306a36Sopenharmony_ci		hs_ep->dir_in = 0;
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
270462306a36Sopenharmony_ci		if (hsotg->test_mode) {
270562306a36Sopenharmony_ci			int ret;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci			ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode);
270862306a36Sopenharmony_ci			if (ret < 0) {
270962306a36Sopenharmony_ci				dev_dbg(hsotg->dev, "Invalid Test #%d\n",
271062306a36Sopenharmony_ci					hsotg->test_mode);
271162306a36Sopenharmony_ci				dwc2_hsotg_stall_ep0(hsotg);
271262306a36Sopenharmony_ci				return;
271362306a36Sopenharmony_ci			}
271462306a36Sopenharmony_ci		}
271562306a36Sopenharmony_ci		dwc2_hsotg_enqueue_setup(hsotg);
271662306a36Sopenharmony_ci		return;
271762306a36Sopenharmony_ci	}
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	/*
272062306a36Sopenharmony_ci	 * Calculate the size of the transfer by checking how much is left
272162306a36Sopenharmony_ci	 * in the endpoint size register and then working it out from
272262306a36Sopenharmony_ci	 * the amount we loaded for the transfer.
272362306a36Sopenharmony_ci	 *
272462306a36Sopenharmony_ci	 * We do this even for DMA, as the transfer may have incremented
272562306a36Sopenharmony_ci	 * past the end of the buffer (DMA transfers are always 32bit
272662306a36Sopenharmony_ci	 * aligned).
272762306a36Sopenharmony_ci	 */
272862306a36Sopenharmony_ci	if (using_desc_dma(hsotg)) {
272962306a36Sopenharmony_ci		size_left = dwc2_gadget_get_xfersize_ddma(hs_ep);
273062306a36Sopenharmony_ci		if (size_left < 0)
273162306a36Sopenharmony_ci			dev_err(hsotg->dev, "error parsing DDMA results %d\n",
273262306a36Sopenharmony_ci				size_left);
273362306a36Sopenharmony_ci	} else {
273462306a36Sopenharmony_ci		size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
273562306a36Sopenharmony_ci	}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	size_done = hs_ep->size_loaded - size_left;
273862306a36Sopenharmony_ci	size_done += hs_ep->last_load;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	if (hs_req->req.actual != size_done)
274162306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n",
274262306a36Sopenharmony_ci			__func__, hs_req->req.actual, size_done);
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	hs_req->req.actual = size_done;
274562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
274662306a36Sopenharmony_ci		hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	if (!size_left && hs_req->req.actual < hs_req->req.length) {
274962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
275062306a36Sopenharmony_ci		dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true);
275162306a36Sopenharmony_ci		return;
275262306a36Sopenharmony_ci	}
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	/* Zlp for all endpoints in non DDMA, for ep0 only in DATA IN stage */
275562306a36Sopenharmony_ci	if (hs_ep->send_zlp) {
275662306a36Sopenharmony_ci		hs_ep->send_zlp = 0;
275762306a36Sopenharmony_ci		if (!using_desc_dma(hsotg)) {
275862306a36Sopenharmony_ci			dwc2_hsotg_program_zlp(hsotg, hs_ep);
275962306a36Sopenharmony_ci			/* transfer will be completed on next complete interrupt */
276062306a36Sopenharmony_ci			return;
276162306a36Sopenharmony_ci		}
276262306a36Sopenharmony_ci	}
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) {
276562306a36Sopenharmony_ci		/* Move to STATUS OUT */
276662306a36Sopenharmony_ci		dwc2_hsotg_ep0_zlp(hsotg, false);
276762306a36Sopenharmony_ci		return;
276862306a36Sopenharmony_ci	}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	/* Set actual frame number for completed transfers */
277162306a36Sopenharmony_ci	if (!using_desc_dma(hsotg) && hs_ep->isochronous) {
277262306a36Sopenharmony_ci		hs_req->req.frame_number = hs_ep->target_frame;
277362306a36Sopenharmony_ci		dwc2_gadget_incr_frame_num(hs_ep);
277462306a36Sopenharmony_ci	}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
277762306a36Sopenharmony_ci}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci/**
278062306a36Sopenharmony_ci * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep
278162306a36Sopenharmony_ci * @hsotg: The device state.
278262306a36Sopenharmony_ci * @idx: Index of ep.
278362306a36Sopenharmony_ci * @dir_in: Endpoint direction 1-in 0-out.
278462306a36Sopenharmony_ci *
278562306a36Sopenharmony_ci * Reads for endpoint with given index and direction, by masking
278662306a36Sopenharmony_ci * epint_reg with coresponding mask.
278762306a36Sopenharmony_ci */
278862306a36Sopenharmony_cistatic u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg,
278962306a36Sopenharmony_ci					  unsigned int idx, int dir_in)
279062306a36Sopenharmony_ci{
279162306a36Sopenharmony_ci	u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK;
279262306a36Sopenharmony_ci	u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
279362306a36Sopenharmony_ci	u32 ints;
279462306a36Sopenharmony_ci	u32 mask;
279562306a36Sopenharmony_ci	u32 diepempmsk;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	mask = dwc2_readl(hsotg, epmsk_reg);
279862306a36Sopenharmony_ci	diepempmsk = dwc2_readl(hsotg, DIEPEMPMSK);
279962306a36Sopenharmony_ci	mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0;
280062306a36Sopenharmony_ci	mask |= DXEPINT_SETUP_RCVD;
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	ints = dwc2_readl(hsotg, epint_reg);
280362306a36Sopenharmony_ci	ints &= mask;
280462306a36Sopenharmony_ci	return ints;
280562306a36Sopenharmony_ci}
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci/**
280862306a36Sopenharmony_ci * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD
280962306a36Sopenharmony_ci * @hs_ep: The endpoint on which interrupt is asserted.
281062306a36Sopenharmony_ci *
281162306a36Sopenharmony_ci * This interrupt indicates that the endpoint has been disabled per the
281262306a36Sopenharmony_ci * application's request.
281362306a36Sopenharmony_ci *
281462306a36Sopenharmony_ci * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK,
281562306a36Sopenharmony_ci * in case of ISOC completes current request.
281662306a36Sopenharmony_ci *
281762306a36Sopenharmony_ci * For ISOC-OUT endpoints completes expired requests. If there is remaining
281862306a36Sopenharmony_ci * request starts it.
281962306a36Sopenharmony_ci */
282062306a36Sopenharmony_cistatic void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
282362306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req;
282462306a36Sopenharmony_ci	unsigned char idx = hs_ep->index;
282562306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
282662306a36Sopenharmony_ci	u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
282762306a36Sopenharmony_ci	int dctl = dwc2_readl(hsotg, DCTL);
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	if (dir_in) {
283262306a36Sopenharmony_ci		int epctl = dwc2_readl(hsotg, epctl_reg);
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci		dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci		if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) {
283762306a36Sopenharmony_ci			int dctl = dwc2_readl(hsotg, DCTL);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci			dctl |= DCTL_CGNPINNAK;
284062306a36Sopenharmony_ci			dwc2_writel(hsotg, dctl, DCTL);
284162306a36Sopenharmony_ci		}
284262306a36Sopenharmony_ci	} else {
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci		if (dctl & DCTL_GOUTNAKSTS) {
284562306a36Sopenharmony_ci			dctl |= DCTL_CGOUTNAK;
284662306a36Sopenharmony_ci			dwc2_writel(hsotg, dctl, DCTL);
284762306a36Sopenharmony_ci		}
284862306a36Sopenharmony_ci	}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	if (!hs_ep->isochronous)
285162306a36Sopenharmony_ci		return;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	if (list_empty(&hs_ep->queue)) {
285462306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n",
285562306a36Sopenharmony_ci			__func__, hs_ep);
285662306a36Sopenharmony_ci		return;
285762306a36Sopenharmony_ci	}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	do {
286062306a36Sopenharmony_ci		hs_req = get_ep_head(hs_ep);
286162306a36Sopenharmony_ci		if (hs_req) {
286262306a36Sopenharmony_ci			hs_req->req.frame_number = hs_ep->target_frame;
286362306a36Sopenharmony_ci			hs_req->req.actual = 0;
286462306a36Sopenharmony_ci			dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
286562306a36Sopenharmony_ci						    -ENODATA);
286662306a36Sopenharmony_ci		}
286762306a36Sopenharmony_ci		dwc2_gadget_incr_frame_num(hs_ep);
286862306a36Sopenharmony_ci		/* Update current frame number value. */
286962306a36Sopenharmony_ci		hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg);
287062306a36Sopenharmony_ci	} while (dwc2_gadget_target_frame_elapsed(hs_ep));
287162306a36Sopenharmony_ci}
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci/**
287462306a36Sopenharmony_ci * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS
287562306a36Sopenharmony_ci * @ep: The endpoint on which interrupt is asserted.
287662306a36Sopenharmony_ci *
287762306a36Sopenharmony_ci * This is starting point for ISOC-OUT transfer, synchronization done with
287862306a36Sopenharmony_ci * first out token received from host while corresponding EP is disabled.
287962306a36Sopenharmony_ci *
288062306a36Sopenharmony_ci * Device does not know initial frame in which out token will come. For this
288162306a36Sopenharmony_ci * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon
288262306a36Sopenharmony_ci * getting this interrupt SW starts calculation for next transfer frame.
288362306a36Sopenharmony_ci */
288462306a36Sopenharmony_cistatic void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
288562306a36Sopenharmony_ci{
288662306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = ep->parent;
288762306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req;
288862306a36Sopenharmony_ci	int dir_in = ep->dir_in;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	if (dir_in || !ep->isochronous)
289162306a36Sopenharmony_ci		return;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	if (using_desc_dma(hsotg)) {
289462306a36Sopenharmony_ci		if (ep->target_frame == TARGET_FRAME_INITIAL) {
289562306a36Sopenharmony_ci			/* Start first ISO Out */
289662306a36Sopenharmony_ci			ep->target_frame = hsotg->frame_number;
289762306a36Sopenharmony_ci			dwc2_gadget_start_isoc_ddma(ep);
289862306a36Sopenharmony_ci		}
289962306a36Sopenharmony_ci		return;
290062306a36Sopenharmony_ci	}
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	if (ep->target_frame == TARGET_FRAME_INITIAL) {
290362306a36Sopenharmony_ci		u32 ctrl;
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci		ep->target_frame = hsotg->frame_number;
290662306a36Sopenharmony_ci		if (ep->interval > 1) {
290762306a36Sopenharmony_ci			ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index));
290862306a36Sopenharmony_ci			if (ep->target_frame & 0x1)
290962306a36Sopenharmony_ci				ctrl |= DXEPCTL_SETODDFR;
291062306a36Sopenharmony_ci			else
291162306a36Sopenharmony_ci				ctrl |= DXEPCTL_SETEVENFR;
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci			dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index));
291462306a36Sopenharmony_ci		}
291562306a36Sopenharmony_ci	}
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	while (dwc2_gadget_target_frame_elapsed(ep)) {
291862306a36Sopenharmony_ci		hs_req = get_ep_head(ep);
291962306a36Sopenharmony_ci		if (hs_req) {
292062306a36Sopenharmony_ci			hs_req->req.frame_number = ep->target_frame;
292162306a36Sopenharmony_ci			hs_req->req.actual = 0;
292262306a36Sopenharmony_ci			dwc2_hsotg_complete_request(hsotg, ep, hs_req, -ENODATA);
292362306a36Sopenharmony_ci		}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci		dwc2_gadget_incr_frame_num(ep);
292662306a36Sopenharmony_ci		/* Update current frame number value. */
292762306a36Sopenharmony_ci		hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg);
292862306a36Sopenharmony_ci	}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	if (!ep->req)
293162306a36Sopenharmony_ci		dwc2_gadget_start_next_request(ep);
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci}
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_cistatic void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
293662306a36Sopenharmony_ci				   struct dwc2_hsotg_ep *hs_ep);
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci/**
293962306a36Sopenharmony_ci * dwc2_gadget_handle_nak - handle NAK interrupt
294062306a36Sopenharmony_ci * @hs_ep: The endpoint on which interrupt is asserted.
294162306a36Sopenharmony_ci *
294262306a36Sopenharmony_ci * This is starting point for ISOC-IN transfer, synchronization done with
294362306a36Sopenharmony_ci * first IN token received from host while corresponding EP is disabled.
294462306a36Sopenharmony_ci *
294562306a36Sopenharmony_ci * Device does not know when first one token will arrive from host. On first
294662306a36Sopenharmony_ci * token arrival HW generates 2 interrupts: 'in token received while FIFO empty'
294762306a36Sopenharmony_ci * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was
294862306a36Sopenharmony_ci * sent in response to that as there was no data in FIFO. SW is basing on this
294962306a36Sopenharmony_ci * interrupt to obtain frame in which token has come and then based on the
295062306a36Sopenharmony_ci * interval calculates next frame for transfer.
295162306a36Sopenharmony_ci */
295262306a36Sopenharmony_cistatic void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
295362306a36Sopenharmony_ci{
295462306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
295562306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req;
295662306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
295762306a36Sopenharmony_ci	u32 ctrl;
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	if (!dir_in || !hs_ep->isochronous)
296062306a36Sopenharmony_ci		return;
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	if (hs_ep->target_frame == TARGET_FRAME_INITIAL) {
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci		if (using_desc_dma(hsotg)) {
296562306a36Sopenharmony_ci			hs_ep->target_frame = hsotg->frame_number;
296662306a36Sopenharmony_ci			dwc2_gadget_incr_frame_num(hs_ep);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci			/* In service interval mode target_frame must
296962306a36Sopenharmony_ci			 * be set to last (u)frame of the service interval.
297062306a36Sopenharmony_ci			 */
297162306a36Sopenharmony_ci			if (hsotg->params.service_interval) {
297262306a36Sopenharmony_ci				/* Set target_frame to the first (u)frame of
297362306a36Sopenharmony_ci				 * the service interval
297462306a36Sopenharmony_ci				 */
297562306a36Sopenharmony_ci				hs_ep->target_frame &= ~hs_ep->interval + 1;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci				/* Set target_frame to the last (u)frame of
297862306a36Sopenharmony_ci				 * the service interval
297962306a36Sopenharmony_ci				 */
298062306a36Sopenharmony_ci				dwc2_gadget_incr_frame_num(hs_ep);
298162306a36Sopenharmony_ci				dwc2_gadget_dec_frame_num_by_one(hs_ep);
298262306a36Sopenharmony_ci			}
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci			dwc2_gadget_start_isoc_ddma(hs_ep);
298562306a36Sopenharmony_ci			return;
298662306a36Sopenharmony_ci		}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci		hs_ep->target_frame = hsotg->frame_number;
298962306a36Sopenharmony_ci		if (hs_ep->interval > 1) {
299062306a36Sopenharmony_ci			u32 ctrl = dwc2_readl(hsotg,
299162306a36Sopenharmony_ci					      DIEPCTL(hs_ep->index));
299262306a36Sopenharmony_ci			if (hs_ep->target_frame & 0x1)
299362306a36Sopenharmony_ci				ctrl |= DXEPCTL_SETODDFR;
299462306a36Sopenharmony_ci			else
299562306a36Sopenharmony_ci				ctrl |= DXEPCTL_SETEVENFR;
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci			dwc2_writel(hsotg, ctrl, DIEPCTL(hs_ep->index));
299862306a36Sopenharmony_ci		}
299962306a36Sopenharmony_ci	}
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	if (using_desc_dma(hsotg))
300262306a36Sopenharmony_ci		return;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	ctrl = dwc2_readl(hsotg, DIEPCTL(hs_ep->index));
300562306a36Sopenharmony_ci	if (ctrl & DXEPCTL_EPENA)
300662306a36Sopenharmony_ci		dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
300762306a36Sopenharmony_ci	else
300862306a36Sopenharmony_ci		dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	while (dwc2_gadget_target_frame_elapsed(hs_ep)) {
301162306a36Sopenharmony_ci		hs_req = get_ep_head(hs_ep);
301262306a36Sopenharmony_ci		if (hs_req) {
301362306a36Sopenharmony_ci			hs_req->req.frame_number = hs_ep->target_frame;
301462306a36Sopenharmony_ci			hs_req->req.actual = 0;
301562306a36Sopenharmony_ci			dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA);
301662306a36Sopenharmony_ci		}
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci		dwc2_gadget_incr_frame_num(hs_ep);
301962306a36Sopenharmony_ci		/* Update current frame number value. */
302062306a36Sopenharmony_ci		hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg);
302162306a36Sopenharmony_ci	}
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	if (!hs_ep->req)
302462306a36Sopenharmony_ci		dwc2_gadget_start_next_request(hs_ep);
302562306a36Sopenharmony_ci}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci/**
302862306a36Sopenharmony_ci * dwc2_hsotg_epint - handle an in/out endpoint interrupt
302962306a36Sopenharmony_ci * @hsotg: The driver state
303062306a36Sopenharmony_ci * @idx: The index for the endpoint (0..15)
303162306a36Sopenharmony_ci * @dir_in: Set if this is an IN endpoint
303262306a36Sopenharmony_ci *
303362306a36Sopenharmony_ci * Process and clear any interrupt pending for an individual endpoint
303462306a36Sopenharmony_ci */
303562306a36Sopenharmony_cistatic void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
303662306a36Sopenharmony_ci			     int dir_in)
303762306a36Sopenharmony_ci{
303862306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in);
303962306a36Sopenharmony_ci	u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
304062306a36Sopenharmony_ci	u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
304162306a36Sopenharmony_ci	u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
304262306a36Sopenharmony_ci	u32 ints;
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in);
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	/* Clear endpoint interrupts */
304762306a36Sopenharmony_ci	dwc2_writel(hsotg, ints, epint_reg);
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	if (!hs_ep) {
305062306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n",
305162306a36Sopenharmony_ci			__func__, idx, dir_in ? "in" : "out");
305262306a36Sopenharmony_ci		return;
305362306a36Sopenharmony_ci	}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
305662306a36Sopenharmony_ci		__func__, idx, dir_in ? "in" : "out", ints);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	/* Don't process XferCompl interrupt if it is a setup packet */
305962306a36Sopenharmony_ci	if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
306062306a36Sopenharmony_ci		ints &= ~DXEPINT_XFERCOMPL;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	/*
306362306a36Sopenharmony_ci	 * Don't process XferCompl interrupt in DDMA if EP0 is still in SETUP
306462306a36Sopenharmony_ci	 * stage and xfercomplete was generated without SETUP phase done
306562306a36Sopenharmony_ci	 * interrupt. SW should parse received setup packet only after host's
306662306a36Sopenharmony_ci	 * exit from setup phase of control transfer.
306762306a36Sopenharmony_ci	 */
306862306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && idx == 0 && !hs_ep->dir_in &&
306962306a36Sopenharmony_ci	    hsotg->ep0_state == DWC2_EP0_SETUP && !(ints & DXEPINT_SETUP))
307062306a36Sopenharmony_ci		ints &= ~DXEPINT_XFERCOMPL;
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	if (ints & DXEPINT_XFERCOMPL) {
307362306a36Sopenharmony_ci		dev_dbg(hsotg->dev,
307462306a36Sopenharmony_ci			"%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
307562306a36Sopenharmony_ci			__func__, dwc2_readl(hsotg, epctl_reg),
307662306a36Sopenharmony_ci			dwc2_readl(hsotg, epsiz_reg));
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci		/* In DDMA handle isochronous requests separately */
307962306a36Sopenharmony_ci		if (using_desc_dma(hsotg) && hs_ep->isochronous) {
308062306a36Sopenharmony_ci			dwc2_gadget_complete_isoc_request_ddma(hs_ep);
308162306a36Sopenharmony_ci		} else if (dir_in) {
308262306a36Sopenharmony_ci			/*
308362306a36Sopenharmony_ci			 * We get OutDone from the FIFO, so we only
308462306a36Sopenharmony_ci			 * need to look at completing IN requests here
308562306a36Sopenharmony_ci			 * if operating slave mode
308662306a36Sopenharmony_ci			 */
308762306a36Sopenharmony_ci			if (!hs_ep->isochronous || !(ints & DXEPINT_NAKINTRPT))
308862306a36Sopenharmony_ci				dwc2_hsotg_complete_in(hsotg, hs_ep);
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci			if (idx == 0 && !hs_ep->req)
309162306a36Sopenharmony_ci				dwc2_hsotg_enqueue_setup(hsotg);
309262306a36Sopenharmony_ci		} else if (using_dma(hsotg)) {
309362306a36Sopenharmony_ci			/*
309462306a36Sopenharmony_ci			 * We're using DMA, we need to fire an OutDone here
309562306a36Sopenharmony_ci			 * as we ignore the RXFIFO.
309662306a36Sopenharmony_ci			 */
309762306a36Sopenharmony_ci			if (!hs_ep->isochronous || !(ints & DXEPINT_OUTTKNEPDIS))
309862306a36Sopenharmony_ci				dwc2_hsotg_handle_outdone(hsotg, idx);
309962306a36Sopenharmony_ci		}
310062306a36Sopenharmony_ci	}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	if (ints & DXEPINT_EPDISBLD)
310362306a36Sopenharmony_ci		dwc2_gadget_handle_ep_disabled(hs_ep);
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	if (ints & DXEPINT_OUTTKNEPDIS)
310662306a36Sopenharmony_ci		dwc2_gadget_handle_out_token_ep_disabled(hs_ep);
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	if (ints & DXEPINT_NAKINTRPT)
310962306a36Sopenharmony_ci		dwc2_gadget_handle_nak(hs_ep);
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	if (ints & DXEPINT_AHBERR)
311262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	if (ints & DXEPINT_SETUP) {  /* Setup or Timeout */
311562306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: Setup/Timeout\n",  __func__);
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci		if (using_dma(hsotg) && idx == 0) {
311862306a36Sopenharmony_ci			/*
311962306a36Sopenharmony_ci			 * this is the notification we've received a
312062306a36Sopenharmony_ci			 * setup packet. In non-DMA mode we'd get this
312162306a36Sopenharmony_ci			 * from the RXFIFO, instead we need to process
312262306a36Sopenharmony_ci			 * the setup here.
312362306a36Sopenharmony_ci			 */
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci			if (dir_in)
312662306a36Sopenharmony_ci				WARN_ON_ONCE(1);
312762306a36Sopenharmony_ci			else
312862306a36Sopenharmony_ci				dwc2_hsotg_handle_outdone(hsotg, 0);
312962306a36Sopenharmony_ci		}
313062306a36Sopenharmony_ci	}
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	if (ints & DXEPINT_STSPHSERCVD) {
313362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__);
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci		/* Safety check EP0 state when STSPHSERCVD asserted */
313662306a36Sopenharmony_ci		if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
313762306a36Sopenharmony_ci			/* Move to STATUS IN for DDMA */
313862306a36Sopenharmony_ci			if (using_desc_dma(hsotg)) {
313962306a36Sopenharmony_ci				if (!hsotg->delayed_status)
314062306a36Sopenharmony_ci					dwc2_hsotg_ep0_zlp(hsotg, true);
314162306a36Sopenharmony_ci				else
314262306a36Sopenharmony_ci				/* In case of 3 stage Control Write with delayed
314362306a36Sopenharmony_ci				 * status, when Status IN transfer started
314462306a36Sopenharmony_ci				 * before STSPHSERCVD asserted, NAKSTS bit not
314562306a36Sopenharmony_ci				 * cleared by CNAK in dwc2_hsotg_start_req()
314662306a36Sopenharmony_ci				 * function. Clear now NAKSTS to allow complete
314762306a36Sopenharmony_ci				 * transfer.
314862306a36Sopenharmony_ci				 */
314962306a36Sopenharmony_ci					dwc2_set_bit(hsotg, DIEPCTL(0),
315062306a36Sopenharmony_ci						     DXEPCTL_CNAK);
315162306a36Sopenharmony_ci			}
315262306a36Sopenharmony_ci		}
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	if (ints & DXEPINT_BACK2BACKSETUP)
315762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	if (ints & DXEPINT_BNAINTR) {
316062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__);
316162306a36Sopenharmony_ci		if (hs_ep->isochronous)
316262306a36Sopenharmony_ci			dwc2_gadget_handle_isoc_bna(hs_ep);
316362306a36Sopenharmony_ci	}
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	if (dir_in && !hs_ep->isochronous) {
316662306a36Sopenharmony_ci		/* not sure if this is important, but we'll clear it anyway */
316762306a36Sopenharmony_ci		if (ints & DXEPINT_INTKNTXFEMP) {
316862306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
316962306a36Sopenharmony_ci				__func__, idx);
317062306a36Sopenharmony_ci		}
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci		/* this probably means something bad is happening */
317362306a36Sopenharmony_ci		if (ints & DXEPINT_INTKNEPMIS) {
317462306a36Sopenharmony_ci			dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
317562306a36Sopenharmony_ci				 __func__, idx);
317662306a36Sopenharmony_ci		}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci		/* FIFO has space or is empty (see GAHBCFG) */
317962306a36Sopenharmony_ci		if (hsotg->dedicated_fifos &&
318062306a36Sopenharmony_ci		    ints & DXEPINT_TXFEMP) {
318162306a36Sopenharmony_ci			dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
318262306a36Sopenharmony_ci				__func__, idx);
318362306a36Sopenharmony_ci			if (!using_dma(hsotg))
318462306a36Sopenharmony_ci				dwc2_hsotg_trytx(hsotg, hs_ep);
318562306a36Sopenharmony_ci		}
318662306a36Sopenharmony_ci	}
318762306a36Sopenharmony_ci}
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci/**
319062306a36Sopenharmony_ci * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done)
319162306a36Sopenharmony_ci * @hsotg: The device state.
319262306a36Sopenharmony_ci *
319362306a36Sopenharmony_ci * Handle updating the device settings after the enumeration phase has
319462306a36Sopenharmony_ci * been completed.
319562306a36Sopenharmony_ci */
319662306a36Sopenharmony_cistatic void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
319762306a36Sopenharmony_ci{
319862306a36Sopenharmony_ci	u32 dsts = dwc2_readl(hsotg, DSTS);
319962306a36Sopenharmony_ci	int ep0_mps = 0, ep_mps = 8;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	/*
320262306a36Sopenharmony_ci	 * This should signal the finish of the enumeration phase
320362306a36Sopenharmony_ci	 * of the USB handshaking, so we should now know what rate
320462306a36Sopenharmony_ci	 * we connected at.
320562306a36Sopenharmony_ci	 */
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts);
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	/*
321062306a36Sopenharmony_ci	 * note, since we're limited by the size of transfer on EP0, and
321162306a36Sopenharmony_ci	 * it seems IN transfers must be a even number of packets we do
321262306a36Sopenharmony_ci	 * not advertise a 64byte MPS on EP0.
321362306a36Sopenharmony_ci	 */
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	/* catch both EnumSpd_FS and EnumSpd_FS48 */
321662306a36Sopenharmony_ci	switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) {
321762306a36Sopenharmony_ci	case DSTS_ENUMSPD_FS:
321862306a36Sopenharmony_ci	case DSTS_ENUMSPD_FS48:
321962306a36Sopenharmony_ci		hsotg->gadget.speed = USB_SPEED_FULL;
322062306a36Sopenharmony_ci		ep0_mps = EP0_MPS_LIMIT;
322162306a36Sopenharmony_ci		ep_mps = 1023;
322262306a36Sopenharmony_ci		break;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	case DSTS_ENUMSPD_HS:
322562306a36Sopenharmony_ci		hsotg->gadget.speed = USB_SPEED_HIGH;
322662306a36Sopenharmony_ci		ep0_mps = EP0_MPS_LIMIT;
322762306a36Sopenharmony_ci		ep_mps = 1024;
322862306a36Sopenharmony_ci		break;
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	case DSTS_ENUMSPD_LS:
323162306a36Sopenharmony_ci		hsotg->gadget.speed = USB_SPEED_LOW;
323262306a36Sopenharmony_ci		ep0_mps = 8;
323362306a36Sopenharmony_ci		ep_mps = 8;
323462306a36Sopenharmony_ci		/*
323562306a36Sopenharmony_ci		 * note, we don't actually support LS in this driver at the
323662306a36Sopenharmony_ci		 * moment, and the documentation seems to imply that it isn't
323762306a36Sopenharmony_ci		 * supported by the PHYs on some of the devices.
323862306a36Sopenharmony_ci		 */
323962306a36Sopenharmony_ci		break;
324062306a36Sopenharmony_ci	}
324162306a36Sopenharmony_ci	dev_info(hsotg->dev, "new device is %s\n",
324262306a36Sopenharmony_ci		 usb_speed_string(hsotg->gadget.speed));
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	/*
324562306a36Sopenharmony_ci	 * we should now know the maximum packet size for an
324662306a36Sopenharmony_ci	 * endpoint, so set the endpoints to a default value.
324762306a36Sopenharmony_ci	 */
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	if (ep0_mps) {
325062306a36Sopenharmony_ci		int i;
325162306a36Sopenharmony_ci		/* Initialize ep0 for both in and out directions */
325262306a36Sopenharmony_ci		dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1);
325362306a36Sopenharmony_ci		dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0);
325462306a36Sopenharmony_ci		for (i = 1; i < hsotg->num_of_eps; i++) {
325562306a36Sopenharmony_ci			if (hsotg->eps_in[i])
325662306a36Sopenharmony_ci				dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps,
325762306a36Sopenharmony_ci							    0, 1);
325862306a36Sopenharmony_ci			if (hsotg->eps_out[i])
325962306a36Sopenharmony_ci				dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps,
326062306a36Sopenharmony_ci							    0, 0);
326162306a36Sopenharmony_ci		}
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	/* ensure after enumeration our EP0 is active */
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	dwc2_hsotg_enqueue_setup(hsotg);
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
326962306a36Sopenharmony_ci		dwc2_readl(hsotg, DIEPCTL0),
327062306a36Sopenharmony_ci		dwc2_readl(hsotg, DOEPCTL0));
327162306a36Sopenharmony_ci}
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci/**
327462306a36Sopenharmony_ci * kill_all_requests - remove all requests from the endpoint's queue
327562306a36Sopenharmony_ci * @hsotg: The device state.
327662306a36Sopenharmony_ci * @ep: The endpoint the requests may be on.
327762306a36Sopenharmony_ci * @result: The result code to use.
327862306a36Sopenharmony_ci *
327962306a36Sopenharmony_ci * Go through the requests on the given endpoint and mark them
328062306a36Sopenharmony_ci * completed with the given result code.
328162306a36Sopenharmony_ci */
328262306a36Sopenharmony_cistatic void kill_all_requests(struct dwc2_hsotg *hsotg,
328362306a36Sopenharmony_ci			      struct dwc2_hsotg_ep *ep,
328462306a36Sopenharmony_ci			      int result)
328562306a36Sopenharmony_ci{
328662306a36Sopenharmony_ci	unsigned int size;
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	ep->req = NULL;
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	while (!list_empty(&ep->queue)) {
329162306a36Sopenharmony_ci		struct dwc2_hsotg_req *req = get_ep_head(ep);
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci		dwc2_hsotg_complete_request(hsotg, ep, req, result);
329462306a36Sopenharmony_ci	}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci	if (!hsotg->dedicated_fifos)
329762306a36Sopenharmony_ci		return;
329862306a36Sopenharmony_ci	size = (dwc2_readl(hsotg, DTXFSTS(ep->fifo_index)) & 0xffff) * 4;
329962306a36Sopenharmony_ci	if (size < ep->fifo_size)
330062306a36Sopenharmony_ci		dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
330162306a36Sopenharmony_ci}
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci/**
330462306a36Sopenharmony_ci * dwc2_hsotg_disconnect - disconnect service
330562306a36Sopenharmony_ci * @hsotg: The device state.
330662306a36Sopenharmony_ci *
330762306a36Sopenharmony_ci * The device has been disconnected. Remove all current
330862306a36Sopenharmony_ci * transactions and signal the gadget driver that this
330962306a36Sopenharmony_ci * has happened.
331062306a36Sopenharmony_ci */
331162306a36Sopenharmony_civoid dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
331262306a36Sopenharmony_ci{
331362306a36Sopenharmony_ci	unsigned int ep;
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	if (!hsotg->connected)
331662306a36Sopenharmony_ci		return;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	hsotg->connected = 0;
331962306a36Sopenharmony_ci	hsotg->test_mode = 0;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	/* all endpoints should be shutdown */
332262306a36Sopenharmony_ci	for (ep = 0; ep < hsotg->num_of_eps; ep++) {
332362306a36Sopenharmony_ci		if (hsotg->eps_in[ep])
332462306a36Sopenharmony_ci			kill_all_requests(hsotg, hsotg->eps_in[ep],
332562306a36Sopenharmony_ci					  -ESHUTDOWN);
332662306a36Sopenharmony_ci		if (hsotg->eps_out[ep])
332762306a36Sopenharmony_ci			kill_all_requests(hsotg, hsotg->eps_out[ep],
332862306a36Sopenharmony_ci					  -ESHUTDOWN);
332962306a36Sopenharmony_ci	}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	call_gadget(hsotg, disconnect);
333262306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L3;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED);
333562306a36Sopenharmony_ci}
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci/**
333862306a36Sopenharmony_ci * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler
333962306a36Sopenharmony_ci * @hsotg: The device state:
334062306a36Sopenharmony_ci * @periodic: True if this is a periodic FIFO interrupt
334162306a36Sopenharmony_ci */
334262306a36Sopenharmony_cistatic void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
334362306a36Sopenharmony_ci{
334462306a36Sopenharmony_ci	struct dwc2_hsotg_ep *ep;
334562306a36Sopenharmony_ci	int epno, ret;
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci	/* look through for any more data to transmit */
334862306a36Sopenharmony_ci	for (epno = 0; epno < hsotg->num_of_eps; epno++) {
334962306a36Sopenharmony_ci		ep = index_to_ep(hsotg, epno, 1);
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci		if (!ep)
335262306a36Sopenharmony_ci			continue;
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci		if (!ep->dir_in)
335562306a36Sopenharmony_ci			continue;
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci		if ((periodic && !ep->periodic) ||
335862306a36Sopenharmony_ci		    (!periodic && ep->periodic))
335962306a36Sopenharmony_ci			continue;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci		ret = dwc2_hsotg_trytx(hsotg, ep);
336262306a36Sopenharmony_ci		if (ret < 0)
336362306a36Sopenharmony_ci			break;
336462306a36Sopenharmony_ci	}
336562306a36Sopenharmony_ci}
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci/* IRQ flags which will trigger a retry around the IRQ loop */
336862306a36Sopenharmony_ci#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \
336962306a36Sopenharmony_ci			GINTSTS_PTXFEMP |  \
337062306a36Sopenharmony_ci			GINTSTS_RXFLVL)
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_disable(struct usb_ep *ep);
337362306a36Sopenharmony_ci/**
337462306a36Sopenharmony_ci * dwc2_hsotg_core_init_disconnected - issue softreset to the core
337562306a36Sopenharmony_ci * @hsotg: The device state
337662306a36Sopenharmony_ci * @is_usb_reset: Usb resetting flag
337762306a36Sopenharmony_ci *
337862306a36Sopenharmony_ci * Issue a soft reset to the core, and await the core finishing it.
337962306a36Sopenharmony_ci */
338062306a36Sopenharmony_civoid dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
338162306a36Sopenharmony_ci				       bool is_usb_reset)
338262306a36Sopenharmony_ci{
338362306a36Sopenharmony_ci	u32 intmsk;
338462306a36Sopenharmony_ci	u32 val;
338562306a36Sopenharmony_ci	u32 usbcfg;
338662306a36Sopenharmony_ci	u32 dcfg = 0;
338762306a36Sopenharmony_ci	int ep;
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	/* Kill any ep0 requests as controller will be reinitialized */
339062306a36Sopenharmony_ci	kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	if (!is_usb_reset) {
339362306a36Sopenharmony_ci		if (dwc2_core_reset(hsotg, true))
339462306a36Sopenharmony_ci			return;
339562306a36Sopenharmony_ci	} else {
339662306a36Sopenharmony_ci		/* all endpoints should be shutdown */
339762306a36Sopenharmony_ci		for (ep = 1; ep < hsotg->num_of_eps; ep++) {
339862306a36Sopenharmony_ci			if (hsotg->eps_in[ep])
339962306a36Sopenharmony_ci				dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
340062306a36Sopenharmony_ci			if (hsotg->eps_out[ep])
340162306a36Sopenharmony_ci				dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
340262306a36Sopenharmony_ci		}
340362306a36Sopenharmony_ci	}
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	/*
340662306a36Sopenharmony_ci	 * we must now enable ep0 ready for host detection and then
340762306a36Sopenharmony_ci	 * set configuration.
340862306a36Sopenharmony_ci	 */
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	/* keep other bits untouched (so e.g. forced modes are not lost) */
341162306a36Sopenharmony_ci	usbcfg = dwc2_readl(hsotg, GUSBCFG);
341262306a36Sopenharmony_ci	usbcfg &= ~GUSBCFG_TOUTCAL_MASK;
341362306a36Sopenharmony_ci	usbcfg |= GUSBCFG_TOUTCAL(7);
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	/* remove the HNP/SRP and set the PHY */
341662306a36Sopenharmony_ci	usbcfg &= ~(GUSBCFG_SRPCAP | GUSBCFG_HNPCAP);
341762306a36Sopenharmony_ci        dwc2_writel(hsotg, usbcfg, GUSBCFG);
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	dwc2_phy_init(hsotg, true);
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci	dwc2_hsotg_init_fifo(hsotg);
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	if (!is_usb_reset)
342462306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	dcfg |= DCFG_EPMISCNT(1);
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	switch (hsotg->params.speed) {
342962306a36Sopenharmony_ci	case DWC2_SPEED_PARAM_LOW:
343062306a36Sopenharmony_ci		dcfg |= DCFG_DEVSPD_LS;
343162306a36Sopenharmony_ci		break;
343262306a36Sopenharmony_ci	case DWC2_SPEED_PARAM_FULL:
343362306a36Sopenharmony_ci		if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS)
343462306a36Sopenharmony_ci			dcfg |= DCFG_DEVSPD_FS48;
343562306a36Sopenharmony_ci		else
343662306a36Sopenharmony_ci			dcfg |= DCFG_DEVSPD_FS;
343762306a36Sopenharmony_ci		break;
343862306a36Sopenharmony_ci	default:
343962306a36Sopenharmony_ci		dcfg |= DCFG_DEVSPD_HS;
344062306a36Sopenharmony_ci	}
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_ci	if (hsotg->params.ipg_isoc_en)
344362306a36Sopenharmony_ci		dcfg |= DCFG_IPG_ISOC_SUPPORDED;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	dwc2_writel(hsotg, dcfg,  DCFG);
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	/* Clear any pending OTG interrupts */
344862306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GOTGINT);
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	/* Clear any pending interrupts */
345162306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
345262306a36Sopenharmony_ci	intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT |
345362306a36Sopenharmony_ci		GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF |
345462306a36Sopenharmony_ci		GINTSTS_USBRST | GINTSTS_RESETDET |
345562306a36Sopenharmony_ci		GINTSTS_ENUMDONE | GINTSTS_OTGINT |
345662306a36Sopenharmony_ci		GINTSTS_USBSUSP | GINTSTS_WKUPINT |
345762306a36Sopenharmony_ci		GINTSTS_LPMTRANRCVD;
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	if (!using_desc_dma(hsotg))
346062306a36Sopenharmony_ci		intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT;
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	if (!hsotg->params.external_id_pin_ctl)
346362306a36Sopenharmony_ci		intmsk |= GINTSTS_CONIDSTSCHNG;
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	dwc2_writel(hsotg, intmsk, GINTMSK);
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	if (using_dma(hsotg)) {
346862306a36Sopenharmony_ci		dwc2_writel(hsotg, GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN |
346962306a36Sopenharmony_ci			    hsotg->params.ahbcfg,
347062306a36Sopenharmony_ci			    GAHBCFG);
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci		/* Set DDMA mode support in the core if needed */
347362306a36Sopenharmony_ci		if (using_desc_dma(hsotg))
347462306a36Sopenharmony_ci			dwc2_set_bit(hsotg, DCFG, DCFG_DESCDMA_EN);
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	} else {
347762306a36Sopenharmony_ci		dwc2_writel(hsotg, ((hsotg->dedicated_fifos) ?
347862306a36Sopenharmony_ci						(GAHBCFG_NP_TXF_EMP_LVL |
347962306a36Sopenharmony_ci						 GAHBCFG_P_TXF_EMP_LVL) : 0) |
348062306a36Sopenharmony_ci			    GAHBCFG_GLBL_INTR_EN, GAHBCFG);
348162306a36Sopenharmony_ci	}
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	/*
348462306a36Sopenharmony_ci	 * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts
348562306a36Sopenharmony_ci	 * when we have no data to transfer. Otherwise we get being flooded by
348662306a36Sopenharmony_ci	 * interrupts.
348762306a36Sopenharmony_ci	 */
348862306a36Sopenharmony_ci
348962306a36Sopenharmony_ci	dwc2_writel(hsotg, ((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
349062306a36Sopenharmony_ci		DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
349162306a36Sopenharmony_ci		DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
349262306a36Sopenharmony_ci		DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK,
349362306a36Sopenharmony_ci		DIEPMSK);
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	/*
349662306a36Sopenharmony_ci	 * don't need XferCompl, we get that from RXFIFO in slave mode. In
349762306a36Sopenharmony_ci	 * DMA mode we may need this and StsPhseRcvd.
349862306a36Sopenharmony_ci	 */
349962306a36Sopenharmony_ci	dwc2_writel(hsotg, (using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK |
350062306a36Sopenharmony_ci		DOEPMSK_STSPHSERCVDMSK) : 0) |
350162306a36Sopenharmony_ci		DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK |
350262306a36Sopenharmony_ci		DOEPMSK_SETUPMSK,
350362306a36Sopenharmony_ci		DOEPMSK);
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	/* Enable BNA interrupt for DDMA */
350662306a36Sopenharmony_ci	if (using_desc_dma(hsotg)) {
350762306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DOEPMSK, DOEPMSK_BNAMSK);
350862306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK);
350962306a36Sopenharmony_ci	}
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	/* Enable Service Interval mode if supported */
351262306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && hsotg->params.service_interval)
351362306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED);
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, DAINTMSK);
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
351862306a36Sopenharmony_ci		dwc2_readl(hsotg, DIEPCTL0),
351962306a36Sopenharmony_ci		dwc2_readl(hsotg, DOEPCTL0));
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	/* enable in and out endpoint interrupts */
352262306a36Sopenharmony_ci	dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT);
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	/*
352562306a36Sopenharmony_ci	 * Enable the RXFIFO when in slave mode, as this is how we collect
352662306a36Sopenharmony_ci	 * the data. In DMA mode, we get events from the FIFO but also
352762306a36Sopenharmony_ci	 * things we cannot process, so do not use it.
352862306a36Sopenharmony_ci	 */
352962306a36Sopenharmony_ci	if (!using_dma(hsotg))
353062306a36Sopenharmony_ci		dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL);
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	/* Enable interrupts for EP0 in and out */
353362306a36Sopenharmony_ci	dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1);
353462306a36Sopenharmony_ci	dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1);
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	if (!is_usb_reset) {
353762306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DCTL, DCTL_PWRONPRGDONE);
353862306a36Sopenharmony_ci		udelay(10);  /* see openiboot */
353962306a36Sopenharmony_ci		dwc2_clear_bit(hsotg, DCTL, DCTL_PWRONPRGDONE);
354062306a36Sopenharmony_ci	}
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg, DCTL));
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	/*
354562306a36Sopenharmony_ci	 * DxEPCTL_USBActEp says RO in manual, but seems to be set by
354662306a36Sopenharmony_ci	 * writing to the EPCTL register..
354762306a36Sopenharmony_ci	 */
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	/* set to read 1 8byte packet */
355062306a36Sopenharmony_ci	dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
355162306a36Sopenharmony_ci	       DXEPTSIZ_XFERSIZE(8), DOEPTSIZ0);
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
355462306a36Sopenharmony_ci	       DXEPCTL_CNAK | DXEPCTL_EPENA |
355562306a36Sopenharmony_ci	       DXEPCTL_USBACTEP,
355662306a36Sopenharmony_ci	       DOEPCTL0);
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci	/* enable, but don't activate EP0in */
355962306a36Sopenharmony_ci	dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
356062306a36Sopenharmony_ci	       DXEPCTL_USBACTEP, DIEPCTL0);
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	/* clear global NAKs */
356362306a36Sopenharmony_ci	val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
356462306a36Sopenharmony_ci	if (!is_usb_reset)
356562306a36Sopenharmony_ci		val |= DCTL_SFTDISCON;
356662306a36Sopenharmony_ci	dwc2_set_bit(hsotg, DCTL, val);
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	/* configure the core to support LPM */
356962306a36Sopenharmony_ci	dwc2_gadget_init_lpm(hsotg);
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	/* program GREFCLK register if needed */
357262306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && hsotg->params.service_interval)
357362306a36Sopenharmony_ci		dwc2_gadget_program_ref_clk(hsotg);
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	/* must be at-least 3ms to allow bus to see disconnect */
357662306a36Sopenharmony_ci	mdelay(3);
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci	dwc2_hsotg_enqueue_setup(hsotg);
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
358362306a36Sopenharmony_ci		dwc2_readl(hsotg, DIEPCTL0),
358462306a36Sopenharmony_ci		dwc2_readl(hsotg, DOEPCTL0));
358562306a36Sopenharmony_ci}
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_civoid dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
358862306a36Sopenharmony_ci{
358962306a36Sopenharmony_ci	/* set the soft-disconnect bit */
359062306a36Sopenharmony_ci	dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
359162306a36Sopenharmony_ci}
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_civoid dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg)
359462306a36Sopenharmony_ci{
359562306a36Sopenharmony_ci	/* remove the soft-disconnect and let's go */
359662306a36Sopenharmony_ci	if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD))
359762306a36Sopenharmony_ci		dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON);
359862306a36Sopenharmony_ci}
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci/**
360162306a36Sopenharmony_ci * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt.
360262306a36Sopenharmony_ci * @hsotg: The device state:
360362306a36Sopenharmony_ci *
360462306a36Sopenharmony_ci * This interrupt indicates one of the following conditions occurred while
360562306a36Sopenharmony_ci * transmitting an ISOC transaction.
360662306a36Sopenharmony_ci * - Corrupted IN Token for ISOC EP.
360762306a36Sopenharmony_ci * - Packet not complete in FIFO.
360862306a36Sopenharmony_ci *
360962306a36Sopenharmony_ci * The following actions will be taken:
361062306a36Sopenharmony_ci * - Determine the EP
361162306a36Sopenharmony_ci * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO
361262306a36Sopenharmony_ci */
361362306a36Sopenharmony_cistatic void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg)
361462306a36Sopenharmony_ci{
361562306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep;
361662306a36Sopenharmony_ci	u32 epctrl;
361762306a36Sopenharmony_ci	u32 daintmsk;
361862306a36Sopenharmony_ci	u32 idx;
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n");
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	daintmsk = dwc2_readl(hsotg, DAINTMSK);
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	for (idx = 1; idx < hsotg->num_of_eps; idx++) {
362562306a36Sopenharmony_ci		hs_ep = hsotg->eps_in[idx];
362662306a36Sopenharmony_ci		/* Proceed only unmasked ISOC EPs */
362762306a36Sopenharmony_ci		if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous)
362862306a36Sopenharmony_ci			continue;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci		epctrl = dwc2_readl(hsotg, DIEPCTL(idx));
363162306a36Sopenharmony_ci		if ((epctrl & DXEPCTL_EPENA) &&
363262306a36Sopenharmony_ci		    dwc2_gadget_target_frame_elapsed(hs_ep)) {
363362306a36Sopenharmony_ci			epctrl |= DXEPCTL_SNAK;
363462306a36Sopenharmony_ci			epctrl |= DXEPCTL_EPDIS;
363562306a36Sopenharmony_ci			dwc2_writel(hsotg, epctrl, DIEPCTL(idx));
363662306a36Sopenharmony_ci		}
363762306a36Sopenharmony_ci	}
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	/* Clear interrupt */
364062306a36Sopenharmony_ci	dwc2_writel(hsotg, GINTSTS_INCOMPL_SOIN, GINTSTS);
364162306a36Sopenharmony_ci}
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci/**
364462306a36Sopenharmony_ci * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt
364562306a36Sopenharmony_ci * @hsotg: The device state:
364662306a36Sopenharmony_ci *
364762306a36Sopenharmony_ci * This interrupt indicates one of the following conditions occurred while
364862306a36Sopenharmony_ci * transmitting an ISOC transaction.
364962306a36Sopenharmony_ci * - Corrupted OUT Token for ISOC EP.
365062306a36Sopenharmony_ci * - Packet not complete in FIFO.
365162306a36Sopenharmony_ci *
365262306a36Sopenharmony_ci * The following actions will be taken:
365362306a36Sopenharmony_ci * - Determine the EP
365462306a36Sopenharmony_ci * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed.
365562306a36Sopenharmony_ci */
365662306a36Sopenharmony_cistatic void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
365762306a36Sopenharmony_ci{
365862306a36Sopenharmony_ci	u32 gintsts;
365962306a36Sopenharmony_ci	u32 gintmsk;
366062306a36Sopenharmony_ci	u32 daintmsk;
366162306a36Sopenharmony_ci	u32 epctrl;
366262306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep;
366362306a36Sopenharmony_ci	int idx;
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	daintmsk = dwc2_readl(hsotg, DAINTMSK);
366862306a36Sopenharmony_ci	daintmsk >>= DAINT_OUTEP_SHIFT;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	for (idx = 1; idx < hsotg->num_of_eps; idx++) {
367162306a36Sopenharmony_ci		hs_ep = hsotg->eps_out[idx];
367262306a36Sopenharmony_ci		/* Proceed only unmasked ISOC EPs */
367362306a36Sopenharmony_ci		if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous)
367462306a36Sopenharmony_ci			continue;
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci		epctrl = dwc2_readl(hsotg, DOEPCTL(idx));
367762306a36Sopenharmony_ci		if ((epctrl & DXEPCTL_EPENA) &&
367862306a36Sopenharmony_ci		    dwc2_gadget_target_frame_elapsed(hs_ep)) {
367962306a36Sopenharmony_ci			/* Unmask GOUTNAKEFF interrupt */
368062306a36Sopenharmony_ci			gintmsk = dwc2_readl(hsotg, GINTMSK);
368162306a36Sopenharmony_ci			gintmsk |= GINTSTS_GOUTNAKEFF;
368262306a36Sopenharmony_ci			dwc2_writel(hsotg, gintmsk, GINTMSK);
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci			gintsts = dwc2_readl(hsotg, GINTSTS);
368562306a36Sopenharmony_ci			if (!(gintsts & GINTSTS_GOUTNAKEFF)) {
368662306a36Sopenharmony_ci				dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK);
368762306a36Sopenharmony_ci				break;
368862306a36Sopenharmony_ci			}
368962306a36Sopenharmony_ci		}
369062306a36Sopenharmony_ci	}
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	/* Clear interrupt */
369362306a36Sopenharmony_ci	dwc2_writel(hsotg, GINTSTS_INCOMPL_SOOUT, GINTSTS);
369462306a36Sopenharmony_ci}
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci/**
369762306a36Sopenharmony_ci * dwc2_hsotg_irq - handle device interrupt
369862306a36Sopenharmony_ci * @irq: The IRQ number triggered
369962306a36Sopenharmony_ci * @pw: The pw value when registered the handler.
370062306a36Sopenharmony_ci */
370162306a36Sopenharmony_cistatic irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
370262306a36Sopenharmony_ci{
370362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = pw;
370462306a36Sopenharmony_ci	int retry_count = 8;
370562306a36Sopenharmony_ci	u32 gintsts;
370662306a36Sopenharmony_ci	u32 gintmsk;
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	if (!dwc2_is_device_mode(hsotg))
370962306a36Sopenharmony_ci		return IRQ_NONE;
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci	spin_lock(&hsotg->lock);
371262306a36Sopenharmony_ciirq_retry:
371362306a36Sopenharmony_ci	gintsts = dwc2_readl(hsotg, GINTSTS);
371462306a36Sopenharmony_ci	gintmsk = dwc2_readl(hsotg, GINTMSK);
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",
371762306a36Sopenharmony_ci		__func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci	gintsts &= gintmsk;
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci	if (gintsts & GINTSTS_RESETDET) {
372262306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__);
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci		dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_ci		/* This event must be used only if controller is suspended */
372762306a36Sopenharmony_ci		if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
372862306a36Sopenharmony_ci			dwc2_exit_partial_power_down(hsotg, 0, true);
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci		hsotg->lx_state = DWC2_L0;
373162306a36Sopenharmony_ci	}
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
373462306a36Sopenharmony_ci		u32 usb_status = dwc2_readl(hsotg, GOTGCTL);
373562306a36Sopenharmony_ci		u32 connected = hsotg->connected;
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: USBRst\n", __func__);
373862306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
373962306a36Sopenharmony_ci			dwc2_readl(hsotg, GNPTXSTS));
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci		dwc2_writel(hsotg, GINTSTS_USBRST, GINTSTS);
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci		/* Report disconnection if it is not already done. */
374462306a36Sopenharmony_ci		dwc2_hsotg_disconnect(hsotg);
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci		/* Reset device address to zero */
374762306a36Sopenharmony_ci		dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK);
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci		if (usb_status & GOTGCTL_BSESVLD && connected)
375062306a36Sopenharmony_ci			dwc2_hsotg_core_init_disconnected(hsotg, true);
375162306a36Sopenharmony_ci	}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	if (gintsts & GINTSTS_ENUMDONE) {
375462306a36Sopenharmony_ci		dwc2_writel(hsotg, GINTSTS_ENUMDONE, GINTSTS);
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci		dwc2_hsotg_irq_enumdone(hsotg);
375762306a36Sopenharmony_ci	}
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci	if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
376062306a36Sopenharmony_ci		u32 daint = dwc2_readl(hsotg, DAINT);
376162306a36Sopenharmony_ci		u32 daintmsk = dwc2_readl(hsotg, DAINTMSK);
376262306a36Sopenharmony_ci		u32 daint_out, daint_in;
376362306a36Sopenharmony_ci		int ep;
376462306a36Sopenharmony_ci
376562306a36Sopenharmony_ci		daint &= daintmsk;
376662306a36Sopenharmony_ci		daint_out = daint >> DAINT_OUTEP_SHIFT;
376762306a36Sopenharmony_ci		daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT);
376862306a36Sopenharmony_ci
376962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ci		for (ep = 0; ep < hsotg->num_of_eps && daint_out;
377262306a36Sopenharmony_ci						ep++, daint_out >>= 1) {
377362306a36Sopenharmony_ci			if (daint_out & 1)
377462306a36Sopenharmony_ci				dwc2_hsotg_epint(hsotg, ep, 0);
377562306a36Sopenharmony_ci		}
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci		for (ep = 0; ep < hsotg->num_of_eps  && daint_in;
377862306a36Sopenharmony_ci						ep++, daint_in >>= 1) {
377962306a36Sopenharmony_ci			if (daint_in & 1)
378062306a36Sopenharmony_ci				dwc2_hsotg_epint(hsotg, ep, 1);
378162306a36Sopenharmony_ci		}
378262306a36Sopenharmony_ci	}
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	/* check both FIFOs */
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci	if (gintsts & GINTSTS_NPTXFEMP) {
378762306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "NPTxFEmp\n");
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci		/*
379062306a36Sopenharmony_ci		 * Disable the interrupt to stop it happening again
379162306a36Sopenharmony_ci		 * unless one of these endpoint routines decides that
379262306a36Sopenharmony_ci		 * it needs re-enabling
379362306a36Sopenharmony_ci		 */
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci		dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP);
379662306a36Sopenharmony_ci		dwc2_hsotg_irq_fifoempty(hsotg, false);
379762306a36Sopenharmony_ci	}
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	if (gintsts & GINTSTS_PTXFEMP) {
380062306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "PTxFEmp\n");
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci		/* See note in GINTSTS_NPTxFEmp */
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci		dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP);
380562306a36Sopenharmony_ci		dwc2_hsotg_irq_fifoempty(hsotg, true);
380662306a36Sopenharmony_ci	}
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	if (gintsts & GINTSTS_RXFLVL) {
380962306a36Sopenharmony_ci		/*
381062306a36Sopenharmony_ci		 * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
381162306a36Sopenharmony_ci		 * we need to retry dwc2_hsotg_handle_rx if this is still
381262306a36Sopenharmony_ci		 * set.
381362306a36Sopenharmony_ci		 */
381462306a36Sopenharmony_ci
381562306a36Sopenharmony_ci		dwc2_hsotg_handle_rx(hsotg);
381662306a36Sopenharmony_ci	}
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	if (gintsts & GINTSTS_ERLYSUSP) {
381962306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
382062306a36Sopenharmony_ci		dwc2_writel(hsotg, GINTSTS_ERLYSUSP, GINTSTS);
382162306a36Sopenharmony_ci	}
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_ci	/*
382462306a36Sopenharmony_ci	 * these next two seem to crop-up occasionally causing the core
382562306a36Sopenharmony_ci	 * to shutdown the USB transfer, so try clearing them and logging
382662306a36Sopenharmony_ci	 * the occurrence.
382762306a36Sopenharmony_ci	 */
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci	if (gintsts & GINTSTS_GOUTNAKEFF) {
383062306a36Sopenharmony_ci		u8 idx;
383162306a36Sopenharmony_ci		u32 epctrl;
383262306a36Sopenharmony_ci		u32 gintmsk;
383362306a36Sopenharmony_ci		u32 daintmsk;
383462306a36Sopenharmony_ci		struct dwc2_hsotg_ep *hs_ep;
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci		daintmsk = dwc2_readl(hsotg, DAINTMSK);
383762306a36Sopenharmony_ci		daintmsk >>= DAINT_OUTEP_SHIFT;
383862306a36Sopenharmony_ci		/* Mask this interrupt */
383962306a36Sopenharmony_ci		gintmsk = dwc2_readl(hsotg, GINTMSK);
384062306a36Sopenharmony_ci		gintmsk &= ~GINTSTS_GOUTNAKEFF;
384162306a36Sopenharmony_ci		dwc2_writel(hsotg, gintmsk, GINTMSK);
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "GOUTNakEff triggered\n");
384462306a36Sopenharmony_ci		for (idx = 1; idx < hsotg->num_of_eps; idx++) {
384562306a36Sopenharmony_ci			hs_ep = hsotg->eps_out[idx];
384662306a36Sopenharmony_ci			/* Proceed only unmasked ISOC EPs */
384762306a36Sopenharmony_ci			if (BIT(idx) & ~daintmsk)
384862306a36Sopenharmony_ci				continue;
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci			epctrl = dwc2_readl(hsotg, DOEPCTL(idx));
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci			//ISOC Ep's only
385362306a36Sopenharmony_ci			if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) {
385462306a36Sopenharmony_ci				epctrl |= DXEPCTL_SNAK;
385562306a36Sopenharmony_ci				epctrl |= DXEPCTL_EPDIS;
385662306a36Sopenharmony_ci				dwc2_writel(hsotg, epctrl, DOEPCTL(idx));
385762306a36Sopenharmony_ci				continue;
385862306a36Sopenharmony_ci			}
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci			//Non-ISOC EP's
386162306a36Sopenharmony_ci			if (hs_ep->halted) {
386262306a36Sopenharmony_ci				if (!(epctrl & DXEPCTL_EPENA))
386362306a36Sopenharmony_ci					epctrl |= DXEPCTL_EPENA;
386462306a36Sopenharmony_ci				epctrl |= DXEPCTL_EPDIS;
386562306a36Sopenharmony_ci				epctrl |= DXEPCTL_STALL;
386662306a36Sopenharmony_ci				dwc2_writel(hsotg, epctrl, DOEPCTL(idx));
386762306a36Sopenharmony_ci			}
386862306a36Sopenharmony_ci		}
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci		/* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */
387162306a36Sopenharmony_ci	}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci	if (gintsts & GINTSTS_GINNAKEFF) {
387462306a36Sopenharmony_ci		dev_info(hsotg->dev, "GINNakEff triggered\n");
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK);
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci		dwc2_hsotg_dump(hsotg);
387962306a36Sopenharmony_ci	}
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci	if (gintsts & GINTSTS_INCOMPL_SOIN)
388262306a36Sopenharmony_ci		dwc2_gadget_handle_incomplete_isoc_in(hsotg);
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	if (gintsts & GINTSTS_INCOMPL_SOOUT)
388562306a36Sopenharmony_ci		dwc2_gadget_handle_incomplete_isoc_out(hsotg);
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	/*
388862306a36Sopenharmony_ci	 * if we've had fifo events, we should try and go around the
388962306a36Sopenharmony_ci	 * loop again to see if there's any point in returning yet.
389062306a36Sopenharmony_ci	 */
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
389362306a36Sopenharmony_ci		goto irq_retry;
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	/* Check WKUP_ALERT interrupt*/
389662306a36Sopenharmony_ci	if (hsotg->params.service_interval)
389762306a36Sopenharmony_ci		dwc2_gadget_wkup_alert_handler(hsotg);
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ci	spin_unlock(&hsotg->lock);
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	return IRQ_HANDLED;
390262306a36Sopenharmony_ci}
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_cistatic void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
390562306a36Sopenharmony_ci				   struct dwc2_hsotg_ep *hs_ep)
390662306a36Sopenharmony_ci{
390762306a36Sopenharmony_ci	u32 epctrl_reg;
390862306a36Sopenharmony_ci	u32 epint_reg;
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci	epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) :
391162306a36Sopenharmony_ci		DOEPCTL(hs_ep->index);
391262306a36Sopenharmony_ci	epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) :
391362306a36Sopenharmony_ci		DOEPINT(hs_ep->index);
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__,
391662306a36Sopenharmony_ci		hs_ep->name);
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	if (hs_ep->dir_in) {
391962306a36Sopenharmony_ci		if (hsotg->dedicated_fifos || hs_ep->periodic) {
392062306a36Sopenharmony_ci			dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_SNAK);
392162306a36Sopenharmony_ci			/* Wait for Nak effect */
392262306a36Sopenharmony_ci			if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg,
392362306a36Sopenharmony_ci						    DXEPINT_INEPNAKEFF, 100))
392462306a36Sopenharmony_ci				dev_warn(hsotg->dev,
392562306a36Sopenharmony_ci					 "%s: timeout DIEPINT.NAKEFF\n",
392662306a36Sopenharmony_ci					 __func__);
392762306a36Sopenharmony_ci		} else {
392862306a36Sopenharmony_ci			dwc2_set_bit(hsotg, DCTL, DCTL_SGNPINNAK);
392962306a36Sopenharmony_ci			/* Wait for Nak effect */
393062306a36Sopenharmony_ci			if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
393162306a36Sopenharmony_ci						    GINTSTS_GINNAKEFF, 100))
393262306a36Sopenharmony_ci				dev_warn(hsotg->dev,
393362306a36Sopenharmony_ci					 "%s: timeout GINTSTS.GINNAKEFF\n",
393462306a36Sopenharmony_ci					 __func__);
393562306a36Sopenharmony_ci		}
393662306a36Sopenharmony_ci	} else {
393762306a36Sopenharmony_ci		/* Mask GINTSTS_GOUTNAKEFF interrupt */
393862306a36Sopenharmony_ci		dwc2_hsotg_disable_gsint(hsotg, GINTSTS_GOUTNAKEFF);
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci		if (!(dwc2_readl(hsotg, GINTSTS) & GINTSTS_GOUTNAKEFF))
394162306a36Sopenharmony_ci			dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK);
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci		if (!using_dma(hsotg)) {
394462306a36Sopenharmony_ci			/* Wait for GINTSTS_RXFLVL interrupt */
394562306a36Sopenharmony_ci			if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
394662306a36Sopenharmony_ci						    GINTSTS_RXFLVL, 100)) {
394762306a36Sopenharmony_ci				dev_warn(hsotg->dev, "%s: timeout GINTSTS.RXFLVL\n",
394862306a36Sopenharmony_ci					 __func__);
394962306a36Sopenharmony_ci			} else {
395062306a36Sopenharmony_ci				/*
395162306a36Sopenharmony_ci				 * Pop GLOBAL OUT NAK status packet from RxFIFO
395262306a36Sopenharmony_ci				 * to assert GOUTNAKEFF interrupt
395362306a36Sopenharmony_ci				 */
395462306a36Sopenharmony_ci				dwc2_readl(hsotg, GRXSTSP);
395562306a36Sopenharmony_ci			}
395662306a36Sopenharmony_ci		}
395762306a36Sopenharmony_ci
395862306a36Sopenharmony_ci		/* Wait for global nak to take effect */
395962306a36Sopenharmony_ci		if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
396062306a36Sopenharmony_ci					    GINTSTS_GOUTNAKEFF, 100))
396162306a36Sopenharmony_ci			dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n",
396262306a36Sopenharmony_ci				 __func__);
396362306a36Sopenharmony_ci	}
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci	/* Disable ep */
396662306a36Sopenharmony_ci	dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK);
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_ci	/* Wait for ep to be disabled */
396962306a36Sopenharmony_ci	if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100))
397062306a36Sopenharmony_ci		dev_warn(hsotg->dev,
397162306a36Sopenharmony_ci			 "%s: timeout DOEPCTL.EPDisable\n", __func__);
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	/* Clear EPDISBLD interrupt */
397462306a36Sopenharmony_ci	dwc2_set_bit(hsotg, epint_reg, DXEPINT_EPDISBLD);
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_ci	if (hs_ep->dir_in) {
397762306a36Sopenharmony_ci		unsigned short fifo_index;
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci		if (hsotg->dedicated_fifos || hs_ep->periodic)
398062306a36Sopenharmony_ci			fifo_index = hs_ep->fifo_index;
398162306a36Sopenharmony_ci		else
398262306a36Sopenharmony_ci			fifo_index = 0;
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_ci		/* Flush TX FIFO */
398562306a36Sopenharmony_ci		dwc2_flush_tx_fifo(hsotg, fifo_index);
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci		/* Clear Global In NP NAK in Shared FIFO for non periodic ep */
398862306a36Sopenharmony_ci		if (!hsotg->dedicated_fifos && !hs_ep->periodic)
398962306a36Sopenharmony_ci			dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK);
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci	} else {
399262306a36Sopenharmony_ci		/* Remove global NAKs */
399362306a36Sopenharmony_ci		dwc2_set_bit(hsotg, DCTL, DCTL_CGOUTNAK);
399462306a36Sopenharmony_ci	}
399562306a36Sopenharmony_ci}
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci/**
399862306a36Sopenharmony_ci * dwc2_hsotg_ep_enable - enable the given endpoint
399962306a36Sopenharmony_ci * @ep: The USB endpint to configure
400062306a36Sopenharmony_ci * @desc: The USB endpoint descriptor to configure with.
400162306a36Sopenharmony_ci *
400262306a36Sopenharmony_ci * This is called from the USB gadget code's usb_ep_enable().
400362306a36Sopenharmony_ci */
400462306a36Sopenharmony_cistatic int dwc2_hsotg_ep_enable(struct usb_ep *ep,
400562306a36Sopenharmony_ci				const struct usb_endpoint_descriptor *desc)
400662306a36Sopenharmony_ci{
400762306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
400862306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
400962306a36Sopenharmony_ci	unsigned long flags;
401062306a36Sopenharmony_ci	unsigned int index = hs_ep->index;
401162306a36Sopenharmony_ci	u32 epctrl_reg;
401262306a36Sopenharmony_ci	u32 epctrl;
401362306a36Sopenharmony_ci	u32 mps;
401462306a36Sopenharmony_ci	u32 mc;
401562306a36Sopenharmony_ci	u32 mask;
401662306a36Sopenharmony_ci	unsigned int dir_in;
401762306a36Sopenharmony_ci	unsigned int i, val, size;
401862306a36Sopenharmony_ci	int ret = 0;
401962306a36Sopenharmony_ci	unsigned char ep_type;
402062306a36Sopenharmony_ci	int desc_num;
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
402362306a36Sopenharmony_ci		"%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n",
402462306a36Sopenharmony_ci		__func__, ep->name, desc->bEndpointAddress, desc->bmAttributes,
402562306a36Sopenharmony_ci		desc->wMaxPacketSize, desc->bInterval);
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_ci	/* not to be called for EP0 */
402862306a36Sopenharmony_ci	if (index == 0) {
402962306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: called for EP 0\n", __func__);
403062306a36Sopenharmony_ci		return -EINVAL;
403162306a36Sopenharmony_ci	}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci	dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
403462306a36Sopenharmony_ci	if (dir_in != hs_ep->dir_in) {
403562306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__);
403662306a36Sopenharmony_ci		return -EINVAL;
403762306a36Sopenharmony_ci	}
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
404062306a36Sopenharmony_ci	mps = usb_endpoint_maxp(desc);
404162306a36Sopenharmony_ci	mc = usb_endpoint_maxp_mult(desc);
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	/* ISOC IN in DDMA supported bInterval up to 10 */
404462306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC &&
404562306a36Sopenharmony_ci	    dir_in && desc->bInterval > 10) {
404662306a36Sopenharmony_ci		dev_err(hsotg->dev,
404762306a36Sopenharmony_ci			"%s: ISOC IN, DDMA: bInterval>10 not supported!\n", __func__);
404862306a36Sopenharmony_ci		return -EINVAL;
404962306a36Sopenharmony_ci	}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci	/* High bandwidth ISOC OUT in DDMA not supported */
405262306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC &&
405362306a36Sopenharmony_ci	    !dir_in && mc > 1) {
405462306a36Sopenharmony_ci		dev_err(hsotg->dev,
405562306a36Sopenharmony_ci			"%s: ISOC OUT, DDMA: HB not supported!\n", __func__);
405662306a36Sopenharmony_ci		return -EINVAL;
405762306a36Sopenharmony_ci	}
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci	/* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
406262306a36Sopenharmony_ci	epctrl = dwc2_readl(hsotg, epctrl_reg);
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
406562306a36Sopenharmony_ci		__func__, epctrl, epctrl_reg);
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC)
406862306a36Sopenharmony_ci		desc_num = MAX_DMA_DESC_NUM_HS_ISOC;
406962306a36Sopenharmony_ci	else
407062306a36Sopenharmony_ci		desc_num = MAX_DMA_DESC_NUM_GENERIC;
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	/* Allocate DMA descriptor chain for non-ctrl endpoints */
407362306a36Sopenharmony_ci	if (using_desc_dma(hsotg) && !hs_ep->desc_list) {
407462306a36Sopenharmony_ci		hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev,
407562306a36Sopenharmony_ci			desc_num * sizeof(struct dwc2_dma_desc),
407662306a36Sopenharmony_ci			&hs_ep->desc_list_dma, GFP_ATOMIC);
407762306a36Sopenharmony_ci		if (!hs_ep->desc_list) {
407862306a36Sopenharmony_ci			ret = -ENOMEM;
407962306a36Sopenharmony_ci			goto error2;
408062306a36Sopenharmony_ci		}
408162306a36Sopenharmony_ci	}
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci	epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK);
408662306a36Sopenharmony_ci	epctrl |= DXEPCTL_MPS(mps);
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	/*
408962306a36Sopenharmony_ci	 * mark the endpoint as active, otherwise the core may ignore
409062306a36Sopenharmony_ci	 * transactions entirely for this endpoint
409162306a36Sopenharmony_ci	 */
409262306a36Sopenharmony_ci	epctrl |= DXEPCTL_USBACTEP;
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci	/* update the endpoint state */
409562306a36Sopenharmony_ci	dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in);
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	/* default, set to non-periodic */
409862306a36Sopenharmony_ci	hs_ep->isochronous = 0;
409962306a36Sopenharmony_ci	hs_ep->periodic = 0;
410062306a36Sopenharmony_ci	hs_ep->halted = 0;
410162306a36Sopenharmony_ci	hs_ep->wedged = 0;
410262306a36Sopenharmony_ci	hs_ep->interval = desc->bInterval;
410362306a36Sopenharmony_ci
410462306a36Sopenharmony_ci	switch (ep_type) {
410562306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
410662306a36Sopenharmony_ci		epctrl |= DXEPCTL_EPTYPE_ISO;
410762306a36Sopenharmony_ci		epctrl |= DXEPCTL_SETEVENFR;
410862306a36Sopenharmony_ci		hs_ep->isochronous = 1;
410962306a36Sopenharmony_ci		hs_ep->interval = 1 << (desc->bInterval - 1);
411062306a36Sopenharmony_ci		hs_ep->target_frame = TARGET_FRAME_INITIAL;
411162306a36Sopenharmony_ci		hs_ep->next_desc = 0;
411262306a36Sopenharmony_ci		hs_ep->compl_desc = 0;
411362306a36Sopenharmony_ci		if (dir_in) {
411462306a36Sopenharmony_ci			hs_ep->periodic = 1;
411562306a36Sopenharmony_ci			mask = dwc2_readl(hsotg, DIEPMSK);
411662306a36Sopenharmony_ci			mask |= DIEPMSK_NAKMSK;
411762306a36Sopenharmony_ci			dwc2_writel(hsotg, mask, DIEPMSK);
411862306a36Sopenharmony_ci		} else {
411962306a36Sopenharmony_ci			epctrl |= DXEPCTL_SNAK;
412062306a36Sopenharmony_ci			mask = dwc2_readl(hsotg, DOEPMSK);
412162306a36Sopenharmony_ci			mask |= DOEPMSK_OUTTKNEPDISMSK;
412262306a36Sopenharmony_ci			dwc2_writel(hsotg, mask, DOEPMSK);
412362306a36Sopenharmony_ci		}
412462306a36Sopenharmony_ci		break;
412562306a36Sopenharmony_ci
412662306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
412762306a36Sopenharmony_ci		epctrl |= DXEPCTL_EPTYPE_BULK;
412862306a36Sopenharmony_ci		break;
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
413162306a36Sopenharmony_ci		if (dir_in)
413262306a36Sopenharmony_ci			hs_ep->periodic = 1;
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci		if (hsotg->gadget.speed == USB_SPEED_HIGH)
413562306a36Sopenharmony_ci			hs_ep->interval = 1 << (desc->bInterval - 1);
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci		epctrl |= DXEPCTL_EPTYPE_INTERRUPT;
413862306a36Sopenharmony_ci		break;
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
414162306a36Sopenharmony_ci		epctrl |= DXEPCTL_EPTYPE_CONTROL;
414262306a36Sopenharmony_ci		break;
414362306a36Sopenharmony_ci	}
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_ci	/*
414662306a36Sopenharmony_ci	 * if the hardware has dedicated fifos, we must give each IN EP
414762306a36Sopenharmony_ci	 * a unique tx-fifo even if it is non-periodic.
414862306a36Sopenharmony_ci	 */
414962306a36Sopenharmony_ci	if (dir_in && hsotg->dedicated_fifos) {
415062306a36Sopenharmony_ci		unsigned fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
415162306a36Sopenharmony_ci		u32 fifo_index = 0;
415262306a36Sopenharmony_ci		u32 fifo_size = UINT_MAX;
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci		size = hs_ep->ep.maxpacket * hs_ep->mc;
415562306a36Sopenharmony_ci		for (i = 1; i <= fifo_count; ++i) {
415662306a36Sopenharmony_ci			if (hsotg->fifo_map & (1 << i))
415762306a36Sopenharmony_ci				continue;
415862306a36Sopenharmony_ci			val = dwc2_readl(hsotg, DPTXFSIZN(i));
415962306a36Sopenharmony_ci			val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4;
416062306a36Sopenharmony_ci			if (val < size)
416162306a36Sopenharmony_ci				continue;
416262306a36Sopenharmony_ci			/* Search for smallest acceptable fifo */
416362306a36Sopenharmony_ci			if (val < fifo_size) {
416462306a36Sopenharmony_ci				fifo_size = val;
416562306a36Sopenharmony_ci				fifo_index = i;
416662306a36Sopenharmony_ci			}
416762306a36Sopenharmony_ci		}
416862306a36Sopenharmony_ci		if (!fifo_index) {
416962306a36Sopenharmony_ci			dev_err(hsotg->dev,
417062306a36Sopenharmony_ci				"%s: No suitable fifo found\n", __func__);
417162306a36Sopenharmony_ci			ret = -ENOMEM;
417262306a36Sopenharmony_ci			goto error1;
417362306a36Sopenharmony_ci		}
417462306a36Sopenharmony_ci		epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT);
417562306a36Sopenharmony_ci		hsotg->fifo_map |= 1 << fifo_index;
417662306a36Sopenharmony_ci		epctrl |= DXEPCTL_TXFNUM(fifo_index);
417762306a36Sopenharmony_ci		hs_ep->fifo_index = fifo_index;
417862306a36Sopenharmony_ci		hs_ep->fifo_size = fifo_size;
417962306a36Sopenharmony_ci	}
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	/* for non control endpoints, set PID to D0 */
418262306a36Sopenharmony_ci	if (index && !hs_ep->isochronous)
418362306a36Sopenharmony_ci		epctrl |= DXEPCTL_SETD0PID;
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_ci	/* WA for Full speed ISOC IN in DDMA mode.
418662306a36Sopenharmony_ci	 * By Clear NAK status of EP, core will send ZLP
418762306a36Sopenharmony_ci	 * to IN token and assert NAK interrupt relying
418862306a36Sopenharmony_ci	 * on TxFIFO status only
418962306a36Sopenharmony_ci	 */
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	if (hsotg->gadget.speed == USB_SPEED_FULL &&
419262306a36Sopenharmony_ci	    hs_ep->isochronous && dir_in) {
419362306a36Sopenharmony_ci		/* The WA applies only to core versions from 2.72a
419462306a36Sopenharmony_ci		 * to 4.00a (including both). Also for FS_IOT_1.00a
419562306a36Sopenharmony_ci		 * and HS_IOT_1.00a.
419662306a36Sopenharmony_ci		 */
419762306a36Sopenharmony_ci		u32 gsnpsid = dwc2_readl(hsotg, GSNPSID);
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci		if ((gsnpsid >= DWC2_CORE_REV_2_72a &&
420062306a36Sopenharmony_ci		     gsnpsid <= DWC2_CORE_REV_4_00a) ||
420162306a36Sopenharmony_ci		     gsnpsid == DWC2_FS_IOT_REV_1_00a ||
420262306a36Sopenharmony_ci		     gsnpsid == DWC2_HS_IOT_REV_1_00a)
420362306a36Sopenharmony_ci			epctrl |= DXEPCTL_CNAK;
420462306a36Sopenharmony_ci	}
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
420762306a36Sopenharmony_ci		__func__, epctrl);
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	dwc2_writel(hsotg, epctrl, epctrl_reg);
421062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n",
421162306a36Sopenharmony_ci		__func__, dwc2_readl(hsotg, epctrl_reg));
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci	/* enable the endpoint interrupt */
421462306a36Sopenharmony_ci	dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_cierror1:
421762306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_cierror2:
422062306a36Sopenharmony_ci	if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) {
422162306a36Sopenharmony_ci		dmam_free_coherent(hsotg->dev, desc_num *
422262306a36Sopenharmony_ci			sizeof(struct dwc2_dma_desc),
422362306a36Sopenharmony_ci			hs_ep->desc_list, hs_ep->desc_list_dma);
422462306a36Sopenharmony_ci		hs_ep->desc_list = NULL;
422562306a36Sopenharmony_ci	}
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	return ret;
422862306a36Sopenharmony_ci}
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_ci/**
423162306a36Sopenharmony_ci * dwc2_hsotg_ep_disable - disable given endpoint
423262306a36Sopenharmony_ci * @ep: The endpoint to disable.
423362306a36Sopenharmony_ci */
423462306a36Sopenharmony_cistatic int dwc2_hsotg_ep_disable(struct usb_ep *ep)
423562306a36Sopenharmony_ci{
423662306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
423762306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
423862306a36Sopenharmony_ci	int dir_in = hs_ep->dir_in;
423962306a36Sopenharmony_ci	int index = hs_ep->index;
424062306a36Sopenharmony_ci	u32 epctrl_reg;
424162306a36Sopenharmony_ci	u32 ctrl;
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
424462306a36Sopenharmony_ci
424562306a36Sopenharmony_ci	if (ep == &hsotg->eps_out[0]->ep) {
424662306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: called for ep0\n", __func__);
424762306a36Sopenharmony_ci		return -EINVAL;
424862306a36Sopenharmony_ci	}
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci	if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) {
425162306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: called in host mode?\n", __func__);
425262306a36Sopenharmony_ci		return -EINVAL;
425362306a36Sopenharmony_ci	}
425462306a36Sopenharmony_ci
425562306a36Sopenharmony_ci	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
425662306a36Sopenharmony_ci
425762306a36Sopenharmony_ci	ctrl = dwc2_readl(hsotg, epctrl_reg);
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_ci	if (ctrl & DXEPCTL_EPENA)
426062306a36Sopenharmony_ci		dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci	ctrl &= ~DXEPCTL_EPENA;
426362306a36Sopenharmony_ci	ctrl &= ~DXEPCTL_USBACTEP;
426462306a36Sopenharmony_ci	ctrl |= DXEPCTL_SNAK;
426562306a36Sopenharmony_ci
426662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
426762306a36Sopenharmony_ci	dwc2_writel(hsotg, ctrl, epctrl_reg);
426862306a36Sopenharmony_ci
426962306a36Sopenharmony_ci	/* disable endpoint interrupts */
427062306a36Sopenharmony_ci	dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci	/* terminate all requests with shutdown */
427362306a36Sopenharmony_ci	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN);
427462306a36Sopenharmony_ci
427562306a36Sopenharmony_ci	hsotg->fifo_map &= ~(1 << hs_ep->fifo_index);
427662306a36Sopenharmony_ci	hs_ep->fifo_index = 0;
427762306a36Sopenharmony_ci	hs_ep->fifo_size = 0;
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci	return 0;
428062306a36Sopenharmony_ci}
428162306a36Sopenharmony_ci
428262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep)
428362306a36Sopenharmony_ci{
428462306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
428562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = hs_ep->parent;
428662306a36Sopenharmony_ci	unsigned long flags;
428762306a36Sopenharmony_ci	int ret;
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
429062306a36Sopenharmony_ci	ret = dwc2_hsotg_ep_disable(ep);
429162306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
429262306a36Sopenharmony_ci	return ret;
429362306a36Sopenharmony_ci}
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci/**
429662306a36Sopenharmony_ci * on_list - check request is on the given endpoint
429762306a36Sopenharmony_ci * @ep: The endpoint to check.
429862306a36Sopenharmony_ci * @test: The request to test if it is on the endpoint.
429962306a36Sopenharmony_ci */
430062306a36Sopenharmony_cistatic bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test)
430162306a36Sopenharmony_ci{
430262306a36Sopenharmony_ci	struct dwc2_hsotg_req *req, *treq;
430362306a36Sopenharmony_ci
430462306a36Sopenharmony_ci	list_for_each_entry_safe(req, treq, &ep->queue, queue) {
430562306a36Sopenharmony_ci		if (req == test)
430662306a36Sopenharmony_ci			return true;
430762306a36Sopenharmony_ci	}
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_ci	return false;
431062306a36Sopenharmony_ci}
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci/**
431362306a36Sopenharmony_ci * dwc2_hsotg_ep_dequeue - dequeue given endpoint
431462306a36Sopenharmony_ci * @ep: The endpoint to dequeue.
431562306a36Sopenharmony_ci * @req: The request to be removed from a queue.
431662306a36Sopenharmony_ci */
431762306a36Sopenharmony_cistatic int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
431862306a36Sopenharmony_ci{
431962306a36Sopenharmony_ci	struct dwc2_hsotg_req *hs_req = our_req(req);
432062306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
432162306a36Sopenharmony_ci	struct dwc2_hsotg *hs = hs_ep->parent;
432262306a36Sopenharmony_ci	unsigned long flags;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci	spin_lock_irqsave(&hs->lock, flags);
432762306a36Sopenharmony_ci
432862306a36Sopenharmony_ci	if (!on_list(hs_ep, hs_req)) {
432962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hs->lock, flags);
433062306a36Sopenharmony_ci		return -EINVAL;
433162306a36Sopenharmony_ci	}
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	/* Dequeue already started request */
433462306a36Sopenharmony_ci	if (req == &hs_ep->req->req)
433562306a36Sopenharmony_ci		dwc2_hsotg_ep_stop_xfr(hs, hs_ep);
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci	dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET);
433862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hs->lock, flags);
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci	return 0;
434162306a36Sopenharmony_ci}
434262306a36Sopenharmony_ci
434362306a36Sopenharmony_ci/**
434462306a36Sopenharmony_ci * dwc2_gadget_ep_set_wedge - set wedge on a given endpoint
434562306a36Sopenharmony_ci * @ep: The endpoint to be wedged.
434662306a36Sopenharmony_ci *
434762306a36Sopenharmony_ci */
434862306a36Sopenharmony_cistatic int dwc2_gadget_ep_set_wedge(struct usb_ep *ep)
434962306a36Sopenharmony_ci{
435062306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
435162306a36Sopenharmony_ci	struct dwc2_hsotg *hs = hs_ep->parent;
435262306a36Sopenharmony_ci
435362306a36Sopenharmony_ci	unsigned long	flags;
435462306a36Sopenharmony_ci	int		ret;
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	spin_lock_irqsave(&hs->lock, flags);
435762306a36Sopenharmony_ci	hs_ep->wedged = 1;
435862306a36Sopenharmony_ci	ret = dwc2_hsotg_ep_sethalt(ep, 1, false);
435962306a36Sopenharmony_ci	spin_unlock_irqrestore(&hs->lock, flags);
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci	return ret;
436262306a36Sopenharmony_ci}
436362306a36Sopenharmony_ci
436462306a36Sopenharmony_ci/**
436562306a36Sopenharmony_ci * dwc2_hsotg_ep_sethalt - set halt on a given endpoint
436662306a36Sopenharmony_ci * @ep: The endpoint to set halt.
436762306a36Sopenharmony_ci * @value: Set or unset the halt.
436862306a36Sopenharmony_ci * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if
436962306a36Sopenharmony_ci *       the endpoint is busy processing requests.
437062306a36Sopenharmony_ci *
437162306a36Sopenharmony_ci * We need to stall the endpoint immediately if request comes from set_feature
437262306a36Sopenharmony_ci * protocol command handler.
437362306a36Sopenharmony_ci */
437462306a36Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
437562306a36Sopenharmony_ci{
437662306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
437762306a36Sopenharmony_ci	struct dwc2_hsotg *hs = hs_ep->parent;
437862306a36Sopenharmony_ci	int index = hs_ep->index;
437962306a36Sopenharmony_ci	u32 epreg;
438062306a36Sopenharmony_ci	u32 epctl;
438162306a36Sopenharmony_ci	u32 xfertype;
438262306a36Sopenharmony_ci
438362306a36Sopenharmony_ci	dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci	if (index == 0) {
438662306a36Sopenharmony_ci		if (value)
438762306a36Sopenharmony_ci			dwc2_hsotg_stall_ep0(hs);
438862306a36Sopenharmony_ci		else
438962306a36Sopenharmony_ci			dev_warn(hs->dev,
439062306a36Sopenharmony_ci				 "%s: can't clear halt on ep0\n", __func__);
439162306a36Sopenharmony_ci		return 0;
439262306a36Sopenharmony_ci	}
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci	if (hs_ep->isochronous) {
439562306a36Sopenharmony_ci		dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name);
439662306a36Sopenharmony_ci		return -EINVAL;
439762306a36Sopenharmony_ci	}
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_ci	if (!now && value && !list_empty(&hs_ep->queue)) {
440062306a36Sopenharmony_ci		dev_dbg(hs->dev, "%s request is pending, cannot halt\n",
440162306a36Sopenharmony_ci			ep->name);
440262306a36Sopenharmony_ci		return -EAGAIN;
440362306a36Sopenharmony_ci	}
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci	if (hs_ep->dir_in) {
440662306a36Sopenharmony_ci		epreg = DIEPCTL(index);
440762306a36Sopenharmony_ci		epctl = dwc2_readl(hs, epreg);
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci		if (value) {
441062306a36Sopenharmony_ci			epctl |= DXEPCTL_STALL | DXEPCTL_SNAK;
441162306a36Sopenharmony_ci			if (epctl & DXEPCTL_EPENA)
441262306a36Sopenharmony_ci				epctl |= DXEPCTL_EPDIS;
441362306a36Sopenharmony_ci		} else {
441462306a36Sopenharmony_ci			epctl &= ~DXEPCTL_STALL;
441562306a36Sopenharmony_ci			hs_ep->wedged = 0;
441662306a36Sopenharmony_ci			xfertype = epctl & DXEPCTL_EPTYPE_MASK;
441762306a36Sopenharmony_ci			if (xfertype == DXEPCTL_EPTYPE_BULK ||
441862306a36Sopenharmony_ci			    xfertype == DXEPCTL_EPTYPE_INTERRUPT)
441962306a36Sopenharmony_ci				epctl |= DXEPCTL_SETD0PID;
442062306a36Sopenharmony_ci		}
442162306a36Sopenharmony_ci		dwc2_writel(hs, epctl, epreg);
442262306a36Sopenharmony_ci	} else {
442362306a36Sopenharmony_ci		epreg = DOEPCTL(index);
442462306a36Sopenharmony_ci		epctl = dwc2_readl(hs, epreg);
442562306a36Sopenharmony_ci
442662306a36Sopenharmony_ci		if (value) {
442762306a36Sopenharmony_ci			/* Unmask GOUTNAKEFF interrupt */
442862306a36Sopenharmony_ci			dwc2_hsotg_en_gsint(hs, GINTSTS_GOUTNAKEFF);
442962306a36Sopenharmony_ci
443062306a36Sopenharmony_ci			if (!(dwc2_readl(hs, GINTSTS) & GINTSTS_GOUTNAKEFF))
443162306a36Sopenharmony_ci				dwc2_set_bit(hs, DCTL, DCTL_SGOUTNAK);
443262306a36Sopenharmony_ci			// STALL bit will be set in GOUTNAKEFF interrupt handler
443362306a36Sopenharmony_ci		} else {
443462306a36Sopenharmony_ci			epctl &= ~DXEPCTL_STALL;
443562306a36Sopenharmony_ci			hs_ep->wedged = 0;
443662306a36Sopenharmony_ci			xfertype = epctl & DXEPCTL_EPTYPE_MASK;
443762306a36Sopenharmony_ci			if (xfertype == DXEPCTL_EPTYPE_BULK ||
443862306a36Sopenharmony_ci			    xfertype == DXEPCTL_EPTYPE_INTERRUPT)
443962306a36Sopenharmony_ci				epctl |= DXEPCTL_SETD0PID;
444062306a36Sopenharmony_ci			dwc2_writel(hs, epctl, epreg);
444162306a36Sopenharmony_ci		}
444262306a36Sopenharmony_ci	}
444362306a36Sopenharmony_ci
444462306a36Sopenharmony_ci	hs_ep->halted = value;
444562306a36Sopenharmony_ci	return 0;
444662306a36Sopenharmony_ci}
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_ci/**
444962306a36Sopenharmony_ci * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held
445062306a36Sopenharmony_ci * @ep: The endpoint to set halt.
445162306a36Sopenharmony_ci * @value: Set or unset the halt.
445262306a36Sopenharmony_ci */
445362306a36Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
445462306a36Sopenharmony_ci{
445562306a36Sopenharmony_ci	struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
445662306a36Sopenharmony_ci	struct dwc2_hsotg *hs = hs_ep->parent;
445762306a36Sopenharmony_ci	unsigned long flags;
445862306a36Sopenharmony_ci	int ret;
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci	spin_lock_irqsave(&hs->lock, flags);
446162306a36Sopenharmony_ci	ret = dwc2_hsotg_ep_sethalt(ep, value, false);
446262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hs->lock, flags);
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci	return ret;
446562306a36Sopenharmony_ci}
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_cistatic const struct usb_ep_ops dwc2_hsotg_ep_ops = {
446862306a36Sopenharmony_ci	.enable		= dwc2_hsotg_ep_enable,
446962306a36Sopenharmony_ci	.disable	= dwc2_hsotg_ep_disable_lock,
447062306a36Sopenharmony_ci	.alloc_request	= dwc2_hsotg_ep_alloc_request,
447162306a36Sopenharmony_ci	.free_request	= dwc2_hsotg_ep_free_request,
447262306a36Sopenharmony_ci	.queue		= dwc2_hsotg_ep_queue_lock,
447362306a36Sopenharmony_ci	.dequeue	= dwc2_hsotg_ep_dequeue,
447462306a36Sopenharmony_ci	.set_halt	= dwc2_hsotg_ep_sethalt_lock,
447562306a36Sopenharmony_ci	.set_wedge	= dwc2_gadget_ep_set_wedge,
447662306a36Sopenharmony_ci	/* note, don't believe we have any call for the fifo routines */
447762306a36Sopenharmony_ci};
447862306a36Sopenharmony_ci
447962306a36Sopenharmony_ci/**
448062306a36Sopenharmony_ci * dwc2_hsotg_init - initialize the usb core
448162306a36Sopenharmony_ci * @hsotg: The driver state
448262306a36Sopenharmony_ci */
448362306a36Sopenharmony_cistatic void dwc2_hsotg_init(struct dwc2_hsotg *hsotg)
448462306a36Sopenharmony_ci{
448562306a36Sopenharmony_ci	/* unmask subset of endpoint interrupts */
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
448862306a36Sopenharmony_ci		    DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK,
448962306a36Sopenharmony_ci		    DIEPMSK);
449062306a36Sopenharmony_ci
449162306a36Sopenharmony_ci	dwc2_writel(hsotg, DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK |
449262306a36Sopenharmony_ci		    DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK,
449362306a36Sopenharmony_ci		    DOEPMSK);
449462306a36Sopenharmony_ci
449562306a36Sopenharmony_ci	dwc2_writel(hsotg, 0, DAINTMSK);
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	/* Be in disconnected state until gadget is registered */
449862306a36Sopenharmony_ci	dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
449962306a36Sopenharmony_ci
450062306a36Sopenharmony_ci	/* setup fifos */
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
450362306a36Sopenharmony_ci		dwc2_readl(hsotg, GRXFSIZ),
450462306a36Sopenharmony_ci		dwc2_readl(hsotg, GNPTXFSIZ));
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci	dwc2_hsotg_init_fifo(hsotg);
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	if (using_dma(hsotg))
450962306a36Sopenharmony_ci		dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN);
451062306a36Sopenharmony_ci}
451162306a36Sopenharmony_ci
451262306a36Sopenharmony_ci/**
451362306a36Sopenharmony_ci * dwc2_hsotg_udc_start - prepare the udc for work
451462306a36Sopenharmony_ci * @gadget: The usb gadget state
451562306a36Sopenharmony_ci * @driver: The usb gadget driver
451662306a36Sopenharmony_ci *
451762306a36Sopenharmony_ci * Perform initialization to prepare udc device and driver
451862306a36Sopenharmony_ci * to work.
451962306a36Sopenharmony_ci */
452062306a36Sopenharmony_cistatic int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
452162306a36Sopenharmony_ci				struct usb_gadget_driver *driver)
452262306a36Sopenharmony_ci{
452362306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
452462306a36Sopenharmony_ci	unsigned long flags;
452562306a36Sopenharmony_ci	int ret;
452662306a36Sopenharmony_ci
452762306a36Sopenharmony_ci	if (!hsotg) {
452862306a36Sopenharmony_ci		pr_err("%s: called with no device\n", __func__);
452962306a36Sopenharmony_ci		return -ENODEV;
453062306a36Sopenharmony_ci	}
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	if (!driver) {
453362306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: no driver\n", __func__);
453462306a36Sopenharmony_ci		return -EINVAL;
453562306a36Sopenharmony_ci	}
453662306a36Sopenharmony_ci
453762306a36Sopenharmony_ci	if (driver->max_speed < USB_SPEED_FULL)
453862306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: bad speed\n", __func__);
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci	if (!driver->setup) {
454162306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
454262306a36Sopenharmony_ci		return -EINVAL;
454362306a36Sopenharmony_ci	}
454462306a36Sopenharmony_ci
454562306a36Sopenharmony_ci	WARN_ON(hsotg->driver);
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	hsotg->driver = driver;
454862306a36Sopenharmony_ci	hsotg->gadget.dev.of_node = hsotg->dev->of_node;
454962306a36Sopenharmony_ci	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
455062306a36Sopenharmony_ci
455162306a36Sopenharmony_ci	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
455262306a36Sopenharmony_ci		ret = dwc2_lowlevel_hw_enable(hsotg);
455362306a36Sopenharmony_ci		if (ret)
455462306a36Sopenharmony_ci			goto err;
455562306a36Sopenharmony_ci	}
455662306a36Sopenharmony_ci
455762306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hsotg->uphy))
455862306a36Sopenharmony_ci		otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget);
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
456162306a36Sopenharmony_ci	if (dwc2_hw_is_device(hsotg)) {
456262306a36Sopenharmony_ci		dwc2_hsotg_init(hsotg);
456362306a36Sopenharmony_ci		dwc2_hsotg_core_init_disconnected(hsotg, false);
456462306a36Sopenharmony_ci	}
456562306a36Sopenharmony_ci
456662306a36Sopenharmony_ci	hsotg->enabled = 0;
456762306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
456862306a36Sopenharmony_ci
456962306a36Sopenharmony_ci	gadget->sg_supported = using_desc_dma(hsotg);
457062306a36Sopenharmony_ci	dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci	return 0;
457362306a36Sopenharmony_ci
457462306a36Sopenharmony_cierr:
457562306a36Sopenharmony_ci	hsotg->driver = NULL;
457662306a36Sopenharmony_ci	return ret;
457762306a36Sopenharmony_ci}
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci/**
458062306a36Sopenharmony_ci * dwc2_hsotg_udc_stop - stop the udc
458162306a36Sopenharmony_ci * @gadget: The usb gadget state
458262306a36Sopenharmony_ci *
458362306a36Sopenharmony_ci * Stop udc hw block and stay tunned for future transmissions
458462306a36Sopenharmony_ci */
458562306a36Sopenharmony_cistatic int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
458662306a36Sopenharmony_ci{
458762306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
458862306a36Sopenharmony_ci	unsigned long flags;
458962306a36Sopenharmony_ci	int ep;
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_ci	if (!hsotg)
459262306a36Sopenharmony_ci		return -ENODEV;
459362306a36Sopenharmony_ci
459462306a36Sopenharmony_ci	/* all endpoints should be shutdown */
459562306a36Sopenharmony_ci	for (ep = 1; ep < hsotg->num_of_eps; ep++) {
459662306a36Sopenharmony_ci		if (hsotg->eps_in[ep])
459762306a36Sopenharmony_ci			dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
459862306a36Sopenharmony_ci		if (hsotg->eps_out[ep])
459962306a36Sopenharmony_ci			dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
460062306a36Sopenharmony_ci	}
460162306a36Sopenharmony_ci
460262306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci	hsotg->driver = NULL;
460562306a36Sopenharmony_ci	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
460662306a36Sopenharmony_ci	hsotg->enabled = 0;
460762306a36Sopenharmony_ci
460862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
460962306a36Sopenharmony_ci
461062306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hsotg->uphy))
461162306a36Sopenharmony_ci		otg_set_peripheral(hsotg->uphy->otg, NULL);
461262306a36Sopenharmony_ci
461362306a36Sopenharmony_ci	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
461462306a36Sopenharmony_ci		dwc2_lowlevel_hw_disable(hsotg);
461562306a36Sopenharmony_ci
461662306a36Sopenharmony_ci	return 0;
461762306a36Sopenharmony_ci}
461862306a36Sopenharmony_ci
461962306a36Sopenharmony_ci/**
462062306a36Sopenharmony_ci * dwc2_hsotg_gadget_getframe - read the frame number
462162306a36Sopenharmony_ci * @gadget: The usb gadget state
462262306a36Sopenharmony_ci *
462362306a36Sopenharmony_ci * Read the {micro} frame number
462462306a36Sopenharmony_ci */
462562306a36Sopenharmony_cistatic int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget)
462662306a36Sopenharmony_ci{
462762306a36Sopenharmony_ci	return dwc2_hsotg_read_frameno(to_hsotg(gadget));
462862306a36Sopenharmony_ci}
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci/**
463162306a36Sopenharmony_ci * dwc2_hsotg_set_selfpowered - set if device is self/bus powered
463262306a36Sopenharmony_ci * @gadget: The usb gadget state
463362306a36Sopenharmony_ci * @is_selfpowered: Whether the device is self-powered
463462306a36Sopenharmony_ci *
463562306a36Sopenharmony_ci * Set if the device is self or bus powered.
463662306a36Sopenharmony_ci */
463762306a36Sopenharmony_cistatic int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget,
463862306a36Sopenharmony_ci				      int is_selfpowered)
463962306a36Sopenharmony_ci{
464062306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
464162306a36Sopenharmony_ci	unsigned long flags;
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
464462306a36Sopenharmony_ci	gadget->is_selfpowered = !!is_selfpowered;
464562306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci	return 0;
464862306a36Sopenharmony_ci}
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci/**
465162306a36Sopenharmony_ci * dwc2_hsotg_pullup - connect/disconnect the USB PHY
465262306a36Sopenharmony_ci * @gadget: The usb gadget state
465362306a36Sopenharmony_ci * @is_on: Current state of the USB PHY
465462306a36Sopenharmony_ci *
465562306a36Sopenharmony_ci * Connect/Disconnect the USB PHY pullup
465662306a36Sopenharmony_ci */
465762306a36Sopenharmony_cistatic int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
465862306a36Sopenharmony_ci{
465962306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
466062306a36Sopenharmony_ci	unsigned long flags;
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on,
466362306a36Sopenharmony_ci		hsotg->op_state);
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	/* Don't modify pullup state while in host mode */
466662306a36Sopenharmony_ci	if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) {
466762306a36Sopenharmony_ci		hsotg->enabled = is_on;
466862306a36Sopenharmony_ci		return 0;
466962306a36Sopenharmony_ci	}
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
467262306a36Sopenharmony_ci	if (is_on) {
467362306a36Sopenharmony_ci		hsotg->enabled = 1;
467462306a36Sopenharmony_ci		dwc2_hsotg_core_init_disconnected(hsotg, false);
467562306a36Sopenharmony_ci		/* Enable ACG feature in device mode,if supported */
467662306a36Sopenharmony_ci		dwc2_enable_acg(hsotg);
467762306a36Sopenharmony_ci		dwc2_hsotg_core_connect(hsotg);
467862306a36Sopenharmony_ci	} else {
467962306a36Sopenharmony_ci		dwc2_hsotg_core_disconnect(hsotg);
468062306a36Sopenharmony_ci		dwc2_hsotg_disconnect(hsotg);
468162306a36Sopenharmony_ci		hsotg->enabled = 0;
468262306a36Sopenharmony_ci	}
468362306a36Sopenharmony_ci
468462306a36Sopenharmony_ci	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
468562306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
468662306a36Sopenharmony_ci
468762306a36Sopenharmony_ci	return 0;
468862306a36Sopenharmony_ci}
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_cistatic int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
469162306a36Sopenharmony_ci{
469262306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
469362306a36Sopenharmony_ci	unsigned long flags;
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active);
469662306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_ci	/*
469962306a36Sopenharmony_ci	 * If controller is in partial power down state, it must exit from
470062306a36Sopenharmony_ci	 * that state before being initialized / de-initialized
470162306a36Sopenharmony_ci	 */
470262306a36Sopenharmony_ci	if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd)
470362306a36Sopenharmony_ci		/*
470462306a36Sopenharmony_ci		 * No need to check the return value as
470562306a36Sopenharmony_ci		 * registers are not being restored.
470662306a36Sopenharmony_ci		 */
470762306a36Sopenharmony_ci		dwc2_exit_partial_power_down(hsotg, 0, false);
470862306a36Sopenharmony_ci
470962306a36Sopenharmony_ci	if (is_active) {
471062306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_ci		dwc2_hsotg_core_init_disconnected(hsotg, false);
471362306a36Sopenharmony_ci		if (hsotg->enabled) {
471462306a36Sopenharmony_ci			/* Enable ACG feature in device mode,if supported */
471562306a36Sopenharmony_ci			dwc2_enable_acg(hsotg);
471662306a36Sopenharmony_ci			dwc2_hsotg_core_connect(hsotg);
471762306a36Sopenharmony_ci		}
471862306a36Sopenharmony_ci	} else {
471962306a36Sopenharmony_ci		dwc2_hsotg_core_disconnect(hsotg);
472062306a36Sopenharmony_ci		dwc2_hsotg_disconnect(hsotg);
472162306a36Sopenharmony_ci	}
472262306a36Sopenharmony_ci
472362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
472462306a36Sopenharmony_ci	return 0;
472562306a36Sopenharmony_ci}
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_ci/**
472862306a36Sopenharmony_ci * dwc2_hsotg_vbus_draw - report bMaxPower field
472962306a36Sopenharmony_ci * @gadget: The usb gadget state
473062306a36Sopenharmony_ci * @mA: Amount of current
473162306a36Sopenharmony_ci *
473262306a36Sopenharmony_ci * Report how much power the device may consume to the phy.
473362306a36Sopenharmony_ci */
473462306a36Sopenharmony_cistatic int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
473562306a36Sopenharmony_ci{
473662306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(hsotg->uphy))
473962306a36Sopenharmony_ci		return -ENOTSUPP;
474062306a36Sopenharmony_ci	return usb_phy_set_power(hsotg->uphy, mA);
474162306a36Sopenharmony_ci}
474262306a36Sopenharmony_ci
474362306a36Sopenharmony_cistatic void dwc2_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
474462306a36Sopenharmony_ci{
474562306a36Sopenharmony_ci	struct dwc2_hsotg *hsotg = to_hsotg(g);
474662306a36Sopenharmony_ci	unsigned long		flags;
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
474962306a36Sopenharmony_ci	switch (speed) {
475062306a36Sopenharmony_ci	case USB_SPEED_HIGH:
475162306a36Sopenharmony_ci		hsotg->params.speed = DWC2_SPEED_PARAM_HIGH;
475262306a36Sopenharmony_ci		break;
475362306a36Sopenharmony_ci	case USB_SPEED_FULL:
475462306a36Sopenharmony_ci		hsotg->params.speed = DWC2_SPEED_PARAM_FULL;
475562306a36Sopenharmony_ci		break;
475662306a36Sopenharmony_ci	case USB_SPEED_LOW:
475762306a36Sopenharmony_ci		hsotg->params.speed = DWC2_SPEED_PARAM_LOW;
475862306a36Sopenharmony_ci		break;
475962306a36Sopenharmony_ci	default:
476062306a36Sopenharmony_ci		dev_err(hsotg->dev, "invalid speed (%d)\n", speed);
476162306a36Sopenharmony_ci	}
476262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
476362306a36Sopenharmony_ci}
476462306a36Sopenharmony_ci
476562306a36Sopenharmony_cistatic const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
476662306a36Sopenharmony_ci	.get_frame	= dwc2_hsotg_gadget_getframe,
476762306a36Sopenharmony_ci	.set_selfpowered	= dwc2_hsotg_set_selfpowered,
476862306a36Sopenharmony_ci	.udc_start		= dwc2_hsotg_udc_start,
476962306a36Sopenharmony_ci	.udc_stop		= dwc2_hsotg_udc_stop,
477062306a36Sopenharmony_ci	.pullup                 = dwc2_hsotg_pullup,
477162306a36Sopenharmony_ci	.udc_set_speed		= dwc2_gadget_set_speed,
477262306a36Sopenharmony_ci	.vbus_session		= dwc2_hsotg_vbus_session,
477362306a36Sopenharmony_ci	.vbus_draw		= dwc2_hsotg_vbus_draw,
477462306a36Sopenharmony_ci};
477562306a36Sopenharmony_ci
477662306a36Sopenharmony_ci/**
477762306a36Sopenharmony_ci * dwc2_hsotg_initep - initialise a single endpoint
477862306a36Sopenharmony_ci * @hsotg: The device state.
477962306a36Sopenharmony_ci * @hs_ep: The endpoint to be initialised.
478062306a36Sopenharmony_ci * @epnum: The endpoint number
478162306a36Sopenharmony_ci * @dir_in: True if direction is in.
478262306a36Sopenharmony_ci *
478362306a36Sopenharmony_ci * Initialise the given endpoint (as part of the probe and device state
478462306a36Sopenharmony_ci * creation) to give to the gadget driver. Setup the endpoint name, any
478562306a36Sopenharmony_ci * direction information and other state that may be required.
478662306a36Sopenharmony_ci */
478762306a36Sopenharmony_cistatic void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg,
478862306a36Sopenharmony_ci			      struct dwc2_hsotg_ep *hs_ep,
478962306a36Sopenharmony_ci				       int epnum,
479062306a36Sopenharmony_ci				       bool dir_in)
479162306a36Sopenharmony_ci{
479262306a36Sopenharmony_ci	char *dir;
479362306a36Sopenharmony_ci
479462306a36Sopenharmony_ci	if (epnum == 0)
479562306a36Sopenharmony_ci		dir = "";
479662306a36Sopenharmony_ci	else if (dir_in)
479762306a36Sopenharmony_ci		dir = "in";
479862306a36Sopenharmony_ci	else
479962306a36Sopenharmony_ci		dir = "out";
480062306a36Sopenharmony_ci
480162306a36Sopenharmony_ci	hs_ep->dir_in = dir_in;
480262306a36Sopenharmony_ci	hs_ep->index = epnum;
480362306a36Sopenharmony_ci
480462306a36Sopenharmony_ci	snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir);
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci	INIT_LIST_HEAD(&hs_ep->queue);
480762306a36Sopenharmony_ci	INIT_LIST_HEAD(&hs_ep->ep.ep_list);
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ci	/* add to the list of endpoints known by the gadget driver */
481062306a36Sopenharmony_ci	if (epnum)
481162306a36Sopenharmony_ci		list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list);
481262306a36Sopenharmony_ci
481362306a36Sopenharmony_ci	hs_ep->parent = hsotg;
481462306a36Sopenharmony_ci	hs_ep->ep.name = hs_ep->name;
481562306a36Sopenharmony_ci
481662306a36Sopenharmony_ci	if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW)
481762306a36Sopenharmony_ci		usb_ep_set_maxpacket_limit(&hs_ep->ep, 8);
481862306a36Sopenharmony_ci	else
481962306a36Sopenharmony_ci		usb_ep_set_maxpacket_limit(&hs_ep->ep,
482062306a36Sopenharmony_ci					   epnum ? 1024 : EP0_MPS_LIMIT);
482162306a36Sopenharmony_ci	hs_ep->ep.ops = &dwc2_hsotg_ep_ops;
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	if (epnum == 0) {
482462306a36Sopenharmony_ci		hs_ep->ep.caps.type_control = true;
482562306a36Sopenharmony_ci	} else {
482662306a36Sopenharmony_ci		if (hsotg->params.speed != DWC2_SPEED_PARAM_LOW) {
482762306a36Sopenharmony_ci			hs_ep->ep.caps.type_iso = true;
482862306a36Sopenharmony_ci			hs_ep->ep.caps.type_bulk = true;
482962306a36Sopenharmony_ci		}
483062306a36Sopenharmony_ci		hs_ep->ep.caps.type_int = true;
483162306a36Sopenharmony_ci	}
483262306a36Sopenharmony_ci
483362306a36Sopenharmony_ci	if (dir_in)
483462306a36Sopenharmony_ci		hs_ep->ep.caps.dir_in = true;
483562306a36Sopenharmony_ci	else
483662306a36Sopenharmony_ci		hs_ep->ep.caps.dir_out = true;
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_ci	/*
483962306a36Sopenharmony_ci	 * if we're using dma, we need to set the next-endpoint pointer
484062306a36Sopenharmony_ci	 * to be something valid.
484162306a36Sopenharmony_ci	 */
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_ci	if (using_dma(hsotg)) {
484462306a36Sopenharmony_ci		u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15);
484562306a36Sopenharmony_ci
484662306a36Sopenharmony_ci		if (dir_in)
484762306a36Sopenharmony_ci			dwc2_writel(hsotg, next, DIEPCTL(epnum));
484862306a36Sopenharmony_ci		else
484962306a36Sopenharmony_ci			dwc2_writel(hsotg, next, DOEPCTL(epnum));
485062306a36Sopenharmony_ci	}
485162306a36Sopenharmony_ci}
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci/**
485462306a36Sopenharmony_ci * dwc2_hsotg_hw_cfg - read HW configuration registers
485562306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
485662306a36Sopenharmony_ci *
485762306a36Sopenharmony_ci * Read the USB core HW configuration registers
485862306a36Sopenharmony_ci */
485962306a36Sopenharmony_cistatic int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
486062306a36Sopenharmony_ci{
486162306a36Sopenharmony_ci	u32 cfg;
486262306a36Sopenharmony_ci	u32 ep_type;
486362306a36Sopenharmony_ci	u32 i;
486462306a36Sopenharmony_ci
486562306a36Sopenharmony_ci	/* check hardware configuration */
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci	hsotg->num_of_eps = hsotg->hw_params.num_dev_ep;
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci	/* Add ep0 */
487062306a36Sopenharmony_ci	hsotg->num_of_eps++;
487162306a36Sopenharmony_ci
487262306a36Sopenharmony_ci	hsotg->eps_in[0] = devm_kzalloc(hsotg->dev,
487362306a36Sopenharmony_ci					sizeof(struct dwc2_hsotg_ep),
487462306a36Sopenharmony_ci					GFP_KERNEL);
487562306a36Sopenharmony_ci	if (!hsotg->eps_in[0])
487662306a36Sopenharmony_ci		return -ENOMEM;
487762306a36Sopenharmony_ci	/* Same dwc2_hsotg_ep is used in both directions for ep0 */
487862306a36Sopenharmony_ci	hsotg->eps_out[0] = hsotg->eps_in[0];
487962306a36Sopenharmony_ci
488062306a36Sopenharmony_ci	cfg = hsotg->hw_params.dev_ep_dirs;
488162306a36Sopenharmony_ci	for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) {
488262306a36Sopenharmony_ci		ep_type = cfg & 3;
488362306a36Sopenharmony_ci		/* Direction in or both */
488462306a36Sopenharmony_ci		if (!(ep_type & 2)) {
488562306a36Sopenharmony_ci			hsotg->eps_in[i] = devm_kzalloc(hsotg->dev,
488662306a36Sopenharmony_ci				sizeof(struct dwc2_hsotg_ep), GFP_KERNEL);
488762306a36Sopenharmony_ci			if (!hsotg->eps_in[i])
488862306a36Sopenharmony_ci				return -ENOMEM;
488962306a36Sopenharmony_ci		}
489062306a36Sopenharmony_ci		/* Direction out or both */
489162306a36Sopenharmony_ci		if (!(ep_type & 1)) {
489262306a36Sopenharmony_ci			hsotg->eps_out[i] = devm_kzalloc(hsotg->dev,
489362306a36Sopenharmony_ci				sizeof(struct dwc2_hsotg_ep), GFP_KERNEL);
489462306a36Sopenharmony_ci			if (!hsotg->eps_out[i])
489562306a36Sopenharmony_ci				return -ENOMEM;
489662306a36Sopenharmony_ci		}
489762306a36Sopenharmony_ci	}
489862306a36Sopenharmony_ci
489962306a36Sopenharmony_ci	hsotg->fifo_mem = hsotg->hw_params.total_fifo_size;
490062306a36Sopenharmony_ci	hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo;
490162306a36Sopenharmony_ci
490262306a36Sopenharmony_ci	dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
490362306a36Sopenharmony_ci		 hsotg->num_of_eps,
490462306a36Sopenharmony_ci		 hsotg->dedicated_fifos ? "dedicated" : "shared",
490562306a36Sopenharmony_ci		 hsotg->fifo_mem);
490662306a36Sopenharmony_ci	return 0;
490762306a36Sopenharmony_ci}
490862306a36Sopenharmony_ci
490962306a36Sopenharmony_ci/**
491062306a36Sopenharmony_ci * dwc2_hsotg_dump - dump state of the udc
491162306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
491262306a36Sopenharmony_ci *
491362306a36Sopenharmony_ci */
491462306a36Sopenharmony_cistatic void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
491562306a36Sopenharmony_ci{
491662306a36Sopenharmony_ci#ifdef DEBUG
491762306a36Sopenharmony_ci	struct device *dev = hsotg->dev;
491862306a36Sopenharmony_ci	u32 val;
491962306a36Sopenharmony_ci	int idx;
492062306a36Sopenharmony_ci
492162306a36Sopenharmony_ci	dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n",
492262306a36Sopenharmony_ci		 dwc2_readl(hsotg, DCFG), dwc2_readl(hsotg, DCTL),
492362306a36Sopenharmony_ci		 dwc2_readl(hsotg, DIEPMSK));
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_ci	dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n",
492662306a36Sopenharmony_ci		 dwc2_readl(hsotg, GAHBCFG), dwc2_readl(hsotg, GHWCFG1));
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_ci	dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
492962306a36Sopenharmony_ci		 dwc2_readl(hsotg, GRXFSIZ), dwc2_readl(hsotg, GNPTXFSIZ));
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci	/* show periodic fifo settings */
493262306a36Sopenharmony_ci
493362306a36Sopenharmony_ci	for (idx = 1; idx < hsotg->num_of_eps; idx++) {
493462306a36Sopenharmony_ci		val = dwc2_readl(hsotg, DPTXFSIZN(idx));
493562306a36Sopenharmony_ci		dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
493662306a36Sopenharmony_ci			 val >> FIFOSIZE_DEPTH_SHIFT,
493762306a36Sopenharmony_ci			 val & FIFOSIZE_STARTADDR_MASK);
493862306a36Sopenharmony_ci	}
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci	for (idx = 0; idx < hsotg->num_of_eps; idx++) {
494162306a36Sopenharmony_ci		dev_info(dev,
494262306a36Sopenharmony_ci			 "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
494362306a36Sopenharmony_ci			 dwc2_readl(hsotg, DIEPCTL(idx)),
494462306a36Sopenharmony_ci			 dwc2_readl(hsotg, DIEPTSIZ(idx)),
494562306a36Sopenharmony_ci			 dwc2_readl(hsotg, DIEPDMA(idx)));
494662306a36Sopenharmony_ci
494762306a36Sopenharmony_ci		val = dwc2_readl(hsotg, DOEPCTL(idx));
494862306a36Sopenharmony_ci		dev_info(dev,
494962306a36Sopenharmony_ci			 "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n",
495062306a36Sopenharmony_ci			 idx, dwc2_readl(hsotg, DOEPCTL(idx)),
495162306a36Sopenharmony_ci			 dwc2_readl(hsotg, DOEPTSIZ(idx)),
495262306a36Sopenharmony_ci			 dwc2_readl(hsotg, DOEPDMA(idx)));
495362306a36Sopenharmony_ci	}
495462306a36Sopenharmony_ci
495562306a36Sopenharmony_ci	dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
495662306a36Sopenharmony_ci		 dwc2_readl(hsotg, DVBUSDIS), dwc2_readl(hsotg, DVBUSPULSE));
495762306a36Sopenharmony_ci#endif
495862306a36Sopenharmony_ci}
495962306a36Sopenharmony_ci
496062306a36Sopenharmony_ci/**
496162306a36Sopenharmony_ci * dwc2_gadget_init - init function for gadget
496262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
496362306a36Sopenharmony_ci *
496462306a36Sopenharmony_ci */
496562306a36Sopenharmony_ciint dwc2_gadget_init(struct dwc2_hsotg *hsotg)
496662306a36Sopenharmony_ci{
496762306a36Sopenharmony_ci	struct device *dev = hsotg->dev;
496862306a36Sopenharmony_ci	int epnum;
496962306a36Sopenharmony_ci	int ret;
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_ci	/* Dump fifo information */
497262306a36Sopenharmony_ci	dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
497362306a36Sopenharmony_ci		hsotg->params.g_np_tx_fifo_size);
497462306a36Sopenharmony_ci	dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size);
497562306a36Sopenharmony_ci
497662306a36Sopenharmony_ci	switch (hsotg->params.speed) {
497762306a36Sopenharmony_ci	case DWC2_SPEED_PARAM_LOW:
497862306a36Sopenharmony_ci		hsotg->gadget.max_speed = USB_SPEED_LOW;
497962306a36Sopenharmony_ci		break;
498062306a36Sopenharmony_ci	case DWC2_SPEED_PARAM_FULL:
498162306a36Sopenharmony_ci		hsotg->gadget.max_speed = USB_SPEED_FULL;
498262306a36Sopenharmony_ci		break;
498362306a36Sopenharmony_ci	default:
498462306a36Sopenharmony_ci		hsotg->gadget.max_speed = USB_SPEED_HIGH;
498562306a36Sopenharmony_ci		break;
498662306a36Sopenharmony_ci	}
498762306a36Sopenharmony_ci
498862306a36Sopenharmony_ci	hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
498962306a36Sopenharmony_ci	hsotg->gadget.name = dev_name(dev);
499062306a36Sopenharmony_ci	hsotg->gadget.otg_caps = &hsotg->params.otg_caps;
499162306a36Sopenharmony_ci	hsotg->remote_wakeup_allowed = 0;
499262306a36Sopenharmony_ci
499362306a36Sopenharmony_ci	if (hsotg->params.lpm)
499462306a36Sopenharmony_ci		hsotg->gadget.lpm_capable = true;
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	if (hsotg->dr_mode == USB_DR_MODE_OTG)
499762306a36Sopenharmony_ci		hsotg->gadget.is_otg = 1;
499862306a36Sopenharmony_ci	else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
499962306a36Sopenharmony_ci		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci	ret = dwc2_hsotg_hw_cfg(hsotg);
500262306a36Sopenharmony_ci	if (ret) {
500362306a36Sopenharmony_ci		dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret);
500462306a36Sopenharmony_ci		return ret;
500562306a36Sopenharmony_ci	}
500662306a36Sopenharmony_ci
500762306a36Sopenharmony_ci	hsotg->ctrl_buff = devm_kzalloc(hsotg->dev,
500862306a36Sopenharmony_ci			DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
500962306a36Sopenharmony_ci	if (!hsotg->ctrl_buff)
501062306a36Sopenharmony_ci		return -ENOMEM;
501162306a36Sopenharmony_ci
501262306a36Sopenharmony_ci	hsotg->ep0_buff = devm_kzalloc(hsotg->dev,
501362306a36Sopenharmony_ci			DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
501462306a36Sopenharmony_ci	if (!hsotg->ep0_buff)
501562306a36Sopenharmony_ci		return -ENOMEM;
501662306a36Sopenharmony_ci
501762306a36Sopenharmony_ci	if (using_desc_dma(hsotg)) {
501862306a36Sopenharmony_ci		ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg);
501962306a36Sopenharmony_ci		if (ret < 0)
502062306a36Sopenharmony_ci			return ret;
502162306a36Sopenharmony_ci	}
502262306a36Sopenharmony_ci
502362306a36Sopenharmony_ci	ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq,
502462306a36Sopenharmony_ci			       IRQF_SHARED, dev_name(hsotg->dev), hsotg);
502562306a36Sopenharmony_ci	if (ret < 0) {
502662306a36Sopenharmony_ci		dev_err(dev, "cannot claim IRQ for gadget\n");
502762306a36Sopenharmony_ci		return ret;
502862306a36Sopenharmony_ci	}
502962306a36Sopenharmony_ci
503062306a36Sopenharmony_ci	/* hsotg->num_of_eps holds number of EPs other than ep0 */
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	if (hsotg->num_of_eps == 0) {
503362306a36Sopenharmony_ci		dev_err(dev, "wrong number of EPs (zero)\n");
503462306a36Sopenharmony_ci		return -EINVAL;
503562306a36Sopenharmony_ci	}
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_ci	/* setup endpoint information */
503862306a36Sopenharmony_ci
503962306a36Sopenharmony_ci	INIT_LIST_HEAD(&hsotg->gadget.ep_list);
504062306a36Sopenharmony_ci	hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
504162306a36Sopenharmony_ci
504262306a36Sopenharmony_ci	/* allocate EP0 request */
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
504562306a36Sopenharmony_ci						     GFP_KERNEL);
504662306a36Sopenharmony_ci	if (!hsotg->ctrl_req) {
504762306a36Sopenharmony_ci		dev_err(dev, "failed to allocate ctrl req\n");
504862306a36Sopenharmony_ci		return -ENOMEM;
504962306a36Sopenharmony_ci	}
505062306a36Sopenharmony_ci
505162306a36Sopenharmony_ci	/* initialise the endpoints now the core has been initialised */
505262306a36Sopenharmony_ci	for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) {
505362306a36Sopenharmony_ci		if (hsotg->eps_in[epnum])
505462306a36Sopenharmony_ci			dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum],
505562306a36Sopenharmony_ci					  epnum, 1);
505662306a36Sopenharmony_ci		if (hsotg->eps_out[epnum])
505762306a36Sopenharmony_ci			dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum],
505862306a36Sopenharmony_ci					  epnum, 0);
505962306a36Sopenharmony_ci	}
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_ci	dwc2_hsotg_dump(hsotg);
506262306a36Sopenharmony_ci
506362306a36Sopenharmony_ci	return 0;
506462306a36Sopenharmony_ci}
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci/**
506762306a36Sopenharmony_ci * dwc2_hsotg_remove - remove function for hsotg driver
506862306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
506962306a36Sopenharmony_ci *
507062306a36Sopenharmony_ci */
507162306a36Sopenharmony_ciint dwc2_hsotg_remove(struct dwc2_hsotg *hsotg)
507262306a36Sopenharmony_ci{
507362306a36Sopenharmony_ci	usb_del_gadget_udc(&hsotg->gadget);
507462306a36Sopenharmony_ci	dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, hsotg->ctrl_req);
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci	return 0;
507762306a36Sopenharmony_ci}
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_ciint dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
508062306a36Sopenharmony_ci{
508162306a36Sopenharmony_ci	unsigned long flags;
508262306a36Sopenharmony_ci
508362306a36Sopenharmony_ci	if (hsotg->lx_state != DWC2_L0)
508462306a36Sopenharmony_ci		return 0;
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci	if (hsotg->driver) {
508762306a36Sopenharmony_ci		int ep;
508862306a36Sopenharmony_ci
508962306a36Sopenharmony_ci		dev_info(hsotg->dev, "suspending usb gadget %s\n",
509062306a36Sopenharmony_ci			 hsotg->driver->driver.name);
509162306a36Sopenharmony_ci
509262306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
509362306a36Sopenharmony_ci		if (hsotg->enabled)
509462306a36Sopenharmony_ci			dwc2_hsotg_core_disconnect(hsotg);
509562306a36Sopenharmony_ci		dwc2_hsotg_disconnect(hsotg);
509662306a36Sopenharmony_ci		hsotg->gadget.speed = USB_SPEED_UNKNOWN;
509762306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci		for (ep = 1; ep < hsotg->num_of_eps; ep++) {
510062306a36Sopenharmony_ci			if (hsotg->eps_in[ep])
510162306a36Sopenharmony_ci				dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
510262306a36Sopenharmony_ci			if (hsotg->eps_out[ep])
510362306a36Sopenharmony_ci				dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
510462306a36Sopenharmony_ci		}
510562306a36Sopenharmony_ci	}
510662306a36Sopenharmony_ci
510762306a36Sopenharmony_ci	return 0;
510862306a36Sopenharmony_ci}
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_ciint dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
511162306a36Sopenharmony_ci{
511262306a36Sopenharmony_ci	unsigned long flags;
511362306a36Sopenharmony_ci
511462306a36Sopenharmony_ci	if (hsotg->lx_state == DWC2_L2)
511562306a36Sopenharmony_ci		return 0;
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	if (hsotg->driver) {
511862306a36Sopenharmony_ci		dev_info(hsotg->dev, "resuming usb gadget %s\n",
511962306a36Sopenharmony_ci			 hsotg->driver->driver.name);
512062306a36Sopenharmony_ci
512162306a36Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
512262306a36Sopenharmony_ci		dwc2_hsotg_core_init_disconnected(hsotg, false);
512362306a36Sopenharmony_ci		if (hsotg->enabled) {
512462306a36Sopenharmony_ci			/* Enable ACG feature in device mode,if supported */
512562306a36Sopenharmony_ci			dwc2_enable_acg(hsotg);
512662306a36Sopenharmony_ci			dwc2_hsotg_core_connect(hsotg);
512762306a36Sopenharmony_ci		}
512862306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
512962306a36Sopenharmony_ci	}
513062306a36Sopenharmony_ci
513162306a36Sopenharmony_ci	return 0;
513262306a36Sopenharmony_ci}
513362306a36Sopenharmony_ci
513462306a36Sopenharmony_ci/**
513562306a36Sopenharmony_ci * dwc2_backup_device_registers() - Backup controller device registers.
513662306a36Sopenharmony_ci * When suspending usb bus, registers needs to be backuped
513762306a36Sopenharmony_ci * if controller power is disabled once suspended.
513862306a36Sopenharmony_ci *
513962306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
514062306a36Sopenharmony_ci */
514162306a36Sopenharmony_ciint dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
514262306a36Sopenharmony_ci{
514362306a36Sopenharmony_ci	struct dwc2_dregs_backup *dr;
514462306a36Sopenharmony_ci	int i;
514562306a36Sopenharmony_ci
514662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s\n", __func__);
514762306a36Sopenharmony_ci
514862306a36Sopenharmony_ci	/* Backup dev regs */
514962306a36Sopenharmony_ci	dr = &hsotg->dr_backup;
515062306a36Sopenharmony_ci
515162306a36Sopenharmony_ci	dr->dcfg = dwc2_readl(hsotg, DCFG);
515262306a36Sopenharmony_ci	dr->dctl = dwc2_readl(hsotg, DCTL);
515362306a36Sopenharmony_ci	dr->daintmsk = dwc2_readl(hsotg, DAINTMSK);
515462306a36Sopenharmony_ci	dr->diepmsk = dwc2_readl(hsotg, DIEPMSK);
515562306a36Sopenharmony_ci	dr->doepmsk = dwc2_readl(hsotg, DOEPMSK);
515662306a36Sopenharmony_ci
515762306a36Sopenharmony_ci	for (i = 0; i < hsotg->num_of_eps; i++) {
515862306a36Sopenharmony_ci		/* Backup IN EPs */
515962306a36Sopenharmony_ci		dr->diepctl[i] = dwc2_readl(hsotg, DIEPCTL(i));
516062306a36Sopenharmony_ci
516162306a36Sopenharmony_ci		/* Ensure DATA PID is correctly configured */
516262306a36Sopenharmony_ci		if (dr->diepctl[i] & DXEPCTL_DPID)
516362306a36Sopenharmony_ci			dr->diepctl[i] |= DXEPCTL_SETD1PID;
516462306a36Sopenharmony_ci		else
516562306a36Sopenharmony_ci			dr->diepctl[i] |= DXEPCTL_SETD0PID;
516662306a36Sopenharmony_ci
516762306a36Sopenharmony_ci		dr->dieptsiz[i] = dwc2_readl(hsotg, DIEPTSIZ(i));
516862306a36Sopenharmony_ci		dr->diepdma[i] = dwc2_readl(hsotg, DIEPDMA(i));
516962306a36Sopenharmony_ci
517062306a36Sopenharmony_ci		/* Backup OUT EPs */
517162306a36Sopenharmony_ci		dr->doepctl[i] = dwc2_readl(hsotg, DOEPCTL(i));
517262306a36Sopenharmony_ci
517362306a36Sopenharmony_ci		/* Ensure DATA PID is correctly configured */
517462306a36Sopenharmony_ci		if (dr->doepctl[i] & DXEPCTL_DPID)
517562306a36Sopenharmony_ci			dr->doepctl[i] |= DXEPCTL_SETD1PID;
517662306a36Sopenharmony_ci		else
517762306a36Sopenharmony_ci			dr->doepctl[i] |= DXEPCTL_SETD0PID;
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_ci		dr->doeptsiz[i] = dwc2_readl(hsotg, DOEPTSIZ(i));
518062306a36Sopenharmony_ci		dr->doepdma[i] = dwc2_readl(hsotg, DOEPDMA(i));
518162306a36Sopenharmony_ci		dr->dtxfsiz[i] = dwc2_readl(hsotg, DPTXFSIZN(i));
518262306a36Sopenharmony_ci	}
518362306a36Sopenharmony_ci	dr->valid = true;
518462306a36Sopenharmony_ci	return 0;
518562306a36Sopenharmony_ci}
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci/**
518862306a36Sopenharmony_ci * dwc2_restore_device_registers() - Restore controller device registers.
518962306a36Sopenharmony_ci * When resuming usb bus, device registers needs to be restored
519062306a36Sopenharmony_ci * if controller power were disabled.
519162306a36Sopenharmony_ci *
519262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
519362306a36Sopenharmony_ci * @remote_wakeup: Indicates whether resume is initiated by Device or Host.
519462306a36Sopenharmony_ci *
519562306a36Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
519662306a36Sopenharmony_ci */
519762306a36Sopenharmony_ciint dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
519862306a36Sopenharmony_ci{
519962306a36Sopenharmony_ci	struct dwc2_dregs_backup *dr;
520062306a36Sopenharmony_ci	int i;
520162306a36Sopenharmony_ci
520262306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "%s\n", __func__);
520362306a36Sopenharmony_ci
520462306a36Sopenharmony_ci	/* Restore dev regs */
520562306a36Sopenharmony_ci	dr = &hsotg->dr_backup;
520662306a36Sopenharmony_ci	if (!dr->valid) {
520762306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: no device registers to restore\n",
520862306a36Sopenharmony_ci			__func__);
520962306a36Sopenharmony_ci		return -EINVAL;
521062306a36Sopenharmony_ci	}
521162306a36Sopenharmony_ci	dr->valid = false;
521262306a36Sopenharmony_ci
521362306a36Sopenharmony_ci	if (!remote_wakeup)
521462306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->dctl, DCTL);
521562306a36Sopenharmony_ci
521662306a36Sopenharmony_ci	dwc2_writel(hsotg, dr->daintmsk, DAINTMSK);
521762306a36Sopenharmony_ci	dwc2_writel(hsotg, dr->diepmsk, DIEPMSK);
521862306a36Sopenharmony_ci	dwc2_writel(hsotg, dr->doepmsk, DOEPMSK);
521962306a36Sopenharmony_ci
522062306a36Sopenharmony_ci	for (i = 0; i < hsotg->num_of_eps; i++) {
522162306a36Sopenharmony_ci		/* Restore IN EPs */
522262306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->dieptsiz[i], DIEPTSIZ(i));
522362306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->diepdma[i], DIEPDMA(i));
522462306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i));
522562306a36Sopenharmony_ci		/** WA for enabled EPx's IN in DDMA mode. On entering to
522662306a36Sopenharmony_ci		 * hibernation wrong value read and saved from DIEPDMAx,
522762306a36Sopenharmony_ci		 * as result BNA interrupt asserted on hibernation exit
522862306a36Sopenharmony_ci		 * by restoring from saved area.
522962306a36Sopenharmony_ci		 */
523062306a36Sopenharmony_ci		if (using_desc_dma(hsotg) &&
523162306a36Sopenharmony_ci		    (dr->diepctl[i] & DXEPCTL_EPENA))
523262306a36Sopenharmony_ci			dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma;
523362306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->dtxfsiz[i], DPTXFSIZN(i));
523462306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->diepctl[i], DIEPCTL(i));
523562306a36Sopenharmony_ci		/* Restore OUT EPs */
523662306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i));
523762306a36Sopenharmony_ci		/* WA for enabled EPx's OUT in DDMA mode. On entering to
523862306a36Sopenharmony_ci		 * hibernation wrong value read and saved from DOEPDMAx,
523962306a36Sopenharmony_ci		 * as result BNA interrupt asserted on hibernation exit
524062306a36Sopenharmony_ci		 * by restoring from saved area.
524162306a36Sopenharmony_ci		 */
524262306a36Sopenharmony_ci		if (using_desc_dma(hsotg) &&
524362306a36Sopenharmony_ci		    (dr->doepctl[i] & DXEPCTL_EPENA))
524462306a36Sopenharmony_ci			dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma;
524562306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->doepdma[i], DOEPDMA(i));
524662306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->doepctl[i], DOEPCTL(i));
524762306a36Sopenharmony_ci	}
524862306a36Sopenharmony_ci
524962306a36Sopenharmony_ci	return 0;
525062306a36Sopenharmony_ci}
525162306a36Sopenharmony_ci
525262306a36Sopenharmony_ci/**
525362306a36Sopenharmony_ci * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode
525462306a36Sopenharmony_ci *
525562306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
525662306a36Sopenharmony_ci *
525762306a36Sopenharmony_ci */
525862306a36Sopenharmony_civoid dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
525962306a36Sopenharmony_ci{
526062306a36Sopenharmony_ci	u32 val;
526162306a36Sopenharmony_ci
526262306a36Sopenharmony_ci	if (!hsotg->params.lpm)
526362306a36Sopenharmony_ci		return;
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES;
526662306a36Sopenharmony_ci	val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0;
526762306a36Sopenharmony_ci	val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0;
526862306a36Sopenharmony_ci	val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT;
526962306a36Sopenharmony_ci	val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
527062306a36Sopenharmony_ci	val |= GLPMCFG_LPM_REJECT_CTRL_CONTROL;
527162306a36Sopenharmony_ci	val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC;
527262306a36Sopenharmony_ci	dwc2_writel(hsotg, val, GLPMCFG);
527362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));
527462306a36Sopenharmony_ci
527562306a36Sopenharmony_ci	/* Unmask WKUP_ALERT Interrupt */
527662306a36Sopenharmony_ci	if (hsotg->params.service_interval)
527762306a36Sopenharmony_ci		dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK);
527862306a36Sopenharmony_ci}
527962306a36Sopenharmony_ci
528062306a36Sopenharmony_ci/**
528162306a36Sopenharmony_ci * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode
528262306a36Sopenharmony_ci *
528362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller
528462306a36Sopenharmony_ci *
528562306a36Sopenharmony_ci */
528662306a36Sopenharmony_civoid dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
528762306a36Sopenharmony_ci{
528862306a36Sopenharmony_ci	u32 val = 0;
528962306a36Sopenharmony_ci
529062306a36Sopenharmony_ci	val |= GREFCLK_REF_CLK_MODE;
529162306a36Sopenharmony_ci	val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT;
529262306a36Sopenharmony_ci	val |= hsotg->params.sof_cnt_wkup_alert <<
529362306a36Sopenharmony_ci	       GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT;
529462306a36Sopenharmony_ci
529562306a36Sopenharmony_ci	dwc2_writel(hsotg, val, GREFCLK);
529662306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK));
529762306a36Sopenharmony_ci}
529862306a36Sopenharmony_ci
529962306a36Sopenharmony_ci/**
530062306a36Sopenharmony_ci * dwc2_gadget_enter_hibernation() - Put controller in Hibernation.
530162306a36Sopenharmony_ci *
530262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
530362306a36Sopenharmony_ci *
530462306a36Sopenharmony_ci * Return non-zero if failed to enter to hibernation.
530562306a36Sopenharmony_ci */
530662306a36Sopenharmony_ciint dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
530762306a36Sopenharmony_ci{
530862306a36Sopenharmony_ci	u32 gpwrdn;
530962306a36Sopenharmony_ci	int ret = 0;
531062306a36Sopenharmony_ci
531162306a36Sopenharmony_ci	/* Change to L2(suspend) state */
531262306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
531362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Start of hibernation completed\n");
531462306a36Sopenharmony_ci	ret = dwc2_backup_global_registers(hsotg);
531562306a36Sopenharmony_ci	if (ret) {
531662306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup global registers\n",
531762306a36Sopenharmony_ci			__func__);
531862306a36Sopenharmony_ci		return ret;
531962306a36Sopenharmony_ci	}
532062306a36Sopenharmony_ci	ret = dwc2_backup_device_registers(hsotg);
532162306a36Sopenharmony_ci	if (ret) {
532262306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup device registers\n",
532362306a36Sopenharmony_ci			__func__);
532462306a36Sopenharmony_ci		return ret;
532562306a36Sopenharmony_ci	}
532662306a36Sopenharmony_ci
532762306a36Sopenharmony_ci	gpwrdn = GPWRDN_PWRDNRSTN;
532862306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PMUACTV;
532962306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
533062306a36Sopenharmony_ci	udelay(10);
533162306a36Sopenharmony_ci
533262306a36Sopenharmony_ci	/* Set flag to indicate that we are in hibernation */
533362306a36Sopenharmony_ci	hsotg->hibernated = 1;
533462306a36Sopenharmony_ci
533562306a36Sopenharmony_ci	/* Enable interrupts from wake up logic */
533662306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
533762306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PMUINTSEL;
533862306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
533962306a36Sopenharmony_ci	udelay(10);
534062306a36Sopenharmony_ci
534162306a36Sopenharmony_ci	/* Unmask device mode interrupts in GPWRDN */
534262306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
534362306a36Sopenharmony_ci	gpwrdn |= GPWRDN_RST_DET_MSK;
534462306a36Sopenharmony_ci	gpwrdn |= GPWRDN_LNSTSCHG_MSK;
534562306a36Sopenharmony_ci	gpwrdn |= GPWRDN_STS_CHGINT_MSK;
534662306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
534762306a36Sopenharmony_ci	udelay(10);
534862306a36Sopenharmony_ci
534962306a36Sopenharmony_ci	/* Enable Power Down Clamp */
535062306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
535162306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PWRDNCLMP;
535262306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
535362306a36Sopenharmony_ci	udelay(10);
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_ci	/* Switch off VDD */
535662306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
535762306a36Sopenharmony_ci	gpwrdn |= GPWRDN_PWRDNSWTCH;
535862306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
535962306a36Sopenharmony_ci	udelay(10);
536062306a36Sopenharmony_ci
536162306a36Sopenharmony_ci	/* Save gpwrdn register for further usage if stschng interrupt */
536262306a36Sopenharmony_ci	hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg, GPWRDN);
536362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Hibernation completed\n");
536462306a36Sopenharmony_ci
536562306a36Sopenharmony_ci	return ret;
536662306a36Sopenharmony_ci}
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci/**
536962306a36Sopenharmony_ci * dwc2_gadget_exit_hibernation()
537062306a36Sopenharmony_ci * This function is for exiting from Device mode hibernation by host initiated
537162306a36Sopenharmony_ci * resume/reset and device initiated remote-wakeup.
537262306a36Sopenharmony_ci *
537362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
537462306a36Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by Device or Host.
537562306a36Sopenharmony_ci * @reset: indicates whether resume is initiated by Reset.
537662306a36Sopenharmony_ci *
537762306a36Sopenharmony_ci * Return non-zero if failed to exit from hibernation.
537862306a36Sopenharmony_ci */
537962306a36Sopenharmony_ciint dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
538062306a36Sopenharmony_ci				 int rem_wakeup, int reset)
538162306a36Sopenharmony_ci{
538262306a36Sopenharmony_ci	u32 pcgcctl;
538362306a36Sopenharmony_ci	u32 gpwrdn;
538462306a36Sopenharmony_ci	u32 dctl;
538562306a36Sopenharmony_ci	int ret = 0;
538662306a36Sopenharmony_ci	struct dwc2_gregs_backup *gr;
538762306a36Sopenharmony_ci	struct dwc2_dregs_backup *dr;
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ci	gr = &hsotg->gr_backup;
539062306a36Sopenharmony_ci	dr = &hsotg->dr_backup;
539162306a36Sopenharmony_ci
539262306a36Sopenharmony_ci	if (!hsotg->hibernated) {
539362306a36Sopenharmony_ci		dev_dbg(hsotg->dev, "Already exited from Hibernation\n");
539462306a36Sopenharmony_ci		return 1;
539562306a36Sopenharmony_ci	}
539662306a36Sopenharmony_ci	dev_dbg(hsotg->dev,
539762306a36Sopenharmony_ci		"%s: called with rem_wakeup = %d reset = %d\n",
539862306a36Sopenharmony_ci		__func__, rem_wakeup, reset);
539962306a36Sopenharmony_ci
540062306a36Sopenharmony_ci	dwc2_hib_restore_common(hsotg, rem_wakeup, 0);
540162306a36Sopenharmony_ci
540262306a36Sopenharmony_ci	if (!reset) {
540362306a36Sopenharmony_ci		/* Clear all pending interupts */
540462306a36Sopenharmony_ci		dwc2_writel(hsotg, 0xffffffff, GINTSTS);
540562306a36Sopenharmony_ci	}
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ci	/* De-assert Restore */
540862306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
540962306a36Sopenharmony_ci	gpwrdn &= ~GPWRDN_RESTORE;
541062306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
541162306a36Sopenharmony_ci	udelay(10);
541262306a36Sopenharmony_ci
541362306a36Sopenharmony_ci	if (!rem_wakeup) {
541462306a36Sopenharmony_ci		pcgcctl = dwc2_readl(hsotg, PCGCTL);
541562306a36Sopenharmony_ci		pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
541662306a36Sopenharmony_ci		dwc2_writel(hsotg, pcgcctl, PCGCTL);
541762306a36Sopenharmony_ci	}
541862306a36Sopenharmony_ci
541962306a36Sopenharmony_ci	/* Restore GUSBCFG, DCFG and DCTL */
542062306a36Sopenharmony_ci	dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
542162306a36Sopenharmony_ci	dwc2_writel(hsotg, dr->dcfg, DCFG);
542262306a36Sopenharmony_ci	dwc2_writel(hsotg, dr->dctl, DCTL);
542362306a36Sopenharmony_ci
542462306a36Sopenharmony_ci	/* On USB Reset, reset device address to zero */
542562306a36Sopenharmony_ci	if (reset)
542662306a36Sopenharmony_ci		dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK);
542762306a36Sopenharmony_ci
542862306a36Sopenharmony_ci	/* De-assert Wakeup Logic */
542962306a36Sopenharmony_ci	gpwrdn = dwc2_readl(hsotg, GPWRDN);
543062306a36Sopenharmony_ci	gpwrdn &= ~GPWRDN_PMUACTV;
543162306a36Sopenharmony_ci	dwc2_writel(hsotg, gpwrdn, GPWRDN);
543262306a36Sopenharmony_ci
543362306a36Sopenharmony_ci	if (rem_wakeup) {
543462306a36Sopenharmony_ci		udelay(10);
543562306a36Sopenharmony_ci		/* Start Remote Wakeup Signaling */
543662306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->dctl | DCTL_RMTWKUPSIG, DCTL);
543762306a36Sopenharmony_ci	} else {
543862306a36Sopenharmony_ci		udelay(50);
543962306a36Sopenharmony_ci		/* Set Device programming done bit */
544062306a36Sopenharmony_ci		dctl = dwc2_readl(hsotg, DCTL);
544162306a36Sopenharmony_ci		dctl |= DCTL_PWRONPRGDONE;
544262306a36Sopenharmony_ci		dwc2_writel(hsotg, dctl, DCTL);
544362306a36Sopenharmony_ci	}
544462306a36Sopenharmony_ci	/* Wait for interrupts which must be cleared */
544562306a36Sopenharmony_ci	mdelay(2);
544662306a36Sopenharmony_ci	/* Clear all pending interupts */
544762306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
544862306a36Sopenharmony_ci
544962306a36Sopenharmony_ci	/* Restore global registers */
545062306a36Sopenharmony_ci	ret = dwc2_restore_global_registers(hsotg);
545162306a36Sopenharmony_ci	if (ret) {
545262306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to restore registers\n",
545362306a36Sopenharmony_ci			__func__);
545462306a36Sopenharmony_ci		return ret;
545562306a36Sopenharmony_ci	}
545662306a36Sopenharmony_ci
545762306a36Sopenharmony_ci	/* Restore device registers */
545862306a36Sopenharmony_ci	ret = dwc2_restore_device_registers(hsotg, rem_wakeup);
545962306a36Sopenharmony_ci	if (ret) {
546062306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to restore device registers\n",
546162306a36Sopenharmony_ci			__func__);
546262306a36Sopenharmony_ci		return ret;
546362306a36Sopenharmony_ci	}
546462306a36Sopenharmony_ci
546562306a36Sopenharmony_ci	if (rem_wakeup) {
546662306a36Sopenharmony_ci		mdelay(10);
546762306a36Sopenharmony_ci		dctl = dwc2_readl(hsotg, DCTL);
546862306a36Sopenharmony_ci		dctl &= ~DCTL_RMTWKUPSIG;
546962306a36Sopenharmony_ci		dwc2_writel(hsotg, dctl, DCTL);
547062306a36Sopenharmony_ci	}
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci	hsotg->hibernated = 0;
547362306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
547462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Hibernation recovery completes here\n");
547562306a36Sopenharmony_ci
547662306a36Sopenharmony_ci	return ret;
547762306a36Sopenharmony_ci}
547862306a36Sopenharmony_ci
547962306a36Sopenharmony_ci/**
548062306a36Sopenharmony_ci * dwc2_gadget_enter_partial_power_down() - Put controller in partial
548162306a36Sopenharmony_ci * power down.
548262306a36Sopenharmony_ci *
548362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
548462306a36Sopenharmony_ci *
548562306a36Sopenharmony_ci * Return: non-zero if failed to enter device partial power down.
548662306a36Sopenharmony_ci *
548762306a36Sopenharmony_ci * This function is for entering device mode partial power down.
548862306a36Sopenharmony_ci */
548962306a36Sopenharmony_ciint dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
549062306a36Sopenharmony_ci{
549162306a36Sopenharmony_ci	u32 pcgcctl;
549262306a36Sopenharmony_ci	int ret = 0;
549362306a36Sopenharmony_ci
549462306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Entering device partial power down started.\n");
549562306a36Sopenharmony_ci
549662306a36Sopenharmony_ci	/* Backup all registers */
549762306a36Sopenharmony_ci	ret = dwc2_backup_global_registers(hsotg);
549862306a36Sopenharmony_ci	if (ret) {
549962306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup global registers\n",
550062306a36Sopenharmony_ci			__func__);
550162306a36Sopenharmony_ci		return ret;
550262306a36Sopenharmony_ci	}
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	ret = dwc2_backup_device_registers(hsotg);
550562306a36Sopenharmony_ci	if (ret) {
550662306a36Sopenharmony_ci		dev_err(hsotg->dev, "%s: failed to backup device registers\n",
550762306a36Sopenharmony_ci			__func__);
550862306a36Sopenharmony_ci		return ret;
550962306a36Sopenharmony_ci	}
551062306a36Sopenharmony_ci
551162306a36Sopenharmony_ci	/*
551262306a36Sopenharmony_ci	 * Clear any pending interrupts since dwc2 will not be able to
551362306a36Sopenharmony_ci	 * clear them after entering partial_power_down.
551462306a36Sopenharmony_ci	 */
551562306a36Sopenharmony_ci	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
551662306a36Sopenharmony_ci
551762306a36Sopenharmony_ci	/* Put the controller in low power state */
551862306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
551962306a36Sopenharmony_ci
552062306a36Sopenharmony_ci	pcgcctl |= PCGCTL_PWRCLMP;
552162306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
552262306a36Sopenharmony_ci	udelay(5);
552362306a36Sopenharmony_ci
552462306a36Sopenharmony_ci	pcgcctl |= PCGCTL_RSTPDWNMODULE;
552562306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
552662306a36Sopenharmony_ci	udelay(5);
552762306a36Sopenharmony_ci
552862306a36Sopenharmony_ci	pcgcctl |= PCGCTL_STOPPCLK;
552962306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
553062306a36Sopenharmony_ci
553162306a36Sopenharmony_ci	/* Set in_ppd flag to 1 as here core enters suspend. */
553262306a36Sopenharmony_ci	hsotg->in_ppd = 1;
553362306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
553462306a36Sopenharmony_ci
553562306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Entering device partial power down completed.\n");
553662306a36Sopenharmony_ci
553762306a36Sopenharmony_ci	return ret;
553862306a36Sopenharmony_ci}
553962306a36Sopenharmony_ci
554062306a36Sopenharmony_ci/*
554162306a36Sopenharmony_ci * dwc2_gadget_exit_partial_power_down() - Exit controller from device partial
554262306a36Sopenharmony_ci * power down.
554362306a36Sopenharmony_ci *
554462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
554562306a36Sopenharmony_ci * @restore: indicates whether need to restore the registers or not.
554662306a36Sopenharmony_ci *
554762306a36Sopenharmony_ci * Return: non-zero if failed to exit device partial power down.
554862306a36Sopenharmony_ci *
554962306a36Sopenharmony_ci * This function is for exiting from device mode partial power down.
555062306a36Sopenharmony_ci */
555162306a36Sopenharmony_ciint dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
555262306a36Sopenharmony_ci					bool restore)
555362306a36Sopenharmony_ci{
555462306a36Sopenharmony_ci	u32 pcgcctl;
555562306a36Sopenharmony_ci	u32 dctl;
555662306a36Sopenharmony_ci	struct dwc2_dregs_backup *dr;
555762306a36Sopenharmony_ci	int ret = 0;
555862306a36Sopenharmony_ci
555962306a36Sopenharmony_ci	dr = &hsotg->dr_backup;
556062306a36Sopenharmony_ci
556162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Exiting device partial Power Down started.\n");
556262306a36Sopenharmony_ci
556362306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
556462306a36Sopenharmony_ci	pcgcctl &= ~PCGCTL_STOPPCLK;
556562306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
556662306a36Sopenharmony_ci
556762306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
556862306a36Sopenharmony_ci	pcgcctl &= ~PCGCTL_PWRCLMP;
556962306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
557062306a36Sopenharmony_ci
557162306a36Sopenharmony_ci	pcgcctl = dwc2_readl(hsotg, PCGCTL);
557262306a36Sopenharmony_ci	pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
557362306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgcctl, PCGCTL);
557462306a36Sopenharmony_ci
557562306a36Sopenharmony_ci	udelay(100);
557662306a36Sopenharmony_ci	if (restore) {
557762306a36Sopenharmony_ci		ret = dwc2_restore_global_registers(hsotg);
557862306a36Sopenharmony_ci		if (ret) {
557962306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s: failed to restore registers\n",
558062306a36Sopenharmony_ci				__func__);
558162306a36Sopenharmony_ci			return ret;
558262306a36Sopenharmony_ci		}
558362306a36Sopenharmony_ci		/* Restore DCFG */
558462306a36Sopenharmony_ci		dwc2_writel(hsotg, dr->dcfg, DCFG);
558562306a36Sopenharmony_ci
558662306a36Sopenharmony_ci		ret = dwc2_restore_device_registers(hsotg, 0);
558762306a36Sopenharmony_ci		if (ret) {
558862306a36Sopenharmony_ci			dev_err(hsotg->dev, "%s: failed to restore device registers\n",
558962306a36Sopenharmony_ci				__func__);
559062306a36Sopenharmony_ci			return ret;
559162306a36Sopenharmony_ci		}
559262306a36Sopenharmony_ci	}
559362306a36Sopenharmony_ci
559462306a36Sopenharmony_ci	/* Set the Power-On Programming done bit */
559562306a36Sopenharmony_ci	dctl = dwc2_readl(hsotg, DCTL);
559662306a36Sopenharmony_ci	dctl |= DCTL_PWRONPRGDONE;
559762306a36Sopenharmony_ci	dwc2_writel(hsotg, dctl, DCTL);
559862306a36Sopenharmony_ci
559962306a36Sopenharmony_ci	/* Set in_ppd flag to 0 as here core exits from suspend. */
560062306a36Sopenharmony_ci	hsotg->in_ppd = 0;
560162306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
560262306a36Sopenharmony_ci
560362306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n");
560462306a36Sopenharmony_ci	return ret;
560562306a36Sopenharmony_ci}
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_ci/**
560862306a36Sopenharmony_ci * dwc2_gadget_enter_clock_gating() - Put controller in clock gating.
560962306a36Sopenharmony_ci *
561062306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
561162306a36Sopenharmony_ci *
561262306a36Sopenharmony_ci * Return: non-zero if failed to enter device partial power down.
561362306a36Sopenharmony_ci *
561462306a36Sopenharmony_ci * This function is for entering device mode clock gating.
561562306a36Sopenharmony_ci */
561662306a36Sopenharmony_civoid dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg)
561762306a36Sopenharmony_ci{
561862306a36Sopenharmony_ci	u32 pcgctl;
561962306a36Sopenharmony_ci
562062306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Entering device clock gating.\n");
562162306a36Sopenharmony_ci
562262306a36Sopenharmony_ci	/* Set the Phy Clock bit as suspend is received. */
562362306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
562462306a36Sopenharmony_ci	pcgctl |= PCGCTL_STOPPCLK;
562562306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
562662306a36Sopenharmony_ci	udelay(5);
562762306a36Sopenharmony_ci
562862306a36Sopenharmony_ci	/* Set the Gate hclk as suspend is received. */
562962306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
563062306a36Sopenharmony_ci	pcgctl |= PCGCTL_GATEHCLK;
563162306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
563262306a36Sopenharmony_ci	udelay(5);
563362306a36Sopenharmony_ci
563462306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L2;
563562306a36Sopenharmony_ci	hsotg->bus_suspended = true;
563662306a36Sopenharmony_ci}
563762306a36Sopenharmony_ci
563862306a36Sopenharmony_ci/*
563962306a36Sopenharmony_ci * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating.
564062306a36Sopenharmony_ci *
564162306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
564262306a36Sopenharmony_ci * @rem_wakeup: indicates whether remote wake up is enabled.
564362306a36Sopenharmony_ci *
564462306a36Sopenharmony_ci * This function is for exiting from device mode clock gating.
564562306a36Sopenharmony_ci */
564662306a36Sopenharmony_civoid dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup)
564762306a36Sopenharmony_ci{
564862306a36Sopenharmony_ci	u32 pcgctl;
564962306a36Sopenharmony_ci	u32 dctl;
565062306a36Sopenharmony_ci
565162306a36Sopenharmony_ci	dev_dbg(hsotg->dev, "Exiting device clock gating.\n");
565262306a36Sopenharmony_ci
565362306a36Sopenharmony_ci	/* Clear the Gate hclk. */
565462306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
565562306a36Sopenharmony_ci	pcgctl &= ~PCGCTL_GATEHCLK;
565662306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
565762306a36Sopenharmony_ci	udelay(5);
565862306a36Sopenharmony_ci
565962306a36Sopenharmony_ci	/* Phy Clock bit. */
566062306a36Sopenharmony_ci	pcgctl = dwc2_readl(hsotg, PCGCTL);
566162306a36Sopenharmony_ci	pcgctl &= ~PCGCTL_STOPPCLK;
566262306a36Sopenharmony_ci	dwc2_writel(hsotg, pcgctl, PCGCTL);
566362306a36Sopenharmony_ci	udelay(5);
566462306a36Sopenharmony_ci
566562306a36Sopenharmony_ci	if (rem_wakeup) {
566662306a36Sopenharmony_ci		/* Set Remote Wakeup Signaling */
566762306a36Sopenharmony_ci		dctl = dwc2_readl(hsotg, DCTL);
566862306a36Sopenharmony_ci		dctl |= DCTL_RMTWKUPSIG;
566962306a36Sopenharmony_ci		dwc2_writel(hsotg, dctl, DCTL);
567062306a36Sopenharmony_ci	}
567162306a36Sopenharmony_ci
567262306a36Sopenharmony_ci	/* Change to L0 state */
567362306a36Sopenharmony_ci	call_gadget(hsotg, resume);
567462306a36Sopenharmony_ci	hsotg->lx_state = DWC2_L0;
567562306a36Sopenharmony_ci	hsotg->bus_suspended = false;
567662306a36Sopenharmony_ci}
5677