X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/7c3e076bdfc22dba29e7691afa9f30b1d20ccae9..d29edcf013f273ebb64d5d065d7b3925a1993689:/target/linux/generic/files/drivers/net/phy/ar8216.c diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index c199ac178..485cb5205 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -36,6 +36,16 @@ #define AR8X16_MAX_VLANS 128 #define AR8X16_PROBE_RETRIES 10 +struct ar8216_priv; + +struct ar8xxx_chip { + int (*hw_init)(struct ar8216_priv *priv); + void (*init_port)(struct ar8216_priv *priv, int port); + void (*setup_port)(struct ar8216_priv *priv, int port, u32 egress, + u32 ingress, u32 members, u32 pvid); + int (*atu_flush)(struct ar8216_priv *priv); +}; + struct ar8216_priv { struct switch_dev dev; struct phy_device *phy; @@ -44,7 +54,8 @@ struct ar8216_priv { const struct net_device_ops *ndo_old; struct net_device_ops ndo; struct mutex reg_mutex; - int chip; + int chip_type; + const struct ar8xxx_chip *chip; bool initialized; bool port4_phy; char buf[80]; @@ -87,7 +98,7 @@ ar8216_mii_read(struct ar8216_priv *priv, int reg) mutex_lock(&bus->mdio_lock); bus->write(bus, 0x18, 0, page); - msleep(1); /* wait for the page switch to propagate */ + usleep_range(1000, 2000); /* wait for the page switch to propagate */ lo = bus->read(bus, 0x10 | r2, r1); hi = bus->read(bus, 0x10 | r2, r1 + 1); @@ -111,13 +122,25 @@ ar8216_mii_write(struct ar8216_priv *priv, int reg, u32 val) mutex_lock(&bus->mdio_lock); bus->write(bus, 0x18, 0, r3); - msleep(1); /* wait for the page switch to propagate */ + usleep_range(1000, 2000); /* wait for the page switch to propagate */ bus->write(bus, 0x10 | r2, r1 + 1, hi); bus->write(bus, 0x10 | r2, r1, lo); mutex_unlock(&bus->mdio_lock); } +static void +ar8216_phy_dbg_write(struct ar8216_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data) +{ + struct mii_bus *bus = priv->phy->bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); + mutex_unlock(&bus->mdio_lock); +} + static u32 ar8216_rmw(struct ar8216_priv *priv, int reg, u32 mask, u32 val) { @@ -133,57 +156,6 @@ ar8216_rmw(struct ar8216_priv *priv, int reg, u32 mask, u32 val) return v; } -static inline int -ar8216_id_chip(struct ar8216_priv *priv) -{ - u32 val; - u16 id; - int i; - - priv->chip = UNKNOWN; - - val = ar8216_mii_read(priv, AR8216_REG_CTRL); - if (val == ~0) - return -ENODEV; - - id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); - for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { - u16 t; - - val = ar8216_mii_read(priv, AR8216_REG_CTRL); - if (val == ~0) - return -ENODEV; - - t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); - if (t != id) - return -ENODEV; - } - - switch (id) { - case 0x0101: - priv->chip = AR8216; - break; - case 0x0301: - priv->chip = AR8236; - break; - case 0x1000: - case 0x1001: - priv->chip = AR8316; - break; - default: - printk(KERN_DEBUG - "ar8216: Unknown Atheros device [ver=%d, rev=%d, phy_id=%04x%04x]\n", - (int)(id >> AR8216_CTRL_VERSION_S), - (int)(id & AR8216_CTRL_REVISION), - mdiobus_read(priv->phy->bus, priv->phy->addr, 2), - mdiobus_read(priv->phy->bus, priv->phy->addr, 3)); - - return -ENODEV; - } - - return 0; -} - static void ar8216_read_port_link(struct ar8216_priv *priv, int port, struct switch_port_link *link) @@ -510,13 +482,25 @@ ar8216_vtu_op(struct ar8216_priv *priv, u32 op, u32 val) priv->write(priv, AR8216_REG_VTU, op); } +static int +ar8216_atu_flush(struct ar8216_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0); + if (!ret) + priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH); + + return ret; +} + static void ar8216_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress, u32 members, u32 pvid) { u32 header; - if (priv->vlan && port == AR8216_PORT_CPU && priv->chip == AR8216) + if (priv->vlan && port == AR8216_PORT_CPU && priv->chip_type == AR8216) header = AR8216_PORT_CTRL_HEADER; else header = 0; @@ -609,31 +593,21 @@ ar8216_hw_apply(struct switch_dev *dev) int egress, ingress; int pvid; - if (priv->vlan) - pvid = priv->vlan_id[priv->pvid[i]]; - else - pvid = i; - if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[i]]; if (priv->vlan_tagged & (1 << i)) egress = AR8216_OUT_ADD_VLAN; else egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; } else { + pvid = i; egress = AR8216_OUT_KEEP; - } - - if (priv->vlan) - ingress = AR8216_IN_SECURE; - else ingress = AR8216_IN_PORT_ONLY; + } - if (priv->chip == AR8236) - ar8236_setup_port(priv, i, egress, ingress, portmask[i], - pvid); - else - ar8216_setup_port(priv, i, egress, ingress, portmask[i], - pvid); + priv->chip->setup_port(priv, i, egress, ingress, portmask[i], + pvid); } mutex_unlock(&priv->reg_mutex); return 0; @@ -642,11 +616,6 @@ ar8216_hw_apply(struct switch_dev *dev) static int ar8216_hw_init(struct ar8216_priv *priv) { - /* XXX: undocumented magic from atheros, required! */ - priv->write(priv, 0x38, 0xc000050e); - - ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, - AR8216_GCTRL_MTU, 1518 + 8 + 2); return 0; } @@ -669,10 +638,6 @@ ar8236_hw_init(struct ar8216_priv *priv) } msleep(1000); - /* enable jumbo frames */ - ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, - AR8316_GCTRL_MTU, 9018 + 8 + 2); - priv->initialized = true; return 0; } @@ -710,23 +675,17 @@ ar8316_hw_init(struct ar8216_priv *priv) priv->write(priv, 0x8, newval); - /* standard atheros magic */ - priv->write(priv, 0x38, 0xc000050e); - /* Initialize the ports */ bus = priv->phy->bus; for (i = 0; i < 5; i++) { if ((i == 4) && priv->port4_phy && priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { /* work around for phy4 rgmii mode */ - mdiobus_write(bus, i, MII_ATH_DBG_ADDR, 0x12); - mdiobus_write(bus, i, MII_ATH_DBG_DATA, 0x480c); + ar8216_phy_dbg_write(priv, i, 0x12, 0x480c); /* rx delay */ - mdiobus_write(bus, i, MII_ATH_DBG_ADDR, 0x0); - mdiobus_write(bus, i, MII_ATH_DBG_DATA, 0x824e); + ar8216_phy_dbg_write(priv, i, 0x0, 0x824e); /* tx delay */ - mdiobus_write(bus, i, MII_ATH_DBG_ADDR, 0x5); - mdiobus_write(bus, i, MII_ATH_DBG_DATA, 0x3d47); + ar8216_phy_dbg_write(priv, i, 0x5, 0x3d47); msleep(1000); } @@ -738,18 +697,38 @@ ar8316_hw_init(struct ar8216_priv *priv) msleep(1000); } - /* enable jumbo frames */ - ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, - AR8316_GCTRL_MTU, 9018 + 8 + 2); - - /* enable cpu port to receive multicast and broadcast frames */ - priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); - out: priv->initialized = true; return 0; } +static void +ar8216_init_globals(struct ar8216_priv *priv) +{ + switch (priv->chip_type) { + case AR8216: + /* standard atheros magic */ + priv->write(priv, 0x38, 0xc000050e); + + ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8216_GCTRL_MTU, 1518 + 8 + 2); + break; + case AR8316: + /* standard atheros magic */ + priv->write(priv, 0x38, 0xc000050e); + + /* enable cpu port to receive multicast and broadcast frames */ + priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); + + /* fall through */ + case AR8236: + /* enable jumbo frames */ + ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + break; + } +} + static void ar8216_init_port(struct ar8216_priv *priv, int port) { @@ -763,12 +742,12 @@ ar8216_init_port(struct ar8216_priv *priv, int port) if (port == AR8216_PORT_CPU) { priv->write(priv, AR8216_REG_PORT_STATUS(port), AR8216_PORT_STATUS_LINK_UP | - ((priv->chip == AR8316) ? + ((priv->chip_type == AR8316) ? AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC | - ((priv->chip == AR8316) ? AR8216_PORT_STATUS_RXFLOW : 0) | - ((priv->chip == AR8316) ? AR8216_PORT_STATUS_TXFLOW : 0) | + ((priv->chip_type == AR8316) ? AR8216_PORT_STATUS_RXFLOW : 0) | + ((priv->chip_type == AR8316) ? AR8216_PORT_STATUS_TXFLOW : 0) | AR8216_PORT_STATUS_DUPLEX); } else { priv->write(priv, AR8216_REG_PORT_STATUS(port), @@ -776,6 +755,27 @@ ar8216_init_port(struct ar8216_priv *priv, int port) } } +static const struct ar8xxx_chip ar8216_chip = { + .hw_init = ar8216_hw_init, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .atu_flush = ar8216_atu_flush, +}; + +static const struct ar8xxx_chip ar8236_chip = { + .hw_init = ar8236_hw_init, + .init_port = ar8216_init_port, + .setup_port = ar8236_setup_port, + .atu_flush = ar8216_atu_flush, +}; + +static const struct ar8xxx_chip ar8316_chip = { + .hw_init = ar8316_hw_init, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .atu_flush = ar8216_atu_flush, +}; + static int ar8216_reset_switch(struct switch_dev *dev) { @@ -791,14 +791,15 @@ ar8216_reset_switch(struct switch_dev *dev) /* Configure all ports */ for (i = 0; i < AR8216_NUM_PORTS; i++) - ar8216_init_port(priv, i); + priv->chip->init_port(priv, i); + ar8216_init_globals(priv); mutex_unlock(&priv->reg_mutex); + return ar8216_hw_apply(dev); } - -static const struct switch_dev_ops ar8216_ops = { +static const struct switch_dev_ops ar8216_sw_ops = { .attr_global = { .attr = ar8216_globals, .n_attr = ARRAY_SIZE(ar8216_globals), @@ -820,6 +821,60 @@ static const struct switch_dev_ops ar8216_ops = { .get_port_link = ar8216_get_port_link, }; +static int +ar8216_id_chip(struct ar8216_priv *priv) +{ + u32 val; + u16 id; + int i; + + priv->chip_type = UNKNOWN; + + val = ar8216_mii_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { + u16 t; + + val = ar8216_mii_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + if (t != id) + return -ENODEV; + } + + switch (id) { + case 0x0101: + priv->chip_type = AR8216; + priv->chip = &ar8216_chip; + break; + case 0x0301: + priv->chip_type = AR8236; + priv->chip = &ar8236_chip; + break; + case 0x1000: + case 0x1001: + priv->chip_type = AR8316; + priv->chip = &ar8316_chip; + break; + default: + printk(KERN_DEBUG + "ar8216: Unknown Atheros device [ver=%d, rev=%d, phy_id=%04x%04x]\n", + (int)(id >> AR8216_CTRL_VERSION_S), + (int)(id & AR8216_CTRL_REVISION), + mdiobus_read(priv->phy->bus, priv->phy->addr, 2), + mdiobus_read(priv->phy->bus, priv->phy->addr, 3)); + + return -ENODEV; + } + + return 0; +} + static int ar8216_config_init(struct phy_device *pdev) { @@ -841,7 +896,7 @@ ar8216_config_init(struct phy_device *pdev) goto err_free_priv; if (pdev->addr != 0) { - if (priv->chip == AR8316) { + if (priv->chip_type == AR8316) { pdev->supported |= SUPPORTED_1000baseT_Full; pdev->advertising |= ADVERTISED_1000baseT_Full; @@ -875,9 +930,9 @@ ar8216_config_init(struct phy_device *pdev) } printk(KERN_INFO "%s: AR%d switch driver attached.\n", - pdev->attached_dev->name, priv->chip); + pdev->attached_dev->name, priv->chip_type); - pdev->supported = priv->chip == AR8316 ? + pdev->supported = priv->chip_type == AR8316 ? SUPPORTED_1000baseT_Full : SUPPORTED_100baseT_Full; pdev->advertising = pdev->supported; @@ -889,10 +944,10 @@ ar8216_config_init(struct phy_device *pdev) swdev = &priv->dev; swdev->cpu_port = AR8216_PORT_CPU; - swdev->ops = &ar8216_ops; + swdev->ops = &ar8216_sw_ops; swdev->ports = AR8216_NUM_PORTS; - if (priv->chip == AR8316) { + if (priv->chip_type == AR8316) { swdev->name = "Atheros AR8316"; swdev->vlans = AR8X16_MAX_VLANS; @@ -900,7 +955,7 @@ ar8216_config_init(struct phy_device *pdev) /* port 5 connected to the other mac, therefore unusable */ swdev->ports = (AR8216_NUM_PORTS - 1); } - } else if (priv->chip == AR8236) { + } else if (priv->chip_type == AR8236) { swdev->name = "Atheros AR8236"; swdev->vlans = AR8216_NUM_VLANS; swdev->ports = AR8216_NUM_PORTS; @@ -915,14 +970,7 @@ ar8216_config_init(struct phy_device *pdev) priv->init = true; - ret = 0; - if (priv->chip == AR8216) - ret = ar8216_hw_init(priv); - else if (priv->chip == AR8236) - ret = ar8236_hw_init(priv); - else if (priv->chip == AR8316) - ret = ar8316_hw_init(priv); - + ret = priv->chip->hw_init(priv); if (ret) goto err_free_priv; @@ -933,7 +981,7 @@ ar8216_config_init(struct phy_device *pdev) dev->phy_ptr = priv; /* VID fixup only needed on ar8216 */ - if (pdev->addr == 0 && priv->chip == AR8216) { + if (pdev->addr == 0 && priv->chip_type == AR8216) { pdev->pkt_align = 2; pdev->netif_receive_skb = ar8216_netif_receive_skb; pdev->netif_rx = ar8216_netif_rx; @@ -984,9 +1032,7 @@ ar8216_read_status(struct phy_device *phydev) /* flush the address translation unit */ mutex_lock(&priv->reg_mutex); - ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0); - if (!ret) - priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH); + ret = priv->chip->atu_flush(priv); mutex_unlock(&priv->reg_mutex); phydev->state = PHY_RUNNING;