aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/dsa/microchip
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/microchip')
-rw-r--r--drivers/net/dsa/microchip/ksz8795.c26
-rw-r--r--drivers/net/dsa/microchip/ksz9477.c57
-rw-r--r--drivers/net/dsa/microchip/ksz9477_i2c.c1
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c36
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h3
5 files changed, 92 insertions, 31 deletions
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
index 8f1d15ea15d9..1e101ab56cea 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -782,10 +782,14 @@ static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port)
}
static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool flag)
+ bool flag,
+ struct switchdev_trans *trans)
{
struct ksz_device *dev = ds->priv;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
return 0;
@@ -932,11 +936,19 @@ static void ksz8795_port_setup(struct ksz_device *dev, int port, bool cpu_port)
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true);
if (cpu_port) {
+ if (!p->interface && dev->compat_interface) {
+ dev_warn(dev->dev,
+ "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
+ "Please update your device tree.\n",
+ port);
+ p->interface = dev->compat_interface;
+ }
+
/* Configure MII interface for proper network communication. */
ksz_read8(dev, REG_PORT_5_CTRL_6, &data8);
data8 &= ~PORT_INTERFACE_TYPE;
data8 &= ~PORT_GMII_1GPS_MODE;
- switch (dev->interface) {
+ switch (p->interface) {
case PHY_INTERFACE_MODE_MII:
p->phydev.speed = SPEED_100;
break;
@@ -952,11 +964,11 @@ static void ksz8795_port_setup(struct ksz_device *dev, int port, bool cpu_port)
default:
data8 &= ~PORT_RGMII_ID_IN_ENABLE;
data8 &= ~PORT_RGMII_ID_OUT_ENABLE;
- if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- dev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
data8 |= PORT_RGMII_ID_IN_ENABLE;
- if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- dev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
data8 |= PORT_RGMII_ID_OUT_ENABLE;
data8 |= PORT_GMII_1GPS_MODE;
data8 |= PORT_INTERFACE_RGMII;
@@ -1252,7 +1264,7 @@ static int ksz8795_switch_init(struct ksz_device *dev)
}
/* set the real number of ports */
- dev->ds->num_ports = dev->port_cnt;
+ dev->ds->num_ports = dev->port_cnt + 1;
return 0;
}
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index 3cb22d149813..abfd3802bb51 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -493,10 +493,14 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
}
static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool flag)
+ bool flag,
+ struct switchdev_trans *trans)
{
struct ksz_device *dev = ds->priv;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
if (flag) {
ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
PORT_VLAN_LOOKUP_VID_0, true);
@@ -1208,7 +1212,7 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* configure MAC to 1G & RGMII mode */
ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
- switch (dev->interface) {
+ switch (p->interface) {
case PHY_INTERFACE_MODE_MII:
ksz9477_set_xmii(dev, 0, &data8);
ksz9477_set_gbit(dev, false, &data8);
@@ -1229,12 +1233,15 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
ksz9477_set_gbit(dev, true, &data8);
data8 &= ~PORT_RGMII_ID_IG_ENABLE;
data8 &= ~PORT_RGMII_ID_EG_ENABLE;
- if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- dev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
data8 |= PORT_RGMII_ID_IG_ENABLE;
- if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- dev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
data8 |= PORT_RGMII_ID_EG_ENABLE;
+ /* On KSZ9893, disable RGMII in-band status support */
+ if (dev->features & IS_9893)
+ data8 &= ~PORT_MII_MAC_MODE;
p->phydev.speed = SPEED_1000;
break;
}
@@ -1265,27 +1272,46 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
for (i = 0; i < dev->port_cnt; i++) {
if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) {
phy_interface_t interface;
+ const char *prev_msg;
+ const char *prev_mode;
dev->cpu_port = i;
dev->host_mask = (1 << dev->cpu_port);
dev->port_mask |= dev->host_mask;
+ p = &dev->ports[i];
/* Read from XMII register to determine host port
* interface. If set specifically in device tree
* note the difference to help debugging.
*/
interface = ksz9477_get_interface(dev, i);
- if (!dev->interface)
- dev->interface = interface;
- if (interface && interface != dev->interface)
- dev_info(dev->dev,
- "use %s instead of %s\n",
- phy_modes(dev->interface),
- phy_modes(interface));
+ if (!p->interface) {
+ if (dev->compat_interface) {
+ dev_warn(dev->dev,
+ "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
+ "Please update your device tree.\n",
+ i);
+ p->interface = dev->compat_interface;
+ } else {
+ p->interface = interface;
+ }
+ }
+ if (interface && interface != p->interface) {
+ prev_msg = " instead of ";
+ prev_mode = phy_modes(interface);
+ } else {
+ prev_msg = "";
+ prev_mode = "";
+ }
+ dev_info(dev->dev,
+ "Port%d: using phy mode %s%s%s\n",
+ i,
+ phy_modes(p->interface),
+ prev_msg,
+ prev_mode);
/* enable cpu port */
ksz9477_port_setup(dev, i, true);
- p = &dev->ports[dev->cpu_port];
p->vid_member = dev->port_mask;
p->on = 1;
}
@@ -1426,10 +1452,12 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
/* Default capability is gigabit capable. */
dev->features = GBIT_SUPPORT;
+ dev_dbg(dev->dev, "Switch detect: ID=%08x%02x\n", id32, data8);
id_hi = (u8)(id32 >> 16);
id_lo = (u8)(id32 >> 8);
if ((id_lo & 0xf) == 3) {
/* Chip is from KSZ9893 design. */
+ dev_info(dev->dev, "Found KSZ9893\n");
dev->features |= IS_9893;
/* Chip does not support gigabit. */
@@ -1438,6 +1466,7 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
dev->mib_port_cnt = 3;
dev->phy_port_cnt = 2;
} else {
+ dev_info(dev->dev, "Found KSZ9477 or compatible\n");
/* Chip uses new XMII register definitions. */
dev->features |= NEW_XMII;
diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
index 7951f52d860d..4e053a25d077 100644
--- a/drivers/net/dsa/microchip/ksz9477_i2c.c
+++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
@@ -80,6 +80,7 @@ static const struct of_device_id ksz9477_dt_ids[] = {
{ .compatible = "microchip,ksz9477" },
{ .compatible = "microchip,ksz9897" },
{ .compatible = "microchip,ksz9893" },
+ { .compatible = "microchip,ksz9563" },
{ .compatible = "microchip,ksz9567" },
{},
};
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 8d53b12d40a8..0ef854911f21 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -103,14 +103,8 @@ void ksz_init_mib_timer(struct ksz_device *dev)
INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work);
- /* Read MIB counters every 30 seconds to avoid overflow. */
- dev->mib_read_interval = msecs_to_jiffies(30000);
-
for (i = 0; i < dev->mib_port_cnt; i++)
dev->dev_ops->port_init_cnt(dev, i);
-
- /* Start the timer 2 seconds later. */
- schedule_delayed_work(&dev->mib_read, msecs_to_jiffies(2000));
}
EXPORT_SYMBOL_GPL(ksz_init_mib_timer);
@@ -143,7 +137,9 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
/* Read all MIB counters when the link is going down. */
p->read = true;
- schedule_delayed_work(&dev->mib_read, 0);
+ /* timer started */
+ if (dev->mib_read_interval)
+ schedule_delayed_work(&dev->mib_read, 0);
}
EXPORT_SYMBOL_GPL(ksz_mac_link_down);
@@ -387,7 +383,9 @@ EXPORT_SYMBOL(ksz_switch_alloc);
int ksz_switch_register(struct ksz_device *dev,
const struct ksz_dev_ops *ops)
{
+ struct device_node *port, *ports;
phy_interface_t interface;
+ unsigned int port_num;
int ret;
if (dev->pdata)
@@ -400,8 +398,9 @@ int ksz_switch_register(struct ksz_device *dev,
if (dev->reset_gpio) {
gpiod_set_value_cansleep(dev->reset_gpio, 1);
- mdelay(10);
+ usleep_range(10000, 12000);
gpiod_set_value_cansleep(dev->reset_gpio, 0);
+ usleep_range(100, 1000);
}
mutex_init(&dev->dev_mutex);
@@ -421,10 +420,23 @@ int ksz_switch_register(struct ksz_device *dev,
/* Host port interface will be self detected, or specifically set in
* device tree.
*/
+ for (port_num = 0; port_num < dev->port_cnt; ++port_num)
+ dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA;
if (dev->dev->of_node) {
ret = of_get_phy_mode(dev->dev->of_node, &interface);
if (ret == 0)
- dev->interface = interface;
+ dev->compat_interface = interface;
+ ports = of_get_child_by_name(dev->dev->of_node, "ports");
+ if (ports)
+ for_each_available_child_of_node(ports, port) {
+ if (of_property_read_u32(port, "reg",
+ &port_num))
+ continue;
+ if (port_num >= dev->port_cnt)
+ return -EINVAL;
+ of_get_phy_mode(port,
+ &dev->ports[port_num].interface);
+ }
dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
"microchip,synclko-125");
}
@@ -435,6 +447,12 @@ int ksz_switch_register(struct ksz_device *dev,
return ret;
}
+ /* Read MIB counters every 30 seconds to avoid overflow. */
+ dev->mib_read_interval = msecs_to_jiffies(30000);
+
+ /* Start the MIB timer. */
+ schedule_delayed_work(&dev->mib_read, 0);
+
return 0;
}
EXPORT_SYMBOL(ksz_switch_register);
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 206838160f49..cf866e48ff66 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -39,6 +39,7 @@ struct ksz_port {
u32 freeze:1; /* MIB counter freeze is enabled */
struct ksz_port_mib mib;
+ phy_interface_t interface;
};
struct ksz_device {
@@ -72,7 +73,7 @@ struct ksz_device {
int mib_cnt;
int mib_port_cnt;
int last_port; /* ports after that not used */
- phy_interface_t interface;
+ phy_interface_t compat_interface;
u32 regs_size;
bool phy_errata_9477;
bool synclko_125;