diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c index d45eb0c43cee..8a4853a5d715 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -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);