diff mbox series

usb: dwc2: update reset method for host and device mode

Message ID 20240328131811.94559-1-seashell11234455@gmail.com
State New
Delegated to: Marek Vasut
Headers show
Series usb: dwc2: update reset method for host and device mode | expand

Commit Message

Kongyang Liu March 28, 2024, 1:14 p.m. UTC
Starting from version 4.20a, there has been a change in the reset method.
A new bit, GRSTCTL_CSFTRST_DONE, has been introduced in the GRSTCTL
register to indicate whether the reset has been completed.

Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
---

 drivers/usb/gadget/dwc2_udc_otg.c      | 18 ++++++++++++++++--
 drivers/usb/gadget/dwc2_udc_otg_regs.h | 19 +++++++++++++------
 drivers/usb/host/dwc2.c                | 19 ++++++++++++++++---
 drivers/usb/host/dwc2.h                |  6 ++++++
 4 files changed, 51 insertions(+), 11 deletions(-)

Comments

Mattijs Korpershoek April 16, 2024, 8:50 a.m. UTC | #1
Hi Kongyang,

Thank you for the patch.

On jeu., mars 28, 2024 at 21:14, Kongyang Liu <seashell11234455@gmail.com> wrote:

> Starting from version 4.20a, there has been a change in the reset method.
> A new bit, GRSTCTL_CSFTRST_DONE, has been introduced in the GRSTCTL
> register to indicate whether the reset has been completed.
>
> Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>

I've compared this with the equivalent Linux patch found here:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65dc2e725286106f99c6f6b78e3d9c52c15f3a9c

Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>

Also tested on VIM3 that I could use fastboot.

Tested-by: Mattijs Korpershoek <mkorpershoek@baylibre.com> # on vim3

I will add the linux link in the commit message when applying. Please
consider adding it yourself if you receive review comments that require
sending a v2.

Thanks
Mattijs

