[RFC,3/4] usb: dwc3: add quirk to be compatible for AMD NL

Message ID 20140927043044.GA28474@saruman
State New
Headers show

Commit Message

Felipe Balbi Sept. 27, 2014, 4:30 a.m.
Hi,

On Sat, Sep 27, 2014 at 01:05:46AM +0000, Paul Zimmerman wrote:
> > From: Felipe Balbi [mailto:balbi@ti.com]
> > Sent: Friday, September 26, 2014 5:54 PM
> > 
> > On Fri, Sep 26, 2014 at 11:18:48PM +0000, Paul Zimmerman wrote:
> > > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > > Sent: Friday, September 26, 2014 2:40 PM
> > > >
> > > > On Fri, Sep 26, 2014 at 08:57:19PM +0000, Paul Zimmerman wrote:
> > > > > > > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > > > > > > index 0fcc0a3..8277065 100644
> > > > > > > --- a/drivers/usb/dwc3/gadget.c
> > > > > > > +++ b/drivers/usb/dwc3/gadget.c
> > > > > > > @@ -2635,6 +2635,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
> > > > > > >   */
> > > > > > >  int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > >  {
> > > > > > > +	u32					reg;
> > > > > > >  	int					ret;
> > > > > > >
> > > > > > >  	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
> > > > > > > @@ -2689,6 +2690,13 @@ int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > >  	if (ret)
> > > > > > >  		goto err4;
> > > > > > >
> > > > > > > +	if (dwc->quirks & DWC3_AMD_NL_PLAT) {
> > > > > > > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > > > > > > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > > > > >
> > > > > > weird, why would Synopsys put this here ? It seems like this is only
> > > > > > useful when LPM Errata is enabled and that's, apparently, a host-side
> > > > > > thing.
> > > > > >
> > > > > > Paul, can you comment ?
> > > > >
> > > > > These bits contribute to how the device responds to an LPM transaction
> > > > > from the host. If DCFG.LPMCap=1, they set the BESL value above which
> > > > > the core will send a NYET. If DCFG.LPMCap=0, they have no effect. So
> > > > > it's definitely a device-side thing, but only if the core is configured
> > > > > with LPM Errata support enabled.
> > > >
> > > > right, and how can SW detect if LPM Errata was enabled ? From the host
> > > > point of view, we can check bit 20 of xHCI capability register. What
> > > > about device ? I can't seem to find anything :-s
> > >
> > > I just talked to one of our RTL designers. You're right, there is no
> > > way to tell from the Device registers alone whether the controller is
> > > configured with LPM Errata support or not.
> > >
> > > You can tell for sure if it is *not* enabled, by checking GSNPSID, and
> > > if the version is earlier than 2.40a, the feature wasn't available.
> > 
> > alright, we can use this for something like:
> > 
> > WARN(rev < 2.40a && (flags & LPM_ERRATA || of_property_read_bool("lpm-errata")),
> > 	"LPM Errata not available on dwc3 revisions <= 2.40a\n");
> > 
> > > So for Device-mode only controllers, I guess you will need a DT property
> > > for this.
> > 
> > right, DT property and platform_data feature flag, or something. I don't
> > wanna call it a quirk though, although it _is_ an erratum WRT LPM
> > support. Dunno. Any strong feelings ?
> 
> Well, it's called LPM Errata because the feature was added to the USB
> spec as an erratum. It's not an erratum to our controller. But I don't
> have any strong feelings about how the driver support is implemented.

how about adding a "has_lpm_erratum" to struct dwc3 which gets
initialized either through pdata or DT ? Then above WARN() would become:

WARN(dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum",
	"LPM Erratum not available on dwc3 revisisions < 2.40a\n");

Then we're not really calling it a quirk. In fact Huang, when respining
your series, let's convert your quirk bits into single-bit fields inside
struct dwc3 and struct platform_data. Like so:


note that I have also moved DCTL access from gadget_init to
gadget_start.

cheers

Comments

Huang Rui Sept. 28, 2014, 9:18 a.m. | #1
On Fri, Sep 26, 2014 at 11:30:44PM -0500, Felipe Balbi wrote:
> Hi,
> 
> On Sat, Sep 27, 2014 at 01:05:46AM +0000, Paul Zimmerman wrote:
> > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > Sent: Friday, September 26, 2014 5:54 PM
> > > 
> > > On Fri, Sep 26, 2014 at 11:18:48PM +0000, Paul Zimmerman wrote:
> > > > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > > > Sent: Friday, September 26, 2014 2:40 PM
> > > > >
> > > > > On Fri, Sep 26, 2014 at 08:57:19PM +0000, Paul Zimmerman wrote:
> > > > > > > > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > > > > > > > index 0fcc0a3..8277065 100644
> > > > > > > > --- a/drivers/usb/dwc3/gadget.c
> > > > > > > > +++ b/drivers/usb/dwc3/gadget.c
> > > > > > > > @@ -2635,6 +2635,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
> > > > > > > >   */
> > > > > > > >  int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > > >  {
> > > > > > > > +	u32					reg;
> > > > > > > >  	int					ret;
> > > > > > > >
> > > > > > > >  	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
> > > > > > > > @@ -2689,6 +2690,13 @@ int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > > >  	if (ret)
> > > > > > > >  		goto err4;
> > > > > > > >
> > > > > > > > +	if (dwc->quirks & DWC3_AMD_NL_PLAT) {
> > > > > > > > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > > > > > > > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > > > > > >
> > > > > > > weird, why would Synopsys put this here ? It seems like this is only
> > > > > > > useful when LPM Errata is enabled and that's, apparently, a host-side
> > > > > > > thing.
> > > > > > >
> > > > > > > Paul, can you comment ?
> > > > > >
> > > > > > These bits contribute to how the device responds to an LPM transaction
> > > > > > from the host. If DCFG.LPMCap=1, they set the BESL value above which
> > > > > > the core will send a NYET. If DCFG.LPMCap=0, they have no effect. So
> > > > > > it's definitely a device-side thing, but only if the core is configured
> > > > > > with LPM Errata support enabled.
> > > > >
> > > > > right, and how can SW detect if LPM Errata was enabled ? From the host
> > > > > point of view, we can check bit 20 of xHCI capability register. What
> > > > > about device ? I can't seem to find anything :-s
> > > >
> > > > I just talked to one of our RTL designers. You're right, there is no
> > > > way to tell from the Device registers alone whether the controller is
> > > > configured with LPM Errata support or not.
> > > >
> > > > You can tell for sure if it is *not* enabled, by checking GSNPSID, and
> > > > if the version is earlier than 2.40a, the feature wasn't available.
> > > 
> > > alright, we can use this for something like:
> > > 
> > > WARN(rev < 2.40a && (flags & LPM_ERRATA || of_property_read_bool("lpm-errata")),
> > > 	"LPM Errata not available on dwc3 revisions <= 2.40a\n");
> > > 
> > > > So for Device-mode only controllers, I guess you will need a DT property
> > > > for this.
> > > 
> > > right, DT property and platform_data feature flag, or something. I don't
> > > wanna call it a quirk though, although it _is_ an erratum WRT LPM
> > > support. Dunno. Any strong feelings ?
> > 
> > Well, it's called LPM Errata because the feature was added to the USB
> > spec as an erratum. It's not an erratum to our controller. But I don't
> > have any strong feelings about how the driver support is implemented.
> 
> how about adding a "has_lpm_erratum" to struct dwc3 which gets
> initialized either through pdata or DT ? Then above WARN() would become:
> 
> WARN(dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum",
> 	"LPM Erratum not available on dwc3 revisisions < 2.40a\n");
> 
> Then we're not really calling it a quirk. In fact Huang, when respining
> your series, let's convert your quirk bits into single-bit fields inside
> struct dwc3 and struct platform_data. Like so:
> 

Looks like a good suggestion.

> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 4d4e854..e233ce1 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -695,11 +695,13 @@ static int dwc3_probe(struct platform_device *pdev)
>  
>  	if (node) {
>  		dwc->maximum_speed = of_usb_get_maximum_speed(node);
> +		dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum");
>  
>  		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
>  		dwc->dr_mode = of_usb_get_dr_mode(node);
>  	} else if (pdata) {
>  		dwc->maximum_speed = pdata->maximum_speed;
> +		dwc->has_lpm_erratum = pdata->has_lpm_erratum; >  
>  		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
>  		dwc->dr_mode = pdata->dr_mode;
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 66f6256..23e1504 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -661,6 +661,8 @@ struct dwc3_scratchpad_array {
>   * @ep0_bounced: true when we used bounce buffer
>   * @ep0_expect_in: true when we expect a DATA IN transfer
>   * @has_hibernation: true when dwc3 was configured with Hibernation
> + * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
> + *			there's now way for software to detect this in runtime.
>   * @is_selfpowered: true when we are selfpowered
>   * @needs_fifo_resize: not all users might want fifo resizing, flag it
>   * @pullups_connected: true when Run/Stop bit is set
> @@ -764,6 +766,7 @@ struct dwc3 {
>  	unsigned		ep0_bounced:1;
>  	unsigned		ep0_expect_in:1;
>  	unsigned		has_hibernation:1;
> +	unsigned		has_lpm_erratum:1;
>  	unsigned		is_selfpowered:1;
>  	unsigned		needs_fifo_resize:1;
>  	unsigned		pullups_connected:1;
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index 68497b3..112352e 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -1577,6 +1577,13 @@ static int dwc3_gadget_start(struct usb_gadget *g,
>  	}
>  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
>  
> +	if (dwc->has_lpm_erratum) {
> +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> +		/* REVISIT should this be configurable ? */
> +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> +	}
> +
>  	dwc->start_config_issued = false;
>  
>  	/* Start with SuperSpeed Default */
> diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
> index 7db34f0..4bcec7c 100644
> --- a/drivers/usb/dwc3/platform_data.h
> +++ b/drivers/usb/dwc3/platform_data.h
> @@ -24,4 +24,6 @@ struct dwc3_platform_data {
>  	enum usb_device_speed maximum_speed;
>  	enum usb_dr_mode dr_mode;
>  	bool tx_fifo_resize;
> +
> +	unsigned has_lpm_erratum:1;
>  };
> 
> note that I have also moved DCTL access from gadget_init to
> gadget_start.
> 

Yes, I see. Will update it into V2.

A question, the dwc3 controller is the PCI-E device in my platform,
but the class code of PCI header is 0x0c0330, the same with xHC.
That's because it need to meet the windows enviroment. The dwc3
controller acted as only host mode to bind with windows xhci driver.
But on linux, sometimes, we auto-bind with xhci driver as well (class
code 0x0c0330) despite we use Pid/Vid on dwc3 driver. Then I need
rmmod xhci_hcd module and modprobe dwc3_pci module manually.

Any idea to resolve this issue?

Thanks,
Rui
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Felipe Balbi Sept. 28, 2014, 11:46 p.m. | #2
Hi,

On Sun, Sep 28, 2014 at 05:18:58PM +0800, Huang Rui wrote:
> > > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > > Sent: Friday, September 26, 2014 5:54 PM
> > > > 
> > > > On Fri, Sep 26, 2014 at 11:18:48PM +0000, Paul Zimmerman wrote:
> > > > > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > > > > Sent: Friday, September 26, 2014 2:40 PM
> > > > > >
> > > > > > On Fri, Sep 26, 2014 at 08:57:19PM +0000, Paul Zimmerman wrote:
> > > > > > > > > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > > > > > > > > index 0fcc0a3..8277065 100644
> > > > > > > > > --- a/drivers/usb/dwc3/gadget.c
> > > > > > > > > +++ b/drivers/usb/dwc3/gadget.c
> > > > > > > > > @@ -2635,6 +2635,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
> > > > > > > > >   */
> > > > > > > > >  int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > > > >  {
> > > > > > > > > +	u32					reg;
> > > > > > > > >  	int					ret;
> > > > > > > > >
> > > > > > > > >  	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
> > > > > > > > > @@ -2689,6 +2690,13 @@ int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > > > >  	if (ret)
> > > > > > > > >  		goto err4;
> > > > > > > > >
> > > > > > > > > +	if (dwc->quirks & DWC3_AMD_NL_PLAT) {
> > > > > > > > > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > > > > > > > > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > > > > > > >
> > > > > > > > weird, why would Synopsys put this here ? It seems like this is only
> > > > > > > > useful when LPM Errata is enabled and that's, apparently, a host-side
> > > > > > > > thing.
> > > > > > > >
> > > > > > > > Paul, can you comment ?
> > > > > > >
> > > > > > > These bits contribute to how the device responds to an LPM transaction
> > > > > > > from the host. If DCFG.LPMCap=1, they set the BESL value above which
> > > > > > > the core will send a NYET. If DCFG.LPMCap=0, they have no effect. So
> > > > > > > it's definitely a device-side thing, but only if the core is configured
> > > > > > > with LPM Errata support enabled.
> > > > > >
> > > > > > right, and how can SW detect if LPM Errata was enabled ? From the host
> > > > > > point of view, we can check bit 20 of xHCI capability register. What
> > > > > > about device ? I can't seem to find anything :-s
> > > > >
> > > > > I just talked to one of our RTL designers. You're right, there is no
> > > > > way to tell from the Device registers alone whether the controller is
> > > > > configured with LPM Errata support or not.
> > > > >
> > > > > You can tell for sure if it is *not* enabled, by checking GSNPSID, and
> > > > > if the version is earlier than 2.40a, the feature wasn't available.
> > > > 
> > > > alright, we can use this for something like:
> > > > 
> > > > WARN(rev < 2.40a && (flags & LPM_ERRATA || of_property_read_bool("lpm-errata")),
> > > > 	"LPM Errata not available on dwc3 revisions <= 2.40a\n");
> > > > 
> > > > > So for Device-mode only controllers, I guess you will need a DT property
> > > > > for this.
> > > > 
> > > > right, DT property and platform_data feature flag, or something. I don't
> > > > wanna call it a quirk though, although it _is_ an erratum WRT LPM
> > > > support. Dunno. Any strong feelings ?
> > > 
> > > Well, it's called LPM Errata because the feature was added to the USB
> > > spec as an erratum. It's not an erratum to our controller. But I don't
> > > have any strong feelings about how the driver support is implemented.
> > 
> > how about adding a "has_lpm_erratum" to struct dwc3 which gets
> > initialized either through pdata or DT ? Then above WARN() would become:
> > 
> > WARN(dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum",
> > 	"LPM Erratum not available on dwc3 revisisions < 2.40a\n");
> > 
> > Then we're not really calling it a quirk. In fact Huang, when respining
> > your series, let's convert your quirk bits into single-bit fields inside
> > struct dwc3 and struct platform_data. Like so:
> > 
> 
> Looks like a good suggestion.
> 
> > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> > index 4d4e854..e233ce1 100644
> > --- a/drivers/usb/dwc3/core.c
> > +++ b/drivers/usb/dwc3/core.c
> > @@ -695,11 +695,13 @@ static int dwc3_probe(struct platform_device *pdev)
> >  
> >  	if (node) {
> >  		dwc->maximum_speed = of_usb_get_maximum_speed(node);
> > +		dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum");
> >  
> >  		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
> >  		dwc->dr_mode = of_usb_get_dr_mode(node);
> >  	} else if (pdata) {
> >  		dwc->maximum_speed = pdata->maximum_speed;
> > +		dwc->has_lpm_erratum = pdata->has_lpm_erratum; >  
> >  		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
> >  		dwc->dr_mode = pdata->dr_mode;
> > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> > index 66f6256..23e1504 100644
> > --- a/drivers/usb/dwc3/core.h
> > +++ b/drivers/usb/dwc3/core.h
> > @@ -661,6 +661,8 @@ struct dwc3_scratchpad_array {
> >   * @ep0_bounced: true when we used bounce buffer
> >   * @ep0_expect_in: true when we expect a DATA IN transfer
> >   * @has_hibernation: true when dwc3 was configured with Hibernation
> > + * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
> > + *			there's now way for software to detect this in runtime.
> >   * @is_selfpowered: true when we are selfpowered
> >   * @needs_fifo_resize: not all users might want fifo resizing, flag it
> >   * @pullups_connected: true when Run/Stop bit is set
> > @@ -764,6 +766,7 @@ struct dwc3 {
> >  	unsigned		ep0_bounced:1;
> >  	unsigned		ep0_expect_in:1;
> >  	unsigned		has_hibernation:1;
> > +	unsigned		has_lpm_erratum:1;
> >  	unsigned		is_selfpowered:1;
> >  	unsigned		needs_fifo_resize:1;
> >  	unsigned		pullups_connected:1;
> > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > index 68497b3..112352e 100644
> > --- a/drivers/usb/dwc3/gadget.c
> > +++ b/drivers/usb/dwc3/gadget.c
> > @@ -1577,6 +1577,13 @@ static int dwc3_gadget_start(struct usb_gadget *g,
> >  	}
> >  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
> >  
> > +	if (dwc->has_lpm_erratum) {
> > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > +		/* REVISIT should this be configurable ? */
> > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> > +	}
> > +
> >  	dwc->start_config_issued = false;
> >  
> >  	/* Start with SuperSpeed Default */
> > diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
> > index 7db34f0..4bcec7c 100644
> > --- a/drivers/usb/dwc3/platform_data.h
> > +++ b/drivers/usb/dwc3/platform_data.h
> > @@ -24,4 +24,6 @@ struct dwc3_platform_data {
> >  	enum usb_device_speed maximum_speed;
> >  	enum usb_dr_mode dr_mode;
> >  	bool tx_fifo_resize;
> > +
> > +	unsigned has_lpm_erratum:1;
> >  };
> > 
> > note that I have also moved DCTL access from gadget_init to
> > gadget_start.
> > 
> 
> Yes, I see. Will update it into V2.
> 
> A question, the dwc3 controller is the PCI-E device in my platform,
> but the class code of PCI header is 0x0c0330, the same with xHC.
> That's because it need to meet the windows enviroment. The dwc3
> controller acted as only host mode to bind with windows xhci driver.
> But on linux, sometimes, we auto-bind with xhci driver as well (class
> code 0x0c0330) despite we use Pid/Vid on dwc3 driver. Then I need
> rmmod xhci_hcd module and modprobe dwc3_pci module manually.
> 
> Any idea to resolve this issue?

that probably won't be the case on final Silicon. I reckon you're using
Synopsys' HAPS for development, right ? That's just how Synopsys
designed the PCIe wrapper to make it easy to test with xHCI. Please make
sure to not use the same PCI header as xHCI on final silicon, otherwise
SW engineers' lifes will become more difficult :-)

Meanwhile, you can just blacklist xhci under /etc/modprobe.d/. Create a
new file (say xhci-blacklist.conf) and add this to it:

blacklist xhci-hcd

Save and restart. xhci-hcd will never load by default anymore, but you
can still manually load it.

Heikki, can you confirm if your DWC3 incarnations present this same
"feature" ? :-)
Huang Rui Sept. 29, 2014, 1:48 a.m. | #3
On Sun, Sep 28, 2014 at 06:46:14PM -0500, Felipe Balbi wrote:
> Hi,
> 
> On Sun, Sep 28, 2014 at 05:18:58PM +0800, Huang Rui wrote:
> > > > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > > > Sent: Friday, September 26, 2014 5:54 PM
> > > > > 
> > > > > On Fri, Sep 26, 2014 at 11:18:48PM +0000, Paul Zimmerman wrote:
> > > > > > > From: Felipe Balbi [mailto:balbi@ti.com]
> > > > > > > Sent: Friday, September 26, 2014 2:40 PM
> > > > > > >
> > > > > > > On Fri, Sep 26, 2014 at 08:57:19PM +0000, Paul Zimmerman wrote:
> > > > > > > > > > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > > > > > > > > > index 0fcc0a3..8277065 100644
> > > > > > > > > > --- a/drivers/usb/dwc3/gadget.c
> > > > > > > > > > +++ b/drivers/usb/dwc3/gadget.c
> > > > > > > > > > @@ -2635,6 +2635,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
> > > > > > > > > >   */
> > > > > > > > > >  int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > > > > >  {
> > > > > > > > > > +	u32					reg;
> > > > > > > > > >  	int					ret;
> > > > > > > > > >
> > > > > > > > > >  	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
> > > > > > > > > > @@ -2689,6 +2690,13 @@ int dwc3_gadget_init(struct dwc3 *dwc)
> > > > > > > > > >  	if (ret)
> > > > > > > > > >  		goto err4;
> > > > > > > > > >
> > > > > > > > > > +	if (dwc->quirks & DWC3_AMD_NL_PLAT) {
> > > > > > > > > > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > > > > > > > > > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > > > > > > > >
> > > > > > > > > weird, why would Synopsys put this here ? It seems like this is only
> > > > > > > > > useful when LPM Errata is enabled and that's, apparently, a host-side
> > > > > > > > > thing.
> > > > > > > > >
> > > > > > > > > Paul, can you comment ?
> > > > > > > >
> > > > > > > > These bits contribute to how the device responds to an LPM transaction
> > > > > > > > from the host. If DCFG.LPMCap=1, they set the BESL value above which
> > > > > > > > the core will send a NYET. If DCFG.LPMCap=0, they have no effect. So
> > > > > > > > it's definitely a device-side thing, but only if the core is configured
> > > > > > > > with LPM Errata support enabled.
> > > > > > >
> > > > > > > right, and how can SW detect if LPM Errata was enabled ? From the host
> > > > > > > point of view, we can check bit 20 of xHCI capability register. What
> > > > > > > about device ? I can't seem to find anything :-s
> > > > > >
> > > > > > I just talked to one of our RTL designers. You're right, there is no
> > > > > > way to tell from the Device registers alone whether the controller is
> > > > > > configured with LPM Errata support or not.
> > > > > >
> > > > > > You can tell for sure if it is *not* enabled, by checking GSNPSID, and
> > > > > > if the version is earlier than 2.40a, the feature wasn't available.
> > > > > 
> > > > > alright, we can use this for something like:
> > > > > 
> > > > > WARN(rev < 2.40a && (flags & LPM_ERRATA || of_property_read_bool("lpm-errata")),
> > > > > 	"LPM Errata not available on dwc3 revisions <= 2.40a\n");
> > > > > 
> > > > > > So for Device-mode only controllers, I guess you will need a DT property
> > > > > > for this.
> > > > > 
> > > > > right, DT property and platform_data feature flag, or something. I don't
> > > > > wanna call it a quirk though, although it _is_ an erratum WRT LPM
> > > > > support. Dunno. Any strong feelings ?
> > > > 
> > > > Well, it's called LPM Errata because the feature was added to the USB
> > > > spec as an erratum. It's not an erratum to our controller. But I don't
> > > > have any strong feelings about how the driver support is implemented.
> > > 
> > > how about adding a "has_lpm_erratum" to struct dwc3 which gets
> > > initialized either through pdata or DT ? Then above WARN() would become:
> > > 
> > > WARN(dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum",
> > > 	"LPM Erratum not available on dwc3 revisisions < 2.40a\n");
> > > 
> > > Then we're not really calling it a quirk. In fact Huang, when respining
> > > your series, let's convert your quirk bits into single-bit fields inside
> > > struct dwc3 and struct platform_data. Like so:
> > > 
> > 
> > Looks like a good suggestion.
> > 
> > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> > > index 4d4e854..e233ce1 100644
> > > --- a/drivers/usb/dwc3/core.c
> > > +++ b/drivers/usb/dwc3/core.c
> > > @@ -695,11 +695,13 @@ static int dwc3_probe(struct platform_device *pdev)
> > >  
> > >  	if (node) {
> > >  		dwc->maximum_speed = of_usb_get_maximum_speed(node);
> > > +		dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum");
> > >  
> > >  		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
> > >  		dwc->dr_mode = of_usb_get_dr_mode(node);
> > >  	} else if (pdata) {
> > >  		dwc->maximum_speed = pdata->maximum_speed;
> > > +		dwc->has_lpm_erratum = pdata->has_lpm_erratum; >  
> > >  		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
> > >  		dwc->dr_mode = pdata->dr_mode;
> > > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> > > index 66f6256..23e1504 100644
> > > --- a/drivers/usb/dwc3/core.h
> > > +++ b/drivers/usb/dwc3/core.h
> > > @@ -661,6 +661,8 @@ struct dwc3_scratchpad_array {
> > >   * @ep0_bounced: true when we used bounce buffer
> > >   * @ep0_expect_in: true when we expect a DATA IN transfer
> > >   * @has_hibernation: true when dwc3 was configured with Hibernation
> > > + * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
> > > + *			there's now way for software to detect this in runtime.
> > >   * @is_selfpowered: true when we are selfpowered
> > >   * @needs_fifo_resize: not all users might want fifo resizing, flag it
> > >   * @pullups_connected: true when Run/Stop bit is set
> > > @@ -764,6 +766,7 @@ struct dwc3 {
> > >  	unsigned		ep0_bounced:1;
> > >  	unsigned		ep0_expect_in:1;
> > >  	unsigned		has_hibernation:1;
> > > +	unsigned		has_lpm_erratum:1;
> > >  	unsigned		is_selfpowered:1;
> > >  	unsigned		needs_fifo_resize:1;
> > >  	unsigned		pullups_connected:1;
> > > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > > index 68497b3..112352e 100644
> > > --- a/drivers/usb/dwc3/gadget.c
> > > +++ b/drivers/usb/dwc3/gadget.c
> > > @@ -1577,6 +1577,13 @@ static int dwc3_gadget_start(struct usb_gadget *g,
> > >  	}
> > >  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
> > >  
> > > +	if (dwc->has_lpm_erratum) {
> > > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > > +		/* REVISIT should this be configurable ? */
> > > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > > +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> > > +	}
> > > +
> > >  	dwc->start_config_issued = false;
> > >  
> > >  	/* Start with SuperSpeed Default */
> > > diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
> > > index 7db34f0..4bcec7c 100644
> > > --- a/drivers/usb/dwc3/platform_data.h
> > > +++ b/drivers/usb/dwc3/platform_data.h
> > > @@ -24,4 +24,6 @@ struct dwc3_platform_data {
> > >  	enum usb_device_speed maximum_speed;
> > >  	enum usb_dr_mode dr_mode;
> > >  	bool tx_fifo_resize;
> > > +
> > > +	unsigned has_lpm_erratum:1;
> > >  };
> > > 
> > > note that I have also moved DCTL access from gadget_init to
> > > gadget_start.
> > > 
> > 
> > Yes, I see. Will update it into V2.
> > 
> > A question, the dwc3 controller is the PCI-E device in my platform,
> > but the class code of PCI header is 0x0c0330, the same with xHC.
> > That's because it need to meet the windows enviroment. The dwc3
> > controller acted as only host mode to bind with windows xhci driver.
> > But on linux, sometimes, we auto-bind with xhci driver as well (class
> > code 0x0c0330) despite we use Pid/Vid on dwc3 driver. Then I need
> > rmmod xhci_hcd module and modprobe dwc3_pci module manually.
> > 
> > Any idea to resolve this issue?
> 
> that probably won't be the case on final Silicon. I reckon you're using
> Synopsys' HAPS for development, right ? That's just how Synopsys
> designed the PCIe wrapper to make it easy to test with xHCI. Please make
> sure to not use the same PCI header as xHCI on final silicon, otherwise
> SW engineers' lifes will become more difficult :-)

Unfortunately, this will go to the final solution for supporting
windows. As you known, windows doesn't support USB Device mode, so it
will act as "xHC" on windows os and PCI class code must set as
0x0c0330.

Can I add a blacklist into xhci or pci driver, to ignore the binding
behavoir on specific product id and vendor id.

> 
> Meanwhile, you can just blacklist xhci under /etc/modprobe.d/. Create a
> new file (say xhci-blacklist.conf) and add this to it:
> 
> blacklist xhci-hcd
> 
> Save and restart. xhci-hcd will never load by default anymore, but you
> can still manually load it.
> 

Yes, this is another workaround, but still do some action manually.

Thanks,
Rui

> Heikki, can you confirm if your DWC3 incarnations present this same
> "feature" ? :-)
> 
> -- 
> balbi


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Heikki Krogerus Sept. 29, 2014, 8:28 a.m. | #4
> > > A question, the dwc3 controller is the PCI-E device in my platform,
> > > but the class code of PCI header is 0x0c0330, the same with xHC.
> > > That's because it need to meet the windows enviroment. The dwc3
> > > controller acted as only host mode to bind with windows xhci driver.
> > > But on linux, sometimes, we auto-bind with xhci driver as well (class
> > > code 0x0c0330) despite we use Pid/Vid on dwc3 driver. Then I need
> > > rmmod xhci_hcd module and modprobe dwc3_pci module manually.
> > > 
> > > Any idea to resolve this issue?

Declare a fixup quirk. I'm not a pci expert, but I think something
like this should work..

static void dwc3_fix_amd_nl_class(struct pci_dev *pdev)
{
        pdev->class = 0x0c03fe;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL,
dwc3_fix_amd_nl_class);

> > Heikki, can you confirm if your DWC3 incarnations present this same
> > "feature" ? :-)

The DWC3 is not given xHCI class code on our boards.


Cheers,
Paul Zimmerman Sept. 29, 2014, 5:59 p.m. | #5
> From: Felipe Balbi [mailto:balbi@ti.com]
> Sent: Friday, September 26, 2014 9:31 PM
> 
> On Sat, Sep 27, 2014 at 01:05:46AM +0000, Paul Zimmerman wrote:
> >
> > Well, it's called LPM Errata because the feature was added to the USB
> > spec as an erratum. It's not an erratum to our controller. But I don't
> > have any strong feelings about how the driver support is implemented.
> 
> how about adding a "has_lpm_erratum" to struct dwc3 which gets
> initialized either through pdata or DT ? Then above WARN() would become:
> 
> WARN(dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum",
> 	"LPM Erratum not available on dwc3 revisisions < 2.40a\n");
> 
> Then we're not really calling it a quirk. In fact Huang, when respining
> your series, let's convert your quirk bits into single-bit fields inside
> struct dwc3 and struct platform_data. Like so:
> 
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 4d4e854..e233ce1 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -695,11 +695,13 @@ static int dwc3_probe(struct platform_device *pdev)
> 
>  	if (node) {
>  		dwc->maximum_speed = of_usb_get_maximum_speed(node);
> +		dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum");
> 
>  		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
>  		dwc->dr_mode = of_usb_get_dr_mode(node);
>  	} else if (pdata) {
>  		dwc->maximum_speed = pdata->maximum_speed;
> +		dwc->has_lpm_erratum = pdata->has_lpm_erratum;
> 
>  		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
>  		dwc->dr_mode = pdata->dr_mode;
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 66f6256..23e1504 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -661,6 +661,8 @@ struct dwc3_scratchpad_array {
>   * @ep0_bounced: true when we used bounce buffer
>   * @ep0_expect_in: true when we expect a DATA IN transfer
>   * @has_hibernation: true when dwc3 was configured with Hibernation
> + * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
> + *			there's now way for software to detect this in runtime.
>   * @is_selfpowered: true when we are selfpowered
>   * @needs_fifo_resize: not all users might want fifo resizing, flag it
>   * @pullups_connected: true when Run/Stop bit is set
> @@ -764,6 +766,7 @@ struct dwc3 {
>  	unsigned		ep0_bounced:1;
>  	unsigned		ep0_expect_in:1;
>  	unsigned		has_hibernation:1;
> +	unsigned		has_lpm_erratum:1;
>  	unsigned		is_selfpowered:1;
>  	unsigned		needs_fifo_resize:1;
>  	unsigned		pullups_connected:1;
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index 68497b3..112352e 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -1577,6 +1577,13 @@ static int dwc3_gadget_start(struct usb_gadget *g,
>  	}
>  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
> 
> +	if (dwc->has_lpm_erratum) {
> +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> +		/* REVISIT should this be configurable ? */
> +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> +	}

Yes, I think this really wants to be configurable. The value used is
supposed to depend on the latencies in the system etc.
Felipe Balbi Sept. 29, 2014, 6:59 p.m. | #6
Hi,

On Mon, Sep 29, 2014 at 05:59:42PM +0000, Paul Zimmerman wrote:
> > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > index 68497b3..112352e 100644
> > --- a/drivers/usb/dwc3/gadget.c
> > +++ b/drivers/usb/dwc3/gadget.c
> > @@ -1577,6 +1577,13 @@ static int dwc3_gadget_start(struct usb_gadget *g,
> >  	}
> >  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
> > 
> > +	if (dwc->has_lpm_erratum) {
> > +		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
> > +		/* REVISIT should this be configurable ? */
> > +		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
> > +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> > +	}
> 
> Yes, I think this really wants to be configurable. The value used is
> supposed to depend on the latencies in the system etc.

alright, in that case we need to pass that through DT/pdata as well.
Huang Rui Oct. 9, 2014, 3:51 a.m. | #7
On Mon, Sep 29, 2014 at 11:28:57AM +0300, Heikki Krogerus wrote:
> > > > A question, the dwc3 controller is the PCI-E device in my platform,
> > > > but the class code of PCI header is 0x0c0330, the same with xHC.
> > > > That's because it need to meet the windows enviroment. The dwc3
> > > > controller acted as only host mode to bind with windows xhci driver.
> > > > But on linux, sometimes, we auto-bind with xhci driver as well (class
> > > > code 0x0c0330) despite we use Pid/Vid on dwc3 driver. Then I need
> > > > rmmod xhci_hcd module and modprobe dwc3_pci module manually.
> > > > 
> > > > Any idea to resolve this issue?
> 
> Declare a fixup quirk. I'm not a pci expert, but I think something
> like this should work..
> 
> static void dwc3_fix_amd_nl_class(struct pci_dev *pdev)
> {
>         pdev->class = 0x0c03fe;
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL,
> dwc3_fix_amd_nl_class);
> 

Heikki, your info inspires me. :)

I looked at pci driver, this update should put in pci/quirks.c.
Because the behavior of the global pci_fixups_header array is
maintained at that file.
When system inits, pci driver would load fixup devices before driver
attached. So it should define the fixup header under pci/quirks.c.

After do some tests in my side. This quirk works well.

Thanks,
Rui
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 4d4e854..e233ce1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -695,11 +695,13 @@  static int dwc3_probe(struct platform_device *pdev)
 
 	if (node) {
 		dwc->maximum_speed = of_usb_get_maximum_speed(node);
+		dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum");
 
 		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
 		dwc->dr_mode = of_usb_get_dr_mode(node);
 	} else if (pdata) {
 		dwc->maximum_speed = pdata->maximum_speed;
+		dwc->has_lpm_erratum = pdata->has_lpm_erratum;
 
 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
 		dwc->dr_mode = pdata->dr_mode;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 66f6256..23e1504 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -661,6 +661,8 @@  struct dwc3_scratchpad_array {
  * @ep0_bounced: true when we used bounce buffer
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @has_hibernation: true when dwc3 was configured with Hibernation
+ * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
+ *			there's now way for software to detect this in runtime.
  * @is_selfpowered: true when we are selfpowered
  * @needs_fifo_resize: not all users might want fifo resizing, flag it
  * @pullups_connected: true when Run/Stop bit is set
@@ -764,6 +766,7 @@  struct dwc3 {
 	unsigned		ep0_bounced:1;
 	unsigned		ep0_expect_in:1;
 	unsigned		has_hibernation:1;
+	unsigned		has_lpm_erratum:1;
 	unsigned		is_selfpowered:1;
 	unsigned		needs_fifo_resize:1;
 	unsigned		pullups_connected:1;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 68497b3..112352e 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1577,6 +1577,13 @@  static int dwc3_gadget_start(struct usb_gadget *g,
 	}
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
+	if (dwc->has_lpm_erratum) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		/* REVISIT should this be configurable ? */
+		reg |= DWC3_DCTL_LPM_ERRATA(0xf);
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
+
 	dwc->start_config_issued = false;
 
 	/* Start with SuperSpeed Default */
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index 7db34f0..4bcec7c 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -24,4 +24,6 @@  struct dwc3_platform_data {
 	enum usb_device_speed maximum_speed;
 	enum usb_dr_mode dr_mode;
 	bool tx_fifo_resize;
+
+	unsigned has_lpm_erratum:1;
 };