You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
3.9 KiB
C

/*
* Atheros AR71xx built-in ethernet mac driver
*
* 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.
*/
#include <linux/sizes.h>
#include <linux/of_address.h>
#include "ag71xx.h"
static void ag71xx_of_set(struct device_node *np, const char *prop,
u32 *reg, u32 shift, u32 mask)
{
u32 val;
if (of_property_read_u32(np, prop, &val))
return;
*reg &= ~(mask << shift);
*reg |= ((val & mask) << shift);
}
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 void ag71xx_setup_gmac_934x(struct device_node *np, void __iomem *base)
{
u32 val = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
ag71xx_of_bit(np, "rgmii-gmac0", &val, AR934X_ETH_CFG_RGMII_GMAC0);
ag71xx_of_bit(np, "mii-gmac0", &val, AR934X_ETH_CFG_MII_GMAC0);
ag71xx_of_bit(np, "mii-gmac0-slave", &val, AR934X_ETH_CFG_MII_GMAC0_SLAVE);
ag71xx_of_bit(np, "gmii-gmac0", &val, AR934X_ETH_CFG_GMII_GMAC0);
ag71xx_of_bit(np, "switch-phy-swap", &val, AR934X_ETH_CFG_SW_PHY_SWAP);
ag71xx_of_bit(np, "switch-only-mode", &val,
AR934X_ETH_CFG_SW_ONLY_MODE);
ath79: gmac: add parsers for rxd(v)- and tx(d|en)-delay for AR9344 Some AR9344 boards do very poorly with the default settings and need custom rxdv-delay, rxd-delay, txd-delay, txen-delay flags to perform reasonably. In this case the WD My Net Wi-Fi Range Extender can not even manage 10Mbps on a 1Gbit link: root@AR9344:~# iperf3 -s ----------------------------------------------------------- Server listening on 5201 ----------------------------------------------------------- Accepted connection from client [...] [ 5] local [...] connected to client [ ID] Interval Transfer Bitrate [ 5] 0.00-1.00 sec 1.09 MBytes 9.16 Mbits/sec [ 5] 1.00-2.00 sec 895 KBytes 7.33 Mbits/sec [ 5] 2.00-3.00 sec 762 KBytes 6.25 Mbits/sec [...] [ 5] 10.00-10.03 sec 17.0 KBytes 4.74 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate [ 5] 0.00-10.03 sec 9.00 MBytes 7.52 Mbits/sec with but with the correct settings in place, it does much better: root@AR9344:~# iperf3 -s ----------------------------------------------------------- Server listening on 5201 ----------------------------------------------------------- Accepted connection from client [...] [ 5] local [...] connected to client [ ID] Interval Transfer Bitrate [ 5] 0.00-1.00 sec 23.1 MBytes 193 Mbits/sec [ 5] 1.00-2.00 sec 23.1 MBytes 194 Mbits/sec [ 5] 2.00-3.00 sec 23.2 MBytes 195 Mbits/sec [...] [ 5] 10.00-10.04 sec 710 KBytes 180 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate [ 5] 0.00-10.04 sec 237 MBytes 198 Mbits/sec The tx data and enable delay bits definitions are taken from Atheros' AR9344 Data Sheet Section "8.6.1 Ethernet Configuration (ETH_CFG)" on page 153. Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
6 years ago
ag71xx_of_set(np, "rxdv-delay", &val,
AR934X_ETH_CFG_RDV_DELAY_SHIFT, 0x3);
ag71xx_of_set(np, "rxd-delay", &val,
AR934X_ETH_CFG_RXD_DELAY_SHIFT, 0x3);
ag71xx_of_set(np, "txd-delay", &val,
AR934X_ETH_CFG_TXD_DELAY_SHIFT, 0x3);
ag71xx_of_set(np, "txen-delay", &val,
AR934X_ETH_CFG_TXE_DELAY_SHIFT, 0x3);
__raw_writel(val, base + AR934X_GMAC_REG_ETH_CFG);
}
static void ag71xx_setup_gmac_955x(struct device_node *np, void __iomem *base)
{
u32 val = __raw_readl(base + QCA955X_GMAC_REG_ETH_CFG);
ag71xx_of_bit(np, "rgmii-enabled", &val, QCA955X_ETH_CFG_RGMII_EN);
ag71xx_of_bit(np, "ge0-sgmii", &val, QCA955X_ETH_CFG_GE0_SGMII);
ag71xx_of_set(np, "txen-delay", &val, QCA955X_ETH_CFG_TXE_DELAY_SHIFT, 0x3);
ag71xx_of_set(np, "txd-delay", &val, QCA955X_ETH_CFG_TXD_DELAY_SHIFT, 0x3);
ag71xx_of_set(np, "rxdv-delay", &val, QCA955X_ETH_CFG_RDV_DELAY_SHIFT, 0x3);
ag71xx_of_set(np, "rxd-delay", &val, QCA955X_ETH_CFG_RXD_DELAY_SHIFT, 0x3);
__raw_writel(val, base + QCA955X_GMAC_REG_ETH_CFG);
}
static void ag71xx_setup_gmac_956x(struct device_node *np, void __iomem *base)
{
u32 val = __raw_readl(base + QCA956X_GMAC_REG_ETH_CFG);
ag71xx_of_bit(np, "switch-phy-swap", &val, QCA956X_ETH_CFG_SW_PHY_SWAP);
ag71xx_of_bit(np, "switch-phy-addr-swap", &val,
QCA956X_ETH_CFG_SW_PHY_ADDR_SWAP);
__raw_writel(val, base + QCA956X_GMAC_REG_ETH_CFG);
}
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);
else if (of_device_is_compatible(np_dev, "qca,ar9340-gmac"))
ag71xx_setup_gmac_934x(np, base);
else if (of_device_is_compatible(np_dev, "qca,qca9550-gmac"))
ag71xx_setup_gmac_955x(np, base);
else if (of_device_is_compatible(np_dev, "qca,qca9560-gmac"))
ag71xx_setup_gmac_956x(np, base);
iounmap(base);
err_iomap:
of_node_put(np_dev);
out:
of_node_put(np);
return err;
}