mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-04 16:15:11 +00:00
usb: xhci-mtk: fix a short packet issue of gen1 isoc-in transfer
For Gen1 isoc-in transfer, host still send out unexpected ACK after device
finish the burst with a short packet, this will cause an exception on the
connected device, such as, a usb 4k camera.
It can be fixed by setting rxfifo depth less than 4k bytes, prefer to use
3k here, the side-effect is that may cause performance drop about 10%,
including bulk transfer.
Fixes: 926d60ae64
("usb: xhci-mtk: modify the SOF/ITP interval for mt8195")
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/20240104061640.7335-2-chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
223b4ef5a3
commit
017dbfc05c
2 changed files with 40 additions and 2 deletions
|
@ -7,6 +7,7 @@
|
||||||
* Chunfeng Yun <chunfeng.yun@mediatek.com>
|
* Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -73,6 +74,9 @@
|
||||||
#define FRMCNT_LEV1_RANG (0x12b << 8)
|
#define FRMCNT_LEV1_RANG (0x12b << 8)
|
||||||
#define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8)
|
#define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8)
|
||||||
|
|
||||||
|
#define HSCH_CFG1 0x960
|
||||||
|
#define SCH3_RXFIFO_DEPTH_MASK GENMASK(21, 20)
|
||||||
|
|
||||||
#define SS_GEN2_EOF_CFG 0x990
|
#define SS_GEN2_EOF_CFG 0x990
|
||||||
#define SSG2EOF_OFFSET 0x3c
|
#define SSG2EOF_OFFSET 0x3c
|
||||||
|
|
||||||
|
@ -114,6 +118,8 @@
|
||||||
#define SSC_IP_SLEEP_EN BIT(4)
|
#define SSC_IP_SLEEP_EN BIT(4)
|
||||||
#define SSC_SPM_INT_EN BIT(1)
|
#define SSC_SPM_INT_EN BIT(1)
|
||||||
|
|
||||||
|
#define SCH_FIFO_TO_KB(x) ((x) >> 10)
|
||||||
|
|
||||||
enum ssusb_uwk_vers {
|
enum ssusb_uwk_vers {
|
||||||
SSUSB_UWK_V1 = 1,
|
SSUSB_UWK_V1 = 1,
|
||||||
SSUSB_UWK_V2,
|
SSUSB_UWK_V2,
|
||||||
|
@ -165,6 +171,35 @@ static void xhci_mtk_set_frame_interval(struct xhci_hcd_mtk *mtk)
|
||||||
writel(value, hcd->regs + SS_GEN2_EOF_CFG);
|
writel(value, hcd->regs + SS_GEN2_EOF_CFG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* workaround: usb3.2 gen1 isoc rx hw issue
|
||||||
|
* host send out unexpected ACK afer device fininsh a burst transfer with
|
||||||
|
* a short packet.
|
||||||
|
*/
|
||||||
|
static void xhci_mtk_rxfifo_depth_set(struct xhci_hcd_mtk *mtk)
|
||||||
|
{
|
||||||
|
struct usb_hcd *hcd = mtk->hcd;
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
if (!mtk->rxfifo_depth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
value = readl(hcd->regs + HSCH_CFG1);
|
||||||
|
value &= ~SCH3_RXFIFO_DEPTH_MASK;
|
||||||
|
value |= FIELD_PREP(SCH3_RXFIFO_DEPTH_MASK,
|
||||||
|
SCH_FIFO_TO_KB(mtk->rxfifo_depth) - 1);
|
||||||
|
writel(value, hcd->regs + HSCH_CFG1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xhci_mtk_init_quirk(struct xhci_hcd_mtk *mtk)
|
||||||
|
{
|
||||||
|
/* workaround only for mt8195 */
|
||||||
|
xhci_mtk_set_frame_interval(mtk);
|
||||||
|
|
||||||
|
/* workaround for SoCs using SSUSB about before IPM v1.6.0 */
|
||||||
|
xhci_mtk_rxfifo_depth_set(mtk);
|
||||||
|
}
|
||||||
|
|
||||||
static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
|
static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
|
||||||
{
|
{
|
||||||
struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
|
struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
|
||||||
|
@ -448,8 +483,7 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* workaround only for mt8195 */
|
xhci_mtk_init_quirk(mtk);
|
||||||
xhci_mtk_set_frame_interval(mtk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = xhci_gen_setup(hcd, xhci_mtk_quirks);
|
ret = xhci_gen_setup(hcd, xhci_mtk_quirks);
|
||||||
|
@ -527,6 +561,8 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
||||||
of_property_read_u32(node, "mediatek,u2p-dis-msk",
|
of_property_read_u32(node, "mediatek,u2p-dis-msk",
|
||||||
&mtk->u2p_dis_msk);
|
&mtk->u2p_dis_msk);
|
||||||
|
|
||||||
|
of_property_read_u32(node, "rx-fifo-depth", &mtk->rxfifo_depth);
|
||||||
|
|
||||||
ret = usb_wakeup_of_property_parse(mtk, node);
|
ret = usb_wakeup_of_property_parse(mtk, node);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to parse uwk property\n");
|
dev_err(dev, "failed to parse uwk property\n");
|
||||||
|
|
|
@ -171,6 +171,8 @@ struct xhci_hcd_mtk {
|
||||||
struct regmap *uwk;
|
struct regmap *uwk;
|
||||||
u32 uwk_reg_base;
|
u32 uwk_reg_base;
|
||||||
u32 uwk_vers;
|
u32 uwk_vers;
|
||||||
|
/* quirk */
|
||||||
|
u32 rxfifo_depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
|
static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
|
||||||
|
|
Loading…
Reference in a new issue