> ---
>
>  drivers/usb/gadget/dwc2_udc_otg.c      | 18 ++++++++++++++++--
>  drivers/usb/gadget/dwc2_udc_otg_regs.h | 19 +++++++++++++------
>  drivers/usb/host/dwc2.c                | 19 ++++++++++++++++---
>  drivers/usb/host/dwc2.h                |  6 ++++++
>  4 files changed, 51 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
> index 27082f5152..d1dd469a0f 100644
> --- a/drivers/usb/gadget/dwc2_udc_otg.c
> +++ b/drivers/usb/gadget/dwc2_udc_otg.c
> @@ -42,7 +42,7 @@
>  #include <asm/unaligned.h>
>  #include <asm/io.h>
>  
> -#include <asm/mach-types.h>
> +#include <wait_bit.h>
>  
>  #include <power/regulator.h>
>  
> @@ -464,12 +464,26 @@ static void reconfig_usbd(struct dwc2_udc *dev)
>  {
>  	/* 2. Soft-reset OTG Core and then unreset again. */
>  	int i;
> -	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
> +	unsigned int uTemp;
>  	uint32_t dflt_gusbcfg;
>  	uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
>  	u32 max_hw_ep;
>  	int pdata_hw_ep;
>  
> +	u32 snpsid, greset;
> +
> +	snpsid = readl(&reg->gsnpsid);
> +	writel(CORE_SOFT_RESET, &reg->grstctl);
> +	if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) {
> +		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET, false, 1000, false);
> +	} else {
> +		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false);
> +		greset = readl(&reg->grstctl);
> +		greset &= ~CORE_SOFT_RESET;
> +		greset |= CORE_SOFT_RESET_DONE;
> +		writel(greset, &reg->grstctl);
> +	}
> +
>  	debug("Resetting OTG controller\n");
>  
>  	dflt_gusbcfg =
> diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h
> index 9ca6f42375..b3d9117033 100644
> --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h
> +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h
> @@ -63,24 +63,26 @@ struct dwc2_usbotg_reg {
>  	u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
>  	u8  res0[12];
>  	u32 ggpio;     /* 0x038 */
> -	u8  res1[20];
> +	u8  res1[4];
> +	u32 gsnpsid;
> +	u8  res2[12];
>  	u32 ghwcfg4; /* User HW Config4 */
> -	u8  res2[176];
> +	u8  res3[176];
>  	u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
> -	u8  res3[1728];
> +	u8  res4[1728];
>  	/* Device Configuration */
>  	u32 dcfg; /* Device Configuration Register */
>  	u32 dctl; /* Device Control */
>  	u32 dsts; /* Device Status */
> -	u8  res4[4];
> +	u8  res5[4];
>  	u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
>  	u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
>  	u32 daint; /* Device All Endpoints Interrupt */
>  	u32 daintmsk; /* Device All Endpoints Interrupt Mask */
> -	u8  res5[224];
> +	u8  res6[224];
>  	struct dwc2_dev_in_endp in_endp[16];
>  	struct dwc2_dev_out_endp out_endp[16];
> -	u8  res6[768];
> +	u8  res7[768];
>  	struct ep_fifo ep[16];
>  };
>  
> @@ -118,6 +120,7 @@ struct dwc2_usbotg_reg {
>  /* DWC2_UDC_OTG_GRSTCTL */
>  #define AHB_MASTER_IDLE		(1u<<31)
>  #define CORE_SOFT_RESET		(0x1<<0)
> +#define CORE_SOFT_RESET_DONE		(0x1<<29)
>  
>  /* DWC2_UDC_OTG_GINTSTS/DWC2_UDC_OTG_GINTMSK core interrupt register */
>  #define INT_RESUME			(1u<<31)
> @@ -285,6 +288,10 @@ struct dwc2_usbotg_reg {
>  #define DAINT_IN_EP_INT(x)                        (x << 0)
>  #define DAINT_OUT_EP_INT(x)                       (x << 16)
>  
> +/* DWC2_UDC_OTG_GSNPSID */
> +#define SNPSID_VER_420a					0x4f54420a
> +#define SNPSID_VER_MASK					0xffff
> +
>  /* User HW Config4 */
>  #define GHWCFG4_NUM_IN_EPS_MASK		(0xf << 26)
>  #define GHWCFG4_NUM_IN_EPS_SHIFT	26
> diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
> index 637eb2dd06..1baeff96ee 100644
> --- a/drivers/usb/host/dwc2.c
> +++ b/drivers/usb/host/dwc2.c
> @@ -159,6 +159,7 @@ static void dwc_otg_core_reset(struct udevice *dev,
>  			       struct dwc2_core_regs *regs)
>  {
>  	int ret;
> +	u32 snpsid, greset;
>  
>  	/* Wait for AHB master IDLE state. */
>  	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
> @@ -167,9 +168,20 @@ static void dwc_otg_core_reset(struct udevice *dev,
>  		dev_info(dev, "%s: Timeout!\n", __func__);
>  
>  	/* Core Soft Reset */
> +	snpsid = readl(&regs->gsnpsid);
>  	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
> -	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
> -				false, 1000, false);
> +	if ((snpsid & DWC2_SNPSID_VER_MASK) < (DWC2_SNPSID_DEVID_VER_420a & DWC2_SNPSID_VER_MASK)) {
> +		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
> +					false, 1000, false);
> +	} else {
> +		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_GSFTRST_DONE,
> +					true, 1000, false);
> +		greset = readl(&regs->grstctl);
> +		greset &= ~DWC2_GRSTCTL_CSFTRST;
> +		greset |= DWC2_GRSTCTL_GSFTRST_DONE;
> +		writel(greset, &regs->grstctl);
> +	}
> +
>  	if (ret)
>  		dev_info(dev, "%s: Timeout!\n", __func__);
>  
> @@ -1180,7 +1192,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
>  		 snpsid >> 12 & 0xf, snpsid & 0xfff);
>  
>  	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
> -	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
> +		(snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx &&
> +	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_4xx) {
>  		dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
>  			 snpsid);
>  		return -ENODEV;
> diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h
> index 6f022e33a1..e1f0f59b82 100644
> --- a/drivers/usb/host/dwc2.h
> +++ b/drivers/usb/host/dwc2.h
> @@ -207,6 +207,8 @@ struct dwc2_core_regs {
>  #define DWC2_GRSTCTL_TXFFLSH_OFFSET			5
>  #define DWC2_GRSTCTL_TXFNUM_MASK			(0x1F << 6)
>  #define DWC2_GRSTCTL_TXFNUM_OFFSET			6
> +#define DWC2_GRSTCTL_GSFTRST_DONE			(1 << 29)
> +#define DWC2_GRSTCTL_GSFTRST_DONE_OFFSET	29
>  #define DWC2_GRSTCTL_DMAREQ				(1 << 30)
>  #define DWC2_GRSTCTL_DMAREQ_OFFSET			30
>  #define DWC2_GRSTCTL_AHBIDLE				(1 << 31)
> @@ -739,8 +741,12 @@ struct dwc2_core_regs {
>  #define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET			7
>  #define DWC2_SNPSID_DEVID_VER_2xx			(0x4f542 << 12)
>  #define DWC2_SNPSID_DEVID_VER_3xx			(0x4f543 << 12)
> +#define DWC2_SNPSID_DEVID_VER_4xx			(0x4f544 << 12)
> +#define DWC2_SNPSID_DEVID_VER_420a			0x4f54420a
>  #define DWC2_SNPSID_DEVID_MASK				(0xfffff << 12)
>  #define DWC2_SNPSID_DEVID_OFFSET			12
> +#define DWC2_SNPSID_VER_MASK				0xffff
> +#define DWC2_SNPSID_VER_OFFSET				0
>  
>  /* Host controller specific */
>  #define DWC2_HC_PID_DATA0		0
> -- 
> 2.41.0
Mattijs Korpershoek April 16, 2024, 8:54 a.m. UTC | #2
On mar., avril 16, 2024 at 10:50, Mattijs Korpershoek <mkorpershoek@baylibre.com> wrote:

> Hi Kongyang,
>
> Thank you for the patch.
>
> On jeu., mars 28, 2024 at 21:14, Kongyang Liu <seashell11234455@gmail.com> wrote:
>
>> Starting from version 4.20a, there has been a change in the reset method.
>> A new bit, GRSTCTL_CSFTRST_DONE, has been introduced in the GRSTCTL
>> register to indicate whether the reset has been completed.
>>
>> Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
>
> I've compared this with the equivalent Linux patch found here:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65dc2e725286106f99c6f6b78e3d9c52c15f3a9c
>
> Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
>
> Also tested on VIM3 that I could use fastboot.
>
> Tested-by: Mattijs Korpershoek <mkorpershoek@baylibre.com> # on vim3
>
> I will add the linux link in the commit message when applying. Please
> consider adding it yourself if you receive review comments that require
> sending a v2.

Just noticed that this also touches the host part of the driver.

Marek, do you want to review/pick this up, or can this go through
u-boot-dfu ?

>
> Thanks
> Mattijs
>
>> ---
>>
>>  drivers/usb/gadget/dwc2_udc_otg.c      | 18 ++++++++++++++++--
>>  drivers/usb/gadget/dwc2_udc_otg_regs.h | 19 +++++++++++++------
>>  drivers/usb/host/dwc2.c                | 19 ++++++++++++++++---
>>  drivers/usb/host/dwc2.h                |  6 ++++++
>>  4 files changed, 51 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
>> index 27082f5152..d1dd469a0f 100644
>> --- a/drivers/usb/gadget/dwc2_udc_otg.c
>> +++ b/drivers/usb/gadget/dwc2_udc_otg.c
>> @@ -42,7 +42,7 @@
>>  #include <asm/unaligned.h>
>>  #include <asm/io.h>
>>  
>> -#include <asm/mach-types.h>
>> +#include <wait_bit.h>
>>  
>>  #include <power/regulator.h>
>>  
>> @@ -464,12 +464,26 @@ static void reconfig_usbd(struct dwc2_udc *dev)
>>  {
>>  	/* 2. Soft-reset OTG Core and then unreset again. */
>>  	int i;
>> -	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
>> +	unsigned int uTemp;
>>  	uint32_t dflt_gusbcfg;
>>  	uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
>>  	u32 max_hw_ep;
>>  	int pdata_hw_ep;
>>  
>> +	u32 snpsid, greset;
>> +
>> +	snpsid = readl(&reg->gsnpsid);
>> +	writel(CORE_SOFT_RESET, &reg->grstctl);
>> +	if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) {
>> +		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET, false, 1000, false);
>> +	} else {
>> +		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false);
>> +		greset = readl(&reg->grstctl);
>> +		greset &= ~CORE_SOFT_RESET;
>> +		greset |= CORE_SOFT_RESET_DONE;
>> +		writel(greset, &reg->grstctl);
>> +	}
>> +
>>  	debug("Resetting OTG controller\n");
>>  
>>  	dflt_gusbcfg =
>> diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h
>> index 9ca6f42375..b3d9117033 100644
>> --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h
>> +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h
>> @@ -63,24 +63,26 @@ struct dwc2_usbotg_reg {
>>  	u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
>>  	u8  res0[12];
>>  	u32 ggpio;     /* 0x038 */
>> -	u8  res1[20];
>> +	u8  res1[4];
>> +	u32 gsnpsid;
>> +	u8  res2[12];
>>  	u32 ghwcfg4; /* User HW Config4 */
>> -	u8  res2[176];
>> +	u8  res3[176];
>>  	u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
>> -	u8  res3[1728];
>> +	u8  res4[1728];
>>  	/* Device Configuration */
>>  	u32 dcfg; /* Device Configuration Register */
>>  	u32 dctl; /* Device Control */
>>  	u32 dsts; /* Device Status */
>> -	u8  res4[4];
>> +	u8  res5[4];
>>  	u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
>>  	u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
>>  	u32 daint; /* Device All Endpoints Interrupt */
>>  	u32 daintmsk; /* Device All Endpoints Interrupt Mask */
>> -	u8  res5[224];
>> +	u8  res6[224];
>>  	struct dwc2_dev_in_endp in_endp[16];
>>  	struct dwc2_dev_out_endp out_endp[16];
>> -	u8  res6[768];
>> +	u8  res7[768];
>>  	struct ep_fifo ep[16];
>>  };
>>  
>> @@ -118,6 +120,7 @@ struct dwc2_usbotg_reg {
>>  /* DWC2_UDC_OTG_GRSTCTL */
>>  #define AHB_MASTER_IDLE		(1u<<31)
>>  #define CORE_SOFT_RESET		(0x1<<0)
>> +#define CORE_SOFT_RESET_DONE		(0x1<<29)
>>  
>>  /* DWC2_UDC_OTG_GINTSTS/DWC2_UDC_OTG_GINTMSK core interrupt register */
>>  #define INT_RESUME			(1u<<31)
>> @@ -285,6 +288,10 @@ struct dwc2_usbotg_reg {
>>  #define DAINT_IN_EP_INT(x)                        (x << 0)
>>  #define DAINT_OUT_EP_INT(x)                       (x << 16)
>>  
>> +/* DWC2_UDC_OTG_GSNPSID */
>> +#define SNPSID_VER_420a					0x4f54420a
>> +#define SNPSID_VER_MASK					0xffff
>> +
>>  /* User HW Config4 */
>>  #define GHWCFG4_NUM_IN_EPS_MASK		(0xf << 26)
>>  #define GHWCFG4_NUM_IN_EPS_SHIFT	26
>> diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
>> index 637eb2dd06..1baeff96ee 100644
>> --- a/drivers/usb/host/dwc2.c
>> +++ b/drivers/usb/host/dwc2.c
>> @@ -159,6 +159,7 @@ static void dwc_otg_core_reset(struct udevice *dev,
>>  			       struct dwc2_core_regs *regs)
>>  {
>>  	int ret;
>> +	u32 snpsid, greset;
>>  
>>  	/* Wait for AHB master IDLE state. */
>>  	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
>> @@ -167,9 +168,20 @@ static void dwc_otg_core_reset(struct udevice *dev,
>>  		dev_info(dev, "%s: Timeout!\n", __func__);
>>  
>>  	/* Core Soft Reset */
>> +	snpsid = readl(&regs->gsnpsid);
>>  	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
>> -	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
>> -				false, 1000, false);
>> +	if ((snpsid & DWC2_SNPSID_VER_MASK) < (DWC2_SNPSID_DEVID_VER_420a & DWC2_SNPSID_VER_MASK)) {
>> +		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
>> +					false, 1000, false);
>> +	} else {
>> +		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_GSFTRST_DONE,
>> +					true, 1000, false);
>> +		greset = readl(&regs->grstctl);
>> +		greset &= ~DWC2_GRSTCTL_CSFTRST;
>> +		greset |= DWC2_GRSTCTL_GSFTRST_DONE;
>> +		writel(greset, &regs->grstctl);
>> +	}
>> +
>>  	if (ret)
>>  		dev_info(dev, "%s: Timeout!\n", __func__);
>>  
>> @@ -1180,7 +1192,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
>>  		 snpsid >> 12 & 0xf, snpsid & 0xfff);
>>  
>>  	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
>> -	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
>> +		(snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx &&
>> +	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_4xx) {
>>  		dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
>>  			 snpsid);
>>  		return -ENODEV;
>> diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h
>> index 6f022e33a1..e1f0f59b82 100644
>> --- a/drivers/usb/host/dwc2.h
>> +++ b/drivers/usb/host/dwc2.h
>> @@ -207,6 +207,8 @@ struct dwc2_core_regs {
>>  #define DWC2_GRSTCTL_TXFFLSH_OFFSET			5
>>  #define DWC2_GRSTCTL_TXFNUM_MASK			(0x1F << 6)
>>  #define DWC2_GRSTCTL_TXFNUM_OFFSET			6
>> +#define DWC2_GRSTCTL_GSFTRST_DONE			(1 << 29)
>> +#define DWC2_GRSTCTL_GSFTRST_DONE_OFFSET	29
>>  #define DWC2_GRSTCTL_DMAREQ				(1 << 30)
>>  #define DWC2_GRSTCTL_DMAREQ_OFFSET			30
>>  #define DWC2_GRSTCTL_AHBIDLE				(1 << 31)
>> @@ -739,8 +741,12 @@ struct dwc2_core_regs {
>>  #define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET			7
>>  #define DWC2_SNPSID_DEVID_VER_2xx			(0x4f542 << 12)
>>  #define DWC2_SNPSID_DEVID_VER_3xx			(0x4f543 << 12)
>> +#define DWC2_SNPSID_DEVID_VER_4xx			(0x4f544 << 12)
>> +#define DWC2_SNPSID_DEVID_VER_420a			0x4f54420a
>>  #define DWC2_SNPSID_DEVID_MASK				(0xfffff << 12)
>>  #define DWC2_SNPSID_DEVID_OFFSET			12
>> +#define DWC2_SNPSID_VER_MASK				0xffff
>> +#define DWC2_SNPSID_VER_OFFSET				0
>>  
>>  /* Host controller specific */
>>  #define DWC2_HC_PID_DATA0		0
>> -- 
>> 2.41.0
Marek Vasut April 21, 2024, 8:42 p.m. UTC | #3
On 3/28/24 2:14 PM, Kongyang Liu wrote:

[...]

> @@ -464,12 +464,26 @@ static void reconfig_usbd(struct dwc2_udc *dev)
>   {
>   	/* 2. Soft-reset OTG Core and then unreset again. */
>   	int i;
> -	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
> +	unsigned int uTemp;
>   	uint32_t dflt_gusbcfg;
>   	uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
>   	u32 max_hw_ep;
>   	int pdata_hw_ep;
>   

Drop this newline

> +	u32 snpsid, greset;
> +
> +	snpsid = readl(&reg->gsnpsid);
> +	writel(CORE_SOFT_RESET, &reg->grstctl);
> +	if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) {

Can you use FIELD_GET()/FIELD_PREP() for this ?

> +		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET, false, 1000, false);
> +	} else {
> +		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false);
> +		greset = readl(&reg->grstctl);
> +		greset &= ~CORE_SOFT_RESET;
> +		greset |= CORE_SOFT_RESET_DONE;
> +		writel(greset, &reg->grstctl);

clrsetbits_le32()

[...]

> diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
> index 637eb2dd06..1baeff96ee 100644
> --- a/drivers/usb/host/dwc2.c
> +++ b/drivers/usb/host/dwc2.c
> @@ -159,6 +159,7 @@ static void dwc_otg_core_reset(struct udevice *dev,
>   			       struct dwc2_core_regs *regs)
>   {
>   	int ret;
> +	u32 snpsid, greset;
>   
>   	/* Wait for AHB master IDLE state. */
>   	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
> @@ -167,9 +168,20 @@ static void dwc_otg_core_reset(struct udevice *dev,
>   		dev_info(dev, "%s: Timeout!\n", __func__);
>   
>   	/* Core Soft Reset */
> +	snpsid = readl(&regs->gsnpsid);
>   	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
> -	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
> -				false, 1000, false);
> +	if ((snpsid & DWC2_SNPSID_VER_MASK) < (DWC2_SNPSID_DEVID_VER_420a & DWC2_SNPSID_VER_MASK)) {
> +		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
> +					false, 1000, false);
> +	} else {
> +		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_GSFTRST_DONE,
> +					true, 1000, false);
> +		greset = readl(&regs->grstctl);
> +		greset &= ~DWC2_GRSTCTL_CSFTRST;
> +		greset |= DWC2_GRSTCTL_GSFTRST_DONE;
> +		writel(greset, &regs->grstctl);

Same comments as above.

Maybe this should be pulled into dedicated function to avoid duplication?

> +	}
> +
>   	if (ret)
>   		dev_info(dev, "%s: Timeout!\n", __func__);
>   
> @@ -1180,7 +1192,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
>   		 snpsid >> 12 & 0xf, snpsid & 0xfff);
>   
>   	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
> -	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
> +		(snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx &&
> +	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_4xx) {

Try FIELD_GET/FIELD_PREP
Kongyang Liu April 22, 2024, 5:31 a.m. UTC | #4
Marek Vasut <marex@denx.de> 于2024年4月22日周一 04:45写道:
>
> On 3/28/24 2:14 PM, Kongyang Liu wrote:
>
> [...]
>
> > @@ -464,12 +464,26 @@ static void reconfig_usbd(struct dwc2_udc *dev)
> >   {
> >       /* 2. Soft-reset OTG Core and then unreset again. */
> >       int i;
> > -     unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
> > +     unsigned int uTemp;
> >       uint32_t dflt_gusbcfg;
> >       uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
> >       u32 max_hw_ep;
> >       int pdata_hw_ep;
> >
>
> Drop this newline
>

I will fix it

> > +     u32 snpsid, greset;
> > +
> > +     snpsid = readl(&reg->gsnpsid);
> > +     writel(CORE_SOFT_RESET, &reg->grstctl);
> > +     if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) {
>
> Can you use FIELD_GET()/FIELD_PREP() for this ?
>

I will fix it

> > +             wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET, false, 1000, false);
> > +     } else {
> > +             wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false);
> > +             greset = readl(&reg->grstctl);
> > +             greset &= ~CORE_SOFT_RESET;
> > +             greset |= CORE_SOFT_RESET_DONE;
> > +             writel(greset, &reg->grstctl);
>
> clrsetbits_le32()
>

