Commit 2d919d39 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-dsa-microchip-error-hndling-reg-access-validation'

Oleksij Rempel says:

====================
net: dsa: microchip: add error handling and register access validation

changes v4:
- add Reviewed-by: Vladimir Oltean <olteanv@gmail.com> to all patches
- fix checkpatch warnings.

changes v3:
- fix build error in the middle of the patch stack.

changes v2:
- add regmap_ranges for KSZ9477
- drop output clock devicetree in driver validation patches. DTs need
  some more refactoring and can be done in a separate patch set.
- remove some unused variables.

This patch series adds error handling for the PHY read/write path and optional
register access validation.
After adding regmap_ranges for KSZ8563 some bugs was detected, so
critical bug fixes are sorted before ragmap_range patch.

Potentially this bug fixes can be ported to stable kernels, but need to be
reworked.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 21cb860c 32cbac21
...@@ -17,8 +17,8 @@ u32 ksz8_get_port_addr(int port, int offset); ...@@ -17,8 +17,8 @@ u32 ksz8_get_port_addr(int port, int offset);
void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member); void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member);
void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port); void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port);
void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port); void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port);
void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val); int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val);
int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr, int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries); u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries);
int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
......
...@@ -552,7 +552,7 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) ...@@ -552,7 +552,7 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
ksz8_w_table(dev, TABLE_VLAN, addr, buf); ksz8_w_table(dev, TABLE_VLAN, addr, buf);
} }
void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{ {
u8 restart, speed, ctrl, link; u8 restart, speed, ctrl, link;
int processed = true; int processed = true;
...@@ -560,14 +560,24 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -560,14 +560,24 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
u8 val1, val2; u8 val1, val2;
u16 data = 0; u16 data = 0;
u8 p = phy; u8 p = phy;
int ret;
regs = dev->info->regs; regs = dev->info->regs;
switch (reg) { switch (reg) {
case MII_BMCR: case MII_BMCR:
ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); if (ret)
ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); return ret;
ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
if (ret)
return ret;
ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
if (ret)
return ret;
if (restart & PORT_PHY_LOOPBACK) if (restart & PORT_PHY_LOOPBACK)
data |= BMCR_LOOPBACK; data |= BMCR_LOOPBACK;
if (ctrl & PORT_FORCE_100_MBIT) if (ctrl & PORT_FORCE_100_MBIT)
...@@ -597,7 +607,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -597,7 +607,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data |= KSZ886X_BMCR_DISABLE_LED; data |= KSZ886X_BMCR_DISABLE_LED;
break; break;
case MII_BMSR: case MII_BMSR:
ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
if (ret)
return ret;
data = BMSR_100FULL | data = BMSR_100FULL |
BMSR_100HALF | BMSR_100HALF |
BMSR_10FULL | BMSR_10FULL |
...@@ -618,7 +631,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -618,7 +631,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data = KSZ8795_ID_LO; data = KSZ8795_ID_LO;
break; break;
case MII_ADVERTISE: case MII_ADVERTISE:
ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
if (ret)
return ret;
data = ADVERTISE_CSMA; data = ADVERTISE_CSMA;
if (ctrl & PORT_AUTO_NEG_SYM_PAUSE) if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
data |= ADVERTISE_PAUSE_CAP; data |= ADVERTISE_PAUSE_CAP;
...@@ -632,7 +648,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -632,7 +648,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data |= ADVERTISE_10HALF; data |= ADVERTISE_10HALF;
break; break;
case MII_LPA: case MII_LPA:
ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link); ret = ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link);
if (ret)
return ret;
data = LPA_SLCT; data = LPA_SLCT;
if (link & PORT_REMOTE_SYM_PAUSE) if (link & PORT_REMOTE_SYM_PAUSE)
data |= LPA_PAUSE_CAP; data |= LPA_PAUSE_CAP;
...@@ -648,8 +667,14 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -648,8 +667,14 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data |= LPA_LPACK; data |= LPA_LPACK;
break; break;
case PHY_REG_LINK_MD: case PHY_REG_LINK_MD:
ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1); ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1);
ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2); if (ret)
return ret;
ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2);
if (ret)
return ret;
if (val1 & PORT_START_CABLE_DIAG) if (val1 & PORT_START_CABLE_DIAG)
data |= PHY_START_CABLE_DIAG; data |= PHY_START_CABLE_DIAG;
...@@ -664,7 +689,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -664,7 +689,10 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2)); FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2));
break; break;
case PHY_REG_PHY_CTRL: case PHY_REG_PHY_CTRL:
ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
if (ret)
return ret;
if (link & PORT_MDIX_STATUS) if (link & PORT_MDIX_STATUS)
data |= KSZ886X_CTRL_MDIX_STAT; data |= KSZ886X_CTRL_MDIX_STAT;
break; break;
...@@ -674,13 +702,16 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -674,13 +702,16 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
} }
if (processed) if (processed)
*val = data; *val = data;
return 0;
} }
void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{ {
u8 restart, speed, ctrl, data; u8 restart, speed, ctrl, data;
const u16 *regs; const u16 *regs;
u8 p = phy; u8 p = phy;
int ret;
regs = dev->info->regs; regs = dev->info->regs;
...@@ -690,15 +721,26 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -690,15 +721,26 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
/* Do not support PHY reset function. */ /* Do not support PHY reset function. */
if (val & BMCR_RESET) if (val & BMCR_RESET)
break; break;
ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
if (ret)
return ret;
data = speed; data = speed;
if (val & KSZ886X_BMCR_HP_MDIX) if (val & KSZ886X_BMCR_HP_MDIX)
data |= PORT_HP_MDIX; data |= PORT_HP_MDIX;
else else
data &= ~PORT_HP_MDIX; data &= ~PORT_HP_MDIX;
if (data != speed)
ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); if (data != speed) {
ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); ret = ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data);
if (ret)
return ret;
}
ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
if (ret)
return ret;
data = ctrl; data = ctrl;
if (ksz_is_ksz88x3(dev)) { if (ksz_is_ksz88x3(dev)) {
if ((val & BMCR_ANENABLE)) if ((val & BMCR_ANENABLE))
...@@ -724,9 +766,17 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -724,9 +766,17 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
data |= PORT_FORCE_FULL_DUPLEX; data |= PORT_FORCE_FULL_DUPLEX;
else else
data &= ~PORT_FORCE_FULL_DUPLEX; data &= ~PORT_FORCE_FULL_DUPLEX;
if (data != ctrl)
ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data); if (data != ctrl) {
ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); ret = ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data);
if (ret)
return ret;
}
ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
if (ret)
return ret;
data = restart; data = restart;
if (val & KSZ886X_BMCR_DISABLE_LED) if (val & KSZ886X_BMCR_DISABLE_LED)
data |= PORT_LED_OFF; data |= PORT_LED_OFF;
...@@ -756,11 +806,19 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -756,11 +806,19 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
data |= PORT_PHY_LOOPBACK; data |= PORT_PHY_LOOPBACK;
else else
data &= ~PORT_PHY_LOOPBACK; data &= ~PORT_PHY_LOOPBACK;
if (data != restart)
ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], data); if (data != restart) {
ret = ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL],
data);
if (ret)
return ret;
}
break; break;
case MII_ADVERTISE: case MII_ADVERTISE:
ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
if (ret)
return ret;
data = ctrl; data = ctrl;
data &= ~(PORT_AUTO_NEG_SYM_PAUSE | data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX_FD |
...@@ -777,8 +835,12 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -777,8 +835,12 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
data |= PORT_AUTO_NEG_10BT_FD; data |= PORT_AUTO_NEG_10BT_FD;
if (val & ADVERTISE_10HALF) if (val & ADVERTISE_10HALF)
data |= PORT_AUTO_NEG_10BT; data |= PORT_AUTO_NEG_10BT;
if (data != ctrl)
ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data); if (data != ctrl) {
ret = ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data);
if (ret)
return ret;
}
break; break;
case PHY_REG_LINK_MD: case PHY_REG_LINK_MD:
if (val & PHY_START_CABLE_DIAG) if (val & PHY_START_CABLE_DIAG)
...@@ -787,6 +849,8 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -787,6 +849,8 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
default: default:
break; break;
} }
return 0;
} }
void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
...@@ -1187,7 +1251,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) ...@@ -1187,7 +1251,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
if (i == dev->phy_port_cnt) if (i == dev->phy_port_cnt)
break; break;
p->on = 1; p->on = 1;
p->phy = 1;
} }
for (i = 0; i < dev->phy_port_cnt; i++) { for (i = 0; i < dev->phy_port_cnt; i++) {
p = &dev->ports[i]; p = &dev->ports[i];
......
...@@ -193,6 +193,11 @@ int ksz9477_reset_switch(struct ksz_device *dev) ...@@ -193,6 +193,11 @@ int ksz9477_reset_switch(struct ksz_device *dev)
ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F);
ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
/* KSZ9893 compatible chips do not support refclk configuration */
if (dev->chip_id == KSZ9893_CHIP_ID ||
dev->chip_id == KSZ8563_CHIP_ID)
return 0;
data8 = SW_ENABLE_REFCLKO; data8 = SW_ENABLE_REFCLKO;
if (dev->synclko_disable) if (dev->synclko_disable)
data8 = 0; data8 = 0;
...@@ -264,9 +269,20 @@ void ksz9477_port_init_cnt(struct ksz_device *dev, int port) ...@@ -264,9 +269,20 @@ void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
mutex_unlock(&mib->cnt_mutex); mutex_unlock(&mib->cnt_mutex);
} }
void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) static void ksz9477_r_phy_quirks(struct ksz_device *dev, u16 addr, u16 reg,
u16 *data)
{
/* KSZ8563R do not have extended registers but BMSR_ESTATEN and
* BMSR_ERCAP bits are set.
*/
if (dev->chip_id == KSZ8563_CHIP_ID && reg == MII_BMSR)
*data &= ~(BMSR_ESTATEN | BMSR_ERCAP);
}
int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
{ {
u16 val = 0xffff; u16 val = 0xffff;
int ret;
/* No real PHY after this. Simulate the PHY. /* No real PHY after this. Simulate the PHY.
* A fixed PHY can be setup in the device tree, but this function is * A fixed PHY can be setup in the device tree, but this function is
...@@ -274,7 +290,7 @@ void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) ...@@ -274,7 +290,7 @@ void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
* For RGMII PHY there is no way to access it so the fixed PHY should * For RGMII PHY there is no way to access it so the fixed PHY should
* be used. For SGMII PHY the supporting code will be added later. * be used. For SGMII PHY the supporting code will be added later.
*/ */
if (addr >= dev->phy_port_cnt) { if (!dev->info->internal_phy[addr]) {
struct ksz_port *p = &dev->ports[addr]; struct ksz_port *p = &dev->ports[addr];
switch (reg) { switch (reg) {
...@@ -307,23 +323,25 @@ void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) ...@@ -307,23 +323,25 @@ void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
break; break;
} }
} else { } else {
ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); ret = ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
if (ret)
return ret;
ksz9477_r_phy_quirks(dev, addr, reg, &val);
} }
*data = val; *data = val;
return 0;
} }
void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
{ {
/* No real PHY after this. */ /* No real PHY after this. */
if (addr >= dev->phy_port_cnt) if (!dev->info->internal_phy[addr])
return; return 0;
/* No gigabit support. Do not write to this register. */
if (!(dev->features & GBIT_SUPPORT) && reg == MII_CTRL1000)
return;
ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
} }
void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member) void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member)
...@@ -869,7 +887,7 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port) ...@@ -869,7 +887,7 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port)
phy_interface_t interface; phy_interface_t interface;
bool gbit; bool gbit;
if (port < dev->phy_port_cnt) if (dev->info->internal_phy[port])
return PHY_INTERFACE_MODE_NA; return PHY_INTERFACE_MODE_NA;
gbit = ksz_get_gbit(dev, port); gbit = ksz_get_gbit(dev, port);
...@@ -914,7 +932,7 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) ...@@ -914,7 +932,7 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
/* Energy Efficient Ethernet (EEE) feature select must /* Energy Efficient Ethernet (EEE) feature select must
* be manually disabled (except on KSZ8565 which is 100Mbit) * be manually disabled (except on KSZ8565 which is 100Mbit)
*/ */
if (dev->features & GBIT_SUPPORT) if (dev->info->gbit_capable[port])
ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000); ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000);
/* Register settings are required to meet data sheet /* Register settings are required to meet data sheet
...@@ -941,7 +959,7 @@ void ksz9477_get_caps(struct ksz_device *dev, int port, ...@@ -941,7 +959,7 @@ void ksz9477_get_caps(struct ksz_device *dev, int port,
config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE | config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE |
MAC_SYM_PAUSE; MAC_SYM_PAUSE;
if (dev->features & GBIT_SUPPORT) if (dev->info->gbit_capable[port])
config->mac_capabilities |= MAC_1000FD; config->mac_capabilities |= MAC_1000FD;
} }
...@@ -976,7 +994,7 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -976,7 +994,7 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* enable 802.1p priority */ /* enable 802.1p priority */
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true);
if (port < dev->phy_port_cnt) { if (dev->info->internal_phy[port]) {
/* do not force flow control */ /* do not force flow control */
ksz_port_cfg(dev, port, REG_PORT_CTRL_0, ksz_port_cfg(dev, port, REG_PORT_CTRL_0,
PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL,
...@@ -999,7 +1017,7 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -999,7 +1017,7 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
ksz9477_cfg_port_member(dev, port, member); ksz9477_cfg_port_member(dev, port, member);
/* clear pending interrupts */ /* clear pending interrupts */
if (port < dev->phy_port_cnt) if (dev->info->internal_phy[port])
ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
} }
...@@ -1051,25 +1069,13 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) ...@@ -1051,25 +1069,13 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds)
/* enable cpu port */ /* enable cpu port */
ksz9477_port_setup(dev, i, true); ksz9477_port_setup(dev, i, true);
p->on = 1;
} }
} }
for (i = 0; i < dev->info->port_cnt; i++) { for (i = 0; i < dev->info->port_cnt; i++) {
if (i == dev->cpu_port) if (i == dev->cpu_port)
continue; continue;
p = &dev->ports[i];
ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
p->on = 1;
if (i < dev->phy_port_cnt)
p->phy = 1;
if (dev->chip_id == 0x00947700 && i == 6) {
p->sgmii = 1;
/* SGMII PHY detection code is not implemented yet. */
p->phy = 0;
}
} }
} }
...@@ -1158,29 +1164,6 @@ int ksz9477_switch_init(struct ksz_device *dev) ...@@ -1158,29 +1164,6 @@ int ksz9477_switch_init(struct ksz_device *dev)
if (ret) if (ret)
return ret; return ret;
ret = ksz_read8(dev, REG_GLOBAL_OPTIONS, &data8);
if (ret)
return ret;
/* Number of ports can be reduced depending on chip. */
dev->phy_port_cnt = 5;
/* Default capability is gigabit capable. */
dev->features = GBIT_SUPPORT;
if (dev->chip_id == KSZ9893_CHIP_ID) {
dev->features |= IS_9893;
/* Chip does not support gigabit. */
if (data8 & SW_QW_ABLE)
dev->features &= ~GBIT_SUPPORT;
dev->phy_port_cnt = 2;
} else {
/* Chip does not support gigabit. */
if (!(data8 & SW_GIGABIT_ABLE))
dev->features &= ~GBIT_SUPPORT;
}
return 0; return 0;
} }
......
...@@ -16,8 +16,8 @@ u32 ksz9477_get_port_addr(int port, int offset); ...@@ -16,8 +16,8 @@ u32 ksz9477_get_port_addr(int port, int offset);
void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member); void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member);
void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port); void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port);
void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port); void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port);
void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data);
void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val);
void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt);
void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt); u64 *dropped, u64 *cnt);
......
...@@ -412,7 +412,422 @@ static const u8 lan937x_shifts[] = { ...@@ -412,7 +412,422 @@ static const u8 lan937x_shifts[] = {
[ALU_STAT_INDEX] = 8, [ALU_STAT_INDEX] = 8,
}; };
static const struct regmap_range ksz8563_valid_regs[] = {
regmap_reg_range(0x0000, 0x0003),
regmap_reg_range(0x0006, 0x0006),
regmap_reg_range(0x000f, 0x001f),
regmap_reg_range(0x0100, 0x0100),
regmap_reg_range(0x0104, 0x0107),
regmap_reg_range(0x010d, 0x010d),
regmap_reg_range(0x0110, 0x0113),
regmap_reg_range(0x0120, 0x012b),
regmap_reg_range(0x0201, 0x0201),
regmap_reg_range(0x0210, 0x0213),
regmap_reg_range(0x0300, 0x0300),
regmap_reg_range(0x0302, 0x031b),
regmap_reg_range(0x0320, 0x032b),
regmap_reg_range(0x0330, 0x0336),
regmap_reg_range(0x0338, 0x033e),
regmap_reg_range(0x0340, 0x035f),
regmap_reg_range(0x0370, 0x0370),
regmap_reg_range(0x0378, 0x0378),
regmap_reg_range(0x037c, 0x037d),
regmap_reg_range(0x0390, 0x0393),
regmap_reg_range(0x0400, 0x040e),
regmap_reg_range(0x0410, 0x042f),
regmap_reg_range(0x0500, 0x0519),
regmap_reg_range(0x0520, 0x054b),
regmap_reg_range(0x0550, 0x05b3),
/* port 1 */
regmap_reg_range(0x1000, 0x1001),
regmap_reg_range(0x1004, 0x100b),
regmap_reg_range(0x1013, 0x1013),
regmap_reg_range(0x1017, 0x1017),
regmap_reg_range(0x101b, 0x101b),
regmap_reg_range(0x101f, 0x1021),
regmap_reg_range(0x1030, 0x1030),
regmap_reg_range(0x1100, 0x1111),
regmap_reg_range(0x111a, 0x111d),
regmap_reg_range(0x1122, 0x1127),
regmap_reg_range(0x112a, 0x112b),
regmap_reg_range(0x1136, 0x1139),
regmap_reg_range(0x113e, 0x113f),
regmap_reg_range(0x1400, 0x1401),
regmap_reg_range(0x1403, 0x1403),
regmap_reg_range(0x1410, 0x1417),
regmap_reg_range(0x1420, 0x1423),
regmap_reg_range(0x1500, 0x1507),
regmap_reg_range(0x1600, 0x1612),
regmap_reg_range(0x1800, 0x180f),
regmap_reg_range(0x1900, 0x1907),
regmap_reg_range(0x1914, 0x191b),
regmap_reg_range(0x1a00, 0x1a03),
regmap_reg_range(0x1a04, 0x1a08),
regmap_reg_range(0x1b00, 0x1b01),
regmap_reg_range(0x1b04, 0x1b04),
regmap_reg_range(0x1c00, 0x1c05),
regmap_reg_range(0x1c08, 0x1c1b),
/* port 2 */
regmap_reg_range(0x2000, 0x2001),
regmap_reg_range(0x2004, 0x200b),
regmap_reg_range(0x2013, 0x2013),
regmap_reg_range(0x2017, 0x2017),
regmap_reg_range(0x201b, 0x201b),
regmap_reg_range(0x201f, 0x2021),
regmap_reg_range(0x2030, 0x2030),
regmap_reg_range(0x2100, 0x2111),
regmap_reg_range(0x211a, 0x211d),
regmap_reg_range(0x2122, 0x2127),
regmap_reg_range(0x212a, 0x212b),
regmap_reg_range(0x2136, 0x2139),
regmap_reg_range(0x213e, 0x213f),
regmap_reg_range(0x2400, 0x2401),
regmap_reg_range(0x2403, 0x2403),
regmap_reg_range(0x2410, 0x2417),
regmap_reg_range(0x2420, 0x2423),
regmap_reg_range(0x2500, 0x2507),
regmap_reg_range(0x2600, 0x2612),
regmap_reg_range(0x2800, 0x280f),
regmap_reg_range(0x2900, 0x2907),
regmap_reg_range(0x2914, 0x291b),
regmap_reg_range(0x2a00, 0x2a03),
regmap_reg_range(0x2a04, 0x2a08),
regmap_reg_range(0x2b00, 0x2b01),
regmap_reg_range(0x2b04, 0x2b04),
regmap_reg_range(0x2c00, 0x2c05),
regmap_reg_range(0x2c08, 0x2c1b),
/* port 3 */
regmap_reg_range(0x3000, 0x3001),
regmap_reg_range(0x3004, 0x300b),
regmap_reg_range(0x3013, 0x3013),
regmap_reg_range(0x3017, 0x3017),
regmap_reg_range(0x301b, 0x301b),
regmap_reg_range(0x301f, 0x3021),
regmap_reg_range(0x3030, 0x3030),
regmap_reg_range(0x3300, 0x3301),
regmap_reg_range(0x3303, 0x3303),
regmap_reg_range(0x3400, 0x3401),
regmap_reg_range(0x3403, 0x3403),
regmap_reg_range(0x3410, 0x3417),
regmap_reg_range(0x3420, 0x3423),
regmap_reg_range(0x3500, 0x3507),
regmap_reg_range(0x3600, 0x3612),
regmap_reg_range(0x3800, 0x380f),
regmap_reg_range(0x3900, 0x3907),
regmap_reg_range(0x3914, 0x391b),
regmap_reg_range(0x3a00, 0x3a03),
regmap_reg_range(0x3a04, 0x3a08),
regmap_reg_range(0x3b00, 0x3b01),
regmap_reg_range(0x3b04, 0x3b04),
regmap_reg_range(0x3c00, 0x3c05),
regmap_reg_range(0x3c08, 0x3c1b),
};
static const struct regmap_access_table ksz8563_register_set = {
.yes_ranges = ksz8563_valid_regs,
.n_yes_ranges = ARRAY_SIZE(ksz8563_valid_regs),
};
static const struct regmap_range ksz9477_valid_regs[] = {
regmap_reg_range(0x0000, 0x0003),
regmap_reg_range(0x0006, 0x0006),
regmap_reg_range(0x0010, 0x001f),
regmap_reg_range(0x0100, 0x0100),
regmap_reg_range(0x0103, 0x0107),
regmap_reg_range(0x010d, 0x010d),
regmap_reg_range(0x0110, 0x0113),
regmap_reg_range(0x0120, 0x012b),
regmap_reg_range(0x0201, 0x0201),
regmap_reg_range(0x0210, 0x0213),
regmap_reg_range(0x0300, 0x0300),
regmap_reg_range(0x0302, 0x031b),
regmap_reg_range(0x0320, 0x032b),
regmap_reg_range(0x0330, 0x0336),
regmap_reg_range(0x0338, 0x033e),
regmap_reg_range(0x0340, 0x035f),
regmap_reg_range(0x0370, 0x0370),
regmap_reg_range(0x0378, 0x0378),
regmap_reg_range(0x037c, 0x037d),
regmap_reg_range(0x0390, 0x0393),
regmap_reg_range(0x0400, 0x040e),
regmap_reg_range(0x0410, 0x042f),
regmap_reg_range(0x0444, 0x044b),
regmap_reg_range(0x0450, 0x046f),
regmap_reg_range(0x0500, 0x0519),
regmap_reg_range(0x0520, 0x054b),
regmap_reg_range(0x0550, 0x05b3),
regmap_reg_range(0x0604, 0x060b),
regmap_reg_range(0x0610, 0x0612),
regmap_reg_range(0x0614, 0x062c),
regmap_reg_range(0x0640, 0x0645),
regmap_reg_range(0x0648, 0x064d),
/* port 1 */
regmap_reg_range(0x1000, 0x1001),
regmap_reg_range(0x1013, 0x1013),
regmap_reg_range(0x1017, 0x1017),
regmap_reg_range(0x101b, 0x101b),
regmap_reg_range(0x101f, 0x1020),
regmap_reg_range(0x1030, 0x1030),
regmap_reg_range(0x1100, 0x1115),
regmap_reg_range(0x111a, 0x111f),
regmap_reg_range(0x1122, 0x1127),
regmap_reg_range(0x112a, 0x112b),
regmap_reg_range(0x1136, 0x1139),
regmap_reg_range(0x113e, 0x113f),
regmap_reg_range(0x1400, 0x1401),
regmap_reg_range(0x1403, 0x1403),
regmap_reg_range(0x1410, 0x1417),
regmap_reg_range(0x1420, 0x1423),
regmap_reg_range(0x1500, 0x1507),
regmap_reg_range(0x1600, 0x1613),
regmap_reg_range(0x1800, 0x180f),
regmap_reg_range(0x1820, 0x1827),
regmap_reg_range(0x1830, 0x1837),
regmap_reg_range(0x1840, 0x184b),
regmap_reg_range(0x1900, 0x1907),
regmap_reg_range(0x1914, 0x191b),
regmap_reg_range(0x1920, 0x1920),
regmap_reg_range(0x1923, 0x1927),
regmap_reg_range(0x1a00, 0x1a03),
regmap_reg_range(0x1a04, 0x1a07),
regmap_reg_range(0x1b00, 0x1b01),
regmap_reg_range(0x1b04, 0x1b04),
regmap_reg_range(0x1c00, 0x1c05),
regmap_reg_range(0x1c08, 0x1c1b),
/* port 2 */
regmap_reg_range(0x2000, 0x2001),
regmap_reg_range(0x2013, 0x2013),
regmap_reg_range(0x2017, 0x2017),
regmap_reg_range(0x201b, 0x201b),
regmap_reg_range(0x201f, 0x2020),
regmap_reg_range(0x2030, 0x2030),
regmap_reg_range(0x2100, 0x2115),
regmap_reg_range(0x211a, 0x211f),
regmap_reg_range(0x2122, 0x2127),
regmap_reg_range(0x212a, 0x212b),
regmap_reg_range(0x2136, 0x2139),
regmap_reg_range(0x213e, 0x213f),
regmap_reg_range(0x2400, 0x2401),
regmap_reg_range(0x2403, 0x2403),
regmap_reg_range(0x2410, 0x2417),
regmap_reg_range(0x2420, 0x2423),
regmap_reg_range(0x2500, 0x2507),
regmap_reg_range(0x2600, 0x2613),
regmap_reg_range(0x2800, 0x280f),
regmap_reg_range(0x2820, 0x2827),
regmap_reg_range(0x2830, 0x2837),
regmap_reg_range(0x2840, 0x284b),
regmap_reg_range(0x2900, 0x2907),
regmap_reg_range(0x2914, 0x291b),
regmap_reg_range(0x2920, 0x2920),
regmap_reg_range(0x2923, 0x2927),
regmap_reg_range(0x2a00, 0x2a03),
regmap_reg_range(0x2a04, 0x2a07),
regmap_reg_range(0x2b00, 0x2b01),
regmap_reg_range(0x2b04, 0x2b04),
regmap_reg_range(0x2c00, 0x2c05),
regmap_reg_range(0x2c08, 0x2c1b),
/* port 3 */
regmap_reg_range(0x3000, 0x3001),
regmap_reg_range(0x3013, 0x3013),
regmap_reg_range(0x3017, 0x3017),
regmap_reg_range(0x301b, 0x301b),
regmap_reg_range(0x301f, 0x3020),
regmap_reg_range(0x3030, 0x3030),
regmap_reg_range(0x3100, 0x3115),
regmap_reg_range(0x311a, 0x311f),
regmap_reg_range(0x3122, 0x3127),
regmap_reg_range(0x312a, 0x312b),
regmap_reg_range(0x3136, 0x3139),
regmap_reg_range(0x313e, 0x313f),
regmap_reg_range(0x3400, 0x3401),
regmap_reg_range(0x3403, 0x3403),
regmap_reg_range(0x3410, 0x3417),
regmap_reg_range(0x3420, 0x3423),
regmap_reg_range(0x3500, 0x3507),
regmap_reg_range(0x3600, 0x3613),
regmap_reg_range(0x3800, 0x380f),
regmap_reg_range(0x3820, 0x3827),
regmap_reg_range(0x3830, 0x3837),
regmap_reg_range(0x3840, 0x384b),
regmap_reg_range(0x3900, 0x3907),
regmap_reg_range(0x3914, 0x391b),
regmap_reg_range(0x3920, 0x3920),
regmap_reg_range(0x3923, 0x3927),
regmap_reg_range(0x3a00, 0x3a03),
regmap_reg_range(0x3a04, 0x3a07),
regmap_reg_range(0x3b00, 0x3b01),
regmap_reg_range(0x3b04, 0x3b04),
regmap_reg_range(0x3c00, 0x3c05),
regmap_reg_range(0x3c08, 0x3c1b),
/* port 4 */
regmap_reg_range(0x4000, 0x4001),
regmap_reg_range(0x4013, 0x4013),
regmap_reg_range(0x4017, 0x4017),
regmap_reg_range(0x401b, 0x401b),
regmap_reg_range(0x401f, 0x4020),
regmap_reg_range(0x4030, 0x4030),
regmap_reg_range(0x4100, 0x4115),
regmap_reg_range(0x411a, 0x411f),
regmap_reg_range(0x4122, 0x4127),
regmap_reg_range(0x412a, 0x412b),
regmap_reg_range(0x4136, 0x4139),
regmap_reg_range(0x413e, 0x413f),
regmap_reg_range(0x4400, 0x4401),
regmap_reg_range(0x4403, 0x4403),
regmap_reg_range(0x4410, 0x4417),
regmap_reg_range(0x4420, 0x4423),
regmap_reg_range(0x4500, 0x4507),
regmap_reg_range(0x4600, 0x4613),
regmap_reg_range(0x4800, 0x480f),
regmap_reg_range(0x4820, 0x4827),
regmap_reg_range(0x4830, 0x4837),
regmap_reg_range(0x4840, 0x484b),
regmap_reg_range(0x4900, 0x4907),
regmap_reg_range(0x4914, 0x491b),
regmap_reg_range(0x4920, 0x4920),
regmap_reg_range(0x4923, 0x4927),
regmap_reg_range(0x4a00, 0x4a03),
regmap_reg_range(0x4a04, 0x4a07),
regmap_reg_range(0x4b00, 0x4b01),
regmap_reg_range(0x4b04, 0x4b04),
regmap_reg_range(0x4c00, 0x4c05),
regmap_reg_range(0x4c08, 0x4c1b),
/* port 5 */
regmap_reg_range(0x5000, 0x5001),
regmap_reg_range(0x5013, 0x5013),
regmap_reg_range(0x5017, 0x5017),
regmap_reg_range(0x501b, 0x501b),
regmap_reg_range(0x501f, 0x5020),
regmap_reg_range(0x5030, 0x5030),
regmap_reg_range(0x5100, 0x5115),
regmap_reg_range(0x511a, 0x511f),
regmap_reg_range(0x5122, 0x5127),
regmap_reg_range(0x512a, 0x512b),
regmap_reg_range(0x5136, 0x5139),
regmap_reg_range(0x513e, 0x513f),
regmap_reg_range(0x5400, 0x5401),
regmap_reg_range(0x5403, 0x5403),
regmap_reg_range(0x5410, 0x5417),
regmap_reg_range(0x5420, 0x5423),
regmap_reg_range(0x5500, 0x5507),
regmap_reg_range(0x5600, 0x5613),
regmap_reg_range(0x5800, 0x580f),
regmap_reg_range(0x5820, 0x5827),
regmap_reg_range(0x5830, 0x5837),
regmap_reg_range(0x5840, 0x584b),
regmap_reg_range(0x5900, 0x5907),
regmap_reg_range(0x5914, 0x591b),
regmap_reg_range(0x5920, 0x5920),
regmap_reg_range(0x5923, 0x5927),
regmap_reg_range(0x5a00, 0x5a03),
regmap_reg_range(0x5a04, 0x5a07),
regmap_reg_range(0x5b00, 0x5b01),
regmap_reg_range(0x5b04, 0x5b04),
regmap_reg_range(0x5c00, 0x5c05),
regmap_reg_range(0x5c08, 0x5c1b),
/* port 6 */
regmap_reg_range(0x6000, 0x6001),
regmap_reg_range(0x6013, 0x6013),
regmap_reg_range(0x6017, 0x6017),
regmap_reg_range(0x601b, 0x601b),
regmap_reg_range(0x601f, 0x6020),
regmap_reg_range(0x6030, 0x6030),
regmap_reg_range(0x6300, 0x6301),
regmap_reg_range(0x6400, 0x6401),
regmap_reg_range(0x6403, 0x6403),
regmap_reg_range(0x6410, 0x6417),
regmap_reg_range(0x6420, 0x6423),
regmap_reg_range(0x6500, 0x6507),
regmap_reg_range(0x6600, 0x6613),
regmap_reg_range(0x6800, 0x680f),
regmap_reg_range(0x6820, 0x6827),
regmap_reg_range(0x6830, 0x6837),
regmap_reg_range(0x6840, 0x684b),
regmap_reg_range(0x6900, 0x6907),
regmap_reg_range(0x6914, 0x691b),
regmap_reg_range(0x6920, 0x6920),
regmap_reg_range(0x6923, 0x6927),
regmap_reg_range(0x6a00, 0x6a03),
regmap_reg_range(0x6a04, 0x6a07),
regmap_reg_range(0x6b00, 0x6b01),
regmap_reg_range(0x6b04, 0x6b04),
regmap_reg_range(0x6c00, 0x6c05),
regmap_reg_range(0x6c08, 0x6c1b),
/* port 7 */
regmap_reg_range(0x7000, 0x7001),
regmap_reg_range(0x7013, 0x7013),
regmap_reg_range(0x7017, 0x7017),
regmap_reg_range(0x701b, 0x701b),
regmap_reg_range(0x701f, 0x7020),
regmap_reg_range(0x7030, 0x7030),
regmap_reg_range(0x7200, 0x7203),
regmap_reg_range(0x7206, 0x7207),
regmap_reg_range(0x7300, 0x7301),
regmap_reg_range(0x7400, 0x7401),
regmap_reg_range(0x7403, 0x7403),
regmap_reg_range(0x7410, 0x7417),
regmap_reg_range(0x7420, 0x7423),
regmap_reg_range(0x7500, 0x7507),
regmap_reg_range(0x7600, 0x7613),
regmap_reg_range(0x7800, 0x780f),
regmap_reg_range(0x7820, 0x7827),
regmap_reg_range(0x7830, 0x7837),
regmap_reg_range(0x7840, 0x784b),
regmap_reg_range(0x7900, 0x7907),
regmap_reg_range(0x7914, 0x791b),
regmap_reg_range(0x7920, 0x7920),
regmap_reg_range(0x7923, 0x7927),
regmap_reg_range(0x7a00, 0x7a03),
regmap_reg_range(0x7a04, 0x7a07),
regmap_reg_range(0x7b00, 0x7b01),
regmap_reg_range(0x7b04, 0x7b04),
regmap_reg_range(0x7c00, 0x7c05),
regmap_reg_range(0x7c08, 0x7c1b),
};
static const struct regmap_access_table ksz9477_register_set = {
.yes_ranges = ksz9477_valid_regs,
.n_yes_ranges = ARRAY_SIZE(ksz9477_valid_regs),
};
const struct ksz_chip_data ksz_switch_chips[] = { const struct ksz_chip_data ksz_switch_chips[] = {
[KSZ8563] = {
.chip_id = KSZ8563_CHIP_ID,
.dev_name = "KSZ8563",
.num_vlans = 4096,
.num_alus = 4096,
.num_statics = 16,
.cpu_ports = 0x07, /* can be configured as cpu port */
.port_cnt = 3, /* total port count */
.ops = &ksz9477_dev_ops,
.mib_names = ksz9477_mib_names,
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
.reg_mib_cnt = MIB_COUNTER_NUM,
.regs = ksz9477_regs,
.masks = ksz9477_masks,
.shifts = ksz9477_shifts,
.xmii_ctrl0 = ksz9477_xmii_ctrl0,
.xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */
.supports_mii = {false, false, true},
.supports_rmii = {false, false, true},
.supports_rgmii = {false, false, true},
.internal_phy = {true, true, false},
.gbit_capable = {false, false, true},
.wr_table = &ksz8563_register_set,
.rd_table = &ksz8563_register_set,
},
[KSZ8795] = { [KSZ8795] = {
.chip_id = KSZ8795_CHIP_ID, .chip_id = KSZ8795_CHIP_ID,
.dev_name = "KSZ8795", .dev_name = "KSZ8795",
...@@ -545,6 +960,9 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -545,6 +960,9 @@ const struct ksz_chip_data ksz_switch_chips[] = {
false, true, false}, false, true, false},
.internal_phy = {true, true, true, true, .internal_phy = {true, true, true, true,
true, false, false}, true, false, false},
.gbit_capable = {true, true, true, true, true, true, true},
.wr_table = &ksz9477_register_set,
.rd_table = &ksz9477_register_set,
}, },
[KSZ9897] = { [KSZ9897] = {
...@@ -573,6 +991,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -573,6 +991,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
false, true, true}, false, true, true},
.internal_phy = {true, true, true, true, .internal_phy = {true, true, true, true,
true, false, false}, true, false, false},
.gbit_capable = {true, true, true, true, true, true, true},
}, },
[KSZ9893] = { [KSZ9893] = {
...@@ -596,6 +1015,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -596,6 +1015,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.supports_rmii = {false, false, true}, .supports_rmii = {false, false, true},
.supports_rgmii = {false, false, true}, .supports_rgmii = {false, false, true},
.internal_phy = {true, true, false}, .internal_phy = {true, true, false},
.gbit_capable = {true, true, true},
}, },
[KSZ9567] = { [KSZ9567] = {
...@@ -624,6 +1044,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { ...@@ -624,6 +1044,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
false, true, true}, false, true, true},
.internal_phy = {true, true, true, true, .internal_phy = {true, true, true, true,
true, false, false}, true, false, false},
.gbit_capable = {true, true, true, true, true, true, true},
}, },
[LAN9370] = { [LAN9370] = {
...@@ -1104,8 +1525,11 @@ static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) ...@@ -1104,8 +1525,11 @@ static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
u16 val = 0xffff; u16 val = 0xffff;
int ret;
dev->dev_ops->r_phy(dev, addr, reg, &val); ret = dev->dev_ops->r_phy(dev, addr, reg, &val);
if (ret)
return ret;
return val; return val;
} }
...@@ -1113,8 +1537,11 @@ static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) ...@@ -1113,8 +1537,11 @@ static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
int ret;
dev->dev_ops->w_phy(dev, addr, reg, val); ret = dev->dev_ops->w_phy(dev, addr, reg, val);
if (ret)
return ret;
return 0; return 0;
} }
...@@ -1366,6 +1793,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, ...@@ -1366,6 +1793,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
proto = DSA_TAG_PROTO_KSZ8795; proto = DSA_TAG_PROTO_KSZ8795;
if (dev->chip_id == KSZ8830_CHIP_ID || if (dev->chip_id == KSZ8830_CHIP_ID ||
dev->chip_id == KSZ8563_CHIP_ID ||
dev->chip_id == KSZ9893_CHIP_ID) dev->chip_id == KSZ9893_CHIP_ID)
proto = DSA_TAG_PROTO_KSZ9893; proto = DSA_TAG_PROTO_KSZ9893;
...@@ -1484,7 +1912,8 @@ static void ksz_set_xmii(struct ksz_device *dev, int port, ...@@ -1484,7 +1912,8 @@ static void ksz_set_xmii(struct ksz_device *dev, int port,
case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_RXID:
data8 |= bitval[P_RGMII_SEL]; data8 |= bitval[P_RGMII_SEL];
/* On KSZ9893, disable RGMII in-band status support */ /* On KSZ9893, disable RGMII in-band status support */
if (dev->features & IS_9893) if (dev->chip_id == KSZ9893_CHIP_ID ||
dev->chip_id == KSZ8563_CHIP_ID)
data8 &= ~P_MII_MAC_MODE; data8 &= ~P_MII_MAC_MODE;
break; break;
default: default:
...@@ -1685,7 +2114,7 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port, ...@@ -1685,7 +2114,7 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
static int ksz_switch_detect(struct ksz_device *dev) static int ksz_switch_detect(struct ksz_device *dev)
{ {
u8 id1, id2; u8 id1, id2, id4;
u16 id16; u16 id16;
u32 id32; u32 id32;
int ret; int ret;
...@@ -1731,7 +2160,6 @@ static int ksz_switch_detect(struct ksz_device *dev) ...@@ -1731,7 +2160,6 @@ static int ksz_switch_detect(struct ksz_device *dev)
switch (id32) { switch (id32) {
case KSZ9477_CHIP_ID: case KSZ9477_CHIP_ID:
case KSZ9897_CHIP_ID: case KSZ9897_CHIP_ID:
case KSZ9893_CHIP_ID:
case KSZ9567_CHIP_ID: case KSZ9567_CHIP_ID:
case LAN9370_CHIP_ID: case LAN9370_CHIP_ID:
case LAN9371_CHIP_ID: case LAN9371_CHIP_ID:
...@@ -1739,6 +2167,18 @@ static int ksz_switch_detect(struct ksz_device *dev) ...@@ -1739,6 +2167,18 @@ static int ksz_switch_detect(struct ksz_device *dev)
case LAN9373_CHIP_ID: case LAN9373_CHIP_ID:
case LAN9374_CHIP_ID: case LAN9374_CHIP_ID:
dev->chip_id = id32; dev->chip_id = id32;
break;
case KSZ9893_CHIP_ID:
ret = ksz_read8(dev, REG_CHIP_ID4,
&id4);
if (ret)
return ret;
if (id4 == SKU_ID_KSZ8563)
dev->chip_id = KSZ8563_CHIP_ID;
else
dev->chip_id = KSZ9893_CHIP_ID;
break; break;
default: default:
dev_err(dev->dev, dev_err(dev->dev,
......
...@@ -61,6 +61,9 @@ struct ksz_chip_data { ...@@ -61,6 +61,9 @@ struct ksz_chip_data {
bool supports_rmii[KSZ_MAX_NUM_PORTS]; bool supports_rmii[KSZ_MAX_NUM_PORTS];
bool supports_rgmii[KSZ_MAX_NUM_PORTS]; bool supports_rgmii[KSZ_MAX_NUM_PORTS];
bool internal_phy[KSZ_MAX_NUM_PORTS]; bool internal_phy[KSZ_MAX_NUM_PORTS];
bool gbit_capable[KSZ_MAX_NUM_PORTS];
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
}; };
struct ksz_port { struct ksz_port {
...@@ -70,9 +73,7 @@ struct ksz_port { ...@@ -70,9 +73,7 @@ struct ksz_port {
struct phy_device phydev; struct phy_device phydev;
u32 on:1; /* port is not disabled by hardware */ u32 on:1; /* port is not disabled by hardware */
u32 phy:1; /* port has a PHY */
u32 fiber:1; /* port is fiber */ u32 fiber:1; /* port is fiber */
u32 sgmii:1; /* port is SGMII */
u32 force:1; u32 force:1;
u32 read:1; /* read MIB counters in background */ u32 read:1; /* read MIB counters in background */
u32 freeze:1; /* MIB counter freeze is enabled */ u32 freeze:1; /* MIB counter freeze is enabled */
...@@ -118,12 +119,12 @@ struct ksz_device { ...@@ -118,12 +119,12 @@ struct ksz_device {
unsigned long mib_read_interval; unsigned long mib_read_interval;
u16 mirror_rx; u16 mirror_rx;
u16 mirror_tx; u16 mirror_tx;
u32 features; /* chip specific features */
u16 port_mask; u16 port_mask;
}; };
/* List of supported models */ /* List of supported models */
enum ksz_model { enum ksz_model {
KSZ8563,
KSZ8795, KSZ8795,
KSZ8794, KSZ8794,
KSZ8765, KSZ8765,
...@@ -140,6 +141,7 @@ enum ksz_model { ...@@ -140,6 +141,7 @@ enum ksz_model {
}; };
enum ksz_chip_id { enum ksz_chip_id {
KSZ8563_CHIP_ID = 0x8563,
KSZ8795_CHIP_ID = 0x8795, KSZ8795_CHIP_ID = 0x8795,
KSZ8794_CHIP_ID = 0x8794, KSZ8794_CHIP_ID = 0x8794,
KSZ8765_CHIP_ID = 0x8765, KSZ8765_CHIP_ID = 0x8765,
...@@ -259,8 +261,8 @@ struct ksz_dev_ops { ...@@ -259,8 +261,8 @@ struct ksz_dev_ops {
void (*flush_dyn_mac_table)(struct ksz_device *dev, int port); void (*flush_dyn_mac_table)(struct ksz_device *dev, int port);
void (*port_cleanup)(struct ksz_device *dev, int port); void (*port_cleanup)(struct ksz_device *dev, int port);
void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port); void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port);
void (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); int (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
void (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); int (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val);
void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr,
u64 *cnt); u64 *cnt);
void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr,
...@@ -330,6 +332,10 @@ static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) ...@@ -330,6 +332,10 @@ static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val)
unsigned int value; unsigned int value;
int ret = regmap_read(dev->regmap[0], reg, &value); int ret = regmap_read(dev->regmap[0], reg, &value);
if (ret)
dev_err(dev->dev, "can't read 8bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
*val = value; *val = value;
return ret; return ret;
} }
...@@ -339,6 +345,10 @@ static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) ...@@ -339,6 +345,10 @@ static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val)
unsigned int value; unsigned int value;
int ret = regmap_read(dev->regmap[1], reg, &value); int ret = regmap_read(dev->regmap[1], reg, &value);
if (ret)
dev_err(dev->dev, "can't read 16bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
*val = value; *val = value;
return ret; return ret;
} }
...@@ -348,6 +358,10 @@ static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) ...@@ -348,6 +358,10 @@ static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val)
unsigned int value; unsigned int value;
int ret = regmap_read(dev->regmap[2], reg, &value); int ret = regmap_read(dev->regmap[2], reg, &value);
if (ret)
dev_err(dev->dev, "can't read 32bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
*val = value; *val = value;
return ret; return ret;
} }
...@@ -358,7 +372,10 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val) ...@@ -358,7 +372,10 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val)
int ret; int ret;
ret = regmap_bulk_read(dev->regmap[2], reg, value, 2); ret = regmap_bulk_read(dev->regmap[2], reg, value, 2);
if (!ret) if (ret)
dev_err(dev->dev, "can't read 64bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
else
*val = (u64)value[0] << 32 | value[1]; *val = (u64)value[0] << 32 | value[1];
return ret; return ret;
...@@ -366,17 +383,38 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val) ...@@ -366,17 +383,38 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val)
static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value) static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value)
{ {
return regmap_write(dev->regmap[0], reg, value); int ret;
ret = regmap_write(dev->regmap[0], reg, value);
if (ret)
dev_err(dev->dev, "can't write 8bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
return ret;
} }
static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value)
{ {
return regmap_write(dev->regmap[1], reg, value); int ret;
ret = regmap_write(dev->regmap[1], reg, value);
if (ret)
dev_err(dev->dev, "can't write 16bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
return ret;
} }
static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value)
{ {
return regmap_write(dev->regmap[2], reg, value); int ret;
ret = regmap_write(dev->regmap[2], reg, value);
if (ret)
dev_err(dev->dev, "can't write 32bit reg: 0x%x %pe\n", reg,
ERR_PTR(ret));
return ret;
} }
static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value)
...@@ -391,40 +429,42 @@ static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) ...@@ -391,40 +429,42 @@ static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value)
return regmap_bulk_write(dev->regmap[2], reg, val, 2); return regmap_bulk_write(dev->regmap[2], reg, val, 2);
} }
static inline void ksz_pread8(struct ksz_device *dev, int port, int offset, static inline int ksz_pread8(struct ksz_device *dev, int port, int offset,
u8 *data) u8 *data)
{ {
ksz_read8(dev, dev->dev_ops->get_port_addr(port, offset), data); return ksz_read8(dev, dev->dev_ops->get_port_addr(port, offset), data);
} }
static inline void ksz_pread16(struct ksz_device *dev, int port, int offset, static inline int ksz_pread16(struct ksz_device *dev, int port, int offset,
u16 *data) u16 *data)
{ {
ksz_read16(dev, dev->dev_ops->get_port_addr(port, offset), data); return ksz_read16(dev, dev->dev_ops->get_port_addr(port, offset), data);
} }
static inline void ksz_pread32(struct ksz_device *dev, int port, int offset, static inline int ksz_pread32(struct ksz_device *dev, int port, int offset,
u32 *data) u32 *data)
{ {
ksz_read32(dev, dev->dev_ops->get_port_addr(port, offset), data); return ksz_read32(dev, dev->dev_ops->get_port_addr(port, offset), data);
} }
static inline void ksz_pwrite8(struct ksz_device *dev, int port, int offset, static inline int ksz_pwrite8(struct ksz_device *dev, int port, int offset,
u8 data) u8 data)
{ {
ksz_write8(dev, dev->dev_ops->get_port_addr(port, offset), data); return ksz_write8(dev, dev->dev_ops->get_port_addr(port, offset), data);
} }
static inline void ksz_pwrite16(struct ksz_device *dev, int port, int offset, static inline int ksz_pwrite16(struct ksz_device *dev, int port, int offset,
u16 data) u16 data)
{ {
ksz_write16(dev, dev->dev_ops->get_port_addr(port, offset), data); return ksz_write16(dev, dev->dev_ops->get_port_addr(port, offset),
data);
} }
static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, static inline int ksz_pwrite32(struct ksz_device *dev, int port, int offset,
u32 data) u32 data)
{ {
ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); return ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset),
data);
} }
static inline void ksz_prmw8(struct ksz_device *dev, int port, int offset, static inline void ksz_prmw8(struct ksz_device *dev, int port, int offset,
...@@ -483,6 +523,10 @@ static inline int is_lan937x(struct ksz_device *dev) ...@@ -483,6 +523,10 @@ static inline int is_lan937x(struct ksz_device *dev)
#define SW_REV_ID_M GENMASK(7, 4) #define SW_REV_ID_M GENMASK(7, 4)
/* KSZ9893, KSZ9563, KSZ8563 specific register */
#define REG_CHIP_ID4 0x0f
#define SKU_ID_KSZ8563 0x3c
/* Driver set switch broadcast storm protection at 10% rate. */ /* Driver set switch broadcast storm protection at 10% rate. */
#define BROADCAST_STORM_PROT_RATE 10 #define BROADCAST_STORM_PROT_RATE 10
...@@ -497,10 +541,6 @@ static inline int is_lan937x(struct ksz_device *dev) ...@@ -497,10 +541,6 @@ static inline int is_lan937x(struct ksz_device *dev)
#define SW_START 0x01 #define SW_START 0x01
/* Used with variable features to indicate capabilities. */
#define GBIT_SUPPORT BIT(0)
#define IS_9893 BIT(2)
/* xMII configuration */ /* xMII configuration */
#define P_MII_DUPLEX_M BIT(6) #define P_MII_DUPLEX_M BIT(6)
#define P_MII_100MBIT_M BIT(4) #define P_MII_100MBIT_M BIT(4)
......
...@@ -66,7 +66,10 @@ static int ksz_spi_probe(struct spi_device *spi) ...@@ -66,7 +66,10 @@ static int ksz_spi_probe(struct spi_device *spi)
for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
rc = regmap_config[i]; rc = regmap_config[i];
rc.lock_arg = &dev->regmap_mutex; rc.lock_arg = &dev->regmap_mutex;
rc.wr_table = chip->wr_table;
rc.rd_table = chip->rd_table;
dev->regmap[i] = devm_regmap_init_spi(spi, &rc); dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
if (IS_ERR(dev->regmap[i])) { if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]); ret = PTR_ERR(dev->regmap[i]);
dev_err(&spi->dev, dev_err(&spi->dev,
...@@ -160,7 +163,7 @@ static const struct of_device_id ksz_dt_ids[] = { ...@@ -160,7 +163,7 @@ static const struct of_device_id ksz_dt_ids[] = {
}, },
{ {
.compatible = "microchip,ksz8563", .compatible = "microchip,ksz8563",
.data = &ksz_switch_chips[KSZ9893] .data = &ksz_switch_chips[KSZ8563]
}, },
{ {
.compatible = "microchip,ksz9567", .compatible = "microchip,ksz9567",
......
...@@ -12,8 +12,8 @@ void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port); ...@@ -12,8 +12,8 @@ void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port);
void lan937x_config_cpu_port(struct dsa_switch *ds); void lan937x_config_cpu_port(struct dsa_switch *ds);
int lan937x_switch_init(struct ksz_device *dev); int lan937x_switch_init(struct ksz_device *dev);
void lan937x_switch_exit(struct ksz_device *dev); void lan937x_switch_exit(struct ksz_device *dev);
void lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data);
void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val);
int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu); int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu);
void lan937x_phylink_get_caps(struct ksz_device *dev, int port, void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config); struct phylink_config *config);
......
...@@ -128,14 +128,14 @@ static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, ...@@ -128,14 +128,14 @@ static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg,
return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); return ksz_read16(dev, REG_VPHY_IND_DATA__2, val);
} }
void lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
{ {
lan937x_internal_phy_read(dev, addr, reg, data); return lan937x_internal_phy_read(dev, addr, reg, data);
} }
void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
{ {
lan937x_internal_phy_write(dev, addr, reg, val); return lan937x_internal_phy_write(dev, addr, reg, val);
} }
static int lan937x_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) static int lan937x_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
......
...@@ -66,7 +66,7 @@ struct update_classid_context { ...@@ -66,7 +66,7 @@ struct update_classid_context {
#define UPDATE_CLASSID_BATCH 1000 #define UPDATE_CLASSID_BATCH 1000
static int update_classid_sock(const void *v, struct file *file, unsigned n) static int update_classid_sock(const void *v, struct file *file, unsigned int n)
{ {
struct update_classid_context *ctx = (void *)v; struct update_classid_context *ctx = (void *)v;
struct socket *sock = sock_from_file(file); struct socket *sock = sock_from_file(file);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment