Commit 5b738211 authored by Thinh Nguyen's avatar Thinh Nguyen Committed by Greg Kroah-Hartman
Browse files

usb: dwc3: gadget: Don't send unintended link state change



DCTL.ULSTCHNGREQ is a write-only field. When doing a read-modify-write
to DCTL, the driver must make sure that there's no unintended link state
change request from whatever is read from DCTL.ULSTCHNGREQ. Set link
state change to no-action when the driver writes to DCTL.

Signed-off-by: default avatarThinh Nguyen <thinhn@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 704a940d
Loading
Loading
Loading
Loading
+7 −9
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
		return -EINVAL;
	}

	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
	dwc3_gadget_dctl_write_safe(dwc, reg);

	return 0;
}
@@ -1828,7 +1828,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
		dwc->pullups_connected = false;
	}

	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
	dwc3_gadget_dctl_write_safe(dwc, reg);

	do {
		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
@@ -2761,10 +2761,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg &= ~DWC3_DCTL_INITU1ENA;
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);

	reg &= ~DWC3_DCTL_INITU2ENA;
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
	dwc3_gadget_dctl_write_safe(dwc, reg);

	dwc3_disconnect_gadget(dwc);

@@ -2816,7 +2814,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
	dwc3_gadget_dctl_write_safe(dwc, reg);
	dwc->test_mode = false;
	dwc3_clear_stall_all_ep(dwc);

@@ -2920,11 +2918,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
		if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
			reg |= DWC3_DCTL_NYET_THRES(dwc->lpm_nyet_threshold);

		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
		dwc3_gadget_dctl_write_safe(dwc, reg);
	} else {
		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
		reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
		dwc3_gadget_dctl_write_safe(dwc, reg);
	}

	dep = dwc->eps[0];
@@ -3033,7 +3031,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,

				reg &= ~u1u2;

				dwc3_writel(dwc->regs, DWC3_DCTL, reg);
				dwc3_gadget_dctl_write_safe(dwc, reg);
				break;
			default:
				/* do nothing */
+14 −0
Original line number Diff line number Diff line
@@ -127,4 +127,18 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
	dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id);
}

/**
 * dwc3_gadget_dctl_write_safe - write to DCTL safe from link state change
 * @dwc: pointer to our context structure
 * @value: value to write to DCTL
 *
 * Use this function when doing read-modify-write to DCTL. It will not
 * send link state change request.
 */
static inline void dwc3_gadget_dctl_write_safe(struct dwc3 *dwc, u32 value)
{
	value &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
	dwc3_writel(dwc->regs, DWC3_DCTL, value);
}

#endif /* __DRIVERS_USB_DWC3_GADGET_H */