Commit 21651635 authored by David S. Miller's avatar David S. Miller

Merge branch 'mtk-star-emac-features'

Biao Huang says:

====================
net: add more features for mtk-star-emac

Changes in v4:
1. correct the usage of spin_lock/__napi_schedule.
2. fix coding style as Jakub's comments.

Changes in v3:
1. refractor driver as Jakub's comments in patch
   "net: ethernet: mtk-star-emac: separate tx/rx handling with two NAPIs".
2. add acked-by as Rob's comments.
3. add a new patch for halp-duplex support in driver.

Changes in v2:
1. fix coding style as Bartosz's comments.
2. add reviewed-by as Bartosz's comments.

This series add more features for mtk-star-emac:
1. add reference clock pad selection for RMII;
2. add simple timing adjustment for RMII;
3. add support for MII;
4. add support for new IC MT8365;
5. separate tx/rx interrupt handling.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bfc71514 02e9ce07
......@@ -23,6 +23,7 @@ properties:
- mediatek,mt8516-eth
- mediatek,mt8518-eth
- mediatek,mt8175-eth
- mediatek,mt8365-eth
reg:
maxItems: 1
......@@ -47,6 +48,22 @@ properties:
Phandle to the device containing the PERICFG register range. This is used
to control the MII mode.
mediatek,rmii-rxc:
type: boolean
description:
If present, indicates that the RMII reference clock, which is from external
PHYs, is connected to RXC pin. Otherwise, is connected to TXC pin.
mediatek,rxc-inverse:
type: boolean
description:
If present, indicates that clock on RXC pad will be inversed.
mediatek,txc-inverse:
type: boolean
description:
If present, indicates that clock on TXC pad will be inversed.
mdio:
$ref: mdio.yaml#
unevaluatedProperties: false
......
......@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/platform_device.h>
......@@ -32,6 +33,7 @@
#define MTK_STAR_SKB_ALIGNMENT 16
#define MTK_STAR_HASHTABLE_MC_LIMIT 256
#define MTK_STAR_HASHTABLE_SIZE_MAX 512
#define MTK_STAR_DESC_NEEDED (MAX_SKB_FRAGS + 4)
/* Normally we'd use NET_IP_ALIGN but on arm64 its value is 0 and it doesn't
* work for this controller.
......@@ -129,6 +131,11 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
#define MTK_STAR_REG_INT_MASK 0x0054
#define MTK_STAR_BIT_INT_MASK_FNRC BIT(6)
/* Delay-Macro Register */
#define MTK_STAR_REG_TEST0 0x0058
#define MTK_STAR_BIT_INV_RX_CLK BIT(30)
#define MTK_STAR_BIT_INV_TX_CLK BIT(31)
/* Misc. Config Register */
#define MTK_STAR_REG_TEST1 0x005c
#define MTK_STAR_BIT_TEST1_RST_HASH_MBIST BIT(31)
......@@ -149,6 +156,7 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
#define MTK_STAR_REG_MAC_CLK_CONF 0x00ac
#define MTK_STAR_MSK_MAC_CLK_CONF GENMASK(7, 0)
#define MTK_STAR_BIT_CLK_DIV_10 0x0a
#define MTK_STAR_BIT_CLK_DIV_50 0x32
/* Counter registers. */
#define MTK_STAR_REG_C_RXOKPKT 0x0100
......@@ -181,9 +189,14 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
#define MTK_STAR_REG_C_RX_TWIST 0x0218
/* Ethernet CFG Control */
#define MTK_PERICFG_REG_NIC_CFG_CON 0x03c4
#define MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII GENMASK(3, 0)
#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII BIT(0)
#define MTK_PERICFG_REG_NIC_CFG0_CON 0x03c4
#define MTK_PERICFG_REG_NIC_CFG1_CON 0x03c8
#define MTK_PERICFG_REG_NIC_CFG_CON_V2 0x0c10
#define MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF GENMASK(3, 0)
#define MTK_PERICFG_BIT_NIC_CFG_CON_MII 0
#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII 1
#define MTK_PERICFG_BIT_NIC_CFG_CON_CLK BIT(0)
#define MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2 BIT(8)
/* Represents the actual structure of descriptors used by the MAC. We can
* reuse the same structure for both TX and RX - the layout is the same, only
......@@ -216,7 +229,8 @@ struct mtk_star_ring_desc_data {
struct sk_buff *skb;
};
#define MTK_STAR_RING_NUM_DESCS 128
#define MTK_STAR_RING_NUM_DESCS 512
#define MTK_STAR_TX_THRESH (MTK_STAR_RING_NUM_DESCS / 4)
#define MTK_STAR_NUM_TX_DESCS MTK_STAR_RING_NUM_DESCS
#define MTK_STAR_NUM_RX_DESCS MTK_STAR_RING_NUM_DESCS
#define MTK_STAR_NUM_DESCS_TOTAL (MTK_STAR_RING_NUM_DESCS * 2)
......@@ -231,6 +245,11 @@ struct mtk_star_ring {
unsigned int tail;
};
struct mtk_star_compat {
int (*set_interface_mode)(struct net_device *ndev);
unsigned char bit_clk_div;
};
struct mtk_star_priv {
struct net_device *ndev;
......@@ -246,7 +265,8 @@ struct mtk_star_priv {
struct mtk_star_ring rx_ring;
struct mii_bus *mii;
struct napi_struct napi;
struct napi_struct tx_napi;
struct napi_struct rx_napi;
struct device_node *phy_node;
phy_interface_t phy_intf;
......@@ -255,6 +275,11 @@ struct mtk_star_priv {
int speed;
int duplex;
int pause;
bool rmii_rxc;
bool rx_inv;
bool tx_inv;
const struct mtk_star_compat *compat_data;
/* Protects against concurrent descriptor access. */
spinlock_t lock;
......@@ -357,19 +382,16 @@ mtk_star_ring_push_head_tx(struct mtk_star_ring *ring,
mtk_star_ring_push_head(ring, desc_data, flags);
}
static unsigned int mtk_star_ring_num_used_descs(struct mtk_star_ring *ring)
static unsigned int mtk_star_tx_ring_avail(struct mtk_star_ring *ring)
{
return abs(ring->head - ring->tail);
}
u32 avail;
static bool mtk_star_ring_full(struct mtk_star_ring *ring)
{
return mtk_star_ring_num_used_descs(ring) == MTK_STAR_RING_NUM_DESCS;
}
if (ring->tail > ring->head)
avail = ring->tail - ring->head - 1;
else
avail = MTK_STAR_RING_NUM_DESCS - ring->head + ring->tail - 1;
static bool mtk_star_ring_descs_available(struct mtk_star_ring *ring)
{
return mtk_star_ring_num_used_descs(ring) > 0;
return avail;
}
static dma_addr_t mtk_star_dma_map_rx(struct mtk_star_priv *priv,
......@@ -414,6 +436,36 @@ static void mtk_star_nic_disable_pd(struct mtk_star_priv *priv)
MTK_STAR_BIT_MAC_CFG_NIC_PD);
}
static void mtk_star_enable_dma_irq(struct mtk_star_priv *priv,
bool rx, bool tx)
{
u32 value;
regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
if (tx)
value &= ~MTK_STAR_BIT_INT_STS_TNTC;
if (rx)
value &= ~MTK_STAR_BIT_INT_STS_FNRC;
regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
}
static void mtk_star_disable_dma_irq(struct mtk_star_priv *priv,
bool rx, bool tx)
{
u32 value;
regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
if (tx)
value |= MTK_STAR_BIT_INT_STS_TNTC;
if (rx)
value |= MTK_STAR_BIT_INT_STS_FNRC;
regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
}
/* Unmask the three interrupts we care about, mask all others. */
static void mtk_star_intr_enable(struct mtk_star_priv *priv)
{
......@@ -429,20 +481,11 @@ static void mtk_star_intr_disable(struct mtk_star_priv *priv)
regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~0);
}
static unsigned int mtk_star_intr_read(struct mtk_star_priv *priv)
{
unsigned int val;
regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
return val;
}
static unsigned int mtk_star_intr_ack_all(struct mtk_star_priv *priv)
{
unsigned int val;
val = mtk_star_intr_read(priv);
regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
regmap_write(priv->regs, MTK_STAR_REG_INT_STS, val);
return val;
......@@ -714,25 +757,44 @@ static void mtk_star_free_tx_skbs(struct mtk_star_priv *priv)
mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_tx);
}
/* All processing for TX and RX happens in the napi poll callback.
*
* FIXME: The interrupt handling should be more fine-grained with each
* interrupt enabled/disabled independently when needed. Unfortunatly this
* turned out to impact the driver's stability and until we have something
* working properly, we're disabling all interrupts during TX & RX processing
* or when resetting the counter registers.
*/
/**
* mtk_star_handle_irq - Interrupt Handler.
* @irq: interrupt number.
* @data: pointer to a network interface device structure.
* Description : this is the driver interrupt service routine.
* it mainly handles:
* 1. tx complete interrupt for frame transmission.
* 2. rx complete interrupt for frame reception.
* 3. MAC Management Counter interrupt to avoid counter overflow.
**/
static irqreturn_t mtk_star_handle_irq(int irq, void *data)
{
struct mtk_star_priv *priv;
struct net_device *ndev;
struct net_device *ndev = data;
struct mtk_star_priv *priv = netdev_priv(ndev);
unsigned int intr_status = mtk_star_intr_ack_all(priv);
bool rx, tx;
ndev = data;
priv = netdev_priv(ndev);
rx = (intr_status & MTK_STAR_BIT_INT_STS_FNRC) &&
napi_schedule_prep(&priv->rx_napi);
tx = (intr_status & MTK_STAR_BIT_INT_STS_TNTC) &&
napi_schedule_prep(&priv->tx_napi);
if (netif_running(ndev)) {
mtk_star_intr_disable(priv);
napi_schedule(&priv->napi);
if (rx || tx) {
spin_lock(&priv->lock);
/* mask Rx and TX Complete interrupt */
mtk_star_disable_dma_irq(priv, rx, tx);
spin_unlock(&priv->lock);
if (rx)
__napi_schedule(&priv->rx_napi);
if (tx)
__napi_schedule(&priv->tx_napi);
}
/* interrupt is triggered once any counters reach 0x8000000 */
if (intr_status & MTK_STAR_REG_INT_STS_MIB_CNT_TH) {
mtk_star_update_stats(priv);
mtk_star_reset_counters(priv);
}
return IRQ_HANDLED;
......@@ -821,32 +883,26 @@ static void mtk_star_phy_config(struct mtk_star_priv *priv)
val <<= MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD;
val |= MTK_STAR_BIT_PHY_CTRL1_AN_EN;
if (priv->pause) {
val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
/* Only full-duplex supported for now. */
val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
} else {
val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
}
regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val);
if (priv->pause) {
val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K;
val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH;
val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR;
} else {
val = 0;
}
regmap_update_bits(priv->regs, MTK_STAR_REG_FC_CFG,
MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH |
MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR, val);
if (priv->pause) {
val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS;
} else {
val = 0;
}
regmap_update_bits(priv->regs, MTK_STAR_REG_EXT_CFG,
MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS, val);
}
......@@ -898,14 +954,7 @@ static void mtk_star_init_config(struct mtk_star_priv *priv)
regmap_write(priv->regs, MTK_STAR_REG_SYS_CONF, val);
regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CLK_CONF,
MTK_STAR_MSK_MAC_CLK_CONF,
MTK_STAR_BIT_CLK_DIV_10);
}
static void mtk_star_set_mode_rmii(struct mtk_star_priv *priv)
{
regmap_update_bits(priv->pericfg, MTK_PERICFG_REG_NIC_CFG_CON,
MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII,
MTK_PERICFG_BIT_NIC_CFG_CON_RMII);
priv->compat_data->bit_clk_div);
}
static int mtk_star_enable(struct net_device *ndev)
......@@ -951,11 +1000,12 @@ static int mtk_star_enable(struct net_device *ndev)
/* Request the interrupt */
ret = request_irq(ndev->irq, mtk_star_handle_irq,
IRQF_TRIGGER_FALLING, ndev->name, ndev);
IRQF_TRIGGER_NONE, ndev->name, ndev);
if (ret)
goto err_free_skbs;
napi_enable(&priv->napi);
napi_enable(&priv->tx_napi);
napi_enable(&priv->rx_napi);
mtk_star_intr_ack_all(priv);
mtk_star_intr_enable(priv);
......@@ -988,7 +1038,8 @@ static void mtk_star_disable(struct net_device *ndev)
struct mtk_star_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev);
napi_disable(&priv->napi);
napi_disable(&priv->tx_napi);
napi_disable(&priv->rx_napi);
mtk_star_intr_disable(priv);
mtk_star_dma_disable(priv);
mtk_star_intr_ack_all(priv);
......@@ -1020,13 +1071,45 @@ static int mtk_star_netdev_ioctl(struct net_device *ndev,
return phy_mii_ioctl(ndev->phydev, req, cmd);
}
static int mtk_star_netdev_start_xmit(struct sk_buff *skb,
static int __mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
{
netif_stop_queue(priv->ndev);
/* Might race with mtk_star_tx_poll, check again */
smp_mb();
if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) < size))
return -EBUSY;
netif_start_queue(priv->ndev);
return 0;
}
static inline int mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
{
if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) >= size))
return 0;
return __mtk_star_maybe_stop_tx(priv, size);
}
static netdev_tx_t mtk_star_netdev_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
struct mtk_star_priv *priv = netdev_priv(ndev);
struct mtk_star_ring *ring = &priv->tx_ring;
struct device *dev = mtk_star_get_dev(priv);
struct mtk_star_ring_desc_data desc_data;
int nfrags = skb_shinfo(skb)->nr_frags;
if (unlikely(mtk_star_tx_ring_avail(ring) < nfrags + 1)) {
if (!netif_queue_stopped(ndev)) {
netif_stop_queue(ndev);
/* This is a hard error, log it. */
pr_err_ratelimited("Tx ring full when queue awake\n");
}
return NETDEV_TX_BUSY;
}
desc_data.dma_addr = mtk_star_dma_map_tx(priv, skb);
if (dma_mapping_error(dev, desc_data.dma_addr))
......@@ -1034,17 +1117,11 @@ static int mtk_star_netdev_start_xmit(struct sk_buff *skb,
desc_data.skb = skb;
desc_data.len = skb->len;
spin_lock_bh(&priv->lock);
mtk_star_ring_push_head_tx(ring, &desc_data);
netdev_sent_queue(ndev, skb->len);
if (mtk_star_ring_full(ring))
netif_stop_queue(ndev);
spin_unlock_bh(&priv->lock);
mtk_star_maybe_stop_tx(priv, MTK_STAR_DESC_NEEDED);
mtk_star_dma_resume_tx(priv);
......@@ -1076,31 +1153,40 @@ static int mtk_star_tx_complete_one(struct mtk_star_priv *priv)
return ret;
}
static void mtk_star_tx_complete_all(struct mtk_star_priv *priv)
static int mtk_star_tx_poll(struct napi_struct *napi, int budget)
{
struct mtk_star_priv *priv = container_of(napi, struct mtk_star_priv,
tx_napi);
int ret = 0, pkts_compl = 0, bytes_compl = 0, count = 0;
struct mtk_star_ring *ring = &priv->tx_ring;
struct net_device *ndev = priv->ndev;
int ret, pkts_compl, bytes_compl;
bool wake = false;
spin_lock(&priv->lock);
for (pkts_compl = 0, bytes_compl = 0;;
pkts_compl++, bytes_compl += ret, wake = true) {
if (!mtk_star_ring_descs_available(ring))
break;
unsigned int head = ring->head;
unsigned int entry = ring->tail;
while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) {
ret = mtk_star_tx_complete_one(priv);
if (ret < 0)
break;
count++;
pkts_compl++;
bytes_compl += ret;
entry = ring->tail;
}
netdev_completed_queue(ndev, pkts_compl, bytes_compl);
if (wake && netif_queue_stopped(ndev))
if (unlikely(netif_queue_stopped(ndev)) &&
(mtk_star_tx_ring_avail(ring) > MTK_STAR_TX_THRESH))
netif_wake_queue(ndev);
if (napi_complete(napi)) {
spin_lock(&priv->lock);
mtk_star_enable_dma_irq(priv, false, true);
spin_unlock(&priv->lock);
}
return 0;
}
static void mtk_star_netdev_get_stats64(struct net_device *ndev,
......@@ -1180,7 +1266,7 @@ static const struct ethtool_ops mtk_star_ethtool_ops = {
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
static int mtk_star_receive_packet(struct mtk_star_priv *priv)
static int mtk_star_rx(struct mtk_star_priv *priv, int budget)
{
struct mtk_star_ring *ring = &priv->rx_ring;
struct device *dev = mtk_star_get_dev(priv);
......@@ -1188,11 +1274,10 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
struct net_device *ndev = priv->ndev;
struct sk_buff *curr_skb, *new_skb;
dma_addr_t new_dma_addr;
int ret;
int ret, count = 0;
spin_lock(&priv->lock);
while (count < budget) {
ret = mtk_star_ring_pop_tail(ring, &desc_data);
spin_unlock(&priv->lock);
if (ret)
return -1;
......@@ -1205,8 +1290,8 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
goto push_new_skb;
}
/* Prepare new skb before receiving the current one. Reuse the current
* skb if we fail at any point.
/* Prepare new skb before receiving the current one.
* Reuse the current skb if we fail at any point.
*/
new_skb = mtk_star_alloc_skb(ndev);
if (!new_skb) {
......@@ -1224,7 +1309,9 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
goto push_new_skb;
}
/* We can't fail anymore at this point: it's safe to unmap the skb. */
/* We can't fail anymore at this point:
* it's safe to unmap the skb.
*/
mtk_star_dma_unmap_rx(priv, &desc_data);
skb_put(desc_data.skb, desc_data.len);
......@@ -1237,58 +1324,35 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
desc_data.dma_addr = new_dma_addr;
push_new_skb:
count++;
desc_data.len = skb_tailroom(new_skb);
desc_data.skb = new_skb;
spin_lock(&priv->lock);
mtk_star_ring_push_head_rx(ring, &desc_data);
spin_unlock(&priv->lock);
return 0;
}
static int mtk_star_process_rx(struct mtk_star_priv *priv, int budget)
{
int received, ret;
for (received = 0, ret = 0; received < budget && ret == 0; received++)
ret = mtk_star_receive_packet(priv);
}
mtk_star_dma_resume_rx(priv);
return received;
return count;
}
static int mtk_star_poll(struct napi_struct *napi, int budget)
static int mtk_star_rx_poll(struct napi_struct *napi, int budget)
{
struct mtk_star_priv *priv;
unsigned int status;
int received = 0;
priv = container_of(napi, struct mtk_star_priv, napi);
status = mtk_star_intr_read(priv);
mtk_star_intr_ack_all(priv);
if (status & MTK_STAR_BIT_INT_STS_TNTC)
/* Clean-up all TX descriptors. */
mtk_star_tx_complete_all(priv);
int work_done = 0;
if (status & MTK_STAR_BIT_INT_STS_FNRC)
/* Receive up to $budget packets. */
received = mtk_star_process_rx(priv, budget);
priv = container_of(napi, struct mtk_star_priv, rx_napi);
if (unlikely(status & MTK_STAR_REG_INT_STS_MIB_CNT_TH)) {
mtk_star_update_stats(priv);
mtk_star_reset_counters(priv);
work_done = mtk_star_rx(priv, budget);
if (work_done < budget) {
napi_complete_done(napi, work_done);
spin_lock(&priv->lock);
mtk_star_enable_dma_irq(priv, true, false);
spin_unlock(&priv->lock);
}
if (received < budget)
napi_complete_done(napi, received);
mtk_star_intr_enable(priv);
return received;
return work_done;
}
static void mtk_star_mdio_rwok_clear(struct mtk_star_priv *priv)
......@@ -1442,6 +1506,25 @@ static void mtk_star_clk_disable_unprepare(void *data)
clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
}
static int mtk_star_set_timing(struct mtk_star_priv *priv)
{
struct device *dev = mtk_star_get_dev(priv);
unsigned int delay_val = 0;
switch (priv->phy_intf) {
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_RMII:
delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_RX_CLK, priv->rx_inv);
delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_TX_CLK, priv->tx_inv);
break;
default:
dev_err(dev, "This interface not supported\n");
return -EINVAL;
}
return regmap_write(priv->regs, MTK_STAR_REG_TEST0, delay_val);
}
static int mtk_star_probe(struct platform_device *pdev)
{
struct device_node *of_node;
......@@ -1460,6 +1543,7 @@ static int mtk_star_probe(struct platform_device *pdev)
priv = netdev_priv(ndev);
priv->ndev = ndev;
priv->compat_data = of_device_get_match_data(&pdev->dev);
SET_NETDEV_DEV(ndev, dev);
platform_set_drvdata(pdev, ndev);
......@@ -1510,7 +1594,8 @@ static int mtk_star_probe(struct platform_device *pdev)
ret = of_get_phy_mode(of_node, &priv->phy_intf);
if (ret) {
return ret;
} else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII) {
} else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII &&
priv->phy_intf != PHY_INTERFACE_MODE_MII) {
dev_err(dev, "unsupported phy mode: %s\n",
phy_modes(priv->phy_intf));
return -EINVAL;
......@@ -1522,7 +1607,23 @@ static int mtk_star_probe(struct platform_device *pdev)
return -ENODEV;
}
mtk_star_set_mode_rmii(priv);
priv->rmii_rxc = of_property_read_bool(of_node, "mediatek,rmii-rxc");
priv->rx_inv = of_property_read_bool(of_node, "mediatek,rxc-inverse");
priv->tx_inv = of_property_read_bool(of_node, "mediatek,txc-inverse");
if (priv->compat_data->set_interface_mode) {
ret = priv->compat_data->set_interface_mode(ndev);
if (ret) {
dev_err(dev, "Failed to set phy interface, err = %d\n", ret);
return -EINVAL;
}
}
ret = mtk_star_set_timing(priv);
if (ret) {
dev_err(dev, "Failed to set timing, err = %d\n", ret);
return -EINVAL;
}
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret) {
......@@ -1550,16 +1651,93 @@ static int mtk_star_probe(struct platform_device *pdev)
ndev->netdev_ops = &mtk_star_netdev_ops;
ndev->ethtool_ops = &mtk_star_ethtool_ops;
netif_napi_add(ndev, &priv->napi, mtk_star_poll, NAPI_POLL_WEIGHT);
netif_napi_add(ndev, &priv->rx_napi, mtk_star_rx_poll,
NAPI_POLL_WEIGHT);
netif_tx_napi_add(ndev, &priv->tx_napi, mtk_star_tx_poll,
NAPI_POLL_WEIGHT);
return devm_register_netdev(dev, ndev);
}
#ifdef CONFIG_OF
static int mt8516_set_interface_mode(struct net_device *ndev)
{
struct mtk_star_priv *priv = netdev_priv(ndev);
struct device *dev = mtk_star_get_dev(priv);
unsigned int intf_val, ret, rmii_rxc;
switch (priv->phy_intf) {
case PHY_INTERFACE_MODE_MII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
rmii_rxc = 0;
break;
case PHY_INTERFACE_MODE_RMII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
rmii_rxc = priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK;
break;
default:
dev_err(dev, "This interface not supported\n");
return -EINVAL;
}
ret = regmap_update_bits(priv->pericfg,
MTK_PERICFG_REG_NIC_CFG1_CON,
MTK_PERICFG_BIT_NIC_CFG_CON_CLK,
rmii_rxc);
if (ret)
return ret;
return regmap_update_bits(priv->pericfg,
MTK_PERICFG_REG_NIC_CFG0_CON,
MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF,
intf_val);
}
static int mt8365_set_interface_mode(struct net_device *ndev)
{
struct mtk_star_priv *priv = netdev_priv(ndev);
struct device *dev = mtk_star_get_dev(priv);
unsigned int intf_val;
switch (priv->phy_intf) {
case PHY_INTERFACE_MODE_MII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
break;
case PHY_INTERFACE_MODE_RMII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
intf_val |= priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2;
break;
default:
dev_err(dev, "This interface not supported\n");
return -EINVAL;
}
return regmap_update_bits(priv->pericfg,
MTK_PERICFG_REG_NIC_CFG_CON_V2,
MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF |
MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2,
intf_val);
}
static const struct mtk_star_compat mtk_star_mt8516_compat = {
.set_interface_mode = mt8516_set_interface_mode,
.bit_clk_div = MTK_STAR_BIT_CLK_DIV_10,
};
static const struct mtk_star_compat mtk_star_mt8365_compat = {
.set_interface_mode = mt8365_set_interface_mode,
.bit_clk_div = MTK_STAR_BIT_CLK_DIV_50,
};
static const struct of_device_id mtk_star_of_match[] = {
{ .compatible = "mediatek,mt8516-eth", },
{ .compatible = "mediatek,mt8518-eth", },
{ .compatible = "mediatek,mt8175-eth", },
{ .compatible = "mediatek,mt8516-eth",
.data = &mtk_star_mt8516_compat },
{ .compatible = "mediatek,mt8518-eth",
.data = &mtk_star_mt8516_compat },
{ .compatible = "mediatek,mt8175-eth",
.data = &mtk_star_mt8516_compat },
{ .compatible = "mediatek,mt8365-eth",
.data = &mtk_star_mt8365_compat },
{ }
};
MODULE_DEVICE_TABLE(of, mtk_star_of_match);
......
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