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

Commit 774e9013 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: Use pwr_evt_irq to wakeup if dp/dm directly connected to GIC"

parents 7c784bfe 11760143
Loading
Loading
Loading
Loading
+72 −24
Original line number Diff line number Diff line
@@ -490,11 +490,15 @@ struct dwc3_msm {
	bool			suspend;
	bool			use_pdc_interrupts;
	enum dwc3_id_state	id_state;
	bool			use_pwr_event_for_wakeup;
	unsigned long		use_pwr_event_for_wakeup;
#define PWR_EVENT_SS_WAKEUP		BIT(0)
#define PWR_EVENT_HS_WAKEUP		BIT(1)

	unsigned long		lpm_flags;
#define MDWC3_SS_PHY_SUSPEND		BIT(0)
#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY	BIT(1)
#define MDWC3_POWER_COLLAPSE		BIT(2)
#define MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP BIT(3)

	struct extcon_nb	*extcon;
	int			ext_idx;
@@ -3047,7 +3051,7 @@ static void configure_usb_wakeup_interrupt(struct dwc3_msm *mdwc,
	}
}

static void enable_usb_pdc_interrupt(struct dwc3_msm *mdwc, bool enable)
static void configure_usb_wakeup_interrupts(struct dwc3_msm *mdwc, bool enable)
{
	if (!enable)
		goto disable_usb_irq;
@@ -3131,7 +3135,7 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc,
	}
}

static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on)
static void dwc3_msm_set_pwr_events(struct dwc3_msm *mdwc, bool on)
{
	u32 irq_mask, irq_stat;

@@ -3142,12 +3146,28 @@ static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on)

	irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG);

	if (on)
	if (on) {
		/*
		 * In case of platforms which use mpm interrupts, in case where
		 * suspend happens with a hs/fs/ls device connected in host mode.
		 * DP/DM falling edge will be monitored, but gic doesn't have
		 * capability to detect falling edge. So program power event irq
		 * to notify exit from lpm in such case.
		 */
		if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_HS_WAKEUP)
			irq_mask |= PWR_EVNT_LPM_OUT_L2_MASK;
		if ((mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP)
					&& !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND))
			irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK |
						PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
	else
	} else {
		if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_HS_WAKEUP)
			irq_mask &= ~PWR_EVNT_LPM_OUT_L2_MASK;
		if ((mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP)
					&& !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND))
			irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK |
						PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
	}

	dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask);
}
@@ -3280,7 +3300,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
		((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) &&
			!dwc3_msm_is_superspeed(mdwc)));
	can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER &&
			(!mdwc->use_pwr_event_for_wakeup || no_active_ss ||
			(!(mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) || no_active_ss ||
			 !enable_wakeup);
	/* Suspend SS PHY */
	if (can_suspend_ssphy) {
@@ -3306,10 +3326,21 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
		usb_phy_set_suspend(mdwc->ss_phy, 1);
		usb_phy_set_suspend(mdwc->ss_phy1, 1);
		mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND;
	} else if (mdwc->use_pwr_event_for_wakeup) {
		dwc3_msm_set_ss_pwr_events(mdwc, true);
	} else if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) {
		mdwc->lpm_flags |= MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP;
	}

	/*
	 * When operating in HS host mode, check if pwr event IRQ is
	 * required for wakeup.
	 */
	if (mdwc->in_host_mode && (mdwc->use_pwr_event_for_wakeup
						& PWR_EVENT_HS_WAKEUP))
		mdwc->lpm_flags |= MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP;

	if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP)
		dwc3_msm_set_pwr_events(mdwc, true);

	/* make sure above writes are completed before turning off clocks */
	wmb();

