18c7bd5a4SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0-only
28c7bd5a4SBartosz Golaszewski /*
38c7bd5a4SBartosz Golaszewski  * Copyright (c) 2020 MediaTek Corporation
48c7bd5a4SBartosz Golaszewski  * Copyright (c) 2020 BayLibre SAS
58c7bd5a4SBartosz Golaszewski  *
68c7bd5a4SBartosz Golaszewski  * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
78c7bd5a4SBartosz Golaszewski  */
88c7bd5a4SBartosz Golaszewski 
98c7bd5a4SBartosz Golaszewski #include <linux/bits.h>
108c7bd5a4SBartosz Golaszewski #include <linux/clk.h>
118c7bd5a4SBartosz Golaszewski #include <linux/compiler.h>
128c7bd5a4SBartosz Golaszewski #include <linux/dma-mapping.h>
138c7bd5a4SBartosz Golaszewski #include <linux/etherdevice.h>
148c7bd5a4SBartosz Golaszewski #include <linux/kernel.h>
158c7bd5a4SBartosz Golaszewski #include <linux/mfd/syscon.h>
168c7bd5a4SBartosz Golaszewski #include <linux/mii.h>
178c7bd5a4SBartosz Golaszewski #include <linux/module.h>
188c7bd5a4SBartosz Golaszewski #include <linux/netdevice.h>
198c7bd5a4SBartosz Golaszewski #include <linux/of.h>
208c7bd5a4SBartosz Golaszewski #include <linux/of_mdio.h>
218c7bd5a4SBartosz Golaszewski #include <linux/of_net.h>
228c7bd5a4SBartosz Golaszewski #include <linux/platform_device.h>
238c7bd5a4SBartosz Golaszewski #include <linux/pm.h>
248c7bd5a4SBartosz Golaszewski #include <linux/regmap.h>
258c7bd5a4SBartosz Golaszewski #include <linux/skbuff.h>
268c7bd5a4SBartosz Golaszewski #include <linux/spinlock.h>
278c7bd5a4SBartosz Golaszewski 
288c7bd5a4SBartosz Golaszewski #define MTK_STAR_DRVNAME			"mtk_star_emac"
298c7bd5a4SBartosz Golaszewski 
308c7bd5a4SBartosz Golaszewski #define MTK_STAR_WAIT_TIMEOUT			300
318c7bd5a4SBartosz Golaszewski #define MTK_STAR_MAX_FRAME_SIZE			1514
328c7bd5a4SBartosz Golaszewski #define MTK_STAR_SKB_ALIGNMENT			16
338c7bd5a4SBartosz Golaszewski #define MTK_STAR_HASHTABLE_MC_LIMIT		256
348c7bd5a4SBartosz Golaszewski #define MTK_STAR_HASHTABLE_SIZE_MAX		512
350a8bd81fSBiao Huang #define MTK_STAR_DESC_NEEDED			(MAX_SKB_FRAGS + 4)
368c7bd5a4SBartosz Golaszewski 
378c7bd5a4SBartosz Golaszewski /* Normally we'd use NET_IP_ALIGN but on arm64 its value is 0 and it doesn't
388c7bd5a4SBartosz Golaszewski  * work for this controller.
398c7bd5a4SBartosz Golaszewski  */
408c7bd5a4SBartosz Golaszewski #define MTK_STAR_IP_ALIGN			2
418c7bd5a4SBartosz Golaszewski 
428c7bd5a4SBartosz Golaszewski static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
438c7bd5a4SBartosz Golaszewski #define MTK_STAR_NCLKS ARRAY_SIZE(mtk_star_clk_names)
448c7bd5a4SBartosz Golaszewski 
458c7bd5a4SBartosz Golaszewski /* PHY Control Register 0 */
468c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_PHY_CTRL0			0x0000
478c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL0_WTCMD		BIT(13)
488c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL0_RDCMD		BIT(14)
498c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL0_RWOK		BIT(15)
508c7bd5a4SBartosz Golaszewski #define MTK_STAR_MSK_PHY_CTRL0_PREG		GENMASK(12, 8)
518c7bd5a4SBartosz Golaszewski #define MTK_STAR_OFF_PHY_CTRL0_PREG		8
528c7bd5a4SBartosz Golaszewski #define MTK_STAR_MSK_PHY_CTRL0_RWDATA		GENMASK(31, 16)
538c7bd5a4SBartosz Golaszewski #define MTK_STAR_OFF_PHY_CTRL0_RWDATA		16
548c7bd5a4SBartosz Golaszewski 
558c7bd5a4SBartosz Golaszewski /* PHY Control Register 1 */
568c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_PHY_CTRL1			0x0004
578c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL1_LINK_ST		BIT(0)
588c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL1_AN_EN		BIT(8)
598c7bd5a4SBartosz Golaszewski #define MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD	9
608c7bd5a4SBartosz Golaszewski #define MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_10M	0x00
618c7bd5a4SBartosz Golaszewski #define MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_100M	0x01
628c7bd5a4SBartosz Golaszewski #define MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_1000M	0x02
638c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX	BIT(11)
648c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX	BIT(12)
658c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX	BIT(13)
668c7bd5a4SBartosz Golaszewski 
678c7bd5a4SBartosz Golaszewski /* MAC Configuration Register */
688c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_MAC_CFG			0x0008
698c7bd5a4SBartosz Golaszewski #define MTK_STAR_OFF_MAC_CFG_IPG		10
708c7bd5a4SBartosz Golaszewski #define MTK_STAR_VAL_MAC_CFG_IPG_96BIT		GENMASK(4, 0)
718c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_MAC_CFG_MAXLEN_1522	BIT(16)
728c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_MAC_CFG_AUTO_PAD		BIT(19)
738c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_MAC_CFG_CRC_STRIP		BIT(20)
748c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_MAC_CFG_VLAN_STRIP		BIT(22)
758c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_MAC_CFG_NIC_PD		BIT(31)
768c7bd5a4SBartosz Golaszewski 
778c7bd5a4SBartosz Golaszewski /* Flow-Control Configuration Register */
788c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_FC_CFG			0x000c
798c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_FC_CFG_BP_EN		BIT(7)
808c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR	BIT(8)
818c7bd5a4SBartosz Golaszewski #define MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH	16
828c7bd5a4SBartosz Golaszewski #define MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH	GENMASK(27, 16)
838c7bd5a4SBartosz Golaszewski #define MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K	0x800
848c7bd5a4SBartosz Golaszewski 
858c7bd5a4SBartosz Golaszewski /* ARL Configuration Register */
868c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_ARL_CFG			0x0010
878c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_ARL_CFG_HASH_ALG		BIT(0)
888c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_ARL_CFG_MISC_MODE		BIT(4)
898c7bd5a4SBartosz Golaszewski 
908c7bd5a4SBartosz Golaszewski /* MAC High and Low Bytes Registers */
918c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_MY_MAC_H			0x0014
928c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_MY_MAC_L			0x0018
938c7bd5a4SBartosz Golaszewski 
948c7bd5a4SBartosz Golaszewski /* Hash Table Control Register */
958c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_HASH_CTRL			0x001c
968c7bd5a4SBartosz Golaszewski #define MTK_STAR_MSK_HASH_CTRL_HASH_BIT_ADDR	GENMASK(8, 0)
978c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_HASH_CTRL_HASH_BIT_DATA	BIT(12)
988c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_HASH_CTRL_ACC_CMD		BIT(13)
998c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_HASH_CTRL_CMD_START	BIT(14)
1008c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_HASH_CTRL_BIST_OK		BIT(16)
1018c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_HASH_CTRL_BIST_DONE	BIT(17)
1028c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_HASH_CTRL_BIST_EN		BIT(31)
1038c7bd5a4SBartosz Golaszewski 
1048c7bd5a4SBartosz Golaszewski /* TX DMA Control Register */
1058c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_TX_DMA_CTRL		0x0034
1068c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_TX_DMA_CTRL_START		BIT(0)
1078c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_TX_DMA_CTRL_STOP		BIT(1)
1088c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_TX_DMA_CTRL_RESUME		BIT(2)
1098c7bd5a4SBartosz Golaszewski 
1108c7bd5a4SBartosz Golaszewski /* RX DMA Control Register */
1118c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_RX_DMA_CTRL		0x0038
1128c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_RX_DMA_CTRL_START		BIT(0)
1138c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_RX_DMA_CTRL_STOP		BIT(1)
1148c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_RX_DMA_CTRL_RESUME		BIT(2)
1158c7bd5a4SBartosz Golaszewski 
1168c7bd5a4SBartosz Golaszewski /* DMA Address Registers */
1178c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_TX_DPTR			0x003c
1188c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_RX_DPTR			0x0040
1198c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_TX_BASE_ADDR		0x0044
1208c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_RX_BASE_ADDR		0x0048
1218c7bd5a4SBartosz Golaszewski 
1228c7bd5a4SBartosz Golaszewski /* Interrupt Status Register */
1238c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_INT_STS			0x0050
1248c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_INT_STS_PORT_STS_CHG	BIT(2)
1258c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_INT_STS_MIB_CNT_TH		BIT(3)
1268c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_INT_STS_FNRC		BIT(6)
1278c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_INT_STS_TNTC		BIT(8)
1288c7bd5a4SBartosz Golaszewski 
1298c7bd5a4SBartosz Golaszewski /* Interrupt Mask Register */
1308c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_INT_MASK			0x0054
1318c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_INT_MASK_FNRC		BIT(6)
1328c7bd5a4SBartosz Golaszewski 
133769c197bSBiao Huang /* Delay-Macro Register */
134769c197bSBiao Huang #define MTK_STAR_REG_TEST0			0x0058
135769c197bSBiao Huang #define MTK_STAR_BIT_INV_RX_CLK			BIT(30)
136769c197bSBiao Huang #define MTK_STAR_BIT_INV_TX_CLK			BIT(31)
137769c197bSBiao Huang 
1388c7bd5a4SBartosz Golaszewski /* Misc. Config Register */
1398c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_TEST1			0x005c
1408c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_TEST1_RST_HASH_MBIST	BIT(31)
1418c7bd5a4SBartosz Golaszewski 
1428c7bd5a4SBartosz Golaszewski /* Extended Configuration Register */
1438c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_EXT_CFG			0x0060
1448c7bd5a4SBartosz Golaszewski #define MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS	16
1458c7bd5a4SBartosz Golaszewski #define MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS	GENMASK(26, 16)
1468c7bd5a4SBartosz Golaszewski #define MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K	0x400
1478c7bd5a4SBartosz Golaszewski 
1488c7bd5a4SBartosz Golaszewski /* EthSys Configuration Register */
1498c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_SYS_CONF			0x0094
1508c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_MII_PAD_OUT_ENABLE		BIT(0)
1518c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_EXT_MDC_MODE		BIT(1)
1528c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_SWC_MII_MODE		BIT(2)
1538c7bd5a4SBartosz Golaszewski 
1548c7bd5a4SBartosz Golaszewski /* MAC Clock Configuration Register */
1558c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_MAC_CLK_CONF		0x00ac
1568c7bd5a4SBartosz Golaszewski #define MTK_STAR_MSK_MAC_CLK_CONF		GENMASK(7, 0)
1578c7bd5a4SBartosz Golaszewski #define MTK_STAR_BIT_CLK_DIV_10			0x0a
1586cde23b3SBiao Huang #define MTK_STAR_BIT_CLK_DIV_50			0x32
1598c7bd5a4SBartosz Golaszewski 
1608c7bd5a4SBartosz Golaszewski /* Counter registers. */
1618c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXOKPKT			0x0100
1628c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXOKBYTE			0x0104
1638c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXRUNT			0x0108
1648c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXLONG			0x010c
1658c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXDROP			0x0110
1668c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXCRC			0x0114
1678c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXARLDROP		0x0118
1688c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXVLANDROP		0x011c
1698c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXCSERR			0x0120
1708c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RXPAUSE			0x0124
1718c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TXOKPKT			0x0128
1728c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TXOKBYTE			0x012c
1738c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TXPAUSECOL		0x0130
1748c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TXRTY			0x0134
1758c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TXSKIP			0x0138
1768c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TX_ARP			0x013c
1778c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_RERR			0x01d8
1788c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_UNI			0x01dc
1798c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_MULTI			0x01e0
1808c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_BROAD			0x01e4
1818c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_ALIGNERR		0x01e8
1828c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TX_UNI			0x01ec
1838c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TX_MULTI			0x01f0
1848c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TX_BROAD			0x01f4
1858c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TX_TIMEOUT		0x01f8
1868c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_TX_LATECOL		0x01fc
1878c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_LENGTHERR		0x0214
1888c7bd5a4SBartosz Golaszewski #define MTK_STAR_REG_C_RX_TWIST			0x0218
1898c7bd5a4SBartosz Golaszewski 
1908c7bd5a4SBartosz Golaszewski /* Ethernet CFG Control */
1916cde23b3SBiao Huang #define MTK_PERICFG_REG_NIC_CFG0_CON		0x03c4
1926cde23b3SBiao Huang #define MTK_PERICFG_REG_NIC_CFG1_CON		0x03c8
1936cde23b3SBiao Huang #define MTK_PERICFG_REG_NIC_CFG_CON_V2		0x0c10
1946cde23b3SBiao Huang #define MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF	GENMASK(3, 0)
1950027340aSBiao Huang #define MTK_PERICFG_BIT_NIC_CFG_CON_MII		0
1966cde23b3SBiao Huang #define MTK_PERICFG_BIT_NIC_CFG_CON_RMII	1
19785ef6033SBiao Huang #define MTK_PERICFG_BIT_NIC_CFG_CON_CLK		BIT(0)
19885ef6033SBiao Huang #define MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2	BIT(8)
1998c7bd5a4SBartosz Golaszewski 
2008c7bd5a4SBartosz Golaszewski /* Represents the actual structure of descriptors used by the MAC. We can
2018c7bd5a4SBartosz Golaszewski  * reuse the same structure for both TX and RX - the layout is the same, only
2028c7bd5a4SBartosz Golaszewski  * the flags differ slightly.
2038c7bd5a4SBartosz Golaszewski  */
2048c7bd5a4SBartosz Golaszewski struct mtk_star_ring_desc {
2058c7bd5a4SBartosz Golaszewski 	/* Contains both the status flags as well as packet length. */
2068c7bd5a4SBartosz Golaszewski 	u32 status;
2078c7bd5a4SBartosz Golaszewski 	u32 data_ptr;
2088c7bd5a4SBartosz Golaszewski 	u32 vtag;
2098c7bd5a4SBartosz Golaszewski 	u32 reserved;
2108c7bd5a4SBartosz Golaszewski };
2118c7bd5a4SBartosz Golaszewski 
2128c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_MSK_LEN			GENMASK(15, 0)
2138c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_RX_CRCE		BIT(24)
2148c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_RX_OSIZE		BIT(25)
2158c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_INT			BIT(27)
2168c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_LS			BIT(28)
2178c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_FS			BIT(29)
2188c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_EOR			BIT(30)
2198c7bd5a4SBartosz Golaszewski #define MTK_STAR_DESC_BIT_COWN			BIT(31)
2208c7bd5a4SBartosz Golaszewski 
2218c7bd5a4SBartosz Golaszewski /* Helper structure for storing data read from/written to descriptors in order
2228c7bd5a4SBartosz Golaszewski  * to limit reads from/writes to DMA memory.
2238c7bd5a4SBartosz Golaszewski  */
2248c7bd5a4SBartosz Golaszewski struct mtk_star_ring_desc_data {
2258c7bd5a4SBartosz Golaszewski 	unsigned int len;
2268c7bd5a4SBartosz Golaszewski 	unsigned int flags;
2278c7bd5a4SBartosz Golaszewski 	dma_addr_t dma_addr;
2288c7bd5a4SBartosz Golaszewski 	struct sk_buff *skb;
2298c7bd5a4SBartosz Golaszewski };
2308c7bd5a4SBartosz Golaszewski 
2310a8bd81fSBiao Huang #define MTK_STAR_RING_NUM_DESCS			512
2320a8bd81fSBiao Huang #define MTK_STAR_TX_THRESH			(MTK_STAR_RING_NUM_DESCS / 4)
2338c7bd5a4SBartosz Golaszewski #define MTK_STAR_NUM_TX_DESCS			MTK_STAR_RING_NUM_DESCS
2348c7bd5a4SBartosz Golaszewski #define MTK_STAR_NUM_RX_DESCS			MTK_STAR_RING_NUM_DESCS
2358c7bd5a4SBartosz Golaszewski #define MTK_STAR_NUM_DESCS_TOTAL		(MTK_STAR_RING_NUM_DESCS * 2)
2368c7bd5a4SBartosz Golaszewski #define MTK_STAR_DMA_SIZE \
2378c7bd5a4SBartosz Golaszewski 		(MTK_STAR_NUM_DESCS_TOTAL * sizeof(struct mtk_star_ring_desc))
2388c7bd5a4SBartosz Golaszewski 
2398c7bd5a4SBartosz Golaszewski struct mtk_star_ring {
2408c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc *descs;
2418c7bd5a4SBartosz Golaszewski 	struct sk_buff *skbs[MTK_STAR_RING_NUM_DESCS];
2428c7bd5a4SBartosz Golaszewski 	dma_addr_t dma_addrs[MTK_STAR_RING_NUM_DESCS];
2438c7bd5a4SBartosz Golaszewski 	unsigned int head;
2448c7bd5a4SBartosz Golaszewski 	unsigned int tail;
2458c7bd5a4SBartosz Golaszewski };
2468c7bd5a4SBartosz Golaszewski 
247c16cc6a0SBiao Huang struct mtk_star_compat {
2486cde23b3SBiao Huang 	int (*set_interface_mode)(struct net_device *ndev);
249c16cc6a0SBiao Huang 	unsigned char bit_clk_div;
250c16cc6a0SBiao Huang };
251c16cc6a0SBiao Huang 
2528c7bd5a4SBartosz Golaszewski struct mtk_star_priv {
2538c7bd5a4SBartosz Golaszewski 	struct net_device *ndev;
2548c7bd5a4SBartosz Golaszewski 
2558c7bd5a4SBartosz Golaszewski 	struct regmap *regs;
2568c7bd5a4SBartosz Golaszewski 	struct regmap *pericfg;
2578c7bd5a4SBartosz Golaszewski 
2588c7bd5a4SBartosz Golaszewski 	struct clk_bulk_data clks[MTK_STAR_NCLKS];
2598c7bd5a4SBartosz Golaszewski 
2608c7bd5a4SBartosz Golaszewski 	void *ring_base;
2618c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc *descs_base;
2628c7bd5a4SBartosz Golaszewski 	dma_addr_t dma_addr;
2638c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring tx_ring;
2648c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring rx_ring;
2658c7bd5a4SBartosz Golaszewski 
2668c7bd5a4SBartosz Golaszewski 	struct mii_bus *mii;
2670a8bd81fSBiao Huang 	struct napi_struct tx_napi;
2680a8bd81fSBiao Huang 	struct napi_struct rx_napi;
2698c7bd5a4SBartosz Golaszewski 
2708c7bd5a4SBartosz Golaszewski 	struct device_node *phy_node;
2718c7bd5a4SBartosz Golaszewski 	phy_interface_t phy_intf;
2728c7bd5a4SBartosz Golaszewski 	struct phy_device *phydev;
2738c7bd5a4SBartosz Golaszewski 	unsigned int link;
2748c7bd5a4SBartosz Golaszewski 	int speed;
2758c7bd5a4SBartosz Golaszewski 	int duplex;
2768c7bd5a4SBartosz Golaszewski 	int pause;
27785ef6033SBiao Huang 	bool rmii_rxc;
278769c197bSBiao Huang 	bool rx_inv;
279769c197bSBiao Huang 	bool tx_inv;
2808c7bd5a4SBartosz Golaszewski 
281c16cc6a0SBiao Huang 	const struct mtk_star_compat *compat_data;
282c16cc6a0SBiao Huang 
2838c7bd5a4SBartosz Golaszewski 	/* Protects against concurrent descriptor access. */
2848c7bd5a4SBartosz Golaszewski 	spinlock_t lock;
2858c7bd5a4SBartosz Golaszewski 
2868c7bd5a4SBartosz Golaszewski 	struct rtnl_link_stats64 stats;
2878c7bd5a4SBartosz Golaszewski };
2888c7bd5a4SBartosz Golaszewski 
mtk_star_get_dev(struct mtk_star_priv * priv)2898c7bd5a4SBartosz Golaszewski static struct device *mtk_star_get_dev(struct mtk_star_priv *priv)
2908c7bd5a4SBartosz Golaszewski {
2918c7bd5a4SBartosz Golaszewski 	return priv->ndev->dev.parent;
2928c7bd5a4SBartosz Golaszewski }
2938c7bd5a4SBartosz Golaszewski 
2948c7bd5a4SBartosz Golaszewski static const struct regmap_config mtk_star_regmap_config = {
2958c7bd5a4SBartosz Golaszewski 	.reg_bits		= 32,
2968c7bd5a4SBartosz Golaszewski 	.val_bits		= 32,
2978c7bd5a4SBartosz Golaszewski 	.reg_stride		= 4,
2988c7bd5a4SBartosz Golaszewski 	.disable_locking	= true,
2998c7bd5a4SBartosz Golaszewski };
3008c7bd5a4SBartosz Golaszewski 
mtk_star_ring_init(struct mtk_star_ring * ring,struct mtk_star_ring_desc * descs)3018c7bd5a4SBartosz Golaszewski static void mtk_star_ring_init(struct mtk_star_ring *ring,
3028c7bd5a4SBartosz Golaszewski 			       struct mtk_star_ring_desc *descs)
3038c7bd5a4SBartosz Golaszewski {
3048c7bd5a4SBartosz Golaszewski 	memset(ring, 0, sizeof(*ring));
3058c7bd5a4SBartosz Golaszewski 	ring->descs = descs;
3068c7bd5a4SBartosz Golaszewski 	ring->head = 0;
3078c7bd5a4SBartosz Golaszewski 	ring->tail = 0;
3088c7bd5a4SBartosz Golaszewski }
3098c7bd5a4SBartosz Golaszewski 
mtk_star_ring_pop_tail(struct mtk_star_ring * ring,struct mtk_star_ring_desc_data * desc_data)3108c7bd5a4SBartosz Golaszewski static int mtk_star_ring_pop_tail(struct mtk_star_ring *ring,
3118c7bd5a4SBartosz Golaszewski 				  struct mtk_star_ring_desc_data *desc_data)
3128c7bd5a4SBartosz Golaszewski {
3138c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc *desc = &ring->descs[ring->tail];
3148c7bd5a4SBartosz Golaszewski 	unsigned int status;
3158c7bd5a4SBartosz Golaszewski 
3168c7bd5a4SBartosz Golaszewski 	status = READ_ONCE(desc->status);
3178c7bd5a4SBartosz Golaszewski 	dma_rmb(); /* Make sure we read the status bits before checking it. */
3188c7bd5a4SBartosz Golaszewski 
3198c7bd5a4SBartosz Golaszewski 	if (!(status & MTK_STAR_DESC_BIT_COWN))
3208c7bd5a4SBartosz Golaszewski 		return -1;
3218c7bd5a4SBartosz Golaszewski 
3228c7bd5a4SBartosz Golaszewski 	desc_data->len = status & MTK_STAR_DESC_MSK_LEN;
3238c7bd5a4SBartosz Golaszewski 	desc_data->flags = status & ~MTK_STAR_DESC_MSK_LEN;
3248c7bd5a4SBartosz Golaszewski 	desc_data->dma_addr = ring->dma_addrs[ring->tail];
3258c7bd5a4SBartosz Golaszewski 	desc_data->skb = ring->skbs[ring->tail];
3268c7bd5a4SBartosz Golaszewski 
3278c7bd5a4SBartosz Golaszewski 	ring->dma_addrs[ring->tail] = 0;
3288c7bd5a4SBartosz Golaszewski 	ring->skbs[ring->tail] = NULL;
3298c7bd5a4SBartosz Golaszewski 
3308c7bd5a4SBartosz Golaszewski 	status &= MTK_STAR_DESC_BIT_COWN | MTK_STAR_DESC_BIT_EOR;
3318c7bd5a4SBartosz Golaszewski 
3328c7bd5a4SBartosz Golaszewski 	WRITE_ONCE(desc->data_ptr, 0);
3338c7bd5a4SBartosz Golaszewski 	WRITE_ONCE(desc->status, status);
3348c7bd5a4SBartosz Golaszewski 
3358c7bd5a4SBartosz Golaszewski 	ring->tail = (ring->tail + 1) % MTK_STAR_RING_NUM_DESCS;
3368c7bd5a4SBartosz Golaszewski 
3378c7bd5a4SBartosz Golaszewski 	return 0;
3388c7bd5a4SBartosz Golaszewski }
3398c7bd5a4SBartosz Golaszewski 
mtk_star_ring_push_head(struct mtk_star_ring * ring,struct mtk_star_ring_desc_data * desc_data,unsigned int flags)3408c7bd5a4SBartosz Golaszewski static void mtk_star_ring_push_head(struct mtk_star_ring *ring,
3418c7bd5a4SBartosz Golaszewski 				    struct mtk_star_ring_desc_data *desc_data,
3428c7bd5a4SBartosz Golaszewski 				    unsigned int flags)
3438c7bd5a4SBartosz Golaszewski {
3448c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc *desc = &ring->descs[ring->head];
3458c7bd5a4SBartosz Golaszewski 	unsigned int status;
3468c7bd5a4SBartosz Golaszewski 
3478c7bd5a4SBartosz Golaszewski 	status = READ_ONCE(desc->status);
3488c7bd5a4SBartosz Golaszewski 
3498c7bd5a4SBartosz Golaszewski 	ring->skbs[ring->head] = desc_data->skb;
3508c7bd5a4SBartosz Golaszewski 	ring->dma_addrs[ring->head] = desc_data->dma_addr;
3518c7bd5a4SBartosz Golaszewski 
3528c7bd5a4SBartosz Golaszewski 	status |= desc_data->len;
3538c7bd5a4SBartosz Golaszewski 	if (flags)
3548c7bd5a4SBartosz Golaszewski 		status |= flags;
3558c7bd5a4SBartosz Golaszewski 
3568c7bd5a4SBartosz Golaszewski 	WRITE_ONCE(desc->data_ptr, desc_data->dma_addr);
3578c7bd5a4SBartosz Golaszewski 	WRITE_ONCE(desc->status, status);
3588c7bd5a4SBartosz Golaszewski 	status &= ~MTK_STAR_DESC_BIT_COWN;
3598c7bd5a4SBartosz Golaszewski 	/* Flush previous modifications before ownership change. */
3608c7bd5a4SBartosz Golaszewski 	dma_wmb();
3618c7bd5a4SBartosz Golaszewski 	WRITE_ONCE(desc->status, status);
3628c7bd5a4SBartosz Golaszewski 
3638c7bd5a4SBartosz Golaszewski 	ring->head = (ring->head + 1) % MTK_STAR_RING_NUM_DESCS;
3648c7bd5a4SBartosz Golaszewski }
3658c7bd5a4SBartosz Golaszewski 
3668c7bd5a4SBartosz Golaszewski static void
mtk_star_ring_push_head_rx(struct mtk_star_ring * ring,struct mtk_star_ring_desc_data * desc_data)3678c7bd5a4SBartosz Golaszewski mtk_star_ring_push_head_rx(struct mtk_star_ring *ring,
3688c7bd5a4SBartosz Golaszewski 			   struct mtk_star_ring_desc_data *desc_data)
3698c7bd5a4SBartosz Golaszewski {
3708c7bd5a4SBartosz Golaszewski 	mtk_star_ring_push_head(ring, desc_data, 0);
3718c7bd5a4SBartosz Golaszewski }
3728c7bd5a4SBartosz Golaszewski 
3738c7bd5a4SBartosz Golaszewski static void
mtk_star_ring_push_head_tx(struct mtk_star_ring * ring,struct mtk_star_ring_desc_data * desc_data)3748c7bd5a4SBartosz Golaszewski mtk_star_ring_push_head_tx(struct mtk_star_ring *ring,
3758c7bd5a4SBartosz Golaszewski 			   struct mtk_star_ring_desc_data *desc_data)
3768c7bd5a4SBartosz Golaszewski {
3778c7bd5a4SBartosz Golaszewski 	static const unsigned int flags = MTK_STAR_DESC_BIT_FS |
3788c7bd5a4SBartosz Golaszewski 					  MTK_STAR_DESC_BIT_LS |
3798c7bd5a4SBartosz Golaszewski 					  MTK_STAR_DESC_BIT_INT;
3808c7bd5a4SBartosz Golaszewski 
3818c7bd5a4SBartosz Golaszewski 	mtk_star_ring_push_head(ring, desc_data, flags);
3828c7bd5a4SBartosz Golaszewski }
3838c7bd5a4SBartosz Golaszewski 
mtk_star_tx_ring_avail(struct mtk_star_ring * ring)3840a8bd81fSBiao Huang static unsigned int mtk_star_tx_ring_avail(struct mtk_star_ring *ring)
3858c7bd5a4SBartosz Golaszewski {
3860a8bd81fSBiao Huang 	u32 avail;
3878c7bd5a4SBartosz Golaszewski 
3880a8bd81fSBiao Huang 	if (ring->tail > ring->head)
3890a8bd81fSBiao Huang 		avail = ring->tail - ring->head - 1;
3900a8bd81fSBiao Huang 	else
3910a8bd81fSBiao Huang 		avail = MTK_STAR_RING_NUM_DESCS - ring->head + ring->tail - 1;
3928c7bd5a4SBartosz Golaszewski 
3930a8bd81fSBiao Huang 	return avail;
3948c7bd5a4SBartosz Golaszewski }
3958c7bd5a4SBartosz Golaszewski 
mtk_star_dma_map_rx(struct mtk_star_priv * priv,struct sk_buff * skb)3968c7bd5a4SBartosz Golaszewski static dma_addr_t mtk_star_dma_map_rx(struct mtk_star_priv *priv,
3978c7bd5a4SBartosz Golaszewski 				      struct sk_buff *skb)
3988c7bd5a4SBartosz Golaszewski {
3998c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
4008c7bd5a4SBartosz Golaszewski 
4018c7bd5a4SBartosz Golaszewski 	/* Data pointer for the RX DMA descriptor must be aligned to 4N + 2. */
4028c7bd5a4SBartosz Golaszewski 	return dma_map_single(dev, skb_tail_pointer(skb) - 2,
4038c7bd5a4SBartosz Golaszewski 			      skb_tailroom(skb), DMA_FROM_DEVICE);
4048c7bd5a4SBartosz Golaszewski }
4058c7bd5a4SBartosz Golaszewski 
mtk_star_dma_unmap_rx(struct mtk_star_priv * priv,struct mtk_star_ring_desc_data * desc_data)4068c7bd5a4SBartosz Golaszewski static void mtk_star_dma_unmap_rx(struct mtk_star_priv *priv,
4078c7bd5a4SBartosz Golaszewski 				  struct mtk_star_ring_desc_data *desc_data)
4088c7bd5a4SBartosz Golaszewski {
4098c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
4108c7bd5a4SBartosz Golaszewski 
4118c7bd5a4SBartosz Golaszewski 	dma_unmap_single(dev, desc_data->dma_addr,
4128c7bd5a4SBartosz Golaszewski 			 skb_tailroom(desc_data->skb), DMA_FROM_DEVICE);
4138c7bd5a4SBartosz Golaszewski }
4148c7bd5a4SBartosz Golaszewski 
mtk_star_dma_map_tx(struct mtk_star_priv * priv,struct sk_buff * skb)4158c7bd5a4SBartosz Golaszewski static dma_addr_t mtk_star_dma_map_tx(struct mtk_star_priv *priv,
4168c7bd5a4SBartosz Golaszewski 				      struct sk_buff *skb)
4178c7bd5a4SBartosz Golaszewski {
4188c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
4198c7bd5a4SBartosz Golaszewski 
4208c7bd5a4SBartosz Golaszewski 	return dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
4218c7bd5a4SBartosz Golaszewski }
4228c7bd5a4SBartosz Golaszewski 
mtk_star_dma_unmap_tx(struct mtk_star_priv * priv,struct mtk_star_ring_desc_data * desc_data)4238c7bd5a4SBartosz Golaszewski static void mtk_star_dma_unmap_tx(struct mtk_star_priv *priv,
4248c7bd5a4SBartosz Golaszewski 				  struct mtk_star_ring_desc_data *desc_data)
4258c7bd5a4SBartosz Golaszewski {
4268c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
4278c7bd5a4SBartosz Golaszewski 
4288c7bd5a4SBartosz Golaszewski 	return dma_unmap_single(dev, desc_data->dma_addr,
4298c7bd5a4SBartosz Golaszewski 				skb_headlen(desc_data->skb), DMA_TO_DEVICE);
4308c7bd5a4SBartosz Golaszewski }
4318c7bd5a4SBartosz Golaszewski 
mtk_star_nic_disable_pd(struct mtk_star_priv * priv)4328c7bd5a4SBartosz Golaszewski static void mtk_star_nic_disable_pd(struct mtk_star_priv *priv)
4338c7bd5a4SBartosz Golaszewski {
434240f1ae4SBartosz Golaszewski 	regmap_clear_bits(priv->regs, MTK_STAR_REG_MAC_CFG,
435240f1ae4SBartosz Golaszewski 			  MTK_STAR_BIT_MAC_CFG_NIC_PD);
4368c7bd5a4SBartosz Golaszewski }
4378c7bd5a4SBartosz Golaszewski 
mtk_star_enable_dma_irq(struct mtk_star_priv * priv,bool rx,bool tx)4380a8bd81fSBiao Huang static void mtk_star_enable_dma_irq(struct mtk_star_priv *priv,
4390a8bd81fSBiao Huang 				    bool rx, bool tx)
4400a8bd81fSBiao Huang {
4410a8bd81fSBiao Huang 	u32 value;
4420a8bd81fSBiao Huang 
4430a8bd81fSBiao Huang 	regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
4440a8bd81fSBiao Huang 
4450a8bd81fSBiao Huang 	if (tx)
4460a8bd81fSBiao Huang 		value &= ~MTK_STAR_BIT_INT_STS_TNTC;
4470a8bd81fSBiao Huang 	if (rx)
4480a8bd81fSBiao Huang 		value &= ~MTK_STAR_BIT_INT_STS_FNRC;
4490a8bd81fSBiao Huang 
4500a8bd81fSBiao Huang 	regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
4510a8bd81fSBiao Huang }
4520a8bd81fSBiao Huang 
mtk_star_disable_dma_irq(struct mtk_star_priv * priv,bool rx,bool tx)4530a8bd81fSBiao Huang static void mtk_star_disable_dma_irq(struct mtk_star_priv *priv,
4540a8bd81fSBiao Huang 				     bool rx, bool tx)
4550a8bd81fSBiao Huang {
4560a8bd81fSBiao Huang 	u32 value;
4570a8bd81fSBiao Huang 
4580a8bd81fSBiao Huang 	regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
4590a8bd81fSBiao Huang 
4600a8bd81fSBiao Huang 	if (tx)
4610a8bd81fSBiao Huang 		value |= MTK_STAR_BIT_INT_STS_TNTC;
4620a8bd81fSBiao Huang 	if (rx)
4630a8bd81fSBiao Huang 		value |= MTK_STAR_BIT_INT_STS_FNRC;
4640a8bd81fSBiao Huang 
4650a8bd81fSBiao Huang 	regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
4660a8bd81fSBiao Huang }
4670a8bd81fSBiao Huang 
4688c7bd5a4SBartosz Golaszewski /* Unmask the three interrupts we care about, mask all others. */
mtk_star_intr_enable(struct mtk_star_priv * priv)4698c7bd5a4SBartosz Golaszewski static void mtk_star_intr_enable(struct mtk_star_priv *priv)
4708c7bd5a4SBartosz Golaszewski {
4718c7bd5a4SBartosz Golaszewski 	unsigned int val = MTK_STAR_BIT_INT_STS_TNTC |
4728c7bd5a4SBartosz Golaszewski 			   MTK_STAR_BIT_INT_STS_FNRC |
4738c7bd5a4SBartosz Golaszewski 			   MTK_STAR_REG_INT_STS_MIB_CNT_TH;
4748c7bd5a4SBartosz Golaszewski 
4758c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~val);
4768c7bd5a4SBartosz Golaszewski }
4778c7bd5a4SBartosz Golaszewski 
mtk_star_intr_disable(struct mtk_star_priv * priv)4788c7bd5a4SBartosz Golaszewski static void mtk_star_intr_disable(struct mtk_star_priv *priv)
4798c7bd5a4SBartosz Golaszewski {
4808c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~0);
4818c7bd5a4SBartosz Golaszewski }
4828c7bd5a4SBartosz Golaszewski 
mtk_star_intr_ack_all(struct mtk_star_priv * priv)4838c7bd5a4SBartosz Golaszewski static unsigned int mtk_star_intr_ack_all(struct mtk_star_priv *priv)
4848c7bd5a4SBartosz Golaszewski {
4858c7bd5a4SBartosz Golaszewski 	unsigned int val;
4868c7bd5a4SBartosz Golaszewski 
4870a8bd81fSBiao Huang 	regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
4888c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_INT_STS, val);
4898c7bd5a4SBartosz Golaszewski 
4908c7bd5a4SBartosz Golaszewski 	return val;
4918c7bd5a4SBartosz Golaszewski }
4928c7bd5a4SBartosz Golaszewski 
mtk_star_dma_init(struct mtk_star_priv * priv)4938c7bd5a4SBartosz Golaszewski static void mtk_star_dma_init(struct mtk_star_priv *priv)
4948c7bd5a4SBartosz Golaszewski {
4958c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc *desc;
4968c7bd5a4SBartosz Golaszewski 	unsigned int val;
4978c7bd5a4SBartosz Golaszewski 	int i;
4988c7bd5a4SBartosz Golaszewski 
4998c7bd5a4SBartosz Golaszewski 	priv->descs_base = (struct mtk_star_ring_desc *)priv->ring_base;
5008c7bd5a4SBartosz Golaszewski 
5018c7bd5a4SBartosz Golaszewski 	for (i = 0; i < MTK_STAR_NUM_DESCS_TOTAL; i++) {
5028c7bd5a4SBartosz Golaszewski 		desc = &priv->descs_base[i];
5038c7bd5a4SBartosz Golaszewski 
5048c7bd5a4SBartosz Golaszewski 		memset(desc, 0, sizeof(*desc));
5058c7bd5a4SBartosz Golaszewski 		desc->status = MTK_STAR_DESC_BIT_COWN;
5068c7bd5a4SBartosz Golaszewski 		if ((i == MTK_STAR_NUM_TX_DESCS - 1) ||
5078c7bd5a4SBartosz Golaszewski 		    (i == MTK_STAR_NUM_DESCS_TOTAL - 1))
5088c7bd5a4SBartosz Golaszewski 			desc->status |= MTK_STAR_DESC_BIT_EOR;
5098c7bd5a4SBartosz Golaszewski 	}
5108c7bd5a4SBartosz Golaszewski 
5118c7bd5a4SBartosz Golaszewski 	mtk_star_ring_init(&priv->tx_ring, priv->descs_base);
5128c7bd5a4SBartosz Golaszewski 	mtk_star_ring_init(&priv->rx_ring,
5138c7bd5a4SBartosz Golaszewski 			   priv->descs_base + MTK_STAR_NUM_TX_DESCS);
5148c7bd5a4SBartosz Golaszewski 
5158c7bd5a4SBartosz Golaszewski 	/* Set DMA pointers. */
5168c7bd5a4SBartosz Golaszewski 	val = (unsigned int)priv->dma_addr;
5178c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_TX_BASE_ADDR, val);
5188c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_TX_DPTR, val);
5198c7bd5a4SBartosz Golaszewski 
5208c7bd5a4SBartosz Golaszewski 	val += sizeof(struct mtk_star_ring_desc) * MTK_STAR_NUM_TX_DESCS;
5218c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_RX_BASE_ADDR, val);
5228c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_RX_DPTR, val);
5238c7bd5a4SBartosz Golaszewski }
5248c7bd5a4SBartosz Golaszewski 
mtk_star_dma_start(struct mtk_star_priv * priv)5258c7bd5a4SBartosz Golaszewski static void mtk_star_dma_start(struct mtk_star_priv *priv)
5268c7bd5a4SBartosz Golaszewski {
527240f1ae4SBartosz Golaszewski 	regmap_set_bits(priv->regs, MTK_STAR_REG_TX_DMA_CTRL,
5288c7bd5a4SBartosz Golaszewski 			MTK_STAR_BIT_TX_DMA_CTRL_START);
529240f1ae4SBartosz Golaszewski 	regmap_set_bits(priv->regs, MTK_STAR_REG_RX_DMA_CTRL,
5308c7bd5a4SBartosz Golaszewski 			MTK_STAR_BIT_RX_DMA_CTRL_START);
5318c7bd5a4SBartosz Golaszewski }
5328c7bd5a4SBartosz Golaszewski 
mtk_star_dma_stop(struct mtk_star_priv * priv)5338c7bd5a4SBartosz Golaszewski static void mtk_star_dma_stop(struct mtk_star_priv *priv)
5348c7bd5a4SBartosz Golaszewski {
5358c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_TX_DMA_CTRL,
5368c7bd5a4SBartosz Golaszewski 		     MTK_STAR_BIT_TX_DMA_CTRL_STOP);
5378c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_RX_DMA_CTRL,
5388c7bd5a4SBartosz Golaszewski 		     MTK_STAR_BIT_RX_DMA_CTRL_STOP);
5398c7bd5a4SBartosz Golaszewski }
5408c7bd5a4SBartosz Golaszewski 
mtk_star_dma_disable(struct mtk_star_priv * priv)5418c7bd5a4SBartosz Golaszewski static void mtk_star_dma_disable(struct mtk_star_priv *priv)
5428c7bd5a4SBartosz Golaszewski {
5438c7bd5a4SBartosz Golaszewski 	int i;
5448c7bd5a4SBartosz Golaszewski 
5458c7bd5a4SBartosz Golaszewski 	mtk_star_dma_stop(priv);
5468c7bd5a4SBartosz Golaszewski 
5478c7bd5a4SBartosz Golaszewski 	/* Take back all descriptors. */
5488c7bd5a4SBartosz Golaszewski 	for (i = 0; i < MTK_STAR_NUM_DESCS_TOTAL; i++)
5498c7bd5a4SBartosz Golaszewski 		priv->descs_base[i].status |= MTK_STAR_DESC_BIT_COWN;
5508c7bd5a4SBartosz Golaszewski }
5518c7bd5a4SBartosz Golaszewski 
mtk_star_dma_resume_rx(struct mtk_star_priv * priv)5528c7bd5a4SBartosz Golaszewski static void mtk_star_dma_resume_rx(struct mtk_star_priv *priv)
5538c7bd5a4SBartosz Golaszewski {
554240f1ae4SBartosz Golaszewski 	regmap_set_bits(priv->regs, MTK_STAR_REG_RX_DMA_CTRL,
5558c7bd5a4SBartosz Golaszewski 			MTK_STAR_BIT_RX_DMA_CTRL_RESUME);
5568c7bd5a4SBartosz Golaszewski }
5578c7bd5a4SBartosz Golaszewski 
mtk_star_dma_resume_tx(struct mtk_star_priv * priv)5588c7bd5a4SBartosz Golaszewski static void mtk_star_dma_resume_tx(struct mtk_star_priv *priv)
5598c7bd5a4SBartosz Golaszewski {
560240f1ae4SBartosz Golaszewski 	regmap_set_bits(priv->regs, MTK_STAR_REG_TX_DMA_CTRL,
5618c7bd5a4SBartosz Golaszewski 			MTK_STAR_BIT_TX_DMA_CTRL_RESUME);
5628c7bd5a4SBartosz Golaszewski }
5638c7bd5a4SBartosz Golaszewski 
mtk_star_set_mac_addr(struct net_device * ndev)5648c7bd5a4SBartosz Golaszewski static void mtk_star_set_mac_addr(struct net_device *ndev)
5658c7bd5a4SBartosz Golaszewski {
5668c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
56776660757SJakub Kicinski 	const u8 *mac_addr = ndev->dev_addr;
5688c7bd5a4SBartosz Golaszewski 	unsigned int high, low;
5698c7bd5a4SBartosz Golaszewski 
5708c7bd5a4SBartosz Golaszewski 	high = mac_addr[0] << 8 | mac_addr[1] << 0;
5718c7bd5a4SBartosz Golaszewski 	low = mac_addr[2] << 24 | mac_addr[3] << 16 |
5728c7bd5a4SBartosz Golaszewski 	      mac_addr[4] << 8 | mac_addr[5];
5738c7bd5a4SBartosz Golaszewski 
5748c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_MY_MAC_H, high);
5758c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_MY_MAC_L, low);
5768c7bd5a4SBartosz Golaszewski }
5778c7bd5a4SBartosz Golaszewski 
mtk_star_reset_counters(struct mtk_star_priv * priv)5788c7bd5a4SBartosz Golaszewski static void mtk_star_reset_counters(struct mtk_star_priv *priv)
5798c7bd5a4SBartosz Golaszewski {
5808c7bd5a4SBartosz Golaszewski 	static const unsigned int counter_regs[] = {
5818c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXOKPKT,
5828c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXOKBYTE,
5838c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXRUNT,
5848c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXLONG,
5858c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXDROP,
5868c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXCRC,
5878c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXARLDROP,
5888c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXVLANDROP,
5898c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXCSERR,
5908c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RXPAUSE,
5918c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TXOKPKT,
5928c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TXOKBYTE,
5938c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TXPAUSECOL,
5948c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TXRTY,
5958c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TXSKIP,
5968c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TX_ARP,
5978c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_RERR,
5988c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_UNI,
5998c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_MULTI,
6008c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_BROAD,
6018c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_ALIGNERR,
6028c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TX_UNI,
6038c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TX_MULTI,
6048c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TX_BROAD,
6058c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TX_TIMEOUT,
6068c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_TX_LATECOL,
6078c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_LENGTHERR,
6088c7bd5a4SBartosz Golaszewski 		MTK_STAR_REG_C_RX_TWIST,
6098c7bd5a4SBartosz Golaszewski 	};
6108c7bd5a4SBartosz Golaszewski 
6118c7bd5a4SBartosz Golaszewski 	unsigned int i, val;
6128c7bd5a4SBartosz Golaszewski 
6138c7bd5a4SBartosz Golaszewski 	for (i = 0; i < ARRAY_SIZE(counter_regs); i++)
6148c7bd5a4SBartosz Golaszewski 		regmap_read(priv->regs, counter_regs[i], &val);
6158c7bd5a4SBartosz Golaszewski }
6168c7bd5a4SBartosz Golaszewski 
mtk_star_update_stat(struct mtk_star_priv * priv,unsigned int reg,u64 * stat)6178c7bd5a4SBartosz Golaszewski static void mtk_star_update_stat(struct mtk_star_priv *priv,
6188c7bd5a4SBartosz Golaszewski 				 unsigned int reg, u64 *stat)
6198c7bd5a4SBartosz Golaszewski {
6208c7bd5a4SBartosz Golaszewski 	unsigned int val;
6218c7bd5a4SBartosz Golaszewski 
6228c7bd5a4SBartosz Golaszewski 	regmap_read(priv->regs, reg, &val);
6238c7bd5a4SBartosz Golaszewski 	*stat += val;
6248c7bd5a4SBartosz Golaszewski }
6258c7bd5a4SBartosz Golaszewski 
6268c7bd5a4SBartosz Golaszewski /* Try to get as many stats as possible from the internal registers instead
6278c7bd5a4SBartosz Golaszewski  * of tracking them ourselves.
6288c7bd5a4SBartosz Golaszewski  */
mtk_star_update_stats(struct mtk_star_priv * priv)6298c7bd5a4SBartosz Golaszewski static void mtk_star_update_stats(struct mtk_star_priv *priv)
6308c7bd5a4SBartosz Golaszewski {
6318c7bd5a4SBartosz Golaszewski 	struct rtnl_link_stats64 *stats = &priv->stats;
6328c7bd5a4SBartosz Golaszewski 
6338c7bd5a4SBartosz Golaszewski 	/* OK packets and bytes. */
6348c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RXOKPKT, &stats->rx_packets);
6358c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_TXOKPKT, &stats->tx_packets);
6368c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RXOKBYTE, &stats->rx_bytes);
6378c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_TXOKBYTE, &stats->tx_bytes);
6388c7bd5a4SBartosz Golaszewski 
6398c7bd5a4SBartosz Golaszewski 	/* RX & TX multicast. */
6408c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_MULTI, &stats->multicast);
6418c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_TX_MULTI, &stats->multicast);
6428c7bd5a4SBartosz Golaszewski 
6438c7bd5a4SBartosz Golaszewski 	/* Collisions. */
6448c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_TXPAUSECOL,
6458c7bd5a4SBartosz Golaszewski 			     &stats->collisions);
6468c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_TX_LATECOL,
6478c7bd5a4SBartosz Golaszewski 			     &stats->collisions);
6488c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RXRUNT, &stats->collisions);
6498c7bd5a4SBartosz Golaszewski 
6508c7bd5a4SBartosz Golaszewski 	/* RX Errors. */
6518c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_LENGTHERR,
6528c7bd5a4SBartosz Golaszewski 			     &stats->rx_length_errors);
6538c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RXLONG,
6548c7bd5a4SBartosz Golaszewski 			     &stats->rx_over_errors);
6558c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RXCRC, &stats->rx_crc_errors);
6568c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_ALIGNERR,
6578c7bd5a4SBartosz Golaszewski 			     &stats->rx_frame_errors);
6588c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RXDROP,
6598c7bd5a4SBartosz Golaszewski 			     &stats->rx_fifo_errors);
6608c7bd5a4SBartosz Golaszewski 	/* Sum of the general RX error counter + all of the above. */
6618c7bd5a4SBartosz Golaszewski 	mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_RERR, &stats->rx_errors);
6628c7bd5a4SBartosz Golaszewski 	stats->rx_errors += stats->rx_length_errors;
6638c7bd5a4SBartosz Golaszewski 	stats->rx_errors += stats->rx_over_errors;
6648c7bd5a4SBartosz Golaszewski 	stats->rx_errors += stats->rx_crc_errors;
6658c7bd5a4SBartosz Golaszewski 	stats->rx_errors += stats->rx_frame_errors;
6668c7bd5a4SBartosz Golaszewski 	stats->rx_errors += stats->rx_fifo_errors;
6678c7bd5a4SBartosz Golaszewski }
6688c7bd5a4SBartosz Golaszewski 
mtk_star_alloc_skb(struct net_device * ndev)6698c7bd5a4SBartosz Golaszewski static struct sk_buff *mtk_star_alloc_skb(struct net_device *ndev)
6708c7bd5a4SBartosz Golaszewski {
6718c7bd5a4SBartosz Golaszewski 	uintptr_t tail, offset;
6728c7bd5a4SBartosz Golaszewski 	struct sk_buff *skb;
6738c7bd5a4SBartosz Golaszewski 
6748c7bd5a4SBartosz Golaszewski 	skb = dev_alloc_skb(MTK_STAR_MAX_FRAME_SIZE);
6758c7bd5a4SBartosz Golaszewski 	if (!skb)
6768c7bd5a4SBartosz Golaszewski 		return NULL;
6778c7bd5a4SBartosz Golaszewski 
6788c7bd5a4SBartosz Golaszewski 	/* Align to 16 bytes. */
6798c7bd5a4SBartosz Golaszewski 	tail = (uintptr_t)skb_tail_pointer(skb);
6808c7bd5a4SBartosz Golaszewski 	if (tail & (MTK_STAR_SKB_ALIGNMENT - 1)) {
6818c7bd5a4SBartosz Golaszewski 		offset = tail & (MTK_STAR_SKB_ALIGNMENT - 1);
6828c7bd5a4SBartosz Golaszewski 		skb_reserve(skb, MTK_STAR_SKB_ALIGNMENT - offset);
6838c7bd5a4SBartosz Golaszewski 	}
6848c7bd5a4SBartosz Golaszewski 
6858c7bd5a4SBartosz Golaszewski 	/* Ensure 16-byte alignment of the skb pointer: eth_type_trans() will
6868c7bd5a4SBartosz Golaszewski 	 * extract the Ethernet header (14 bytes) so we need two more bytes.
6878c7bd5a4SBartosz Golaszewski 	 */
6888c7bd5a4SBartosz Golaszewski 	skb_reserve(skb, MTK_STAR_IP_ALIGN);
6898c7bd5a4SBartosz Golaszewski 
6908c7bd5a4SBartosz Golaszewski 	return skb;
6918c7bd5a4SBartosz Golaszewski }
6928c7bd5a4SBartosz Golaszewski 
mtk_star_prepare_rx_skbs(struct net_device * ndev)6938c7bd5a4SBartosz Golaszewski static int mtk_star_prepare_rx_skbs(struct net_device *ndev)
6948c7bd5a4SBartosz Golaszewski {
6958c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
6968c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->rx_ring;
6978c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
6988c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc *desc;
6998c7bd5a4SBartosz Golaszewski 	struct sk_buff *skb;
7008c7bd5a4SBartosz Golaszewski 	dma_addr_t dma_addr;
7018c7bd5a4SBartosz Golaszewski 	int i;
7028c7bd5a4SBartosz Golaszewski 
7038c7bd5a4SBartosz Golaszewski 	for (i = 0; i < MTK_STAR_NUM_RX_DESCS; i++) {
7048c7bd5a4SBartosz Golaszewski 		skb = mtk_star_alloc_skb(ndev);
7058c7bd5a4SBartosz Golaszewski 		if (!skb)
7068c7bd5a4SBartosz Golaszewski 			return -ENOMEM;
7078c7bd5a4SBartosz Golaszewski 
7088c7bd5a4SBartosz Golaszewski 		dma_addr = mtk_star_dma_map_rx(priv, skb);
7098c7bd5a4SBartosz Golaszewski 		if (dma_mapping_error(dev, dma_addr)) {
7108c7bd5a4SBartosz Golaszewski 			dev_kfree_skb(skb);
7118c7bd5a4SBartosz Golaszewski 			return -ENOMEM;
7128c7bd5a4SBartosz Golaszewski 		}
7138c7bd5a4SBartosz Golaszewski 
7148c7bd5a4SBartosz Golaszewski 		desc = &ring->descs[i];
7158c7bd5a4SBartosz Golaszewski 		desc->data_ptr = dma_addr;
7168c7bd5a4SBartosz Golaszewski 		desc->status |= skb_tailroom(skb) & MTK_STAR_DESC_MSK_LEN;
7178c7bd5a4SBartosz Golaszewski 		desc->status &= ~MTK_STAR_DESC_BIT_COWN;
7188c7bd5a4SBartosz Golaszewski 		ring->skbs[i] = skb;
7198c7bd5a4SBartosz Golaszewski 		ring->dma_addrs[i] = dma_addr;
7208c7bd5a4SBartosz Golaszewski 	}
7218c7bd5a4SBartosz Golaszewski 
7228c7bd5a4SBartosz Golaszewski 	return 0;
7238c7bd5a4SBartosz Golaszewski }
7248c7bd5a4SBartosz Golaszewski 
7258c7bd5a4SBartosz Golaszewski static void
mtk_star_ring_free_skbs(struct mtk_star_priv * priv,struct mtk_star_ring * ring,void (* unmap_func)(struct mtk_star_priv *,struct mtk_star_ring_desc_data *))7268c7bd5a4SBartosz Golaszewski mtk_star_ring_free_skbs(struct mtk_star_priv *priv, struct mtk_star_ring *ring,
7278c7bd5a4SBartosz Golaszewski 			void (*unmap_func)(struct mtk_star_priv *,
7288c7bd5a4SBartosz Golaszewski 					   struct mtk_star_ring_desc_data *))
7298c7bd5a4SBartosz Golaszewski {
7308c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc_data desc_data;
7318c7bd5a4SBartosz Golaszewski 	int i;
7328c7bd5a4SBartosz Golaszewski 
7338c7bd5a4SBartosz Golaszewski 	for (i = 0; i < MTK_STAR_RING_NUM_DESCS; i++) {
7348c7bd5a4SBartosz Golaszewski 		if (!ring->dma_addrs[i])
7358c7bd5a4SBartosz Golaszewski 			continue;
7368c7bd5a4SBartosz Golaszewski 
7378c7bd5a4SBartosz Golaszewski 		desc_data.dma_addr = ring->dma_addrs[i];
7388c7bd5a4SBartosz Golaszewski 		desc_data.skb = ring->skbs[i];
7398c7bd5a4SBartosz Golaszewski 
7408c7bd5a4SBartosz Golaszewski 		unmap_func(priv, &desc_data);
7418c7bd5a4SBartosz Golaszewski 		dev_kfree_skb(desc_data.skb);
7428c7bd5a4SBartosz Golaszewski 	}
7438c7bd5a4SBartosz Golaszewski }
7448c7bd5a4SBartosz Golaszewski 
mtk_star_free_rx_skbs(struct mtk_star_priv * priv)7458c7bd5a4SBartosz Golaszewski static void mtk_star_free_rx_skbs(struct mtk_star_priv *priv)
7468c7bd5a4SBartosz Golaszewski {
7478c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->rx_ring;
7488c7bd5a4SBartosz Golaszewski 
7498c7bd5a4SBartosz Golaszewski 	mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_rx);
7508c7bd5a4SBartosz Golaszewski }
7518c7bd5a4SBartosz Golaszewski 
mtk_star_free_tx_skbs(struct mtk_star_priv * priv)7528c7bd5a4SBartosz Golaszewski static void mtk_star_free_tx_skbs(struct mtk_star_priv *priv)
7538c7bd5a4SBartosz Golaszewski {
7548c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->tx_ring;
7558c7bd5a4SBartosz Golaszewski 
7568c7bd5a4SBartosz Golaszewski 	mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_tx);
7578c7bd5a4SBartosz Golaszewski }
7588c7bd5a4SBartosz Golaszewski 
7590a8bd81fSBiao Huang /**
7600a8bd81fSBiao Huang  * mtk_star_handle_irq - Interrupt Handler.
7610a8bd81fSBiao Huang  * @irq: interrupt number.
7620a8bd81fSBiao Huang  * @data: pointer to a network interface device structure.
7630a8bd81fSBiao Huang  * Description : this is the driver interrupt service routine.
7640a8bd81fSBiao Huang  * it mainly handles:
7650a8bd81fSBiao Huang  *  1. tx complete interrupt for frame transmission.
7660a8bd81fSBiao Huang  *  2. rx complete interrupt for frame reception.
7670a8bd81fSBiao Huang  *  3. MAC Management Counter interrupt to avoid counter overflow.
7680a8bd81fSBiao Huang  **/
mtk_star_handle_irq(int irq,void * data)7698c7bd5a4SBartosz Golaszewski static irqreturn_t mtk_star_handle_irq(int irq, void *data)
7708c7bd5a4SBartosz Golaszewski {
7710a8bd81fSBiao Huang 	struct net_device *ndev = data;
7720a8bd81fSBiao Huang 	struct mtk_star_priv *priv = netdev_priv(ndev);
7730a8bd81fSBiao Huang 	unsigned int intr_status = mtk_star_intr_ack_all(priv);
7740a8bd81fSBiao Huang 	bool rx, tx;
7758c7bd5a4SBartosz Golaszewski 
7760a8bd81fSBiao Huang 	rx = (intr_status & MTK_STAR_BIT_INT_STS_FNRC) &&
7770a8bd81fSBiao Huang 	     napi_schedule_prep(&priv->rx_napi);
7780a8bd81fSBiao Huang 	tx = (intr_status & MTK_STAR_BIT_INT_STS_TNTC) &&
7790a8bd81fSBiao Huang 	     napi_schedule_prep(&priv->tx_napi);
7808c7bd5a4SBartosz Golaszewski 
7810a8bd81fSBiao Huang 	if (rx || tx) {
7820a8bd81fSBiao Huang 		spin_lock(&priv->lock);
7830a8bd81fSBiao Huang 		/* mask Rx and TX Complete interrupt */
7840a8bd81fSBiao Huang 		mtk_star_disable_dma_irq(priv, rx, tx);
7850a8bd81fSBiao Huang 		spin_unlock(&priv->lock);
7860a8bd81fSBiao Huang 
7870a8bd81fSBiao Huang 		if (rx)
7880a8bd81fSBiao Huang 			__napi_schedule(&priv->rx_napi);
7890a8bd81fSBiao Huang 		if (tx)
7900a8bd81fSBiao Huang 			__napi_schedule(&priv->tx_napi);
7910a8bd81fSBiao Huang 	}
7920a8bd81fSBiao Huang 
7930a8bd81fSBiao Huang 	/* interrupt is triggered once any counters reach 0x8000000 */
7940a8bd81fSBiao Huang 	if (intr_status & MTK_STAR_REG_INT_STS_MIB_CNT_TH) {
7950a8bd81fSBiao Huang 		mtk_star_update_stats(priv);
7960a8bd81fSBiao Huang 		mtk_star_reset_counters(priv);
7978c7bd5a4SBartosz Golaszewski 	}
7988c7bd5a4SBartosz Golaszewski 
7998c7bd5a4SBartosz Golaszewski 	return IRQ_HANDLED;
8008c7bd5a4SBartosz Golaszewski }
8018c7bd5a4SBartosz Golaszewski 
8028c7bd5a4SBartosz Golaszewski /* Wait for the completion of any previous command - CMD_START bit must be
8038c7bd5a4SBartosz Golaszewski  * cleared by hardware.
8048c7bd5a4SBartosz Golaszewski  */
mtk_star_hash_wait_cmd_start(struct mtk_star_priv * priv)8058c7bd5a4SBartosz Golaszewski static int mtk_star_hash_wait_cmd_start(struct mtk_star_priv *priv)
8068c7bd5a4SBartosz Golaszewski {
8078c7bd5a4SBartosz Golaszewski 	unsigned int val;
8088c7bd5a4SBartosz Golaszewski 
8098c7bd5a4SBartosz Golaszewski 	return regmap_read_poll_timeout_atomic(priv->regs,
8108c7bd5a4SBartosz Golaszewski 				MTK_STAR_REG_HASH_CTRL, val,
8118c7bd5a4SBartosz Golaszewski 				!(val & MTK_STAR_BIT_HASH_CTRL_CMD_START),
8128c7bd5a4SBartosz Golaszewski 				10, MTK_STAR_WAIT_TIMEOUT);
8138c7bd5a4SBartosz Golaszewski }
8148c7bd5a4SBartosz Golaszewski 
mtk_star_hash_wait_ok(struct mtk_star_priv * priv)8158c7bd5a4SBartosz Golaszewski static int mtk_star_hash_wait_ok(struct mtk_star_priv *priv)
8168c7bd5a4SBartosz Golaszewski {
8178c7bd5a4SBartosz Golaszewski 	unsigned int val;
8188c7bd5a4SBartosz Golaszewski 	int ret;
8198c7bd5a4SBartosz Golaszewski 
8208c7bd5a4SBartosz Golaszewski 	/* Wait for BIST_DONE bit. */
8218c7bd5a4SBartosz Golaszewski 	ret = regmap_read_poll_timeout_atomic(priv->regs,
8228c7bd5a4SBartosz Golaszewski 					MTK_STAR_REG_HASH_CTRL, val,
8238c7bd5a4SBartosz Golaszewski 					val & MTK_STAR_BIT_HASH_CTRL_BIST_DONE,
8248c7bd5a4SBartosz Golaszewski 					10, MTK_STAR_WAIT_TIMEOUT);
8258c7bd5a4SBartosz Golaszewski 	if (ret)
8268c7bd5a4SBartosz Golaszewski 		return ret;
8278c7bd5a4SBartosz Golaszewski 
8288c7bd5a4SBartosz Golaszewski 	/* Check the BIST_OK bit. */
829240f1ae4SBartosz Golaszewski 	if (!regmap_test_bits(priv->regs, MTK_STAR_REG_HASH_CTRL,
830240f1ae4SBartosz Golaszewski 			      MTK_STAR_BIT_HASH_CTRL_BIST_OK))
8318c7bd5a4SBartosz Golaszewski 		return -EIO;
8328c7bd5a4SBartosz Golaszewski 
8338c7bd5a4SBartosz Golaszewski 	return 0;
8348c7bd5a4SBartosz Golaszewski }
8358c7bd5a4SBartosz Golaszewski 
mtk_star_set_hashbit(struct mtk_star_priv * priv,unsigned int hash_addr)8368c7bd5a4SBartosz Golaszewski static int mtk_star_set_hashbit(struct mtk_star_priv *priv,
8378c7bd5a4SBartosz Golaszewski 				unsigned int hash_addr)
8388c7bd5a4SBartosz Golaszewski {
8398c7bd5a4SBartosz Golaszewski 	unsigned int val;
8408c7bd5a4SBartosz Golaszewski 	int ret;
8418c7bd5a4SBartosz Golaszewski 
8428c7bd5a4SBartosz Golaszewski 	ret = mtk_star_hash_wait_cmd_start(priv);
8438c7bd5a4SBartosz Golaszewski 	if (ret)
8448c7bd5a4SBartosz Golaszewski 		return ret;
8458c7bd5a4SBartosz Golaszewski 
8468c7bd5a4SBartosz Golaszewski 	val = hash_addr & MTK_STAR_MSK_HASH_CTRL_HASH_BIT_ADDR;
8478c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_HASH_CTRL_ACC_CMD;
8488c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_HASH_CTRL_CMD_START;
8498c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_HASH_CTRL_BIST_EN;
8508c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_HASH_CTRL_HASH_BIT_DATA;
8518c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_HASH_CTRL, val);
8528c7bd5a4SBartosz Golaszewski 
8538c7bd5a4SBartosz Golaszewski 	return mtk_star_hash_wait_ok(priv);
8548c7bd5a4SBartosz Golaszewski }
8558c7bd5a4SBartosz Golaszewski 
mtk_star_reset_hash_table(struct mtk_star_priv * priv)8568c7bd5a4SBartosz Golaszewski static int mtk_star_reset_hash_table(struct mtk_star_priv *priv)
8578c7bd5a4SBartosz Golaszewski {
8588c7bd5a4SBartosz Golaszewski 	int ret;
8598c7bd5a4SBartosz Golaszewski 
8608c7bd5a4SBartosz Golaszewski 	ret = mtk_star_hash_wait_cmd_start(priv);
8618c7bd5a4SBartosz Golaszewski 	if (ret)
8628c7bd5a4SBartosz Golaszewski 		return ret;
8638c7bd5a4SBartosz Golaszewski 
864240f1ae4SBartosz Golaszewski 	regmap_set_bits(priv->regs, MTK_STAR_REG_HASH_CTRL,
8658c7bd5a4SBartosz Golaszewski 			MTK_STAR_BIT_HASH_CTRL_BIST_EN);
866240f1ae4SBartosz Golaszewski 	regmap_set_bits(priv->regs, MTK_STAR_REG_TEST1,
8678c7bd5a4SBartosz Golaszewski 			MTK_STAR_BIT_TEST1_RST_HASH_MBIST);
8688c7bd5a4SBartosz Golaszewski 
8698c7bd5a4SBartosz Golaszewski 	return mtk_star_hash_wait_ok(priv);
8708c7bd5a4SBartosz Golaszewski }
8718c7bd5a4SBartosz Golaszewski 
mtk_star_phy_config(struct mtk_star_priv * priv)8728c7bd5a4SBartosz Golaszewski static void mtk_star_phy_config(struct mtk_star_priv *priv)
8738c7bd5a4SBartosz Golaszewski {
8748c7bd5a4SBartosz Golaszewski 	unsigned int val;
8758c7bd5a4SBartosz Golaszewski 
8768c7bd5a4SBartosz Golaszewski 	if (priv->speed == SPEED_1000)
8778c7bd5a4SBartosz Golaszewski 		val = MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_1000M;
8788c7bd5a4SBartosz Golaszewski 	else if (priv->speed == SPEED_100)
8798c7bd5a4SBartosz Golaszewski 		val = MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_100M;
8808c7bd5a4SBartosz Golaszewski 	else
8818c7bd5a4SBartosz Golaszewski 		val = MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_10M;
8828c7bd5a4SBartosz Golaszewski 	val <<= MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD;
8838c7bd5a4SBartosz Golaszewski 
8848c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_PHY_CTRL1_AN_EN;
88502e9ce07SBiao Huang 	if (priv->pause) {
8868c7bd5a4SBartosz Golaszewski 		val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
8878c7bd5a4SBartosz Golaszewski 		val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
8888c7bd5a4SBartosz Golaszewski 		val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
88902e9ce07SBiao Huang 	} else {
89002e9ce07SBiao Huang 		val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
89102e9ce07SBiao Huang 		val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
89202e9ce07SBiao Huang 		val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
89302e9ce07SBiao Huang 	}
8948c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val);
8958c7bd5a4SBartosz Golaszewski 
8968c7bd5a4SBartosz Golaszewski 	val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K;
8978c7bd5a4SBartosz Golaszewski 	val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH;
8988c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR;
8998c7bd5a4SBartosz Golaszewski 	regmap_update_bits(priv->regs, MTK_STAR_REG_FC_CFG,
9008c7bd5a4SBartosz Golaszewski 			   MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH |
9018c7bd5a4SBartosz Golaszewski 			   MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR, val);
9028c7bd5a4SBartosz Golaszewski 
9038c7bd5a4SBartosz Golaszewski 	val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
9048c7bd5a4SBartosz Golaszewski 	val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS;
9058c7bd5a4SBartosz Golaszewski 	regmap_update_bits(priv->regs, MTK_STAR_REG_EXT_CFG,
9068c7bd5a4SBartosz Golaszewski 			   MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS, val);
9078c7bd5a4SBartosz Golaszewski }
9088c7bd5a4SBartosz Golaszewski 
mtk_star_adjust_link(struct net_device * ndev)9098c7bd5a4SBartosz Golaszewski static void mtk_star_adjust_link(struct net_device *ndev)
9108c7bd5a4SBartosz Golaszewski {
9118c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
9128c7bd5a4SBartosz Golaszewski 	struct phy_device *phydev = priv->phydev;
9138c7bd5a4SBartosz Golaszewski 	bool new_state = false;
9148c7bd5a4SBartosz Golaszewski 
9158c7bd5a4SBartosz Golaszewski 	if (phydev->link) {
9168c7bd5a4SBartosz Golaszewski 		if (!priv->link) {
9178c7bd5a4SBartosz Golaszewski 			priv->link = phydev->link;
9188c7bd5a4SBartosz Golaszewski 			new_state = true;
9198c7bd5a4SBartosz Golaszewski 		}
9208c7bd5a4SBartosz Golaszewski 
9218c7bd5a4SBartosz Golaszewski 		if (priv->speed != phydev->speed) {
9228c7bd5a4SBartosz Golaszewski 			priv->speed = phydev->speed;
9238c7bd5a4SBartosz Golaszewski 			new_state = true;
9248c7bd5a4SBartosz Golaszewski 		}
9258c7bd5a4SBartosz Golaszewski 
9268c7bd5a4SBartosz Golaszewski 		if (priv->pause != phydev->pause) {
9278c7bd5a4SBartosz Golaszewski 			priv->pause = phydev->pause;
9288c7bd5a4SBartosz Golaszewski 			new_state = true;
9298c7bd5a4SBartosz Golaszewski 		}
9308c7bd5a4SBartosz Golaszewski 	} else {
9318c7bd5a4SBartosz Golaszewski 		if (priv->link) {
9328c7bd5a4SBartosz Golaszewski 			priv->link = phydev->link;
9338c7bd5a4SBartosz Golaszewski 			new_state = true;
9348c7bd5a4SBartosz Golaszewski 		}
9358c7bd5a4SBartosz Golaszewski 	}
9368c7bd5a4SBartosz Golaszewski 
9378c7bd5a4SBartosz Golaszewski 	if (new_state) {
9388c7bd5a4SBartosz Golaszewski 		if (phydev->link)
9398c7bd5a4SBartosz Golaszewski 			mtk_star_phy_config(priv);
9408c7bd5a4SBartosz Golaszewski 
9418c7bd5a4SBartosz Golaszewski 		phy_print_status(ndev->phydev);
9428c7bd5a4SBartosz Golaszewski 	}
9438c7bd5a4SBartosz Golaszewski }
9448c7bd5a4SBartosz Golaszewski 
mtk_star_init_config(struct mtk_star_priv * priv)9458c7bd5a4SBartosz Golaszewski static void mtk_star_init_config(struct mtk_star_priv *priv)
9468c7bd5a4SBartosz Golaszewski {
9478c7bd5a4SBartosz Golaszewski 	unsigned int val;
9488c7bd5a4SBartosz Golaszewski 
9498c7bd5a4SBartosz Golaszewski 	val = (MTK_STAR_BIT_MII_PAD_OUT_ENABLE |
9508c7bd5a4SBartosz Golaszewski 	       MTK_STAR_BIT_EXT_MDC_MODE |
9518c7bd5a4SBartosz Golaszewski 	       MTK_STAR_BIT_SWC_MII_MODE);
9528c7bd5a4SBartosz Golaszewski 
9538c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_SYS_CONF, val);
9548c7bd5a4SBartosz Golaszewski 	regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CLK_CONF,
9558c7bd5a4SBartosz Golaszewski 			   MTK_STAR_MSK_MAC_CLK_CONF,
956c16cc6a0SBiao Huang 			   priv->compat_data->bit_clk_div);
9578c7bd5a4SBartosz Golaszewski }
9588c7bd5a4SBartosz Golaszewski 
mtk_star_enable(struct net_device * ndev)9598c7bd5a4SBartosz Golaszewski static int mtk_star_enable(struct net_device *ndev)
9608c7bd5a4SBartosz Golaszewski {
9618c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
9628c7bd5a4SBartosz Golaszewski 	unsigned int val;
9638c7bd5a4SBartosz Golaszewski 	int ret;
9648c7bd5a4SBartosz Golaszewski 
9658c7bd5a4SBartosz Golaszewski 	mtk_star_nic_disable_pd(priv);
9668c7bd5a4SBartosz Golaszewski 	mtk_star_intr_disable(priv);
9678c7bd5a4SBartosz Golaszewski 	mtk_star_dma_stop(priv);
9688c7bd5a4SBartosz Golaszewski 
9698c7bd5a4SBartosz Golaszewski 	mtk_star_set_mac_addr(ndev);
9708c7bd5a4SBartosz Golaszewski 
9718c7bd5a4SBartosz Golaszewski 	/* Configure the MAC */
9728c7bd5a4SBartosz Golaszewski 	val = MTK_STAR_VAL_MAC_CFG_IPG_96BIT;
9738c7bd5a4SBartosz Golaszewski 	val <<= MTK_STAR_OFF_MAC_CFG_IPG;
9748c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_MAC_CFG_MAXLEN_1522;
9758c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_MAC_CFG_AUTO_PAD;
9768c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_MAC_CFG_CRC_STRIP;
9778c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_MAC_CFG, val);
9788c7bd5a4SBartosz Golaszewski 
9798c7bd5a4SBartosz Golaszewski 	/* Enable Hash Table BIST and reset it */
9808c7bd5a4SBartosz Golaszewski 	ret = mtk_star_reset_hash_table(priv);
9818c7bd5a4SBartosz Golaszewski 	if (ret)
9828c7bd5a4SBartosz Golaszewski 		return ret;
9838c7bd5a4SBartosz Golaszewski 
9848c7bd5a4SBartosz Golaszewski 	/* Setup the hashing algorithm */
985240f1ae4SBartosz Golaszewski 	regmap_clear_bits(priv->regs, MTK_STAR_REG_ARL_CFG,
9868c7bd5a4SBartosz Golaszewski 			  MTK_STAR_BIT_ARL_CFG_HASH_ALG |
987240f1ae4SBartosz Golaszewski 			  MTK_STAR_BIT_ARL_CFG_MISC_MODE);
9888c7bd5a4SBartosz Golaszewski 
9898c7bd5a4SBartosz Golaszewski 	/* Don't strip VLAN tags */
990240f1ae4SBartosz Golaszewski 	regmap_clear_bits(priv->regs, MTK_STAR_REG_MAC_CFG,
991240f1ae4SBartosz Golaszewski 			  MTK_STAR_BIT_MAC_CFG_VLAN_STRIP);
9928c7bd5a4SBartosz Golaszewski 
9938c7bd5a4SBartosz Golaszewski 	/* Setup DMA */
9948c7bd5a4SBartosz Golaszewski 	mtk_star_dma_init(priv);
9958c7bd5a4SBartosz Golaszewski 
9968c7bd5a4SBartosz Golaszewski 	ret = mtk_star_prepare_rx_skbs(ndev);
9978c7bd5a4SBartosz Golaszewski 	if (ret)
9988c7bd5a4SBartosz Golaszewski 		goto err_out;
9998c7bd5a4SBartosz Golaszewski 
10008c7bd5a4SBartosz Golaszewski 	/* Request the interrupt */
10018c7bd5a4SBartosz Golaszewski 	ret = request_irq(ndev->irq, mtk_star_handle_irq,
10029ccbfdefSBiao Huang 			  IRQF_TRIGGER_NONE, ndev->name, ndev);
10038c7bd5a4SBartosz Golaszewski 	if (ret)
10048c7bd5a4SBartosz Golaszewski 		goto err_free_skbs;
10058c7bd5a4SBartosz Golaszewski 
10060a8bd81fSBiao Huang 	napi_enable(&priv->tx_napi);
10070a8bd81fSBiao Huang 	napi_enable(&priv->rx_napi);
10088c7bd5a4SBartosz Golaszewski 
10098c7bd5a4SBartosz Golaszewski 	mtk_star_intr_ack_all(priv);
10108c7bd5a4SBartosz Golaszewski 	mtk_star_intr_enable(priv);
10118c7bd5a4SBartosz Golaszewski 
10128c7bd5a4SBartosz Golaszewski 	/* Connect to and start PHY */
10138c7bd5a4SBartosz Golaszewski 	priv->phydev = of_phy_connect(ndev, priv->phy_node,
10148c7bd5a4SBartosz Golaszewski 				      mtk_star_adjust_link, 0, priv->phy_intf);
10158c7bd5a4SBartosz Golaszewski 	if (!priv->phydev) {
10168c7bd5a4SBartosz Golaszewski 		netdev_err(ndev, "failed to connect to PHY\n");
1017baee1991SZhang Changzhong 		ret = -ENODEV;
10188c7bd5a4SBartosz Golaszewski 		goto err_free_irq;
10198c7bd5a4SBartosz Golaszewski 	}
10208c7bd5a4SBartosz Golaszewski 
10218c7bd5a4SBartosz Golaszewski 	mtk_star_dma_start(priv);
10228c7bd5a4SBartosz Golaszewski 	phy_start(priv->phydev);
10238c7bd5a4SBartosz Golaszewski 	netif_start_queue(ndev);
10248c7bd5a4SBartosz Golaszewski 
10258c7bd5a4SBartosz Golaszewski 	return 0;
10268c7bd5a4SBartosz Golaszewski 
10278c7bd5a4SBartosz Golaszewski err_free_irq:
1028*b0c09c7fSZhengchao Shao 	napi_disable(&priv->rx_napi);
1029*b0c09c7fSZhengchao Shao 	napi_disable(&priv->tx_napi);
10308c7bd5a4SBartosz Golaszewski 	free_irq(ndev->irq, ndev);
10318c7bd5a4SBartosz Golaszewski err_free_skbs:
10328c7bd5a4SBartosz Golaszewski 	mtk_star_free_rx_skbs(priv);
10338c7bd5a4SBartosz Golaszewski err_out:
10348c7bd5a4SBartosz Golaszewski 	return ret;
10358c7bd5a4SBartosz Golaszewski }
10368c7bd5a4SBartosz Golaszewski 
mtk_star_disable(struct net_device * ndev)10378c7bd5a4SBartosz Golaszewski static void mtk_star_disable(struct net_device *ndev)
10388c7bd5a4SBartosz Golaszewski {
10398c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
10408c7bd5a4SBartosz Golaszewski 
10418c7bd5a4SBartosz Golaszewski 	netif_stop_queue(ndev);
10420a8bd81fSBiao Huang 	napi_disable(&priv->tx_napi);
10430a8bd81fSBiao Huang 	napi_disable(&priv->rx_napi);
10448c7bd5a4SBartosz Golaszewski 	mtk_star_intr_disable(priv);
10458c7bd5a4SBartosz Golaszewski 	mtk_star_dma_disable(priv);
10468c7bd5a4SBartosz Golaszewski 	mtk_star_intr_ack_all(priv);
10478c7bd5a4SBartosz Golaszewski 	phy_stop(priv->phydev);
10488c7bd5a4SBartosz Golaszewski 	phy_disconnect(priv->phydev);
10498c7bd5a4SBartosz Golaszewski 	free_irq(ndev->irq, ndev);
10508c7bd5a4SBartosz Golaszewski 	mtk_star_free_rx_skbs(priv);
10518c7bd5a4SBartosz Golaszewski 	mtk_star_free_tx_skbs(priv);
10528c7bd5a4SBartosz Golaszewski }
10538c7bd5a4SBartosz Golaszewski 
mtk_star_netdev_open(struct net_device * ndev)10548c7bd5a4SBartosz Golaszewski static int mtk_star_netdev_open(struct net_device *ndev)
10558c7bd5a4SBartosz Golaszewski {
10568c7bd5a4SBartosz Golaszewski 	return mtk_star_enable(ndev);
10578c7bd5a4SBartosz Golaszewski }
10588c7bd5a4SBartosz Golaszewski 
mtk_star_netdev_stop(struct net_device * ndev)10598c7bd5a4SBartosz Golaszewski static int mtk_star_netdev_stop(struct net_device *ndev)
10608c7bd5a4SBartosz Golaszewski {
10618c7bd5a4SBartosz Golaszewski 	mtk_star_disable(ndev);
10628c7bd5a4SBartosz Golaszewski 
10638c7bd5a4SBartosz Golaszewski 	return 0;
10648c7bd5a4SBartosz Golaszewski }
10658c7bd5a4SBartosz Golaszewski 
mtk_star_netdev_ioctl(struct net_device * ndev,struct ifreq * req,int cmd)10668c7bd5a4SBartosz Golaszewski static int mtk_star_netdev_ioctl(struct net_device *ndev,
10678c7bd5a4SBartosz Golaszewski 				 struct ifreq *req, int cmd)
10688c7bd5a4SBartosz Golaszewski {
10698c7bd5a4SBartosz Golaszewski 	if (!netif_running(ndev))
10708c7bd5a4SBartosz Golaszewski 		return -EINVAL;
10718c7bd5a4SBartosz Golaszewski 
10728c7bd5a4SBartosz Golaszewski 	return phy_mii_ioctl(ndev->phydev, req, cmd);
10738c7bd5a4SBartosz Golaszewski }
10748c7bd5a4SBartosz Golaszewski 
__mtk_star_maybe_stop_tx(struct mtk_star_priv * priv,u16 size)10750a8bd81fSBiao Huang static int __mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
10760a8bd81fSBiao Huang {
10770a8bd81fSBiao Huang 	netif_stop_queue(priv->ndev);
10780a8bd81fSBiao Huang 
10790a8bd81fSBiao Huang 	/* Might race with mtk_star_tx_poll, check again */
10800a8bd81fSBiao Huang 	smp_mb();
10810a8bd81fSBiao Huang 	if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) < size))
10820a8bd81fSBiao Huang 		return -EBUSY;
10830a8bd81fSBiao Huang 
10840a8bd81fSBiao Huang 	netif_start_queue(priv->ndev);
10850a8bd81fSBiao Huang 
10860a8bd81fSBiao Huang 	return 0;
10870a8bd81fSBiao Huang }
10880a8bd81fSBiao Huang 
mtk_star_maybe_stop_tx(struct mtk_star_priv * priv,u16 size)10890a8bd81fSBiao Huang static inline int mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
10900a8bd81fSBiao Huang {
10910a8bd81fSBiao Huang 	if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) >= size))
10920a8bd81fSBiao Huang 		return 0;
10930a8bd81fSBiao Huang 
10940a8bd81fSBiao Huang 	return __mtk_star_maybe_stop_tx(priv, size);
10950a8bd81fSBiao Huang }
10960a8bd81fSBiao Huang 
mtk_star_netdev_start_xmit(struct sk_buff * skb,struct net_device * ndev)10970a8bd81fSBiao Huang static netdev_tx_t mtk_star_netdev_start_xmit(struct sk_buff *skb,
10988c7bd5a4SBartosz Golaszewski 					      struct net_device *ndev)
10998c7bd5a4SBartosz Golaszewski {
11008c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
11018c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->tx_ring;
11028c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
11038c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc_data desc_data;
11040a8bd81fSBiao Huang 	int nfrags = skb_shinfo(skb)->nr_frags;
11050a8bd81fSBiao Huang 
11060a8bd81fSBiao Huang 	if (unlikely(mtk_star_tx_ring_avail(ring) < nfrags + 1)) {
11070a8bd81fSBiao Huang 		if (!netif_queue_stopped(ndev)) {
11080a8bd81fSBiao Huang 			netif_stop_queue(ndev);
11090a8bd81fSBiao Huang 			/* This is a hard error, log it. */
11100a8bd81fSBiao Huang 			pr_err_ratelimited("Tx ring full when queue awake\n");
11110a8bd81fSBiao Huang 		}
11120a8bd81fSBiao Huang 		return NETDEV_TX_BUSY;
11130a8bd81fSBiao Huang 	}
11148c7bd5a4SBartosz Golaszewski 
11158c7bd5a4SBartosz Golaszewski 	desc_data.dma_addr = mtk_star_dma_map_tx(priv, skb);
11168c7bd5a4SBartosz Golaszewski 	if (dma_mapping_error(dev, desc_data.dma_addr))
11178c7bd5a4SBartosz Golaszewski 		goto err_drop_packet;
11188c7bd5a4SBartosz Golaszewski 
11198c7bd5a4SBartosz Golaszewski 	desc_data.skb = skb;
11208c7bd5a4SBartosz Golaszewski 	desc_data.len = skb->len;
11218c7bd5a4SBartosz Golaszewski 	mtk_star_ring_push_head_tx(ring, &desc_data);
11228c7bd5a4SBartosz Golaszewski 
11238c7bd5a4SBartosz Golaszewski 	netdev_sent_queue(ndev, skb->len);
11248c7bd5a4SBartosz Golaszewski 
11250a8bd81fSBiao Huang 	mtk_star_maybe_stop_tx(priv, MTK_STAR_DESC_NEEDED);
11268c7bd5a4SBartosz Golaszewski 
11278c7bd5a4SBartosz Golaszewski 	mtk_star_dma_resume_tx(priv);
11288c7bd5a4SBartosz Golaszewski 
11298c7bd5a4SBartosz Golaszewski 	return NETDEV_TX_OK;
11308c7bd5a4SBartosz Golaszewski 
11318c7bd5a4SBartosz Golaszewski err_drop_packet:
11328c7bd5a4SBartosz Golaszewski 	dev_kfree_skb(skb);
11338c7bd5a4SBartosz Golaszewski 	ndev->stats.tx_dropped++;
1134e8aa6d52SVincent Stehlé 	return NETDEV_TX_OK;
11358c7bd5a4SBartosz Golaszewski }
11368c7bd5a4SBartosz Golaszewski 
11378c7bd5a4SBartosz Golaszewski /* Returns the number of bytes sent or a negative number on the first
11388c7bd5a4SBartosz Golaszewski  * descriptor owned by DMA.
11398c7bd5a4SBartosz Golaszewski  */
mtk_star_tx_complete_one(struct mtk_star_priv * priv)11408c7bd5a4SBartosz Golaszewski static int mtk_star_tx_complete_one(struct mtk_star_priv *priv)
11418c7bd5a4SBartosz Golaszewski {
11428c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->tx_ring;
11438c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc_data desc_data;
11448c7bd5a4SBartosz Golaszewski 	int ret;
11458c7bd5a4SBartosz Golaszewski 
11468c7bd5a4SBartosz Golaszewski 	ret = mtk_star_ring_pop_tail(ring, &desc_data);
11478c7bd5a4SBartosz Golaszewski 	if (ret)
11488c7bd5a4SBartosz Golaszewski 		return ret;
11498c7bd5a4SBartosz Golaszewski 
11508c7bd5a4SBartosz Golaszewski 	mtk_star_dma_unmap_tx(priv, &desc_data);
11518c7bd5a4SBartosz Golaszewski 	ret = desc_data.skb->len;
11528c7bd5a4SBartosz Golaszewski 	dev_kfree_skb_irq(desc_data.skb);
11538c7bd5a4SBartosz Golaszewski 
11548c7bd5a4SBartosz Golaszewski 	return ret;
11558c7bd5a4SBartosz Golaszewski }
11568c7bd5a4SBartosz Golaszewski 
mtk_star_tx_poll(struct napi_struct * napi,int budget)11570a8bd81fSBiao Huang static int mtk_star_tx_poll(struct napi_struct *napi, int budget)
11588c7bd5a4SBartosz Golaszewski {
11590a8bd81fSBiao Huang 	struct mtk_star_priv *priv = container_of(napi, struct mtk_star_priv,
11600a8bd81fSBiao Huang 						  tx_napi);
11610a8bd81fSBiao Huang 	int ret = 0, pkts_compl = 0, bytes_compl = 0, count = 0;
11628c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->tx_ring;
11638c7bd5a4SBartosz Golaszewski 	struct net_device *ndev = priv->ndev;
11640a8bd81fSBiao Huang 	unsigned int head = ring->head;
11650a8bd81fSBiao Huang 	unsigned int entry = ring->tail;
11668c7bd5a4SBartosz Golaszewski 
11670a8bd81fSBiao Huang 	while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) {
11688c7bd5a4SBartosz Golaszewski 		ret = mtk_star_tx_complete_one(priv);
11698c7bd5a4SBartosz Golaszewski 		if (ret < 0)
11708c7bd5a4SBartosz Golaszewski 			break;
11710a8bd81fSBiao Huang 
11720a8bd81fSBiao Huang 		count++;
11730a8bd81fSBiao Huang 		pkts_compl++;
11740a8bd81fSBiao Huang 		bytes_compl += ret;
11750a8bd81fSBiao Huang 		entry = ring->tail;
11768c7bd5a4SBartosz Golaszewski 	}
11778c7bd5a4SBartosz Golaszewski 
11788c7bd5a4SBartosz Golaszewski 	netdev_completed_queue(ndev, pkts_compl, bytes_compl);
11798c7bd5a4SBartosz Golaszewski 
11800a8bd81fSBiao Huang 	if (unlikely(netif_queue_stopped(ndev)) &&
11810a8bd81fSBiao Huang 	    (mtk_star_tx_ring_avail(ring) > MTK_STAR_TX_THRESH))
11828c7bd5a4SBartosz Golaszewski 		netif_wake_queue(ndev);
11838c7bd5a4SBartosz Golaszewski 
11840a8bd81fSBiao Huang 	if (napi_complete(napi)) {
11850a8bd81fSBiao Huang 		spin_lock(&priv->lock);
11860a8bd81fSBiao Huang 		mtk_star_enable_dma_irq(priv, false, true);
11878c7bd5a4SBartosz Golaszewski 		spin_unlock(&priv->lock);
11888c7bd5a4SBartosz Golaszewski 	}
11898c7bd5a4SBartosz Golaszewski 
11900a8bd81fSBiao Huang 	return 0;
11910a8bd81fSBiao Huang }
11920a8bd81fSBiao Huang 
mtk_star_netdev_get_stats64(struct net_device * ndev,struct rtnl_link_stats64 * stats)11938c7bd5a4SBartosz Golaszewski static void mtk_star_netdev_get_stats64(struct net_device *ndev,
11948c7bd5a4SBartosz Golaszewski 					struct rtnl_link_stats64 *stats)
11958c7bd5a4SBartosz Golaszewski {
11968c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
11978c7bd5a4SBartosz Golaszewski 
11988c7bd5a4SBartosz Golaszewski 	mtk_star_update_stats(priv);
11998c7bd5a4SBartosz Golaszewski 
12008c7bd5a4SBartosz Golaszewski 	memcpy(stats, &priv->stats, sizeof(*stats));
12018c7bd5a4SBartosz Golaszewski }
12028c7bd5a4SBartosz Golaszewski 
mtk_star_set_rx_mode(struct net_device * ndev)12038c7bd5a4SBartosz Golaszewski static void mtk_star_set_rx_mode(struct net_device *ndev)
12048c7bd5a4SBartosz Golaszewski {
12058c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
12068c7bd5a4SBartosz Golaszewski 	struct netdev_hw_addr *hw_addr;
12078c7bd5a4SBartosz Golaszewski 	unsigned int hash_addr, i;
12088c7bd5a4SBartosz Golaszewski 	int ret;
12098c7bd5a4SBartosz Golaszewski 
12108c7bd5a4SBartosz Golaszewski 	if (ndev->flags & IFF_PROMISC) {
1211240f1ae4SBartosz Golaszewski 		regmap_set_bits(priv->regs, MTK_STAR_REG_ARL_CFG,
12128c7bd5a4SBartosz Golaszewski 				MTK_STAR_BIT_ARL_CFG_MISC_MODE);
12138c7bd5a4SBartosz Golaszewski 	} else if (netdev_mc_count(ndev) > MTK_STAR_HASHTABLE_MC_LIMIT ||
12148c7bd5a4SBartosz Golaszewski 		   ndev->flags & IFF_ALLMULTI) {
12158c7bd5a4SBartosz Golaszewski 		for (i = 0; i < MTK_STAR_HASHTABLE_SIZE_MAX; i++) {
12168c7bd5a4SBartosz Golaszewski 			ret = mtk_star_set_hashbit(priv, i);
12178c7bd5a4SBartosz Golaszewski 			if (ret)
12188c7bd5a4SBartosz Golaszewski 				goto hash_fail;
12198c7bd5a4SBartosz Golaszewski 		}
12208c7bd5a4SBartosz Golaszewski 	} else {
12218c7bd5a4SBartosz Golaszewski 		/* Clear previous settings. */
12228c7bd5a4SBartosz Golaszewski 		ret = mtk_star_reset_hash_table(priv);
12238c7bd5a4SBartosz Golaszewski 		if (ret)
12248c7bd5a4SBartosz Golaszewski 			goto hash_fail;
12258c7bd5a4SBartosz Golaszewski 
12268c7bd5a4SBartosz Golaszewski 		netdev_for_each_mc_addr(hw_addr, ndev) {
12278c7bd5a4SBartosz Golaszewski 			hash_addr = (hw_addr->addr[0] & 0x01) << 8;
12288c7bd5a4SBartosz Golaszewski 			hash_addr += hw_addr->addr[5];
12298c7bd5a4SBartosz Golaszewski 			ret = mtk_star_set_hashbit(priv, hash_addr);
12308c7bd5a4SBartosz Golaszewski 			if (ret)
12318c7bd5a4SBartosz Golaszewski 				goto hash_fail;
12328c7bd5a4SBartosz Golaszewski 		}
12338c7bd5a4SBartosz Golaszewski 	}
12348c7bd5a4SBartosz Golaszewski 
12358c7bd5a4SBartosz Golaszewski 	return;
12368c7bd5a4SBartosz Golaszewski 
12378c7bd5a4SBartosz Golaszewski hash_fail:
12388c7bd5a4SBartosz Golaszewski 	if (ret == -ETIMEDOUT)
12398c7bd5a4SBartosz Golaszewski 		netdev_err(ndev, "setting hash bit timed out\n");
12408c7bd5a4SBartosz Golaszewski 	else
12418c7bd5a4SBartosz Golaszewski 		/* Should be -EIO */
12428c7bd5a4SBartosz Golaszewski 		netdev_err(ndev, "unable to set hash bit");
12438c7bd5a4SBartosz Golaszewski }
12448c7bd5a4SBartosz Golaszewski 
12458c7bd5a4SBartosz Golaszewski static const struct net_device_ops mtk_star_netdev_ops = {
12468c7bd5a4SBartosz Golaszewski 	.ndo_open		= mtk_star_netdev_open,
12478c7bd5a4SBartosz Golaszewski 	.ndo_stop		= mtk_star_netdev_stop,
12488c7bd5a4SBartosz Golaszewski 	.ndo_start_xmit		= mtk_star_netdev_start_xmit,
12498c7bd5a4SBartosz Golaszewski 	.ndo_get_stats64	= mtk_star_netdev_get_stats64,
12508c7bd5a4SBartosz Golaszewski 	.ndo_set_rx_mode	= mtk_star_set_rx_mode,
1251a7605370SArnd Bergmann 	.ndo_eth_ioctl		= mtk_star_netdev_ioctl,
12528c7bd5a4SBartosz Golaszewski 	.ndo_set_mac_address	= eth_mac_addr,
12538c7bd5a4SBartosz Golaszewski 	.ndo_validate_addr	= eth_validate_addr,
12548c7bd5a4SBartosz Golaszewski };
12558c7bd5a4SBartosz Golaszewski 
mtk_star_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)12568c7bd5a4SBartosz Golaszewski static void mtk_star_get_drvinfo(struct net_device *dev,
12578c7bd5a4SBartosz Golaszewski 				 struct ethtool_drvinfo *info)
12588c7bd5a4SBartosz Golaszewski {
1259f029c781SWolfram Sang 	strscpy(info->driver, MTK_STAR_DRVNAME, sizeof(info->driver));
12608c7bd5a4SBartosz Golaszewski }
12618c7bd5a4SBartosz Golaszewski 
12628c7bd5a4SBartosz Golaszewski /* TODO Add ethtool stats. */
12638c7bd5a4SBartosz Golaszewski static const struct ethtool_ops mtk_star_ethtool_ops = {
12648c7bd5a4SBartosz Golaszewski 	.get_drvinfo		= mtk_star_get_drvinfo,
12658c7bd5a4SBartosz Golaszewski 	.get_link		= ethtool_op_get_link,
12668c7bd5a4SBartosz Golaszewski 	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
12678c7bd5a4SBartosz Golaszewski 	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
12688c7bd5a4SBartosz Golaszewski };
12698c7bd5a4SBartosz Golaszewski 
mtk_star_rx(struct mtk_star_priv * priv,int budget)12700a8bd81fSBiao Huang static int mtk_star_rx(struct mtk_star_priv *priv, int budget)
12718c7bd5a4SBartosz Golaszewski {
12728c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring *ring = &priv->rx_ring;
12738c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
12748c7bd5a4SBartosz Golaszewski 	struct mtk_star_ring_desc_data desc_data;
12758c7bd5a4SBartosz Golaszewski 	struct net_device *ndev = priv->ndev;
12768c7bd5a4SBartosz Golaszewski 	struct sk_buff *curr_skb, *new_skb;
12778c7bd5a4SBartosz Golaszewski 	dma_addr_t new_dma_addr;
12780a8bd81fSBiao Huang 	int ret, count = 0;
12798c7bd5a4SBartosz Golaszewski 
12800a8bd81fSBiao Huang 	while (count < budget) {
12818c7bd5a4SBartosz Golaszewski 		ret = mtk_star_ring_pop_tail(ring, &desc_data);
12828c7bd5a4SBartosz Golaszewski 		if (ret)
12838c7bd5a4SBartosz Golaszewski 			return -1;
12848c7bd5a4SBartosz Golaszewski 
12858c7bd5a4SBartosz Golaszewski 		curr_skb = desc_data.skb;
12868c7bd5a4SBartosz Golaszewski 
12878c7bd5a4SBartosz Golaszewski 		if ((desc_data.flags & MTK_STAR_DESC_BIT_RX_CRCE) ||
12888c7bd5a4SBartosz Golaszewski 		    (desc_data.flags & MTK_STAR_DESC_BIT_RX_OSIZE)) {
12898c7bd5a4SBartosz Golaszewski 			/* Error packet -> drop and reuse skb. */
12908c7bd5a4SBartosz Golaszewski 			new_skb = curr_skb;
12918c7bd5a4SBartosz Golaszewski 			goto push_new_skb;
12928c7bd5a4SBartosz Golaszewski 		}
12938c7bd5a4SBartosz Golaszewski 
12940a8bd81fSBiao Huang 		/* Prepare new skb before receiving the current one.
12950a8bd81fSBiao Huang 		 * Reuse the current skb if we fail at any point.
12968c7bd5a4SBartosz Golaszewski 		 */
12978c7bd5a4SBartosz Golaszewski 		new_skb = mtk_star_alloc_skb(ndev);
12988c7bd5a4SBartosz Golaszewski 		if (!new_skb) {
12998c7bd5a4SBartosz Golaszewski 			ndev->stats.rx_dropped++;
13008c7bd5a4SBartosz Golaszewski 			new_skb = curr_skb;
13018c7bd5a4SBartosz Golaszewski 			goto push_new_skb;
13028c7bd5a4SBartosz Golaszewski 		}
13038c7bd5a4SBartosz Golaszewski 
13048c7bd5a4SBartosz Golaszewski 		new_dma_addr = mtk_star_dma_map_rx(priv, new_skb);
13058c7bd5a4SBartosz Golaszewski 		if (dma_mapping_error(dev, new_dma_addr)) {
13068c7bd5a4SBartosz Golaszewski 			ndev->stats.rx_dropped++;
13078c7bd5a4SBartosz Golaszewski 			dev_kfree_skb(new_skb);
13088c7bd5a4SBartosz Golaszewski 			new_skb = curr_skb;
13098c7bd5a4SBartosz Golaszewski 			netdev_err(ndev, "DMA mapping error of RX descriptor\n");
13108c7bd5a4SBartosz Golaszewski 			goto push_new_skb;
13118c7bd5a4SBartosz Golaszewski 		}
13128c7bd5a4SBartosz Golaszewski 
13130a8bd81fSBiao Huang 		/* We can't fail anymore at this point:
13140a8bd81fSBiao Huang 		 * it's safe to unmap the skb.
13150a8bd81fSBiao Huang 		 */
13168c7bd5a4SBartosz Golaszewski 		mtk_star_dma_unmap_rx(priv, &desc_data);
13178c7bd5a4SBartosz Golaszewski 
13188c7bd5a4SBartosz Golaszewski 		skb_put(desc_data.skb, desc_data.len);
13198c7bd5a4SBartosz Golaszewski 		desc_data.skb->ip_summed = CHECKSUM_NONE;
13208c7bd5a4SBartosz Golaszewski 		desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
13218c7bd5a4SBartosz Golaszewski 		desc_data.skb->dev = ndev;
13228c7bd5a4SBartosz Golaszewski 		netif_receive_skb(desc_data.skb);
13238c7bd5a4SBartosz Golaszewski 
132495b39f07SBiao Huang 		/* update dma_addr for new skb */
132595b39f07SBiao Huang 		desc_data.dma_addr = new_dma_addr;
132695b39f07SBiao Huang 
13278c7bd5a4SBartosz Golaszewski push_new_skb:
13280a8bd81fSBiao Huang 
13290a8bd81fSBiao Huang 		count++;
13300a8bd81fSBiao Huang 
13318c7bd5a4SBartosz Golaszewski 		desc_data.len = skb_tailroom(new_skb);
13328c7bd5a4SBartosz Golaszewski 		desc_data.skb = new_skb;
13338c7bd5a4SBartosz Golaszewski 		mtk_star_ring_push_head_rx(ring, &desc_data);
13348c7bd5a4SBartosz Golaszewski 	}
13358c7bd5a4SBartosz Golaszewski 
13368c7bd5a4SBartosz Golaszewski 	mtk_star_dma_resume_rx(priv);
13378c7bd5a4SBartosz Golaszewski 
13380a8bd81fSBiao Huang 	return count;
13398c7bd5a4SBartosz Golaszewski }
13408c7bd5a4SBartosz Golaszewski 
mtk_star_rx_poll(struct napi_struct * napi,int budget)13410a8bd81fSBiao Huang static int mtk_star_rx_poll(struct napi_struct *napi, int budget)
13428c7bd5a4SBartosz Golaszewski {
13438c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv;
13440a8bd81fSBiao Huang 	int work_done = 0;
13458c7bd5a4SBartosz Golaszewski 
13460a8bd81fSBiao Huang 	priv = container_of(napi, struct mtk_star_priv, rx_napi);
13478c7bd5a4SBartosz Golaszewski 
13480a8bd81fSBiao Huang 	work_done = mtk_star_rx(priv, budget);
13490a8bd81fSBiao Huang 	if (work_done < budget) {
13500a8bd81fSBiao Huang 		napi_complete_done(napi, work_done);
13510a8bd81fSBiao Huang 		spin_lock(&priv->lock);
13520a8bd81fSBiao Huang 		mtk_star_enable_dma_irq(priv, true, false);
13530a8bd81fSBiao Huang 		spin_unlock(&priv->lock);
13548c7bd5a4SBartosz Golaszewski 	}
13558c7bd5a4SBartosz Golaszewski 
13560a8bd81fSBiao Huang 	return work_done;
13578c7bd5a4SBartosz Golaszewski }
13588c7bd5a4SBartosz Golaszewski 
mtk_star_mdio_rwok_clear(struct mtk_star_priv * priv)13598c7bd5a4SBartosz Golaszewski static void mtk_star_mdio_rwok_clear(struct mtk_star_priv *priv)
13608c7bd5a4SBartosz Golaszewski {
13618c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL0,
13628c7bd5a4SBartosz Golaszewski 		     MTK_STAR_BIT_PHY_CTRL0_RWOK);
13638c7bd5a4SBartosz Golaszewski }
13648c7bd5a4SBartosz Golaszewski 
mtk_star_mdio_rwok_wait(struct mtk_star_priv * priv)13658c7bd5a4SBartosz Golaszewski static int mtk_star_mdio_rwok_wait(struct mtk_star_priv *priv)
13668c7bd5a4SBartosz Golaszewski {
13678c7bd5a4SBartosz Golaszewski 	unsigned int val;
13688c7bd5a4SBartosz Golaszewski 
13698c7bd5a4SBartosz Golaszewski 	return regmap_read_poll_timeout(priv->regs, MTK_STAR_REG_PHY_CTRL0,
13708c7bd5a4SBartosz Golaszewski 					val, val & MTK_STAR_BIT_PHY_CTRL0_RWOK,
13718c7bd5a4SBartosz Golaszewski 					10, MTK_STAR_WAIT_TIMEOUT);
13728c7bd5a4SBartosz Golaszewski }
13738c7bd5a4SBartosz Golaszewski 
mtk_star_mdio_read(struct mii_bus * mii,int phy_id,int regnum)13748c7bd5a4SBartosz Golaszewski static int mtk_star_mdio_read(struct mii_bus *mii, int phy_id, int regnum)
13758c7bd5a4SBartosz Golaszewski {
13768c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = mii->priv;
13778c7bd5a4SBartosz Golaszewski 	unsigned int val, data;
13788c7bd5a4SBartosz Golaszewski 	int ret;
13798c7bd5a4SBartosz Golaszewski 
13808c7bd5a4SBartosz Golaszewski 	mtk_star_mdio_rwok_clear(priv);
13818c7bd5a4SBartosz Golaszewski 
13828c7bd5a4SBartosz Golaszewski 	val = (regnum << MTK_STAR_OFF_PHY_CTRL0_PREG);
13838c7bd5a4SBartosz Golaszewski 	val &= MTK_STAR_MSK_PHY_CTRL0_PREG;
13848c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_PHY_CTRL0_RDCMD;
13858c7bd5a4SBartosz Golaszewski 
13868c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL0, val);
13878c7bd5a4SBartosz Golaszewski 
13888c7bd5a4SBartosz Golaszewski 	ret = mtk_star_mdio_rwok_wait(priv);
13898c7bd5a4SBartosz Golaszewski 	if (ret)
13908c7bd5a4SBartosz Golaszewski 		return ret;
13918c7bd5a4SBartosz Golaszewski 
13928c7bd5a4SBartosz Golaszewski 	regmap_read(priv->regs, MTK_STAR_REG_PHY_CTRL0, &data);
13938c7bd5a4SBartosz Golaszewski 
13948c7bd5a4SBartosz Golaszewski 	data &= MTK_STAR_MSK_PHY_CTRL0_RWDATA;
13958c7bd5a4SBartosz Golaszewski 	data >>= MTK_STAR_OFF_PHY_CTRL0_RWDATA;
13968c7bd5a4SBartosz Golaszewski 
13978c7bd5a4SBartosz Golaszewski 	return data;
13988c7bd5a4SBartosz Golaszewski }
13998c7bd5a4SBartosz Golaszewski 
mtk_star_mdio_write(struct mii_bus * mii,int phy_id,int regnum,u16 data)14008c7bd5a4SBartosz Golaszewski static int mtk_star_mdio_write(struct mii_bus *mii, int phy_id,
14018c7bd5a4SBartosz Golaszewski 			       int regnum, u16 data)
14028c7bd5a4SBartosz Golaszewski {
14038c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = mii->priv;
14048c7bd5a4SBartosz Golaszewski 	unsigned int val;
14058c7bd5a4SBartosz Golaszewski 
14068c7bd5a4SBartosz Golaszewski 	mtk_star_mdio_rwok_clear(priv);
14078c7bd5a4SBartosz Golaszewski 
14088c7bd5a4SBartosz Golaszewski 	val = data;
14098c7bd5a4SBartosz Golaszewski 	val <<= MTK_STAR_OFF_PHY_CTRL0_RWDATA;
14108c7bd5a4SBartosz Golaszewski 	val &= MTK_STAR_MSK_PHY_CTRL0_RWDATA;
14118c7bd5a4SBartosz Golaszewski 	regnum <<= MTK_STAR_OFF_PHY_CTRL0_PREG;
14128c7bd5a4SBartosz Golaszewski 	regnum &= MTK_STAR_MSK_PHY_CTRL0_PREG;
14138c7bd5a4SBartosz Golaszewski 	val |= regnum;
14148c7bd5a4SBartosz Golaszewski 	val |= MTK_STAR_BIT_PHY_CTRL0_WTCMD;
14158c7bd5a4SBartosz Golaszewski 
14168c7bd5a4SBartosz Golaszewski 	regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL0, val);
14178c7bd5a4SBartosz Golaszewski 
14188c7bd5a4SBartosz Golaszewski 	return mtk_star_mdio_rwok_wait(priv);
14198c7bd5a4SBartosz Golaszewski }
14208c7bd5a4SBartosz Golaszewski 
mtk_star_mdio_init(struct net_device * ndev)14218c7bd5a4SBartosz Golaszewski static int mtk_star_mdio_init(struct net_device *ndev)
14228c7bd5a4SBartosz Golaszewski {
14238c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = netdev_priv(ndev);
14248c7bd5a4SBartosz Golaszewski 	struct device *dev = mtk_star_get_dev(priv);
14258c7bd5a4SBartosz Golaszewski 	struct device_node *of_node, *mdio_node;
14268c7bd5a4SBartosz Golaszewski 	int ret;
14278c7bd5a4SBartosz Golaszewski 
14288c7bd5a4SBartosz Golaszewski 	of_node = dev->of_node;
14298c7bd5a4SBartosz Golaszewski 
14308c7bd5a4SBartosz Golaszewski 	mdio_node = of_get_child_by_name(of_node, "mdio");
14318c7bd5a4SBartosz Golaszewski 	if (!mdio_node)
14328c7bd5a4SBartosz Golaszewski 		return -ENODEV;
14338c7bd5a4SBartosz Golaszewski 
14348c7bd5a4SBartosz Golaszewski 	if (!of_device_is_available(mdio_node)) {
14358c7bd5a4SBartosz Golaszewski 		ret = -ENODEV;
14368c7bd5a4SBartosz Golaszewski 		goto out_put_node;
14378c7bd5a4SBartosz Golaszewski 	}
14388c7bd5a4SBartosz Golaszewski 
14398c7bd5a4SBartosz Golaszewski 	priv->mii = devm_mdiobus_alloc(dev);
14408c7bd5a4SBartosz Golaszewski 	if (!priv->mii) {
14418c7bd5a4SBartosz Golaszewski 		ret = -ENOMEM;
14428c7bd5a4SBartosz Golaszewski 		goto out_put_node;
14438c7bd5a4SBartosz Golaszewski 	}
14448c7bd5a4SBartosz Golaszewski 
14458c7bd5a4SBartosz Golaszewski 	snprintf(priv->mii->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
14468c7bd5a4SBartosz Golaszewski 	priv->mii->name = "mtk-mac-mdio";
14478c7bd5a4SBartosz Golaszewski 	priv->mii->parent = dev;
14488c7bd5a4SBartosz Golaszewski 	priv->mii->read = mtk_star_mdio_read;
14498c7bd5a4SBartosz Golaszewski 	priv->mii->write = mtk_star_mdio_write;
14508c7bd5a4SBartosz Golaszewski 	priv->mii->priv = priv;
14518c7bd5a4SBartosz Golaszewski 
14529ed0a3faSBartosz Golaszewski 	ret = devm_of_mdiobus_register(dev, priv->mii, mdio_node);
14538c7bd5a4SBartosz Golaszewski 
14548c7bd5a4SBartosz Golaszewski out_put_node:
14558c7bd5a4SBartosz Golaszewski 	of_node_put(mdio_node);
14568c7bd5a4SBartosz Golaszewski 	return ret;
14578c7bd5a4SBartosz Golaszewski }
14588c7bd5a4SBartosz Golaszewski 
mtk_star_suspend(struct device * dev)1459f99c0646SArnd Bergmann static __maybe_unused int mtk_star_suspend(struct device *dev)
14608c7bd5a4SBartosz Golaszewski {
14618c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv;
14628c7bd5a4SBartosz Golaszewski 	struct net_device *ndev;
14638c7bd5a4SBartosz Golaszewski 
14648c7bd5a4SBartosz Golaszewski 	ndev = dev_get_drvdata(dev);
14658c7bd5a4SBartosz Golaszewski 	priv = netdev_priv(ndev);
14668c7bd5a4SBartosz Golaszewski 
14678c7bd5a4SBartosz Golaszewski 	if (netif_running(ndev))
14688c7bd5a4SBartosz Golaszewski 		mtk_star_disable(ndev);
14698c7bd5a4SBartosz Golaszewski 
14708c7bd5a4SBartosz Golaszewski 	clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
14718c7bd5a4SBartosz Golaszewski 
14728c7bd5a4SBartosz Golaszewski 	return 0;
14738c7bd5a4SBartosz Golaszewski }
14748c7bd5a4SBartosz Golaszewski 
mtk_star_resume(struct device * dev)1475f99c0646SArnd Bergmann static __maybe_unused int mtk_star_resume(struct device *dev)
14768c7bd5a4SBartosz Golaszewski {
14778c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv;
14788c7bd5a4SBartosz Golaszewski 	struct net_device *ndev;
14798c7bd5a4SBartosz Golaszewski 	int ret;
14808c7bd5a4SBartosz Golaszewski 
14818c7bd5a4SBartosz Golaszewski 	ndev = dev_get_drvdata(dev);
14828c7bd5a4SBartosz Golaszewski 	priv = netdev_priv(ndev);
14838c7bd5a4SBartosz Golaszewski 
14848c7bd5a4SBartosz Golaszewski 	ret = clk_bulk_prepare_enable(MTK_STAR_NCLKS, priv->clks);
14858c7bd5a4SBartosz Golaszewski 	if (ret)
14868c7bd5a4SBartosz Golaszewski 		return ret;
14878c7bd5a4SBartosz Golaszewski 
14888c7bd5a4SBartosz Golaszewski 	if (netif_running(ndev)) {
14898c7bd5a4SBartosz Golaszewski 		ret = mtk_star_enable(ndev);
14908c7bd5a4SBartosz Golaszewski 		if (ret)
14918c7bd5a4SBartosz Golaszewski 			clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
14928c7bd5a4SBartosz Golaszewski 	}
14938c7bd5a4SBartosz Golaszewski 
14948c7bd5a4SBartosz Golaszewski 	return ret;
14958c7bd5a4SBartosz Golaszewski }
14968c7bd5a4SBartosz Golaszewski 
mtk_star_clk_disable_unprepare(void * data)14978c7bd5a4SBartosz Golaszewski static void mtk_star_clk_disable_unprepare(void *data)
14988c7bd5a4SBartosz Golaszewski {
14998c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv = data;
15008c7bd5a4SBartosz Golaszewski 
15018c7bd5a4SBartosz Golaszewski 	clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
15028c7bd5a4SBartosz Golaszewski }
15038c7bd5a4SBartosz Golaszewski 
mtk_star_set_timing(struct mtk_star_priv * priv)1504769c197bSBiao Huang static int mtk_star_set_timing(struct mtk_star_priv *priv)
1505769c197bSBiao Huang {
1506769c197bSBiao Huang 	struct device *dev = mtk_star_get_dev(priv);
1507769c197bSBiao Huang 	unsigned int delay_val = 0;
1508769c197bSBiao Huang 
1509769c197bSBiao Huang 	switch (priv->phy_intf) {
15100027340aSBiao Huang 	case PHY_INTERFACE_MODE_MII:
1511769c197bSBiao Huang 	case PHY_INTERFACE_MODE_RMII:
1512769c197bSBiao Huang 		delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_RX_CLK, priv->rx_inv);
1513769c197bSBiao Huang 		delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_TX_CLK, priv->tx_inv);
1514769c197bSBiao Huang 		break;
1515769c197bSBiao Huang 	default:
1516769c197bSBiao Huang 		dev_err(dev, "This interface not supported\n");
1517769c197bSBiao Huang 		return -EINVAL;
1518769c197bSBiao Huang 	}
1519769c197bSBiao Huang 
1520769c197bSBiao Huang 	return regmap_write(priv->regs, MTK_STAR_REG_TEST0, delay_val);
1521769c197bSBiao Huang }
1522769c197bSBiao Huang 
mtk_star_probe(struct platform_device * pdev)15238c7bd5a4SBartosz Golaszewski static int mtk_star_probe(struct platform_device *pdev)
15248c7bd5a4SBartosz Golaszewski {
15258c7bd5a4SBartosz Golaszewski 	struct device_node *of_node;
15268c7bd5a4SBartosz Golaszewski 	struct mtk_star_priv *priv;
15278c7bd5a4SBartosz Golaszewski 	struct net_device *ndev;
15288c7bd5a4SBartosz Golaszewski 	struct device *dev;
15298c7bd5a4SBartosz Golaszewski 	void __iomem *base;
15308c7bd5a4SBartosz Golaszewski 	int ret, i;
15318c7bd5a4SBartosz Golaszewski 
15328c7bd5a4SBartosz Golaszewski 	dev = &pdev->dev;
15338c7bd5a4SBartosz Golaszewski 	of_node = dev->of_node;
15348c7bd5a4SBartosz Golaszewski 
15358c7bd5a4SBartosz Golaszewski 	ndev = devm_alloc_etherdev(dev, sizeof(*priv));
15368c7bd5a4SBartosz Golaszewski 	if (!ndev)
15378c7bd5a4SBartosz Golaszewski 		return -ENOMEM;
15388c7bd5a4SBartosz Golaszewski 
15398c7bd5a4SBartosz Golaszewski 	priv = netdev_priv(ndev);
15408c7bd5a4SBartosz Golaszewski 	priv->ndev = ndev;
1541c16cc6a0SBiao Huang 	priv->compat_data = of_device_get_match_data(&pdev->dev);
15428c7bd5a4SBartosz Golaszewski 	SET_NETDEV_DEV(ndev, dev);
15438c7bd5a4SBartosz Golaszewski 	platform_set_drvdata(pdev, ndev);
15448c7bd5a4SBartosz Golaszewski 
15458c7bd5a4SBartosz Golaszewski 	ndev->min_mtu = ETH_ZLEN;
15468c7bd5a4SBartosz Golaszewski 	ndev->max_mtu = MTK_STAR_MAX_FRAME_SIZE;
15478c7bd5a4SBartosz Golaszewski 
15488c7bd5a4SBartosz Golaszewski 	spin_lock_init(&priv->lock);
15498c7bd5a4SBartosz Golaszewski 
15508c7bd5a4SBartosz Golaszewski 	base = devm_platform_ioremap_resource(pdev, 0);
15518c7bd5a4SBartosz Golaszewski 	if (IS_ERR(base))
15528c7bd5a4SBartosz Golaszewski 		return PTR_ERR(base);
15538c7bd5a4SBartosz Golaszewski 
15548c7bd5a4SBartosz Golaszewski 	/* We won't be checking the return values of regmap read & write
15558c7bd5a4SBartosz Golaszewski 	 * functions. They can only fail for mmio if there's a clock attached
15568c7bd5a4SBartosz Golaszewski 	 * to regmap which is not the case here.
15578c7bd5a4SBartosz Golaszewski 	 */
15588c7bd5a4SBartosz Golaszewski 	priv->regs = devm_regmap_init_mmio(dev, base,
15598c7bd5a4SBartosz Golaszewski 					   &mtk_star_regmap_config);
15608c7bd5a4SBartosz Golaszewski 	if (IS_ERR(priv->regs))
15618c7bd5a4SBartosz Golaszewski 		return PTR_ERR(priv->regs);
15628c7bd5a4SBartosz Golaszewski 
15638c7bd5a4SBartosz Golaszewski 	priv->pericfg = syscon_regmap_lookup_by_phandle(of_node,
15648c7bd5a4SBartosz Golaszewski 							"mediatek,pericfg");
15658c7bd5a4SBartosz Golaszewski 	if (IS_ERR(priv->pericfg)) {
15668c7bd5a4SBartosz Golaszewski 		dev_err(dev, "Failed to lookup the PERICFG syscon\n");
15678c7bd5a4SBartosz Golaszewski 		return PTR_ERR(priv->pericfg);
15688c7bd5a4SBartosz Golaszewski 	}
15698c7bd5a4SBartosz Golaszewski 
15708c7bd5a4SBartosz Golaszewski 	ndev->irq = platform_get_irq(pdev, 0);
15718c7bd5a4SBartosz Golaszewski 	if (ndev->irq < 0)
15728c7bd5a4SBartosz Golaszewski 		return ndev->irq;
15738c7bd5a4SBartosz Golaszewski 
15748c7bd5a4SBartosz Golaszewski 	for (i = 0; i < MTK_STAR_NCLKS; i++)
15758c7bd5a4SBartosz Golaszewski 		priv->clks[i].id = mtk_star_clk_names[i];
15768c7bd5a4SBartosz Golaszewski 	ret = devm_clk_bulk_get(dev, MTK_STAR_NCLKS, priv->clks);
15778c7bd5a4SBartosz Golaszewski 	if (ret)
15788c7bd5a4SBartosz Golaszewski 		return ret;
15798c7bd5a4SBartosz Golaszewski 
15808c7bd5a4SBartosz Golaszewski 	ret = clk_bulk_prepare_enable(MTK_STAR_NCLKS, priv->clks);
15818c7bd5a4SBartosz Golaszewski 	if (ret)
15828c7bd5a4SBartosz Golaszewski 		return ret;
15838c7bd5a4SBartosz Golaszewski 
15848c7bd5a4SBartosz Golaszewski 	ret = devm_add_action_or_reset(dev,
15858c7bd5a4SBartosz Golaszewski 				       mtk_star_clk_disable_unprepare, priv);
15868c7bd5a4SBartosz Golaszewski 	if (ret)
15878c7bd5a4SBartosz Golaszewski 		return ret;
15888c7bd5a4SBartosz Golaszewski 
15898c7bd5a4SBartosz Golaszewski 	ret = of_get_phy_mode(of_node, &priv->phy_intf);
15908c7bd5a4SBartosz Golaszewski 	if (ret) {
15918c7bd5a4SBartosz Golaszewski 		return ret;
15920027340aSBiao Huang 	} else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII &&
15930027340aSBiao Huang 		   priv->phy_intf != PHY_INTERFACE_MODE_MII) {
15948c7bd5a4SBartosz Golaszewski 		dev_err(dev, "unsupported phy mode: %s\n",
15958c7bd5a4SBartosz Golaszewski 			phy_modes(priv->phy_intf));
15968c7bd5a4SBartosz Golaszewski 		return -EINVAL;
15978c7bd5a4SBartosz Golaszewski 	}
15988c7bd5a4SBartosz Golaszewski 
15998c7bd5a4SBartosz Golaszewski 	priv->phy_node = of_parse_phandle(of_node, "phy-handle", 0);
16008c7bd5a4SBartosz Golaszewski 	if (!priv->phy_node) {
16018c7bd5a4SBartosz Golaszewski 		dev_err(dev, "failed to retrieve the phy handle from device tree\n");
16028c7bd5a4SBartosz Golaszewski 		return -ENODEV;
16038c7bd5a4SBartosz Golaszewski 	}
16048c7bd5a4SBartosz Golaszewski 
160585ef6033SBiao Huang 	priv->rmii_rxc = of_property_read_bool(of_node, "mediatek,rmii-rxc");
1606769c197bSBiao Huang 	priv->rx_inv = of_property_read_bool(of_node, "mediatek,rxc-inverse");
1607769c197bSBiao Huang 	priv->tx_inv = of_property_read_bool(of_node, "mediatek,txc-inverse");
160885ef6033SBiao Huang 
16096cde23b3SBiao Huang 	if (priv->compat_data->set_interface_mode) {
16106cde23b3SBiao Huang 		ret = priv->compat_data->set_interface_mode(ndev);
16116cde23b3SBiao Huang 		if (ret) {
16126cde23b3SBiao Huang 			dev_err(dev, "Failed to set phy interface, err = %d\n", ret);
16136cde23b3SBiao Huang 			return -EINVAL;
16146cde23b3SBiao Huang 		}
16156cde23b3SBiao Huang 	}
16168c7bd5a4SBartosz Golaszewski 
1617769c197bSBiao Huang 	ret = mtk_star_set_timing(priv);
1618769c197bSBiao Huang 	if (ret) {
1619769c197bSBiao Huang 		dev_err(dev, "Failed to set timing, err = %d\n", ret);
1620769c197bSBiao Huang 		return -EINVAL;
1621769c197bSBiao Huang 	}
1622769c197bSBiao Huang 
16238c7bd5a4SBartosz Golaszewski 	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
16248c7bd5a4SBartosz Golaszewski 	if (ret) {
16258c7bd5a4SBartosz Golaszewski 		dev_err(dev, "unsupported DMA mask\n");
16268c7bd5a4SBartosz Golaszewski 		return ret;
16278c7bd5a4SBartosz Golaszewski 	}
16288c7bd5a4SBartosz Golaszewski 
16298c7bd5a4SBartosz Golaszewski 	priv->ring_base = dmam_alloc_coherent(dev, MTK_STAR_DMA_SIZE,
16308c7bd5a4SBartosz Golaszewski 					      &priv->dma_addr,
16318c7bd5a4SBartosz Golaszewski 					      GFP_KERNEL | GFP_DMA);
16328c7bd5a4SBartosz Golaszewski 	if (!priv->ring_base)
16338c7bd5a4SBartosz Golaszewski 		return -ENOMEM;
16348c7bd5a4SBartosz Golaszewski 
16358c7bd5a4SBartosz Golaszewski 	mtk_star_nic_disable_pd(priv);
16368c7bd5a4SBartosz Golaszewski 	mtk_star_init_config(priv);
16378c7bd5a4SBartosz Golaszewski 
16388c7bd5a4SBartosz Golaszewski 	ret = mtk_star_mdio_init(ndev);
16398c7bd5a4SBartosz Golaszewski 	if (ret)
16408c7bd5a4SBartosz Golaszewski 		return ret;
16418c7bd5a4SBartosz Golaszewski 
16424d04cdc5SJakub Kicinski 	ret = platform_get_ethdev_address(dev, ndev);
16438c7bd5a4SBartosz Golaszewski 	if (ret || !is_valid_ether_addr(ndev->dev_addr))
16448c7bd5a4SBartosz Golaszewski 		eth_hw_addr_random(ndev);
16458c7bd5a4SBartosz Golaszewski 
16468c7bd5a4SBartosz Golaszewski 	ndev->netdev_ops = &mtk_star_netdev_ops;
16478c7bd5a4SBartosz Golaszewski 	ndev->ethtool_ops = &mtk_star_ethtool_ops;
16488c7bd5a4SBartosz Golaszewski 
1649b48b89f9SJakub Kicinski 	netif_napi_add(ndev, &priv->rx_napi, mtk_star_rx_poll);
1650c0f50574SJakub Kicinski 	netif_napi_add_tx(ndev, &priv->tx_napi, mtk_star_tx_poll);
16518c7bd5a4SBartosz Golaszewski 
16529250dcccSBartosz Golaszewski 	return devm_register_netdev(dev, ndev);
16538c7bd5a4SBartosz Golaszewski }
16548c7bd5a4SBartosz Golaszewski 
1655a9c5eb64SLorenzo Bianconi #ifdef CONFIG_OF
mt8516_set_interface_mode(struct net_device * ndev)16566cde23b3SBiao Huang static int mt8516_set_interface_mode(struct net_device *ndev)
16576cde23b3SBiao Huang {
16586cde23b3SBiao Huang 	struct mtk_star_priv *priv = netdev_priv(ndev);
16596cde23b3SBiao Huang 	struct device *dev = mtk_star_get_dev(priv);
166085ef6033SBiao Huang 	unsigned int intf_val, ret, rmii_rxc;
16616cde23b3SBiao Huang 
16626cde23b3SBiao Huang 	switch (priv->phy_intf) {
16630027340aSBiao Huang 	case PHY_INTERFACE_MODE_MII:
16640027340aSBiao Huang 		intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
16650027340aSBiao Huang 		rmii_rxc = 0;
16660027340aSBiao Huang 		break;
16676cde23b3SBiao Huang 	case PHY_INTERFACE_MODE_RMII:
16686cde23b3SBiao Huang 		intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
166985ef6033SBiao Huang 		rmii_rxc = priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK;
16706cde23b3SBiao Huang 		break;
16716cde23b3SBiao Huang 	default:
16726cde23b3SBiao Huang 		dev_err(dev, "This interface not supported\n");
16736cde23b3SBiao Huang 		return -EINVAL;
16746cde23b3SBiao Huang 	}
16756cde23b3SBiao Huang 
167685ef6033SBiao Huang 	ret = regmap_update_bits(priv->pericfg,
167785ef6033SBiao Huang 				 MTK_PERICFG_REG_NIC_CFG1_CON,
167885ef6033SBiao Huang 				 MTK_PERICFG_BIT_NIC_CFG_CON_CLK,
167985ef6033SBiao Huang 				 rmii_rxc);
168085ef6033SBiao Huang 	if (ret)
168185ef6033SBiao Huang 		return ret;
168285ef6033SBiao Huang 
16836cde23b3SBiao Huang 	return regmap_update_bits(priv->pericfg,
16846cde23b3SBiao Huang 				  MTK_PERICFG_REG_NIC_CFG0_CON,
16856cde23b3SBiao Huang 				  MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF,
16866cde23b3SBiao Huang 				  intf_val);
16876cde23b3SBiao Huang }
16886cde23b3SBiao Huang 
mt8365_set_interface_mode(struct net_device * ndev)16896cde23b3SBiao Huang static int mt8365_set_interface_mode(struct net_device *ndev)
16906cde23b3SBiao Huang {
16916cde23b3SBiao Huang 	struct mtk_star_priv *priv = netdev_priv(ndev);
16926cde23b3SBiao Huang 	struct device *dev = mtk_star_get_dev(priv);
16936cde23b3SBiao Huang 	unsigned int intf_val;
16946cde23b3SBiao Huang 
16956cde23b3SBiao Huang 	switch (priv->phy_intf) {
16960027340aSBiao Huang 	case PHY_INTERFACE_MODE_MII:
16970027340aSBiao Huang 		intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
16980027340aSBiao Huang 		break;
16996cde23b3SBiao Huang 	case PHY_INTERFACE_MODE_RMII:
17006cde23b3SBiao Huang 		intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
170185ef6033SBiao Huang 		intf_val |= priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2;
17026cde23b3SBiao Huang 		break;
17036cde23b3SBiao Huang 	default:
17046cde23b3SBiao Huang 		dev_err(dev, "This interface not supported\n");
17056cde23b3SBiao Huang 		return -EINVAL;
17066cde23b3SBiao Huang 	}
17076cde23b3SBiao Huang 
17086cde23b3SBiao Huang 	return regmap_update_bits(priv->pericfg,
17096cde23b3SBiao Huang 				  MTK_PERICFG_REG_NIC_CFG_CON_V2,
171085ef6033SBiao Huang 				  MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF |
171185ef6033SBiao Huang 				  MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2,
17126cde23b3SBiao Huang 				  intf_val);
17136cde23b3SBiao Huang }
17146cde23b3SBiao Huang 
1715c16cc6a0SBiao Huang static const struct mtk_star_compat mtk_star_mt8516_compat = {
17166cde23b3SBiao Huang 	.set_interface_mode = mt8516_set_interface_mode,
1717c16cc6a0SBiao Huang 	.bit_clk_div = MTK_STAR_BIT_CLK_DIV_10,
1718c16cc6a0SBiao Huang };
1719c16cc6a0SBiao Huang 
17206cde23b3SBiao Huang static const struct mtk_star_compat mtk_star_mt8365_compat = {
17216cde23b3SBiao Huang 	.set_interface_mode = mt8365_set_interface_mode,
17226cde23b3SBiao Huang 	.bit_clk_div = MTK_STAR_BIT_CLK_DIV_50,
17236cde23b3SBiao Huang };
17246cde23b3SBiao Huang 
17258c7bd5a4SBartosz Golaszewski static const struct of_device_id mtk_star_of_match[] = {
1726c16cc6a0SBiao Huang 	{ .compatible = "mediatek,mt8516-eth",
1727c16cc6a0SBiao Huang 	  .data = &mtk_star_mt8516_compat },
1728c16cc6a0SBiao Huang 	{ .compatible = "mediatek,mt8518-eth",
1729c16cc6a0SBiao Huang 	  .data = &mtk_star_mt8516_compat },
1730c16cc6a0SBiao Huang 	{ .compatible = "mediatek,mt8175-eth",
1731c16cc6a0SBiao Huang 	  .data = &mtk_star_mt8516_compat },
17326cde23b3SBiao Huang 	{ .compatible = "mediatek,mt8365-eth",
17336cde23b3SBiao Huang 	  .data = &mtk_star_mt8365_compat },
17348c7bd5a4SBartosz Golaszewski 	{ }
17358c7bd5a4SBartosz Golaszewski };
17368c7bd5a4SBartosz Golaszewski MODULE_DEVICE_TABLE(of, mtk_star_of_match);
1737a9c5eb64SLorenzo Bianconi #endif
17388c7bd5a4SBartosz Golaszewski 
17398c7bd5a4SBartosz Golaszewski static SIMPLE_DEV_PM_OPS(mtk_star_pm_ops,
17408c7bd5a4SBartosz Golaszewski 			 mtk_star_suspend, mtk_star_resume);
17418c7bd5a4SBartosz Golaszewski 
17428c7bd5a4SBartosz Golaszewski static struct platform_driver mtk_star_driver = {
17438c7bd5a4SBartosz Golaszewski 	.driver = {
17448c7bd5a4SBartosz Golaszewski 		.name = MTK_STAR_DRVNAME,
17458c7bd5a4SBartosz Golaszewski 		.pm = &mtk_star_pm_ops,
17468c7bd5a4SBartosz Golaszewski 		.of_match_table = of_match_ptr(mtk_star_of_match),
17478c7bd5a4SBartosz Golaszewski 	},
17488c7bd5a4SBartosz Golaszewski 	.probe = mtk_star_probe,
17498c7bd5a4SBartosz Golaszewski };
17508c7bd5a4SBartosz Golaszewski module_platform_driver(mtk_star_driver);
17518c7bd5a4SBartosz Golaszewski 
17528c7bd5a4SBartosz Golaszewski MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
17538c7bd5a4SBartosz Golaszewski MODULE_DESCRIPTION("Mediatek STAR Ethernet MAC Driver");
17548c7bd5a4SBartosz Golaszewski MODULE_LICENSE("GPL");
1755