I will fix it

> [...]
>
> > diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
> > index 637eb2dd06..1baeff96ee 100644
> > --- a/drivers/usb/host/dwc2.c
> > +++ b/drivers/usb/host/dwc2.c
> > @@ -159,6 +159,7 @@ static void dwc_otg_core_reset(struct udevice *dev,
> >                              struct dwc2_core_regs *regs)
> >   {
> >       int ret;
> > +     u32 snpsid, greset;
> >
> >       /* Wait for AHB master IDLE state. */
> >       ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
> > @@ -167,9 +168,20 @@ static void dwc_otg_core_reset(struct udevice *dev,
> >               dev_info(dev, "%s: Timeout!\n", __func__);
> >
> >       /* Core Soft Reset */
> > +     snpsid = readl(&regs->gsnpsid);
> >       writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
> > -     ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
> > -                             false, 1000, false);
> > +     if ((snpsid & DWC2_SNPSID_VER_MASK) < (DWC2_SNPSID_DEVID_VER_420a & DWC2_SNPSID_VER_MASK)) {
> > +             ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
> > +                                     false, 1000, false);
> > +     } else {
> > +             ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_GSFTRST_DONE,
> > +                                     true, 1000, false);
> > +             greset = readl(&regs->grstctl);
> > +             greset &= ~DWC2_GRSTCTL_CSFTRST;
> > +             greset |= DWC2_GRSTCTL_GSFTRST_DONE;
> > +             writel(greset, &regs->grstctl);
>
> Same comments as above.
>
> Maybe this should be pulled into dedicated function to avoid duplication?
>

