mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
net: ethernet: stmmac: Fix loopback at dwmac-ethtool for rk3588
slove following issues: - socket buffer is over; - store phyaddr; - get max delayline value for rk3588; - split mac setting and phy setting for loopback to fix flow; - add rgmii-rxid interface loopback; - enable mtl configuration for multi queue; - use phy softreset instead of hard reset. Signed-off-by: David Wu <david.wu@rock-chips.com> Change-Id: I8da5a42948b34bf4a256a6f425c0ed98590ddea6
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -85,6 +86,7 @@ struct dwmac_rk_lb_priv {
|
||||
int rx;
|
||||
int final_tx;
|
||||
int final_rx;
|
||||
int max_delay;
|
||||
};
|
||||
|
||||
#define DMA_CONTROL_OSP BIT(4)
|
||||
@@ -99,6 +101,7 @@ struct dwmac_rk_lb_priv {
|
||||
|
||||
#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES)
|
||||
#define MAX_DELAYLINE 0x7f
|
||||
#define RK3588_MAX_DELAYLINE 0xc7
|
||||
#define SCAN_STEP 0x5
|
||||
#define SCAN_VALID_RANGE 0xA
|
||||
|
||||
@@ -119,7 +122,8 @@ static __maybe_unused struct dwmac_rk_packet_attrs dwmac_rk_tcp_attr = {
|
||||
.size = 1024,
|
||||
};
|
||||
|
||||
static int dwmac_rk_enable_mac_loopback(struct stmmac_priv *priv, int speed)
|
||||
static int dwmac_rk_enable_mac_loopback(struct stmmac_priv *priv, int speed,
|
||||
int addr, bool phy)
|
||||
{
|
||||
u32 ctrl;
|
||||
int phy_val;
|
||||
@@ -128,25 +132,30 @@ static int dwmac_rk_enable_mac_loopback(struct stmmac_priv *priv, int speed)
|
||||
ctrl &= ~priv->hw->link.speed_mask;
|
||||
ctrl |= GMAC_CONTROL_LM;
|
||||
|
||||
phy_val = mdiobus_read(priv->mii, priv->plat->phy_addr, MII_BMCR);
|
||||
if (phy)
|
||||
phy_val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
|
||||
switch (speed) {
|
||||
case LOOPBACK_SPEED1000:
|
||||
ctrl |= priv->hw->link.speed1000;
|
||||
phy_val |= BMCR_ANENABLE;
|
||||
phy_val |= BMCR_SPEED1000;
|
||||
if (phy) {
|
||||
phy_val &= ~BMCR_SPEED100;
|
||||
phy_val |= BMCR_SPEED1000;
|
||||
}
|
||||
break;
|
||||
case LOOPBACK_SPEED100:
|
||||
ctrl |= priv->hw->link.speed100;
|
||||
phy_val &= ~BMCR_ANENABLE;
|
||||
phy_val &= ~BMCR_SPEED1000;
|
||||
phy_val |= BMCR_SPEED100;
|
||||
if (phy) {
|
||||
phy_val &= ~BMCR_SPEED1000;
|
||||
phy_val |= BMCR_SPEED100;
|
||||
}
|
||||
break;
|
||||
case LOOPBACK_SPEED10:
|
||||
ctrl |= priv->hw->link.speed10;
|
||||
phy_val &= ~BMCR_ANENABLE;
|
||||
phy_val &= ~BMCR_SPEED1000;
|
||||
phy_val &= ~BMCR_SPEED100;
|
||||
if (phy) {
|
||||
phy_val &= ~BMCR_SPEED1000;
|
||||
phy_val &= ~BMCR_SPEED100;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EPERM;
|
||||
@@ -155,9 +164,14 @@ static int dwmac_rk_enable_mac_loopback(struct stmmac_priv *priv, int speed)
|
||||
ctrl |= priv->hw->link.duplex;
|
||||
writel(ctrl, priv->ioaddr + GMAC_CONTROL);
|
||||
|
||||
phy_val |= BMCR_FULLDPLX;
|
||||
mdiobus_write(priv->mii, priv->plat->phy_addr, MII_BMCR, phy_val);
|
||||
phy_val = mdiobus_read(priv->mii, priv->plat->phy_addr, MII_BMCR);
|
||||
if (phy) {
|
||||
phy_val &= ~BMCR_PDOWN;
|
||||
phy_val &= ~BMCR_ANENABLE;
|
||||
phy_val &= ~BMCR_PDOWN;
|
||||
phy_val |= BMCR_FULLDPLX;
|
||||
mdiobus_write(priv->mii, addr, MII_BMCR, phy_val);
|
||||
phy_val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
}
|
||||
|
||||
if (likely(priv->plat->fix_mac_speed))
|
||||
priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed);
|
||||
@@ -165,7 +179,7 @@ static int dwmac_rk_enable_mac_loopback(struct stmmac_priv *priv, int speed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac_rk_disable_mac_loopback(struct stmmac_priv *priv)
|
||||
static int dwmac_rk_disable_mac_loopback(struct stmmac_priv *priv, int addr)
|
||||
{
|
||||
u32 ctrl;
|
||||
int phy_val;
|
||||
@@ -174,25 +188,27 @@ static int dwmac_rk_disable_mac_loopback(struct stmmac_priv *priv)
|
||||
ctrl &= ~GMAC_CONTROL_LM;
|
||||
writel(ctrl, priv->ioaddr + GMAC_CONTROL);
|
||||
|
||||
phy_val = mdiobus_read(priv->mii, priv->plat->phy_addr, MII_BMCR);
|
||||
phy_val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
phy_val |= BMCR_ANENABLE;
|
||||
|
||||
mdiobus_write(priv->mii, priv->plat->phy_addr, MII_BMCR, phy_val);
|
||||
phy_val = mdiobus_read(priv->mii, priv->plat->phy_addr, MII_BMCR);
|
||||
mdiobus_write(priv->mii, addr, MII_BMCR, phy_val);
|
||||
phy_val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac_rk_set_mac_loopback(struct stmmac_priv *priv,
|
||||
int speed, bool enable)
|
||||
int speed, bool enable,
|
||||
int addr, bool phy)
|
||||
{
|
||||
if (enable)
|
||||
return dwmac_rk_enable_mac_loopback(priv, speed);
|
||||
return dwmac_rk_enable_mac_loopback(priv, speed, addr, phy);
|
||||
else
|
||||
return dwmac_rk_disable_mac_loopback(priv);
|
||||
return dwmac_rk_disable_mac_loopback(priv, addr);
|
||||
}
|
||||
|
||||
static int dwmac_rk_enable_phy_loopback(struct stmmac_priv *priv, int speed)
|
||||
static int dwmac_rk_enable_phy_loopback(struct stmmac_priv *priv, int speed,
|
||||
int addr, bool phy)
|
||||
{
|
||||
u32 ctrl;
|
||||
int val;
|
||||
@@ -200,25 +216,30 @@ static int dwmac_rk_enable_phy_loopback(struct stmmac_priv *priv, int speed)
|
||||
ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
|
||||
ctrl &= ~priv->hw->link.speed_mask;
|
||||
|
||||
val = mdiobus_read(priv->mii, 0, MII_BMCR);
|
||||
|
||||
val &= ~BMCR_ANENABLE;
|
||||
val |= BMCR_LOOPBACK;
|
||||
if (phy)
|
||||
val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
|
||||
switch (speed) {
|
||||
case LOOPBACK_SPEED1000:
|
||||
ctrl |= priv->hw->link.speed1000;
|
||||
val |= BMCR_SPEED1000;
|
||||
if (phy) {
|
||||
val &= ~BMCR_SPEED100;
|
||||
val |= BMCR_SPEED1000;
|
||||
}
|
||||
break;
|
||||
case LOOPBACK_SPEED100:
|
||||
ctrl |= priv->hw->link.speed100;
|
||||
val &= ~BMCR_SPEED1000;
|
||||
val |= BMCR_SPEED100;
|
||||
if (phy) {
|
||||
val &= ~BMCR_SPEED1000;
|
||||
val |= BMCR_SPEED100;
|
||||
}
|
||||
break;
|
||||
case LOOPBACK_SPEED10:
|
||||
ctrl |= priv->hw->link.speed10;
|
||||
val &= ~BMCR_SPEED1000;
|
||||
val &= ~BMCR_SPEED100;
|
||||
if (phy) {
|
||||
val &= ~BMCR_SPEED1000;
|
||||
val &= ~BMCR_SPEED100;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EPERM;
|
||||
@@ -227,9 +248,14 @@ static int dwmac_rk_enable_phy_loopback(struct stmmac_priv *priv, int speed)
|
||||
ctrl |= priv->hw->link.duplex;
|
||||
writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
|
||||
|
||||
val |= BMCR_FULLDPLX;
|
||||
mdiobus_write(priv->mii, 0, MII_BMCR, val);
|
||||
val = mdiobus_read(priv->mii, 0, MII_BMCR);
|
||||
if (phy) {
|
||||
val |= BMCR_FULLDPLX;
|
||||
val &= ~BMCR_PDOWN;
|
||||
val &= ~BMCR_ANENABLE;
|
||||
val |= BMCR_LOOPBACK;
|
||||
mdiobus_write(priv->mii, addr, MII_BMCR, val);
|
||||
val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
}
|
||||
|
||||
if (likely(priv->plat->fix_mac_speed))
|
||||
priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed);
|
||||
@@ -237,40 +263,43 @@ static int dwmac_rk_enable_phy_loopback(struct stmmac_priv *priv, int speed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac_rk_disable_phy_loopback(struct stmmac_priv *priv)
|
||||
static int dwmac_rk_disable_phy_loopback(struct stmmac_priv *priv, int addr)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = mdiobus_read(priv->mii, 0, MII_BMCR);
|
||||
val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
val |= BMCR_ANENABLE;
|
||||
val &= ~BMCR_LOOPBACK;
|
||||
|
||||
mdiobus_write(priv->mii, 0, MII_BMCR, val);
|
||||
val = mdiobus_read(priv->mii, priv->plat->phy_addr, MII_BMCR);
|
||||
mdiobus_write(priv->mii, addr, MII_BMCR, val);
|
||||
val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac_rk_set_phy_loopback(struct stmmac_priv *priv,
|
||||
int speed, bool enable)
|
||||
int speed, bool enable,
|
||||
int addr, bool phy)
|
||||
{
|
||||
if (enable)
|
||||
return dwmac_rk_enable_phy_loopback(priv, speed);
|
||||
return dwmac_rk_enable_phy_loopback(priv, speed,
|
||||
addr, phy);
|
||||
else
|
||||
return dwmac_rk_disable_phy_loopback(priv);
|
||||
return dwmac_rk_disable_phy_loopback(priv, addr);
|
||||
}
|
||||
|
||||
static int dwmac_rk_set_loopback(struct stmmac_priv *priv,
|
||||
int type, int speed, bool enable)
|
||||
int type, int speed, bool enable,
|
||||
int addr, bool phy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (type) {
|
||||
case LOOPBACK_TYPE_PHY:
|
||||
ret = dwmac_rk_set_phy_loopback(priv, speed, enable);
|
||||
ret = dwmac_rk_set_phy_loopback(priv, speed, enable, addr, phy);
|
||||
break;
|
||||
case LOOPBACK_TYPE_GMAC:
|
||||
ret = dwmac_rk_set_mac_loopback(priv, speed, enable);
|
||||
ret = dwmac_rk_set_mac_loopback(priv, speed, enable, addr, phy);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
@@ -565,6 +594,7 @@ static int dwmac_rk_rx_validate(struct stmmac_priv *priv,
|
||||
struct sk_buff *skb;
|
||||
int coe = priv->hw->rx_csum;
|
||||
unsigned int frame_len;
|
||||
int ret;
|
||||
|
||||
p = lb_priv->dma_rx;
|
||||
skb = lb_priv->rx_skbuff;
|
||||
@@ -584,7 +614,11 @@ static int dwmac_rk_rx_validate(struct stmmac_priv *priv,
|
||||
frame_len -= ETH_FCS_LEN;
|
||||
skb_put(skb, frame_len);
|
||||
|
||||
return dwmac_rk_loopback_validate(priv, lb_priv, skb);
|
||||
ret = dwmac_rk_loopback_validate(priv, lb_priv, skb);
|
||||
dwmac_rk_rx_clean(priv, lb_priv);
|
||||
dwmac_rk_rx_fill(priv, lb_priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac_rk_get_desc_status(struct stmmac_priv *priv,
|
||||
@@ -771,9 +805,20 @@ static int dwmac_rk_loopback_with_identify(struct stmmac_priv *priv,
|
||||
return __dwmac_rk_loopback_run(priv, lb_priv);
|
||||
}
|
||||
|
||||
static inline bool dwmac_rk_delayline_is_valid(int tx, int rx)
|
||||
static inline bool dwmac_rk_delayline_is_txvalid(struct dwmac_rk_lb_priv *lb_priv,
|
||||
int tx)
|
||||
{
|
||||
if ((tx > 0 && tx < MAX_DELAYLINE) && (rx > 0 && rx < MAX_DELAYLINE))
|
||||
if (tx > 0 && tx < lb_priv->max_delay)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool dwmac_rk_delayline_is_valid(struct dwmac_rk_lb_priv *lb_priv,
|
||||
int tx, int rx)
|
||||
{
|
||||
if ((tx > 0 && tx < lb_priv->max_delay) &&
|
||||
(rx > 0 && rx < lb_priv->max_delay))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@@ -784,7 +829,7 @@ static int dwmac_rk_delayline_scan_cross(struct stmmac_priv *priv,
|
||||
{
|
||||
int tx_left, tx_right, rx_up, rx_down;
|
||||
int i, j, tx_index, rx_index;
|
||||
int tx_mid, rx_mid;
|
||||
int tx_mid = 0, rx_mid = 0;
|
||||
|
||||
/* initiation */
|
||||
tx_index = SCAN_STEP;
|
||||
@@ -792,12 +837,12 @@ static int dwmac_rk_delayline_scan_cross(struct stmmac_priv *priv,
|
||||
|
||||
re_scan:
|
||||
/* start from rx based on the experience */
|
||||
for (i = rx_index; i <= (MAX_DELAYLINE - SCAN_STEP); i += SCAN_STEP) {
|
||||
for (i = rx_index; i <= (lb_priv->max_delay - SCAN_STEP); i += SCAN_STEP) {
|
||||
tx_left = 0;
|
||||
tx_right = 0;
|
||||
tx_mid = 0;
|
||||
|
||||
for (j = tx_index; j <= (MAX_DELAYLINE - SCAN_STEP);
|
||||
for (j = tx_index; j <= (lb_priv->max_delay - SCAN_STEP);
|
||||
j += SCAN_STEP) {
|
||||
if (!dwmac_rk_loopback_with_identify(priv,
|
||||
lb_priv, j, i)) {
|
||||
@@ -815,14 +860,14 @@ re_scan:
|
||||
}
|
||||
|
||||
/* Worst case: reach the end */
|
||||
if (i >= (MAX_DELAYLINE - SCAN_STEP))
|
||||
if (i >= (lb_priv->max_delay - SCAN_STEP))
|
||||
goto end;
|
||||
|
||||
rx_up = 0;
|
||||
rx_down = 0;
|
||||
|
||||
/* look for rx_mid base on the tx_mid */
|
||||
for (i = SCAN_STEP; i <= (MAX_DELAYLINE - SCAN_STEP);
|
||||
for (i = SCAN_STEP; i <= (lb_priv->max_delay - SCAN_STEP);
|
||||
i += SCAN_STEP) {
|
||||
if (!dwmac_rk_loopback_with_identify(priv, lb_priv,
|
||||
tx_mid, i)) {
|
||||
@@ -841,23 +886,24 @@ re_scan:
|
||||
goto re_scan;
|
||||
}
|
||||
|
||||
if (dwmac_rk_delayline_is_valid(tx_mid, rx_mid)) {
|
||||
if (dwmac_rk_delayline_is_valid(lb_priv, tx_mid, rx_mid)) {
|
||||
lb_priv->final_tx = tx_mid;
|
||||
lb_priv->final_rx = rx_mid;
|
||||
|
||||
pr_info("Find suitable tx_delay = 0x%02x, rx_delay = 0x%02x\n",
|
||||
pr_info("Find available tx_delay = 0x%02x, rx_delay = 0x%02x\n",
|
||||
lb_priv->final_tx, lb_priv->final_rx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
end:
|
||||
pr_err("Can't find suitable delayline\n");
|
||||
pr_err("Can't find available delayline\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int dwmac_rk_delayline_scan(struct stmmac_priv *priv,
|
||||
struct dwmac_rk_lb_priv *lb_priv)
|
||||
{
|
||||
int phy_iface = dwmac_rk_get_phy_interface(priv);
|
||||
int tx, rx, tx_sum, rx_sum, count;
|
||||
int tx_mid, rx_mid;
|
||||
int ret = -ENXIO;
|
||||
@@ -866,9 +912,11 @@ static int dwmac_rk_delayline_scan(struct stmmac_priv *priv,
|
||||
rx_sum = 0;
|
||||
count = 0;
|
||||
|
||||
for (rx = 0x0; rx <= MAX_DELAYLINE; rx++) {
|
||||
printk(KERN_CONT "RX(0x%02x):", rx);
|
||||
for (tx = 0x0; tx <= MAX_DELAYLINE; tx++) {
|
||||
for (rx = 0x0; rx <= lb_priv->max_delay; rx++) {
|
||||
if (phy_iface == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
rx = -1;
|
||||
printk(KERN_CONT "RX(%03d):", rx);
|
||||
for (tx = 0x0; tx <= lb_priv->max_delay; tx++) {
|
||||
if (!dwmac_rk_loopback_with_identify(priv,
|
||||
lb_priv, tx, rx)) {
|
||||
tx_sum += tx;
|
||||
@@ -880,24 +928,40 @@ static int dwmac_rk_delayline_scan(struct stmmac_priv *priv,
|
||||
}
|
||||
}
|
||||
printk(KERN_CONT "\n");
|
||||
|
||||
if (phy_iface == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tx_sum && rx_sum && count) {
|
||||
tx_mid = tx_sum / count;
|
||||
rx_mid = rx_sum / count;
|
||||
|
||||
if (dwmac_rk_delayline_is_valid(tx_mid, rx_mid)) {
|
||||
lb_priv->final_tx = tx_mid;
|
||||
lb_priv->final_rx = rx_mid;
|
||||
ret = 0;
|
||||
if (phy_iface == PHY_INTERFACE_MODE_RGMII_RXID) {
|
||||
if (dwmac_rk_delayline_is_txvalid(lb_priv, tx_mid)) {
|
||||
lb_priv->final_tx = tx_mid;
|
||||
lb_priv->final_rx = -1;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
if (dwmac_rk_delayline_is_valid(lb_priv, tx_mid, rx_mid)) {
|
||||
lb_priv->final_tx = tx_mid;
|
||||
lb_priv->final_rx = rx_mid;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pr_err("\nCan't find suitable delayline\n");
|
||||
else
|
||||
pr_info("\nFind suitable tx_delay = 0x%02x, rx_delay = 0x%02x\n",
|
||||
lb_priv->final_tx, lb_priv->final_rx);
|
||||
} else {
|
||||
if (phy_iface == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
pr_info("Find available tx_delay = 0x%02x, rx_delay = disable\n",
|
||||
lb_priv->final_tx);
|
||||
else
|
||||
pr_info("\nFind suitable tx_delay = 0x%02x, rx_delay = 0x%02x\n",
|
||||
lb_priv->final_tx, lb_priv->final_rx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1090,6 +1154,39 @@ static void dwmac_rk_dma_operation_mode(struct stmmac_priv *priv,
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac_rk_rx_queue_dma_chan_map(struct stmmac_priv *priv)
|
||||
{
|
||||
u32 rx_queues_count = min_t(u32, priv->plat->rx_queues_to_use, 1);
|
||||
u32 queue;
|
||||
u32 chan;
|
||||
|
||||
for (queue = 0; queue < rx_queues_count; queue++) {
|
||||
chan = priv->plat->rx_queues_cfg[queue].chan;
|
||||
stmmac_map_mtl_to_dma(priv, priv->hw, queue, chan);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac_rk_mac_enable_rx_queues(struct stmmac_priv *priv)
|
||||
{
|
||||
u32 rx_queues_count = min_t(u32, priv->plat->rx_queues_to_use, 1);
|
||||
int queue;
|
||||
u8 mode;
|
||||
|
||||
for (queue = 0; queue < rx_queues_count; queue++) {
|
||||
mode = priv->plat->rx_queues_cfg[queue].mode_to_use;
|
||||
stmmac_rx_queue_enable(priv, priv->hw, mode, queue);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac_rk_mtl_configuration(struct stmmac_priv *priv)
|
||||
{
|
||||
/* Map RX MTL to DMA channels */
|
||||
dwmac_rk_rx_queue_dma_chan_map(priv);
|
||||
|
||||
/* Enable MAC RX Queues */
|
||||
dwmac_rk_mac_enable_rx_queues(priv);
|
||||
}
|
||||
|
||||
static int dwmac_rk_init(struct net_device *dev,
|
||||
struct dwmac_rk_lb_priv *lb_priv)
|
||||
{
|
||||
@@ -1129,6 +1226,8 @@ static int dwmac_rk_init(struct net_device *dev,
|
||||
/* Initialize the MAC Core */
|
||||
stmmac_core_init(priv, priv->hw, dev);
|
||||
|
||||
dwmac_rk_mtl_configuration(priv);
|
||||
|
||||
ret = priv->hw->mac->rx_ipc(priv->hw);
|
||||
if (!ret) {
|
||||
pr_warn(" RX IPC Checksum Offload disabled\n");
|
||||
@@ -1173,17 +1272,51 @@ static void dwmac_rk_release(struct net_device *dev,
|
||||
dwmac_rk_free_dma_desc_resources(priv, lb_priv);
|
||||
}
|
||||
|
||||
static int dwmac_rk_get_max_delayline(struct stmmac_priv *priv)
|
||||
{
|
||||
if (of_device_is_compatible(priv->device->of_node,
|
||||
"rockchip,rk3588-gmac"))
|
||||
return RK3588_MAX_DELAYLINE;
|
||||
else
|
||||
return MAX_DELAYLINE;
|
||||
}
|
||||
|
||||
static int dwmac_rk_phy_poll_reset(struct stmmac_priv *priv, int addr)
|
||||
{
|
||||
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
|
||||
unsigned int val, retries = 12;
|
||||
int ret;
|
||||
|
||||
val = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
mdiobus_write(priv->mii, addr, MII_BMCR, val | BMCR_RESET);
|
||||
|
||||
do {
|
||||
msleep(50);
|
||||
ret = mdiobus_read(priv->mii, addr, MII_BMCR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} while (ret & BMCR_RESET && --retries);
|
||||
if (ret & BMCR_RESET)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
msleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac_rk_loopback_run(struct stmmac_priv *priv,
|
||||
struct dwmac_rk_lb_priv *lb_priv)
|
||||
{
|
||||
struct net_device *ndev = priv->dev;
|
||||
int phy_iface = dwmac_rk_get_phy_interface(priv);
|
||||
int ndev_up;
|
||||
int ndev_up, phy_addr;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!ndev || !priv->mii)
|
||||
return -EINVAL;
|
||||
|
||||
phy_addr = priv->dev->phydev->mdio.addr;
|
||||
lb_priv->max_delay = dwmac_rk_get_max_delayline(priv);
|
||||
|
||||
rtnl_lock();
|
||||
/* check the netdevice up or not */
|
||||
ndev_up = ndev->flags & IFF_UP;
|
||||
@@ -1206,25 +1339,29 @@ static int dwmac_rk_loopback_run(struct stmmac_priv *priv,
|
||||
|
||||
if (priv->plat->stmmac_rst)
|
||||
reset_control_assert(priv->plat->stmmac_rst);
|
||||
|
||||
if (priv->mii)
|
||||
priv->mii->reset(priv->mii);
|
||||
|
||||
dwmac_rk_phy_poll_reset(priv, phy_addr);
|
||||
if (priv->plat->stmmac_rst)
|
||||
reset_control_deassert(priv->plat->stmmac_rst);
|
||||
}
|
||||
/* wait for phy and controller ready */
|
||||
usleep_range(100000, 200000);
|
||||
|
||||
dwmac_rk_set_loopback(priv, lb_priv->type, lb_priv->speed,
|
||||
true, phy_addr, true);
|
||||
|
||||
ret = dwmac_rk_init(ndev, lb_priv);
|
||||
if (ret)
|
||||
goto exit_init;
|
||||
dwmac_rk_set_loopback(priv, lb_priv->type, lb_priv->speed, true);
|
||||
|
||||
dwmac_rk_set_loopback(priv, lb_priv->type, lb_priv->speed,
|
||||
true, phy_addr, false);
|
||||
|
||||
if (lb_priv->scan) {
|
||||
/* scan only support for rgmii mode */
|
||||
if (phy_iface != PHY_INTERFACE_MODE_RGMII &&
|
||||
phy_iface != PHY_INTERFACE_MODE_RGMII_ID) {
|
||||
phy_iface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
phy_iface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
phy_iface != PHY_INTERFACE_MODE_RGMII_TXID) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1240,8 +1377,8 @@ static int dwmac_rk_loopback_run(struct stmmac_priv *priv,
|
||||
|
||||
out:
|
||||
dwmac_rk_release(ndev, lb_priv);
|
||||
dwmac_rk_set_loopback(priv, lb_priv->type, lb_priv->speed, false);
|
||||
|
||||
dwmac_rk_set_loopback(priv, lb_priv->type, lb_priv->speed,
|
||||
false, phy_addr, false);
|
||||
exit_init:
|
||||
if (ndev_up)
|
||||
ndev->netdev_ops->ndo_open(ndev);
|
||||
@@ -1286,10 +1423,10 @@ static ssize_t rgmii_delayline_store(struct device *dev,
|
||||
*data = 0;
|
||||
data++;
|
||||
|
||||
if (kstrtoint(tmp, 0, &tx) || tx > MAX_DELAYLINE)
|
||||
if (kstrtoint(tmp, 0, &tx) || tx > dwmac_rk_get_max_delayline(priv))
|
||||
goto out;
|
||||
|
||||
if (kstrtoint(data, 0, &rx) || rx > MAX_DELAYLINE)
|
||||
if (kstrtoint(data, 0, &rx) || rx > dwmac_rk_get_max_delayline(priv))
|
||||
goto out;
|
||||
|
||||
dwmac_rk_set_rgmii_delayline(priv, tx, rx);
|
||||
|
||||
Reference in New Issue
Block a user