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

Commit 544dc9d3 authored by Sriharsha Allenki's avatar Sriharsha Allenki Committed by Jack Pham
Browse files

usb: dwc3: Use pwr_event_irq to wakeup if there is no ss_phy_irq



On platforms where there is no support for ss_phy_irq,
pwr_event_irq is used for wakeup events from SS PHY. Add
the proper programming to enable the Superspeed wakeup events
and do not suspend SS PHY to get these wakeup events.

Change-Id: I812fb13f6b59cfab07532d6e42baa9fe46568c03
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent dc2ecf77
Loading
Loading
Loading
Loading
+58 −1
Original line number Original line Diff line number Diff line
@@ -75,6 +75,7 @@
#define PWR_EVNT_POWERDOWN_OUT_P3_MASK		BIT(3)
#define PWR_EVNT_POWERDOWN_OUT_P3_MASK		BIT(3)
#define PWR_EVNT_LPM_IN_L2_MASK			BIT(4)
#define PWR_EVNT_LPM_IN_L2_MASK			BIT(4)
#define PWR_EVNT_LPM_OUT_L2_MASK		BIT(5)
#define PWR_EVNT_LPM_OUT_L2_MASK		BIT(5)
#define PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK	BIT(12)
#define PWR_EVNT_LPM_OUT_L1_MASK		BIT(13)
#define PWR_EVNT_LPM_OUT_L1_MASK		BIT(13)


/* QSCRATCH_GENERAL_CFG register bit offset */
/* QSCRATCH_GENERAL_CFG register bit offset */
@@ -247,6 +248,7 @@ struct dwc3_msm {
	bool			suspend;
	bool			suspend;
	bool			use_pdc_interrupts;
	bool			use_pdc_interrupts;
	enum dwc3_id_state	id_state;
	enum dwc3_id_state	id_state;
	bool			use_pwr_event_for_wakeup;
	unsigned long		lpm_flags;
	unsigned long		lpm_flags;
#define MDWC3_SS_PHY_SUSPEND		BIT(0)
#define MDWC3_SS_PHY_SUSPEND		BIT(0)
#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY	BIT(1)
#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY	BIT(1)
@@ -2207,6 +2209,27 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc,
	}
	}
}
}


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

	irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG);

	/* clear pending interrupts */
	dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_stat);

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

	if (on)
		irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK |
					PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
	else
		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);
}

static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv)
static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv)
{
{
	int ret = 0;
	int ret = 0;
@@ -2246,6 +2269,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	struct dwc3_event_buffer *evt;
	struct dwc3_event_buffer *evt;
	struct usb_irq *uirq;
	struct usb_irq *uirq;
	bool can_suspend_ssphy, no_active_ss;


	mutex_lock(&mdwc->suspend_resume_mutex);
	mutex_lock(&mdwc->suspend_resume_mutex);
	if (atomic_read(&dwc->in_lpm)) {
	if (atomic_read(&dwc->in_lpm)) {
@@ -2321,8 +2345,20 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
	/* Suspend HS PHY */
	/* Suspend HS PHY */
	usb_phy_set_suspend(mdwc->hs_phy, 1);
	usb_phy_set_suspend(mdwc->hs_phy, 1);


	/*
	 * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect
	 * any wakeup events in host mode PHY cannot be suspended.
	 * This Superspeed PHY can be suspended only in the following cases:
	 *	1. The core is not in host mode
	 *	2. A Highspeed device is connected but not a Superspeed device
	 */
	no_active_ss = (!mdwc->in_host_mode) || (mdwc->in_host_mode &&
		((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);
	/* Suspend SS PHY */
	/* Suspend SS PHY */
	if (dwc->maximum_speed >= USB_SPEED_SUPER) {
	if (can_suspend_ssphy) {
		if (mdwc->in_host_mode) {
		if (mdwc->in_host_mode) {
			u32 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
			u32 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));


@@ -2334,6 +2370,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
			mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE;
			mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE;
		usb_phy_set_suspend(mdwc->ss_phy, 1);
		usb_phy_set_suspend(mdwc->ss_phy, 1);
		mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND;
		mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND;
	} else if (mdwc->use_pwr_event_for_wakeup) {
		dwc3_msm_set_ss_pwr_events(mdwc, true);
		enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
	}
	}


	/* make sure above writes are completed before turning off clocks */
	/* make sure above writes are completed before turning off clocks */
@@ -2489,6 +2528,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
	if (mdwc->bus_aggr_clk)
	if (mdwc->bus_aggr_clk)
		clk_prepare_enable(mdwc->bus_aggr_clk);
		clk_prepare_enable(mdwc->bus_aggr_clk);


	/*
	 * 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)) {
		disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
		dwc3_msm_set_ss_pwr_events(mdwc, false);
	}

	/* Resume SS PHY */
	/* Resume SS PHY */
	if (dwc->maximum_speed >= USB_SPEED_SUPER &&
	if (dwc->maximum_speed >= USB_SPEED_SUPER &&
			mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) {
			mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) {
@@ -3541,6 +3590,14 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		goto put_dwc3;
		goto put_dwc3;
	}
	}


	/*
	 * 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;


	/* IOMMU will be reattached upon each resume/connect */
	/* IOMMU will be reattached upon each resume/connect */
	if (mdwc->iommu_map)
	if (mdwc->iommu_map)
		__depr_arm_iommu_detach_device(mdwc->dev);
		__depr_arm_iommu_detach_device(mdwc->dev);