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

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
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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
+354 −176
Original line number Diff line number Diff line
@@ -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,33 +1153,42 @@ 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,
					struct rtnl_link_stats64 *stats)
{
@@ -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);
	int work_done = 0;

	if (status & MTK_STAR_BIT_INT_STS_TNTC)
		/* Clean-up all TX descriptors. */
		mtk_star_tx_complete_all(priv);
	priv = container_of(napi, struct mtk_star_priv, rx_napi);

	if (status & MTK_STAR_BIT_INT_STS_FNRC)
		/* Receive up to $budget packets. */
		received = mtk_star_process_rx(priv, budget);

	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);