@@ -22,6 +22,21 @@
#define MDIO_READ 2
#define MDIO_WRITE 1
+/* KSZ8863 Serial Management Interface (SMI) uses the following frame format:
+ *
+ * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle
+ * |frame| OP code |address |address| | |
+ * read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z
+ * write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z
+ *
+ * The register number is encoded with the 5 least significant bits in REG
+ * and the 3 most significant bits in PHY
+ */
+
+#define SMI_KSZ88X3_RW_OPCODE 0
+#define SMI_KSZ88X3_READ_PHY (1 << 4)
+#define SMI_KSZ88X3_WRITE_PHY (0 << 4)
+
#define MDIO_C45 (1<<15)
#define MDIO_C45_ADDR (MDIO_C45 | 0)
#define MDIO_C45_READ (MDIO_C45 | 3)
@@ -157,6 +172,9 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+ } else if (reg & MII_ADDR_SMI_KSZ88X3) {
+ mdiobb_cmd(ctrl, SMI_KSZ88X3_RW_OPCODE,
+ (reg & 0xE0) >> 5 | SMI_KSZ88X3_READ_PHY, reg);
} else
mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
@@ -188,6 +206,9 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+ } else if (reg & MII_ADDR_SMI_KSZ88X3) {
+ mdiobb_cmd(ctrl, SMI_KSZ88X3_RW_OPCODE,
+ (reg & 0xE0) >> 5 | SMI_KSZ88X3_WRITE_PHY, reg);
} else
mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
@@ -201,6 +201,8 @@ static inline const char *phy_modes(phy_interface_t interface)
#define MII_DEVADDR_C45_SHIFT 16
#define MII_REGADDR_C45_MASK GENMASK(15, 0)
+#define MII_ADDR_SMI_KSZ88X3 (1<<31)
+
struct device;
struct phylink;
struct sk_buff;