diff options
Diffstat (limited to 'drivers/usb/dwc2/core.c')
| -rw-r--r-- | drivers/usb/dwc2/core.c | 429 | 
1 files changed, 344 insertions, 85 deletions
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index ef73e498e98f..39a0fa8a4c0a 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -481,64 +481,168 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)   * Do core a soft reset of the core.  Be careful with this because it   * resets all the internal state machines of the core.   */ -static int dwc2_core_reset(struct dwc2_hsotg *hsotg) +int dwc2_core_reset(struct dwc2_hsotg *hsotg)  {  	u32 greset;  	int count = 0; -	u32 gusbcfg;  	dev_vdbg(hsotg->dev, "%s()\n", __func__); -	/* Wait for AHB master IDLE state */ +	/* Core Soft Reset */ +	greset = dwc2_readl(hsotg->regs + GRSTCTL); +	greset |= GRSTCTL_CSFTRST; +	dwc2_writel(greset, hsotg->regs + GRSTCTL);  	do { -		usleep_range(20000, 40000); +		udelay(1);  		greset = dwc2_readl(hsotg->regs + GRSTCTL);  		if (++count > 50) {  			dev_warn(hsotg->dev, -				 "%s() HANG! AHB Idle GRSTCTL=%0x\n", +				 "%s() HANG! Soft Reset GRSTCTL=%0x\n",  				 __func__, greset);  			return -EBUSY;  		} -	} while (!(greset & GRSTCTL_AHBIDLE)); +	} while (greset & GRSTCTL_CSFTRST); -	/* Core Soft Reset */ +	/* Wait for AHB master IDLE state */  	count = 0; -	greset |= GRSTCTL_CSFTRST; -	dwc2_writel(greset, hsotg->regs + GRSTCTL);  	do { -		usleep_range(20000, 40000); +		udelay(1);  		greset = dwc2_readl(hsotg->regs + GRSTCTL);  		if (++count > 50) {  			dev_warn(hsotg->dev, -				 "%s() HANG! Soft Reset GRSTCTL=%0x\n", +				 "%s() HANG! AHB Idle GRSTCTL=%0x\n",  				 __func__, greset);  			return -EBUSY;  		} -	} while (greset & GRSTCTL_CSFTRST); +	} while (!(greset & GRSTCTL_AHBIDLE)); -	if (hsotg->dr_mode == USB_DR_MODE_HOST) { -		gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); -		gusbcfg &= ~GUSBCFG_FORCEDEVMODE; -		gusbcfg |= GUSBCFG_FORCEHOSTMODE; -		dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); -	} else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { -		gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); -		gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; -		gusbcfg |= GUSBCFG_FORCEDEVMODE; -		dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); -	} else if (hsotg->dr_mode == USB_DR_MODE_OTG) { -		gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); -		gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; -		gusbcfg &= ~GUSBCFG_FORCEDEVMODE; -		dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); -	} +	return 0; +} + +/* + * Force the mode of the controller. + * + * Forcing the mode is needed for two cases: + * + * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the + * controller to stay in a particular mode regardless of ID pin + * changes. We do this usually after a core reset. + * + * 2) During probe we want to read reset values of the hw + * configuration registers that are only available in either host or + * device mode. We may need to force the mode if the current mode does + * not allow us to access the register in the mode that we want. + * + * In either case it only makes sense to force the mode if the + * controller hardware is OTG capable. + * + * Checks are done in this function to determine whether doing a force + * would be valid or not. + * + * If a force is done, it requires a 25ms delay to take effect. + * + * Returns true if the mode was forced. + */ +static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) +{ +	u32 gusbcfg; +	u32 set; +	u32 clear; + +	dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device"); + +	/* +	 * Force mode has no effect if the hardware is not OTG. +	 */ +	if (!dwc2_hw_is_otg(hsotg)) +		return false; + +	/* +	 * If dr_mode is either peripheral or host only, there is no +	 * need to ever force the mode to the opposite mode. +	 */ +	if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) +		return false; + +	if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST)) +		return false; + +	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); + +	set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE; +	clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE; + +	/* +	 * If the force mode bit is already set, don't set it. +	 */ +	if ((gusbcfg & set) && !(gusbcfg & clear)) +		return false; + +	gusbcfg &= ~clear; +	gusbcfg |= set; +	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); + +	msleep(25); +	return true; +} + +/* + * Clears the force mode bits. + */ +static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) +{ +	u32 gusbcfg; + +	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); +	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; +	gusbcfg &= ~GUSBCFG_FORCEDEVMODE; +	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);  	/*  	 * NOTE: This long sleep is _very_ important, otherwise the core will  	 * not stay in host mode after a connector ID change!  	 */ -	usleep_range(150000, 200000); +	msleep(25); +} + +/* + * Sets or clears force mode based on the dr_mode parameter. + */ +void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) +{ +	switch (hsotg->dr_mode) { +	case USB_DR_MODE_HOST: +		dwc2_force_mode(hsotg, true); +		break; +	case USB_DR_MODE_PERIPHERAL: +		dwc2_force_mode(hsotg, false); +		break; +	case USB_DR_MODE_OTG: +		dwc2_clear_force_mode(hsotg); +		break; +	default: +		dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n", +			 __func__, hsotg->dr_mode); +		break; +	} +} + +/* + * Do core a soft reset of the core.  Be careful with this because it + * resets all the internal state machines of the core. + * + * Additionally this will apply force mode as per the hsotg->dr_mode + * parameter. + */ +int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg) +{ +	int retval; +	retval = dwc2_core_reset(hsotg); +	if (retval) +		return retval; + +	dwc2_force_dr_mode(hsotg);  	return 0;  } @@ -553,16 +657,20 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)  	 */  	if (select_phy) {  		dev_dbg(hsotg->dev, "FS PHY selected\n"); +  		usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); -		usbcfg |= GUSBCFG_PHYSEL; -		dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); +		if (!(usbcfg & GUSBCFG_PHYSEL)) { +			usbcfg |= GUSBCFG_PHYSEL; +			dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); -		/* Reset after a PHY select */ -		retval = dwc2_core_reset(hsotg); -		if (retval) { -			dev_err(hsotg->dev, "%s() Reset failed, aborting", -					__func__); -			return retval; +			/* Reset after a PHY select */ +			retval = dwc2_core_reset_and_force_dr_mode(hsotg); + +			if (retval) { +				dev_err(hsotg->dev, +					"%s: Reset failed, aborting", __func__); +				return retval; +			}  		}  	} @@ -597,13 +705,13 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)  static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)  { -	u32 usbcfg; +	u32 usbcfg, usbcfg_old;  	int retval = 0;  	if (!select_phy)  		return 0; -	usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); +	usbcfg = usbcfg_old = dwc2_readl(hsotg->regs + GUSBCFG);  	/*  	 * HS PHY parameters. These parameters are preserved during soft reset @@ -631,14 +739,16 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)  		break;  	} -	dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); +	if (usbcfg != usbcfg_old) { +		dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); -	/* Reset after setting the PHY parameters */ -	retval = dwc2_core_reset(hsotg); -	if (retval) { -		dev_err(hsotg->dev, "%s() Reset failed, aborting", -				__func__); -		return retval; +		/* Reset after setting the PHY parameters */ +		retval = dwc2_core_reset_and_force_dr_mode(hsotg); +		if (retval) { +			dev_err(hsotg->dev, +				"%s: Reset failed, aborting", __func__); +			return retval; +		}  	}  	return retval; @@ -765,11 +875,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)   * dwc2_core_init() - Initializes the DWC_otg controller registers and   * prepares the core for device mode or host mode operation   * - * @hsotg:      Programming view of the DWC_otg controller - * @select_phy: If true then also set the Phy type - * @irq:        If >= 0, the irq to register + * @hsotg:         Programming view of the DWC_otg controller + * @initial_setup: If true then this is the first init for this instance.   */ -int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq) +int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)  {  	u32 usbcfg, otgctl;  	int retval; @@ -791,18 +900,26 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)  	dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); -	/* Reset the Controller */ -	retval = dwc2_core_reset(hsotg); -	if (retval) { -		dev_err(hsotg->dev, "%s(): Reset failed, aborting\n", -				__func__); -		return retval; +	/* +	 * Reset the Controller +	 * +	 * We only need to reset the controller if this is a re-init. +	 * For the first init we know for sure that earlier code reset us (it +	 * needed to in order to properly detect various parameters). +	 */ +	if (!initial_setup) { +		retval = dwc2_core_reset_and_force_dr_mode(hsotg); +		if (retval) { +			dev_err(hsotg->dev, "%s(): Reset failed, aborting\n", +					__func__); +			return retval; +		}  	}  	/*  	 * This needs to happen in FS mode before any other programming occurs  	 */ -	retval = dwc2_phy_init(hsotg, select_phy); +	retval = dwc2_phy_init(hsotg, initial_setup);  	if (retval)  		return retval; @@ -1707,6 +1824,7 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,  	u32 hcchar;  	u32 hctsiz = 0;  	u16 num_packets; +	u32 ec_mc;  	if (dbg_hc(chan))  		dev_vdbg(hsotg->dev, "%s()\n", __func__); @@ -1743,6 +1861,13 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,  		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &  			  TSIZ_XFERSIZE_MASK; + +		/* For split set ec_mc for immediate retries */ +		if (chan->ep_type == USB_ENDPOINT_XFER_INT || +		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) +			ec_mc = 3; +		else +			ec_mc = 1;  	} else {  		if (dbg_hc(chan))  			dev_vdbg(hsotg->dev, "no split\n"); @@ -1805,6 +1930,9 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,  		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &  			  TSIZ_XFERSIZE_MASK; + +		/* The ec_mc gets the multi_count for non-split */ +		ec_mc = chan->multi_count;  	}  	chan->start_pkt_count = num_packets; @@ -1855,8 +1983,7 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,  	hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));  	hcchar &= ~HCCHAR_MULTICNT_MASK; -	hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT & -		  HCCHAR_MULTICNT_MASK; +	hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;  	dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);  	if (hcchar & HCCHAR_CHDIS) @@ -1905,7 +2032,6 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,  				 struct dwc2_host_chan *chan)  {  	u32 hcchar; -	u32 hc_dma;  	u32 hctsiz = 0;  	if (chan->do_ping) @@ -1934,14 +2060,14 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,  	dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num)); -	hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK; +	dma_sync_single_for_device(hsotg->dev, chan->desc_list_addr, +				   chan->desc_list_sz, DMA_TO_DEVICE); + +	dwc2_writel(chan->desc_list_addr, hsotg->regs + HCDMA(chan->hc_num)); -	/* Always start from first descriptor */ -	hc_dma &= ~HCDMA_CTD_MASK; -	dwc2_writel(hc_dma, hsotg->regs + HCDMA(chan->hc_num));  	if (dbg_hc(chan)) -		dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n", -			 hc_dma, chan->hc_num); +		dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n", +			 &chan->desc_list_addr, chan->hc_num);  	hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));  	hcchar &= ~HCCHAR_MULTICNT_MASK; @@ -2485,6 +2611,29 @@ void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)  	hsotg->core_params->dma_desc_enable = val;  } +void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val > 0 && (hsotg->core_params->dma_enable <= 0 || +			!hsotg->hw_params.dma_desc_enable)) +		valid = 0; +	if (val < 0) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for dma_desc_fs_enable parameter. Check HW configuration.\n", +				val); +		val = (hsotg->core_params->dma_enable > 0 && +			hsotg->hw_params.dma_desc_enable); +	} + +	hsotg->core_params->dma_desc_fs_enable = val; +	dev_dbg(hsotg->dev, "Setting dma_desc_fs_enable to %d\n", val); +} +  void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,  						 int val)  { @@ -3016,6 +3165,7 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,  	dwc2_set_param_otg_cap(hsotg, params->otg_cap);  	dwc2_set_param_dma_enable(hsotg, params->dma_enable);  	dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable); +	dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable);  	dwc2_set_param_host_support_fs_ls_low_power(hsotg,  			params->host_support_fs_ls_low_power);  	dwc2_set_param_enable_dynamic_fifo(hsotg, @@ -3052,17 +3202,93 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,  	dwc2_set_param_hibernation(hsotg, params->hibernation);  } +/* + * Forces either host or device mode if the controller is not + * currently in that mode. + * + * Returns true if the mode was forced. + */ +static bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host) +{ +	if (host && dwc2_is_host_mode(hsotg)) +		return false; +	else if (!host && dwc2_is_device_mode(hsotg)) +		return false; + +	return dwc2_force_mode(hsotg, host); +} + +/* + * Gets host hardware parameters. Forces host mode if not currently in + * host mode. Should be called immediately after a core soft reset in + * order to get the reset values. + */ +static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg) +{ +	struct dwc2_hw_params *hw = &hsotg->hw_params; +	u32 gnptxfsiz; +	u32 hptxfsiz; +	bool forced; + +	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) +		return; + +	forced = dwc2_force_mode_if_needed(hsotg, true); + +	gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); +	hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); +	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); +	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz); + +	if (forced) +		dwc2_clear_force_mode(hsotg); + +	hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> +				       FIFOSIZE_DEPTH_SHIFT; +	hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >> +				      FIFOSIZE_DEPTH_SHIFT; +} + +/* + * Gets device hardware parameters. Forces device mode if not + * currently in device mode. Should be called immediately after a core + * soft reset in order to get the reset values. + */ +static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg) +{ +	struct dwc2_hw_params *hw = &hsotg->hw_params; +	bool forced; +	u32 gnptxfsiz; + +	if (hsotg->dr_mode == USB_DR_MODE_HOST) +		return; + +	forced = dwc2_force_mode_if_needed(hsotg, false); + +	gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); +	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); + +	if (forced) +		dwc2_clear_force_mode(hsotg); + +	hw->dev_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> +				       FIFOSIZE_DEPTH_SHIFT; +} +  /**   * During device initialization, read various hardware configuration   * registers and interpret the contents. + * + * This should be called during driver probe. It will perform a core + * soft reset in order to get the reset values of the parameters.   */  int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)  {  	struct dwc2_hw_params *hw = &hsotg->hw_params;  	unsigned width;  	u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4; -	u32 hptxfsiz, grxfsiz, gnptxfsiz; -	u32 gusbcfg; +	u32 grxfsiz; +	int retval;  	/*  	 * Attempt to ensure this device is really a DWC_otg Controller. @@ -3082,6 +3308,10 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)  		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,  		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid); +	retval = dwc2_core_reset(hsotg); +	if (retval) +		return retval; +  	hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1);  	hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);  	hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3); @@ -3094,20 +3324,16 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)  	dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);  	dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz); -	/* Force host mode to get HPTXFSIZ / GNPTXFSIZ exact power on value */ -	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); -	gusbcfg |= GUSBCFG_FORCEHOSTMODE; -	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); -	usleep_range(100000, 150000); +	/* +	 * Host specific hardware parameters. Reading these parameters +	 * requires the controller to be in host mode. The mode will +	 * be forced, if necessary, to read these values. +	 */ +	dwc2_get_host_hwparams(hsotg); +	dwc2_get_dev_hwparams(hsotg); -	gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); -	hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); -	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); -	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz); -	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); -	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; -	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); -	usleep_range(100000, 150000); +	/* hwcfg1 */ +	hw->dev_ep_dirs = hwcfg1;  	/* hwcfg2 */  	hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >> @@ -3163,10 +3389,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)  	/* fifo sizes */  	hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>  				GRXFSIZ_DEPTH_SHIFT; -	hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> -				       FIFOSIZE_DEPTH_SHIFT; -	hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >> -				      FIFOSIZE_DEPTH_SHIFT;  	dev_dbg(hsotg->dev, "Detected values from hardware:\n");  	dev_dbg(hsotg->dev, "  op_mode=%d\n", @@ -3275,6 +3497,43 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)  	dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);  } +/* Returns the controller's GHWCFG2.OTG_MODE. */ +unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg) +{ +	u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2); + +	return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >> +		GHWCFG2_OP_MODE_SHIFT; +} + +/* Returns true if the controller is capable of DRD. */ +bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) +{ +	unsigned op_mode = dwc2_op_mode(hsotg); + +	return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || +		(op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || +		(op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE); +} + +/* Returns true if the controller is host-only. */ +bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) +{ +	unsigned op_mode = dwc2_op_mode(hsotg); + +	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || +		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); +} + +/* Returns true if the controller is device-only. */ +bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) +{ +	unsigned op_mode = dwc2_op_mode(hsotg); + +	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || +		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); +} +  MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");  MODULE_AUTHOR("Synopsys, Inc.");  MODULE_LICENSE("Dual BSD/GPL");  | 
