Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79d6b8c5 authored by Sevak Arakelyan's avatar Sevak Arakelyan Committed by Felipe Balbi
Browse files

usb: dwc2: Update bit polling functionality



Move dwc2_hsotg_wait_bit_set function to core.c so it can be used
anywhere in the code.

Added dwc2_hsotg_wait_bit_clear function in core.c.

Replace all the parts of register bit polling code with
dwc2_hsotg_wait_bit_set or dwc2_hsotg_wait_bit_clear functions
calls depends on code logic.

Acked-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarSevak Arakelyan <sevaka@synopsys.com>
Signed-off-by: default avatarGrigor Tovmasyan <tovmasya@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent d14ccaba
Loading
Loading
Loading
Loading
+64 −44
Original line number Diff line number Diff line
@@ -317,7 +317,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
{
	u32 greset;
	int count = 0;
	bool wait_for_host_mode = false;

	dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -346,29 +345,19 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
	greset = dwc2_readl(hsotg->regs + GRSTCTL);
	greset |= GRSTCTL_CSFTRST;
	dwc2_writel(greset, hsotg->regs + GRSTCTL);
	do {
		udelay(1);
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 50) {
			dev_warn(hsotg->dev,
				 "%s() HANG! Soft Reset GRSTCTL=%0x\n",
				 __func__, greset);

	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
		dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
			 __func__);
		return -EBUSY;
	}
	} while (greset & GRSTCTL_CSFTRST);

	/* Wait for AHB master IDLE state */
	count = 0;
	do {
		udelay(1);
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 50) {
			dev_warn(hsotg->dev,
				 "%s() HANG! AHB Idle GRSTCTL=%0x\n",
				 __func__, greset);
	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
		dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
			 __func__);
		return -EBUSY;
	}
	} while (!(greset & GRSTCTL_AHBIDLE));

	if (wait_for_host_mode && !skip_wait)
		dwc2_wait_for_mode(hsotg, true);
@@ -683,7 +672,6 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
{
	u32 greset;
	int count = 0;

	dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);

@@ -691,17 +679,9 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
	greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
	dwc2_writel(greset, hsotg->regs + GRSTCTL);

	do {
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 10000) {
			dev_warn(hsotg->dev,
				 "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
				 __func__, greset,
				 dwc2_readl(hsotg->regs + GNPTXSTS));
			break;
		}
		udelay(1);
	} while (greset & GRSTCTL_TXFFLSH);
	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
		dev_warn(hsotg->dev, "%s:  HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
			 __func__);

	/* Wait for at least 3 PHY Clocks */
	udelay(1);
@@ -715,22 +695,16 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
{
	u32 greset;
	int count = 0;

	dev_vdbg(hsotg->dev, "%s()\n", __func__);

	greset = GRSTCTL_RXFFLSH;
	dwc2_writel(greset, hsotg->regs + GRSTCTL);

	do {
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 10000) {
			dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
				 __func__, greset);
			break;
		}
		udelay(1);
	} while (greset & GRSTCTL_RXFFLSH);
	/* Wait for RxFIFO flush done */
	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
		dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n",
			 __func__);

	/* Wait for at least 3 PHY Clocks */
	udelay(1);
@@ -825,6 +799,52 @@ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
}

/**
 * dwc2_hsotg_wait_bit_set - Waits for bit to be set.
 * @hsotg: Programming view of DWC_otg controller.
 * @offset: Register's offset where bit/bits must be set.
 * @mask: Mask of the bit/bits which must be set.
 * @timeout: Timeout to wait.
 *
 * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
 */
int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
			    u32 timeout)
{
	u32 i;

	for (i = 0; i < timeout; i++) {
		if (dwc2_readl(hsotg->regs + offset) & mask)
			return 0;
		udelay(1);
	}

	return -ETIMEDOUT;
}

/**
 * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear.
 * @hsotg: Programming view of DWC_otg controller.
 * @offset: Register's offset where bit/bits must be set.
 * @mask: Mask of the bit/bits which must be set.
 * @timeout: Timeout to wait.
 *
 * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
 */
int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
			      u32 timeout)
{
	u32 i;

	for (i = 0; i < timeout; i++) {
		if (!(dwc2_readl(hsotg->regs + offset) & mask))
			return 0;
		udelay(1);
	}

	return -ETIMEDOUT;
}

MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
MODULE_AUTHOR("Synopsys, Inc.");
MODULE_LICENSE("Dual BSD/GPL");
+5 −0
Original line number Diff line number Diff line
@@ -1142,6 +1142,11 @@ extern const struct of_device_id dwc2_of_match_table[];
int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);

/* Common polling functions */
int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg, u32 bit,
			    u32 timeout);
int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hs_otg, u32 reg, u32 bit,
			      u32 timeout);
/* Parameters */
int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
int dwc2_init_params(struct dwc2_hsotg *hsotg);
+4 −34
Original line number Diff line number Diff line
@@ -252,6 +252,7 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
	unsigned int ep;
	unsigned int addr;
	int timeout;

	u32 val;
	u32 *txfsz = hsotg->params.g_tx_fifo_size;

@@ -2495,30 +2496,13 @@ static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
 */
static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx)
{
	int timeout;
	int val;

	dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH,
		    hsotg->regs + GRSTCTL);

	/* wait until the fifo is flushed */
	timeout = 100;

	while (1) {
		val = dwc2_readl(hsotg->regs + GRSTCTL);

		if ((val & (GRSTCTL_TXFFLSH)) == 0)
			break;

		if (--timeout == 0) {
			dev_err(hsotg->dev,
				"%s: timeout flushing fifo (GRSTCTL=%08x)\n",
				__func__, val);
			break;
		}

		udelay(1);
	}
	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100))
		dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n",
			 __func__);
}

/**
@@ -3676,20 +3660,6 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
	return IRQ_HANDLED;
}

static int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg,
				   u32 bit, u32 timeout)
{
	u32 i;

	for (i = 0; i < timeout; i++) {
		if (dwc2_readl(hs_otg->regs + reg) & bit)
			return 0;
		udelay(1);
	}

	return -ETIMEDOUT;
}

static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
				   struct dwc2_hsotg_ep *hs_ep)
{
+6 −12
Original line number Diff line number Diff line
@@ -2403,24 +2403,18 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)

		/* Halt all channels to put them into a known state */
		for (i = 0; i < num_channels; i++) {
			int count = 0;

			hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
			hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
			hcchar &= ~HCCHAR_EPDIR;
			dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
			dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
				__func__, i);
			do {
				hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
				if (++count > 1000) {
					dev_err(hsotg->dev,
						"Unable to clear enable on channel %d\n",

			if (dwc2_hsotg_wait_bit_clear(hsotg, HCCHAR(i),
						      HCCHAR_CHENA, 1000)) {
				dev_warn(hsotg->dev, "Unable to clear enable on channel %d\n",
					 i);
					break;
			}
				udelay(1);
			} while (hcchar & HCCHAR_CHENA);
		}
	}