From 3037c2f6a9de3af9775427059546e705237f6723 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Fri, 4 Sep 2026 06:03:00 +0000 Subject: [PATCH] net: dsa: microchip: enable the SGMII port of the KSZ9897S The KSZ9897 has an SGMII/1000BASE-X capable port 7, but its chip_info entry never set .sgmii_port. ksz_has_sgmii_port() is therefore false, ksz9477_pcs_create() is never called and ksz9477_phylink_mac_select_pcs() returns NULL for port 7, so a phy-mode = "sgmii" or "1000base-x" link on that port cannot come up. Only the KSZ9897S has that port; the KSZ9897R has a second RGMII port instead. Both report chip ID 0x00989700, so the port cannot be enabled from the chip ID alone, and enabling it unconditionally breaks the KSZ9897R badly: ksz9477_setup() propagates the failure of xpcs_create_pcs_mdiodev() on a part without an XPCS, so the switch as a whole stops probing. The variants do differ in the read-only bit 7 of the port 7 XMII control 0 register, which reads one on the KSZ9897S and zero on the KSZ9897R. Compare the KSZ9897S data sheet DS00002394C section 5.2.4.1 with the KSZ9897R data sheet DS00002330D section 5.2.3.1. Read that bit in ksz_switch_register() and use it to select a KSZ9897S chip_data entry, which is the KSZ9897 one plus .sgmii_port = 7, with port 7 no longer marked as supporting MII, RMII and RGMII. On the KSZ9897S that port is permanently an SGMII port and only its differential pairs are brought out, so advertising the xMII modes on it would let phylink accept a mode the driver never programs: ksz_phylink_need_config() skips the XMII control registers for the SGMII port. The KSZ9477, which also has SGMII on port 7, is described the same way. See DS00002394C section 4.11. KSZ9897S_CHIP_ID selects that chip_data entry and nothing else. dev->chip_id keeps the KSZ9897 chip ID that both parts report, so no other chip ID comparison has to know about the variant, ksz_check_device_id() is unchanged, and a device tree naming the KSZ9897 keeps matching whichever part is fitted. No binding change is needed and existing device trees keep working. Tested on a KSZ9897S with a 1000BASE-LX fibre SFP on port 7: bit 7 of the port 7 XMII control 0 register reads one, the switch is identified as a KSZ9897S and the PCS is created. The port advertises 1000baseX/Full, clause 37 in-band autonegotiation completes against the link partner, and the link comes up at 1Gbps/full duplex and passes traffic. Suggested-by: Nicolai Buchwitz Suggested-by: Jerry Ray Suggested-by: Tristram Ha Signed-off-by: Tapio Reijonen Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20260904-ksz9897-sgmii-port-v5-1-9bd4a0381aa8@vaisala.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 61 ++++++++++++++++++++- drivers/net/dsa/microchip/ksz_common.h | 5 ++ include/linux/platform_data/microchip-ksz.h | 1 + 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 1a9d6f83a023..81798a9fa671 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1486,6 +1486,41 @@ const struct ksz_chip_data ksz_switch_chips[] = { .gbit_capable = {true, true, true, true, true, true, true}, }, + [KSZ9897S] = { + .chip_id = KSZ9897S_CHIP_ID, + .dev_name = "KSZ9897S", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x7F, /* can be configured as cpu port */ + .port_cnt = 7, /* total physical port count */ + .port_nirqs = 2, + .num_tx_queues = 4, + .num_ipms = 8, + .ops = &ksz9477_dev_ops, + .switch_ops = &ksz9477_switch_ops, + .phylink_mac_ops = &ksz9477_phylink_mac_ops, + .phy_errata_9477 = true, + .mib_names = ksz9477_mib_names, + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), + .reg_mib_cnt = MIB_COUNTER_NUM, + .regs = ksz9477_regs, + .masks = ksz9477_masks, + .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, + .supports_mii = {false, false, false, false, + false, true, false}, + .supports_rmii = {false, false, false, false, + false, true, false}, + .supports_rgmii = {false, false, false, false, + false, true, false}, + .internal_phy = {true, true, true, true, + true, false, false}, + .gbit_capable = {true, true, true, true, true, true, true}, + .sgmii_port = 7, + }, + [KSZ9893] = { .chip_id = KSZ9893_CHIP_ID, .dev_name = "KSZ9893", @@ -3897,6 +3932,7 @@ int ksz_switch_register(struct ksz_device *dev) struct device_node *ports; phy_interface_t interface; unsigned int port_num; + u32 lookup_chip_id; int ret; int i; @@ -3933,7 +3969,30 @@ int ksz_switch_register(struct ksz_device *dev) if (ret) return ret; - info = ksz_lookup_info(dev->chip_id); + lookup_chip_id = dev->chip_id; + + /* The KSZ9897S and the KSZ9897R report the same chip ID and differ + * only in chip_data: only the S has the SGMII port 7, the R has a + * second RGMII port instead. Bit 7 of the port 7 XMII control 0 + * register is read-only and tells them apart; it reads one on the S. + * Compare the KSZ9897S data sheet DS00002394C section 5.2.4.1 with + * the KSZ9897R data sheet DS00002330D section 5.2.3.1. + * + * Only the chip_data entry differs, so dev->chip_id keeps the shared + * chip ID and nothing else has to know about the variant. + */ + if (dev->chip_id == KSZ9897_CHIP_ID) { + u8 val; + + ret = ksz_read8(dev, KSZ9897_REG_PORT7_XMII_CTRL_0, &val); + if (ret) + return ret; + + if (val & KSZ9897_PORT7_SGMII_SEL) + lookup_chip_id = KSZ9897S_CHIP_ID; + } + + info = ksz_lookup_info(lookup_chip_id); if (!info) return -ENODEV; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index cbe98494578c..0cff33df06a4 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -284,6 +284,7 @@ enum ksz_model { KSZ9477, KSZ9896, KSZ9897, + KSZ9897S, KSZ9893, KSZ9563, KSZ9567, @@ -874,6 +875,10 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port) #define SKU_ID_KSZ8563 0x3c #define SKU_ID_KSZ9563 0x1c +/* KSZ9897 specific register: port 7 XMII control 0 */ +#define KSZ9897_REG_PORT7_XMII_CTRL_0 0x7300 +#define KSZ9897_PORT7_SGMII_SEL BIT(7) + /* Driver set switch broadcast storm protection at 10% rate. */ #define BROADCAST_STORM_PROT_RATE 10 diff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h index 028781ad4059..fe8df1774289 100644 --- a/include/linux/platform_data/microchip-ksz.h +++ b/include/linux/platform_data/microchip-ksz.h @@ -34,6 +34,7 @@ enum ksz_chip_id { KSZ9477_CHIP_ID = 0x00947700, KSZ9896_CHIP_ID = 0x00989600, KSZ9897_CHIP_ID = 0x00989700, + KSZ9897S_CHIP_ID = 0x00989701, KSZ9893_CHIP_ID = 0x00989300, KSZ9563_CHIP_ID = 0x00956300, KSZ8567_CHIP_ID = 0x00856700,