Commit 012466fc authored by Artur Petrosyan's avatar Artur Petrosyan Committed by Greg Kroah-Hartman
Browse files

usb: dwc2: Add device clock gating support functions



Added device clock gating support functions according
programming guide.

Moved "bus_suspended" flag to "dwc2_hsotg" struct because
we need to set that flag while entering to clock gating
in case when the driver is built in peripheral mode.

Added function names:
dwc2_gadget_enter_clock_gating()
dwc2_gadget_exit_clock_gating()

Acked-by: default avatarMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Signed-off-by: default avatarArtur Petrosyan <Arthur.Petrosyan@synopsys.com>
Link: https://lore.kernel.org/r/20210413073607.F41E8A0094@mailhost.synopsys.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5367f82a
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -866,6 +866,7 @@ struct dwc2_hregs_backup {
 * @ll_hw_enabled:	Status of low-level hardware resources.
 * @hibernated:		True if core is hibernated
 * @in_ppd:		True if core is partial power down mode.
 * @bus_suspended:	True if bus is suspended
 * @reset_phy_on_wake:	Quirk saying that we should assert PHY reset on a
 *			remote wakeup.
 * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
@@ -1023,7 +1024,6 @@ struct dwc2_hregs_backup {
 *			a pointer to an array of register definitions, the
 *			array size and the base address where the register bank
 *			is to be found.
 * @bus_suspended:	True if bus is suspended
 * @last_frame_num:	Number of last frame. Range from 0 to  32768
 * @frame_num_array:    Used only  if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is
 *			defined, for missed SOFs tracking. Array holds that
@@ -1062,6 +1062,7 @@ struct dwc2_hsotg {
	unsigned int ll_hw_enabled:1;
	unsigned int hibernated:1;
	unsigned int in_ppd:1;
	bool bus_suspended;
	unsigned int reset_phy_on_wake:1;
	unsigned int need_phy_for_wake:1;
	unsigned int phy_off_for_suspend:1;
@@ -1145,7 +1146,6 @@ struct dwc2_hsotg {
	unsigned long hs_periodic_bitmap[
		DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)];
	u16 periodic_qh_count;
	bool bus_suspended;
	bool new_connection;

	u16 last_frame_num;
@@ -1415,6 +1415,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg);
int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
					bool restore);
void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg);
void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
				   int rem_wakeup);
int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
@@ -1453,6 +1456,9 @@ static inline int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
						      bool restore)
{ return 0; }
static inline void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
						 int rem_wakeup) {}
static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
+71 −0
Original line number Diff line number Diff line
@@ -5483,3 +5483,74 @@ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
	dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n");
	return ret;
}

/**
 * dwc2_gadget_enter_clock_gating() - Put controller in clock gating.
 *
 * @hsotg: Programming view of the DWC_otg controller
 *
 * Return: non-zero if failed to enter device partial power down.
 *
 * This function is for entering device mode clock gating.
 */
void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg)
{
	u32 pcgctl;

	dev_dbg(hsotg->dev, "Entering device clock gating.\n");

	/* Set the Phy Clock bit as suspend is received. */
	pcgctl = dwc2_readl(hsotg, PCGCTL);
	pcgctl |= PCGCTL_STOPPCLK;
	dwc2_writel(hsotg, pcgctl, PCGCTL);
	udelay(5);

	/* Set the Gate hclk as suspend is received. */
	pcgctl = dwc2_readl(hsotg, PCGCTL);
	pcgctl |= PCGCTL_GATEHCLK;
	dwc2_writel(hsotg, pcgctl, PCGCTL);
	udelay(5);

	hsotg->lx_state = DWC2_L2;
	hsotg->bus_suspended = true;
}

/*
 * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating.
 *
 * @hsotg: Programming view of the DWC_otg controller
 * @rem_wakeup: indicates whether remote wake up is enabled.
 *
 * This function is for exiting from device mode clock gating.
 */
void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup)
{
	u32 pcgctl;
	u32 dctl;

	dev_dbg(hsotg->dev, "Exiting device clock gating.\n");

	/* Clear the Gate hclk. */
	pcgctl = dwc2_readl(hsotg, PCGCTL);
	pcgctl &= ~PCGCTL_GATEHCLK;
	dwc2_writel(hsotg, pcgctl, PCGCTL);
	udelay(5);

	/* Phy Clock bit. */
	pcgctl = dwc2_readl(hsotg, PCGCTL);
	pcgctl &= ~PCGCTL_STOPPCLK;
	dwc2_writel(hsotg, pcgctl, PCGCTL);
	udelay(5);

	if (rem_wakeup) {
		/* Set Remote Wakeup Signaling */
		dctl = dwc2_readl(hsotg, DCTL);
		dctl |= DCTL_RMTWKUPSIG;
		dwc2_writel(hsotg, dctl, DCTL);
	}

	/* Change to L0 state */
	call_gadget(hsotg, resume);
	hsotg->lx_state = DWC2_L0;
	hsotg->bus_suspended = false;
}