mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	usb: dwc2: Update Core Reset programming flow.
Starting from core version 4.20a Core Reset flow is changed. Introduced new bit in GRSTCTL register - GRSTCTL_CSFTRST_DONE. Core Reset new programming flow steps are follow: 1. Set GRSTCTL_CSFTRST bit. 2. Wait for bit GRSTCTL_CSFTRST_DONE is set. 3. Clear GRSTCTL_CSFTRST and GRSTCTL_CSFTRST_DONE bits. Check core version functionality separated from dwc2_get_hwparams() to new dwc2_check_core_version() function because Core Reset flow depend on SNPSID. Signed-off-by: Minas Harutyunyan <hminas@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
This commit is contained in:
		
							parent
							
								
									4cda340a45
								
							
						
					
					
						commit
						65dc2e7252
					
				
					 5 changed files with 63 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -524,10 +524,25 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
 | 
			
		|||
	greset |= GRSTCTL_CSFTRST;
 | 
			
		||||
	dwc2_writel(hsotg, greset, GRSTCTL);
 | 
			
		||||
 | 
			
		||||
	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 10000)) {
 | 
			
		||||
		dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
 | 
			
		||||
			 __func__);
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) <
 | 
			
		||||
		(DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
 | 
			
		||||
		if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL,
 | 
			
		||||
					      GRSTCTL_CSFTRST, 10000)) {
 | 
			
		||||
			dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n",
 | 
			
		||||
				 __func__);
 | 
			
		||||
			return -EBUSY;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL,
 | 
			
		||||
					    GRSTCTL_CSFTRST_DONE, 10000)) {
 | 
			
		||||
			dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n",
 | 
			
		||||
				 __func__);
 | 
			
		||||
			return -EBUSY;
 | 
			
		||||
		}
 | 
			
		||||
		greset = dwc2_readl(hsotg, GRSTCTL);
 | 
			
		||||
		greset &= ~GRSTCTL_CSFTRST;
 | 
			
		||||
		greset |= GRSTCTL_CSFTRST_DONE;
 | 
			
		||||
		dwc2_writel(hsotg, greset, GRSTCTL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait for AHB master IDLE state */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1103,8 +1103,10 @@ struct dwc2_hsotg {
 | 
			
		|||
#define DWC2_CORE_REV_3_00a	0x4f54300a
 | 
			
		||||
#define DWC2_CORE_REV_3_10a	0x4f54310a
 | 
			
		||||
#define DWC2_CORE_REV_4_00a	0x4f54400a
 | 
			
		||||
#define DWC2_CORE_REV_4_20a	0x4f54420a
 | 
			
		||||
#define DWC2_FS_IOT_REV_1_00a	0x5531100a
 | 
			
		||||
#define DWC2_HS_IOT_REV_1_00a	0x5532100a
 | 
			
		||||
#define DWC2_CORE_REV_MASK	0x0000ffff
 | 
			
		||||
 | 
			
		||||
	/* DWC OTG HW Core ID */
 | 
			
		||||
#define DWC2_OTG_ID		0x4f540000
 | 
			
		||||
| 
						 | 
				
			
			@ -1309,6 +1311,8 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
 | 
			
		|||
 | 
			
		||||
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
 | 
			
		||||
 | 
			
		||||
int dwc2_check_core_version(struct dwc2_hsotg *hsotg);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Common core Functions.
 | 
			
		||||
 * The following functions support managing the DWC_otg controller in either
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,6 +126,7 @@
 | 
			
		|||
#define GRSTCTL				HSOTG_REG(0x010)
 | 
			
		||||
#define GRSTCTL_AHBIDLE			BIT(31)
 | 
			
		||||
#define GRSTCTL_DMAREQ			BIT(30)
 | 
			
		||||
#define GRSTCTL_CSFTRST_DONE		BIT(29)
 | 
			
		||||
#define GRSTCTL_TXFNUM_MASK		(0x1f << 6)
 | 
			
		||||
#define GRSTCTL_TXFNUM_SHIFT		6
 | 
			
		||||
#define GRSTCTL_TXFNUM_LIMIT		0x1f
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -782,25 +782,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
 | 
			
		|||
	u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
 | 
			
		||||
	u32 grxfsiz;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Attempt to ensure this device is really a DWC_otg Controller.
 | 
			
		||||
	 * Read and verify the GSNPSID register contents. The value should be
 | 
			
		||||
	 * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	hw->snpsid = dwc2_readl(hsotg, GSNPSID);
 | 
			
		||||
	if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
 | 
			
		||||
	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
 | 
			
		||||
	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
 | 
			
		||||
		dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
 | 
			
		||||
			hw->snpsid);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
 | 
			
		||||
		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
 | 
			
		||||
		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
 | 
			
		||||
 | 
			
		||||
	hwcfg1 = dwc2_readl(hsotg, GHWCFG1);
 | 
			
		||||
	hwcfg2 = dwc2_readl(hsotg, GHWCFG2);
 | 
			
		||||
	hwcfg3 = dwc2_readl(hsotg, GHWCFG3);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -362,6 +362,37 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check core version
 | 
			
		||||
 *
 | 
			
		||||
 * @hsotg: Programming view of the DWC_otg controller
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int dwc2_check_core_version(struct dwc2_hsotg *hsotg)
 | 
			
		||||
{
 | 
			
		||||
	struct dwc2_hw_params *hw = &hsotg->hw_params;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Attempt to ensure this device is really a DWC_otg Controller.
 | 
			
		||||
	 * Read and verify the GSNPSID register contents. The value should be
 | 
			
		||||
	 * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	hw->snpsid = dwc2_readl(hsotg, GSNPSID);
 | 
			
		||||
	if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
 | 
			
		||||
	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
 | 
			
		||||
	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
 | 
			
		||||
		dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
 | 
			
		||||
			hw->snpsid);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
 | 
			
		||||
		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
 | 
			
		||||
		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
 | 
			
		||||
 * driver
 | 
			
		||||
| 
						 | 
				
			
			@ -444,6 +475,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
 | 
			
		|||
		of_property_read_bool(dev->dev.of_node,
 | 
			
		||||
				      "snps,need-phy-for-wake");
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Before performing any core related operations
 | 
			
		||||
	 * check core version.
 | 
			
		||||
	 */
 | 
			
		||||
	retval = dwc2_check_core_version(hsotg);
 | 
			
		||||
	if (retval)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Reset before dwc2_get_hwparams() then it could get power-on real
 | 
			
		||||
	 * reset value form registers.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue