19f93ac8dSLABBE Corentin /* 29f93ac8dSLABBE Corentin * dwmac-sun8i.c - Allwinner sun8i DWMAC specific glue layer 39f93ac8dSLABBE Corentin * 49f93ac8dSLABBE Corentin * Copyright (C) 2017 Corentin Labbe <clabbe.montjoie@gmail.com> 59f93ac8dSLABBE Corentin * 69f93ac8dSLABBE Corentin * This program is free software; you can redistribute it and/or modify 79f93ac8dSLABBE Corentin * it under the terms of the GNU General Public License as published by 89f93ac8dSLABBE Corentin * the Free Software Foundation; either version 2 of the License, or 99f93ac8dSLABBE Corentin * (at your option) any later version. 109f93ac8dSLABBE Corentin * 119f93ac8dSLABBE Corentin * This program is distributed in the hope that it will be useful, 129f93ac8dSLABBE Corentin * but WITHOUT ANY WARRANTY; without even the implied warranty of 139f93ac8dSLABBE Corentin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149f93ac8dSLABBE Corentin * GNU General Public License for more details. 159f93ac8dSLABBE Corentin */ 169f93ac8dSLABBE Corentin 179f93ac8dSLABBE Corentin #include <linux/clk.h> 189f93ac8dSLABBE Corentin #include <linux/io.h> 199f93ac8dSLABBE Corentin #include <linux/iopoll.h> 209f93ac8dSLABBE Corentin #include <linux/mfd/syscon.h> 219f93ac8dSLABBE Corentin #include <linux/module.h> 229f93ac8dSLABBE Corentin #include <linux/of_device.h> 239f93ac8dSLABBE Corentin #include <linux/of_mdio.h> 249f93ac8dSLABBE Corentin #include <linux/of_net.h> 259f93ac8dSLABBE Corentin #include <linux/phy.h> 269f93ac8dSLABBE Corentin #include <linux/platform_device.h> 279f93ac8dSLABBE Corentin #include <linux/regulator/consumer.h> 289f93ac8dSLABBE Corentin #include <linux/regmap.h> 299f93ac8dSLABBE Corentin #include <linux/stmmac.h> 309f93ac8dSLABBE Corentin 319f93ac8dSLABBE Corentin #include "stmmac.h" 329f93ac8dSLABBE Corentin #include "stmmac_platform.h" 339f93ac8dSLABBE Corentin 349f93ac8dSLABBE Corentin /* General notes on dwmac-sun8i: 359f93ac8dSLABBE Corentin * Locking: no locking is necessary in this file because all necessary locking 369f93ac8dSLABBE Corentin * is done in the "stmmac files" 379f93ac8dSLABBE Corentin */ 389f93ac8dSLABBE Corentin 399f93ac8dSLABBE Corentin /* struct emac_variant - Descrive dwmac-sun8i hardware variant 409f93ac8dSLABBE Corentin * @default_syscon_value: The default value of the EMAC register in syscon 419f93ac8dSLABBE Corentin * This value is used for disabling properly EMAC 429f93ac8dSLABBE Corentin * and used as a good starting value in case of the 439f93ac8dSLABBE Corentin * boot process(uboot) leave some stuff. 449f93ac8dSLABBE Corentin * @internal_phy: Does the MAC embed an internal PHY 459f93ac8dSLABBE Corentin * @support_mii: Does the MAC handle MII 469f93ac8dSLABBE Corentin * @support_rmii: Does the MAC handle RMII 479f93ac8dSLABBE Corentin * @support_rgmii: Does the MAC handle RGMII 489f93ac8dSLABBE Corentin */ 499f93ac8dSLABBE Corentin struct emac_variant { 509f93ac8dSLABBE Corentin u32 default_syscon_value; 519f93ac8dSLABBE Corentin int internal_phy; 529f93ac8dSLABBE Corentin bool support_mii; 539f93ac8dSLABBE Corentin bool support_rmii; 549f93ac8dSLABBE Corentin bool support_rgmii; 559f93ac8dSLABBE Corentin }; 569f93ac8dSLABBE Corentin 579f93ac8dSLABBE Corentin /* struct sunxi_priv_data - hold all sunxi private data 589f93ac8dSLABBE Corentin * @tx_clk: reference to MAC TX clock 599f93ac8dSLABBE Corentin * @ephy_clk: reference to the optional EPHY clock for the internal PHY 609f93ac8dSLABBE Corentin * @regulator: reference to the optional regulator 619f93ac8dSLABBE Corentin * @rst_ephy: reference to the optional EPHY reset for the internal PHY 629f93ac8dSLABBE Corentin * @variant: reference to the current board variant 639f93ac8dSLABBE Corentin * @regmap: regmap for using the syscon 649f93ac8dSLABBE Corentin * @use_internal_phy: Does the current PHY choice imply using the internal PHY 659f93ac8dSLABBE Corentin */ 669f93ac8dSLABBE Corentin struct sunxi_priv_data { 679f93ac8dSLABBE Corentin struct clk *tx_clk; 689f93ac8dSLABBE Corentin struct clk *ephy_clk; 699f93ac8dSLABBE Corentin struct regulator *regulator; 709f93ac8dSLABBE Corentin struct reset_control *rst_ephy; 719f93ac8dSLABBE Corentin const struct emac_variant *variant; 729f93ac8dSLABBE Corentin struct regmap *regmap; 739f93ac8dSLABBE Corentin bool use_internal_phy; 749f93ac8dSLABBE Corentin }; 759f93ac8dSLABBE Corentin 769f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_h3 = { 779f93ac8dSLABBE Corentin .default_syscon_value = 0x58000, 789f93ac8dSLABBE Corentin .internal_phy = PHY_INTERFACE_MODE_MII, 799f93ac8dSLABBE Corentin .support_mii = true, 809f93ac8dSLABBE Corentin .support_rmii = true, 819f93ac8dSLABBE Corentin .support_rgmii = true 829f93ac8dSLABBE Corentin }; 839f93ac8dSLABBE Corentin 84*57fde47dSIcenowy Zheng static const struct emac_variant emac_variant_v3s = { 85*57fde47dSIcenowy Zheng .default_syscon_value = 0x38000, 86*57fde47dSIcenowy Zheng .internal_phy = PHY_INTERFACE_MODE_MII, 87*57fde47dSIcenowy Zheng .support_mii = true 88*57fde47dSIcenowy Zheng }; 89*57fde47dSIcenowy Zheng 909f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_a83t = { 919f93ac8dSLABBE Corentin .default_syscon_value = 0, 929f93ac8dSLABBE Corentin .internal_phy = 0, 939f93ac8dSLABBE Corentin .support_mii = true, 949f93ac8dSLABBE Corentin .support_rgmii = true 959f93ac8dSLABBE Corentin }; 969f93ac8dSLABBE Corentin 979f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_a64 = { 989f93ac8dSLABBE Corentin .default_syscon_value = 0, 999f93ac8dSLABBE Corentin .internal_phy = 0, 1009f93ac8dSLABBE Corentin .support_mii = true, 1019f93ac8dSLABBE Corentin .support_rmii = true, 1029f93ac8dSLABBE Corentin .support_rgmii = true 1039f93ac8dSLABBE Corentin }; 1049f93ac8dSLABBE Corentin 1059f93ac8dSLABBE Corentin #define EMAC_BASIC_CTL0 0x00 1069f93ac8dSLABBE Corentin #define EMAC_BASIC_CTL1 0x04 1079f93ac8dSLABBE Corentin #define EMAC_INT_STA 0x08 1089f93ac8dSLABBE Corentin #define EMAC_INT_EN 0x0C 1099f93ac8dSLABBE Corentin #define EMAC_TX_CTL0 0x10 1109f93ac8dSLABBE Corentin #define EMAC_TX_CTL1 0x14 1119f93ac8dSLABBE Corentin #define EMAC_TX_FLOW_CTL 0x1C 1129f93ac8dSLABBE Corentin #define EMAC_TX_DESC_LIST 0x20 1139f93ac8dSLABBE Corentin #define EMAC_RX_CTL0 0x24 1149f93ac8dSLABBE Corentin #define EMAC_RX_CTL1 0x28 1159f93ac8dSLABBE Corentin #define EMAC_RX_DESC_LIST 0x34 1169f93ac8dSLABBE Corentin #define EMAC_RX_FRM_FLT 0x38 1179f93ac8dSLABBE Corentin #define EMAC_MDIO_CMD 0x48 1189f93ac8dSLABBE Corentin #define EMAC_MDIO_DATA 0x4C 1199f93ac8dSLABBE Corentin #define EMAC_MACADDR_HI(reg) (0x50 + (reg) * 8) 1209f93ac8dSLABBE Corentin #define EMAC_MACADDR_LO(reg) (0x54 + (reg) * 8) 1219f93ac8dSLABBE Corentin #define EMAC_TX_DMA_STA 0xB0 1229f93ac8dSLABBE Corentin #define EMAC_TX_CUR_DESC 0xB4 1239f93ac8dSLABBE Corentin #define EMAC_TX_CUR_BUF 0xB8 1249f93ac8dSLABBE Corentin #define EMAC_RX_DMA_STA 0xC0 1259f93ac8dSLABBE Corentin #define EMAC_RX_CUR_DESC 0xC4 1269f93ac8dSLABBE Corentin #define EMAC_RX_CUR_BUF 0xC8 1279f93ac8dSLABBE Corentin 1289f93ac8dSLABBE Corentin /* Use in EMAC_BASIC_CTL0 */ 1299f93ac8dSLABBE Corentin #define EMAC_DUPLEX_FULL BIT(0) 1309f93ac8dSLABBE Corentin #define EMAC_LOOPBACK BIT(1) 1319f93ac8dSLABBE Corentin #define EMAC_SPEED_1000 0 1329f93ac8dSLABBE Corentin #define EMAC_SPEED_100 (0x03 << 2) 1339f93ac8dSLABBE Corentin #define EMAC_SPEED_10 (0x02 << 2) 1349f93ac8dSLABBE Corentin 1359f93ac8dSLABBE Corentin /* Use in EMAC_BASIC_CTL1 */ 1369f93ac8dSLABBE Corentin #define EMAC_BURSTLEN_SHIFT 24 1379f93ac8dSLABBE Corentin 1389f93ac8dSLABBE Corentin /* Used in EMAC_RX_FRM_FLT */ 1399f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_RXALL BIT(0) 1409f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_CTL BIT(13) 1419f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_MULTICAST BIT(16) 1429f93ac8dSLABBE Corentin 1439f93ac8dSLABBE Corentin /* Used in RX_CTL1*/ 1449f93ac8dSLABBE Corentin #define EMAC_RX_MD BIT(1) 1459f93ac8dSLABBE Corentin #define EMAC_RX_TH_MASK GENMASK(4, 5) 1469f93ac8dSLABBE Corentin #define EMAC_RX_TH_32 0 1479f93ac8dSLABBE Corentin #define EMAC_RX_TH_64 (0x1 << 4) 1489f93ac8dSLABBE Corentin #define EMAC_RX_TH_96 (0x2 << 4) 1499f93ac8dSLABBE Corentin #define EMAC_RX_TH_128 (0x3 << 4) 1509f93ac8dSLABBE Corentin #define EMAC_RX_DMA_EN BIT(30) 1519f93ac8dSLABBE Corentin #define EMAC_RX_DMA_START BIT(31) 1529f93ac8dSLABBE Corentin 1539f93ac8dSLABBE Corentin /* Used in TX_CTL1*/ 1549f93ac8dSLABBE Corentin #define EMAC_TX_MD BIT(1) 1559f93ac8dSLABBE Corentin #define EMAC_TX_NEXT_FRM BIT(2) 1569f93ac8dSLABBE Corentin #define EMAC_TX_TH_MASK GENMASK(8, 10) 1579f93ac8dSLABBE Corentin #define EMAC_TX_TH_64 0 1589f93ac8dSLABBE Corentin #define EMAC_TX_TH_128 (0x1 << 8) 1599f93ac8dSLABBE Corentin #define EMAC_TX_TH_192 (0x2 << 8) 1609f93ac8dSLABBE Corentin #define EMAC_TX_TH_256 (0x3 << 8) 1619f93ac8dSLABBE Corentin #define EMAC_TX_DMA_EN BIT(30) 1629f93ac8dSLABBE Corentin #define EMAC_TX_DMA_START BIT(31) 1639f93ac8dSLABBE Corentin 1649f93ac8dSLABBE Corentin /* Used in RX_CTL0 */ 1659f93ac8dSLABBE Corentin #define EMAC_RX_RECEIVER_EN BIT(31) 1669f93ac8dSLABBE Corentin #define EMAC_RX_DO_CRC BIT(27) 1679f93ac8dSLABBE Corentin #define EMAC_RX_FLOW_CTL_EN BIT(16) 1689f93ac8dSLABBE Corentin 1699f93ac8dSLABBE Corentin /* Used in TX_CTL0 */ 1709f93ac8dSLABBE Corentin #define EMAC_TX_TRANSMITTER_EN BIT(31) 1719f93ac8dSLABBE Corentin 1729f93ac8dSLABBE Corentin /* Used in EMAC_TX_FLOW_CTL */ 1739f93ac8dSLABBE Corentin #define EMAC_TX_FLOW_CTL_EN BIT(0) 1749f93ac8dSLABBE Corentin 1759f93ac8dSLABBE Corentin /* Used in EMAC_INT_STA */ 1769f93ac8dSLABBE Corentin #define EMAC_TX_INT BIT(0) 1779f93ac8dSLABBE Corentin #define EMAC_TX_DMA_STOP_INT BIT(1) 1789f93ac8dSLABBE Corentin #define EMAC_TX_BUF_UA_INT BIT(2) 1799f93ac8dSLABBE Corentin #define EMAC_TX_TIMEOUT_INT BIT(3) 1809f93ac8dSLABBE Corentin #define EMAC_TX_UNDERFLOW_INT BIT(4) 1819f93ac8dSLABBE Corentin #define EMAC_TX_EARLY_INT BIT(5) 1829f93ac8dSLABBE Corentin #define EMAC_RX_INT BIT(8) 1839f93ac8dSLABBE Corentin #define EMAC_RX_BUF_UA_INT BIT(9) 1849f93ac8dSLABBE Corentin #define EMAC_RX_DMA_STOP_INT BIT(10) 1859f93ac8dSLABBE Corentin #define EMAC_RX_TIMEOUT_INT BIT(11) 1869f93ac8dSLABBE Corentin #define EMAC_RX_OVERFLOW_INT BIT(12) 1879f93ac8dSLABBE Corentin #define EMAC_RX_EARLY_INT BIT(13) 1889f93ac8dSLABBE Corentin #define EMAC_RGMII_STA_INT BIT(16) 1899f93ac8dSLABBE Corentin 1909f93ac8dSLABBE Corentin #define MAC_ADDR_TYPE_DST BIT(31) 1919f93ac8dSLABBE Corentin 1929f93ac8dSLABBE Corentin /* H3 specific bits for EPHY */ 1939f93ac8dSLABBE Corentin #define H3_EPHY_ADDR_SHIFT 20 1941450ba8aSIcenowy Zheng #define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */ 1959f93ac8dSLABBE Corentin #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ 1969f93ac8dSLABBE Corentin #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ 1979f93ac8dSLABBE Corentin #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ 1989f93ac8dSLABBE Corentin 1999f93ac8dSLABBE Corentin /* H3/A64 specific bits */ 2009f93ac8dSLABBE Corentin #define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ 2019f93ac8dSLABBE Corentin 2029f93ac8dSLABBE Corentin /* Generic system control EMAC_CLK bits */ 2039f93ac8dSLABBE Corentin #define SYSCON_ETXDC_MASK GENMASK(2, 0) 2049f93ac8dSLABBE Corentin #define SYSCON_ETXDC_SHIFT 10 2059f93ac8dSLABBE Corentin #define SYSCON_ERXDC_MASK GENMASK(4, 0) 2069f93ac8dSLABBE Corentin #define SYSCON_ERXDC_SHIFT 5 2079f93ac8dSLABBE Corentin /* EMAC PHY Interface Type */ 2089f93ac8dSLABBE Corentin #define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ 2099f93ac8dSLABBE Corentin #define SYSCON_ETCS_MASK GENMASK(1, 0) 2109f93ac8dSLABBE Corentin #define SYSCON_ETCS_MII 0x0 2119f93ac8dSLABBE Corentin #define SYSCON_ETCS_EXT_GMII 0x1 2129f93ac8dSLABBE Corentin #define SYSCON_ETCS_INT_GMII 0x2 2139f93ac8dSLABBE Corentin #define SYSCON_EMAC_REG 0x30 2149f93ac8dSLABBE Corentin 2159f93ac8dSLABBE Corentin /* sun8i_dwmac_dma_reset() - reset the EMAC 2169f93ac8dSLABBE Corentin * Called from stmmac via stmmac_dma_ops->reset 2179f93ac8dSLABBE Corentin */ 2189f93ac8dSLABBE Corentin static int sun8i_dwmac_dma_reset(void __iomem *ioaddr) 2199f93ac8dSLABBE Corentin { 2209f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_CTL1); 2219f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_TX_CTL1); 2229f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_FRM_FLT); 2239f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_DESC_LIST); 2249f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_TX_DESC_LIST); 2259f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_INT_EN); 2269f93ac8dSLABBE Corentin writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); 2279f93ac8dSLABBE Corentin return 0; 2289f93ac8dSLABBE Corentin } 2299f93ac8dSLABBE Corentin 2309f93ac8dSLABBE Corentin /* sun8i_dwmac_dma_init() - initialize the EMAC 2319f93ac8dSLABBE Corentin * Called from stmmac via stmmac_dma_ops->init 2329f93ac8dSLABBE Corentin */ 2339f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_init(void __iomem *ioaddr, 2349f93ac8dSLABBE Corentin struct stmmac_dma_cfg *dma_cfg, 2359f93ac8dSLABBE Corentin u32 dma_tx, u32 dma_rx, int atds) 2369f93ac8dSLABBE Corentin { 2379f93ac8dSLABBE Corentin /* Write TX and RX descriptors address */ 2389f93ac8dSLABBE Corentin writel(dma_rx, ioaddr + EMAC_RX_DESC_LIST); 2399f93ac8dSLABBE Corentin writel(dma_tx, ioaddr + EMAC_TX_DESC_LIST); 2409f93ac8dSLABBE Corentin 2419f93ac8dSLABBE Corentin writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); 2429f93ac8dSLABBE Corentin writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); 2439f93ac8dSLABBE Corentin } 2449f93ac8dSLABBE Corentin 2459f93ac8dSLABBE Corentin /* sun8i_dwmac_dump_regs() - Dump EMAC address space 2469f93ac8dSLABBE Corentin * Called from stmmac_dma_ops->dump_regs 2479f93ac8dSLABBE Corentin * Used for ethtool 2489f93ac8dSLABBE Corentin */ 2499f93ac8dSLABBE Corentin static void sun8i_dwmac_dump_regs(void __iomem *ioaddr, u32 *reg_space) 2509f93ac8dSLABBE Corentin { 2519f93ac8dSLABBE Corentin int i; 2529f93ac8dSLABBE Corentin 2539f93ac8dSLABBE Corentin for (i = 0; i < 0xC8; i += 4) { 2549f93ac8dSLABBE Corentin if (i == 0x32 || i == 0x3C) 2559f93ac8dSLABBE Corentin continue; 2569f93ac8dSLABBE Corentin reg_space[i / 4] = readl(ioaddr + i); 2579f93ac8dSLABBE Corentin } 2589f93ac8dSLABBE Corentin } 2599f93ac8dSLABBE Corentin 2609f93ac8dSLABBE Corentin /* sun8i_dwmac_dump_mac_regs() - Dump EMAC address space 2619f93ac8dSLABBE Corentin * Called from stmmac_ops->dump_regs 2629f93ac8dSLABBE Corentin * Used for ethtool 2639f93ac8dSLABBE Corentin */ 2649f93ac8dSLABBE Corentin static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw, 2659f93ac8dSLABBE Corentin u32 *reg_space) 2669f93ac8dSLABBE Corentin { 2679f93ac8dSLABBE Corentin int i; 2689f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 2699f93ac8dSLABBE Corentin 2709f93ac8dSLABBE Corentin for (i = 0; i < 0xC8; i += 4) { 2719f93ac8dSLABBE Corentin if (i == 0x32 || i == 0x3C) 2729f93ac8dSLABBE Corentin continue; 2739f93ac8dSLABBE Corentin reg_space[i / 4] = readl(ioaddr + i); 2749f93ac8dSLABBE Corentin } 2759f93ac8dSLABBE Corentin } 2769f93ac8dSLABBE Corentin 2779f93ac8dSLABBE Corentin static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) 2789f93ac8dSLABBE Corentin { 2799f93ac8dSLABBE Corentin writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); 2809f93ac8dSLABBE Corentin } 2819f93ac8dSLABBE Corentin 2829f93ac8dSLABBE Corentin static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) 2839f93ac8dSLABBE Corentin { 2849f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_INT_EN); 2859f93ac8dSLABBE Corentin } 2869f93ac8dSLABBE Corentin 2879f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan) 2889f93ac8dSLABBE Corentin { 2899f93ac8dSLABBE Corentin u32 v; 2909f93ac8dSLABBE Corentin 2919f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 2929f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_START; 2939f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_EN; 2949f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 2959f93ac8dSLABBE Corentin } 2969f93ac8dSLABBE Corentin 2979f93ac8dSLABBE Corentin static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr) 2989f93ac8dSLABBE Corentin { 2999f93ac8dSLABBE Corentin u32 v; 3009f93ac8dSLABBE Corentin 3019f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 3029f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_START; 3039f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_EN; 3049f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 3059f93ac8dSLABBE Corentin } 3069f93ac8dSLABBE Corentin 3079f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan) 3089f93ac8dSLABBE Corentin { 3099f93ac8dSLABBE Corentin u32 v; 3109f93ac8dSLABBE Corentin 3119f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 3129f93ac8dSLABBE Corentin v &= ~EMAC_TX_DMA_EN; 3139f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 3149f93ac8dSLABBE Corentin } 3159f93ac8dSLABBE Corentin 3169f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan) 3179f93ac8dSLABBE Corentin { 3189f93ac8dSLABBE Corentin u32 v; 3199f93ac8dSLABBE Corentin 3209f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 3219f93ac8dSLABBE Corentin v |= EMAC_RX_DMA_START; 3229f93ac8dSLABBE Corentin v |= EMAC_RX_DMA_EN; 3239f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 3249f93ac8dSLABBE Corentin } 3259f93ac8dSLABBE Corentin 3269f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan) 3279f93ac8dSLABBE Corentin { 3289f93ac8dSLABBE Corentin u32 v; 3299f93ac8dSLABBE Corentin 3309f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 3319f93ac8dSLABBE Corentin v &= ~EMAC_RX_DMA_EN; 3329f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 3339f93ac8dSLABBE Corentin } 3349f93ac8dSLABBE Corentin 3359f93ac8dSLABBE Corentin static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr, 3369f93ac8dSLABBE Corentin struct stmmac_extra_stats *x, u32 chan) 3379f93ac8dSLABBE Corentin { 3389f93ac8dSLABBE Corentin u32 v; 3399f93ac8dSLABBE Corentin int ret = 0; 3409f93ac8dSLABBE Corentin 3419f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_INT_STA); 3429f93ac8dSLABBE Corentin 3439f93ac8dSLABBE Corentin if (v & EMAC_TX_INT) { 3449f93ac8dSLABBE Corentin ret |= handle_tx; 3459f93ac8dSLABBE Corentin x->tx_normal_irq_n++; 3469f93ac8dSLABBE Corentin } 3479f93ac8dSLABBE Corentin 3489f93ac8dSLABBE Corentin if (v & EMAC_TX_DMA_STOP_INT) 3499f93ac8dSLABBE Corentin x->tx_process_stopped_irq++; 3509f93ac8dSLABBE Corentin 3519f93ac8dSLABBE Corentin if (v & EMAC_TX_BUF_UA_INT) 3529f93ac8dSLABBE Corentin x->tx_process_stopped_irq++; 3539f93ac8dSLABBE Corentin 3549f93ac8dSLABBE Corentin if (v & EMAC_TX_TIMEOUT_INT) 3559f93ac8dSLABBE Corentin ret |= tx_hard_error; 3569f93ac8dSLABBE Corentin 3579f93ac8dSLABBE Corentin if (v & EMAC_TX_UNDERFLOW_INT) { 3589f93ac8dSLABBE Corentin ret |= tx_hard_error; 3599f93ac8dSLABBE Corentin x->tx_undeflow_irq++; 3609f93ac8dSLABBE Corentin } 3619f93ac8dSLABBE Corentin 3629f93ac8dSLABBE Corentin if (v & EMAC_TX_EARLY_INT) 3639f93ac8dSLABBE Corentin x->tx_early_irq++; 3649f93ac8dSLABBE Corentin 3659f93ac8dSLABBE Corentin if (v & EMAC_RX_INT) { 3669f93ac8dSLABBE Corentin ret |= handle_rx; 3679f93ac8dSLABBE Corentin x->rx_normal_irq_n++; 3689f93ac8dSLABBE Corentin } 3699f93ac8dSLABBE Corentin 3709f93ac8dSLABBE Corentin if (v & EMAC_RX_BUF_UA_INT) 3719f93ac8dSLABBE Corentin x->rx_buf_unav_irq++; 3729f93ac8dSLABBE Corentin 3739f93ac8dSLABBE Corentin if (v & EMAC_RX_DMA_STOP_INT) 3749f93ac8dSLABBE Corentin x->rx_process_stopped_irq++; 3759f93ac8dSLABBE Corentin 3769f93ac8dSLABBE Corentin if (v & EMAC_RX_TIMEOUT_INT) 3779f93ac8dSLABBE Corentin ret |= tx_hard_error; 3789f93ac8dSLABBE Corentin 3799f93ac8dSLABBE Corentin if (v & EMAC_RX_OVERFLOW_INT) { 3809f93ac8dSLABBE Corentin ret |= tx_hard_error; 3819f93ac8dSLABBE Corentin x->rx_overflow_irq++; 3829f93ac8dSLABBE Corentin } 3839f93ac8dSLABBE Corentin 3849f93ac8dSLABBE Corentin if (v & EMAC_RX_EARLY_INT) 3859f93ac8dSLABBE Corentin x->rx_early_irq++; 3869f93ac8dSLABBE Corentin 3879f93ac8dSLABBE Corentin if (v & EMAC_RGMII_STA_INT) 3889f93ac8dSLABBE Corentin x->irq_rgmii_n++; 3899f93ac8dSLABBE Corentin 3909f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_INT_STA); 3919f93ac8dSLABBE Corentin 3929f93ac8dSLABBE Corentin return ret; 3939f93ac8dSLABBE Corentin } 3949f93ac8dSLABBE Corentin 3959f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_operation_mode(void __iomem *ioaddr, int txmode, 3969f93ac8dSLABBE Corentin int rxmode, int rxfifosz) 3979f93ac8dSLABBE Corentin { 3989f93ac8dSLABBE Corentin u32 v; 3999f93ac8dSLABBE Corentin 4009f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 4019f93ac8dSLABBE Corentin if (txmode == SF_DMA_MODE) { 4029f93ac8dSLABBE Corentin v |= EMAC_TX_MD; 4039f93ac8dSLABBE Corentin /* Undocumented bit (called TX_NEXT_FRM in BSP), the original 4049f93ac8dSLABBE Corentin * comment is 4059f93ac8dSLABBE Corentin * "Operating on second frame increase the performance 4069f93ac8dSLABBE Corentin * especially when transmit store-and-forward is used." 4079f93ac8dSLABBE Corentin */ 4089f93ac8dSLABBE Corentin v |= EMAC_TX_NEXT_FRM; 4099f93ac8dSLABBE Corentin } else { 4109f93ac8dSLABBE Corentin v &= ~EMAC_TX_MD; 4119f93ac8dSLABBE Corentin v &= ~EMAC_TX_TH_MASK; 4129f93ac8dSLABBE Corentin if (txmode < 64) 4139f93ac8dSLABBE Corentin v |= EMAC_TX_TH_64; 4149f93ac8dSLABBE Corentin else if (txmode < 128) 4159f93ac8dSLABBE Corentin v |= EMAC_TX_TH_128; 4169f93ac8dSLABBE Corentin else if (txmode < 192) 4179f93ac8dSLABBE Corentin v |= EMAC_TX_TH_192; 4189f93ac8dSLABBE Corentin else if (txmode < 256) 4199f93ac8dSLABBE Corentin v |= EMAC_TX_TH_256; 4209f93ac8dSLABBE Corentin } 4219f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 4229f93ac8dSLABBE Corentin 4239f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 4249f93ac8dSLABBE Corentin if (rxmode == SF_DMA_MODE) { 4259f93ac8dSLABBE Corentin v |= EMAC_RX_MD; 4269f93ac8dSLABBE Corentin } else { 4279f93ac8dSLABBE Corentin v &= ~EMAC_RX_MD; 4289f93ac8dSLABBE Corentin v &= ~EMAC_RX_TH_MASK; 4299f93ac8dSLABBE Corentin if (rxmode < 32) 4309f93ac8dSLABBE Corentin v |= EMAC_RX_TH_32; 4319f93ac8dSLABBE Corentin else if (rxmode < 64) 4329f93ac8dSLABBE Corentin v |= EMAC_RX_TH_64; 4339f93ac8dSLABBE Corentin else if (rxmode < 96) 4349f93ac8dSLABBE Corentin v |= EMAC_RX_TH_96; 4359f93ac8dSLABBE Corentin else if (rxmode < 128) 4369f93ac8dSLABBE Corentin v |= EMAC_RX_TH_128; 4379f93ac8dSLABBE Corentin } 4389f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 4399f93ac8dSLABBE Corentin } 4409f93ac8dSLABBE Corentin 4419f93ac8dSLABBE Corentin static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { 4429f93ac8dSLABBE Corentin .reset = sun8i_dwmac_dma_reset, 4439f93ac8dSLABBE Corentin .init = sun8i_dwmac_dma_init, 4449f93ac8dSLABBE Corentin .dump_regs = sun8i_dwmac_dump_regs, 4459f93ac8dSLABBE Corentin .dma_mode = sun8i_dwmac_dma_operation_mode, 4469f93ac8dSLABBE Corentin .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission, 4479f93ac8dSLABBE Corentin .enable_dma_irq = sun8i_dwmac_enable_dma_irq, 4489f93ac8dSLABBE Corentin .disable_dma_irq = sun8i_dwmac_disable_dma_irq, 4499f93ac8dSLABBE Corentin .start_tx = sun8i_dwmac_dma_start_tx, 4509f93ac8dSLABBE Corentin .stop_tx = sun8i_dwmac_dma_stop_tx, 4519f93ac8dSLABBE Corentin .start_rx = sun8i_dwmac_dma_start_rx, 4529f93ac8dSLABBE Corentin .stop_rx = sun8i_dwmac_dma_stop_rx, 4539f93ac8dSLABBE Corentin .dma_interrupt = sun8i_dwmac_dma_interrupt, 4549f93ac8dSLABBE Corentin }; 4559f93ac8dSLABBE Corentin 4569f93ac8dSLABBE Corentin static int sun8i_dwmac_init(struct platform_device *pdev, void *priv) 4579f93ac8dSLABBE Corentin { 4589f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv; 4599f93ac8dSLABBE Corentin int ret; 4609f93ac8dSLABBE Corentin 4619f93ac8dSLABBE Corentin if (gmac->regulator) { 4629f93ac8dSLABBE Corentin ret = regulator_enable(gmac->regulator); 4639f93ac8dSLABBE Corentin if (ret) { 4649f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Fail to enable regulator\n"); 4659f93ac8dSLABBE Corentin return ret; 4669f93ac8dSLABBE Corentin } 4679f93ac8dSLABBE Corentin } 4689f93ac8dSLABBE Corentin 4699f93ac8dSLABBE Corentin ret = clk_prepare_enable(gmac->tx_clk); 4709f93ac8dSLABBE Corentin if (ret) { 4719f93ac8dSLABBE Corentin if (gmac->regulator) 4729f93ac8dSLABBE Corentin regulator_disable(gmac->regulator); 4739f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Could not enable AHB clock\n"); 4749f93ac8dSLABBE Corentin return ret; 4759f93ac8dSLABBE Corentin } 4769f93ac8dSLABBE Corentin 4779f93ac8dSLABBE Corentin return 0; 4789f93ac8dSLABBE Corentin } 4799f93ac8dSLABBE Corentin 4809f93ac8dSLABBE Corentin static void sun8i_dwmac_core_init(struct mac_device_info *hw, int mtu) 4819f93ac8dSLABBE Corentin { 4829f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 4839f93ac8dSLABBE Corentin u32 v; 4849f93ac8dSLABBE Corentin 4859f93ac8dSLABBE Corentin v = (8 << EMAC_BURSTLEN_SHIFT); /* burst len */ 4869f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_BASIC_CTL1); 4879f93ac8dSLABBE Corentin } 4889f93ac8dSLABBE Corentin 4899f93ac8dSLABBE Corentin static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable) 4909f93ac8dSLABBE Corentin { 4919f93ac8dSLABBE Corentin u32 t, r; 4929f93ac8dSLABBE Corentin 4939f93ac8dSLABBE Corentin t = readl(ioaddr + EMAC_TX_CTL0); 4949f93ac8dSLABBE Corentin r = readl(ioaddr + EMAC_RX_CTL0); 4959f93ac8dSLABBE Corentin if (enable) { 4969f93ac8dSLABBE Corentin t |= EMAC_TX_TRANSMITTER_EN; 4979f93ac8dSLABBE Corentin r |= EMAC_RX_RECEIVER_EN; 4989f93ac8dSLABBE Corentin } else { 4999f93ac8dSLABBE Corentin t &= ~EMAC_TX_TRANSMITTER_EN; 5009f93ac8dSLABBE Corentin r &= ~EMAC_RX_RECEIVER_EN; 5019f93ac8dSLABBE Corentin } 5029f93ac8dSLABBE Corentin writel(t, ioaddr + EMAC_TX_CTL0); 5039f93ac8dSLABBE Corentin writel(r, ioaddr + EMAC_RX_CTL0); 5049f93ac8dSLABBE Corentin } 5059f93ac8dSLABBE Corentin 5069f93ac8dSLABBE Corentin /* Set MAC address at slot reg_n 5079f93ac8dSLABBE Corentin * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST 5089f93ac8dSLABBE Corentin * If addr is NULL, clear the slot 5099f93ac8dSLABBE Corentin */ 5109f93ac8dSLABBE Corentin static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw, 5119f93ac8dSLABBE Corentin unsigned char *addr, 5129f93ac8dSLABBE Corentin unsigned int reg_n) 5139f93ac8dSLABBE Corentin { 5149f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5159f93ac8dSLABBE Corentin u32 v; 5169f93ac8dSLABBE Corentin 5179f93ac8dSLABBE Corentin if (!addr) { 5189f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_MACADDR_HI(reg_n)); 5199f93ac8dSLABBE Corentin return; 5209f93ac8dSLABBE Corentin } 5219f93ac8dSLABBE Corentin 5229f93ac8dSLABBE Corentin stmmac_set_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), 5239f93ac8dSLABBE Corentin EMAC_MACADDR_LO(reg_n)); 5249f93ac8dSLABBE Corentin if (reg_n > 0) { 5259f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_MACADDR_HI(reg_n)); 5269f93ac8dSLABBE Corentin v |= MAC_ADDR_TYPE_DST; 5279f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_MACADDR_HI(reg_n)); 5289f93ac8dSLABBE Corentin } 5299f93ac8dSLABBE Corentin } 5309f93ac8dSLABBE Corentin 5319f93ac8dSLABBE Corentin static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw, 5329f93ac8dSLABBE Corentin unsigned char *addr, 5339f93ac8dSLABBE Corentin unsigned int reg_n) 5349f93ac8dSLABBE Corentin { 5359f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5369f93ac8dSLABBE Corentin 5379f93ac8dSLABBE Corentin stmmac_get_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), 5389f93ac8dSLABBE Corentin EMAC_MACADDR_LO(reg_n)); 5399f93ac8dSLABBE Corentin } 5409f93ac8dSLABBE Corentin 5419f93ac8dSLABBE Corentin /* caution this function must return non 0 to work */ 5429f93ac8dSLABBE Corentin static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw) 5439f93ac8dSLABBE Corentin { 5449f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5459f93ac8dSLABBE Corentin u32 v; 5469f93ac8dSLABBE Corentin 5479f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL0); 5489f93ac8dSLABBE Corentin v |= EMAC_RX_DO_CRC; 5499f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL0); 5509f93ac8dSLABBE Corentin 5519f93ac8dSLABBE Corentin return 1; 5529f93ac8dSLABBE Corentin } 5539f93ac8dSLABBE Corentin 5549f93ac8dSLABBE Corentin static void sun8i_dwmac_set_filter(struct mac_device_info *hw, 5559f93ac8dSLABBE Corentin struct net_device *dev) 5569f93ac8dSLABBE Corentin { 5579f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5589f93ac8dSLABBE Corentin u32 v; 5599f93ac8dSLABBE Corentin int i = 1; 5609f93ac8dSLABBE Corentin struct netdev_hw_addr *ha; 5619f93ac8dSLABBE Corentin int macaddrs = netdev_uc_count(dev) + netdev_mc_count(dev) + 1; 5629f93ac8dSLABBE Corentin 5639f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_CTL; 5649f93ac8dSLABBE Corentin 5659f93ac8dSLABBE Corentin if (dev->flags & IFF_PROMISC) { 5669f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_RXALL; 5679f93ac8dSLABBE Corentin } else if (dev->flags & IFF_ALLMULTI) { 5689f93ac8dSLABBE Corentin v |= EMAC_FRM_FLT_MULTICAST; 5699f93ac8dSLABBE Corentin } else if (macaddrs <= hw->unicast_filter_entries) { 5709f93ac8dSLABBE Corentin if (!netdev_mc_empty(dev)) { 5719f93ac8dSLABBE Corentin netdev_for_each_mc_addr(ha, dev) { 5729f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, ha->addr, i); 5739f93ac8dSLABBE Corentin i++; 5749f93ac8dSLABBE Corentin } 5759f93ac8dSLABBE Corentin } 5769f93ac8dSLABBE Corentin if (!netdev_uc_empty(dev)) { 5779f93ac8dSLABBE Corentin netdev_for_each_uc_addr(ha, dev) { 5789f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, ha->addr, i); 5799f93ac8dSLABBE Corentin i++; 5809f93ac8dSLABBE Corentin } 5819f93ac8dSLABBE Corentin } 5829f93ac8dSLABBE Corentin } else { 5839f93ac8dSLABBE Corentin netdev_info(dev, "Too many address, switching to promiscuous\n"); 5849f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_RXALL; 5859f93ac8dSLABBE Corentin } 5869f93ac8dSLABBE Corentin 5879f93ac8dSLABBE Corentin /* Disable unused address filter slots */ 5889f93ac8dSLABBE Corentin while (i < hw->unicast_filter_entries) 5899f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, NULL, i++); 5909f93ac8dSLABBE Corentin 5919f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_FRM_FLT); 5929f93ac8dSLABBE Corentin } 5939f93ac8dSLABBE Corentin 5949f93ac8dSLABBE Corentin static void sun8i_dwmac_flow_ctrl(struct mac_device_info *hw, 5959f93ac8dSLABBE Corentin unsigned int duplex, unsigned int fc, 5969f93ac8dSLABBE Corentin unsigned int pause_time, u32 tx_cnt) 5979f93ac8dSLABBE Corentin { 5989f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5999f93ac8dSLABBE Corentin u32 v; 6009f93ac8dSLABBE Corentin 6019f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL0); 6029f93ac8dSLABBE Corentin if (fc == FLOW_AUTO) 6039f93ac8dSLABBE Corentin v |= EMAC_RX_FLOW_CTL_EN; 6049f93ac8dSLABBE Corentin else 6059f93ac8dSLABBE Corentin v &= ~EMAC_RX_FLOW_CTL_EN; 6069f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL0); 6079f93ac8dSLABBE Corentin 6089f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_FLOW_CTL); 6099f93ac8dSLABBE Corentin if (fc == FLOW_AUTO) 6109f93ac8dSLABBE Corentin v |= EMAC_TX_FLOW_CTL_EN; 6119f93ac8dSLABBE Corentin else 6129f93ac8dSLABBE Corentin v &= ~EMAC_TX_FLOW_CTL_EN; 6139f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_FLOW_CTL); 6149f93ac8dSLABBE Corentin } 6159f93ac8dSLABBE Corentin 6169f93ac8dSLABBE Corentin static int sun8i_dwmac_reset(struct stmmac_priv *priv) 6179f93ac8dSLABBE Corentin { 6189f93ac8dSLABBE Corentin u32 v; 6199f93ac8dSLABBE Corentin int err; 6209f93ac8dSLABBE Corentin 6219f93ac8dSLABBE Corentin v = readl(priv->ioaddr + EMAC_BASIC_CTL1); 6229f93ac8dSLABBE Corentin writel(v | 0x01, priv->ioaddr + EMAC_BASIC_CTL1); 6239f93ac8dSLABBE Corentin 6249f93ac8dSLABBE Corentin /* The timeout was previoulsy set to 10ms, but some board (OrangePI0) 6259f93ac8dSLABBE Corentin * need more if no cable plugged. 100ms seems OK 6269f93ac8dSLABBE Corentin */ 6279f93ac8dSLABBE Corentin err = readl_poll_timeout(priv->ioaddr + EMAC_BASIC_CTL1, v, 6289f93ac8dSLABBE Corentin !(v & 0x01), 100, 100000); 6299f93ac8dSLABBE Corentin 6309f93ac8dSLABBE Corentin if (err) { 6319f93ac8dSLABBE Corentin dev_err(priv->device, "EMAC reset timeout\n"); 6329f93ac8dSLABBE Corentin return -EFAULT; 6339f93ac8dSLABBE Corentin } 6349f93ac8dSLABBE Corentin return 0; 6359f93ac8dSLABBE Corentin } 6369f93ac8dSLABBE Corentin 6379f93ac8dSLABBE Corentin static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) 6389f93ac8dSLABBE Corentin { 6399f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 6409f93ac8dSLABBE Corentin struct device_node *node = priv->device->of_node; 6419f93ac8dSLABBE Corentin int ret; 6429f93ac8dSLABBE Corentin u32 reg, val; 6439f93ac8dSLABBE Corentin 6449f93ac8dSLABBE Corentin regmap_read(gmac->regmap, SYSCON_EMAC_REG, &val); 6459f93ac8dSLABBE Corentin reg = gmac->variant->default_syscon_value; 6469f93ac8dSLABBE Corentin if (reg != val) 6479f93ac8dSLABBE Corentin dev_warn(priv->device, 6489f93ac8dSLABBE Corentin "Current syscon value is not the default %x (expect %x)\n", 6499f93ac8dSLABBE Corentin val, reg); 6509f93ac8dSLABBE Corentin 6519f93ac8dSLABBE Corentin if (gmac->variant->internal_phy) { 6529f93ac8dSLABBE Corentin if (!gmac->use_internal_phy) { 6539f93ac8dSLABBE Corentin /* switch to external PHY interface */ 6549f93ac8dSLABBE Corentin reg &= ~H3_EPHY_SELECT; 6559f93ac8dSLABBE Corentin } else { 6569f93ac8dSLABBE Corentin reg |= H3_EPHY_SELECT; 6579f93ac8dSLABBE Corentin reg &= ~H3_EPHY_SHUTDOWN; 6589f93ac8dSLABBE Corentin dev_dbg(priv->device, "Select internal_phy %x\n", reg); 6599f93ac8dSLABBE Corentin 6609f93ac8dSLABBE Corentin if (of_property_read_bool(priv->plat->phy_node, 6619f93ac8dSLABBE Corentin "allwinner,leds-active-low")) 6629f93ac8dSLABBE Corentin reg |= H3_EPHY_LED_POL; 6639f93ac8dSLABBE Corentin else 6649f93ac8dSLABBE Corentin reg &= ~H3_EPHY_LED_POL; 6659f93ac8dSLABBE Corentin 6661450ba8aSIcenowy Zheng /* Force EPHY xtal frequency to 24MHz. */ 6671450ba8aSIcenowy Zheng reg |= H3_EPHY_CLK_SEL; 6681450ba8aSIcenowy Zheng 6699f93ac8dSLABBE Corentin ret = of_mdio_parse_addr(priv->device, 6709f93ac8dSLABBE Corentin priv->plat->phy_node); 6719f93ac8dSLABBE Corentin if (ret < 0) { 6729f93ac8dSLABBE Corentin dev_err(priv->device, "Could not parse MDIO addr\n"); 6739f93ac8dSLABBE Corentin return ret; 6749f93ac8dSLABBE Corentin } 6759f93ac8dSLABBE Corentin /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY 6769f93ac8dSLABBE Corentin * address. No need to mask it again. 6779f93ac8dSLABBE Corentin */ 6789f93ac8dSLABBE Corentin reg |= ret << H3_EPHY_ADDR_SHIFT; 6799f93ac8dSLABBE Corentin } 6809f93ac8dSLABBE Corentin } 6819f93ac8dSLABBE Corentin 6829f93ac8dSLABBE Corentin if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) { 6839f93ac8dSLABBE Corentin if (val % 100) { 6849f93ac8dSLABBE Corentin dev_err(priv->device, "tx-delay must be a multiple of 100\n"); 6859f93ac8dSLABBE Corentin return -EINVAL; 6869f93ac8dSLABBE Corentin } 6879f93ac8dSLABBE Corentin val /= 100; 6889f93ac8dSLABBE Corentin dev_dbg(priv->device, "set tx-delay to %x\n", val); 6899f93ac8dSLABBE Corentin if (val <= SYSCON_ETXDC_MASK) { 6909f93ac8dSLABBE Corentin reg &= ~(SYSCON_ETXDC_MASK << SYSCON_ETXDC_SHIFT); 6919f93ac8dSLABBE Corentin reg |= (val << SYSCON_ETXDC_SHIFT); 6929f93ac8dSLABBE Corentin } else { 6939f93ac8dSLABBE Corentin dev_err(priv->device, "Invalid TX clock delay: %d\n", 6949f93ac8dSLABBE Corentin val); 6959f93ac8dSLABBE Corentin return -EINVAL; 6969f93ac8dSLABBE Corentin } 6979f93ac8dSLABBE Corentin } 6989f93ac8dSLABBE Corentin 6999f93ac8dSLABBE Corentin if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) { 7009f93ac8dSLABBE Corentin if (val % 100) { 7019f93ac8dSLABBE Corentin dev_err(priv->device, "rx-delay must be a multiple of 100\n"); 7029f93ac8dSLABBE Corentin return -EINVAL; 7039f93ac8dSLABBE Corentin } 7049f93ac8dSLABBE Corentin val /= 100; 7059f93ac8dSLABBE Corentin dev_dbg(priv->device, "set rx-delay to %x\n", val); 7069f93ac8dSLABBE Corentin if (val <= SYSCON_ERXDC_MASK) { 7079f93ac8dSLABBE Corentin reg &= ~(SYSCON_ERXDC_MASK << SYSCON_ERXDC_SHIFT); 7089f93ac8dSLABBE Corentin reg |= (val << SYSCON_ERXDC_SHIFT); 7099f93ac8dSLABBE Corentin } else { 7109f93ac8dSLABBE Corentin dev_err(priv->device, "Invalid RX clock delay: %d\n", 7119f93ac8dSLABBE Corentin val); 7129f93ac8dSLABBE Corentin return -EINVAL; 7139f93ac8dSLABBE Corentin } 7149f93ac8dSLABBE Corentin } 7159f93ac8dSLABBE Corentin 7169f93ac8dSLABBE Corentin /* Clear interface mode bits */ 7179f93ac8dSLABBE Corentin reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT); 7189f93ac8dSLABBE Corentin if (gmac->variant->support_rmii) 7199f93ac8dSLABBE Corentin reg &= ~SYSCON_RMII_EN; 7209f93ac8dSLABBE Corentin 7219f93ac8dSLABBE Corentin switch (priv->plat->interface) { 7229f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_MII: 7239f93ac8dSLABBE Corentin /* default */ 7249f93ac8dSLABBE Corentin break; 7259f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_RGMII: 7269f93ac8dSLABBE Corentin reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; 7279f93ac8dSLABBE Corentin break; 7289f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_RMII: 7299f93ac8dSLABBE Corentin reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII; 7309f93ac8dSLABBE Corentin break; 7319f93ac8dSLABBE Corentin default: 7329f93ac8dSLABBE Corentin dev_err(priv->device, "Unsupported interface mode: %s", 7339f93ac8dSLABBE Corentin phy_modes(priv->plat->interface)); 7349f93ac8dSLABBE Corentin return -EINVAL; 7359f93ac8dSLABBE Corentin } 7369f93ac8dSLABBE Corentin 7379f93ac8dSLABBE Corentin regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg); 7389f93ac8dSLABBE Corentin 7399f93ac8dSLABBE Corentin return 0; 7409f93ac8dSLABBE Corentin } 7419f93ac8dSLABBE Corentin 7429f93ac8dSLABBE Corentin static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac) 7439f93ac8dSLABBE Corentin { 7449f93ac8dSLABBE Corentin u32 reg = gmac->variant->default_syscon_value; 7459f93ac8dSLABBE Corentin 7469f93ac8dSLABBE Corentin regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg); 7479f93ac8dSLABBE Corentin } 7489f93ac8dSLABBE Corentin 7499f93ac8dSLABBE Corentin static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv) 7509f93ac8dSLABBE Corentin { 7519f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 7529f93ac8dSLABBE Corentin int ret; 7539f93ac8dSLABBE Corentin 7549f93ac8dSLABBE Corentin if (!gmac->use_internal_phy) 7559f93ac8dSLABBE Corentin return 0; 7569f93ac8dSLABBE Corentin 7579f93ac8dSLABBE Corentin ret = clk_prepare_enable(gmac->ephy_clk); 7589f93ac8dSLABBE Corentin if (ret) { 7599f93ac8dSLABBE Corentin dev_err(priv->device, "Cannot enable ephy\n"); 7609f93ac8dSLABBE Corentin return ret; 7619f93ac8dSLABBE Corentin } 7629f93ac8dSLABBE Corentin 7632f878491SIcenowy Zheng /* Make sure the EPHY is properly reseted, as U-Boot may leave 7642f878491SIcenowy Zheng * it at deasserted state, and thus it may fail to reset EMAC. 7652f878491SIcenowy Zheng */ 7662f878491SIcenowy Zheng reset_control_assert(gmac->rst_ephy); 7672f878491SIcenowy Zheng 7689f93ac8dSLABBE Corentin ret = reset_control_deassert(gmac->rst_ephy); 7699f93ac8dSLABBE Corentin if (ret) { 7709f93ac8dSLABBE Corentin dev_err(priv->device, "Cannot deassert ephy\n"); 7719f93ac8dSLABBE Corentin clk_disable_unprepare(gmac->ephy_clk); 7729f93ac8dSLABBE Corentin return ret; 7739f93ac8dSLABBE Corentin } 7749f93ac8dSLABBE Corentin 7759f93ac8dSLABBE Corentin return 0; 7769f93ac8dSLABBE Corentin } 7779f93ac8dSLABBE Corentin 7789f93ac8dSLABBE Corentin static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac) 7799f93ac8dSLABBE Corentin { 7809f93ac8dSLABBE Corentin if (!gmac->use_internal_phy) 7819f93ac8dSLABBE Corentin return 0; 7829f93ac8dSLABBE Corentin 7839f93ac8dSLABBE Corentin clk_disable_unprepare(gmac->ephy_clk); 7849f93ac8dSLABBE Corentin reset_control_assert(gmac->rst_ephy); 7859f93ac8dSLABBE Corentin return 0; 7869f93ac8dSLABBE Corentin } 7879f93ac8dSLABBE Corentin 7889f93ac8dSLABBE Corentin /* sun8i_power_phy() - Activate the PHY: 7899f93ac8dSLABBE Corentin * In case of error, no need to call sun8i_unpower_phy(), 7909f93ac8dSLABBE Corentin * it will be called anyway by sun8i_dwmac_exit() 7919f93ac8dSLABBE Corentin */ 7929f93ac8dSLABBE Corentin static int sun8i_power_phy(struct stmmac_priv *priv) 7939f93ac8dSLABBE Corentin { 7949f93ac8dSLABBE Corentin int ret; 7959f93ac8dSLABBE Corentin 7969f93ac8dSLABBE Corentin ret = sun8i_dwmac_power_internal_phy(priv); 7979f93ac8dSLABBE Corentin if (ret) 7989f93ac8dSLABBE Corentin return ret; 7999f93ac8dSLABBE Corentin 8009f93ac8dSLABBE Corentin ret = sun8i_dwmac_set_syscon(priv); 8019f93ac8dSLABBE Corentin if (ret) 8029f93ac8dSLABBE Corentin return ret; 8039f93ac8dSLABBE Corentin 8049f93ac8dSLABBE Corentin /* After changing syscon value, the MAC need reset or it will use 8059f93ac8dSLABBE Corentin * the last value (and so the last PHY set. 8069f93ac8dSLABBE Corentin */ 8079f93ac8dSLABBE Corentin ret = sun8i_dwmac_reset(priv); 8089f93ac8dSLABBE Corentin if (ret) 8099f93ac8dSLABBE Corentin return ret; 8109f93ac8dSLABBE Corentin return 0; 8119f93ac8dSLABBE Corentin } 8129f93ac8dSLABBE Corentin 8139f93ac8dSLABBE Corentin static void sun8i_unpower_phy(struct sunxi_priv_data *gmac) 8149f93ac8dSLABBE Corentin { 8159f93ac8dSLABBE Corentin sun8i_dwmac_unset_syscon(gmac); 8169f93ac8dSLABBE Corentin sun8i_dwmac_unpower_internal_phy(gmac); 8179f93ac8dSLABBE Corentin } 8189f93ac8dSLABBE Corentin 8199f93ac8dSLABBE Corentin static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) 8209f93ac8dSLABBE Corentin { 8219f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv; 8229f93ac8dSLABBE Corentin 8239f93ac8dSLABBE Corentin sun8i_unpower_phy(gmac); 8249f93ac8dSLABBE Corentin 8259f93ac8dSLABBE Corentin clk_disable_unprepare(gmac->tx_clk); 8269f93ac8dSLABBE Corentin 8279f93ac8dSLABBE Corentin if (gmac->regulator) 8289f93ac8dSLABBE Corentin regulator_disable(gmac->regulator); 8299f93ac8dSLABBE Corentin } 8309f93ac8dSLABBE Corentin 8319f93ac8dSLABBE Corentin static const struct stmmac_ops sun8i_dwmac_ops = { 8329f93ac8dSLABBE Corentin .core_init = sun8i_dwmac_core_init, 8339f93ac8dSLABBE Corentin .set_mac = sun8i_dwmac_set_mac, 8349f93ac8dSLABBE Corentin .dump_regs = sun8i_dwmac_dump_mac_regs, 8359f93ac8dSLABBE Corentin .rx_ipc = sun8i_dwmac_rx_ipc_enable, 8369f93ac8dSLABBE Corentin .set_filter = sun8i_dwmac_set_filter, 8379f93ac8dSLABBE Corentin .flow_ctrl = sun8i_dwmac_flow_ctrl, 8389f93ac8dSLABBE Corentin .set_umac_addr = sun8i_dwmac_set_umac_addr, 8399f93ac8dSLABBE Corentin .get_umac_addr = sun8i_dwmac_get_umac_addr, 8409f93ac8dSLABBE Corentin }; 8419f93ac8dSLABBE Corentin 8429f93ac8dSLABBE Corentin static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) 8439f93ac8dSLABBE Corentin { 8449f93ac8dSLABBE Corentin struct mac_device_info *mac; 8459f93ac8dSLABBE Corentin struct stmmac_priv *priv = ppriv; 8469f93ac8dSLABBE Corentin int ret; 8479f93ac8dSLABBE Corentin 8489f93ac8dSLABBE Corentin mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); 8499f93ac8dSLABBE Corentin if (!mac) 8509f93ac8dSLABBE Corentin return NULL; 8519f93ac8dSLABBE Corentin 8529f93ac8dSLABBE Corentin ret = sun8i_power_phy(priv); 8539f93ac8dSLABBE Corentin if (ret) 8549f93ac8dSLABBE Corentin return NULL; 8559f93ac8dSLABBE Corentin 8569f93ac8dSLABBE Corentin mac->pcsr = priv->ioaddr; 8579f93ac8dSLABBE Corentin mac->mac = &sun8i_dwmac_ops; 8589f93ac8dSLABBE Corentin mac->dma = &sun8i_dwmac_dma_ops; 8599f93ac8dSLABBE Corentin 8609f93ac8dSLABBE Corentin /* The loopback bit seems to be re-set when link change 8619f93ac8dSLABBE Corentin * Simply mask it each time 8629f93ac8dSLABBE Corentin * Speed 10/100/1000 are set in BIT(2)/BIT(3) 8639f93ac8dSLABBE Corentin */ 8649f93ac8dSLABBE Corentin mac->link.speed_mask = GENMASK(3, 2) | EMAC_LOOPBACK; 8659f93ac8dSLABBE Corentin mac->link.speed10 = EMAC_SPEED_10; 8669f93ac8dSLABBE Corentin mac->link.speed100 = EMAC_SPEED_100; 8679f93ac8dSLABBE Corentin mac->link.speed1000 = EMAC_SPEED_1000; 8689f93ac8dSLABBE Corentin mac->link.duplex = EMAC_DUPLEX_FULL; 8699f93ac8dSLABBE Corentin mac->mii.addr = EMAC_MDIO_CMD; 8709f93ac8dSLABBE Corentin mac->mii.data = EMAC_MDIO_DATA; 8719f93ac8dSLABBE Corentin mac->mii.reg_shift = 4; 8729f93ac8dSLABBE Corentin mac->mii.reg_mask = GENMASK(8, 4); 8739f93ac8dSLABBE Corentin mac->mii.addr_shift = 12; 8749f93ac8dSLABBE Corentin mac->mii.addr_mask = GENMASK(16, 12); 8759f93ac8dSLABBE Corentin mac->mii.clk_csr_shift = 20; 8769f93ac8dSLABBE Corentin mac->mii.clk_csr_mask = GENMASK(22, 20); 8779f93ac8dSLABBE Corentin mac->unicast_filter_entries = 8; 8789f93ac8dSLABBE Corentin 8799f93ac8dSLABBE Corentin /* Synopsys Id is not available */ 8809f93ac8dSLABBE Corentin priv->synopsys_id = 0; 8819f93ac8dSLABBE Corentin 8829f93ac8dSLABBE Corentin return mac; 8839f93ac8dSLABBE Corentin } 8849f93ac8dSLABBE Corentin 8859f93ac8dSLABBE Corentin static int sun8i_dwmac_probe(struct platform_device *pdev) 8869f93ac8dSLABBE Corentin { 8879f93ac8dSLABBE Corentin struct plat_stmmacenet_data *plat_dat; 8889f93ac8dSLABBE Corentin struct stmmac_resources stmmac_res; 8899f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac; 8909f93ac8dSLABBE Corentin struct device *dev = &pdev->dev; 8919f93ac8dSLABBE Corentin int ret; 8929f93ac8dSLABBE Corentin 8939f93ac8dSLABBE Corentin ret = stmmac_get_platform_resources(pdev, &stmmac_res); 8949f93ac8dSLABBE Corentin if (ret) 8959f93ac8dSLABBE Corentin return ret; 8969f93ac8dSLABBE Corentin 8979f93ac8dSLABBE Corentin plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 8989f93ac8dSLABBE Corentin if (IS_ERR(plat_dat)) 8999f93ac8dSLABBE Corentin return PTR_ERR(plat_dat); 9009f93ac8dSLABBE Corentin 9019f93ac8dSLABBE Corentin gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); 9029f93ac8dSLABBE Corentin if (!gmac) 9039f93ac8dSLABBE Corentin return -ENOMEM; 9049f93ac8dSLABBE Corentin 9059f93ac8dSLABBE Corentin gmac->variant = of_device_get_match_data(&pdev->dev); 9069f93ac8dSLABBE Corentin if (!gmac->variant) { 9079f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Missing dwmac-sun8i variant\n"); 9089f93ac8dSLABBE Corentin return -EINVAL; 9099f93ac8dSLABBE Corentin } 9109f93ac8dSLABBE Corentin 9119f93ac8dSLABBE Corentin gmac->tx_clk = devm_clk_get(dev, "stmmaceth"); 9129f93ac8dSLABBE Corentin if (IS_ERR(gmac->tx_clk)) { 9139f93ac8dSLABBE Corentin dev_err(dev, "Could not get TX clock\n"); 9149f93ac8dSLABBE Corentin return PTR_ERR(gmac->tx_clk); 9159f93ac8dSLABBE Corentin } 9169f93ac8dSLABBE Corentin 9179f93ac8dSLABBE Corentin /* Optional regulator for PHY */ 9189f93ac8dSLABBE Corentin gmac->regulator = devm_regulator_get_optional(dev, "phy"); 9199f93ac8dSLABBE Corentin if (IS_ERR(gmac->regulator)) { 9209f93ac8dSLABBE Corentin if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) 9219f93ac8dSLABBE Corentin return -EPROBE_DEFER; 9229f93ac8dSLABBE Corentin dev_info(dev, "No regulator found\n"); 9239f93ac8dSLABBE Corentin gmac->regulator = NULL; 9249f93ac8dSLABBE Corentin } 9259f93ac8dSLABBE Corentin 9269f93ac8dSLABBE Corentin gmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 9279f93ac8dSLABBE Corentin "syscon"); 9289f93ac8dSLABBE Corentin if (IS_ERR(gmac->regmap)) { 9299f93ac8dSLABBE Corentin ret = PTR_ERR(gmac->regmap); 9309f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret); 9319f93ac8dSLABBE Corentin return ret; 9329f93ac8dSLABBE Corentin } 9339f93ac8dSLABBE Corentin 9349f93ac8dSLABBE Corentin plat_dat->interface = of_get_phy_mode(dev->of_node); 9359f93ac8dSLABBE Corentin if (plat_dat->interface == gmac->variant->internal_phy) { 9369f93ac8dSLABBE Corentin dev_info(&pdev->dev, "Will use internal PHY\n"); 9379f93ac8dSLABBE Corentin gmac->use_internal_phy = true; 9389f93ac8dSLABBE Corentin gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0); 9399f93ac8dSLABBE Corentin if (IS_ERR(gmac->ephy_clk)) { 9409f93ac8dSLABBE Corentin ret = PTR_ERR(gmac->ephy_clk); 9419f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret); 9429f93ac8dSLABBE Corentin return -EINVAL; 9439f93ac8dSLABBE Corentin } 9449f93ac8dSLABBE Corentin 9459f93ac8dSLABBE Corentin gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL); 9469f93ac8dSLABBE Corentin if (IS_ERR(gmac->rst_ephy)) { 9479f93ac8dSLABBE Corentin ret = PTR_ERR(gmac->rst_ephy); 9489f93ac8dSLABBE Corentin if (ret == -EPROBE_DEFER) 9499f93ac8dSLABBE Corentin return ret; 9509f93ac8dSLABBE Corentin dev_err(&pdev->dev, "No EPHY reset control found %d\n", 9519f93ac8dSLABBE Corentin ret); 9529f93ac8dSLABBE Corentin return -EINVAL; 9539f93ac8dSLABBE Corentin } 9549f93ac8dSLABBE Corentin } else { 9559f93ac8dSLABBE Corentin dev_info(&pdev->dev, "Will use external PHY\n"); 9569f93ac8dSLABBE Corentin gmac->use_internal_phy = false; 9579f93ac8dSLABBE Corentin } 9589f93ac8dSLABBE Corentin 9599f93ac8dSLABBE Corentin /* platform data specifying hardware features and callbacks. 9609f93ac8dSLABBE Corentin * hardware features were copied from Allwinner drivers. 9619f93ac8dSLABBE Corentin */ 9629f93ac8dSLABBE Corentin plat_dat->rx_coe = STMMAC_RX_COE_TYPE2; 9639f93ac8dSLABBE Corentin plat_dat->tx_coe = 1; 9649f93ac8dSLABBE Corentin plat_dat->has_sun8i = true; 9659f93ac8dSLABBE Corentin plat_dat->bsp_priv = gmac; 9669f93ac8dSLABBE Corentin plat_dat->init = sun8i_dwmac_init; 9679f93ac8dSLABBE Corentin plat_dat->exit = sun8i_dwmac_exit; 9689f93ac8dSLABBE Corentin plat_dat->setup = sun8i_dwmac_setup; 9699f93ac8dSLABBE Corentin 9709f93ac8dSLABBE Corentin ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv); 9719f93ac8dSLABBE Corentin if (ret) 9729f93ac8dSLABBE Corentin return ret; 9739f93ac8dSLABBE Corentin 9749f93ac8dSLABBE Corentin ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 9759f93ac8dSLABBE Corentin if (ret) 9769f93ac8dSLABBE Corentin sun8i_dwmac_exit(pdev, plat_dat->bsp_priv); 9779f93ac8dSLABBE Corentin 9789f93ac8dSLABBE Corentin return ret; 9799f93ac8dSLABBE Corentin } 9809f93ac8dSLABBE Corentin 9819f93ac8dSLABBE Corentin static const struct of_device_id sun8i_dwmac_match[] = { 9829f93ac8dSLABBE Corentin { .compatible = "allwinner,sun8i-h3-emac", 9839f93ac8dSLABBE Corentin .data = &emac_variant_h3 }, 984*57fde47dSIcenowy Zheng { .compatible = "allwinner,sun8i-v3s-emac", 985*57fde47dSIcenowy Zheng .data = &emac_variant_v3s }, 9869f93ac8dSLABBE Corentin { .compatible = "allwinner,sun8i-a83t-emac", 9879f93ac8dSLABBE Corentin .data = &emac_variant_a83t }, 9889f93ac8dSLABBE Corentin { .compatible = "allwinner,sun50i-a64-emac", 9899f93ac8dSLABBE Corentin .data = &emac_variant_a64 }, 9909f93ac8dSLABBE Corentin { } 9919f93ac8dSLABBE Corentin }; 9929f93ac8dSLABBE Corentin MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); 9939f93ac8dSLABBE Corentin 9949f93ac8dSLABBE Corentin static struct platform_driver sun8i_dwmac_driver = { 9959f93ac8dSLABBE Corentin .probe = sun8i_dwmac_probe, 9969f93ac8dSLABBE Corentin .remove = stmmac_pltfr_remove, 9979f93ac8dSLABBE Corentin .driver = { 9989f93ac8dSLABBE Corentin .name = "dwmac-sun8i", 9999f93ac8dSLABBE Corentin .pm = &stmmac_pltfr_pm_ops, 10009f93ac8dSLABBE Corentin .of_match_table = sun8i_dwmac_match, 10019f93ac8dSLABBE Corentin }, 10029f93ac8dSLABBE Corentin }; 10039f93ac8dSLABBE Corentin module_platform_driver(sun8i_dwmac_driver); 10049f93ac8dSLABBE Corentin 10059f93ac8dSLABBE Corentin MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>"); 10069f93ac8dSLABBE Corentin MODULE_DESCRIPTION("Allwinner sun8i DWMAC specific glue layer"); 10079f93ac8dSLABBE Corentin MODULE_LICENSE("GPL"); 1008