There are switches which share the same overall hardware design but remove
just a couple of components for the low cost variant. For example, a 8+2
(ethernet+SFP) switch might have a low cost variant which only has 8
ethernet ports. In this case, the PCB will be shared but components for SFP
will just be dropped.
The LED shift registers will be the same between the two switches but the
ports are different. But since the rtl930x_led_init code is trying to
calculate the number of LEDs using the LED ports, the ethernet status ports
will then suddenly be shifted by two ports.
It is therefore necessary to have a mechanism to overwrite the detection of
the ethernet ports in the LED initialization and force some ports to
"virtually there" for the LED controller.
This functionality was already implemented for Plasma Cloud PSX8 (RTL930x)
but some devices using RTL931x might also benefit from a similar feature.
Signed-off-by: Harshal Gohel <hg@simonwunderlich.de>
Co-developed-by: Sven Eckelmann <se@simonwunderlich.de>
Signed-off-by: Sven Eckelmann <se@simonwunderlich.de>
Link: https://github.com/openwrt/openwrt/pull/20300
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2));
}
sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2));
}
+static void rtldsa_931x_led_get_forced(const struct device_node *node,
+ const u8 leds_in_set[4],
+ u8 forced_leds_per_port[RTL931X_CPU_PORT])
+{
+ DECLARE_BITMAP(mask, RTL931X_CPU_PORT);
+ unsigned int port;
+ char set_str[36];
+ u64 pm;
+
+ for (u8 set = 0; set < 4; set++) {
+ snprintf(set_str, sizeof(set_str), "realtek,led-set%d-force-port-mask", set);
+ if (of_property_read_u64(node, set_str, &pm))
+ continue;
+
+ bitmap_from_arr64(mask, &pm, RTL931X_CPU_PORT);
+
+ for_each_set_bit(port, mask, RTL931X_CPU_PORT)
+ forced_leds_per_port[port] = leds_in_set[set];
+ }
+}
+
static void rtldsa_931x_led_init(struct rtl838x_switch_priv *priv)
{
static void rtldsa_931x_led_init(struct rtl838x_switch_priv *priv)
{
+ u8 forced_leds_per_port[RTL931X_CPU_PORT] = {};
u64 pm_copper = 0, pm_fiber = 0;
struct device *dev = priv->dev;
struct device_node *node;
u64 pm_copper = 0, pm_fiber = 0;
struct device *dev = priv->dev;
struct device_node *node;
+ u8 leds_in_set[4] = {};
node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300-leds");
if (!node) {
node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300-leds");
if (!node) {
}
dev_info(dev, "%s has %d LEDs configured\n", set_name, leds_in_this_set);
}
dev_info(dev, "%s has %d LEDs configured\n", set_name, leds_in_this_set);
+ leds_in_set[set] = leds_in_this_set;
if (of_property_read_u32_array(node, set_name, set_config, leds_in_this_set))
break;
if (of_property_read_u32_array(node, set_name, set_config, leds_in_this_set))
break;
+ rtldsa_931x_led_get_forced(node, leds_in_set, forced_leds_per_port);
+
for (int i = 0; i < priv->cpu_port; i++) {
int pos = (i << 1) % 32;
u32 set;
for (int i = 0; i < priv->cpu_port; i++) {
int pos = (i << 1) % 32;
u32 set;
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i));
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i));
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
- if (!priv->ports[i].phy)
+ /* Skip port if not present (auto-detect) or not in forced mask */
+ if (!priv->ports[i].phy && !(forced_leds_per_port[i]))
+ if (forced_leds_per_port[i] > 0)
+ priv->ports[i].leds_on_this_port = forced_leds_per_port[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,
RTL931X_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,
RTL931X_LED_PORT_NUM_CTRL(i));