|
7 | 7 | * Chunfeng Yun <[email protected]>
|
8 | 8 | */
|
9 | 9 |
|
| 10 | +#include <linux/bitfield.h> |
10 | 11 | #include <linux/dma-mapping.h>
|
11 | 12 | #include <linux/iopoll.h>
|
12 | 13 | #include <linux/kernel.h>
|
|
73 | 74 | #define FRMCNT_LEV1_RANG (0x12b << 8)
|
74 | 75 | #define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8)
|
75 | 76 |
|
| 77 | +#define HSCH_CFG1 0x960 |
| 78 | +#define SCH3_RXFIFO_DEPTH_MASK GENMASK(21, 20) |
| 79 | + |
76 | 80 | #define SS_GEN2_EOF_CFG 0x990
|
77 | 81 | #define SSG2EOF_OFFSET 0x3c
|
78 | 82 |
|
|
114 | 118 | #define SSC_IP_SLEEP_EN BIT(4)
|
115 | 119 | #define SSC_SPM_INT_EN BIT(1)
|
116 | 120 |
|
| 121 | +#define SCH_FIFO_TO_KB(x) ((x) >> 10) |
| 122 | + |
117 | 123 | enum ssusb_uwk_vers {
|
118 | 124 | SSUSB_UWK_V1 = 1,
|
119 | 125 | SSUSB_UWK_V2,
|
@@ -165,6 +171,35 @@ static void xhci_mtk_set_frame_interval(struct xhci_hcd_mtk *mtk)
|
165 | 171 | writel(value, hcd->regs + SS_GEN2_EOF_CFG);
|
166 | 172 | }
|
167 | 173 |
|
| 174 | +/* |
| 175 | + * workaround: usb3.2 gen1 isoc rx hw issue |
| 176 | + * host send out unexpected ACK afer device fininsh a burst transfer with |
| 177 | + * a short packet. |
| 178 | + */ |
| 179 | +static void xhci_mtk_rxfifo_depth_set(struct xhci_hcd_mtk *mtk) |
| 180 | +{ |
| 181 | + struct usb_hcd *hcd = mtk->hcd; |
| 182 | + u32 value; |
| 183 | + |
| 184 | + if (!mtk->rxfifo_depth) |
| 185 | + return; |
| 186 | + |
| 187 | + value = readl(hcd->regs + HSCH_CFG1); |
| 188 | + value &= ~SCH3_RXFIFO_DEPTH_MASK; |
| 189 | + value |= FIELD_PREP(SCH3_RXFIFO_DEPTH_MASK, |
| 190 | + SCH_FIFO_TO_KB(mtk->rxfifo_depth) - 1); |
| 191 | + writel(value, hcd->regs + HSCH_CFG1); |
| 192 | +} |
| 193 | + |
| 194 | +static void xhci_mtk_init_quirk(struct xhci_hcd_mtk *mtk) |
| 195 | +{ |
| 196 | + /* workaround only for mt8195 */ |
| 197 | + xhci_mtk_set_frame_interval(mtk); |
| 198 | + |
| 199 | + /* workaround for SoCs using SSUSB about before IPM v1.6.0 */ |
| 200 | + xhci_mtk_rxfifo_depth_set(mtk); |
| 201 | +} |
| 202 | + |
168 | 203 | static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
|
169 | 204 | {
|
170 | 205 | struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
|
@@ -448,8 +483,7 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
|
448 | 483 | if (ret)
|
449 | 484 | return ret;
|
450 | 485 |
|
451 |
| - /* workaround only for mt8195 */ |
452 |
| - xhci_mtk_set_frame_interval(mtk); |
| 486 | + xhci_mtk_init_quirk(mtk); |
453 | 487 | }
|
454 | 488 |
|
455 | 489 | ret = xhci_gen_setup(hcd, xhci_mtk_quirks);
|
@@ -527,6 +561,8 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
527 | 561 | of_property_read_u32(node, "mediatek,u2p-dis-msk",
|
528 | 562 | &mtk->u2p_dis_msk);
|
529 | 563 |
|
| 564 | + of_property_read_u32(node, "rx-fifo-depth", &mtk->rxfifo_depth); |
| 565 | + |
530 | 566 | ret = usb_wakeup_of_property_parse(mtk, node);
|
531 | 567 | if (ret) {
|
532 | 568 | dev_err(dev, "failed to parse uwk property\n");
|
|
0 commit comments