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,