Message ID | 20230809024432.535160-2-xu.yang_2@nxp.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 12e6ac69cc7e7d3367599ae26a92a0f9a18bc728 |
Headers | show |
Series | [v2,1/2] usb: ehci: add workaround for chipidea PORTSC.PEC bug | expand |
On Wed, Aug 9, 2023 at 10:40 AM Xu Yang <xu.yang_2@nxp.com> wrote: > > Some NXP processors using ChipIdea USB IP have a bug when frame babble is > detected. > > Issue description: > In USB camera test, our controller is host in HS mode. In ISOC IN, when > device sends data across the micro frame, it causes the babble in host > controller. This will clear the PE bit. In spec, it also requires to set > the PEC bit and then set the PCI bit. Without the PCI interrupt, the > software does not know the PE is cleared. > > This will add a flag CI_HDRC_HAS_PORTSC_PEC_MISSED to some impacted > platform datas. And the ehci host driver will assert PEC by SW when > specific conditions are satisfied. > > Signed-off-by: Xu Yang <xu.yang_2@nxp.com> > Acked-by: Peter Chen <peter.chen@kernel.org> Peter > --- > Changes in v2: > - no change > --- > drivers/usb/chipidea/ci.h | 1 + > drivers/usb/chipidea/ci_hdrc_imx.c | 4 +++- > drivers/usb/chipidea/core.c | 2 ++ > drivers/usb/chipidea/host.c | 1 + > include/linux/usb/chipidea.h | 1 + > 5 files changed, 8 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h > index d262b9df7b3d..d9bb3d3f026e 100644 > --- a/drivers/usb/chipidea/ci.h > +++ b/drivers/usb/chipidea/ci.h > @@ -257,6 +257,7 @@ struct ci_hdrc { > bool id_event; > bool b_sess_valid_event; > bool imx28_write_fix; > + bool has_portsc_pec_bug; > bool supports_runtime_pm; > bool in_lpm; > bool wakeup_int; > diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c > index 772bbdade994..e28bb2f2612d 100644 > --- a/drivers/usb/chipidea/ci_hdrc_imx.c > +++ b/drivers/usb/chipidea/ci_hdrc_imx.c > @@ -68,11 +68,13 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = { > > static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = { > .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | > + CI_HDRC_HAS_PORTSC_PEC_MISSED | > CI_HDRC_PMQOS, > }; > > static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { > - .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, > + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | > + CI_HDRC_HAS_PORTSC_PEC_MISSED, > }; > > static const struct of_device_id ci_hdrc_imx_dt_ids[] = { > diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c > index 6e1196b53253..7ac39a281b8c 100644 > --- a/drivers/usb/chipidea/core.c > +++ b/drivers/usb/chipidea/core.c > @@ -1044,6 +1044,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) > CI_HDRC_IMX28_WRITE_FIX); > ci->supports_runtime_pm = !!(ci->platdata->flags & > CI_HDRC_SUPPORTS_RUNTIME_PM); > + ci->has_portsc_pec_bug = !!(ci->platdata->flags & > + CI_HDRC_HAS_PORTSC_PEC_MISSED); > platform_set_drvdata(pdev, ci); > > ret = hw_device_init(ci, base); > diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c > index ebe7400243b1..08af26b762a2 100644 > --- a/drivers/usb/chipidea/host.c > +++ b/drivers/usb/chipidea/host.c > @@ -151,6 +151,7 @@ static int host_start(struct ci_hdrc *ci) > ehci->has_hostpc = ci->hw_bank.lpm; > ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; > ehci->imx28_write_fix = ci->imx28_write_fix; > + ehci->has_ci_pec_bug = ci->has_portsc_pec_bug; > > priv = (struct ehci_ci_priv *)ehci->priv; > priv->reg_vbus = NULL; > diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h > index ee38835ed77c..0b4f2d5faa08 100644 > --- a/include/linux/usb/chipidea.h > +++ b/include/linux/usb/chipidea.h > @@ -63,6 +63,7 @@ struct ci_hdrc_platform_data { > #define CI_HDRC_IMX_IS_HSIC BIT(14) > #define CI_HDRC_PMQOS BIT(15) > #define CI_HDRC_PHY_VBUS_CONTROL BIT(16) > +#define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17) > enum usb_dr_mode dr_mode; > #define CI_HDRC_CONTROLLER_RESET_EVENT 0 > #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 > -- > 2.34.1 >
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index d262b9df7b3d..d9bb3d3f026e 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -257,6 +257,7 @@ struct ci_hdrc { bool id_event; bool b_sess_valid_event; bool imx28_write_fix; + bool has_portsc_pec_bug; bool supports_runtime_pm; bool in_lpm; bool wakeup_int; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 772bbdade994..e28bb2f2612d 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -68,11 +68,13 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = { static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = { .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | + CI_HDRC_HAS_PORTSC_PEC_MISSED | CI_HDRC_PMQOS, }; static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { - .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | + CI_HDRC_HAS_PORTSC_PEC_MISSED, }; static const struct of_device_id ci_hdrc_imx_dt_ids[] = { diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 6e1196b53253..7ac39a281b8c 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -1044,6 +1044,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) CI_HDRC_IMX28_WRITE_FIX); ci->supports_runtime_pm = !!(ci->platdata->flags & CI_HDRC_SUPPORTS_RUNTIME_PM); + ci->has_portsc_pec_bug = !!(ci->platdata->flags & + CI_HDRC_HAS_PORTSC_PEC_MISSED); platform_set_drvdata(pdev, ci); ret = hw_device_init(ci, base); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index ebe7400243b1..08af26b762a2 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -151,6 +151,7 @@ static int host_start(struct ci_hdrc *ci) ehci->has_hostpc = ci->hw_bank.lpm; ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; ehci->imx28_write_fix = ci->imx28_write_fix; + ehci->has_ci_pec_bug = ci->has_portsc_pec_bug; priv = (struct ehci_ci_priv *)ehci->priv; priv->reg_vbus = NULL; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ee38835ed77c..0b4f2d5faa08 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -63,6 +63,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_IMX_IS_HSIC BIT(14) #define CI_HDRC_PMQOS BIT(15) #define CI_HDRC_PHY_VBUS_CONTROL BIT(16) +#define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1
Some NXP processors using ChipIdea USB IP have a bug when frame babble is detected. Issue description: In USB camera test, our controller is host in HS mode. In ISOC IN, when device sends data across the micro frame, it causes the babble in host controller. This will clear the PE bit. In spec, it also requires to set the PEC bit and then set the PCI bit. Without the PCI interrupt, the software does not know the PE is cleared. This will add a flag CI_HDRC_HAS_PORTSC_PEC_MISSED to some impacted platform datas. And the ehci host driver will assert PEC by SW when specific conditions are satisfied. Signed-off-by: Xu Yang <xu.yang_2@nxp.com> --- Changes in v2: - no change --- drivers/usb/chipidea/ci.h | 1 + drivers/usb/chipidea/ci_hdrc_imx.c | 4 +++- drivers/usb/chipidea/core.c | 2 ++ drivers/usb/chipidea/host.c | 1 + include/linux/usb/chipidea.h | 1 + 5 files changed, 8 insertions(+), 1 deletion(-)