diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile | 3 | ||||
-rw-r--r-- | target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c | 149 |
2 files changed, 84 insertions, 68 deletions
diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile index 3636077166..480dbb62c0 100644 --- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile +++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile @@ -6,10 +6,9 @@ ag71xx-y += ag71xx_main.o ag71xx-y += ag71xx_gmac.o ag71xx-y += ag71xx_ethtool.o ag71xx-y += ag71xx_phy.o -ag71xx-y += ag71xx_ar7240.o ag71xx-$(CONFIG_AG71XX_DEBUG_FS) += ag71xx_debugfs.o +obj-$(CONFIG_AG71XX) += ag71xx_ar7240.o obj-$(CONFIG_AG71XX) += ag71xx_mdio.o obj-$(CONFIG_AG71XX) += ag71xx.o - diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c index 741f48e9cf..f91144da6e 100644 --- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c +++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c @@ -12,6 +12,8 @@ #include <linux/etherdevice.h> #include <linux/list.h> #include <linux/netdevice.h> +#include <linux/of_mdio.h> +#include <linux/of_net.h> #include <linux/phy.h> #include <linux/mii.h> #include <linux/bitops.h> @@ -291,7 +293,9 @@ struct ar7240sw_port_stat { struct ar7240sw { struct mii_bus *mii_bus; - struct ag71xx_switch_platform_data *swdata; + struct mii_bus *switch_mii_bus; + struct device_node *of_node; + struct device_node *mdio_node; struct switch_dev swdev; int num_ports; u8 ver; @@ -366,9 +370,11 @@ static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg) phy_reg = mk_phy_reg(reg); local_irq_save(flags); - ag71xx_mdio_mii_write(mii, 0x1f, 0x10, mk_high_addr(reg)); - lo = (u32) ag71xx_mdio_mii_read(mii, phy_addr, phy_reg); - hi = (u32) ag71xx_mdio_mii_read(mii, phy_addr, phy_reg + 1); + mutex_lock(&mii->mdio_lock); + mii->write(mii, 0x1f, 0x10, mk_high_addr(reg)); + lo = (u32) mii->read(mii, phy_addr, phy_reg); + hi = (u32) mii->read(mii, phy_addr, phy_reg + 1); + mutex_unlock(&mii->mdio_lock); local_irq_restore(flags); return (hi << 16) | lo; @@ -385,9 +391,11 @@ static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val) phy_reg = mk_phy_reg(reg); local_irq_save(flags); - ag71xx_mdio_mii_write(mii, 0x1f, 0x10, mk_high_addr(reg)); - ag71xx_mdio_mii_write(mii, phy_addr, phy_reg + 1, (val >> 16)); - ag71xx_mdio_mii_write(mii, phy_addr, phy_reg, (val & 0xffff)); + mutex_lock(&mii->mdio_lock); + mii->write(mii, 0x1f, 0x10, mk_high_addr(reg)); + mii->write(mii, phy_addr, phy_reg + 1, (val >> 16)); + mii->write(mii, phy_addr, phy_reg, (val & 0xffff)); + mutex_unlock(&mii->mdio_lock); local_irq_restore(flags); } @@ -463,10 +471,12 @@ static int ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val, return ret; } -int ar7240sw_phy_read(struct mii_bus *mii, int phy_addr, int reg_addr) +int ar7240sw_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr) { u32 t, val = 0xffff; int err; + struct ar7240sw *as = bus->priv; + struct mii_bus *mii = as->mii_bus; if (phy_addr >= AR7240_NUM_PHYS) return 0xffff; @@ -488,11 +498,13 @@ int ar7240sw_phy_read(struct mii_bus *mii, int phy_addr, int reg_addr) return val & AR7240_MDIO_CTRL_DATA_M; } -int ar7240sw_phy_write(struct mii_bus *mii, int phy_addr, int reg_addr, +int ar7240sw_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr, u16 reg_val) { u32 t; int ret; + struct ar7240sw *as = bus->priv; + struct mii_bus *mii = as->mii_bus; if (phy_addr >= AR7240_NUM_PHYS) return -EINVAL; @@ -646,6 +658,7 @@ ar7240sw_phy_poll_reset(struct mii_bus *bus) static int ar7240sw_reset(struct ar7240sw *as) { struct mii_bus *mii = as->mii_bus; + struct mii_bus *swmii = as->switch_mii_bus; int ret; int i; @@ -665,13 +678,13 @@ static int ar7240sw_reset(struct ar7240sw *as) /* setup PHYs */ for (i = 0; i < AR7240_NUM_PHYS; i++) { - ar7240sw_phy_write(mii, i, MII_ADVERTISE, + ar7240sw_phy_write(swmii, i, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - ar7240sw_phy_write(mii, i, MII_BMCR, + ar7240sw_phy_write(swmii, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); } - ret = ar7240sw_phy_poll_reset(mii); + ret = ar7240sw_phy_poll_reset(swmii); if (ret) return ret; @@ -1199,31 +1212,22 @@ static const struct switch_dev_ops ar7240_ops = { .get_port_stats = ar7240_get_port_stats, }; -static struct ar7240sw * -ar7240_probe(struct ag71xx *ag, struct device_node *np) +static int +ag71xx_ar7240_probe(struct mdio_device *mdiodev) { - struct mii_bus *mii = ag->mii_bus; + struct mii_bus *mii = mdiodev->bus; struct ar7240sw *as; struct switch_dev *swdev; u32 ctrl; - u16 phy_id1; - u16 phy_id2; - int i; + int phy_if_mode, err, i; - phy_id1 = ar7240sw_phy_read(mii, 0, MII_PHYSID1); - phy_id2 = ar7240sw_phy_read(mii, 0, MII_PHYSID2); - if ((phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) && - (phy_id1 != AR934X_PHY_ID1 || phy_id2 != AR934X_PHY_ID2)) { - pr_err("%s: unknown phy id '%04x:%04x'\n", - dev_name(&mii->dev), phy_id1, phy_id2); - return NULL; - } - - as = kzalloc(sizeof(*as), GFP_KERNEL); + as = devm_kzalloc(&mdiodev->dev, sizeof(*as), GFP_KERNEL); if (!as) - return NULL; + return -ENOMEM; as->mii_bus = mii; + as->of_node = mdiodev->dev.of_node; + as->mdio_node = of_get_child_by_name(as->of_node, "mdio-bus"); swdev = &as->swdev; @@ -1236,20 +1240,21 @@ ar7240_probe(struct ag71xx *ag, struct device_node *np) swdev->ports = AR7240_NUM_PORTS - 1; } else if (sw_is_ar934x(as)) { swdev->name = "AR934X built-in switch"; + phy_if_mode = of_get_phy_mode(as->of_node); - if (ag->phy_if_mode == PHY_INTERFACE_MODE_GMII) { + if (phy_if_mode == PHY_INTERFACE_MODE_GMII) { ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0, AR934X_OPER_MODE0_MAC_GMII_EN); - } else if (ag->phy_if_mode == PHY_INTERFACE_MODE_MII) { + } else if (phy_if_mode == PHY_INTERFACE_MODE_MII) { ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0, AR934X_OPER_MODE0_PHY_MII_EN); } else { pr_err("%s: invalid PHY interface mode\n", - dev_name(&mii->dev)); - goto err_free; + dev_name(&mdiodev->dev)); + return -EINVAL; } - if (of_property_read_bool(np, "phy4-mii-enable")) { + if (of_property_read_bool(as->of_node, "phy4-mii-enable")) { ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE1, AR934X_REG_OPER_MODE1_PHY4_MII_EN); swdev->ports = AR7240_NUM_PORTS - 1; @@ -1258,57 +1263,69 @@ ar7240_probe(struct ag71xx *ag, struct device_node *np) } } else { pr_err("%s: unsupported chip, ctrl=%08x\n", - dev_name(&mii->dev), ctrl); - goto err_free; + dev_name(&mdiodev->dev), ctrl); + return -EINVAL; } swdev->cpu_port = AR7240_PORT_CPU; swdev->vlans = AR7240_MAX_VLANS; swdev->ops = &ar7240_ops; + swdev->alias = dev_name(&mdiodev->dev); + + if ((err = register_switch(&as->swdev, NULL)) < 0) + return err; - if (register_switch(&as->swdev, ag->dev) < 0) - goto err_free; + pr_info("%s: Found an %s\n", dev_name(&mdiodev->dev), swdev->name); - pr_info("%s: Found an %s\n", dev_name(&mii->dev), swdev->name); + as->switch_mii_bus = devm_mdiobus_alloc(&mdiodev->dev); + as->switch_mii_bus->name = "ar7240sw_mdio"; + as->switch_mii_bus->read = ar7240sw_phy_read; + as->switch_mii_bus->write = ar7240sw_phy_write; + as->switch_mii_bus->priv = as; + as->switch_mii_bus->parent = &mdiodev->dev; + snprintf(as->switch_mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&mdiodev->dev)); + + if(as->mdio_node) { + err = of_mdiobus_register(as->switch_mii_bus, as->mdio_node); + if (err) + return err; + } /* initialize defaults */ for (i = 0; i < AR7240_MAX_VLANS; i++) as->vlan_id[i] = i; as->vlan_table[0] = ar7240sw_port_mask_all(as); - - return as; - -err_free: - kfree(as); - return NULL; -} - -int ag71xx_ar7240_init(struct ag71xx *ag, struct device_node *np) -{ - struct ar7240sw *as; - - as = ar7240_probe(ag, np); - if (!as) - return -ENODEV; - - ag->phy_priv = as; ar7240sw_reset(as); ar7240_hw_apply(&as->swdev); - rwlock_init(&as->stats_lock); - + dev_set_drvdata(&mdiodev->dev, as); return 0; } -void ag71xx_ar7240_cleanup(struct ag71xx *ag) +static void +ag71xx_ar7240_remove(struct mdio_device *mdiodev) { - struct ar7240sw *as = ag->phy_priv; - - if (!as) - return; - + struct ar7240sw *as = dev_get_drvdata(&mdiodev->dev); + if(as->mdio_node) + mdiobus_unregister(as->switch_mii_bus); unregister_switch(&as->swdev); - kfree(as); - ag->phy_priv = NULL; } + +static const struct of_device_id ag71xx_sw_of_match[] = { + { .compatible = "qca,ar8216-builtin" }, + { .compatible = "qca,ar8229-builtin" }, + { /* sentinel */ }, +}; + +static struct mdio_driver ag71xx_sw_driver = { + .probe = ag71xx_ar7240_probe, + .remove = ag71xx_ar7240_remove, + .mdiodrv.driver = { + .name = "ag71xx-switch", + .of_match_table = ag71xx_sw_of_match, + }, +}; + +mdio_module_driver(ag71xx_sw_driver); +MODULE_LICENSE("GPL"); |