Commit b367e61c authored by Zhangfei Gao's avatar Zhangfei Gao Committed by Andrey Konovalov

ether: support eth1

test:
ifconfig eth1 192.168.1.99; ping 192.168.1.10

by default pc ethernet is 100M, also can work
Can be change via command:
host:
sudo ethtool eth0
sudo ethtool -s eth0 duplex full speed 1000
Signed-off-by: default avatarZhangfei Gao <zhangfei.gao@linaro.org>
parent 4f748ab9
......@@ -14,6 +14,8 @@
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/dmapool.h>
#include <linux/phy.h>
#include <linux/of_mdio.h>
#define PPE_CFG_RX_CFF_ADDR 0x100
#define PPE_CFG_POOL_GRP 0x300
......@@ -36,6 +38,18 @@
#define PPE_CFG_STS_MODE 0x700
#define PPE_HIS_RX_PKT_CNT 0x804
#define GE_MAX_FRM_SIZE_REG 0x3c
#define GE_SHORT_RUNTS_THR_REG 0x50
#define GE_TX_LOCAL_PAGE_REG 0x5c
#define GE_TRANSMIT_CONTROL_REG 0x60
#define GE_CF_CRC_STRIP_REG 0x1b0
#define GE_RECV_CONTROL_REG 0x1e0
#define PPE_CFG_MAX_FRAME_LEN_REG 0x408
#define PPE_CFG_BUS_CTRL_REG 0x424
#define PPE_CFG_RX_PKT_MODE_REG 0x438
#define GMAC_PPE_RX_PKT_MAX_LEN (379)
#define GMAC_MAX_PKT_LEN 1516
/* REG_INTERRUPT_MASK */
#define RCV_INT BIT(10)
#define RCV_NOBUF BIT(8)
......@@ -71,6 +85,7 @@ struct hip04_priv {
void __iomem *base;
unsigned int port;
unsigned int speed;
unsigned int duplex;
unsigned int id;
unsigned int reg_inten;
......@@ -90,6 +105,9 @@ struct hip04_priv {
unsigned char *rx_buf[RX_DESC_NUM];
unsigned int rx_head;
unsigned int rx_buf_size;
struct device_node *phy_node;
struct phy_device *phy;
};
static void __iomem *ppebase;
......@@ -98,49 +116,87 @@ static void hip04_config_port(struct hip04_priv *priv, u32 speed, u32 duplex)
{
u32 val, reg;
priv->speed = speed;
priv->duplex = duplex;
switch (speed) {
case SPEED_1000:
reg = 8;
break;
case SPEED_100:
reg = 1;
if (!priv->id)
reg = 1;
else
reg = 7;
break;
default:
reg = 0;
break;
}
val = readl_relaxed(priv->base + GE_PORT_MODE);
val &= ~(0xf);
val |= reg;
writel_relaxed(val, priv->base + GE_PORT_MODE);
reg = (duplex) ? BIT(1) : BIT(0);
reg = (duplex) ? BIT(0) : 0;
val = readl_relaxed(priv->base + GE_DUPLEX_TYPE);
val &= ~(0x1);
val |= reg;
writel_relaxed(val, priv->base + GE_DUPLEX_TYPE);
val = readl_relaxed(priv->base + GE_MODE_CHANGE_EN);
val |= BIT(1);
val |= BIT(0);
writel_relaxed(val, priv->base + GE_MODE_CHANGE_EN);
}
#ifdef OBSOLETE_CONFIG
#define GE_MAX_FRM_SIZE_REG 0x3c
#define GE_SHORT_RUNTS_THR_REG 0x50
#define GE_TX_LOCAL_PAGE_REG 0x5c
#define GE_TRANSMIT_CONTROL_REG 0x60
#define GE_CF_CRC_STRIP_REG 0x1b0
#define GE_RECV_CONTROL_REG 0x1e0
#define PPE_CFG_MAX_FRAME_LEN_REG 0x408
#define PPE_CFG_BUS_CTRL_REG 0x424
#define PPE_CFG_RX_PKT_MODE_REG 0x438
#define GMAC_PPE_RX_PKT_MAX_LEN (379)
#define GMAC_MAX_PKT_LEN 1516
static void hip04_reset_ppe(struct hip04_priv *priv)
{
u32 val;
do {
val =
readl_relaxed(ppebase + priv->port * 4 + PPE_CURR_BUF_CNT_REG);
readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_CFF_ADDR);
} while (val & 0xfff);
}
static void hip04_test_config(struct hip04_priv *priv)
static void hip04_config_fifo(struct hip04_priv *priv)
{
u32 val;
val = readl_relaxed(priv->base + PPE_CFG_STS_MODE);
val |= BIT(12); /* PPE_HIS_RX_PKT_CNT read clear */
writel_relaxed(val, priv->base + PPE_CFG_STS_MODE);
val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_POOL_GRP);
val |= BIT(priv->port);
writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_POOL_GRP);
val = readl_relaxed(priv->base + PPE_CFG_QOS_VMID_GEN);
val &= ~(0x7f00); /* [14:8]*/
val |= BIT(14);
val |= priv->port << 8;
writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN);
val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_BUF_SIZE);
val &= ~(0xffff); /* [15:0]*/
val |= RX_BUF_SIZE;
writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_RX_BUF_SIZE);
val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_FIFO_SIZE);
val &= ~(0xfff0fff); /* [27:16] [11:0]*/
val |= RX_DESC_NUM << 16; /* depth */
val |= BIT(11); /* seq: first set first ues */
val |= RX_DESC_NUM * priv->id; /* start_addr */
writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_RX_FIFO_SIZE);
/* pkt store format */
val = readl_relaxed(priv->base + PPE_CFG_RX_CTRL_REG);
val &= ~(0x1f80f); /* [16:11] [3:0]*/
val |= 2 << 11; /* align */
writel_relaxed(val, priv->base + PPE_CFG_RX_CTRL_REG);
/* following cfg required for 1000M */
/* pkt mode */
val = readl_relaxed(priv->base + PPE_CFG_RX_PKT_MODE_REG);
val &= ~(0xc0000); /* [19:18] */
......@@ -150,8 +206,6 @@ static void hip04_test_config(struct hip04_priv *priv)
/* set bus ctrl */
val = 1 << 14; /* buffer locally release */
val |= 1; /* big endian */
/* fixme: fe only ?*/
val &= ~BIT(7); /* disable poe */
writel_relaxed(val, priv->base + PPE_CFG_BUS_CTRL_REG);
/* set max pkt len, curtail if exceed */
......@@ -183,9 +237,10 @@ static void hip04_test_config(struct hip04_priv *priv)
val |= 1; /* rx strip crc */
writel_relaxed(val, priv->base + GE_CF_CRC_STRIP_REG);
/* rx pad */
/* rx */
val = readl_relaxed(priv->base + GE_RECV_CONTROL_REG);
val |= 1 << 3; /* rx strip pad */
val |= 1 << 4; /* run pkt en */
writel_relaxed(val, priv->base + GE_RECV_CONTROL_REG);
/* auto neg control */
......@@ -196,55 +251,6 @@ static void hip04_test_config(struct hip04_priv *priv)
val &= ~(0x8000); /* [15] = 0*/
writel_relaxed(val, priv->base + GE_TX_LOCAL_PAGE_REG);
}
#endif
static void hip04_reset_ppe(struct hip04_priv *priv)
{
u32 val;
do {
val =
readl_relaxed(ppebase + priv->port * 4 + PPE_CURR_BUF_CNT_REG);
readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_CFF_ADDR);
} while (val & 0xfff);
}
static void hip04_config_fifo(struct hip04_priv *priv)
{
u32 val;
val = readl_relaxed(priv->base + PPE_CFG_STS_MODE);
val |= BIT(12); /* PPE_HIS_RX_PKT_CNT read clear */
writel_relaxed(val, priv->base + PPE_CFG_STS_MODE);
val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_POOL_GRP);
val |= BIT(priv->port);
writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_POOL_GRP);
val = readl_relaxed(priv->base + PPE_CFG_QOS_VMID_GEN);
val &= ~(0x7f00); /* [14:8]*/
val |= BIT(14);
val |= priv->port << 8;
writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN);
val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_BUF_SIZE);
val &= ~(0xffff); /* [15:0]*/
val |= RX_BUF_SIZE;
writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_RX_BUF_SIZE);
val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_FIFO_SIZE);
val &= ~(0xfff0fff); /* [27:16] [11:0]*/
val |= RX_DESC_NUM << 16; /* depth */
val |= BIT(11); /* seq: first set first ues */
val |= RX_DESC_NUM * priv->id; /* start_addr */
writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_RX_FIFO_SIZE);
/* pkt store format */
val = readl_relaxed(priv->base + PPE_CFG_RX_CTRL_REG);
val &= ~(0x1f80f); /* [16:11] [3:0]*/
val |= 2 << 11; /* align */
writel_relaxed(val, priv->base + PPE_CFG_RX_CTRL_REG);
}
static void hip04_mac_enable(struct net_device *ndev, bool enable)
{
......@@ -502,6 +508,15 @@ out_unlock:
return ret;
}
static void hip04_adjust_link(struct net_device *ndev)
{
struct hip04_priv *priv = netdev_priv(ndev);
struct phy_device *phy = priv->phy;
if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex))
hip04_config_port(priv, phy->speed, phy->duplex);
}
static int hip04_mac_open(struct net_device *ndev)
{
struct hip04_priv *priv = netdev_priv(ndev);
......@@ -520,6 +535,14 @@ static int hip04_mac_open(struct net_device *ndev)
priv->tx_tail = 0;
priv->tx_count = 0;
if (priv->phy_node) {
priv->phy = of_phy_connect(ndev, priv->phy_node,
&hip04_adjust_link, 0, PHY_INTERFACE_MODE_GMII);
if (!priv->phy)
return -ENODEV;
phy_start(priv->phy);
}
netif_start_queue(ndev);
hip04_mac_enable(ndev, true);
napi_enable(&priv->napi);
......@@ -663,7 +686,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
if (!ppebase) {
struct device_node *n;
n = of_find_compatible_node(NULL, NULL, "hisilicon,ppebase");
n = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-ppebase");
if (!n) {
ret = -EINVAL;
netdev_err(ndev, "not find hisilicon,ppebase\n");
......@@ -689,6 +712,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
priv->speed = SPEED_100;
else
priv->speed = SPEED_1000;
priv->duplex = DUPLEX_FULL;
/* fixme any id can be used directly? */
ret = of_property_read_u32(node, "id", &priv->id);
......@@ -710,7 +734,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, &pdev->dev);
hip04_reset_ppe(priv);
hip04_config_port(priv, priv->speed, DUPLEX_FULL);
hip04_config_port(priv, priv->speed, priv->duplex);
hip04_config_fifo(priv);
random_ether_addr(ndev->dev_addr);
hip04_update_mac_address(ndev);
......@@ -730,6 +754,8 @@ static int hip04_mac_probe(struct platform_device *pdev)
goto init_fail;
}
priv->phy_node = of_parse_phandle(node, "phy-handle", 0);
ret = register_netdev(ndev);
if (ret) {
free_netdev(ndev);
......@@ -740,6 +766,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
alloc_fail:
hip04_free_ring(ndev);
init_fail:
of_node_put(priv->phy_node);
free_netdev(ndev);
return ret;
}
......@@ -747,11 +774,13 @@ init_fail:
static int hip04_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct hip04_priv *priv = netdev_priv(ndev);
unregister_netdev(ndev);
free_irq(ndev->irq, ndev);
free_netdev(ndev);
free_netdev(ndev);
of_node_put(priv->phy_node);
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment