Commit 4b20a07e authored by Oleksij Rempel's avatar Oleksij Rempel Committed by David S. Miller

net: dsa: microchip: ksz8795: add support for ksz88xx chips

We add support for the ksz8863 and ksz8873 chips which are
using the same register patterns but other offsets as the
ksz8795.
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9f73e112
...@@ -72,9 +72,60 @@ static const u8 ksz8795_shifts[] = { ...@@ -72,9 +72,60 @@ static const u8 ksz8795_shifts[] = {
[DYNAMIC_MAC_SRC_PORT] = 24, [DYNAMIC_MAC_SRC_PORT] = 24,
}; };
static const struct { static const u8 ksz8863_regs[] = {
[REG_IND_CTRL_0] = 0x79,
[REG_IND_DATA_8] = 0x7B,
[REG_IND_DATA_CHECK] = 0x7B,
[REG_IND_DATA_HI] = 0x7C,
[REG_IND_DATA_LO] = 0x80,
[REG_IND_MIB_CHECK] = 0x80,
[P_FORCE_CTRL] = 0x0C,
[P_LINK_STATUS] = 0x0E,
[P_LOCAL_CTRL] = 0x0C,
[P_NEG_RESTART_CTRL] = 0x0D,
[P_REMOTE_STATUS] = 0x0E,
[P_SPEED_STATUS] = 0x0F,
[S_TAIL_TAG_CTRL] = 0x03,
};
static const u32 ksz8863_masks[] = {
[PORT_802_1P_REMAPPING] = BIT(3),
[SW_TAIL_TAG_ENABLE] = BIT(6),
[MIB_COUNTER_OVERFLOW] = BIT(7),
[MIB_COUNTER_VALID] = BIT(6),
[VLAN_TABLE_FID] = GENMASK(15, 12),
[VLAN_TABLE_MEMBERSHIP] = GENMASK(18, 16),
[VLAN_TABLE_VALID] = BIT(19),
[STATIC_MAC_TABLE_VALID] = BIT(19),
[STATIC_MAC_TABLE_USE_FID] = BIT(21),
[STATIC_MAC_TABLE_FID] = GENMASK(29, 26),
[STATIC_MAC_TABLE_OVERRIDE] = BIT(20),
[STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16),
[DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(5, 0),
[DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7),
[DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7),
[DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 28),
[DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16),
[DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20),
[DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22),
};
static u8 ksz8863_shifts[] = {
[VLAN_TABLE_MEMBERSHIP_S] = 16,
[STATIC_MAC_FWD_PORTS] = 16,
[STATIC_MAC_FID] = 22,
[DYNAMIC_MAC_ENTRIES_H] = 3,
[DYNAMIC_MAC_ENTRIES] = 24,
[DYNAMIC_MAC_FID] = 16,
[DYNAMIC_MAC_TIMESTAMP] = 24,
[DYNAMIC_MAC_SRC_PORT] = 20,
};
struct mib_names {
char string[ETH_GSTRING_LEN]; char string[ETH_GSTRING_LEN];
} mib_names[] = { };
static const struct mib_names ksz87xx_mib_names[] = {
{ "rx_hi" }, { "rx_hi" },
{ "rx_undersize" }, { "rx_undersize" },
{ "rx_fragments" }, { "rx_fragments" },
...@@ -113,6 +164,48 @@ static const struct { ...@@ -113,6 +164,48 @@ static const struct {
{ "tx_discards" }, { "tx_discards" },
}; };
static const struct mib_names ksz88xx_mib_names[] = {
{ "rx" },
{ "rx_hi" },
{ "rx_undersize" },
{ "rx_fragments" },
{ "rx_oversize" },
{ "rx_jabbers" },
{ "rx_symbol_err" },
{ "rx_crc_err" },
{ "rx_align_err" },
{ "rx_mac_ctrl" },
{ "rx_pause" },
{ "rx_bcast" },
{ "rx_mcast" },
{ "rx_ucast" },
{ "rx_64_or_less" },
{ "rx_65_127" },
{ "rx_128_255" },
{ "rx_256_511" },
{ "rx_512_1023" },
{ "rx_1024_1522" },
{ "tx" },
{ "tx_hi" },
{ "tx_late_col" },
{ "tx_pause" },
{ "tx_bcast" },
{ "tx_mcast" },
{ "tx_ucast" },
{ "tx_deferred" },
{ "tx_total_col" },
{ "tx_exc_col" },
{ "tx_single_col" },
{ "tx_mult_col" },
{ "rx_discards" },
{ "tx_discards" },
};
static bool ksz_is_ksz88x3(struct ksz_device *dev)
{
return dev->chip_id == 0x8830;
}
static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{ {
regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
...@@ -127,10 +220,18 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, ...@@ -127,10 +220,18 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
static int ksz8_reset_switch(struct ksz_device *dev) static int ksz8_reset_switch(struct ksz_device *dev)
{ {
/* reset switch */ if (ksz_is_ksz88x3(dev)) {
ksz_write8(dev, REG_POWER_MANAGEMENT_1, /* reset switch */
SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S); ksz_cfg(dev, KSZ8863_REG_SW_RESET,
ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0); KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true);
ksz_cfg(dev, KSZ8863_REG_SW_RESET,
KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false);
} else {
/* reset switch */
ksz_write8(dev, REG_POWER_MANAGEMENT_1,
SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S);
ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0);
}
return 0; return 0;
} }
...@@ -204,8 +305,8 @@ static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt) ...@@ -204,8 +305,8 @@ static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
mutex_unlock(&dev->alu_mutex); mutex_unlock(&dev->alu_mutex);
} }
static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt) u64 *dropped, u64 *cnt)
{ {
struct ksz8 *ksz8 = dev->priv; struct ksz8 *ksz8 = dev->priv;
const u32 *masks; const u32 *masks;
...@@ -219,8 +320,8 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, ...@@ -219,8 +320,8 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
regs = ksz8->regs; regs = ksz8->regs;
addr -= dev->reg_mib_cnt; addr -= dev->reg_mib_cnt;
ctrl_addr = (KS_MIB_TOTAL_RX_1 - KS_MIB_TOTAL_RX_0) * port; ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port;
ctrl_addr += addr + KS_MIB_TOTAL_RX_0; ctrl_addr += addr + KSZ8795_MIB_TOTAL_RX_0;
ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
mutex_lock(&dev->alu_mutex); mutex_lock(&dev->alu_mutex);
...@@ -257,8 +358,52 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, ...@@ -257,8 +358,52 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
mutex_unlock(&dev->alu_mutex); mutex_unlock(&dev->alu_mutex);
} }
static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt)
{
struct ksz8 *ksz8 = dev->priv;
const u8 *regs = ksz8->regs;
u32 *last = (u32 *)dropped;
u16 ctrl_addr;
u32 data;
u32 cur;
addr -= dev->reg_mib_cnt;
ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 :
KSZ8863_MIB_PACKET_DROPPED_RX_0;
ctrl_addr += port;
ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
mutex_lock(&dev->alu_mutex);
ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
mutex_unlock(&dev->alu_mutex);
data &= MIB_PACKET_DROPPED;
cur = last[addr];
if (data != cur) {
last[addr] = data;
if (data < cur)
data += MIB_PACKET_DROPPED + 1;
data -= cur;
*cnt += data;
}
}
static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt)
{
if (ksz_is_ksz88x3(dev))
ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
else
ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
}
static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze) static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
{ {
if (ksz_is_ksz88x3(dev))
return;
/* enable the port for flush/freeze function */ /* enable the port for flush/freeze function */
if (freeze) if (freeze)
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
...@@ -272,11 +417,14 @@ static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze) ...@@ -272,11 +417,14 @@ static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
static void ksz8_port_init_cnt(struct ksz_device *dev, int port) static void ksz8_port_init_cnt(struct ksz_device *dev, int port)
{ {
struct ksz_port_mib *mib = &dev->ports[port].mib; struct ksz_port_mib *mib = &dev->ports[port].mib;
u64 *dropped;
/* flush all enabled port MIB counters */ if (!ksz_is_ksz88x3(dev)) {
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); /* flush all enabled port MIB counters */
ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true); ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false); ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
}
mib->cnt_ptr = 0; mib->cnt_ptr = 0;
...@@ -287,10 +435,13 @@ static void ksz8_port_init_cnt(struct ksz_device *dev, int port) ...@@ -287,10 +435,13 @@ static void ksz8_port_init_cnt(struct ksz_device *dev, int port)
++mib->cnt_ptr; ++mib->cnt_ptr;
} }
/* last one in storage */
dropped = &mib->counters[dev->mib_cnt];
/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */ /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
while (mib->cnt_ptr < dev->mib_cnt) { while (mib->cnt_ptr < dev->mib_cnt) {
dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr, dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
NULL, &mib->counters[mib->cnt_ptr]); dropped, &mib->counters[mib->cnt_ptr]);
++mib->cnt_ptr; ++mib->cnt_ptr;
} }
mib->cnt_ptr = 0; mib->cnt_ptr = 0;
...@@ -588,8 +739,13 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -588,8 +739,13 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data |= PHY_LOOPBACK; data |= PHY_LOOPBACK;
if (ctrl & PORT_FORCE_100_MBIT) if (ctrl & PORT_FORCE_100_MBIT)
data |= PHY_SPEED_100MBIT; data |= PHY_SPEED_100MBIT;
if (!(ctrl & PORT_AUTO_NEG_DISABLE)) if (ksz_is_ksz88x3(dev)) {
data |= PHY_AUTO_NEG_ENABLE; if ((ctrl & PORT_AUTO_NEG_ENABLE))
data |= PHY_AUTO_NEG_ENABLE;
} else {
if (!(ctrl & PORT_AUTO_NEG_DISABLE))
data |= PHY_AUTO_NEG_ENABLE;
}
if (restart & PORT_POWER_DOWN) if (restart & PORT_POWER_DOWN)
data |= PHY_POWER_DOWN; data |= PHY_POWER_DOWN;
if (restart & PORT_AUTO_NEG_RESTART) if (restart & PORT_AUTO_NEG_RESTART)
...@@ -623,7 +779,10 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) ...@@ -623,7 +779,10 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data = KSZ8795_ID_HI; data = KSZ8795_ID_HI;
break; break;
case PHY_REG_ID_2: case PHY_REG_ID_2:
data = KSZ8795_ID_LO; if (ksz_is_ksz88x3(dev))
data = KSZ8863_ID_LO;
else
data = KSZ8795_ID_LO;
break; break;
case PHY_REG_AUTO_NEGOTIATION: case PHY_REG_AUTO_NEGOTIATION:
ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
...@@ -686,14 +845,22 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -686,14 +845,22 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data);
ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
data = ctrl; data = ctrl;
if (!(val & PHY_AUTO_NEG_ENABLE)) if (ksz_is_ksz88x3(dev)) {
data |= PORT_AUTO_NEG_DISABLE; if ((val & PHY_AUTO_NEG_ENABLE))
else data |= PORT_AUTO_NEG_ENABLE;
data &= ~PORT_AUTO_NEG_DISABLE; else
data &= ~PORT_AUTO_NEG_ENABLE;
} else {
if (!(val & PHY_AUTO_NEG_ENABLE))
data |= PORT_AUTO_NEG_DISABLE;
else
data &= ~PORT_AUTO_NEG_DISABLE;
/* Fiber port does not support auto-negotiation. */
if (dev->ports[p].fiber)
data |= PORT_AUTO_NEG_DISABLE;
}
/* Fiber port does not support auto-negotiation. */
if (dev->ports[p].fiber)
data |= PORT_AUTO_NEG_DISABLE;
if (val & PHY_SPEED_100MBIT) if (val & PHY_SPEED_100MBIT)
data |= PORT_FORCE_100_MBIT; data |= PORT_FORCE_100_MBIT;
else else
...@@ -767,7 +934,11 @@ static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds, ...@@ -767,7 +934,11 @@ static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds,
int port, int port,
enum dsa_tag_protocol mp) enum dsa_tag_protocol mp)
{ {
return DSA_TAG_PROTO_KSZ8795; struct ksz_device *dev = ds->priv;
/* ksz88x3 uses the same tag schema as KSZ9893 */
return ksz_is_ksz88x3(dev) ?
DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795;
} }
static void ksz8_get_strings(struct dsa_switch *ds, int port, static void ksz8_get_strings(struct dsa_switch *ds, int port,
...@@ -777,8 +948,8 @@ static void ksz8_get_strings(struct dsa_switch *ds, int port, ...@@ -777,8 +948,8 @@ static void ksz8_get_strings(struct dsa_switch *ds, int port,
int i; int i;
for (i = 0; i < dev->mib_cnt; i++) { for (i = 0; i < dev->mib_cnt; i++) {
memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, memcpy(buf + i * ETH_GSTRING_LEN,
ETH_GSTRING_LEN); dev->mib_names[i].string, ETH_GSTRING_LEN);
} }
} }
...@@ -904,6 +1075,9 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag, ...@@ -904,6 +1075,9 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag,
{ {
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
if (ksz_is_ksz88x3(dev))
return -ENOTSUPP;
ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag); ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
return 0; return 0;
...@@ -918,6 +1092,9 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port, ...@@ -918,6 +1092,9 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port,
u16 data, new_pvid = 0; u16 data, new_pvid = 0;
u8 fid, member, valid; u8 fid, member, valid;
if (ksz_is_ksz88x3(dev))
return -ENOTSUPP;
ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged); ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
ksz8_r_vlan_table(dev, vlan->vid, &data); ksz8_r_vlan_table(dev, vlan->vid, &data);
...@@ -958,6 +1135,9 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port, ...@@ -958,6 +1135,9 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port,
u16 data, pvid, new_pvid = 0; u16 data, pvid, new_pvid = 0;
u8 fid, member, valid; u8 fid, member, valid;
if (ksz_is_ksz88x3(dev))
return -ENOTSUPP;
ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid); ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
pvid = pvid & 0xFFF; pvid = pvid & 0xFFF;
...@@ -1091,7 +1271,8 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -1091,7 +1271,8 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* enable broadcast storm limit */ /* enable broadcast storm limit */
ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
ksz8795_set_prio_queue(dev, port, 4); if (!ksz_is_ksz88x3(dev))
ksz8795_set_prio_queue(dev, port, 4);
/* disable DiffServ priority */ /* disable DiffServ priority */
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false); ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false);
...@@ -1104,7 +1285,8 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) ...@@ -1104,7 +1285,8 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true); ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true);
if (cpu_port) { if (cpu_port) {
ksz8795_cpu_interface_select(dev, port); if (!ksz_is_ksz88x3(dev))
ksz8795_cpu_interface_select(dev, port);
member = dev->port_mask; member = dev->port_mask;
} else { } else {
...@@ -1156,9 +1338,11 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds) ...@@ -1156,9 +1338,11 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)
p = &dev->ports[i]; p = &dev->ports[i];
if (!p->on) if (!p->on)
continue; continue;
ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote); if (!ksz_is_ksz88x3(dev)) {
if (remote & PORT_FIBER_MODE) ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
p->fiber = 1; if (remote & PORT_FIBER_MODE)
p->fiber = 1;
}
if (p->fiber) if (p->fiber)
ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL, ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL,
true); true);
...@@ -1277,19 +1461,30 @@ static int ksz8_switch_detect(struct ksz_device *dev) ...@@ -1277,19 +1461,30 @@ static int ksz8_switch_detect(struct ksz_device *dev)
id1 = id16 >> 8; id1 = id16 >> 8;
id2 = id16 & SW_CHIP_ID_M; id2 = id16 & SW_CHIP_ID_M;
if (id1 != FAMILY_ID ||
(id2 != CHIP_ID_94 && id2 != CHIP_ID_95))
return -ENODEV;
if (id2 == CHIP_ID_95) { switch (id1) {
u8 val; case KSZ87_FAMILY_ID:
if ((id2 != CHIP_ID_94 && id2 != CHIP_ID_95))
return -ENODEV;
if (id2 == CHIP_ID_95) {
u8 val;
id2 = 0x95; id2 = 0x95;
ksz_read8(dev, REG_PORT_1_STATUS_0, &val); ksz_read8(dev, REG_PORT_STATUS_0, &val);
if (val & PORT_FIBER_MODE) if (val & PORT_FIBER_MODE)
id2 = 0x65; id2 = 0x65;
} else if (id2 == CHIP_ID_94) { } else if (id2 == CHIP_ID_94) {
id2 = 0x94; id2 = 0x94;
}
break;
case KSZ88_FAMILY_ID:
if (id2 != CHIP_ID_63)
return -ENODEV;
break;
default:
dev_err(dev->dev, "invalid family id: %d\n", id1);
return -ENODEV;
} }
id16 &= ~0xff; id16 &= ~0xff;
id16 |= id2; id16 |= id2;
...@@ -1350,6 +1545,15 @@ static const struct ksz_chip_data ksz8_switch_chips[] = { ...@@ -1350,6 +1545,15 @@ static const struct ksz_chip_data ksz8_switch_chips[] = {
.cpu_ports = 0x10, /* can be configured as cpu port */ .cpu_ports = 0x10, /* can be configured as cpu port */
.port_cnt = 5, /* total cpu and user ports */ .port_cnt = 5, /* total cpu and user ports */
}, },
{
.chip_id = 0x8830,
.dev_name = "KSZ8863/KSZ8873",
.num_vlans = 16,
.num_alus = 0,
.num_statics = 8,
.cpu_ports = 0x4, /* can be configured as cpu port */
.port_cnt = 3,
},
}; };
static int ksz8_switch_init(struct ksz_device *dev) static int ksz8_switch_init(struct ksz_device *dev)
...@@ -1382,12 +1586,21 @@ static int ksz8_switch_init(struct ksz_device *dev) ...@@ -1382,12 +1586,21 @@ static int ksz8_switch_init(struct ksz_device *dev)
if (!dev->cpu_ports) if (!dev->cpu_ports)
return -ENODEV; return -ENODEV;
ksz8->regs = ksz8795_regs; if (ksz_is_ksz88x3(dev)) {
ksz8->masks = ksz8795_masks; ksz8->regs = ksz8863_regs;
ksz8->shifts = ksz8795_shifts; ksz8->masks = ksz8863_masks;
ksz8->shifts = ksz8863_shifts;
dev->mib_cnt = ARRAY_SIZE(ksz88xx_mib_names);
dev->mib_names = ksz88xx_mib_names;
} else {
ksz8->regs = ksz8795_regs;
ksz8->masks = ksz8795_masks;
ksz8->shifts = ksz8795_shifts;
dev->mib_cnt = ARRAY_SIZE(ksz87xx_mib_names);
dev->mib_names = ksz87xx_mib_names;
}
dev->reg_mib_cnt = KSZ8795_COUNTER_NUM; dev->reg_mib_cnt = MIB_COUNTER_NUM;
dev->mib_cnt = ARRAY_SIZE(mib_names);
dev->ports = devm_kzalloc(dev->dev, dev->ports = devm_kzalloc(dev->dev,
dev->port_cnt * sizeof(struct ksz_port), dev->port_cnt * sizeof(struct ksz_port),
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
#define REG_CHIP_ID0 0x00 #define REG_CHIP_ID0 0x00
#define FAMILY_ID 0x87 #define KSZ87_FAMILY_ID 0x87
#define KSZ88_FAMILY_ID 0x88
#define REG_CHIP_ID1 0x01 #define REG_CHIP_ID1 0x01
...@@ -28,6 +29,12 @@ ...@@ -28,6 +29,12 @@
#define CHIP_ID_94 0x60 #define CHIP_ID_94 0x60
#define CHIP_ID_95 0x90 #define CHIP_ID_95 0x90
#define CHIP_ID_63 0x30
#define KSZ8863_REG_SW_RESET 0x43
#define KSZ8863_GLOBAL_SOFTWARE_RESET BIT(4)
#define KSZ8863_PCS_RESET BIT(0)
#define REG_SW_CTRL_0 0x02 #define REG_SW_CTRL_0 0x02
...@@ -267,6 +274,7 @@ ...@@ -267,6 +274,7 @@
#define REG_PORT_3_CTRL_9 0x3C #define REG_PORT_3_CTRL_9 0x3C
#define REG_PORT_4_CTRL_9 0x4C #define REG_PORT_4_CTRL_9 0x4C
#define PORT_AUTO_NEG_ENABLE BIT(7)
#define PORT_AUTO_NEG_DISABLE BIT(7) #define PORT_AUTO_NEG_DISABLE BIT(7)
#define PORT_FORCE_100_MBIT BIT(6) #define PORT_FORCE_100_MBIT BIT(6)
#define PORT_FORCE_FULL_DUPLEX BIT(5) #define PORT_FORCE_FULL_DUPLEX BIT(5)
...@@ -800,6 +808,7 @@ ...@@ -800,6 +808,7 @@
#define KSZ8795_ID_HI 0x0022 #define KSZ8795_ID_HI 0x0022
#define KSZ8795_ID_LO 0x1550 #define KSZ8795_ID_LO 0x1550
#define KSZ8863_ID_LO 0x1430
#define KSZ8795_SW_ID 0x8795 #define KSZ8795_SW_ID 0x8795
...@@ -830,7 +839,7 @@ ...@@ -830,7 +839,7 @@
#define KS_PRIO_IN_REG 4 #define KS_PRIO_IN_REG 4
#define KSZ8795_COUNTER_NUM 0x20 #define MIB_COUNTER_NUM 0x20
/* Common names used by other drivers */ /* Common names used by other drivers */
...@@ -876,26 +885,13 @@ ...@@ -876,26 +885,13 @@
#define MIB_COUNTER_VALUE 0x3FFFFFFF #define MIB_COUNTER_VALUE 0x3FFFFFFF
#define KS_MIB_TOTAL_RX_0 0x100 #define KSZ8795_MIB_TOTAL_RX_0 0x100
#define KS_MIB_TOTAL_TX_0 0x101 #define KSZ8795_MIB_TOTAL_TX_0 0x101
#define KS_MIB_PACKET_DROPPED_RX_0 0x102 #define KSZ8795_MIB_TOTAL_RX_1 0x104
#define KS_MIB_PACKET_DROPPED_TX_0 0x103 #define KSZ8795_MIB_TOTAL_TX_1 0x105
#define KS_MIB_TOTAL_RX_1 0x104
#define KS_MIB_TOTAL_TX_1 0x105 #define KSZ8863_MIB_PACKET_DROPPED_TX_0 0x100
#define KS_MIB_PACKET_DROPPED_TX_1 0x106 #define KSZ8863_MIB_PACKET_DROPPED_RX_0 0x105
#define KS_MIB_PACKET_DROPPED_RX_1 0x107
#define KS_MIB_TOTAL_RX_2 0x108
#define KS_MIB_TOTAL_TX_2 0x109
#define KS_MIB_PACKET_DROPPED_TX_2 0x10A
#define KS_MIB_PACKET_DROPPED_RX_2 0x10B
#define KS_MIB_TOTAL_RX_3 0x10C
#define KS_MIB_TOTAL_TX_3 0x10D
#define KS_MIB_PACKET_DROPPED_TX_3 0x10E
#define KS_MIB_PACKET_DROPPED_RX_3 0x10F
#define KS_MIB_TOTAL_RX_4 0x110
#define KS_MIB_TOTAL_TX_4 0x111
#define KS_MIB_PACKET_DROPPED_TX_4 0x112
#define KS_MIB_PACKET_DROPPED_RX_4 0x113
#define MIB_PACKET_DROPPED 0x0000FFFF #define MIB_PACKET_DROPPED 0x0000FFFF
......
...@@ -71,6 +71,7 @@ struct ksz_device { ...@@ -71,6 +71,7 @@ struct ksz_device {
int port_cnt; int port_cnt;
int reg_mib_cnt; int reg_mib_cnt;
int mib_cnt; int mib_cnt;
const struct mib_names *mib_names;
phy_interface_t compat_interface; phy_interface_t compat_interface;
u32 regs_size; u32 regs_size;
bool phy_errata_9477; bool phy_errata_9477;
......
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