]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
phy: zynqmp: keep SERDES scrambler and 8b/10b enabled for USB
authorNava kishore Manne <nava.kishore.manne@amd.com>
Sat, 27 Jun 2026 15:52:29 +0000 (21:22 +0530)
committerVinod Koul <vkoul@kernel.org>
Wed, 22 Jul 2026 15:22:59 +0000 (20:52 +0530)
USB Gen1 requires scrambling and 8b/10b encoding to be performed in the
physical layer. Do not bypass PHY-side scrambler or encoder/decoder for
USB operation, as mandated by the USB 3.x specification.

Scrambler and 8b/10b bypass remain restricted to SATA and SGMII
modes, where encoding is handled in the controller.

Fixes: 4a33bea00314 ("phy: zynqmp: Add PHY driver for the Xilinx ZynqMP Gigabit Transceiver")
Cc: stable@vger.kernel.org
Signed-off-by: Nava kishore Manne <nava.kishore.manne@amd.com>
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Acked-by: Michal Simek <michal.simek@amd.com>
Link: https://patch.msgid.link/20260627155229.2791113-4-radhey.shyam.pandey@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/xilinx/phy-zynqmp.c

index 0e99b2cc2a2db7a015826f5dee33419737275d81..240626b5547505b49c93f45b8f1f36f245b00481 100644 (file)
@@ -502,15 +502,30 @@ static void xpsgtr_lane_set_protocol(struct xpsgtr_phy *gtr_phy)
        }
 }
 
-/* Bypass (de)scrambler and 8b/10b decoder and encoder. */
-static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy)
+/**
+ * xpsgtr_bypass_scrambler_8b10b - Configure scrambler/encoder behavior
+ * @gtr_phy: pointer to lane context
+ * @bypass: true to enable scrambler/encoder bypass (SATA/SGMII),
+ *          false to disable scrambler/encoder bypass (USB3)
+ *
+ * Uses RMW to preserve reserved and unrelated register fields.
+ */
+static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy,
+                                         bool bypass)
 {
-       xpsgtr_clr_set_phy(gtr_phy, L0_TM_DIG_6,
-                          L0_TM_DIS_DESCRAMBLE_DECODER,
-                          L0_TM_DIS_DESCRAMBLE_DECODER);
-       xpsgtr_clr_set_phy(gtr_phy, L0_TX_DIG_61,
-                          L0_TM_DISABLE_SCRAMBLE_ENCODER,
-                          L0_TM_DISABLE_SCRAMBLE_ENCODER);
+       if (bypass) {
+               xpsgtr_clr_set_phy(gtr_phy, L0_TM_DIG_6,
+                                  L0_TM_DIS_DESCRAMBLE_DECODER,
+                                  L0_TM_DIS_DESCRAMBLE_DECODER);
+               xpsgtr_clr_set_phy(gtr_phy, L0_TX_DIG_61,
+                                  L0_TM_DISABLE_SCRAMBLE_ENCODER,
+                                  L0_TM_DISABLE_SCRAMBLE_ENCODER);
+       } else {
+               xpsgtr_clr_set_phy(gtr_phy, L0_TM_DIG_6,
+                                  L0_TM_DIS_DESCRAMBLE_DECODER, 0);
+               xpsgtr_clr_set_phy(gtr_phy, L0_TX_DIG_61,
+                                  L0_TM_DISABLE_SCRAMBLE_ENCODER, 0);
+       }
 }
 
 /* DP-specific initialization. */
@@ -531,7 +546,7 @@ static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
 {
        struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
 
-       xpsgtr_bypass_scrambler_8b10b(gtr_phy);
+       xpsgtr_bypass_scrambler_8b10b(gtr_phy, true);
 
        writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
 }
@@ -547,7 +562,7 @@ static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
        xpsgtr_clr_set(gtr_dev, TX_PROT_BUS_WIDTH, mask, val);
        xpsgtr_clr_set(gtr_dev, RX_PROT_BUS_WIDTH, mask, val);
 
-       xpsgtr_bypass_scrambler_8b10b(gtr_phy);
+       xpsgtr_bypass_scrambler_8b10b(gtr_phy, true);
 }
 
 /* Configure TX de-emphasis and margining for DP. */
@@ -708,6 +723,10 @@ static int xpsgtr_phy_init(struct phy *phy)
        case ICM_PROTOCOL_SGMII:
                xpsgtr_phy_init_sgmii(gtr_phy);
                break;
+
+       case ICM_PROTOCOL_USB:
+               xpsgtr_bypass_scrambler_8b10b(gtr_phy, false);
+               break;
        }
 
        goto out;