Skip to content

Commit

Permalink
net: dsa: mv88e6xxx: Support LED control
Browse files Browse the repository at this point in the history
This adds control over the hardware LEDs in the Marvell
MV88E6xxx DSA switch and enables it for MV88E6352.

This fixes an imminent problem on the Inteno XG6846 which
has a WAN LED that simply do not work with hardware
defaults: driver amendment is necessary.

The patch is modeled after Christian Marangis LED support
code for the QCA8k DSA switch, I got help with the register
definitions from Tim Harvey.

After this patch it is possible to activate hardware link
indication like this (or with a similar script):

  cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
  echo netdev > trigger
  echo 1 > link

This makes the green link indicator come up on any link
speed. It is also possible to be more elaborate, like this:

  cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/
  echo netdev > trigger
  echo 1 > link_1000
  cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/
  echo netdev > trigger
  echo 1 > link_100

Making the green LED come on for a gigabit link and the
amber LED come on for a 100 mbit link.

Each port has 2 LED slots (the hardware may use just one or
none) and the hardware triggers are specified in four bits per
LED, and some of the hardware triggers are only available on the
SFP (fiber) uplink. The restrictions are described in the
port.h header file where the registers are described. For
example, selector 1 set for LED 1 on port 5 or 6 will indicate
Fiber 1000 (gigabit) and activity with a blinking LED, but
ONLY for an SFP connection. If port 5/6 is used with something
not SFP, this selector is a noop: something else need to be
selected.

After the previous series rewriting the MV88E6xxx DT
bindings to use YAML a "leds" subnode is already valid
for each port, in my scratch device tree it looks like
this:

   leds {
     #address-cells = <1>;
     #size-cells = <0>;

     led@0 {
       reg = <0>;
       color = <LED_COLOR_ID_GREEN>;
       function = LED_FUNCTION_LAN;
       default-state = "off";
       linux,default-trigger = "netdev";
     };
     led@1 {
       reg = <1>;
       color = <LED_COLOR_ID_AMBER>;
       function = LED_FUNCTION_LAN;
       default-state = "off";
     };
   };

This DT config is not yet configuring everything: when the netdev
default trigger is assigned the hw acceleration callbacks are
not called, and there is no way to set the netdev sub-trigger
type (such as link_1000) from the device tree, such as if you want
a gigabit link indicator. This has to be done from userspace at
this point.

We add LED operations to all switches in the 6352 family:
6172, 6176, 6240 and 6352.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241001-mv88e6xxx-leds-v4-1-cc11c4f49b18@linaro.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
linusw authored and kuba-moo committed Oct 4, 2024
1 parent c86ab60 commit 94a2a84
Show file tree
Hide file tree
Showing 7 changed files with 1,031 additions and 2 deletions.
10 changes: 10 additions & 0 deletions drivers/net/dsa/mv88e6xxx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP
help
Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
chips that support it.

config NET_DSA_MV88E6XXX_LEDS
bool "LED support for Marvell 88E6xxx"
default y
depends on NET_DSA_MV88E6XXX
depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX
depends on LEDS_TRIGGERS
help
This enabled support for controlling the LEDs attached to the
Marvell 88E6xxx switch chips.
1 change: 1 addition & 0 deletions drivers/net/dsa/mv88e6xxx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
mv88e6xxx-objs += global2_avb.o
mv88e6xxx-objs += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o
mv88e6xxx-objs += pcs-6185.o
mv88e6xxx-objs += pcs-6352.o
mv88e6xxx-objs += pcs-639x.o
Expand Down
38 changes: 36 additions & 2 deletions drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/platform_data/mv88e6xxx.h>
#include <linux/property.h>
#include <linux/netdevice.h>
#include <linux/gpio/consumer.h>
#include <linux/phylink.h>
Expand Down Expand Up @@ -3371,14 +3372,43 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
{
struct device_node *phy_handle = NULL;
struct fwnode_handle *ports_fwnode;
struct fwnode_handle *port_fwnode;
struct dsa_switch *ds = chip->ds;
struct mv88e6xxx_port *p;
struct dsa_port *dp;
int tx_amp;
int err;
u16 reg;
u32 val;

p = &chip->ports[port];
p->chip = chip;
p->port = port;

/* Look up corresponding fwnode if any */
ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports");
if (!ports_fwnode)
ports_fwnode = device_get_named_child_node(chip->dev, "ports");
if (ports_fwnode) {
fwnode_for_each_child_node(ports_fwnode, port_fwnode) {
if (fwnode_property_read_u32(port_fwnode, "reg", &val))
continue;
if (val == port) {
p->fwnode = port_fwnode;
p->fiber = fwnode_property_present(port_fwnode, "sfp");
break;
}
}
} else {
dev_dbg(chip->dev, "no ethernet ports node defined for the device\n");
}

chip->ports[port].chip = chip;
chip->ports[port].port = port;
if (chip->info->ops->port_setup_leds) {
err = chip->info->ops->port_setup_leds(chip, port);
if (err && err != -EOPNOTSUPP)
return err;
}

err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
SPEED_UNFORCED, DUPLEX_UNFORCED,
Expand Down Expand Up @@ -4597,6 +4627,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_leds = mv88e6xxx_port_setup_leds,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
Expand Down Expand Up @@ -4699,6 +4730,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_leds = mv88e6xxx_port_setup_leds,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
Expand Down Expand Up @@ -4974,6 +5006,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_leds = mv88e6xxx_port_setup_leds,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
Expand Down Expand Up @@ -5396,6 +5429,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_get_cmode = mv88e6352_port_get_cmode,
.port_setup_leds = mv88e6xxx_port_setup_leds,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/dsa/mv88e6xxx/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include <linux/irq.h>
#include <linux/gpio/consumer.h>
#include <linux/kthread.h>
#include <linux/leds.h>
#include <linux/phy.h>
#include <linux/property.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
#include <net/dsa.h>
Expand Down Expand Up @@ -275,6 +277,7 @@ struct mv88e6xxx_vlan {
struct mv88e6xxx_port {
struct mv88e6xxx_chip *chip;
int port;
struct fwnode_handle *fwnode;
struct mv88e6xxx_vlan bridge_pvid;
u64 serdes_stats[2];
u64 atu_member_violation;
Expand All @@ -289,6 +292,11 @@ struct mv88e6xxx_port {
struct devlink_region *region;
void *pcs_private;

/* LED related information */
bool fiber;
struct led_classdev led0;
struct led_classdev led1;

/* MacAuth Bypass control flag */
bool mab;
};
Expand Down Expand Up @@ -572,6 +580,9 @@ struct mv88e6xxx_ops {
phy_interface_t mode);
int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);

/* LED control */
int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port);

/* Some devices have a per port register indicating what is
* the upstream port this port should forward to.
*/
Expand Down
Loading

0 comments on commit 94a2a84

Please sign in to comment.