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 |
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, ®->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(®->gsnpsid); > + writel(CORE_SOFT_RESET, ®->grstctl); > + if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) { > + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET, false, 1000, false); > + } else { > + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false); > + greset = readl(®->grstctl); > + greset &= ~CORE_SOFT_RESET; > + greset |= CORE_SOFT_RESET_DONE; > + writel(greset, ®->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(®s->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(®s->gsnpsid); > writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); > - ret = wait_for_bit_le32(®s->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(®s->grstctl, DWC2_GRSTCTL_CSFTRST, > + false, 1000, false); > + } else { > + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_GSFTRST_DONE, > + true, 1000, false); > + greset = readl(®s->grstctl); > + greset &= ~DWC2_GRSTCTL_CSFTRST; > + greset |= DWC2_GRSTCTL_GSFTRST_DONE; > + writel(greset, ®s->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
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, ®->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(®->gsnpsid); >> + writel(CORE_SOFT_RESET, ®->grstctl); >> + if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) { >> + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET, false, 1000, false); >> + } else { >> + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false); >> + greset = readl(®->grstctl); >> + greset &= ~CORE_SOFT_RESET; >> + greset |= CORE_SOFT_RESET_DONE; >> + writel(greset, ®->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(®s->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(®s->gsnpsid); >> writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); >> - ret = wait_for_bit_le32(®s->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(®s->grstctl, DWC2_GRSTCTL_CSFTRST, >> + false, 1000, false); >> + } else { >> + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_GSFTRST_DONE, >> + true, 1000, false); >> + greset = readl(®s->grstctl); >> + greset &= ~DWC2_GRSTCTL_CSFTRST; >> + greset |= DWC2_GRSTCTL_GSFTRST_DONE; >> + writel(greset, ®s->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
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, ®->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(®->gsnpsid); > + writel(CORE_SOFT_RESET, ®->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(®->grstctl, CORE_SOFT_RESET, false, 1000, false); > + } else { > + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false); > + greset = readl(®->grstctl); > + greset &= ~CORE_SOFT_RESET; > + greset |= CORE_SOFT_RESET_DONE; > + writel(greset, ®->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(®s->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(®s->gsnpsid); > writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); > - ret = wait_for_bit_le32(®s->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(®s->grstctl, DWC2_GRSTCTL_CSFTRST, > + false, 1000, false); > + } else { > + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_GSFTRST_DONE, > + true, 1000, false); > + greset = readl(®s->grstctl); > + greset &= ~DWC2_GRSTCTL_CSFTRST; > + greset |= DWC2_GRSTCTL_GSFTRST_DONE; > + writel(greset, ®s->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
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, ®->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(®->gsnpsid); > > + writel(CORE_SOFT_RESET, ®->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(®->grstctl, CORE_SOFT_RESET, false, 1000, false); > > + } else { > > + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false); > > + greset = readl(®->grstctl); > > + greset &= ~CORE_SOFT_RESET; > > + greset |= CORE_SOFT_RESET_DONE; > > + writel(greset, ®->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(®s->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(®s->gsnpsid); > > writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); > > - ret = wait_for_bit_le32(®s->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(®s->grstctl, DWC2_GRSTCTL_CSFTRST, > > + false, 1000, false); > > + } else { > > + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_GSFTRST_DONE, > > + true, 1000, false); > > + greset = readl(®s->grstctl); > > + greset &= ~DWC2_GRSTCTL_CSFTRST; > > + greset |= DWC2_GRSTCTL_GSFTRST_DONE; > > + writel(greset, ®s->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
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(®s->gsnpsid); >>> writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); >>> - ret = wait_for_bit_le32(®s->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(®s->grstctl, DWC2_GRSTCTL_CSFTRST, >>> + false, 1000, false); >>> + } else { >>> + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_GSFTRST_DONE, >>> + true, 1000, false); >>> + greset = readl(®s->grstctl); >>> + greset &= ~DWC2_GRSTCTL_CSFTRST; >>> + greset |= DWC2_GRSTCTL_GSFTRST_DONE; >>> + writel(greset, ®s->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 --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, ®->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(®->gsnpsid); + writel(CORE_SOFT_RESET, ®->grstctl); + if ((snpsid & SNPSID_VER_MASK) < (SNPSID_VER_420a & SNPSID_VER_MASK)) { + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET, false, 1000, false); + } else { + wait_for_bit_le32(®->grstctl, CORE_SOFT_RESET_DONE, true, 1000, false); + greset = readl(®->grstctl); + greset &= ~CORE_SOFT_RESET; + greset |= CORE_SOFT_RESET_DONE; + writel(greset, ®->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(®s->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(®s->gsnpsid); writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); - ret = wait_for_bit_le32(®s->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(®s->grstctl, DWC2_GRSTCTL_CSFTRST, + false, 1000, false); + } else { + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_GSFTRST_DONE, + true, 1000, false); + greset = readl(®s->grstctl); + greset &= ~DWC2_GRSTCTL_CSFTRST; + greset |= DWC2_GRSTCTL_GSFTRST_DONE; + writel(greset, ®s->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
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(-)