new file mode 100644
@@ -0,0 +1,41 @@
+/*
+ * Microchip KSZ9477 register definitions
+ *
+ * Copyright (C) 2017
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __KSZ9477_REGS_H
+#define __KSZ9477_REGS_H
+
+#define KS_PRIO_M 0x3
+#define KS_PRIO_S 2
+
+/* 0 - Operation */
+#define REG_CHIP_ID0__1 0x0000
+
+#define REG_CHIP_ID1__1 0x0001
+
+#define FAMILY_ID 0x95
+#define FAMILY_ID_94 0x94
+#define FAMILY_ID_95 0x95
+#define FAMILY_ID_85 0x85
+#define FAMILY_ID_98 0x98
+#define FAMILY_ID_88 0x88
+
+#define TOTAL_SWITCH_COUNTER_NUM 0x24 /* FIXME */
+#define PORT_CTRL_ADDR(port, addr) ((addr) | (((port) + 1) << 4))
+
+
+#endif /* KSZ9477_REGS_H */
@@ -16,6 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#error This is not switch we have
#ifndef __KSZ9477_REGS_H
#define __KSZ9477_REGS_H
@@ -2,6 +2,7 @@
* Microchip switch driver main logic
*
* Copyright (C) 2017
+ * Copyright (C) 2017 Pavel Machek <pavel@denx.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -29,6 +30,7 @@
#include <net/switchdev.h>
#include "ksz_priv.h"
+#include "ksz_sw_phy.h"
static const struct {
int index;
@@ -130,10 +132,14 @@ static void ksz_port_cfg32(struct ksz_device *dev, int port, int offset,
ksz_write32(dev, addr, data);
}
+#define NOTIMPL() do { NOTIMPLV(); return -EJUKEBOX; } while (0)
+#define NOTIMPLV() do { printk("Not implemented -- %s\n", __func__); } while (0)
+
static int wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, int timeout)
{
+#ifdef KSOLD
u8 data;
-
+
do {
ksz_read8(dev, REG_SW_VLAN_CTRL, &data);
if (!(data & waiton))
@@ -145,10 +151,14 @@ static int wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, int timeout)
return -ETIMEDOUT;
return 0;
+#else
+ NOTIMPL();
+#endif
}
static int get_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
int ret;
@@ -172,12 +182,15 @@ static int get_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
exit:
mutex_unlock(&dev->vlan_mutex);
-
return ret;
+#else
+ NOTIMPL();
+#endif
}
static int set_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
int ret;
@@ -208,30 +221,42 @@ static int set_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
mutex_unlock(&dev->vlan_mutex);
return ret;
+#else
+ NOTIMPL();
+#endif
}
static void read_table(struct dsa_switch *ds, u32 *table)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]);
ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]);
ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]);
ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]);
+#else
+ NOTIMPLV();
+#endif
}
static void write_table(struct dsa_switch *ds, u32 *table)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]);
ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]);
ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]);
ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]);
+#else
+ NOTIMPLV();
+#endif
}
static int wait_alu_ready(struct ksz_device *dev, u32 waiton, int timeout)
{
+#ifdef KSOLD
u32 data;
do {
@@ -245,12 +270,15 @@ static int wait_alu_ready(struct ksz_device *dev, u32 waiton, int timeout)
return -ETIMEDOUT;
return 0;
+#else
+ NOTIMPL();
+#endif
}
static int wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, int timeout)
{
+#ifdef KSOLD
u32 data;
-
do {
ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data);
if (!(data & waiton))
@@ -262,10 +290,14 @@ static int wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, int timeout)
return -ETIMEDOUT;
return 0;
+#else
+ NOTIMPL();
+#endif
}
static int ksz_reset_switch(struct dsa_switch *ds)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u8 data8;
u16 data16;
@@ -295,22 +327,69 @@ static int ksz_reset_switch(struct dsa_switch *ds)
data16 &= ~BROADCAST_STORM_RATE;
data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;
ksz_write16(dev, REG_SW_MAC_CTRL_2, data16);
+#else
+ /* reset switch */
+ //ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
+
+ /* turn off SPI DO Edge select */
+ //ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
+ //data8 &= ~SPI_AUTO_EDGE_DETECTION;
+ //ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8);
+
+ /* default configuration */
+ //ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8);
+ //data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING |
+// SW_SRC_ADDR_FILTER | SW_FLUSH_STP_TABLE | SW_FLUSH_MSTP_TABLE;
+ //ksz_write8(dev, REG_SW_LUE_CTRL_1, data8);
+
+ /* disable interrupts */
+ //ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);
+ //ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F);
+ //ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
+
+ /* set broadcast storm protection 10% rate */
+ //ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16);
+ //data16 &= ~BROADCAST_STORM_RATE;
+ //data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;
+ //ksz_write16(dev, REG_SW_MAC_CTRL_2, data16);
+#endif
return 0;
}
+#define PORT_MAC_LOOPBACK_my 0x80
+#ifdef KSZOLD
+#define REG_PORT_CTRL_LOOPBACK REG_PORT_CTRL_0
+#else
+#define REG_PORT_CTRL_LOOPBACK 0x0f
+#endif
+
static void port_setup(struct ksz_device *dev, int port, bool cpu_port)
{
+#ifdef KSZOLD
u8 data8;
u16 data16;
+#endif
+ printk("Port setup %d, %d\n", port, cpu_port);
+
+#ifndef KSZOLD
+ if (cpu_port && port != 4)
+ printk("!!! tail tagging only works on port 5\n");
+ if (cpu_port) {
+ printk("enable tail tagging\n");
+ ksz_cfg(dev, S_TAIL_TAG_CTRL, SW_TAIL_TAG_ENABLE, true);
+ }
+#endif
+#ifdef KSZOLD
/* enable tag tail for host port */
if (cpu_port)
ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE,
true);
+#endif
- ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false);
-
+ ksz_port_cfg(dev, port, REG_PORT_CTRL_LOOPBACK, PORT_MAC_LOOPBACK_my, false);
+#ifdef KSZOLD
/* set back pressure */
ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true);
@@ -343,6 +422,7 @@ static void port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* clear pending interrupts */
ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
+#endif
}
static void ksz_config_cpu_port(struct dsa_switch *ds)
@@ -379,18 +459,27 @@ static int ksz_setup(struct dsa_switch *ds)
}
/* accept packet up to 2000bytes */
- ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true);
+ //ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true);
ksz_config_cpu_port(ds);
+#ifdef KSOLD
ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true);
+#else
+ ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true);
+#endif
/* queue based egress rate limit */
- ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
+ //ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
/* start switch */
+#ifndef KSZOLD
+#define REG_SW_OPERATION 1
+#define SW_START 1
+#endif
ksz_cfg(dev, REG_SW_OPERATION, SW_START, true);
+
return 0;
}
@@ -399,13 +488,17 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds)
return DSA_TAG_PROTO_KSZ;
}
+#ifdef KSZOLD
static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
{
struct ksz_device *dev = ds->priv;
u16 val = 0;
- ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
+ /* "MIIM" registers. */
+ printk("Phy: read16 @ %lx, %lx\n", addr, reg);
+ ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
+ printk("Phy: read16 @ %lx, %lx -> %lx\n", addr, reg, val);
return val;
}
@@ -413,10 +506,14 @@ static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
{
struct ksz_device *dev = ds->priv;
+ printk("Phy: write16 @ %lx, %lx, %lx\n", addr, reg, val);
ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
return 0;
}
+#else
+#include "ksz_mdio_emulation.c"
+#endif
static int ksz_enable_port(struct dsa_switch *ds, int port,
struct phy_device *phy)
@@ -429,13 +526,14 @@ static int ksz_enable_port(struct dsa_switch *ds, int port,
return 0;
}
+
static void ksz_disable_port(struct dsa_switch *ds, int port,
struct phy_device *phy)
{
struct ksz_device *dev = ds->priv;
/* there is no port disable */
- ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, true);
+ ksz_port_cfg(dev, port, REG_PORT_CTRL_LOOPBACK, PORT_MAC_LOOPBACK_my, true);
}
static int ksz_sset_count(struct dsa_switch *ds)
@@ -456,6 +554,7 @@ static void ksz_get_strings(struct dsa_switch *ds, int port, uint8_t *buf)
static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
uint64_t *buf)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
int i;
u32 data;
@@ -491,13 +590,35 @@ static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
}
mutex_unlock(&dev->stats_mutex);
+#else
+ NOTIMPLV();
+#endif
+}
+
+static void ksz_dump(struct ksz_device *dev)
+{
+ int i;
+ u8 v;
+
+ printk("ksz: dumping:\n");
+ for (i = 0; i < 0x100; i++) {
+ if (!(i % 0x10))
+ printk("\n %lx: ", i);
+ ksz_read8(dev, i, &v);
+ printk("%02x ", v);
+ }
+ printk("\nksz: dump done\n");
}
static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{
struct ksz_device *dev = ds->priv;
u8 data;
+#ifndef KSOLD
+#define P_STP_CTRL 2
+#endif
+ printk("port %d state %d\n", port, state);
ksz_pread8(dev, port, P_STP_CTRL, &data);
data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
@@ -512,6 +633,7 @@ static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
data |= PORT_RX_ENABLE;
break;
case BR_STATE_FORWARDING:
+ printk("port %d state %d forwarding\n", port, state);
data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
break;
case BR_STATE_BLOCKING:
@@ -523,10 +645,18 @@ static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
}
ksz_pwrite8(dev, port, P_STP_CTRL, data);
+
+ /* FIXME ! */
+ //ksz_write8(dev, 0x0c, 0x16);
+
+ ksz_dump(dev);
+
+
}
static void ksz_port_fast_age(struct dsa_switch *ds, int port)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u8 data8;
@@ -536,10 +666,15 @@ static void ksz_port_fast_age(struct dsa_switch *ds, int port)
data8 &= ~SW_FAST_AGING;
ksz_write8(dev, REG_SW_LUE_CTRL_1, data8);
+#else
+ NOTIMPLV();
+#endif
+
}
static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
if (flag) {
@@ -553,7 +688,9 @@ static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag)
ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
PORT_VLAN_LOOKUP_VID_0, false);
}
-
+#else
+ NOTIMPL();
+#endif
return 0;
}
@@ -570,6 +707,7 @@ static void ksz_port_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u32 vlan_table[3];
u16 vid;
@@ -599,11 +737,15 @@ static void ksz_port_vlan_add(struct dsa_switch *ds, int port,
if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vid);
}
+#else
+ NOTIMPLV();
+#endif
}
static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
u32 vlan_table[3];
@@ -634,6 +776,9 @@ static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
}
ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid);
+#else
+ NOTIMPL();
+#endif
return 0;
}
@@ -642,6 +787,7 @@ static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_vlan *vlan,
switchdev_obj_dump_cb_t *cb)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u16 vid;
u16 data;
@@ -676,6 +822,9 @@ static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
mutex_unlock(&dev->vlan_mutex);
return err;
+#else
+ NOTIMPL();
+#endif
}
static int ksz_port_fdb_prepare(struct dsa_switch *ds, int port,
@@ -710,6 +859,7 @@ static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb,
struct switchdev_trans *trans)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u32 alu_table[4];
u32 data;
@@ -757,11 +907,15 @@ static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
exit:
mutex_unlock(&dev->alu_mutex);
+#else
+ NOTIMPL();
+#endif
}
static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u32 alu_table[4];
u32 data;
@@ -822,12 +976,15 @@ static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
exit:
mutex_unlock(&dev->alu_mutex);
-
return ret;
+#else
+ NOTIMPL();
+#endif
}
static void convert_alu(struct alu_struct *alu, u32 *alu_table)
{
+#ifdef KSOLD
alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID);
alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER);
alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER);
@@ -847,12 +1004,16 @@ static void convert_alu(struct alu_struct *alu, u32 *alu_table)
alu->mac[3] = (alu_table[3] >> 16) & 0xFF;
alu->mac[4] = (alu_table[3] >> 8) & 0xFF;
alu->mac[5] = alu_table[3] & 0xFF;
+#else
+ NOTIMPLV();
+#endif
}
static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_fdb *fdb,
switchdev_obj_dump_cb_t *cb)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
int ret = 0;
u32 data;
@@ -860,6 +1021,7 @@ static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
struct alu_struct alu;
int timeout;
+
mutex_lock(&dev->alu_mutex);
/* start ALU search */
@@ -907,6 +1069,9 @@ static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
mutex_unlock(&dev->alu_mutex);
return ret;
+#else
+ NOTIMPL();
+#endif
}
static int ksz_port_mdb_prepare(struct dsa_switch *ds, int port,
@@ -921,6 +1086,7 @@ static void ksz_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct switchdev_trans *trans)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u32 static_table[4];
u32 data;
@@ -986,11 +1152,15 @@ static void ksz_port_mdb_add(struct dsa_switch *ds, int port,
exit:
mutex_unlock(&dev->alu_mutex);
+#else
+ NOTIMPL();
+#endif
}
static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u32 static_table[4];
u32 data;
@@ -1063,6 +1233,9 @@ static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
mutex_unlock(&dev->alu_mutex);
return ret;
+#else
+ NOTIMPL();
+#endif
}
static int ksz_port_mdb_dump(struct dsa_switch *ds, int port,
@@ -1077,6 +1250,7 @@ static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
if (ingress)
@@ -1093,11 +1267,16 @@ static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
return 0;
+#else
+ NOTIMPL();
+#endif
+
}
static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror)
{
+#ifdef KSOLD
struct ksz_device *dev = ds->priv;
u8 data;
@@ -1111,6 +1290,10 @@ static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
if (!(data & (PORT_MIRROR_RX | PORT_MIRROR_TX)))
ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
PORT_MIRROR_SNIFFER, false);
+#else
+ NOTIMPLV();
+#endif
+
}
static const struct dsa_switch_ops ksz_switch_ops = {
@@ -1162,6 +1345,15 @@ static const struct ksz_chip_data ksz_switch_chips[] = {
.cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */
},
+ {
+ .chip_id = 0x95600c04,
+ .dev_name = "KSZ8895",
+ .num_vlans = 4096, /* FIXME ? */
+ .num_alus = 4096,
+ .num_statics = 16,
+ .cpu_ports = 0x10, /* can be configured as cpu port */
+ .port_cnt = 5, /* total physical port count */
+ },
};
static int ksz_switch_init(struct ksz_device *dev)
@@ -1175,9 +1367,13 @@ static int ksz_switch_init(struct ksz_device *dev)
dev->ds->ops = &ksz_switch_ops;
+ printk("\n\n\nksz_switch_init: detecting\n");
+
for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) {
const struct ksz_chip_data *chip = &ksz_switch_chips[i];
+ printk("ksz_switch_init: have id %lx %lx\n", dev->chip_id, chip->chip_id);
+
if (dev->chip_id == chip->chip_id) {
dev->name = chip->dev_name;
dev->num_vlans = chip->num_vlans;
@@ -1189,6 +1385,8 @@ static int ksz_switch_init(struct ksz_device *dev)
break;
}
}
+
+ printk("ksz_switch_init: detected %s\n", dev->name);
/* no switch found */
if (!dev->port_cnt)
@@ -1228,7 +1426,7 @@ int ksz_switch_detect(struct ksz_device *dev)
u8 data8;
u32 id32;
int ret;
-
+#ifdef KSOLD
/* turn off SPI DO Edge select */
ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
if (ret)
@@ -1238,12 +1436,24 @@ int ksz_switch_detect(struct ksz_device *dev)
ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8);
if (ret)
return ret;
-
+#endif
/* read chip id */
ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32);
- if (ret)
+ if (ret) {
+ printk("ksz_switch_detect: error\n");
return ret;
-
+ }
+ printk("ksz_switch_detect: id %lx\n", id32);
+
+ ret = ksz_read8(dev, 0, &data8);
+ printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+ ret = ksz_read8(dev, 1, &data8);
+ printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+ ret = ksz_read8(dev, 2, &data8);
+ printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+ ret = ksz_read8(dev, 3, &data8);
+ printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+
dev->chip_id = id32;
return 0;
new file mode 100644
@@ -0,0 +1,373 @@
+/**
+ * Micrel KSZ8895 SPI driver
+ *
+ * Copyright (c) 2015 Micrel, Inc.
+ *
+ * GPLv2
+ */
+
+#include "ksz_sw_phy.h"
+#define PHY_ID_KSZ8895 ((KSZ8895_ID_HI << 16) | KSZ8895_ID_LO)
+
+/**
+ * sw_r_phy - read data from PHY register
+ * @sw: The switch instance.
+ * @phy: PHY address to read.
+ * @reg: PHY register to read.
+ * @val: Buffer to store the read data.
+ *
+ * This routine reads data from the PHY register.
+ */
+static void sw_r_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 *val)
+{
+ u8 ctrl;
+ u8 restart;
+ u8 link;
+ u8 speed;
+ u8 force;
+ u8 p = phy;
+ u16 data = 0;
+
+ switch (reg) {
+ case PHY_REG_CTRL:
+ ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+ ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
+ ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+ ksz_pread8(sw, p, P_FORCE_CTRL, &force);
+ if (restart & PORT_PHY_LOOPBACK)
+ data |= PHY_LOOPBACK;
+ if (force & PORT_FORCE_100_MBIT)
+ data |= PHY_SPEED_100MBIT;
+ if (!(force & PORT_AUTO_NEG_DISABLE))
+ data |= PHY_AUTO_NEG_ENABLE;
+ if (restart & PORT_POWER_DOWN)
+ data |= PHY_POWER_DOWN;
+ if (restart & PORT_AUTO_NEG_RESTART)
+ data |= PHY_AUTO_NEG_RESTART;
+ if (force & PORT_FORCE_FULL_DUPLEX)
+ data |= PHY_FULL_DUPLEX;
+ if (speed & PORT_HP_MDIX)
+ data |= PHY_HP_MDIX;
+ if (restart & PORT_FORCE_MDIX)
+ data |= PHY_FORCE_MDIX;
+ if (restart & PORT_AUTO_MDIX_DISABLE)
+ data |= PHY_AUTO_MDIX_DISABLE;
+ if (restart & PORT_TX_DISABLE)
+ data |= PHY_TRANSMIT_DISABLE;
+ if (restart & PORT_LED_OFF)
+ data |= PHY_LED_DISABLE;
+ break;
+ case PHY_REG_STATUS:
+ ksz_pread8(sw, p, P_LINK_STATUS, &link);
+ ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+ data = PHY_100BTX_FD_CAPABLE |
+ PHY_100BTX_CAPABLE |
+ PHY_10BT_FD_CAPABLE |
+ PHY_10BT_CAPABLE |
+ PHY_AUTO_NEG_CAPABLE;
+ if (link & PORT_AUTO_NEG_COMPLETE)
+ data |= PHY_AUTO_NEG_ACKNOWLEDGE;
+ if (link & PORT_STAT_LINK_GOOD)
+ data |= PHY_LINK_STATUS;
+ break;
+ case PHY_REG_ID_1:
+ data = KSZ8895_ID_HI;
+ break;
+ case PHY_REG_ID_2:
+ data = KSZ8895_ID_LO;
+ break;
+ case PHY_REG_AUTO_NEGOTIATION:
+ ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+ data = PHY_AUTO_NEG_802_3;
+ if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
+ data |= PHY_AUTO_NEG_SYM_PAUSE;
+ if (ctrl & PORT_AUTO_NEG_100BTX_FD)
+ data |= PHY_AUTO_NEG_100BTX_FD;
+ if (ctrl & PORT_AUTO_NEG_100BTX)
+ data |= PHY_AUTO_NEG_100BTX;
+ if (ctrl & PORT_AUTO_NEG_10BT_FD)
+ data |= PHY_AUTO_NEG_10BT_FD;
+ if (ctrl & PORT_AUTO_NEG_10BT)
+ data |= PHY_AUTO_NEG_10BT;
+ break;
+ case PHY_REG_REMOTE_CAPABILITY:
+ ksz_pread8(sw, p, P_REMOTE_STATUS, &link);
+ data = PHY_AUTO_NEG_802_3;
+ if (link & PORT_REMOTE_SYM_PAUSE)
+ data |= PHY_AUTO_NEG_SYM_PAUSE;
+ if (link & PORT_REMOTE_100BTX_FD)
+ data |= PHY_AUTO_NEG_100BTX_FD;
+ if (link & PORT_REMOTE_100BTX)
+ data |= PHY_AUTO_NEG_100BTX;
+ if (link & PORT_REMOTE_10BT_FD)
+ data |= PHY_AUTO_NEG_10BT_FD;
+ if (link & PORT_REMOTE_10BT)
+ data |= PHY_AUTO_NEG_10BT;
+ break;
+ default:
+ break;
+ }
+ *val = data;
+} /* sw_r_phy */
+
+/**
+ * sw_w_phy - write data to PHY register
+ * @hw: The switch instance.
+ * @phy: PHY address to write.
+ * @reg: PHY register to write.
+ * @val: Word data to write.
+ *
+ * This routine writes data to the PHY register.
+ */
+static void sw_w_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 val)
+{
+ u8 ctrl;
+ u8 restart;
+ u8 speed;
+ u8 data;
+ u8 p = phy;
+
+ switch (reg) {
+ case PHY_REG_CTRL:
+ ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+ data = speed;
+ if (val & PHY_HP_MDIX)
+ data |= PORT_HP_MDIX;
+ else
+ data &= ~PORT_HP_MDIX;
+ if (data != speed)
+ ksz_pwrite8(sw, p, P_SPEED_STATUS, data);
+ ksz_pread8(sw, p, P_FORCE_CTRL, &ctrl);
+ data = ctrl;
+ if (!(val & PHY_AUTO_NEG_ENABLE))
+ data |= PORT_AUTO_NEG_DISABLE;
+ else
+ data &= ~PORT_AUTO_NEG_DISABLE;
+ if (val & PHY_SPEED_100MBIT)
+ data |= PORT_FORCE_100_MBIT;
+ else
+ data &= ~PORT_FORCE_100_MBIT;
+ if (val & PHY_FULL_DUPLEX)
+ data |= PORT_FORCE_FULL_DUPLEX;
+ else
+ data &= ~PORT_FORCE_FULL_DUPLEX;
+ if (data != ctrl)
+ ksz_pwrite8(sw, p, P_FORCE_CTRL, data);
+ ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
+ data = restart;
+ if (val & PHY_LED_DISABLE)
+ data |= PORT_LED_OFF;
+ else
+ data &= ~PORT_LED_OFF;
+ if (val & PHY_TRANSMIT_DISABLE)
+ data |= PORT_TX_DISABLE;
+ else
+ data &= ~PORT_TX_DISABLE;
+ if (val & PHY_AUTO_NEG_RESTART)
+ data |= PORT_AUTO_NEG_RESTART;
+ else
+ data &= ~(PORT_AUTO_NEG_RESTART);
+ if (val & PHY_POWER_DOWN)
+ data |= PORT_POWER_DOWN;
+ else
+ data &= ~PORT_POWER_DOWN;
+ if (val & PHY_AUTO_MDIX_DISABLE)
+ data |= PORT_AUTO_MDIX_DISABLE;
+ else
+ data &= ~PORT_AUTO_MDIX_DISABLE;
+ if (val & PHY_FORCE_MDIX)
+ data |= PORT_FORCE_MDIX;
+ else
+ data &= ~PORT_FORCE_MDIX;
+ if (val & PHY_LOOPBACK)
+ data |= PORT_PHY_LOOPBACK;
+ else
+ data &= ~PORT_PHY_LOOPBACK;
+ if (data != restart)
+ ksz_pwrite8(sw, p, P_NEG_RESTART_CTRL, data);
+ break;
+ case PHY_REG_AUTO_NEGOTIATION:
+ ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+ data = ctrl;
+ data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
+ PORT_AUTO_NEG_100BTX_FD |
+ PORT_AUTO_NEG_100BTX |
+ PORT_AUTO_NEG_10BT_FD |
+ PORT_AUTO_NEG_10BT);
+ if (val & PHY_AUTO_NEG_SYM_PAUSE)
+ data |= PORT_AUTO_NEG_SYM_PAUSE;
+ if (val & PHY_AUTO_NEG_100BTX_FD)
+ data |= PORT_AUTO_NEG_100BTX_FD;
+ if (val & PHY_AUTO_NEG_100BTX)
+ data |= PORT_AUTO_NEG_100BTX;
+ if (val & PHY_AUTO_NEG_10BT_FD)
+ data |= PORT_AUTO_NEG_10BT_FD;
+ if (val & PHY_AUTO_NEG_10BT)
+ data |= PORT_AUTO_NEG_10BT;
+ if (data != ctrl)
+ ksz_pwrite8(sw, p, P_LOCAL_CTRL, data);
+ break;
+ default:
+ break;
+ }
+} /* sw_w_phy */
+
+static int ksz_mii_addr(int *reg, int *bank)
+{
+ int ret;
+
+ ret = (*reg & 0xC000) >> ADDR_SHIFT;
+ *bank = (*reg & 0x3000) >> BANK_SHIFT;
+ *reg &= 0x0FFF;
+ return ret;
+}
+
+static int ksz_phy_read16(struct dsa_switch *ds, int phy_id, int regnum)
+{
+ struct ksz_device *sw = ds->priv;
+ int addr;
+ int bank;
+ u16 data;
+ int ret = 0xffff;
+
+ if (phy_id > SWITCH_PORT_NUM + 1)
+ return 0xffff;
+#ifdef FIXME
+ if (sw->port_cnt < sw->mib_port_cnt && 1 == phy_id)
+ return 0xffff;
+#endif
+
+ addr = ksz_mii_addr(®num, &bank);
+ BUG_ON(addr >= 6);
+
+ switch (addr) {
+#ifdef FIXME
+ case ADDR_8:
+ ret = HW_R8(ks, regnum);
+ break;
+ case ADDR_16:
+ ret = HW_R16(ks, regnum);
+ break;
+ case ADDR_32:
+ ret = HW_R32(ks, regnum);
+ break;
+#endif
+ case ADDR_8:
+ case ADDR_16:
+ case ADDR_32:
+ BUG();
+
+ default:
+ if (regnum < 6) {
+ int id = phy_id;
+
+ sw_r_phy(sw, phy_id, regnum, &data);
+ ret = data;
+#ifdef FIXME?
+ if (0 == id) {
+ switch (regnum) {
+ case 0:
+ ret = 0x3120;
+ break;
+ case 1:
+ ret = 0x782c;
+ break;
+ case 4:
+ case 5:
+ ret = 0x05e1;
+ break;
+ }
+ }
+#endif
+ } else
+ ret = 0;
+ }
+
+ return ret;
+} /* ksz_mii_read */
+
+static int ksz_phy_write16(struct dsa_switch *ds, int phy_id, int regnum, u16 val)
+{
+ struct ksz_device *sw = ds->priv;
+ static int last_reg;
+ static int last_val;
+ int addr;
+ int bank;
+ int reg;
+
+ if (phy_id > SWITCH_PORT_NUM + 1)
+ return -EINVAL;
+#ifdef FIXME
+ if (sw->port_cnt < sw->mib_port_cnt && 1 == phy_id)
+ return -EINVAL;
+#endif
+
+ BUG_ON(regnum >= 6);
+ reg = regnum;
+ addr = ksz_mii_addr(®num, &bank);
+
+ switch (addr) {
+#ifdef FIXME
+ case ADDR_8:
+ HW_W8(ks, regnum, val);
+ break;
+ case ADDR_16:
+ HW_W16(ks, regnum, val);
+ break;
+ case ADDR_32:
+ /*
+ * The phy_write interface allows only 16-bit value. Break
+ * the 32-bit write into two calls for SPI efficiency.
+ */
+
+ /* Previous write to high word. */
+ if (last_reg == reg + 2) {
+ last_val <<= 16;
+ last_val |= val;
+ HW_W32(ks, regnum, last_val);
+ last_reg = 0;
+ } else {
+ /* Somebody has written to different address! */
+ if (last_reg) {
+ int last_bank;
+
+ addr = ksz_mii_addr(&last_reg, &last_bank);
+ HW_W16(ks, last_reg, last_val);
+ last_reg = 0;
+ }
+
+ /* Cache the 16-bit write to high word. */
+ if (reg & 3) {
+ last_reg = reg;
+ last_val = val;
+
+ /* Did not find the previous write to high word.*/
+ } else
+ HW_W16(ks, regnum, val);
+ }
+ break;
+#endif
+ case ADDR_8:
+ case ADDR_16:
+ case ADDR_32:
+ BUG();
+ default:
+ if (regnum < 6) {
+ int i;
+ int p = 0;
+
+ /* PHY device driver resets or powers down the PHY. */
+ if (0 == regnum &&
+ (val & (PHY_RESET | PHY_POWER_DOWN)))
+ break;
+#ifdef FIXME
+ if (sw->port_cnt < sw->mib_port_cnt)
+ p = 1;
+#endif
+ sw_w_phy(sw, phy_id, regnum, val);
+ }
+ break;
+ }
+
+ return 0;
+} /* ksz_mii_write */
@@ -25,7 +25,7 @@
#include <linux/etherdevice.h>
#include <net/dsa.h>
-#include "ksz_9477_reg.h"
+#include "ksz_8895_reg.h"
struct ksz_io_ops;
@@ -174,6 +174,7 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value)
static inline void ksz_pread8(struct ksz_device *dev, int port, int offset,
u8 *data)
{
+ //printk("pread8 %d %d -> %d\n", port, offset, PORT_CTRL_ADDR(port, offset));
ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data);
}
@@ -29,22 +29,38 @@
#define KS_SPIOP_RD 3
#define KS_SPIOP_WR 2
+#ifdef KSOLD
#define SPI_ADDR_SHIFT 24
-#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1)
#define SPI_TURNAROUND_SHIFT 5
+#else
+/* FIXME?! */
+#define SPI_ADDR_SHIFT 12
+#define SPI_TURNAROUND_SHIFT 1
+#endif
+#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1)
static int ksz_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val,
unsigned int len)
{
- u32 txbuf;
int ret;
+#ifdef KSOLD
+ u32 txbuf;
txbuf = reg & SPI_ADDR_MASK;
txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT;
txbuf <<= SPI_TURNAROUND_SHIFT;
txbuf = cpu_to_be32(txbuf);
ret = spi_write_then_read(spi, &txbuf, 4, val, len);
+#else
+ u8 buf[2];
+
+ buf[0] = KS_SPIOP_RD;
+ buf[1] = reg;
+
+ ret = spi_write_then_read(spi, buf, 2, val, len);
+#endif
+
return ret;
}
@@ -99,8 +115,10 @@ static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val)
static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
unsigned int len)
{
- u32 txbuf;
u8 data[12];
+
+#ifdef KSOLD
+ u32 txbuf;
int i;
txbuf = reg & SPI_ADDR_MASK;
@@ -116,6 +134,16 @@ static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
data[i + 4] = val[i];
return spi_write(spi, &data, 4 + len);
+#else
+ int i;
+
+ data[0] = KS_SPIOP_WR;
+ data[1] = reg;
+ for (i = 0; i < len; i++)
+ data[i + 2] = val[i];
+
+ return spi_write(spi, &data, 2 + len);
+#endif
}
static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value)
@@ -174,6 +202,8 @@ static int ksz_spi_probe(struct spi_device *spi)
if (spi->dev.platform_data)
dev->pdata = spi->dev.platform_data;
+ //printk("Chip variant is %lx\n", spi_get_device_id(spi)->driver_data
+
ret = ksz_switch_register(dev);
if (ret)
return ret;
@@ -195,6 +225,7 @@ static int ksz_spi_remove(struct spi_device *spi)
static const struct of_device_id ksz_dt_ids[] = {
{ .compatible = "microchip,ksz9477" },
+ { .compatible = "microchip,ksz8895" },
{},
};
MODULE_DEVICE_TABLE(of, ksz_dt_ids);
new file mode 100644
@@ -0,0 +1,754 @@
+/**
+ * Micrel switch PHY common header
+ *
+ * Copyright (c) 2012-2015 Micrel, Inc.
+ * Tristram Ha <Tristram.Ha@micrel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef KSZ_PHY_H
+#define KSZ_PHY_H
+
+#define ADDR_SHIFT 14
+#define ADDR_8 1
+#define ADDR_16 2
+#define ADDR_24 3
+#define ADDR_32 4
+
+#define BANK_SHIFT 12
+
+#define PHY_REG(addr, reg) \
+ (((addr) << ADDR_SHIFT) | (reg))
+
+#define PHY_BANK_REG(addr, bank, reg) \
+ (((addr) << ADDR_SHIFT) | ((bank) << BANK_SHIFT) | (reg))
+
+/* Use PHY access if no direct access. */
+#ifndef SW_R8
+#define SW_R8(s, r) phy_read(s->phydev, PHY_REG(ADDR_8, r))
+#define SW_W8(s, r, v) phy_write(s->phydev, PHY_REG(ADDR_8, r), v)
+#define SW_R16(s, r) phy_read(s->phydev, PHY_REG(ADDR_16, r))
+#define SW_W16(s, r, v) phy_write(s->phydev, PHY_REG(ADDR_16, r), v)
+#define SW_R32(s, r) phy_read(s->phydev, PHY_REG(ADDR_32, r))
+#define SW_W32(s, r, v) \
+ do { \
+ phy_write(s->phydev, PHY_REG(ADDR_32, (r) + 2), (v) >> 16); \
+ phy_write(s->phydev, PHY_REG(ADDR_32, r), v); \
+ } while (0)
+#define SW_LOCK(s) \
+ do { \
+ mutex_lock(s->hwlock); \
+ } while (0)
+#define SW_UNLOCK(s) \
+ do { \
+ mutex_unlock(s->hwlock); \
+ } while (0)
+#endif
+
+
+#define KS_PORT_M 0x1F
+
+#define REG_CHIP_ID0 0x00
+
+#define FAMILY_ID 0x95
+
+#define REG_CHIP_ID1 0x01
+
+#define SW_CHIP_ID_M 0xF0
+#define SW_CHIP_ID_S 4
+#define SW_REVISION_M 0x0E
+#define SW_REVISION_S 1
+
+#define CHIP_ID_95 0x40
+#define CHIP_ID_95R 0x60
+
+#define REG_SW_CTRL_0 0x02
+
+#define SW_NEW_BACKOFF (1 << 7)
+#define SW_FLUSH_DYN_MAC_TABLE (1 << 5)
+#define SW_FLUSH_STA_MAC_TABLE (1 << 4)
+#define SW_UNH_MODE (1 << 1)
+#define SW_LINK_AUTO_AGING (1 << 0)
+
+#define REG_SW_CTRL_1 0x03
+
+#define SW_PASS_ALL (1 << 7)
+#define SW_2K_PACKET (1 << 6)
+#define SW_TX_FLOW_CTRL_DISABLE (1 << 5)
+#define SW_RX_FLOW_CTRL_DISABLE (1 << 4)
+#define SW_CHECK_LENGTH (1 << 3)
+#define SW_AGING_ENABLE (1 << 2)
+#define SW_FAST_AGING (1 << 1)
+#define SW_AGGR_BACKOFF (1 << 0)
+
+#define REG_SW_CTRL_2 0x04
+
+#define UNICAST_VLAN_BOUNDARY (1 << 7)
+#define MULTICAST_STORM_DISABLE (1 << 6)
+#define SW_BACK_PRESSURE (1 << 5)
+#define FAIR_FLOW_CTRL (1 << 4)
+#define NO_EXC_COLLISION_DROP (1 << 3)
+#define SW_HUGE_PACKET (1 << 2)
+#define SW_LEGAL_PACKET (1 << 1)
+
+#define REG_SW_CTRL_3 0x05
+#define SW_VLAN_ENABLE (1 << 7)
+#define SW_IGMP_SNOOP (1 << 6)
+#define SW_DIRECT (1 << 5)
+#define SW_PRE_TAG (1 << 4)
+#define SW_VLAN_TAG (1 << 1)
+#define SW_MIRROR_RX_TX (1 << 0)
+
+#define REG_SW_CTRL_4 0x06
+
+#define SW_HALF_DUPLEX_FLOW_CTRL (1 << 7)
+#define SW_HALF_DUPLEX (1 << 6)
+#define SW_FLOW_CTRL (1 << 5)
+#define SW_10_MBIT (1 << 4)
+#define SW_REPLACE_VID (1 << 3)
+#define BROADCAST_STORM_RATE_HI 0x07
+
+#define REG_SW_CTRL_5 0x07
+
+#define BROADCAST_STORM_RATE_LO 0xFF
+#define BROADCAST_STORM_RATE 0x07FF
+
+#define REG_SW_CTRL_9 0x0B
+
+#define SW_DATA_SAMPLING_NEG (1 << 6)
+#define SW_PHY_POWER_SAVE_DISABLE (1 << 3)
+#define SW_LED_MODE_1 (1 << 1)
+#define SW_SPI_SAMPLING_RISING (1 << 0)
+
+#define REG_SW_CTRL_10 0x0C
+
+#define SPI_CLK_125_MHZ 0x20
+#define SPI_CLK_83_33_MHZ 0x10
+#define SPI_CLK_41_67_MHZ 0x00
+#define SW_TAIL_TAG_ENABLE (1 << 1)
+#define SW_PASS_PAUSE (1 << 0)
+
+#define REG_SW_CTRL_11 0x0D
+
+#define REG_POWER_MANAGEMENT_1 0x0E
+
+#define SW_PLL_POWER_DOWN (1 << 5)
+#define SW_POWER_MANAGEMENT_MODE_M 0x3
+#define SW_POWER_MANAGEMENT_MODE_S 3
+#define SW_POWER_NORMAL 0
+#define SW_ENERGY_DETECTION 1
+#define SW_SOFTWARE_POWER_DOWN 2
+#define SW_POWER_SAVING 3
+
+#define REG_POWER_MANAGEMENT_2 0x0F
+
+
+#define REG_PORT_1_CTRL_0 0x10
+#define REG_PORT_2_CTRL_0 0x20
+#define REG_PORT_3_CTRL_0 0x30
+#define REG_PORT_4_CTRL_0 0x40
+#define REG_PORT_5_CTRL_0 0x50
+
+#define PORT_BROADCAST_STORM (1 << 7)
+#define PORT_DIFFSERV_ENABLE (1 << 6)
+#define PORT_802_1P_ENABLE (1 << 5)
+#define PORT_BASED_PRIO_S 3
+#define PORT_BASED_PRIO_M (KS_PRIO_M << PORT_BASED_PRIO_S)
+#define PORT_PORT_PRIO_0 0
+#define PORT_PORT_PRIO_1 1
+#define PORT_PORT_PRIO_2 2
+#define PORT_PORT_PRIO_3 3
+#define PORT_INSERT_TAG (1 << 2)
+#define PORT_REMOVE_TAG (1 << 1)
+#define PORT_QUEUE_SPLIT_L (1 << 0)
+
+#define REG_PORT_1_CTRL_1 0x11
+#define REG_PORT_2_CTRL_1 0x21
+#define REG_PORT_3_CTRL_1 0x31
+#define REG_PORT_4_CTRL_1 0x41
+#define REG_PORT_5_CTRL_1 0x51
+
+#define PORT_MIRROR_SNIFFER (1 << 7)
+#define PORT_MIRROR_RX (1 << 6)
+#define PORT_MIRROR_TX (1 << 5)
+#define PORT_VLAN_MEMBERSHIP KS_PORT_M
+
+#define REG_PORT_1_CTRL_2 0x12
+#define REG_PORT_2_CTRL_2 0x22
+#define REG_PORT_3_CTRL_2 0x32
+#define REG_PORT_4_CTRL_2 0x42
+#define REG_PORT_5_CTRL_2 0x52
+
+#define PORT_802_1P_REMAPPING (1 << 7)
+#define PORT_INGRESS_FILTER (1 << 6)
+#define PORT_DISCARD_NON_VID (1 << 5)
+#define PORT_FORCE_FLOW_CTRL (1 << 4)
+#define PORT_BACK_PRESSURE (1 << 3)
+#define PORT_TX_ENABLE (1 << 2)
+#define PORT_RX_ENABLE (1 << 1)
+#define PORT_LEARN_DISABLE (1 << 0)
+
+#define REG_PORT_1_CTRL_3 0x13
+#define REG_PORT_2_CTRL_3 0x23
+#define REG_PORT_3_CTRL_3 0x33
+#define REG_PORT_4_CTRL_3 0x43
+#define REG_PORT_5_CTRL_3 0x53
+#define REG_PORT_1_CTRL_4 0x14
+#define REG_PORT_2_CTRL_4 0x24
+#define REG_PORT_3_CTRL_4 0x34
+#define REG_PORT_4_CTRL_4 0x44
+#define REG_PORT_5_CTRL_4 0x54
+
+#define PORT_DEFAULT_VID 0x0001
+
+#define REG_PORT_1_STATUS_0 0x19
+#define REG_PORT_2_STATUS_0 0x29
+#define REG_PORT_3_STATUS_0 0x39
+#define REG_PORT_4_STATUS_0 0x49
+#define REG_PORT_5_STATUS_0 0x59
+
+#define PORT_HP_MDIX (1 << 7)
+#define PORT_REVERSED_POLARITY (1 << 5)
+#define PORT_TX_FLOW_CTRL (1 << 4)
+#define PORT_RX_FLOW_CTRL (1 << 3)
+#define PORT_STAT_SPEED_100MBIT (1 << 2)
+#define PORT_STAT_FULL_DUPLEX (1 << 1)
+
+#define REG_PORT_1_LINK_MD_CTRL 0x1A
+#define REG_PORT_2_LINK_MD_CTRL 0x2A
+#define REG_PORT_3_LINK_MD_CTRL 0x3A
+#define REG_PORT_4_LINK_MD_CTRL 0x4A
+#define REG_PORT_5_LINK_MD_CTRL 0x5A
+
+#define PORT_CABLE_10M_SHORT (1 << 7)
+#define PORT_CABLE_DIAG_RESULT_M 0x3
+#define PORT_CABLE_DIAG_RESULT_S 5
+#define PORT_CABLE_STAT_NORMAL 0
+#define PORT_CABLE_STAT_OPEN 1
+#define PORT_CABLE_STAT_SHORT 2
+#define PORT_CABLE_STAT_FAILED 3
+#define PORT_START_CABLE_DIAG (1 << 4)
+#define PORT_FORCE_LINK (1 << 3)
+#define PORT_POWER_SAVING (1 << 2)
+#define PORT_PHY_REMOTE_LOOPBACK (1 << 1)
+#define PORT_CABLE_FAULT_COUNTER_H 0x01
+
+#define REG_PORT_1_LINK_MD_RESULT 0x1B
+#define REG_PORT_2_LINK_MD_RESULT 0x2B
+#define REG_PORT_3_LINK_MD_RESULT 0x3B
+#define REG_PORT_4_LINK_MD_RESULT 0x4B
+#define REG_PORT_5_LINK_MD_RESULT 0x5B
+
+#define PORT_CABLE_FAULT_COUNTER_L 0xFF
+#define PORT_CABLE_FAULT_COUNTER 0x1FF
+
+#define REG_PORT_1_CTRL_5 0x1C
+#define REG_PORT_2_CTRL_5 0x2C
+#define REG_PORT_3_CTRL_5 0x3C
+#define REG_PORT_4_CTRL_5 0x4C
+#define REG_PORT_5_CTRL_5 0x5C
+
+#define PORT_AUTO_NEG_DISABLE (1 << 7)
+#define PORT_FORCE_100_MBIT (1 << 6)
+#define PORT_FORCE_FULL_DUPLEX (1 << 5)
+#define PORT_AUTO_NEG_SYM_PAUSE (1 << 4)
+#define PORT_AUTO_NEG_100BTX_FD (1 << 3)
+#define PORT_AUTO_NEG_100BTX (1 << 2)
+#define PORT_AUTO_NEG_10BT_FD (1 << 1)
+#define PORT_AUTO_NEG_10BT (1 << 0)
+
+#define REG_PORT_1_CTRL_6 0x1D
+#define REG_PORT_2_CTRL_6 0x2D
+#define REG_PORT_3_CTRL_6 0x3D
+#define REG_PORT_4_CTRL_6 0x4D
+#define REG_PORT_5_CTRL_6 0x5D
+
+#define PORT_LED_OFF (1 << 7)
+#define PORT_TX_DISABLE (1 << 6)
+#define PORT_AUTO_NEG_RESTART (1 << 5)
+#define PORT_POWER_DOWN (1 << 3)
+#define PORT_AUTO_MDIX_DISABLE (1 << 2)
+#define PORT_FORCE_MDIX (1 << 1)
+#define PORT_MAC_LOOPBACK (1 << 0)
+
+#define REG_PORT_1_STATUS_1 0x1E
+#define REG_PORT_2_STATUS_1 0x2E
+#define REG_PORT_3_STATUS_1 0x3E
+#define REG_PORT_4_STATUS_1 0x4E
+#define REG_PORT_5_STATUS_1 0x5E
+
+#define PORT_MDIX_STATUS (1 << 7)
+#define PORT_AUTO_NEG_COMPLETE (1 << 6)
+#define PORT_STAT_LINK_GOOD (1 << 5)
+#define PORT_REMOTE_SYM_PAUSE (1 << 4)
+#define PORT_REMOTE_100BTX_FD (1 << 3)
+#define PORT_REMOTE_100BTX (1 << 2)
+#define PORT_REMOTE_10BT_FD (1 << 1)
+#define PORT_REMOTE_10BT (1 << 0)
+
+#define REG_PORT_1_STATUS_2 0x1F
+#define REG_PORT_2_STATUS_2 0x2F
+#define REG_PORT_3_STATUS_2 0x3F
+#define REG_PORT_4_STATUS_2 0x4F
+#define REG_PORT_5_STATUS_2 0x5F
+
+#define PORT_PHY_LOOPBACK (1 << 7)
+#define PORT_PHY_ISOLATE (1 << 5)
+#define PORT_PHY_SOFT_RESET (1 << 4)
+#define PORT_PHY_FORCE_LINK (1 << 3)
+#define PORT_PHY_MODE_M 0x7
+#define PHY_MODE_IN_AUTO_NEG 1
+#define PHY_MODE_10BT_HALF 2
+#define PHY_MODE_100BT_HALF 3
+#define PHY_MODE_10BT_FULL 5
+#define PHY_MODE_100BT_FULL 6
+#define PHY_MODE_ISOLDATE 7
+
+#define REG_PORT_CTRL_0 0x00
+#define REG_PORT_CTRL_1 0x01
+#define REG_PORT_CTRL_2 0x02
+#define REG_PORT_CTRL_VID 0x03
+
+#define REG_PORT_STATUS_0 0x09
+#define REG_PORT_LINK_MD_CTRL 0x0A
+#define REG_PORT_LINK_MD_RESULT 0x0B
+#define REG_PORT_CTRL_5 0x0C
+#define REG_PORT_CTRL_6 0x0D
+#define REG_PORT_STATUS_1 0x0E
+#define REG_PORT_STATUS_2 0x0F
+
+#define REG_PORT_CTRL_8 0xA0
+#define REG_PORT_CTRL_9 0xA1
+#define REG_PORT_RATE_CTRL_3 0xA2
+#define REG_PORT_RATE_CTRL_2 0xA3
+#define REG_PORT_RATE_CTRL_1 0xA4
+#define REG_PORT_RATE_CTRL_0 0xA5
+#define REG_PORT_RATE_LIMIT 0xA6
+#define REG_PORT_IN_RATE_0 0xA7
+#define REG_PORT_IN_RATE_1 0xA8
+#define REG_PORT_IN_RATE_2 0xA9
+#define REG_PORT_IN_RATE_3 0xAA
+#define REG_PORT_OUT_RATE_0 0xAB
+#define REG_PORT_OUT_RATE_1 0xAC
+#define REG_PORT_OUT_RATE_2 0xAD
+#define REG_PORT_OUT_RATE_3 0xAE
+
+#define REG_SW_MAC_ADDR_0 0x68
+#define REG_SW_MAC_ADDR_1 0x69
+#define REG_SW_MAC_ADDR_2 0x6A
+#define REG_SW_MAC_ADDR_3 0x6B
+#define REG_SW_MAC_ADDR_4 0x6C
+#define REG_SW_MAC_ADDR_5 0x6D
+
+#define REG_IND_CTRL_0 0x6E
+
+#define TABLE_READ (1 << 4)
+#define TABLE_SELECT_S 2
+#define TABLE_STATIC_MAC (0 << TABLE_SELECT_S)
+#define TABLE_VLAN (1 << TABLE_SELECT_S)
+#define TABLE_DYNAMIC_MAC (2 << TABLE_SELECT_S)
+#define TABLE_MIB (3 << TABLE_SELECT_S)
+
+#define REG_IND_CTRL_1 0x6F
+
+#define TABLE_ENTRY_MASK 0x03FF
+
+#define REG_IND_DATA_8 0x70
+#define REG_IND_DATA_7 0x71
+#define REG_IND_DATA_6 0x72
+#define REG_IND_DATA_5 0x73
+#define REG_IND_DATA_4 0x74
+#define REG_IND_DATA_3 0x75
+#define REG_IND_DATA_2 0x76
+#define REG_IND_DATA_1 0x77
+#define REG_IND_DATA_0 0x78
+
+#define REG_IND_DATA_CHECK REG_IND_DATA_6
+#define REG_IND_MIB_CHECK REG_IND_DATA_3
+#define REG_IND_DATA_HI REG_IND_DATA_7
+#define REG_IND_DATA_LO REG_IND_DATA_3
+
+#define REG_INT_STATUS 0x7C
+#define REG_INT_ENABLE 0x7D
+
+#define INT_PORT_5 (1 << 4)
+#define INT_PORT_4 (1 << 3)
+#define INT_PORT_3 (1 << 2)
+#define INT_PORT_2 (1 << 1)
+#define INT_PORT_1 (1 << 0)
+
+#define REG_SW_CTRL_12 0x80
+#define REG_SW_CTRL_13 0x81
+
+#define SWITCH_802_1P_MASK 3
+#define SWITCH_802_1P_BASE 3
+#define SWITCH_802_1P_SHIFT 2
+
+#define SW_802_1P_MAP_M KS_PRIO_M
+#define SW_802_1P_MAP_S KS_PRIO_S
+
+#define REG_SWITCH_CTRL_14 0x82
+
+#define SW_PRIO_MAPPING_M KS_PRIO_M
+#define SW_PRIO_MAPPING_S 6
+#define SW_PRIO_MAP_3_HI 0
+#define SW_PRIO_MAP_2_HI 2
+#define SW_PRIO_MAP_0_LO 3
+
+#define REG_SW_CTRL_15 0x83
+#define REG_SW_CTRL_16 0x84
+
+#define SW_DRIVE_STRENGTH_M 0x3
+#define SW_DRIVE_STRENGTH_4MA 0
+#define SW_DRIVE_STRENGTH_8MA 1
+#define SW_DRIVE_STRENGTH_10MA 2
+#define SW_DRIVE_STRENGTH_14MA 3
+#define SW_MII_DRIVE_STRENGTH_S 6
+
+#define REG_SW_CTRL_17 0x85
+#define REG_SW_CTRL_18 0x86
+
+#define SW_SELF_ADDR_FILTER_ENABLE (1 << 6)
+
+#define REG_SW_UNK_UCAST_CTRL 0x83
+#define REG_SW_UNK_MCAST_CTRL 0x84
+#define REG_SW_UNK_VID_CTRL 0x85
+#define REG_SW_UNK_IP_MCAST_CTRL 0x86
+
+#define SW_UNK_FWD_ENABLE (1 << 5)
+#define SW_UNK_FWD_MAP KS_PORT_M
+
+#define REG_SW_CTRL_19 0x87
+
+#define SW_IN_RATE_LIMIT_PERIOD_M 0x3
+#define SW_IN_RATE_LIMIT_PERIOD_S 4
+#define SW_IN_RATE_LIMIT_16_MS 0
+#define SW_IN_RATE_LIMIT_64_MS 1
+#define SW_IN_RATE_LIMIT_256_MS 2
+#define SW_QUEUE_BASED_OUT_RATE_LIMIT (1 << 3)
+#define SW_INS_TAG_ENABLE (1 << 2)
+
+#define REG_TOS_PRIO_CTRL_0 0x90
+#define REG_TOS_PRIO_CTRL_1 0x91
+#define REG_TOS_PRIO_CTRL_2 0x92
+#define REG_TOS_PRIO_CTRL_3 0x93
+#define REG_TOS_PRIO_CTRL_4 0x94
+#define REG_TOS_PRIO_CTRL_5 0x95
+#define REG_TOS_PRIO_CTRL_6 0x96
+#define REG_TOS_PRIO_CTRL_7 0x97
+#define REG_TOS_PRIO_CTRL_8 0x98
+#define REG_TOS_PRIO_CTRL_9 0x99
+#define REG_TOS_PRIO_CTRL_10 0x9A
+#define REG_TOS_PRIO_CTRL_11 0x9B
+#define REG_TOS_PRIO_CTRL_12 0x9C
+#define REG_TOS_PRIO_CTRL_13 0x9D
+#define REG_TOS_PRIO_CTRL_14 0x9E
+#define REG_TOS_PRIO_CTRL_15 0x9F
+
+#define TOS_PRIO_M KS_PRIO_M
+#define TOS_PRIO_S KS_PRIO_S
+
+
+#define REG_PORT_1_CTRL_8 0xB0
+#define REG_PORT_2_CTRL_8 0xC0
+#define REG_PORT_3_CTRL_8 0xD0
+#define REG_PORT_4_CTRL_8 0xE0
+#define REG_PORT_5_CTRL_8 0xF0
+
+#define PORT_INS_TAG_FOR_PORT_5_S 3
+#define PORT_INS_TAG_FOR_PORT_5 (1 << 3)
+#define PORT_INS_TAG_FOR_PORT_4 (1 << 2)
+#define PORT_INS_TAG_FOR_PORT_3 (1 << 1)
+#define PORT_INS_TAG_FOR_PORT_2 (1 << 0)
+
+#define REG_PORT_1_CTRL_9 0xB1
+#define REG_PORT_2_CTRL_9 0xC1
+#define REG_PORT_3_CTRL_9 0xD1
+#define REG_PORT_4_CTRL_9 0xE1
+#define REG_PORT_5_CTRL_9 0xF1
+
+#define PORT_QUEUE_SPLIT_H (1 << 1)
+#define PORT_QUEUE_SPLIT_1 0
+#define PORT_QUEUE_SPLIT_2 1
+#define PORT_QUEUE_SPLIT_4 2
+#define PORT_DROP_TAG (1 << 0)
+
+#define REG_PORT_1_CTRL_10 0xB2
+#define REG_PORT_2_CTRL_10 0xC2
+#define REG_PORT_3_CTRL_10 0xD2
+#define REG_PORT_4_CTRL_10 0xE2
+#define REG_PORT_5_CTRL_10 0xF2
+#define REG_PORT_1_CTRL_11 0xB3
+#define REG_PORT_2_CTRL_11 0xC3
+#define REG_PORT_3_CTRL_11 0xD3
+#define REG_PORT_4_CTRL_11 0xE3
+#define REG_PORT_5_CTRL_11 0xF3
+#define REG_PORT_1_CTRL_12 0xB4
+#define REG_PORT_2_CTRL_12 0xC4
+#define REG_PORT_3_CTRL_12 0xD4
+#define REG_PORT_4_CTRL_12 0xE4
+#define REG_PORT_5_CTRL_12 0xF4
+#define REG_PORT_1_CTRL_13 0xB5
+#define REG_PORT_2_CTRL_13 0xC5
+#define REG_PORT_3_CTRL_13 0xD5
+#define REG_PORT_4_CTRL_13 0xE5
+#define REG_PORT_5_CTRL_13 0xF5
+
+#define REG_PORT_1_RATE_CTRL_3 0xB2
+#define REG_PORT_1_RATE_CTRL_2 0xB3
+#define REG_PORT_1_RATE_CTRL_1 0xB4
+#define REG_PORT_1_RATE_CTRL_0 0xB5
+#define REG_PORT_2_RATE_CTRL_3 0xC2
+#define REG_PORT_2_RATE_CTRL_2 0xC3
+#define REG_PORT_2_RATE_CTRL_1 0xC4
+#define REG_PORT_2_RATE_CTRL_0 0xC5
+#define REG_PORT_3_RATE_CTRL_3 0xD2
+#define REG_PORT_3_RATE_CTRL_2 0xD3
+#define REG_PORT_3_RATE_CTRL_1 0xD4
+#define REG_PORT_3_RATE_CTRL_0 0xD5
+#define REG_PORT_4_RATE_CTRL_3 0xE2
+#define REG_PORT_4_RATE_CTRL_2 0xE3
+#define REG_PORT_4_RATE_CTRL_1 0xE4
+#define REG_PORT_4_RATE_CTRL_0 0xE5
+#define REG_PORT_5_RATE_CTRL_3 0xF2
+#define REG_PORT_5_RATE_CTRL_2 0xF3
+#define REG_PORT_5_RATE_CTRL_1 0xF4
+#define REG_PORT_5_RATE_CTRL_0 0xF5
+
+#define RATE_CTRL_ENABLE (1 << 7)
+#define RATE_RATIO_M ((1 << 7) - 1)
+
+#define REG_PORT_1_RATE_LIMIT 0xB6
+#define REG_PORT_2_RATE_LIMIT 0xC6
+#define REG_PORT_3_RATE_LIMIT 0xD6
+#define REG_PORT_4_RATE_LIMIT 0xE6
+#define REG_PORT_5_RATE_LIMIT 0xF6
+
+#define PORT_IN_FLOW_CTRL_S 4
+#define PORT_IN_LIMIT_MODE_M 0x3
+#define PORT_IN_LIMIT_MODE_S 2
+#define PORT_COUNT_IFG_S 1
+#define PORT_COUNT_PREAMBLE_S 0
+#define PORT_IN_FLOW_CTRL (1 << PORT_IN_FLOW_CTRL_S)
+#define PORT_IN_ALL 0
+#define PORT_IN_UNICAST 1
+#define PORT_IN_MULTICAST 2
+#define PORT_IN_BROADCAST 3
+#define PORT_COUNT_IFG (1 << PORT_COUNT_IFG_S)
+#define PORT_COUNT_PREAMBLE (1 << PORT_COUNT_PREAMBLE_S)
+
+#define REG_PORT_1_IN_RATE_0 0xB7
+#define REG_PORT_2_IN_RATE_0 0xC7
+#define REG_PORT_3_IN_RATE_0 0xD7
+#define REG_PORT_4_IN_RATE_0 0xE7
+#define REG_PORT_5_IN_RATE_0 0xF7
+#define REG_PORT_1_IN_RATE_1 0xB8
+#define REG_PORT_2_IN_RATE_1 0xC8
+#define REG_PORT_3_IN_RATE_1 0xD8
+#define REG_PORT_4_IN_RATE_1 0xE8
+#define REG_PORT_5_IN_RATE_1 0xF8
+#define REG_PORT_1_IN_RATE_2 0xB9
+#define REG_PORT_2_IN_RATE_2 0xC9
+#define REG_PORT_3_IN_RATE_2 0xD9
+#define REG_PORT_4_IN_RATE_2 0xE9
+#define REG_PORT_5_IN_RATE_2 0xF9
+#define REG_PORT_1_IN_RATE_3 0xBA
+#define REG_PORT_2_IN_RATE_3 0xCA
+#define REG_PORT_3_IN_RATE_3 0xDA
+#define REG_PORT_4_IN_RATE_3 0xEA
+#define REG_PORT_5_IN_RATE_3 0xFA
+
+#define PORT_RATE_LIMIT_M ((1 << 7) - 1)
+
+#define REG_PORT_1_OUT_RATE_0 0xBB
+#define REG_PORT_2_OUT_RATE_0 0xCB
+#define REG_PORT_3_OUT_RATE_0 0xDB
+#define REG_PORT_4_OUT_RATE_0 0xEB
+#define REG_PORT_5_OUT_RATE_0 0xFB
+#define REG_PORT_1_OUT_RATE_1 0xBC
+#define REG_PORT_2_OUT_RATE_1 0xCC
+#define REG_PORT_3_OUT_RATE_1 0xDC
+#define REG_PORT_4_OUT_RATE_1 0xEC
+#define REG_PORT_5_OUT_RATE_1 0xFC
+#define REG_PORT_1_OUT_RATE_2 0xBD
+#define REG_PORT_2_OUT_RATE_2 0xCD
+#define REG_PORT_3_OUT_RATE_2 0xDD
+#define REG_PORT_4_OUT_RATE_2 0xED
+#define REG_PORT_5_OUT_RATE_2 0xFD
+#define REG_PORT_1_OUT_RATE_3 0xBE
+#define REG_PORT_2_OUT_RATE_3 0xCE
+#define REG_PORT_3_OUT_RATE_3 0xDE
+#define REG_PORT_4_OUT_RATE_3 0xEE
+#define REG_PORT_5_OUT_RATE_3 0xFE
+
+
+#define REG_SW_CFG 0xEF
+
+#define SW_PORT_3_FIBER (1 << 7)
+
+/* KSZ8864 */
+
+#define REG_PHY_PORT_CTRL_1 0xCF
+
+#define PORT_HALF_DUPLEX (1 << 7)
+#define PORT_FLOW_CTRL (1 << 6)
+#define PORT_10_MBIT (1 << 5)
+
+#define REG_PHY_PORT_CTRL_2 0xDF
+
+#define PORT_MII_MAC_MODE (1 << 6)
+
+#define REG_KSZ8864_CHIP_ID 0xFE
+
+#define SW_KSZ8864 (1 << 7)
+
+
+#ifndef PHY_REG_CTRL
+#define PHY_REG_CTRL 0
+
+#define PHY_RESET (1 << 15)
+#define PHY_LOOPBACK (1 << 14)
+#define PHY_SPEED_100MBIT (1 << 13)
+#define PHY_AUTO_NEG_ENABLE (1 << 12)
+#define PHY_POWER_DOWN (1 << 11)
+#define PHY_MII_DISABLE (1 << 10)
+#define PHY_AUTO_NEG_RESTART (1 << 9)
+#define PHY_FULL_DUPLEX (1 << 8)
+#define PHY_COLLISION_TEST_NOT (1 << 7)
+#define PHY_HP_MDIX (1 << 5)
+#define PHY_FORCE_MDIX (1 << 4)
+#define PHY_AUTO_MDIX_DISABLE (1 << 3)
+#define PHY_REMOTE_FAULT_DISABLE (1 << 2)
+#define PHY_TRANSMIT_DISABLE (1 << 1)
+#define PHY_LED_DISABLE (1 << 0)
+
+#define PHY_REG_STATUS 1
+
+#define PHY_100BT4_CAPABLE (1 << 15)
+#define PHY_100BTX_FD_CAPABLE (1 << 14)
+#define PHY_100BTX_CAPABLE (1 << 13)
+#define PHY_10BT_FD_CAPABLE (1 << 12)
+#define PHY_10BT_CAPABLE (1 << 11)
+#define PHY_MII_SUPPRESS_CAPABLE_NOT (1 << 6)
+#define PHY_AUTO_NEG_ACKNOWLEDGE (1 << 5)
+#define PHY_REMOTE_FAULT (1 << 4)
+#define PHY_AUTO_NEG_CAPABLE (1 << 3)
+#define PHY_LINK_STATUS (1 << 2)
+#define PHY_JABBER_DETECT_NOT (1 << 1)
+#define PHY_EXTENDED_CAPABILITY (1 << 0)
+
+#define PHY_REG_ID_1 2
+#define PHY_REG_ID_2 3
+
+#define KSZ8895_ID_HI 0x0022
+#define KSZ8895_ID_LO 0x1450
+
+#define PHY_REG_AUTO_NEGOTIATION 4
+
+#define PHY_AUTO_NEG_NEXT_PAGE_NOT (1 << 15)
+#define PHY_AUTO_NEG_REMOTE_FAULT_NOT (1 << 13)
+#define PHY_AUTO_NEG_SYM_PAUSE (1 << 10)
+#define PHY_AUTO_NEG_100BT4 (1 << 9)
+#define PHY_AUTO_NEG_100BTX_FD (1 << 8)
+#define PHY_AUTO_NEG_100BTX (1 << 7)
+#define PHY_AUTO_NEG_10BT_FD (1 << 6)
+#define PHY_AUTO_NEG_10BT (1 << 5)
+#define PHY_AUTO_NEG_SELECTOR 0x001F
+#define PHY_AUTO_NEG_802_3 0x0001
+
+#define PHY_REG_REMOTE_CAPABILITY 5
+
+#define PHY_REMOTE_NEXT_PAGE_NOT (1 << 15)
+#define PHY_REMOTE_ACKNOWLEDGE_NOT (1 << 14)
+#define PHY_REMOTE_REMOTE_FAULT_NOT (1 << 13)
+#define PHY_REMOTE_SYM_PAUSE (1 << 10)
+#define PHY_REMOTE_100BTX_FD (1 << 8)
+#define PHY_REMOTE_100BTX (1 << 7)
+#define PHY_REMOTE_10BT_FD (1 << 6)
+#define PHY_REMOTE_10BT (1 << 5)
+
+#define PHY_REG_LINK_MD 0x1D
+
+#define PHY_START_CABLE_DIAG (1 << 15)
+#define PHY_CABLE_DIAG_RESULT 0x6000
+#define PHY_CABLE_STAT_NORMAL 0x0000
+#define PHY_CABLE_STAT_OPEN 0x2000
+#define PHY_CABLE_STAT_SHORT 0x4000
+#define PHY_CABLE_STAT_FAILED 0x6000
+#define PHY_CABLE_10M_SHORT (1 << 12)
+#define PHY_CABLE_FAULT_COUNTER 0x01FF
+
+#define PHY_REG_PHY_CTRL 0x1F
+
+#define PHY_MODE_M 0x7
+#define PHY_MODE_S 8
+#define PHY_STAT_REVERSED_POLARITY (1 << 5)
+#define PHY_STAT_MDIX (1 << 4)
+#define PHY_FORCE_LINK (1 << 3)
+#define PHY_POWER_SAVING_ENABLE (1 << 2)
+#define PHY_REMOTE_LOOPBACK (1 << 1)
+#endif
+
+
+/* Default values are used in ksz_sw.h if these are not defined. */
+#define PRIO_QUEUES 4
+
+#define KS_PRIO_IN_REG 4
+
+#define SWITCH_PORT_NUM 4
+
+#define KSZ8895_COUNTER_NUM 0x20
+#define TOTAL_KSZ8895_COUNTER_NUM (KSZ8895_COUNTER_NUM + 2)
+
+#define SWITCH_COUNTER_NUM KSZ8895_COUNTER_NUM
+#define TOTAL_SWITCH_COUNTER_NUM TOTAL_KSZ8895_COUNTER_NUM
+
+#define SW_D u8
+#define SW_R(sw, addr) (sw)->reg->r8(sw, addr)
+#define SW_W(sw, addr, val) (sw)->reg->w8(sw, addr, val)
+#define SW_SIZE (1)
+#define SW_SIZE_STR "%02x"
+
+
+#define P_BCAST_STORM_CTRL REG_PORT_CTRL_0
+#define P_PRIO_CTRL REG_PORT_CTRL_0
+#define P_TAG_CTRL REG_PORT_CTRL_0
+#define P_MIRROR_CTRL REG_PORT_CTRL_1
+#define P_802_1P_CTRL REG_PORT_CTRL_2
+#define P_STP_CTRL REG_PORT_CTRL_2
+#define P_LOCAL_CTRL REG_PORT_CTRL_5
+#define P_REMOTE_STATUS REG_PORT_STATUS_1
+#define P_FORCE_CTRL REG_PORT_CTRL_5
+#define P_NEG_RESTART_CTRL REG_PORT_CTRL_6
+#define P_SPEED_STATUS REG_PORT_STATUS_0
+#define P_LINK_STATUS REG_PORT_STATUS_1
+#define P_INS_SRC_PVID_CTRL REG_PORT_CTRL_8
+#define P_DROP_TAG_CTRL REG_PORT_CTRL_9
+#define P_RATE_LIMIT_CTRL REG_PORT_RATE_LIMIT
+
+#define S_FLUSH_TABLE_CTRL REG_SW_CTRL_0
+#define S_LINK_AGING_CTRL REG_SW_CTRL_0
+#define S_HUGE_PACKET_CTRL REG_SW_CTRL_2
+#define S_MIRROR_CTRL REG_SW_CTRL_3
+#define S_REPLACE_VID_CTRL REG_SW_CTRL_4
+#define S_PASS_PAUSE_CTRL REG_SW_CTRL_10
+#define S_TAIL_TAG_CTRL REG_SW_CTRL_10
+#define S_802_1P_PRIO_CTRL REG_SW_CTRL_12
+#define S_TOS_PRIO_CTRL REG_TOS_PRIO_CTRL_0
+#define S_IPV6_MLD_CTRL REG_SW_CTRL_21
+
+#define IND_ACC_TABLE(table) ((table) << 8)
+
+#define TAIL_TAG_OVERRIDE (1 << 6)
+#define TAIL_TAG_LOOKUP (1 << 7)
+
+#endif
@@ -29,7 +29,7 @@
* (eg, 0x00=port1, 0x02=port3, 0x06=port7)
*/
-#define KSZ_INGRESS_TAG_LEN 2
+#define KSZ_INGRESS_TAG_LEN 1
#define KSZ_EGRESS_TAG_LEN 1
static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -40,6 +40,7 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
u8 *tag;
padlen = (skb->len >= ETH_ZLEN) ? 0 : ETH_ZLEN - skb->len;
+ printk("ksz_xmit...\n");
if (skb_tailroom(skb) >= padlen + KSZ_INGRESS_TAG_LEN) {
if (skb_put_padto(skb, skb->len + padlen))
@@ -69,8 +70,9 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
}
tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
- tag[0] = 0;
- tag[1] = 1 << p->dp->index; /* destination port */
+ tag[0] = 1 << p->dp->index; /* destination port */
+
+ printk("ksz_xmit: tagging with %lx\n", 1 << p->dp->index);
return nskb;
}
@@ -88,6 +90,7 @@ static struct sk_buff *ksz_rcv(struct sk_buff *skb, struct net_device *dev,
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
source_port = tag[0] & 7;
+ printk("ksz_rcv: got source port %d\n", source_port);
if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
return NULL;