diff options
Diffstat (limited to 'drivers/usb/dwc3/core.c')
| -rw-r--r-- | drivers/usb/dwc3/core.c | 141 | 
1 files changed, 131 insertions, 10 deletions
| diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ea91310113b9..88c80fcc39f5 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -78,6 +78,14 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)  			mode = USB_DR_MODE_HOST;  		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))  			mode = USB_DR_MODE_PERIPHERAL; + +		/* +		 * dwc_usb31 does not support OTG mode. If the controller +		 * supports DRD but the dr_mode is not specified or set to OTG, +		 * then set the mode to peripheral. +		 */ +		if (mode == USB_DR_MODE_OTG && dwc3_is_usb31(dwc)) +			mode = USB_DR_MODE_PERIPHERAL;  	}  	if (mode != dwc->dr_mode) { @@ -778,6 +786,98 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)  static int dwc3_core_get_phy(struct dwc3 *dwc);  static int dwc3_core_ulpi_init(struct dwc3 *dwc); +/* set global incr burst type configuration registers */ +static void dwc3_set_incr_burst_type(struct dwc3 *dwc) +{ +	struct device *dev = dwc->dev; +	/* incrx_mode : for INCR burst type. */ +	bool incrx_mode; +	/* incrx_size : for size of INCRX burst. */ +	u32 incrx_size; +	u32 *vals; +	u32 cfg; +	int ntype; +	int ret; +	int i; + +	cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0); + +	/* +	 * Handle property "snps,incr-burst-type-adjustment". +	 * Get the number of value from this property: +	 * result <= 0, means this property is not supported. +	 * result = 1, means INCRx burst mode supported. +	 * result > 1, means undefined length burst mode supported. +	 */ +	ntype = device_property_read_u32_array(dev, +			"snps,incr-burst-type-adjustment", NULL, 0); +	if (ntype <= 0) +		return; + +	vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL); +	if (!vals) { +		dev_err(dev, "Error to get memory\n"); +		return; +	} + +	/* Get INCR burst type, and parse it */ +	ret = device_property_read_u32_array(dev, +			"snps,incr-burst-type-adjustment", vals, ntype); +	if (ret) { +		dev_err(dev, "Error to get property\n"); +		return; +	} + +	incrx_size = *vals; + +	if (ntype > 1) { +		/* INCRX (undefined length) burst mode */ +		incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE; +		for (i = 1; i < ntype; i++) { +			if (vals[i] > incrx_size) +				incrx_size = vals[i]; +		} +	} else { +		/* INCRX burst mode */ +		incrx_mode = INCRX_BURST_MODE; +	} + +	/* Enable Undefined Length INCR Burst and Enable INCRx Burst */ +	cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK; +	if (incrx_mode) +		cfg |= DWC3_GSBUSCFG0_INCRBRSTENA; +	switch (incrx_size) { +	case 256: +		cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA; +		break; +	case 128: +		cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA; +		break; +	case 64: +		cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA; +		break; +	case 32: +		cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA; +		break; +	case 16: +		cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA; +		break; +	case 8: +		cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA; +		break; +	case 4: +		cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA; +		break; +	case 1: +		break; +	default: +		dev_err(dev, "Invalid property\n"); +		break; +	} + +	dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg); +} +  /**   * dwc3_core_init - Low-level initialization of DWC3 Core   * @dwc: Pointer to our controller context structure @@ -840,6 +940,8 @@ static int dwc3_core_init(struct dwc3 *dwc)  	/* Adjust Frame Length */  	dwc3_frame_length_adjustment(dwc); +	dwc3_set_incr_burst_type(dwc); +  	usb_phy_set_suspend(dwc->usb2_phy, 0);  	usb_phy_set_suspend(dwc->usb3_phy, 0);  	ret = phy_power_on(dwc->usb2_generic_phy); @@ -883,6 +985,22 @@ static int dwc3_core_init(struct dwc3 *dwc)  		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);  	} +	if (dwc->dr_mode == USB_DR_MODE_HOST || +	    dwc->dr_mode == USB_DR_MODE_OTG) { +		reg = dwc3_readl(dwc->regs, DWC3_GUCTL); + +		/* +		 * Enable Auto retry Feature to make the controller operating in +		 * Host mode on seeing transaction errors(CRC errors or internal +		 * overrun scenerios) on IN transfers to reply to the device +		 * with a non-terminating retry ACK (i.e, an ACK transcation +		 * packet with Retry=1 & Nump != 0) +		 */ +		reg |= DWC3_GUCTL_HSTINAUTORETRY; + +		dwc3_writel(dwc->regs, DWC3_GUCTL, reg); +	} +  	/*  	 * Must config both number of packets and max burst settings to enable  	 * RX and/or TX threshold. @@ -1272,7 +1390,6 @@ static int dwc3_probe(struct platform_device *pdev)  	if (!dwc->clks)  		return -ENOMEM; -	dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);  	dwc->dev = dev;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1307,15 +1424,19 @@ static int dwc3_probe(struct platform_device *pdev)  	if (IS_ERR(dwc->reset))  		return PTR_ERR(dwc->reset); -	ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks); -	if (ret == -EPROBE_DEFER) -		return ret; -	/* -	 * Clocks are optional, but new DT platforms should support all clocks -	 * as required by the DT-binding. -	 */ -	if (ret) -		dwc->num_clks = 0; +	if (dev->of_node) { +		dwc->num_clks = ARRAY_SIZE(dwc3_core_clks); + +		ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks); +		if (ret == -EPROBE_DEFER) +			return ret; +		/* +		 * Clocks are optional, but new DT platforms should support all +		 * clocks as required by the DT-binding. +		 */ +		if (ret) +			dwc->num_clks = 0; +	}  	ret = reset_control_deassert(dwc->reset);  	if (ret) |