For U-Boot, the dwc2 USB driver is split into two modules: host and gadget.
Each has its own register definitions and definitions for register bits,
which makes it difficult to extract a single function. Moreover, deciding
where to place this function is also an issue.

> > +     }
> > +
> >       if (ret)
> >               dev_info(dev, "%s: Timeout!\n", __func__);
> >
> > @@ -1180,7 +1192,8 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
> >                snpsid >> 12 & 0xf, snpsid & 0xfff);
> >
> >       if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
> > -         (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
> > +             (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx &&
> > +         (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_4xx) {
>
> Try FIELD_GET/FIELD_PREP

I will fix it

Best regards
Kongyang Liu
Marek Vasut April 22, 2024, 11:11 p.m. UTC | #5
On 4/22/24 7:31 AM, Kongyang Liu wrote:

[...]

>>> @@ -167,9 +168,20 @@ static void dwc_otg_core_reset(struct udevice *dev,
>>>                dev_info(dev, "%s: Timeout!\n", __func__);
>>>
>>>        /* Core Soft Reset */
>>> +     snpsid = readl(&regs->gsnpsid);
>>>        writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
>>> -     ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
>>> -                             false, 1000, false);
>>> +     if ((snpsid & DWC2_SNPSID_VER_MASK) < (DWC2_SNPSID_DEVID_VER_420a & DWC2_SNPSID_VER_MASK)) {
>>> +             ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
>>> +                                     false, 1000, false);
>>> +     } else {
>>> +             ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_GSFTRST_DONE,
>>> +                                     true, 1000, false);
>>> +             greset = readl(&regs->grstctl);
>>> +             greset &= ~DWC2_GRSTCTL_CSFTRST;
>>> +             greset |= DWC2_GRSTCTL_GSFTRST_DONE;
>>> +             writel(greset, &regs->grstctl);
>>
>> Same comments as above.
>>
>> Maybe this should be pulled into dedicated function to avoid duplication?
>>
> 
> For U-Boot, the dwc2 USB driver is split into two modules: host and gadget.
> Each has its own register definitions and definitions for register bits,
> which makes it difficult to extract a single function. Moreover, deciding
> where to place this function is also an issue.

There is drivers/usb/common/ for such code. The register macros can 
probably be unified into a single header too.
diff mbox series

Patch

diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index 27082f5152..d1dd469a0f 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -42,7 +42,7 @@ 
 #include <asm/unaligned.h>
 #include <asm/io.h>
 
-#include <asm/mach-types.h>
+#include <wait_bit.h>
 
 #include <power/regulator.h>
 
@@ -464,12 +464,26 @@  static void reconfig_usbd(struct dwc2_udc *dev)
 {
 	/* 2. Soft-reset OTG Core and then unreset again. */
 	int i;
-	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
+	unsigned int uTemp;
 	uint32_t dflt_gusbcfg;
 	uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
 	u32 max_hw_ep;
 	int pdata_hw_ep;
 
+	u32 snpsid, greset;
+
+	snpsid = readl(&reg->gsnpsid);
+	writel(CORE_SOFT_RESET, &reg->grstctl);
+	if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) {
+		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET, false, 1000, false);
+	} else {
+		wait_for_bit_le32(&reg->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false);
+		greset = readl(&reg->grstctl);
+		greset &= ~CORE_SOFT_RESET;
+		greset |= CORE_SOFT_RESET_DONE;
+		writel(greset, &reg->grstctl);
+	}
+
 	debug("Resetting OTG controller\n");
 
 	dflt_gusbcfg =
diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h
index 9ca6f42375..b3d9117033 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_regs.h
+++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h
@@ -63,24 +63,26 @@  struct dwc2_usbotg_reg {
 	u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
 	u8  res0[12];
 	u32 ggpio;     /* 0x038 */
-	u8  res1[20];
+	u8  res1[4];
+	u32 gsnpsid;
+	u8  res2[12];
 	u32 ghwcfg4; /* User HW Config4 */
-	u8  res2[176];
+	u8  res3[176];
 	u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
-	u8  res3[1728];
+	u8  res4[1728];
 	/* Device Configuration */
 	u32 dcfg; /* Device Configuration Register */
 	u32 dctl; /* Device Control */
 	u32 dsts; /* Device Status */
-	u8  res4[4];
+	u8  res5[4];
 	u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
 	u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
 	u32 daint; /* Device All Endpoints Interrupt */
 	u32 daintmsk; /* Device All Endpoints Interrupt Mask */
-	u8  res5[224];
+	u8  res6[224];
 	struct dwc2_dev_in_endp in_endp[16];
 	struct dwc2_dev_out_endp out_endp[16];
-	u8  res6[768];
+	u8  res7[768];
 	struct ep_fifo ep[16];
 };
 
@@ -118,6 +120,7 @@  struct dwc2_usbotg_reg {
 /* DWC2_UDC_OTG_GRSTCTL */
 #define AHB_MASTER_IDLE		(1u<<31)
 #define CORE_SOFT_RESET		(0x1<<0)
+#define CORE_SOFT_RESET_DONE		(0x1<<29)
 
 /* DWC2_UDC_OTG_GINTSTS/DWC2_UDC_OTG_GINTMSK core interrupt register */
 #define INT_RESUME			(1u<<31)
@@ -285,6 +288,10 @@  struct dwc2_usbotg_reg {
 #define DAINT_IN_EP_INT(x)                        (x << 0)
 #define DAINT_OUT_EP_INT(x)                       (x << 16)
 
+/* DWC2_UDC_OTG_GSNPSID */
+#define SNPSID_VER_420a					0x4f54420a
+#define SNPSID_VER_MASK					0xffff
+
 /* User HW Config4 */
 #define GHWCFG4_NUM_IN_EPS_MASK		(0xf << 26)
 #define GHWCFG4_NUM_IN_EPS_SHIFT	26
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index 637eb2dd06..1baeff96ee 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -159,6 +159,7 @@  static void dwc_otg_core_reset(struct udevice *dev,
 			       struct dwc2_core_regs *regs)
 {
 	int ret;
+	u32 snpsid, greset;
 
 	/* Wait for AHB master IDLE state. */
 	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
@@ -167,9 +168,20 @@  static void dwc_otg_core_reset(struct udevice *dev,
 		dev_info(dev, "%s: Timeout!\n", __func__);
 
 	/* Core Soft Reset */
+	snpsid = readl(&regs->gsnpsid);
 	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
-	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
-				false, 1000, false);
+	if ((snpsid & DWC2_SNPSID_VER_MASK) < (DWC2_SNPSID_DEVID_VER_420a & DWC2_SNPSID_VER_MASK)) {
+		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
+					false, 1000, false);
+	} else {
+		ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_GSFTRST_DONE,
+					true, 1000, false);
+		greset = readl(&regs->grstctl);
+		greset &= ~DWC2_GRSTCTL_CSFTRST;
+		greset |= DWC2_GRSTCTL_GSFTRST_DONE;
+		writel(greset, &regs->grstctl);
+	}
+
 	if (ret)
 		dev_info(dev, "%s: Timeout!\n", __func__);
 
@@ -1180,7 +1192,8 @@  static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
 		 snpsid >> 12 & 0xf, snpsid & 0xfff);
 
 	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
-	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
+		(snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx &&
+	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_4xx) {
 		dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
 			 snpsid);
 		return -ENODEV;
diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h
index 6f022e33a1..e1f0f59b82 100644
--- a/drivers/usb/host/dwc2.h
+++ b/drivers/usb/host/dwc2.h
@@ -207,6 +207,8 @@  struct dwc2_core_regs {
 #define DWC2_GRSTCTL_TXFFLSH_OFFSET			5
 #define DWC2_GRSTCTL_TXFNUM_MASK			(0x1F << 6)
 #define DWC2_GRSTCTL_TXFNUM_OFFSET			6
+#define DWC2_GRSTCTL_GSFTRST_DONE			(1 << 29)
+#define DWC2_GRSTCTL_GSFTRST_DONE_OFFSET	29
 #define DWC2_GRSTCTL_DMAREQ				(1 << 30)
 #define DWC2_GRSTCTL_DMAREQ_OFFSET			30
 #define DWC2_GRSTCTL_AHBIDLE				(1 << 31)
@@ -739,8 +741,12 @@  struct dwc2_core_regs {
 #define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET			7
 #define DWC2_SNPSID_DEVID_VER_2xx			(0x4f542 << 12)
 #define DWC2_SNPSID_DEVID_VER_3xx			(0x4f543 << 12)
+#define DWC2_SNPSID_DEVID_VER_4xx			(0x4f544 << 12)
+#define DWC2_SNPSID_DEVID_VER_420a			0x4f54420a
 #define DWC2_SNPSID_DEVID_MASK				(0xfffff << 12)
 #define DWC2_SNPSID_DEVID_OFFSET			12
+#define DWC2_SNPSID_VER_MASK				0xffff
+#define DWC2_SNPSID_VER_OFFSET				0
 
 /* Host controller specific */
 #define DWC2_HC_PID_DATA0		0