diff options
Diffstat (limited to 'drivers/net/dsa/realtek/rtl8366rb.c')
-rw-r--r-- | drivers/net/dsa/realtek/rtl8366rb.c | 223 |
1 files changed, 84 insertions, 139 deletions
diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index e10ae94cf771..8bdb52b5fdcb 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -21,16 +21,13 @@ #include <linux/irqchip/chained_irq.h> #include <linux/of_irq.h> #include <linux/regmap.h> +#include <linux/string_choices.h> #include "realtek.h" #include "realtek-smi.h" #include "realtek-mdio.h" #include "rtl83xx.h" - -#define RTL8366RB_PORT_NUM_CPU 5 -#define RTL8366RB_NUM_PORTS 6 -#define RTL8366RB_PHY_NO_MAX 4 -#define RTL8366RB_PHY_ADDR_MAX 31 +#include "rtl8366rb.h" /* Switch Global Configuration register */ #define RTL8366RB_SGCR 0x0000 @@ -175,38 +172,6 @@ */ #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f -/* LED control registers */ -#define RTL8366RB_LED_BLINKRATE_REG 0x0430 -#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 -#define RTL8366RB_LED_BLINKRATE_28MS 0x0000 -#define RTL8366RB_LED_BLINKRATE_56MS 0x0001 -#define RTL8366RB_LED_BLINKRATE_84MS 0x0002 -#define RTL8366RB_LED_BLINKRATE_111MS 0x0003 -#define RTL8366RB_LED_BLINKRATE_222MS 0x0004 -#define RTL8366RB_LED_BLINKRATE_446MS 0x0005 - -#define RTL8366RB_LED_CTRL_REG 0x0431 -#define RTL8366RB_LED_OFF 0x0 -#define RTL8366RB_LED_DUP_COL 0x1 -#define RTL8366RB_LED_LINK_ACT 0x2 -#define RTL8366RB_LED_SPD1000 0x3 -#define RTL8366RB_LED_SPD100 0x4 -#define RTL8366RB_LED_SPD10 0x5 -#define RTL8366RB_LED_SPD1000_ACT 0x6 -#define RTL8366RB_LED_SPD100_ACT 0x7 -#define RTL8366RB_LED_SPD10_ACT 0x8 -#define RTL8366RB_LED_SPD100_10_ACT 0x9 -#define RTL8366RB_LED_FIBER 0xa -#define RTL8366RB_LED_AN_FAULT 0xb -#define RTL8366RB_LED_LINK_RX 0xc -#define RTL8366RB_LED_LINK_TX 0xd -#define RTL8366RB_LED_MASTER 0xe -#define RTL8366RB_LED_FORCE 0xf -#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 -#define RTL8366RB_LED_1_OFFSET 6 -#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 -#define RTL8366RB_LED_3_OFFSET 6 - #define RTL8366RB_MIB_COUNT 33 #define RTL8366RB_GLOBAL_MIB_COUNT 1 #define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 @@ -242,7 +207,6 @@ #define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 #define RTL8366RB_NUM_VLANS 16 -#define RTL8366RB_NUM_LEDGROUPS 4 #define RTL8366RB_NUM_VIDS 4096 #define RTL8366RB_PRIORITYMAX 7 #define RTL8366RB_NUM_FIDS 8 @@ -349,16 +313,6 @@ #define RTL8366RB_GREEN_FEATURE_TX BIT(0) #define RTL8366RB_GREEN_FEATURE_RX BIT(2) -/** - * struct rtl8366rb - RTL8366RB-specific data - * @max_mtu: per-port max MTU setting - * @pvid_enabled: if PVID is set for respective port - */ -struct rtl8366rb { - unsigned int max_mtu[RTL8366RB_NUM_PORTS]; - bool pvid_enabled[RTL8366RB_NUM_PORTS]; -}; - static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { { 0, 0, 4, "IfInOctets" }, { 0, 4, 4, "EtherStatsOctets" }, @@ -568,7 +522,7 @@ static int rtl8366rb_setup_cascaded_irq(struct realtek_priv *priv) } /* Fetch IRQ edge information from the descriptor */ - irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); + irq_trig = irq_get_trigger_type(irq); switch (irq_trig) { case IRQF_TRIGGER_RISING: case IRQF_TRIGGER_HIGH: @@ -596,10 +550,8 @@ static int rtl8366rb_setup_cascaded_irq(struct realtek_priv *priv) dev_err(priv->dev, "unable to request irq: %d\n", ret); goto out_put_node; } - priv->irqdomain = irq_domain_add_linear(intc, - RTL8366RB_NUM_INTERRUPT, - &rtl8366rb_irqdomain_ops, - priv); + priv->irqdomain = irq_domain_create_linear(of_fwnode_handle(intc), RTL8366RB_NUM_INTERRUPT, + &rtl8366rb_irqdomain_ops, priv); if (!priv->irqdomain) { dev_err(priv->dev, "failed to create IRQ domain\n"); ret = -EINVAL; @@ -799,6 +751,47 @@ static int rtl8366rb_jam_table(const struct rtl8366rb_jam_tbl_entry *jam_table, return 0; } +/* This code is used also with LEDs disabled */ +int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv, + u8 led_group, + enum rtl8366_ledgroup_mode mode) +{ + int ret; + u32 val; + + val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group); + + ret = regmap_update_bits(priv->map, + RTL8366RB_LED_CTRL_REG, + RTL8366RB_LED_CTRL_MASK(led_group), + val); + if (ret) + return ret; + + return 0; +} + +/* This code is used also with LEDs disabled */ +static int rtl8366rb_setup_all_leds_off(struct realtek_priv *priv) +{ + int ret = 0; + int i; + + regmap_update_bits(priv->map, + RTL8366RB_INTERRUPT_CONTROL_REG, + RTL8366RB_P4_RGMII_LED, + 0); + + for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) { + ret = rb8366rb_set_ledgroup_mode(priv, i, + RTL8366RB_LEDGROUP_OFF); + if (ret) + return ret; + } + + return ret; +} + static int rtl8366rb_setup(struct dsa_switch *ds) { struct realtek_priv *priv = ds->priv; @@ -807,7 +800,6 @@ static int rtl8366rb_setup(struct dsa_switch *ds) u32 chip_ver = 0; u32 chip_id = 0; int jam_size; - u32 val; int ret; int i; @@ -987,7 +979,9 @@ static int rtl8366rb_setup(struct dsa_switch *ds) if (ret) return ret; - /* Set blinking, TODO: make this configurable */ + /* Set blinking, used by all LED groups using HW triggers. + * TODO: make this configurable + */ ret = regmap_update_bits(priv->map, RTL8366RB_LED_BLINKRATE_REG, RTL8366RB_LED_BLINKRATE_MASK, RTL8366RB_LED_BLINKRATE_56MS); @@ -995,32 +989,17 @@ static int rtl8366rb_setup(struct dsa_switch *ds) return ret; /* Set up LED activity: - * Each port has 4 LEDs, we configure all ports to the same - * behaviour (no individual config) but we can set up each - * LED separately. + * Each port has 4 LEDs on fixed groups. Each group shares the same + * hardware trigger across all ports. LEDs can only be indiviually + * controlled setting the LED group to fixed mode and using the driver + * to toggle them LEDs on/off. */ if (priv->leds_disabled) { - /* Turn everything off */ - regmap_update_bits(priv->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x0FFF, 0); - regmap_update_bits(priv->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x0FFF, 0); - regmap_update_bits(priv->map, - RTL8366RB_INTERRUPT_CONTROL_REG, - RTL8366RB_P4_RGMII_LED, - 0); - val = RTL8366RB_LED_OFF; + ret = rtl8366rb_setup_all_leds_off(priv); + if (ret) + return ret; } else { - /* TODO: make this configurable per LED */ - val = RTL8366RB_LED_FORCE; - } - for (i = 0; i < 4; i++) { - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_CTRL_REG, - 0xf << (i * 4), - val << (i * 4)); + ret = rtl8366rb_setup_leds(priv); if (ret) return ret; } @@ -1077,11 +1056,19 @@ static void rtl8366rb_phylink_get_caps(struct dsa_switch *ds, int port, } static void -rtl8366rb_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, - phy_interface_t interface, struct phy_device *phydev, +rtl8366rb_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void +rtl8366rb_mac_link_up(struct phylink_config *config, struct phy_device *phydev, + unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct realtek_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct realtek_priv *priv = dp->ds->priv; + int port = dp->index; unsigned int val; int ret; @@ -1147,10 +1134,12 @@ rtl8366rb_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, } static void -rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, +rtl8366rb_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct realtek_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct realtek_priv *priv = dp->ds->priv; + int port = dp->index; int ret; if (port != priv->cpu_port) @@ -1167,52 +1156,6 @@ rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, } } -static void rb8366rb_set_port_led(struct realtek_priv *priv, - int port, bool enable) -{ - u16 val = enable ? 0x3f : 0; - int ret; - - if (priv->leds_disabled) - return; - - switch (port) { - case 0: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x3F, val); - break; - case 1: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x3F << RTL8366RB_LED_1_OFFSET, - val << RTL8366RB_LED_1_OFFSET); - break; - case 2: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x3F, val); - break; - case 3: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x3F << RTL8366RB_LED_3_OFFSET, - val << RTL8366RB_LED_3_OFFSET); - break; - case 4: - ret = regmap_update_bits(priv->map, - RTL8366RB_INTERRUPT_CONTROL_REG, - RTL8366RB_P4_RGMII_LED, - enable ? RTL8366RB_P4_RGMII_LED : 0); - break; - default: - dev_err(priv->dev, "no LED for port %d\n", port); - return; - } - if (ret) - dev_err(priv->dev, "error updating LED on port %d\n", port); -} - static int rtl8366rb_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) @@ -1226,7 +1169,6 @@ rtl8366rb_port_enable(struct dsa_switch *ds, int port, if (ret) return ret; - rb8366rb_set_port_led(priv, port, true); return 0; } @@ -1241,8 +1183,6 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port) BIT(port)); if (ret) return; - - rb8366rb_set_port_led(priv, port, false); } static int @@ -1335,7 +1275,7 @@ static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, rb = priv->chip_data; dev_dbg(priv->dev, "port %d: %s VLAN filtering\n", port, - vlan_filtering ? "enable" : "disable"); + str_enable_disable(vlan_filtering)); /* If the port is not in the member set, the frame will be dropped */ ret = regmap_update_bits(priv->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, @@ -1697,7 +1637,7 @@ static bool rtl8366rb_is_vlan_valid(struct realtek_priv *priv, unsigned int vlan static int rtl8366rb_enable_vlan(struct realtek_priv *priv, bool enable) { - dev_dbg(priv->dev, "%s VLAN\n", enable ? "enable" : "disable"); + dev_dbg(priv->dev, "%s VLAN\n", str_enable_disable(enable)); return regmap_update_bits(priv->map, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, enable ? RTL8366RB_SGCR_EN_VLAN : 0); @@ -1705,7 +1645,7 @@ static int rtl8366rb_enable_vlan(struct realtek_priv *priv, bool enable) static int rtl8366rb_enable_vlan4k(struct realtek_priv *priv, bool enable) { - dev_dbg(priv->dev, "%s VLAN 4k\n", enable ? "enable" : "disable"); + dev_dbg(priv->dev, "%s VLAN 4k\n", str_enable_disable(enable)); return regmap_update_bits(priv->map, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN_4KTB, enable ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); @@ -1849,12 +1789,16 @@ static int rtl8366rb_detect(struct realtek_priv *priv) return 0; } +static const struct phylink_mac_ops rtl8366rb_phylink_mac_ops = { + .mac_config = rtl8366rb_mac_config, + .mac_link_down = rtl8366rb_mac_link_down, + .mac_link_up = rtl8366rb_mac_link_up, +}; + static const struct dsa_switch_ops rtl8366rb_switch_ops = { .get_tag_protocol = rtl8366_get_tag_protocol, .setup = rtl8366rb_setup, .phylink_get_caps = rtl8366rb_phylink_get_caps, - .phylink_mac_link_up = rtl8366rb_mac_link_up, - .phylink_mac_link_down = rtl8366rb_mac_link_down, .get_strings = rtl8366_get_strings, .get_ethtool_stats = rtl8366_get_ethtool_stats, .get_sset_count = rtl8366_get_sset_count, @@ -1892,6 +1836,7 @@ static const struct realtek_ops rtl8366rb_ops = { const struct realtek_variant rtl8366rb_variant = { .ds_ops = &rtl8366rb_switch_ops, .ops = &rtl8366rb_ops, + .phylink_mac_ops = &rtl8366rb_phylink_mac_ops, .clk_delay = 10, .cmd_read = 0xa9, .cmd_write = 0xa8, @@ -1910,7 +1855,7 @@ static struct platform_driver rtl8366rb_smi_driver = { .of_match_table = rtl8366rb_of_match, }, .probe = realtek_smi_probe, - .remove_new = realtek_smi_remove, + .remove = realtek_smi_remove, .shutdown = realtek_smi_shutdown, }; @@ -1952,4 +1897,4 @@ module_exit(rtl8366rb_exit); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(REALTEK_DSA); +MODULE_IMPORT_NS("REALTEK_DSA"); |