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