@@ -3361,11 +3392,13 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
	/*
	 * with the core in power collapse, we dont require wakeup
	 * using HS_PHY_IRQ or SS_PHY_IRQ. Hence enable wakeup only in
	 * case of host bus suspend and device bus suspend.
	 * case of host bus suspend and device bus suspend. Also in
	 * case of platforms with mpm interrupts and snps phy, enable
	 * dpse hsphy irq and dmse hsphy irq as done for pdc interrupts.
	 */
	if (!(mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) && enable_wakeup) {
		if (mdwc->use_pdc_interrupts) {
			enable_usb_pdc_interrupt(mdwc, true);
		if (mdwc->use_pdc_interrupts || !mdwc->wakeup_irq[HS_PHY_IRQ].irq) {
			configure_usb_wakeup_interrupts(mdwc, true);
		} else {
			uirq = &mdwc->wakeup_irq[HS_PHY_IRQ];
			configure_nonpdc_usb_interrupt(mdwc, uirq, true);
@@ -3375,8 +3408,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
		mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
	}

	if (mdwc->use_pwr_event_for_wakeup &&
			!(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND))
	if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP)
		enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);

	dev_info(mdwc->dev, "DWC3 in low power mode\n");
@@ -3471,10 +3503,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
	 * Disable any wakeup events that were enabled if pwr_event_irq
	 * is used as wakeup interrupt.
	 */
	if (mdwc->use_pwr_event_for_wakeup &&
			!(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) {
	if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP) {
		disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
		dwc3_msm_set_ss_pwr_events(mdwc, false);
		dwc3_msm_set_pwr_events(mdwc, false);
		mdwc->lpm_flags &= ~MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP;
	}

	/* Resume SS PHY */
@@ -3545,8 +3577,8 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)

	/* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */
	if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) {
		if (mdwc->use_pdc_interrupts) {
			enable_usb_pdc_interrupt(mdwc, false);
		if (mdwc->use_pdc_interrupts || !mdwc->wakeup_irq[HS_PHY_IRQ].irq) {
			configure_usb_wakeup_interrupts(mdwc, false);
		} else {
			uirq = &mdwc->wakeup_irq[HS_PHY_IRQ];
			configure_nonpdc_usb_interrupt(mdwc, uirq, false);
@@ -3794,6 +3826,13 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc)
		irq_clear |= PWR_EVNT_LPM_OUT_L1_MASK;
	}

	/* Handle exit from L2 events */
	if (irq_stat & PWR_EVNT_LPM_OUT_L2_MASK) {
		dev_dbg(mdwc->dev, "%s: handling PWR_EVNT_LPM_OUT_L2_MASK\n",
				__func__);
		irq_stat &= ~PWR_EVNT_LPM_OUT_L2_MASK;
		irq_clear |= PWR_EVNT_LPM_OUT_L2_MASK;
	}
	/* Unhandled events */
	if (irq_stat)
		dev_dbg(mdwc->dev, "%s: unexpected PWR_EVNT, irq_stat=%X\n",
@@ -4898,8 +4937,17 @@ static int dwc3_msm_probe(struct platform_device *pdev)
	 * On platforms with SS PHY that do not support ss_phy_irq for wakeup
	 * events, use pwr_event_irq for wakeup events in superspeed mode.
	 */
	mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER
					&& !mdwc->wakeup_irq[SS_PHY_IRQ].irq;
	if (dwc->maximum_speed >= USB_SPEED_SUPER
			&& !mdwc->wakeup_irq[SS_PHY_IRQ].irq)
		mdwc->use_pwr_event_for_wakeup |= PWR_EVENT_SS_WAKEUP;

	/*
	 * On platforms with mpm interrupts and snps phy, when operating in
	 * HS host mode use power event irq for wakeup events as GIC is not
	 * capable to detect falling edge of dp/dm hsphy irq.
	 */
	if (!mdwc->use_pdc_interrupts && !mdwc->wakeup_irq[HS_PHY_IRQ].irq)
		mdwc->use_pwr_event_for_wakeup |= PWR_EVENT_HS_WAKEUP;

	/*
	 * Clocks and regulators will not be turned on until the first time