diff --git a/target/linux/realtek/dts-5.15/rtl9302_zyxel_xgs1250-12.dts b/target/linux/realtek/dts-5.15/rtl9302_zyxel_xgs1250-12.dts index 0fe8f1997e..98ac08b26a 100644 --- a/target/linux/realtek/dts-5.15/rtl9302_zyxel_xgs1250-12.dts +++ b/target/linux/realtek/dts-5.15/rtl9302_zyxel_xgs1250-12.dts @@ -66,10 +66,10 @@ compatible = "realtek,rtl9300-leds"; active-low; - led_set0 = <0x0000 0xffff 0x0a20 0x0b80>; // LED set 0: 1000Mbps, 10/100Mbps + led_set0 = <0x0a20 0x0b80>; // LED set 0: 1000Mbps, 10/100Mbps led_set1 = <0x0a0b 0x0a28 0x0a82 0x0a0b>; // LED set 1: (10G, 5G, 2.5G) (2.5G, 1G) // (5G, 10/100) (10G, 5G, 2.5G) - led_set2 = <0x0000 0xffff 0x0a20 0x0a01>; // LED set 2: 1000MBit, 10GBit + led_set2 = <0x0a20 0x0a01>; // LED set 2: 1000MBit, 10GBit }; }; diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c index 0434312afc..221428cc77 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/common.c @@ -271,7 +271,7 @@ int write_phy(u32 port, u32 page, u32 reg, u32 val) static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) { struct device *dev = priv->dev; - struct device_node *dn, *phy_node, *mii_np = dev->of_node; + struct device_node *dn, *phy_node, *led_node, *mii_np = dev->of_node; struct mii_bus *bus; int ret; u32 pn; @@ -325,9 +325,12 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) return -ENODEV; } + led_node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300-leds"); + for_each_node_by_name(dn, "port") { phy_interface_t interface; u32 led_set; + char led_set_str[16] = {0}; if (!of_device_is_available(dn)) continue; @@ -355,9 +358,18 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) if (interface == PHY_INTERFACE_MODE_10GBASER) priv->ports[pn].is10G = true; - if (of_property_read_u32(dn, "led-set", &led_set)) - led_set = 0; - priv->ports[pn].led_set = led_set; + priv->ports[pn].leds_on_this_port = 0; + if (led_node) { + if (of_property_read_u32(dn, "led-set", &led_set)) + led_set = 0; + priv->ports[pn].led_set = led_set; + sprintf(led_set_str, "led_set%d", led_set); + priv->ports[pn].leds_on_this_port = of_property_count_u32_elems(led_node, led_set_str); + if (priv->ports[pn].leds_on_this_port > 4) { + dev_err(priv->dev, "led_set %d for port %d configuration is invalid\n", led_set, pn); + return -ENODEV; + } + } /* Check for the integrated SerDes of the RTL8380M first */ if (of_property_read_bool(phy_node, "phy-is-integrated") diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h index 24d18d61fa..a642c74775 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl838x.h @@ -635,6 +635,7 @@ struct rtl838x_port { bool is2G5; int sds_num; int led_set; + int leds_on_this_port; const struct dsa_port *dp; }; diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl930x.c index c4f200bc0e..4a4a926bb2 100644 --- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/rtl930x.c @@ -24,6 +24,15 @@ #define RTL930X_LED_GLB_ACTIVE_LOW BIT(22) +#define RTL930X_LED_SETX_0_CTRL(x) (RTL930X_LED_SET0_0_CTRL - (x * 8)) +#define RTL930X_LED_SETX_1_CTRL(x) (RTL930X_LED_SETX_0_CTRL(x) - 4) + +/* get register for given set and led in the set */ +#define RTL930X_LED_SETX_LEDY(x,y) (RTL930X_LED_SETX_0_CTRL(x) - 4 * (y / 2)) + +/* get shift for given led in any set */ +#define RTL930X_LED_SET_LEDX_SHIFT(x) (16 * (x % 2)) + extern struct mutex smi_lock; extern struct rtl83xx_soc_info soc_info; @@ -2396,10 +2405,44 @@ static void rtl930x_led_init(struct rtl838x_switch_priv *priv) return; } + for (int set = 0; set < 4; set++) { + char set_name[16] = {0}; + u32 set_config[4]; + int leds_in_this_set = 0; + + /* Reset LED set configuration */ + sw_w32(0, RTL930X_LED_SETX_0_CTRL(set)); + sw_w32(0, RTL930X_LED_SETX_1_CTRL(set)); + + /** + * Each led set has 4 number of leds, and each LED is configured with 16 bits + * So each 32bit register holds configuration for 2 leds + * And therefore each set requires 2 registers for configuring 4 LEDs + * + */ + sprintf(set_name, "led_set%d", set); + leds_in_this_set = of_property_count_u32_elems(node, set_name); + + if (leds_in_this_set == 0 || leds_in_this_set > sizeof(set_config)) { + pr_err("%s led_set configuration invalid skipping over this set\n", __func__); + continue; + } + + if (of_property_read_u32_array(node, set_name, set_config, leds_in_this_set)) { + break; + } + + /* Write configuration as per number of LEDs */ + for (int i=0, led = leds_in_this_set-1; led >= 0; led--,i++) { + sw_w32_mask(0xffff << RTL930X_LED_SET_LEDX_SHIFT(led), + (0xffff & set_config[i]) << RTL930X_LED_SET_LEDX_SHIFT(led), + RTL930X_LED_SETX_LEDY(set, led)); + } + } + for (int i = 0; i < priv->cpu_port; i++) { int pos = (i << 1) % 32; u32 set; - u32 v; sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i)); sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_COPR_SET_SEL_CTRL(i)); @@ -2407,12 +2450,8 @@ static void rtl930x_led_init(struct rtl838x_switch_priv *priv) if (!priv->ports[i].phy) continue; - v = 0x1; - if (priv->ports[i].is10G) - v = 0x3; - if (priv->ports[i].phy_is_integrated) - v = 0x1; - sw_w32_mask(0x3 << pos, v << pos, RTL930X_LED_PORT_NUM_CTRL(i)); + /* 0x0 = 1 led, 0x1 = 2 leds, 0x2 = 3 leds, 0x3 = 4 leds per port */ + sw_w32_mask(0x3 << pos, (priv->ports[i].leds_on_this_port -1) << pos, RTL930X_LED_PORT_NUM_CTRL(i)); pm |= BIT(i); @@ -2421,22 +2460,6 @@ static void rtl930x_led_init(struct rtl838x_switch_priv *priv) sw_w32_mask(0, set << pos, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i)); } - for (int i = 0; i < 4; i++) { - const __be32 *led_set; - char set_name[9]; - u32 setlen; - u32 v; - - sprintf(set_name, "led_set%d", i); - led_set = of_get_property(node, set_name, &setlen); - if (!led_set || setlen != 16) - break; - v = be32_to_cpup(led_set) << 16 | be32_to_cpup(led_set + 1); - sw_w32(v, RTL930X_LED_SET0_0_CTRL - 4 - i * 8); - v = be32_to_cpup(led_set + 2) << 16 | be32_to_cpup(led_set + 3); - sw_w32(v, RTL930X_LED_SET0_0_CTRL - i * 8); - } - /* Set LED mode to serial (0x1) */ sw_w32_mask(0x3, 0x1, RTL930X_LED_GLB_CTRL);