#include <linux/sizes.h>
#include <linux/of_net.h>
#include <linux/of_address.h>
+#include <linux/of_platform.h>
#include "ag71xx.h"
#define AG71XX_DEFAULT_MSG_ENABLE \
ag71xx_rr(ag, AG71XX_REG_RX_STATUS));
}
+static void ag71xx_dump_regs(struct ag71xx *ag)
+{
+ DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n",
+ ag->dev->name,
+ ag71xx_rr(ag, AG71XX_REG_MAC_CFG1),
+ ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
+ ag71xx_rr(ag, AG71XX_REG_MAC_IPG),
+ ag71xx_rr(ag, AG71XX_REG_MAC_HDX),
+ ag71xx_rr(ag, AG71XX_REG_MAC_MFL));
+ DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n",
+ ag->dev->name,
+ ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
+ ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1),
+ ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2));
+ DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n",
+ ag->dev->name,
+ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
+ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
+ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
+ DBG("%s: fifo_cfg3=%08x, fifo_cfg4=%08x, fifo_cfg5=%08x\n",
+ ag->dev->name,
+ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
+ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
+ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
+}
+
static inline void ag71xx_dump_intr(struct ag71xx *ag, char *label, u32 intr)
{
DBG("%s: %s intr=%08x %s%s%s%s%s%s\n",
{
ag71xx_hw_stop(ag);
- if (ag->phy_reset) {
- reset_control_assert(ag->phy_reset);
- msleep(50);
- reset_control_deassert(ag->phy_reset);
- msleep(200);
- }
-
ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
udelay(20);
reset_control_assert(ag->mac_reset);
+ if (ag->mdio_reset)
+ reset_control_assert(ag->mdio_reset);
msleep(100);
reset_control_deassert(ag->mac_reset);
+ if (ag->mdio_reset)
+ reset_control_deassert(ag->mdio_reset);
msleep(200);
ag71xx_hw_setup(ag);
udelay(100);
}
+static void ath79_mii_ctrl_set_if(struct ag71xx *ag, unsigned int mii_if)
+{
+ u32 t;
+
+ t = __raw_readl(ag->mii_base);
+ t &= ~(AR71XX_MII_CTRL_IF_MASK);
+ t |= (mii_if & AR71XX_MII_CTRL_IF_MASK);
+ __raw_writel(t, ag->mii_base);
+}
+
+static void ath79_mii0_ctrl_set_if(struct ag71xx *ag)
+{
+ unsigned int mii_if;
+
+ switch (ag->phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ mii_if = AR71XX_MII0_CTRL_IF_MII;
+ break;
+ case PHY_INTERFACE_MODE_GMII:
+ mii_if = AR71XX_MII0_CTRL_IF_GMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ mii_if = AR71XX_MII0_CTRL_IF_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ mii_if = AR71XX_MII0_CTRL_IF_RMII;
+ break;
+ default:
+ WARN(1, "Impossible PHY mode defined.\n");
+ return;
+ }
+
+ ath79_mii_ctrl_set_if(ag, mii_if);
+}
+
+static void ath79_mii1_ctrl_set_if(struct ag71xx *ag)
+{
+ unsigned int mii_if;
+
+ switch (ag->phy_if_mode) {
+ case PHY_INTERFACE_MODE_RMII:
+ mii_if = AR71XX_MII1_CTRL_IF_RMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ mii_if = AR71XX_MII1_CTRL_IF_RGMII;
+ break;
+ default:
+ WARN(1, "Impossible PHY mode defined.\n");
+ return;
+ }
+
+ ath79_mii_ctrl_set_if(ag, mii_if);
+}
+
static void ath79_mii_ctrl_set_speed(struct ag71xx *ag)
{
unsigned int mii_speed;
}
t = __raw_readl(ag->mii_base);
- t &= ~(AR71XX_MII_CTRL_IF_MASK);
- t |= (mii_speed & AR71XX_MII_CTRL_IF_MASK);
+ t &= ~(AR71XX_MII_CTRL_SPEED_MASK << AR71XX_MII_CTRL_SPEED_SHIFT);
+ t |= mii_speed << AR71XX_MII_CTRL_SPEED_SHIFT;
__raw_writel(t, ag->mii_base);
}
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, ag->fifodata[2]);
if (update) {
- if (of_device_is_compatible(np, "qca,ar7100-eth")) {
+ if (of_device_is_compatible(np, "qca,ar7100-eth") ||
+ of_device_is_compatible(np, "qca,ar9130-eth")) {
ath79_set_pll(ag);
ath79_mii_ctrl_set_speed(ag);
- } else if (of_device_is_compatible(np, "qca,ar7242-eth")) {
- ath79_set_pll(ag);
- } else if (of_device_is_compatible(np, "qca,ar9130-eth")) {
- } else if (of_device_is_compatible(np, "qca,ar9340-eth")) {
- } else if (of_device_is_compatible(np, "qca,qca9550-eth")) {
- } else if (of_device_is_compatible(np, "qca,qca9560-eth")) {
+ } else if (of_device_is_compatible(np, "qca,ar7242-eth") ||
+ of_device_is_compatible(np, "qca,ar9340-eth") ||
+ of_device_is_compatible(np, "qca,qca9550-eth") ||
+ of_device_is_compatible(np, "qca,qca9560-eth")) {
+ ath79_set_pllval(ag);
}
}
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
- if (of_device_is_compatible(np, "qca,qca9530-eth")) {
+ if (of_device_is_compatible(np, "qca,qca9530-eth") ||
+ of_device_is_compatible(np, "qca,qca9560-eth")) {
/*
* The rx ring buffer can stall on small packets on QCA953x and
* QCA956x. Disabling the inline checksum engine fixes the stall.
ag71xx_speed_str(ag),
(DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
- DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
- ag->dev->name,
- ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
- ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
- ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
-
- DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
- ag->dev->name,
- ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
- ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
- ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
-
- DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x\n",
- ag->dev->name,
- ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
- ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL));
+ ag71xx_dump_regs(ag);
}
void ag71xx_link_adjust(struct ag71xx *ag)
if (ret)
goto err;
- ag71xx_ar7240_start(ag);
phy_start(ag->phy_dev);
return 0;
static int ag71xx_stop(struct net_device *dev)
{
+ unsigned long flags;
struct ag71xx *ag = netdev_priv(dev);
netif_carrier_off(dev);
phy_stop(ag->phy_dev);
+
+ spin_lock_irqsave(&ag->lock, flags);
+ if (ag->link) {
+ ag->link = 0;
+ ag71xx_link_adjust(ag);
+ }
+ spin_unlock_irqrestore(&ag->lock, flags);
+
ag71xx_hw_disable(ag);
return 0;
#endif
};
-static const char *ag71xx_get_phy_if_mode_name(phy_interface_t mode)
-{
- switch (mode) {
- case PHY_INTERFACE_MODE_MII:
- return "MII";
- case PHY_INTERFACE_MODE_GMII:
- return "GMII";
- case PHY_INTERFACE_MODE_RMII:
- return "RMII";
- case PHY_INTERFACE_MODE_RGMII:
- return "RGMII";
- case PHY_INTERFACE_MODE_SGMII:
- return "SGMII";
- default:
- break;
- }
-
- return "unknown";
-}
-
-static void ag71xx_of_bit(struct device_node *np, const char *prop,
- u32 *reg, u32 mask)
-{
- u32 val;
-
- if (of_property_read_u32(np, prop, &val))
- return;
-
- if (val)
- *reg |= mask;
- else
- *reg &= ~mask;
-}
-
-static void ag71xx_setup_gmac_933x(struct device_node *np, void __iomem *base)
-{
- u32 val = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
-
- ag71xx_of_bit(np, "switch-phy-swap", &val, AR933X_ETH_CFG_SW_PHY_SWAP);
- ag71xx_of_bit(np, "switch-phy-addr-swap", &val,
- AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
-
- __raw_writel(val, base + AR933X_GMAC_REG_ETH_CFG);
-}
-
-static int ag71xx_setup_gmac(struct device_node *np)
-{
- struct device_node *np_dev;
- void __iomem *base;
- int err = 0;
-
- np = of_get_child_by_name(np, "gmac-config");
- if (!np)
- return 0;
-
- np_dev = of_parse_phandle(np, "device", 0);
- if (!np_dev)
- goto out;
-
- base = of_iomap(np_dev, 0);
- if (!base) {
- pr_err("%pOF: can't map GMAC registers\n", np_dev);
- err = -ENOMEM;
- goto err_iomap;
- }
-
- if (of_device_is_compatible(np_dev, "qca,ar9330-gmac"))
- ag71xx_setup_gmac_933x(np, base);
-
- iounmap(base);
-
-err_iomap:
- of_node_put(np_dev);
-out:
- of_node_put(np);
- return err;
-}
-
static int ag71xx_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
if (!np)
return -ENODEV;
- dev = alloc_etherdev(sizeof(*ag));
+ dev = devm_alloc_etherdev(&pdev->dev, sizeof(*ag));
if (!dev)
return -ENOMEM;
AG71XX_DEFAULT_MSG_ENABLE);
spin_lock_init(&ag->lock);
- ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac");
+ ag->mac_reset = devm_reset_control_get_exclusive(&pdev->dev, "mac");
if (IS_ERR(ag->mac_reset)) {
dev_err(&pdev->dev, "missing mac reset\n");
- err = PTR_ERR(ag->mac_reset);
- goto err_free;
+ return PTR_ERR(ag->mac_reset);
}
- ag->phy_reset = devm_reset_control_get_optional(&pdev->dev, "phy");
+ ag->mdio_reset = devm_reset_control_get_optional_exclusive(&pdev->dev, "mdio");
if (of_property_read_u32_array(np, "fifo-data", ag->fifodata, 3)) {
if (of_device_is_compatible(np, "qca,ar9130-eth") ||
ag->mac_base = devm_ioremap_nocache(&pdev->dev, res->start,
res->end - res->start + 1);
- if (!ag->mac_base) {
- err = -ENOMEM;
- goto err_free;
- }
+ if (!ag->mac_base)
+ return -ENOMEM;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
ag->mii_base = devm_ioremap_nocache(&pdev->dev, res->start,
res->end - res->start + 1);
- if (!ag->mii_base) {
- err = -ENOMEM;
- goto err_free;
- }
+ if (!ag->mii_base)
+ return -ENOMEM;
}
dev->irq = platform_get_irq(pdev, 0);
0x0, dev_name(&pdev->dev), dev);
if (err) {
dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
- goto err_free;
+ return err;
}
dev->netdev_ops = &ag71xx_netdev_ops;
sizeof(struct ag71xx_desc),
&ag->stop_desc_dma, GFP_KERNEL);
if (!ag->stop_desc)
- goto err_free;
+ return -ENOMEM;
ag->stop_desc->data = 0;
ag->stop_desc->ctrl = 0;
ag->phy_if_mode = of_get_phy_mode(np);
if (ag->phy_if_mode < 0) {
dev_err(&pdev->dev, "missing phy-mode property in DT\n");
- err = ag->phy_if_mode;
- goto err_free;
+ return ag->phy_if_mode;
}
+ if (of_property_read_u32(np, "qca,mac-idx", &ag->mac_idx))
+ ag->mac_idx = -1;
+ if (ag->mii_base)
+ switch (ag->mac_idx) {
+ case 0:
+ ath79_mii0_ctrl_set_if(ag);
+ break;
+ case 1:
+ ath79_mii1_ctrl_set_if(ag);
+ break;
+ default:
+ break;
+ }
+
netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
+ ag71xx_dump_regs(ag);
+
ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0);
+
ag71xx_hw_init(ag);
- ag71xx_mdio_init(ag);
+
+ ag71xx_dump_regs(ag);
+
+ /*
+ * populate current node to register mdio-bus as a subdevice.
+ * the mdio bus works independently on ar7241 and later chips
+ * and we need to load mdio1 before gmac0, which can be done
+ * by adding a "simple-mfd" compatible to gmac node. The
+ * following code checks OF_POPULATED_BUS flag before populating
+ * to avoid duplicated population.
+ */
+ if (!of_node_check_flag(np, OF_POPULATED_BUS)) {
+ err = of_platform_populate(np, NULL, NULL, &pdev->dev);
+ if (err)
+ return err;
+ }
err = ag71xx_phy_connect(ag);
if (err)
- goto err_mdio_free;
+ return err;
err = ag71xx_debugfs_init(ag);
if (err)
goto err_phy_disconnect;
}
- pr_info("%s: Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n",
+ pr_info("%s: Atheros AG71xx at 0x%08lx, irq %d, mode: %s\n",
dev->name, (unsigned long) ag->mac_base, dev->irq,
- ag71xx_get_phy_if_mode_name(ag->phy_if_mode));
+ phy_modes(ag->phy_if_mode));
return 0;
err_phy_disconnect:
ag71xx_phy_disconnect(ag);
-err_mdio_free:
- ag71xx_mdio_cleanup(ag);
-err_free:
- free_netdev(dev);
return err;
}
ag = netdev_priv(dev);
ag71xx_debugfs_exit(ag);
ag71xx_phy_disconnect(ag);
- ag71xx_mdio_cleanup(ag);
unregister_netdev(dev);
- free_irq(dev->irq, dev);
- iounmap(ag->mac_base);
- kfree(dev);
platform_set_drvdata(pdev, NULL);
-
return 0;
}