From ac68902259dcb908cf7bc5935c256c34c4eab4db Mon Sep 17 00:00:00 2001 From: Heinrich Toews Date: Thu, 27 Nov 2025 16:06:06 +0100 Subject: [PATCH] net: dsa: microchip: ksz_common: add single led mode support for ksz9477 Signed-off-by: Heinrich Toews --- drivers/net/dsa/microchip/ksz_common.c | 41 ++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_common.h | 4 +++ 2 files changed, 45 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 7d382ec38356..2d0a8d9e4cc1 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -447,6 +447,9 @@ static const u16 ksz9477_regs[] = { [S_MULTICAST_CTRL] = 0x0331, [P_XMII_CTRL_0] = 0x0300, [P_XMII_CTRL_1] = 0x0301, + [P_PHY_MMD_SETUP] = 0x011A, + [P_PHY_MMD_DATA] = 0x011C, + [P_PHY_DIGITAL_DEBUG_3] = 0x013C, }; static const u32 ksz9477_masks[] = { @@ -2955,6 +2958,39 @@ static void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit) ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8); } +static void ksz_enable_single_led_mode(struct ksz_device *dev, int port) +{ + const u16 *regs = dev->info->regs; + u16 data16; + + dev_info(dev->dev, "port-%d: enable single-led mode.\n", port); + + /* Set up register address for MMD */ + data16 = 0x0002; + ksz_pwrite16(dev, port, regs[P_PHY_MMD_SETUP], data16); + + /* Select Register 00h of MMD */ + data16 = 0x0000; + ksz_pwrite16(dev, port, regs[P_PHY_MMD_DATA], data16); + + /* Select register data for MMD */ + data16 = 0x4002; + ksz_pwrite16(dev, port, regs[P_PHY_MMD_SETUP], data16); + + /* Write value 0010h to MMD */ + data16 = 0x0011; + ksz_pwrite16(dev, port, regs[P_PHY_MMD_DATA], data16); + + /* Due to Errata Module 19 this workaround is needed to + * enable single-led mode. It has also to be a 32bit + * write. + */ + dev_info(dev->dev, "port-%d: applying errata (Module 19) " \ + "workaround.\n", port); + data16 = 0xfa00; + ksz_pwrite16(dev, port, regs[P_PHY_DIGITAL_DEBUG_3], data16); +} + static void ksz_set_100_10mbit(struct ksz_device *dev, int port, int speed) { const u8 *bitval = dev->info->xmii_ctrl0; @@ -3020,6 +3056,9 @@ static void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port, { struct ksz_port *p; + if (dev->single_led_mode && port != dev->cpu_port) + ksz_enable_single_led_mode(dev, port); + p = &dev->ports[port]; /* Internal PHYs */ @@ -3744,6 +3783,8 @@ int ksz_switch_register(struct ksz_device *dev) ret = of_property_read_u8(dev->dev->of_node, "microchip,led-mode", &dev->led_mode); if (ret) dev->led_mode = 0; + dev->single_led_mode = of_property_read_bool(dev->dev->of_node, + "microchip,single-led-mode"); } ret = dsa_register_switch(dev->ds); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 25391fa8a087..813f37fc9fb3 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -150,6 +150,7 @@ struct ksz_device { struct gpio_desc *reset_gpio; /* Optional reset GPIO */ bool disable_internal_ldo; /* Disable internal 1.8V LDO */ u8 led_mode; + bool single_led_mode; /* Enable Single LED Mode */ /* chip specific data */ u32 chip_id; u8 chip_rev; @@ -232,6 +233,9 @@ enum ksz_regs { S_MULTICAST_CTRL, P_XMII_CTRL_0, P_XMII_CTRL_1, + P_PHY_MMD_SETUP, + P_PHY_MMD_DATA, + P_PHY_DIGITAL_DEBUG_3, }; enum ksz_masks {