Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: chipidea: add workaround for chipidea PEC bug

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>
Link: https://lore.kernel.org/r/20230809024432.535160-2-xu.yang_2@nxp.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Xu Yang and committed by
Greg Kroah-Hartman
12e6ac69 dda4b60e

+8 -1
+1
drivers/usb/chipidea/ci.h
··· 257 257 bool id_event; 258 258 bool b_sess_valid_event; 259 259 bool imx28_write_fix; 260 + bool has_portsc_pec_bug; 260 261 bool supports_runtime_pm; 261 262 bool in_lpm; 262 263 bool wakeup_int;
+3 -1
drivers/usb/chipidea/ci_hdrc_imx.c
··· 68 68 69 69 static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = { 70 70 .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 71 + CI_HDRC_HAS_PORTSC_PEC_MISSED | 71 72 CI_HDRC_PMQOS, 72 73 }; 73 74 74 75 static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { 75 - .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, 76 + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 77 + CI_HDRC_HAS_PORTSC_PEC_MISSED, 76 78 }; 77 79 78 80 static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
+2
drivers/usb/chipidea/core.c
··· 1044 1044 CI_HDRC_IMX28_WRITE_FIX); 1045 1045 ci->supports_runtime_pm = !!(ci->platdata->flags & 1046 1046 CI_HDRC_SUPPORTS_RUNTIME_PM); 1047 + ci->has_portsc_pec_bug = !!(ci->platdata->flags & 1048 + CI_HDRC_HAS_PORTSC_PEC_MISSED); 1047 1049 platform_set_drvdata(pdev, ci); 1048 1050 1049 1051 ret = hw_device_init(ci, base);
+1
drivers/usb/chipidea/host.c
··· 151 151 ehci->has_hostpc = ci->hw_bank.lpm; 152 152 ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; 153 153 ehci->imx28_write_fix = ci->imx28_write_fix; 154 + ehci->has_ci_pec_bug = ci->has_portsc_pec_bug; 154 155 155 156 priv = (struct ehci_ci_priv *)ehci->priv; 156 157 priv->reg_vbus = NULL;
+1
include/linux/usb/chipidea.h
··· 63 63 #define CI_HDRC_IMX_IS_HSIC BIT(14) 64 64 #define CI_HDRC_PMQOS BIT(15) 65 65 #define CI_HDRC_PHY_VBUS_CONTROL BIT(16) 66 + #define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17) 66 67 enum usb_dr_mode dr_mode; 67 68 #define CI_HDRC_CONTROLLER_RESET_EVENT 0 68 69 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1