1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 29f93ac8dSLABBE Corentin /* 39f93ac8dSLABBE Corentin * dwmac-sun8i.c - Allwinner sun8i DWMAC specific glue layer 49f93ac8dSLABBE Corentin * 59f93ac8dSLABBE Corentin * Copyright (C) 2017 Corentin Labbe <clabbe.montjoie@gmail.com> 69f93ac8dSLABBE Corentin */ 79f93ac8dSLABBE Corentin 89f93ac8dSLABBE Corentin #include <linux/clk.h> 99f93ac8dSLABBE Corentin #include <linux/io.h> 109f93ac8dSLABBE Corentin #include <linux/iopoll.h> 11634db83bSCorentin Labbe #include <linux/mdio-mux.h> 129f93ac8dSLABBE Corentin #include <linux/mfd/syscon.h> 139f93ac8dSLABBE Corentin #include <linux/module.h> 14*3d40aed8SRob Herring #include <linux/of.h> 159f93ac8dSLABBE Corentin #include <linux/of_mdio.h> 169f93ac8dSLABBE Corentin #include <linux/of_net.h> 17*3d40aed8SRob Herring #include <linux/of_platform.h> 189f93ac8dSLABBE Corentin #include <linux/phy.h> 199f93ac8dSLABBE Corentin #include <linux/platform_device.h> 20b76bbb34SJisheng Zhang #include <linux/pm_runtime.h> 219f93ac8dSLABBE Corentin #include <linux/regulator/consumer.h> 229f93ac8dSLABBE Corentin #include <linux/regmap.h> 239f93ac8dSLABBE Corentin #include <linux/stmmac.h> 249f93ac8dSLABBE Corentin 259f93ac8dSLABBE Corentin #include "stmmac.h" 269f93ac8dSLABBE Corentin #include "stmmac_platform.h" 279f93ac8dSLABBE Corentin 289f93ac8dSLABBE Corentin /* General notes on dwmac-sun8i: 299f93ac8dSLABBE Corentin * Locking: no locking is necessary in this file because all necessary locking 309f93ac8dSLABBE Corentin * is done in the "stmmac files" 319f93ac8dSLABBE Corentin */ 329f93ac8dSLABBE Corentin 3356c266dcSCorentin Labbe /* struct emac_variant - Describe dwmac-sun8i hardware variant 349f93ac8dSLABBE Corentin * @default_syscon_value: The default value of the EMAC register in syscon 359f93ac8dSLABBE Corentin * This value is used for disabling properly EMAC 369f93ac8dSLABBE Corentin * and used as a good starting value in case of the 379f93ac8dSLABBE Corentin * boot process(uboot) leave some stuff. 3825ae15fbSChen-Yu Tsai * @syscon_field reg_field for the syscon's gmac register 39634db83bSCorentin Labbe * @soc_has_internal_phy: Does the MAC embed an internal PHY 409f93ac8dSLABBE Corentin * @support_mii: Does the MAC handle MII 419f93ac8dSLABBE Corentin * @support_rmii: Does the MAC handle RMII 429f93ac8dSLABBE Corentin * @support_rgmii: Does the MAC handle RGMII 437b270b72SChen-Yu Tsai * 447b270b72SChen-Yu Tsai * @rx_delay_max: Maximum raw value for RX delay chain 457b270b72SChen-Yu Tsai * @tx_delay_max: Maximum raw value for TX delay chain 467b270b72SChen-Yu Tsai * These two also indicate the bitmask for 477b270b72SChen-Yu Tsai * the RX and TX delay chain registers. A 487b270b72SChen-Yu Tsai * value of zero indicates this is not supported. 499f93ac8dSLABBE Corentin */ 509f93ac8dSLABBE Corentin struct emac_variant { 519f93ac8dSLABBE Corentin u32 default_syscon_value; 5225ae15fbSChen-Yu Tsai const struct reg_field *syscon_field; 53634db83bSCorentin Labbe bool soc_has_internal_phy; 549f93ac8dSLABBE Corentin bool support_mii; 559f93ac8dSLABBE Corentin bool support_rmii; 569f93ac8dSLABBE Corentin bool support_rgmii; 577b270b72SChen-Yu Tsai u8 rx_delay_max; 587b270b72SChen-Yu Tsai u8 tx_delay_max; 599f93ac8dSLABBE Corentin }; 609f93ac8dSLABBE Corentin 619f93ac8dSLABBE Corentin /* struct sunxi_priv_data - hold all sunxi private data 629f93ac8dSLABBE Corentin * @ephy_clk: reference to the optional EPHY clock for the internal PHY 639f93ac8dSLABBE Corentin * @regulator: reference to the optional regulator 649f93ac8dSLABBE Corentin * @rst_ephy: reference to the optional EPHY reset for the internal PHY 659f93ac8dSLABBE Corentin * @variant: reference to the current board variant 669f93ac8dSLABBE Corentin * @regmap: regmap for using the syscon 67634db83bSCorentin Labbe * @internal_phy_powered: Does the internal PHY is enabled 68b8239638SSamuel Holland * @use_internal_phy: Is the internal PHY selected for use 69634db83bSCorentin Labbe * @mux_handle: Internal pointer used by mdio-mux lib 709f93ac8dSLABBE Corentin */ 719f93ac8dSLABBE Corentin struct sunxi_priv_data { 729f93ac8dSLABBE Corentin struct clk *ephy_clk; 739f93ac8dSLABBE Corentin struct regulator *regulator; 749f93ac8dSLABBE Corentin struct reset_control *rst_ephy; 759f93ac8dSLABBE Corentin const struct emac_variant *variant; 7625ae15fbSChen-Yu Tsai struct regmap_field *regmap_field; 77634db83bSCorentin Labbe bool internal_phy_powered; 78b8239638SSamuel Holland bool use_internal_phy; 79634db83bSCorentin Labbe void *mux_handle; 809f93ac8dSLABBE Corentin }; 819f93ac8dSLABBE Corentin 8225ae15fbSChen-Yu Tsai /* EMAC clock register @ 0x30 in the "system control" address range */ 8325ae15fbSChen-Yu Tsai static const struct reg_field sun8i_syscon_reg_field = { 8425ae15fbSChen-Yu Tsai .reg = 0x30, 8525ae15fbSChen-Yu Tsai .lsb = 0, 8625ae15fbSChen-Yu Tsai .msb = 31, 8725ae15fbSChen-Yu Tsai }; 8825ae15fbSChen-Yu Tsai 899bf5085aSChen-Yu Tsai /* EMAC clock register @ 0x164 in the CCU address range */ 909bf5085aSChen-Yu Tsai static const struct reg_field sun8i_ccu_reg_field = { 919bf5085aSChen-Yu Tsai .reg = 0x164, 929bf5085aSChen-Yu Tsai .lsb = 0, 939bf5085aSChen-Yu Tsai .msb = 31, 949bf5085aSChen-Yu Tsai }; 959bf5085aSChen-Yu Tsai 969f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_h3 = { 979f93ac8dSLABBE Corentin .default_syscon_value = 0x58000, 9825ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 99634db83bSCorentin Labbe .soc_has_internal_phy = true, 1009f93ac8dSLABBE Corentin .support_mii = true, 1019f93ac8dSLABBE Corentin .support_rmii = true, 1027b270b72SChen-Yu Tsai .support_rgmii = true, 1037b270b72SChen-Yu Tsai .rx_delay_max = 31, 1047b270b72SChen-Yu Tsai .tx_delay_max = 7, 1059f93ac8dSLABBE Corentin }; 1069f93ac8dSLABBE Corentin 10757fde47dSIcenowy Zheng static const struct emac_variant emac_variant_v3s = { 10857fde47dSIcenowy Zheng .default_syscon_value = 0x38000, 10925ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 110634db83bSCorentin Labbe .soc_has_internal_phy = true, 11157fde47dSIcenowy Zheng .support_mii = true 11257fde47dSIcenowy Zheng }; 11357fde47dSIcenowy Zheng 1149f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_a83t = { 1159f93ac8dSLABBE Corentin .default_syscon_value = 0, 11625ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 117634db83bSCorentin Labbe .soc_has_internal_phy = false, 1189f93ac8dSLABBE Corentin .support_mii = true, 1197b270b72SChen-Yu Tsai .support_rgmii = true, 1207b270b72SChen-Yu Tsai .rx_delay_max = 31, 1217b270b72SChen-Yu Tsai .tx_delay_max = 7, 1229f93ac8dSLABBE Corentin }; 1239f93ac8dSLABBE Corentin 1249bf5085aSChen-Yu Tsai static const struct emac_variant emac_variant_r40 = { 1259bf5085aSChen-Yu Tsai .default_syscon_value = 0, 1269bf5085aSChen-Yu Tsai .syscon_field = &sun8i_ccu_reg_field, 1279bf5085aSChen-Yu Tsai .support_mii = true, 1289bf5085aSChen-Yu Tsai .support_rgmii = true, 1299bf5085aSChen-Yu Tsai .rx_delay_max = 7, 1309bf5085aSChen-Yu Tsai }; 1319bf5085aSChen-Yu Tsai 1329f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_a64 = { 1339f93ac8dSLABBE Corentin .default_syscon_value = 0, 13425ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 135634db83bSCorentin Labbe .soc_has_internal_phy = false, 1369f93ac8dSLABBE Corentin .support_mii = true, 1379f93ac8dSLABBE Corentin .support_rmii = true, 1387b270b72SChen-Yu Tsai .support_rgmii = true, 1397b270b72SChen-Yu Tsai .rx_delay_max = 31, 1407b270b72SChen-Yu Tsai .tx_delay_max = 7, 1419f93ac8dSLABBE Corentin }; 1429f93ac8dSLABBE Corentin 143adadd38cSIcenowy Zheng static const struct emac_variant emac_variant_h6 = { 144adadd38cSIcenowy Zheng .default_syscon_value = 0x50000, 145adadd38cSIcenowy Zheng .syscon_field = &sun8i_syscon_reg_field, 146adadd38cSIcenowy Zheng /* The "Internal PHY" of H6 is not on the die. It's on the 147adadd38cSIcenowy Zheng * co-packaged AC200 chip instead. 148adadd38cSIcenowy Zheng */ 149adadd38cSIcenowy Zheng .soc_has_internal_phy = false, 150adadd38cSIcenowy Zheng .support_mii = true, 151adadd38cSIcenowy Zheng .support_rmii = true, 152adadd38cSIcenowy Zheng .support_rgmii = true, 153adadd38cSIcenowy Zheng .rx_delay_max = 31, 154adadd38cSIcenowy Zheng .tx_delay_max = 7, 155adadd38cSIcenowy Zheng }; 156adadd38cSIcenowy Zheng 1579f93ac8dSLABBE Corentin #define EMAC_BASIC_CTL0 0x00 1589f93ac8dSLABBE Corentin #define EMAC_BASIC_CTL1 0x04 1599f93ac8dSLABBE Corentin #define EMAC_INT_STA 0x08 1609f93ac8dSLABBE Corentin #define EMAC_INT_EN 0x0C 1619f93ac8dSLABBE Corentin #define EMAC_TX_CTL0 0x10 1629f93ac8dSLABBE Corentin #define EMAC_TX_CTL1 0x14 1639f93ac8dSLABBE Corentin #define EMAC_TX_FLOW_CTL 0x1C 1649f93ac8dSLABBE Corentin #define EMAC_TX_DESC_LIST 0x20 1659f93ac8dSLABBE Corentin #define EMAC_RX_CTL0 0x24 1669f93ac8dSLABBE Corentin #define EMAC_RX_CTL1 0x28 1679f93ac8dSLABBE Corentin #define EMAC_RX_DESC_LIST 0x34 1689f93ac8dSLABBE Corentin #define EMAC_RX_FRM_FLT 0x38 1699f93ac8dSLABBE Corentin #define EMAC_MDIO_CMD 0x48 1709f93ac8dSLABBE Corentin #define EMAC_MDIO_DATA 0x4C 1719f93ac8dSLABBE Corentin #define EMAC_MACADDR_HI(reg) (0x50 + (reg) * 8) 1729f93ac8dSLABBE Corentin #define EMAC_MACADDR_LO(reg) (0x54 + (reg) * 8) 1739f93ac8dSLABBE Corentin #define EMAC_TX_DMA_STA 0xB0 1749f93ac8dSLABBE Corentin #define EMAC_TX_CUR_DESC 0xB4 1759f93ac8dSLABBE Corentin #define EMAC_TX_CUR_BUF 0xB8 1769f93ac8dSLABBE Corentin #define EMAC_RX_DMA_STA 0xC0 1779f93ac8dSLABBE Corentin #define EMAC_RX_CUR_DESC 0xC4 1789f93ac8dSLABBE Corentin #define EMAC_RX_CUR_BUF 0xC8 1799f93ac8dSLABBE Corentin 1809f93ac8dSLABBE Corentin /* Use in EMAC_BASIC_CTL0 */ 1819f93ac8dSLABBE Corentin #define EMAC_DUPLEX_FULL BIT(0) 1829f93ac8dSLABBE Corentin #define EMAC_LOOPBACK BIT(1) 1839f93ac8dSLABBE Corentin #define EMAC_SPEED_1000 0 1849f93ac8dSLABBE Corentin #define EMAC_SPEED_100 (0x03 << 2) 1859f93ac8dSLABBE Corentin #define EMAC_SPEED_10 (0x02 << 2) 1869f93ac8dSLABBE Corentin 1879f93ac8dSLABBE Corentin /* Use in EMAC_BASIC_CTL1 */ 1889f93ac8dSLABBE Corentin #define EMAC_BURSTLEN_SHIFT 24 1899f93ac8dSLABBE Corentin 1909f93ac8dSLABBE Corentin /* Used in EMAC_RX_FRM_FLT */ 1919f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_RXALL BIT(0) 1929f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_CTL BIT(13) 1939f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_MULTICAST BIT(16) 1949f93ac8dSLABBE Corentin 1959f93ac8dSLABBE Corentin /* Used in RX_CTL1*/ 1969f93ac8dSLABBE Corentin #define EMAC_RX_MD BIT(1) 197aa4c0c90SJoe Perches #define EMAC_RX_TH_MASK GENMASK(5, 4) 1989f93ac8dSLABBE Corentin #define EMAC_RX_TH_32 0 1999f93ac8dSLABBE Corentin #define EMAC_RX_TH_64 (0x1 << 4) 2009f93ac8dSLABBE Corentin #define EMAC_RX_TH_96 (0x2 << 4) 2019f93ac8dSLABBE Corentin #define EMAC_RX_TH_128 (0x3 << 4) 2029f93ac8dSLABBE Corentin #define EMAC_RX_DMA_EN BIT(30) 2039f93ac8dSLABBE Corentin #define EMAC_RX_DMA_START BIT(31) 2049f93ac8dSLABBE Corentin 2059f93ac8dSLABBE Corentin /* Used in TX_CTL1*/ 2069f93ac8dSLABBE Corentin #define EMAC_TX_MD BIT(1) 2079f93ac8dSLABBE Corentin #define EMAC_TX_NEXT_FRM BIT(2) 208aa4c0c90SJoe Perches #define EMAC_TX_TH_MASK GENMASK(10, 8) 2099f93ac8dSLABBE Corentin #define EMAC_TX_TH_64 0 2109f93ac8dSLABBE Corentin #define EMAC_TX_TH_128 (0x1 << 8) 2119f93ac8dSLABBE Corentin #define EMAC_TX_TH_192 (0x2 << 8) 2129f93ac8dSLABBE Corentin #define EMAC_TX_TH_256 (0x3 << 8) 2139f93ac8dSLABBE Corentin #define EMAC_TX_DMA_EN BIT(30) 2149f93ac8dSLABBE Corentin #define EMAC_TX_DMA_START BIT(31) 2159f93ac8dSLABBE Corentin 2169f93ac8dSLABBE Corentin /* Used in RX_CTL0 */ 2179f93ac8dSLABBE Corentin #define EMAC_RX_RECEIVER_EN BIT(31) 2189f93ac8dSLABBE Corentin #define EMAC_RX_DO_CRC BIT(27) 2199f93ac8dSLABBE Corentin #define EMAC_RX_FLOW_CTL_EN BIT(16) 2209f93ac8dSLABBE Corentin 2219f93ac8dSLABBE Corentin /* Used in TX_CTL0 */ 2229f93ac8dSLABBE Corentin #define EMAC_TX_TRANSMITTER_EN BIT(31) 2239f93ac8dSLABBE Corentin 2249f93ac8dSLABBE Corentin /* Used in EMAC_TX_FLOW_CTL */ 2259f93ac8dSLABBE Corentin #define EMAC_TX_FLOW_CTL_EN BIT(0) 2269f93ac8dSLABBE Corentin 2279f93ac8dSLABBE Corentin /* Used in EMAC_INT_STA */ 2289f93ac8dSLABBE Corentin #define EMAC_TX_INT BIT(0) 2299f93ac8dSLABBE Corentin #define EMAC_TX_DMA_STOP_INT BIT(1) 2309f93ac8dSLABBE Corentin #define EMAC_TX_BUF_UA_INT BIT(2) 2319f93ac8dSLABBE Corentin #define EMAC_TX_TIMEOUT_INT BIT(3) 2329f93ac8dSLABBE Corentin #define EMAC_TX_UNDERFLOW_INT BIT(4) 2339f93ac8dSLABBE Corentin #define EMAC_TX_EARLY_INT BIT(5) 2349f93ac8dSLABBE Corentin #define EMAC_RX_INT BIT(8) 2359f93ac8dSLABBE Corentin #define EMAC_RX_BUF_UA_INT BIT(9) 2369f93ac8dSLABBE Corentin #define EMAC_RX_DMA_STOP_INT BIT(10) 2379f93ac8dSLABBE Corentin #define EMAC_RX_TIMEOUT_INT BIT(11) 2389f93ac8dSLABBE Corentin #define EMAC_RX_OVERFLOW_INT BIT(12) 2399f93ac8dSLABBE Corentin #define EMAC_RX_EARLY_INT BIT(13) 2409f93ac8dSLABBE Corentin #define EMAC_RGMII_STA_INT BIT(16) 2419f93ac8dSLABBE Corentin 2427e1c520cSOng Boon Leong #define EMAC_INT_MSK_COMMON EMAC_RGMII_STA_INT 2437e1c520cSOng Boon Leong #define EMAC_INT_MSK_TX (EMAC_TX_INT | \ 2447e1c520cSOng Boon Leong EMAC_TX_DMA_STOP_INT | \ 2457e1c520cSOng Boon Leong EMAC_TX_BUF_UA_INT | \ 2467e1c520cSOng Boon Leong EMAC_TX_TIMEOUT_INT | \ 2477e1c520cSOng Boon Leong EMAC_TX_UNDERFLOW_INT | \ 2487e1c520cSOng Boon Leong EMAC_TX_EARLY_INT |\ 2497e1c520cSOng Boon Leong EMAC_INT_MSK_COMMON) 2507e1c520cSOng Boon Leong #define EMAC_INT_MSK_RX (EMAC_RX_INT | \ 2517e1c520cSOng Boon Leong EMAC_RX_BUF_UA_INT | \ 2527e1c520cSOng Boon Leong EMAC_RX_DMA_STOP_INT | \ 2537e1c520cSOng Boon Leong EMAC_RX_TIMEOUT_INT | \ 2547e1c520cSOng Boon Leong EMAC_RX_OVERFLOW_INT | \ 2557e1c520cSOng Boon Leong EMAC_RX_EARLY_INT | \ 2567e1c520cSOng Boon Leong EMAC_INT_MSK_COMMON) 2577e1c520cSOng Boon Leong 2589f93ac8dSLABBE Corentin #define MAC_ADDR_TYPE_DST BIT(31) 2599f93ac8dSLABBE Corentin 2609f93ac8dSLABBE Corentin /* H3 specific bits for EPHY */ 2619f93ac8dSLABBE Corentin #define H3_EPHY_ADDR_SHIFT 20 2621450ba8aSIcenowy Zheng #define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */ 2639f93ac8dSLABBE Corentin #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ 2649f93ac8dSLABBE Corentin #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ 2659f93ac8dSLABBE Corentin #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ 266634db83bSCorentin Labbe #define H3_EPHY_MUX_MASK (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT) 267634db83bSCorentin Labbe #define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID 1 268634db83bSCorentin Labbe #define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID 2 2699f93ac8dSLABBE Corentin 2709f93ac8dSLABBE Corentin /* H3/A64 specific bits */ 2719f93ac8dSLABBE Corentin #define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ 2729f93ac8dSLABBE Corentin 2739f93ac8dSLABBE Corentin /* Generic system control EMAC_CLK bits */ 2749f93ac8dSLABBE Corentin #define SYSCON_ETXDC_SHIFT 10 2759f93ac8dSLABBE Corentin #define SYSCON_ERXDC_SHIFT 5 2769f93ac8dSLABBE Corentin /* EMAC PHY Interface Type */ 2779f93ac8dSLABBE Corentin #define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ 2789f93ac8dSLABBE Corentin #define SYSCON_ETCS_MASK GENMASK(1, 0) 2799f93ac8dSLABBE Corentin #define SYSCON_ETCS_MII 0x0 2809f93ac8dSLABBE Corentin #define SYSCON_ETCS_EXT_GMII 0x1 2819f93ac8dSLABBE Corentin #define SYSCON_ETCS_INT_GMII 0x2 2829f93ac8dSLABBE Corentin 2839f93ac8dSLABBE Corentin /* sun8i_dwmac_dma_reset() - reset the EMAC 2849f93ac8dSLABBE Corentin * Called from stmmac via stmmac_dma_ops->reset 2859f93ac8dSLABBE Corentin */ 2869f93ac8dSLABBE Corentin static int sun8i_dwmac_dma_reset(void __iomem *ioaddr) 2879f93ac8dSLABBE Corentin { 2889f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_CTL1); 2899f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_TX_CTL1); 2909f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_FRM_FLT); 2919f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_DESC_LIST); 2929f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_TX_DESC_LIST); 2939f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_INT_EN); 2949f93ac8dSLABBE Corentin writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); 2959f93ac8dSLABBE Corentin return 0; 2969f93ac8dSLABBE Corentin } 2979f93ac8dSLABBE Corentin 2989f93ac8dSLABBE Corentin /* sun8i_dwmac_dma_init() - initialize the EMAC 2999f93ac8dSLABBE Corentin * Called from stmmac via stmmac_dma_ops->init 3009f93ac8dSLABBE Corentin */ 3019f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_init(void __iomem *ioaddr, 30224aaed0cSJose Abreu struct stmmac_dma_cfg *dma_cfg, int atds) 3039f93ac8dSLABBE Corentin { 3049f93ac8dSLABBE Corentin writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); 3059f93ac8dSLABBE Corentin writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); 3069f93ac8dSLABBE Corentin } 3079f93ac8dSLABBE Corentin 3081d84b487SAndrew Halaney static void sun8i_dwmac_dma_init_rx(struct stmmac_priv *priv, 3091d84b487SAndrew Halaney void __iomem *ioaddr, 31024aaed0cSJose Abreu struct stmmac_dma_cfg *dma_cfg, 31106a80a7dSJose Abreu dma_addr_t dma_rx_phy, u32 chan) 31224aaed0cSJose Abreu { 31324aaed0cSJose Abreu /* Write RX descriptors address */ 31406a80a7dSJose Abreu writel(lower_32_bits(dma_rx_phy), ioaddr + EMAC_RX_DESC_LIST); 31524aaed0cSJose Abreu } 31624aaed0cSJose Abreu 3171d84b487SAndrew Halaney static void sun8i_dwmac_dma_init_tx(struct stmmac_priv *priv, 3181d84b487SAndrew Halaney void __iomem *ioaddr, 31924aaed0cSJose Abreu struct stmmac_dma_cfg *dma_cfg, 32006a80a7dSJose Abreu dma_addr_t dma_tx_phy, u32 chan) 32124aaed0cSJose Abreu { 32224aaed0cSJose Abreu /* Write TX descriptors address */ 32306a80a7dSJose Abreu writel(lower_32_bits(dma_tx_phy), ioaddr + EMAC_TX_DESC_LIST); 32424aaed0cSJose Abreu } 32524aaed0cSJose Abreu 3269f93ac8dSLABBE Corentin /* sun8i_dwmac_dump_regs() - Dump EMAC address space 3279f93ac8dSLABBE Corentin * Called from stmmac_dma_ops->dump_regs 3289f93ac8dSLABBE Corentin * Used for ethtool 3299f93ac8dSLABBE Corentin */ 3301d84b487SAndrew Halaney static void sun8i_dwmac_dump_regs(struct stmmac_priv *priv, 3311d84b487SAndrew Halaney void __iomem *ioaddr, u32 *reg_space) 3329f93ac8dSLABBE Corentin { 3339f93ac8dSLABBE Corentin int i; 3349f93ac8dSLABBE Corentin 3359f93ac8dSLABBE Corentin for (i = 0; i < 0xC8; i += 4) { 3369f93ac8dSLABBE Corentin if (i == 0x32 || i == 0x3C) 3379f93ac8dSLABBE Corentin continue; 3389f93ac8dSLABBE Corentin reg_space[i / 4] = readl(ioaddr + i); 3399f93ac8dSLABBE Corentin } 3409f93ac8dSLABBE Corentin } 3419f93ac8dSLABBE Corentin 3429f93ac8dSLABBE Corentin /* sun8i_dwmac_dump_mac_regs() - Dump EMAC address space 3439f93ac8dSLABBE Corentin * Called from stmmac_ops->dump_regs 3449f93ac8dSLABBE Corentin * Used for ethtool 3459f93ac8dSLABBE Corentin */ 3469f93ac8dSLABBE Corentin static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw, 3479f93ac8dSLABBE Corentin u32 *reg_space) 3489f93ac8dSLABBE Corentin { 3499f93ac8dSLABBE Corentin int i; 3509f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 3519f93ac8dSLABBE Corentin 3529f93ac8dSLABBE Corentin for (i = 0; i < 0xC8; i += 4) { 3539f93ac8dSLABBE Corentin if (i == 0x32 || i == 0x3C) 3549f93ac8dSLABBE Corentin continue; 3559f93ac8dSLABBE Corentin reg_space[i / 4] = readl(ioaddr + i); 3569f93ac8dSLABBE Corentin } 3579f93ac8dSLABBE Corentin } 3589f93ac8dSLABBE Corentin 3591d84b487SAndrew Halaney static void sun8i_dwmac_enable_dma_irq(struct stmmac_priv *priv, 3601d84b487SAndrew Halaney void __iomem *ioaddr, u32 chan, 361021bd5e3SJose Abreu bool rx, bool tx) 3629f93ac8dSLABBE Corentin { 363021bd5e3SJose Abreu u32 value = readl(ioaddr + EMAC_INT_EN); 364021bd5e3SJose Abreu 365021bd5e3SJose Abreu if (rx) 366021bd5e3SJose Abreu value |= EMAC_RX_INT; 367021bd5e3SJose Abreu if (tx) 368021bd5e3SJose Abreu value |= EMAC_TX_INT; 369021bd5e3SJose Abreu 370021bd5e3SJose Abreu writel(value, ioaddr + EMAC_INT_EN); 3719f93ac8dSLABBE Corentin } 3729f93ac8dSLABBE Corentin 3731d84b487SAndrew Halaney static void sun8i_dwmac_disable_dma_irq(struct stmmac_priv *priv, 3741d84b487SAndrew Halaney void __iomem *ioaddr, u32 chan, 375021bd5e3SJose Abreu bool rx, bool tx) 3769f93ac8dSLABBE Corentin { 377021bd5e3SJose Abreu u32 value = readl(ioaddr + EMAC_INT_EN); 378021bd5e3SJose Abreu 379021bd5e3SJose Abreu if (rx) 380021bd5e3SJose Abreu value &= ~EMAC_RX_INT; 381021bd5e3SJose Abreu if (tx) 382021bd5e3SJose Abreu value &= ~EMAC_TX_INT; 383021bd5e3SJose Abreu 384021bd5e3SJose Abreu writel(value, ioaddr + EMAC_INT_EN); 3859f93ac8dSLABBE Corentin } 3869f93ac8dSLABBE Corentin 3871d84b487SAndrew Halaney static void sun8i_dwmac_dma_start_tx(struct stmmac_priv *priv, 3881d84b487SAndrew Halaney void __iomem *ioaddr, u32 chan) 3899f93ac8dSLABBE Corentin { 3909f93ac8dSLABBE Corentin u32 v; 3919f93ac8dSLABBE Corentin 3929f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 3939f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_START; 3949f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_EN; 3959f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 3969f93ac8dSLABBE Corentin } 3979f93ac8dSLABBE Corentin 3989f93ac8dSLABBE Corentin static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr) 3999f93ac8dSLABBE Corentin { 4009f93ac8dSLABBE Corentin u32 v; 4019f93ac8dSLABBE Corentin 4029f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 4039f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_START; 4049f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_EN; 4059f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 4069f93ac8dSLABBE Corentin } 4079f93ac8dSLABBE Corentin 4081d84b487SAndrew Halaney static void sun8i_dwmac_dma_stop_tx(struct stmmac_priv *priv, 4091d84b487SAndrew Halaney void __iomem *ioaddr, u32 chan) 4109f93ac8dSLABBE Corentin { 4119f93ac8dSLABBE Corentin u32 v; 4129f93ac8dSLABBE Corentin 4139f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 4149f93ac8dSLABBE Corentin v &= ~EMAC_TX_DMA_EN; 4159f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 4169f93ac8dSLABBE Corentin } 4179f93ac8dSLABBE Corentin 4181d84b487SAndrew Halaney static void sun8i_dwmac_dma_start_rx(struct stmmac_priv *priv, 4191d84b487SAndrew Halaney void __iomem *ioaddr, u32 chan) 4209f93ac8dSLABBE Corentin { 4219f93ac8dSLABBE Corentin u32 v; 4229f93ac8dSLABBE Corentin 4239f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 4249f93ac8dSLABBE Corentin v |= EMAC_RX_DMA_START; 4259f93ac8dSLABBE Corentin v |= EMAC_RX_DMA_EN; 4269f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 4279f93ac8dSLABBE Corentin } 4289f93ac8dSLABBE Corentin 4291d84b487SAndrew Halaney static void sun8i_dwmac_dma_stop_rx(struct stmmac_priv *priv, 4301d84b487SAndrew Halaney void __iomem *ioaddr, u32 chan) 4319f93ac8dSLABBE Corentin { 4329f93ac8dSLABBE Corentin u32 v; 4339f93ac8dSLABBE Corentin 4349f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 4359f93ac8dSLABBE Corentin v &= ~EMAC_RX_DMA_EN; 4369f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 4379f93ac8dSLABBE Corentin } 4389f93ac8dSLABBE Corentin 4391d84b487SAndrew Halaney static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, 4401d84b487SAndrew Halaney void __iomem *ioaddr, 4417e1c520cSOng Boon Leong struct stmmac_extra_stats *x, u32 chan, 4427e1c520cSOng Boon Leong u32 dir) 4439f93ac8dSLABBE Corentin { 444133466c3SJisheng Zhang struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; 445133466c3SJisheng Zhang struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; 4469f93ac8dSLABBE Corentin int ret = 0; 447133466c3SJisheng Zhang u32 v; 4489f93ac8dSLABBE Corentin 4499f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_INT_STA); 4509f93ac8dSLABBE Corentin 4517e1c520cSOng Boon Leong if (dir == DMA_DIR_RX) 4527e1c520cSOng Boon Leong v &= EMAC_INT_MSK_RX; 4537e1c520cSOng Boon Leong else if (dir == DMA_DIR_TX) 4547e1c520cSOng Boon Leong v &= EMAC_INT_MSK_TX; 4557e1c520cSOng Boon Leong 4569f93ac8dSLABBE Corentin if (v & EMAC_TX_INT) { 4579f93ac8dSLABBE Corentin ret |= handle_tx; 458133466c3SJisheng Zhang u64_stats_update_begin(&tx_q->txq_stats.syncp); 459133466c3SJisheng Zhang tx_q->txq_stats.tx_normal_irq_n++; 460133466c3SJisheng Zhang u64_stats_update_end(&tx_q->txq_stats.syncp); 4619f93ac8dSLABBE Corentin } 4629f93ac8dSLABBE Corentin 4639f93ac8dSLABBE Corentin if (v & EMAC_TX_DMA_STOP_INT) 4649f93ac8dSLABBE Corentin x->tx_process_stopped_irq++; 4659f93ac8dSLABBE Corentin 4669f93ac8dSLABBE Corentin if (v & EMAC_TX_BUF_UA_INT) 4679f93ac8dSLABBE Corentin x->tx_process_stopped_irq++; 4689f93ac8dSLABBE Corentin 4699f93ac8dSLABBE Corentin if (v & EMAC_TX_TIMEOUT_INT) 4709f93ac8dSLABBE Corentin ret |= tx_hard_error; 4719f93ac8dSLABBE Corentin 4729f93ac8dSLABBE Corentin if (v & EMAC_TX_UNDERFLOW_INT) { 4739f93ac8dSLABBE Corentin ret |= tx_hard_error; 4749f93ac8dSLABBE Corentin x->tx_undeflow_irq++; 4759f93ac8dSLABBE Corentin } 4769f93ac8dSLABBE Corentin 4779f93ac8dSLABBE Corentin if (v & EMAC_TX_EARLY_INT) 4789f93ac8dSLABBE Corentin x->tx_early_irq++; 4799f93ac8dSLABBE Corentin 4809f93ac8dSLABBE Corentin if (v & EMAC_RX_INT) { 4819f93ac8dSLABBE Corentin ret |= handle_rx; 482133466c3SJisheng Zhang u64_stats_update_begin(&rx_q->rxq_stats.syncp); 483133466c3SJisheng Zhang rx_q->rxq_stats.rx_normal_irq_n++; 484133466c3SJisheng Zhang u64_stats_update_end(&rx_q->rxq_stats.syncp); 4859f93ac8dSLABBE Corentin } 4869f93ac8dSLABBE Corentin 4879f93ac8dSLABBE Corentin if (v & EMAC_RX_BUF_UA_INT) 4889f93ac8dSLABBE Corentin x->rx_buf_unav_irq++; 4899f93ac8dSLABBE Corentin 4909f93ac8dSLABBE Corentin if (v & EMAC_RX_DMA_STOP_INT) 4919f93ac8dSLABBE Corentin x->rx_process_stopped_irq++; 4929f93ac8dSLABBE Corentin 4939f93ac8dSLABBE Corentin if (v & EMAC_RX_TIMEOUT_INT) 4949f93ac8dSLABBE Corentin ret |= tx_hard_error; 4959f93ac8dSLABBE Corentin 4969f93ac8dSLABBE Corentin if (v & EMAC_RX_OVERFLOW_INT) { 4979f93ac8dSLABBE Corentin ret |= tx_hard_error; 4989f93ac8dSLABBE Corentin x->rx_overflow_irq++; 4999f93ac8dSLABBE Corentin } 5009f93ac8dSLABBE Corentin 5019f93ac8dSLABBE Corentin if (v & EMAC_RX_EARLY_INT) 5029f93ac8dSLABBE Corentin x->rx_early_irq++; 5039f93ac8dSLABBE Corentin 5049f93ac8dSLABBE Corentin if (v & EMAC_RGMII_STA_INT) 5059f93ac8dSLABBE Corentin x->irq_rgmii_n++; 5069f93ac8dSLABBE Corentin 5079f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_INT_STA); 5089f93ac8dSLABBE Corentin 5099f93ac8dSLABBE Corentin return ret; 5109f93ac8dSLABBE Corentin } 5119f93ac8dSLABBE Corentin 5121d84b487SAndrew Halaney static void sun8i_dwmac_dma_operation_mode_rx(struct stmmac_priv *priv, 5131d84b487SAndrew Halaney void __iomem *ioaddr, int mode, 514ab0204e3SJose Abreu u32 channel, int fifosz, u8 qmode) 515ab0204e3SJose Abreu { 516ab0204e3SJose Abreu u32 v; 517ab0204e3SJose Abreu 518ab0204e3SJose Abreu v = readl(ioaddr + EMAC_RX_CTL1); 519ab0204e3SJose Abreu if (mode == SF_DMA_MODE) { 520ab0204e3SJose Abreu v |= EMAC_RX_MD; 521ab0204e3SJose Abreu } else { 522ab0204e3SJose Abreu v &= ~EMAC_RX_MD; 523ab0204e3SJose Abreu v &= ~EMAC_RX_TH_MASK; 524ab0204e3SJose Abreu if (mode < 32) 525ab0204e3SJose Abreu v |= EMAC_RX_TH_32; 526ab0204e3SJose Abreu else if (mode < 64) 527ab0204e3SJose Abreu v |= EMAC_RX_TH_64; 528ab0204e3SJose Abreu else if (mode < 96) 529ab0204e3SJose Abreu v |= EMAC_RX_TH_96; 530ab0204e3SJose Abreu else if (mode < 128) 531ab0204e3SJose Abreu v |= EMAC_RX_TH_128; 532ab0204e3SJose Abreu } 533ab0204e3SJose Abreu writel(v, ioaddr + EMAC_RX_CTL1); 534ab0204e3SJose Abreu } 535ab0204e3SJose Abreu 5361d84b487SAndrew Halaney static void sun8i_dwmac_dma_operation_mode_tx(struct stmmac_priv *priv, 5371d84b487SAndrew Halaney void __iomem *ioaddr, int mode, 538ab0204e3SJose Abreu u32 channel, int fifosz, u8 qmode) 5399f93ac8dSLABBE Corentin { 5409f93ac8dSLABBE Corentin u32 v; 5419f93ac8dSLABBE Corentin 5429f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 543ab0204e3SJose Abreu if (mode == SF_DMA_MODE) { 5449f93ac8dSLABBE Corentin v |= EMAC_TX_MD; 5459f93ac8dSLABBE Corentin /* Undocumented bit (called TX_NEXT_FRM in BSP), the original 5469f93ac8dSLABBE Corentin * comment is 5479f93ac8dSLABBE Corentin * "Operating on second frame increase the performance 5489f93ac8dSLABBE Corentin * especially when transmit store-and-forward is used." 5499f93ac8dSLABBE Corentin */ 5509f93ac8dSLABBE Corentin v |= EMAC_TX_NEXT_FRM; 5519f93ac8dSLABBE Corentin } else { 5529f93ac8dSLABBE Corentin v &= ~EMAC_TX_MD; 5539f93ac8dSLABBE Corentin v &= ~EMAC_TX_TH_MASK; 554ab0204e3SJose Abreu if (mode < 64) 5559f93ac8dSLABBE Corentin v |= EMAC_TX_TH_64; 556ab0204e3SJose Abreu else if (mode < 128) 5579f93ac8dSLABBE Corentin v |= EMAC_TX_TH_128; 558ab0204e3SJose Abreu else if (mode < 192) 5599f93ac8dSLABBE Corentin v |= EMAC_TX_TH_192; 560ab0204e3SJose Abreu else if (mode < 256) 5619f93ac8dSLABBE Corentin v |= EMAC_TX_TH_256; 5629f93ac8dSLABBE Corentin } 5639f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 5649f93ac8dSLABBE Corentin } 5659f93ac8dSLABBE Corentin 5669f93ac8dSLABBE Corentin static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { 5679f93ac8dSLABBE Corentin .reset = sun8i_dwmac_dma_reset, 5689f93ac8dSLABBE Corentin .init = sun8i_dwmac_dma_init, 56924aaed0cSJose Abreu .init_rx_chan = sun8i_dwmac_dma_init_rx, 57024aaed0cSJose Abreu .init_tx_chan = sun8i_dwmac_dma_init_tx, 5719f93ac8dSLABBE Corentin .dump_regs = sun8i_dwmac_dump_regs, 572ab0204e3SJose Abreu .dma_rx_mode = sun8i_dwmac_dma_operation_mode_rx, 573ab0204e3SJose Abreu .dma_tx_mode = sun8i_dwmac_dma_operation_mode_tx, 5749f93ac8dSLABBE Corentin .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission, 5759f93ac8dSLABBE Corentin .enable_dma_irq = sun8i_dwmac_enable_dma_irq, 5769f93ac8dSLABBE Corentin .disable_dma_irq = sun8i_dwmac_disable_dma_irq, 5779f93ac8dSLABBE Corentin .start_tx = sun8i_dwmac_dma_start_tx, 5789f93ac8dSLABBE Corentin .stop_tx = sun8i_dwmac_dma_stop_tx, 5799f93ac8dSLABBE Corentin .start_rx = sun8i_dwmac_dma_start_rx, 5809f93ac8dSLABBE Corentin .stop_rx = sun8i_dwmac_dma_stop_rx, 5819f93ac8dSLABBE Corentin .dma_interrupt = sun8i_dwmac_dma_interrupt, 5829f93ac8dSLABBE Corentin }; 5839f93ac8dSLABBE Corentin 584b8239638SSamuel Holland static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv); 585b8239638SSamuel Holland 5869f93ac8dSLABBE Corentin static int sun8i_dwmac_init(struct platform_device *pdev, void *priv) 5879f93ac8dSLABBE Corentin { 588b8239638SSamuel Holland struct net_device *ndev = platform_get_drvdata(pdev); 5899f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv; 5909f93ac8dSLABBE Corentin int ret; 5919f93ac8dSLABBE Corentin 5929f93ac8dSLABBE Corentin if (gmac->regulator) { 5939f93ac8dSLABBE Corentin ret = regulator_enable(gmac->regulator); 5949f93ac8dSLABBE Corentin if (ret) { 5959f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Fail to enable regulator\n"); 5969f93ac8dSLABBE Corentin return ret; 5979f93ac8dSLABBE Corentin } 5989f93ac8dSLABBE Corentin } 5999f93ac8dSLABBE Corentin 600b8239638SSamuel Holland if (gmac->use_internal_phy) { 601b8239638SSamuel Holland ret = sun8i_dwmac_power_internal_phy(netdev_priv(ndev)); 602b8239638SSamuel Holland if (ret) 603b76bbb34SJisheng Zhang goto err_disable_regulator; 6049f93ac8dSLABBE Corentin } 6059f93ac8dSLABBE Corentin 6069f93ac8dSLABBE Corentin return 0; 607b8239638SSamuel Holland 608b8239638SSamuel Holland err_disable_regulator: 609b8239638SSamuel Holland if (gmac->regulator) 610b8239638SSamuel Holland regulator_disable(gmac->regulator); 611b8239638SSamuel Holland 612b8239638SSamuel Holland return ret; 6139f93ac8dSLABBE Corentin } 6149f93ac8dSLABBE Corentin 6158cad443eSFlorian Fainelli static void sun8i_dwmac_core_init(struct mac_device_info *hw, 6168cad443eSFlorian Fainelli struct net_device *dev) 6179f93ac8dSLABBE Corentin { 6189f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6199f93ac8dSLABBE Corentin u32 v; 6209f93ac8dSLABBE Corentin 6219f93ac8dSLABBE Corentin v = (8 << EMAC_BURSTLEN_SHIFT); /* burst len */ 6229f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_BASIC_CTL1); 6239f93ac8dSLABBE Corentin } 6249f93ac8dSLABBE Corentin 6259f93ac8dSLABBE Corentin static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable) 6269f93ac8dSLABBE Corentin { 6279f93ac8dSLABBE Corentin u32 t, r; 6289f93ac8dSLABBE Corentin 6299f93ac8dSLABBE Corentin t = readl(ioaddr + EMAC_TX_CTL0); 6309f93ac8dSLABBE Corentin r = readl(ioaddr + EMAC_RX_CTL0); 6319f93ac8dSLABBE Corentin if (enable) { 6329f93ac8dSLABBE Corentin t |= EMAC_TX_TRANSMITTER_EN; 6339f93ac8dSLABBE Corentin r |= EMAC_RX_RECEIVER_EN; 6349f93ac8dSLABBE Corentin } else { 6359f93ac8dSLABBE Corentin t &= ~EMAC_TX_TRANSMITTER_EN; 6369f93ac8dSLABBE Corentin r &= ~EMAC_RX_RECEIVER_EN; 6379f93ac8dSLABBE Corentin } 6389f93ac8dSLABBE Corentin writel(t, ioaddr + EMAC_TX_CTL0); 6399f93ac8dSLABBE Corentin writel(r, ioaddr + EMAC_RX_CTL0); 6409f93ac8dSLABBE Corentin } 6419f93ac8dSLABBE Corentin 6429f93ac8dSLABBE Corentin /* Set MAC address at slot reg_n 6439f93ac8dSLABBE Corentin * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST 6449f93ac8dSLABBE Corentin * If addr is NULL, clear the slot 6459f93ac8dSLABBE Corentin */ 6469f93ac8dSLABBE Corentin static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw, 64776660757SJakub Kicinski const unsigned char *addr, 6489f93ac8dSLABBE Corentin unsigned int reg_n) 6499f93ac8dSLABBE Corentin { 6509f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6519f93ac8dSLABBE Corentin u32 v; 6529f93ac8dSLABBE Corentin 6539f93ac8dSLABBE Corentin if (!addr) { 6549f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_MACADDR_HI(reg_n)); 6559f93ac8dSLABBE Corentin return; 6569f93ac8dSLABBE Corentin } 6579f93ac8dSLABBE Corentin 6589f93ac8dSLABBE Corentin stmmac_set_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), 6599f93ac8dSLABBE Corentin EMAC_MACADDR_LO(reg_n)); 6609f93ac8dSLABBE Corentin if (reg_n > 0) { 6619f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_MACADDR_HI(reg_n)); 6629f93ac8dSLABBE Corentin v |= MAC_ADDR_TYPE_DST; 6639f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_MACADDR_HI(reg_n)); 6649f93ac8dSLABBE Corentin } 6659f93ac8dSLABBE Corentin } 6669f93ac8dSLABBE Corentin 6679f93ac8dSLABBE Corentin static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw, 6689f93ac8dSLABBE Corentin unsigned char *addr, 6699f93ac8dSLABBE Corentin unsigned int reg_n) 6709f93ac8dSLABBE Corentin { 6719f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6729f93ac8dSLABBE Corentin 6739f93ac8dSLABBE Corentin stmmac_get_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), 6749f93ac8dSLABBE Corentin EMAC_MACADDR_LO(reg_n)); 6759f93ac8dSLABBE Corentin } 6769f93ac8dSLABBE Corentin 6779f93ac8dSLABBE Corentin /* caution this function must return non 0 to work */ 6789f93ac8dSLABBE Corentin static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw) 6799f93ac8dSLABBE Corentin { 6809f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6819f93ac8dSLABBE Corentin u32 v; 6829f93ac8dSLABBE Corentin 6839f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL0); 6849f93ac8dSLABBE Corentin v |= EMAC_RX_DO_CRC; 6859f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL0); 6869f93ac8dSLABBE Corentin 6879f93ac8dSLABBE Corentin return 1; 6889f93ac8dSLABBE Corentin } 6899f93ac8dSLABBE Corentin 6909f93ac8dSLABBE Corentin static void sun8i_dwmac_set_filter(struct mac_device_info *hw, 6919f93ac8dSLABBE Corentin struct net_device *dev) 6929f93ac8dSLABBE Corentin { 6939f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6949f93ac8dSLABBE Corentin u32 v; 6959f93ac8dSLABBE Corentin int i = 1; 6969f93ac8dSLABBE Corentin struct netdev_hw_addr *ha; 6979f93ac8dSLABBE Corentin int macaddrs = netdev_uc_count(dev) + netdev_mc_count(dev) + 1; 6989f93ac8dSLABBE Corentin 6999f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_CTL; 7009f93ac8dSLABBE Corentin 7019f93ac8dSLABBE Corentin if (dev->flags & IFF_PROMISC) { 7029f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_RXALL; 7039f93ac8dSLABBE Corentin } else if (dev->flags & IFF_ALLMULTI) { 7049f93ac8dSLABBE Corentin v |= EMAC_FRM_FLT_MULTICAST; 7059f93ac8dSLABBE Corentin } else if (macaddrs <= hw->unicast_filter_entries) { 7069f93ac8dSLABBE Corentin if (!netdev_mc_empty(dev)) { 7079f93ac8dSLABBE Corentin netdev_for_each_mc_addr(ha, dev) { 7089f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, ha->addr, i); 7099f93ac8dSLABBE Corentin i++; 7109f93ac8dSLABBE Corentin } 7119f93ac8dSLABBE Corentin } 7129f93ac8dSLABBE Corentin if (!netdev_uc_empty(dev)) { 7139f93ac8dSLABBE Corentin netdev_for_each_uc_addr(ha, dev) { 7149f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, ha->addr, i); 7159f93ac8dSLABBE Corentin i++; 7169f93ac8dSLABBE Corentin } 7179f93ac8dSLABBE Corentin } 7189f93ac8dSLABBE Corentin } else { 71905908d72SMans Rullgard if (!(readl(ioaddr + EMAC_RX_FRM_FLT) & EMAC_FRM_FLT_RXALL)) 7209f93ac8dSLABBE Corentin netdev_info(dev, "Too many address, switching to promiscuous\n"); 7219f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_RXALL; 7229f93ac8dSLABBE Corentin } 7239f93ac8dSLABBE Corentin 7249f93ac8dSLABBE Corentin /* Disable unused address filter slots */ 7259f93ac8dSLABBE Corentin while (i < hw->unicast_filter_entries) 7269f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, NULL, i++); 7279f93ac8dSLABBE Corentin 7289f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_FRM_FLT); 7299f93ac8dSLABBE Corentin } 7309f93ac8dSLABBE Corentin 7319f93ac8dSLABBE Corentin static void sun8i_dwmac_flow_ctrl(struct mac_device_info *hw, 7329f93ac8dSLABBE Corentin unsigned int duplex, unsigned int fc, 7339f93ac8dSLABBE Corentin unsigned int pause_time, u32 tx_cnt) 7349f93ac8dSLABBE Corentin { 7359f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 7369f93ac8dSLABBE Corentin u32 v; 7379f93ac8dSLABBE Corentin 7389f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL0); 7399f93ac8dSLABBE Corentin if (fc == FLOW_AUTO) 7409f93ac8dSLABBE Corentin v |= EMAC_RX_FLOW_CTL_EN; 7419f93ac8dSLABBE Corentin else 7429f93ac8dSLABBE Corentin v &= ~EMAC_RX_FLOW_CTL_EN; 7439f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL0); 7449f93ac8dSLABBE Corentin 7459f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_FLOW_CTL); 7469f93ac8dSLABBE Corentin if (fc == FLOW_AUTO) 7479f93ac8dSLABBE Corentin v |= EMAC_TX_FLOW_CTL_EN; 7489f93ac8dSLABBE Corentin else 7499f93ac8dSLABBE Corentin v &= ~EMAC_TX_FLOW_CTL_EN; 7509f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_FLOW_CTL); 7519f93ac8dSLABBE Corentin } 7529f93ac8dSLABBE Corentin 7539f93ac8dSLABBE Corentin static int sun8i_dwmac_reset(struct stmmac_priv *priv) 7549f93ac8dSLABBE Corentin { 7559f93ac8dSLABBE Corentin u32 v; 7569f93ac8dSLABBE Corentin int err; 7579f93ac8dSLABBE Corentin 7589f93ac8dSLABBE Corentin v = readl(priv->ioaddr + EMAC_BASIC_CTL1); 7599f93ac8dSLABBE Corentin writel(v | 0x01, priv->ioaddr + EMAC_BASIC_CTL1); 7609f93ac8dSLABBE Corentin 7619f93ac8dSLABBE Corentin /* The timeout was previoulsy set to 10ms, but some board (OrangePI0) 7629f93ac8dSLABBE Corentin * need more if no cable plugged. 100ms seems OK 7639f93ac8dSLABBE Corentin */ 7649f93ac8dSLABBE Corentin err = readl_poll_timeout(priv->ioaddr + EMAC_BASIC_CTL1, v, 7659f93ac8dSLABBE Corentin !(v & 0x01), 100, 100000); 7669f93ac8dSLABBE Corentin 7679f93ac8dSLABBE Corentin if (err) { 7689f93ac8dSLABBE Corentin dev_err(priv->device, "EMAC reset timeout\n"); 7699e0db41eSJisheng Zhang return err; 7709f93ac8dSLABBE Corentin } 7719f93ac8dSLABBE Corentin return 0; 7729f93ac8dSLABBE Corentin } 7739f93ac8dSLABBE Corentin 774634db83bSCorentin Labbe /* Search in mdio-mux node for internal PHY node and get its clk/reset */ 775634db83bSCorentin Labbe static int get_ephy_nodes(struct stmmac_priv *priv) 776634db83bSCorentin Labbe { 777634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 778634db83bSCorentin Labbe struct device_node *mdio_mux, *iphynode; 779634db83bSCorentin Labbe struct device_node *mdio_internal; 780634db83bSCorentin Labbe int ret; 781634db83bSCorentin Labbe 782634db83bSCorentin Labbe mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux"); 783634db83bSCorentin Labbe if (!mdio_mux) { 784634db83bSCorentin Labbe dev_err(priv->device, "Cannot get mdio-mux node\n"); 785634db83bSCorentin Labbe return -ENODEV; 786634db83bSCorentin Labbe } 787634db83bSCorentin Labbe 788ac63043dSJohan Hovold mdio_internal = of_get_compatible_child(mdio_mux, 789634db83bSCorentin Labbe "allwinner,sun8i-h3-mdio-internal"); 790ac63043dSJohan Hovold of_node_put(mdio_mux); 791634db83bSCorentin Labbe if (!mdio_internal) { 792634db83bSCorentin Labbe dev_err(priv->device, "Cannot get internal_mdio node\n"); 793634db83bSCorentin Labbe return -ENODEV; 794634db83bSCorentin Labbe } 795634db83bSCorentin Labbe 796634db83bSCorentin Labbe /* Seek for internal PHY */ 797634db83bSCorentin Labbe for_each_child_of_node(mdio_internal, iphynode) { 798634db83bSCorentin Labbe gmac->ephy_clk = of_clk_get(iphynode, 0); 799634db83bSCorentin Labbe if (IS_ERR(gmac->ephy_clk)) 800634db83bSCorentin Labbe continue; 801634db83bSCorentin Labbe gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL); 802634db83bSCorentin Labbe if (IS_ERR(gmac->rst_ephy)) { 803634db83bSCorentin Labbe ret = PTR_ERR(gmac->rst_ephy); 804ac63043dSJohan Hovold if (ret == -EPROBE_DEFER) { 805ac63043dSJohan Hovold of_node_put(iphynode); 806ac63043dSJohan Hovold of_node_put(mdio_internal); 807634db83bSCorentin Labbe return ret; 808ac63043dSJohan Hovold } 809634db83bSCorentin Labbe continue; 810634db83bSCorentin Labbe } 811634db83bSCorentin Labbe dev_info(priv->device, "Found internal PHY node\n"); 812ac63043dSJohan Hovold of_node_put(iphynode); 813ac63043dSJohan Hovold of_node_put(mdio_internal); 814634db83bSCorentin Labbe return 0; 815634db83bSCorentin Labbe } 816ac63043dSJohan Hovold 817ac63043dSJohan Hovold of_node_put(mdio_internal); 818634db83bSCorentin Labbe return -ENODEV; 819634db83bSCorentin Labbe } 820634db83bSCorentin Labbe 821634db83bSCorentin Labbe static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv) 822634db83bSCorentin Labbe { 823634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 824634db83bSCorentin Labbe int ret; 825634db83bSCorentin Labbe 826634db83bSCorentin Labbe if (gmac->internal_phy_powered) { 827634db83bSCorentin Labbe dev_warn(priv->device, "Internal PHY already powered\n"); 828634db83bSCorentin Labbe return 0; 829634db83bSCorentin Labbe } 830634db83bSCorentin Labbe 831634db83bSCorentin Labbe dev_info(priv->device, "Powering internal PHY\n"); 832634db83bSCorentin Labbe ret = clk_prepare_enable(gmac->ephy_clk); 833634db83bSCorentin Labbe if (ret) { 834634db83bSCorentin Labbe dev_err(priv->device, "Cannot enable internal PHY\n"); 835634db83bSCorentin Labbe return ret; 836634db83bSCorentin Labbe } 837634db83bSCorentin Labbe 838634db83bSCorentin Labbe /* Make sure the EPHY is properly reseted, as U-Boot may leave 839634db83bSCorentin Labbe * it at deasserted state, and thus it may fail to reset EMAC. 8401c22f546SSamuel Holland * 8411c22f546SSamuel Holland * This assumes the driver has exclusive access to the EPHY reset. 842634db83bSCorentin Labbe */ 8431c22f546SSamuel Holland ret = reset_control_reset(gmac->rst_ephy); 844634db83bSCorentin Labbe if (ret) { 8451c22f546SSamuel Holland dev_err(priv->device, "Cannot reset internal PHY\n"); 846634db83bSCorentin Labbe clk_disable_unprepare(gmac->ephy_clk); 847634db83bSCorentin Labbe return ret; 848634db83bSCorentin Labbe } 849634db83bSCorentin Labbe 850634db83bSCorentin Labbe gmac->internal_phy_powered = true; 851634db83bSCorentin Labbe 852634db83bSCorentin Labbe return 0; 853634db83bSCorentin Labbe } 854634db83bSCorentin Labbe 855557ef2dfSSamuel Holland static void sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac) 856634db83bSCorentin Labbe { 857634db83bSCorentin Labbe if (!gmac->internal_phy_powered) 858557ef2dfSSamuel Holland return; 859634db83bSCorentin Labbe 860634db83bSCorentin Labbe clk_disable_unprepare(gmac->ephy_clk); 861634db83bSCorentin Labbe reset_control_assert(gmac->rst_ephy); 862634db83bSCorentin Labbe gmac->internal_phy_powered = false; 863634db83bSCorentin Labbe } 864634db83bSCorentin Labbe 865634db83bSCorentin Labbe /* MDIO multiplexing switch function 866634db83bSCorentin Labbe * This function is called by the mdio-mux layer when it thinks the mdio bus 867634db83bSCorentin Labbe * multiplexer needs to switch. 868634db83bSCorentin Labbe * 'current_child' is the current value of the mux register 869634db83bSCorentin Labbe * 'desired_child' is the value of the 'reg' property of the target child MDIO 870634db83bSCorentin Labbe * node. 871634db83bSCorentin Labbe * The first time this function is called, current_child == -1. 872634db83bSCorentin Labbe * If current_child == desired_child, then the mux is already set to the 873634db83bSCorentin Labbe * correct bus. 874634db83bSCorentin Labbe */ 875634db83bSCorentin Labbe static int mdio_mux_syscon_switch_fn(int current_child, int desired_child, 876634db83bSCorentin Labbe void *data) 877634db83bSCorentin Labbe { 878634db83bSCorentin Labbe struct stmmac_priv *priv = data; 879634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 880634db83bSCorentin Labbe u32 reg, val; 881634db83bSCorentin Labbe int ret = 0; 882634db83bSCorentin Labbe 883634db83bSCorentin Labbe if (current_child ^ desired_child) { 88425ae15fbSChen-Yu Tsai regmap_field_read(gmac->regmap_field, ®); 885634db83bSCorentin Labbe switch (desired_child) { 886634db83bSCorentin Labbe case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID: 887634db83bSCorentin Labbe dev_info(priv->device, "Switch mux to internal PHY"); 888634db83bSCorentin Labbe val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT; 889b8239638SSamuel Holland gmac->use_internal_phy = true; 890634db83bSCorentin Labbe break; 891634db83bSCorentin Labbe case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID: 892634db83bSCorentin Labbe dev_info(priv->device, "Switch mux to external PHY"); 893634db83bSCorentin Labbe val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN; 894b8239638SSamuel Holland gmac->use_internal_phy = false; 895634db83bSCorentin Labbe break; 896634db83bSCorentin Labbe default: 897634db83bSCorentin Labbe dev_err(priv->device, "Invalid child ID %x\n", 898634db83bSCorentin Labbe desired_child); 899634db83bSCorentin Labbe return -EINVAL; 900634db83bSCorentin Labbe } 90125ae15fbSChen-Yu Tsai regmap_field_write(gmac->regmap_field, val); 902b8239638SSamuel Holland if (gmac->use_internal_phy) { 903634db83bSCorentin Labbe ret = sun8i_dwmac_power_internal_phy(priv); 904634db83bSCorentin Labbe if (ret) 905634db83bSCorentin Labbe return ret; 906634db83bSCorentin Labbe } else { 907634db83bSCorentin Labbe sun8i_dwmac_unpower_internal_phy(gmac); 908634db83bSCorentin Labbe } 909634db83bSCorentin Labbe /* After changing syscon value, the MAC need reset or it will 910634db83bSCorentin Labbe * use the last value (and so the last PHY set). 911634db83bSCorentin Labbe */ 912634db83bSCorentin Labbe ret = sun8i_dwmac_reset(priv); 913634db83bSCorentin Labbe } 914634db83bSCorentin Labbe return ret; 915634db83bSCorentin Labbe } 916634db83bSCorentin Labbe 917634db83bSCorentin Labbe static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv) 918634db83bSCorentin Labbe { 919634db83bSCorentin Labbe int ret; 920634db83bSCorentin Labbe struct device_node *mdio_mux; 921634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 922634db83bSCorentin Labbe 923634db83bSCorentin Labbe mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux"); 924634db83bSCorentin Labbe if (!mdio_mux) 925634db83bSCorentin Labbe return -ENODEV; 926634db83bSCorentin Labbe 927634db83bSCorentin Labbe ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn, 928634db83bSCorentin Labbe &gmac->mux_handle, priv, priv->mii); 9291a15267bSYang Yingliang of_node_put(mdio_mux); 930634db83bSCorentin Labbe return ret; 931634db83bSCorentin Labbe } 932634db83bSCorentin Labbe 9339b1e39cfSSamuel Holland static int sun8i_dwmac_set_syscon(struct device *dev, 9349b1e39cfSSamuel Holland struct plat_stmmacenet_data *plat) 9359f93ac8dSLABBE Corentin { 9369b1e39cfSSamuel Holland struct sunxi_priv_data *gmac = plat->bsp_priv; 9379b1e39cfSSamuel Holland struct device_node *node = dev->of_node; 938d93b07f8SLABBE Corentin int ret; 9399f93ac8dSLABBE Corentin u32 reg, val; 9409f93ac8dSLABBE Corentin 941e33b4325SYizhuo ret = regmap_field_read(gmac->regmap_field, &val); 942e33b4325SYizhuo if (ret) { 9439b1e39cfSSamuel Holland dev_err(dev, "Fail to read from regmap field.\n"); 944e33b4325SYizhuo return ret; 945e33b4325SYizhuo } 946e33b4325SYizhuo 9479f93ac8dSLABBE Corentin reg = gmac->variant->default_syscon_value; 9489f93ac8dSLABBE Corentin if (reg != val) 9499b1e39cfSSamuel Holland dev_warn(dev, 9509f93ac8dSLABBE Corentin "Current syscon value is not the default %x (expect %x)\n", 9519f93ac8dSLABBE Corentin val, reg); 9529f93ac8dSLABBE Corentin 953634db83bSCorentin Labbe if (gmac->variant->soc_has_internal_phy) { 9541c08ac0cSCorentin Labbe if (of_property_read_bool(node, "allwinner,leds-active-low")) 9559f93ac8dSLABBE Corentin reg |= H3_EPHY_LED_POL; 9569f93ac8dSLABBE Corentin else 9579f93ac8dSLABBE Corentin reg &= ~H3_EPHY_LED_POL; 9589f93ac8dSLABBE Corentin 9591450ba8aSIcenowy Zheng /* Force EPHY xtal frequency to 24MHz. */ 9601450ba8aSIcenowy Zheng reg |= H3_EPHY_CLK_SEL; 9611450ba8aSIcenowy Zheng 9629b1e39cfSSamuel Holland ret = of_mdio_parse_addr(dev, plat->phy_node); 9639f93ac8dSLABBE Corentin if (ret < 0) { 9649b1e39cfSSamuel Holland dev_err(dev, "Could not parse MDIO addr\n"); 9659f93ac8dSLABBE Corentin return ret; 9669f93ac8dSLABBE Corentin } 9679f93ac8dSLABBE Corentin /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY 9689f93ac8dSLABBE Corentin * address. No need to mask it again. 9699f93ac8dSLABBE Corentin */ 970634db83bSCorentin Labbe reg |= 1 << H3_EPHY_ADDR_SHIFT; 9710fec7e72SIcenowy Zheng } else { 9720fec7e72SIcenowy Zheng /* For SoCs without internal PHY the PHY selection bit should be 9730fec7e72SIcenowy Zheng * set to 0 (external PHY). 9740fec7e72SIcenowy Zheng */ 9750fec7e72SIcenowy Zheng reg &= ~H3_EPHY_SELECT; 9769f93ac8dSLABBE Corentin } 9779f93ac8dSLABBE Corentin 9789f93ac8dSLABBE Corentin if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) { 9799f93ac8dSLABBE Corentin if (val % 100) { 9809b1e39cfSSamuel Holland dev_err(dev, "tx-delay must be a multiple of 100\n"); 9819f93ac8dSLABBE Corentin return -EINVAL; 9829f93ac8dSLABBE Corentin } 9839f93ac8dSLABBE Corentin val /= 100; 9849b1e39cfSSamuel Holland dev_dbg(dev, "set tx-delay to %x\n", val); 9857b270b72SChen-Yu Tsai if (val <= gmac->variant->tx_delay_max) { 9867b270b72SChen-Yu Tsai reg &= ~(gmac->variant->tx_delay_max << 9877b270b72SChen-Yu Tsai SYSCON_ETXDC_SHIFT); 9889f93ac8dSLABBE Corentin reg |= (val << SYSCON_ETXDC_SHIFT); 9899f93ac8dSLABBE Corentin } else { 9909b1e39cfSSamuel Holland dev_err(dev, "Invalid TX clock delay: %d\n", 9919f93ac8dSLABBE Corentin val); 9929f93ac8dSLABBE Corentin return -EINVAL; 9939f93ac8dSLABBE Corentin } 9949f93ac8dSLABBE Corentin } 9959f93ac8dSLABBE Corentin 9969f93ac8dSLABBE Corentin if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) { 9979f93ac8dSLABBE Corentin if (val % 100) { 9989b1e39cfSSamuel Holland dev_err(dev, "rx-delay must be a multiple of 100\n"); 9999f93ac8dSLABBE Corentin return -EINVAL; 10009f93ac8dSLABBE Corentin } 10019f93ac8dSLABBE Corentin val /= 100; 10029b1e39cfSSamuel Holland dev_dbg(dev, "set rx-delay to %x\n", val); 10037b270b72SChen-Yu Tsai if (val <= gmac->variant->rx_delay_max) { 10047b270b72SChen-Yu Tsai reg &= ~(gmac->variant->rx_delay_max << 10057b270b72SChen-Yu Tsai SYSCON_ERXDC_SHIFT); 10069f93ac8dSLABBE Corentin reg |= (val << SYSCON_ERXDC_SHIFT); 10079f93ac8dSLABBE Corentin } else { 10089b1e39cfSSamuel Holland dev_err(dev, "Invalid RX clock delay: %d\n", 10099f93ac8dSLABBE Corentin val); 10109f93ac8dSLABBE Corentin return -EINVAL; 10119f93ac8dSLABBE Corentin } 10129f93ac8dSLABBE Corentin } 10139f93ac8dSLABBE Corentin 10149f93ac8dSLABBE Corentin /* Clear interface mode bits */ 10159f93ac8dSLABBE Corentin reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT); 10169f93ac8dSLABBE Corentin if (gmac->variant->support_rmii) 10179f93ac8dSLABBE Corentin reg &= ~SYSCON_RMII_EN; 10189f93ac8dSLABBE Corentin 10199b1e39cfSSamuel Holland switch (plat->interface) { 10209f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_MII: 10219f93ac8dSLABBE Corentin /* default */ 10229f93ac8dSLABBE Corentin break; 10239f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_RGMII: 1024f1239d8aSChen-Yu Tsai case PHY_INTERFACE_MODE_RGMII_ID: 1025f1239d8aSChen-Yu Tsai case PHY_INTERFACE_MODE_RGMII_RXID: 1026f1239d8aSChen-Yu Tsai case PHY_INTERFACE_MODE_RGMII_TXID: 10279f93ac8dSLABBE Corentin reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; 10289f93ac8dSLABBE Corentin break; 10299f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_RMII: 10309f93ac8dSLABBE Corentin reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII; 10319f93ac8dSLABBE Corentin break; 10329f93ac8dSLABBE Corentin default: 10339b1e39cfSSamuel Holland dev_err(dev, "Unsupported interface mode: %s", 10349b1e39cfSSamuel Holland phy_modes(plat->interface)); 10359f93ac8dSLABBE Corentin return -EINVAL; 10369f93ac8dSLABBE Corentin } 10379f93ac8dSLABBE Corentin 103825ae15fbSChen-Yu Tsai regmap_field_write(gmac->regmap_field, reg); 10399f93ac8dSLABBE Corentin 10409f93ac8dSLABBE Corentin return 0; 10419f93ac8dSLABBE Corentin } 10429f93ac8dSLABBE Corentin 10439f93ac8dSLABBE Corentin static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac) 10449f93ac8dSLABBE Corentin { 10459f93ac8dSLABBE Corentin u32 reg = gmac->variant->default_syscon_value; 10469f93ac8dSLABBE Corentin 104725ae15fbSChen-Yu Tsai regmap_field_write(gmac->regmap_field, reg); 10489f93ac8dSLABBE Corentin } 10499f93ac8dSLABBE Corentin 10509f93ac8dSLABBE Corentin static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) 10519f93ac8dSLABBE Corentin { 10529f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv; 10539f93ac8dSLABBE Corentin 1054afac1d34SSamuel Holland if (gmac->variant->soc_has_internal_phy) 1055634db83bSCorentin Labbe sun8i_dwmac_unpower_internal_phy(gmac); 1056634db83bSCorentin Labbe 10579f93ac8dSLABBE Corentin if (gmac->regulator) 10589f93ac8dSLABBE Corentin regulator_disable(gmac->regulator); 10599f93ac8dSLABBE Corentin } 10609f93ac8dSLABBE Corentin 10618edb1271SCorentin Labbe static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable) 10628edb1271SCorentin Labbe { 10638edb1271SCorentin Labbe u32 value = readl(ioaddr + EMAC_BASIC_CTL0); 10648edb1271SCorentin Labbe 10658edb1271SCorentin Labbe if (enable) 10668edb1271SCorentin Labbe value |= EMAC_LOOPBACK; 10678edb1271SCorentin Labbe else 10688edb1271SCorentin Labbe value &= ~EMAC_LOOPBACK; 10698edb1271SCorentin Labbe 10708edb1271SCorentin Labbe writel(value, ioaddr + EMAC_BASIC_CTL0); 10718edb1271SCorentin Labbe } 10728edb1271SCorentin Labbe 10739f93ac8dSLABBE Corentin static const struct stmmac_ops sun8i_dwmac_ops = { 10749f93ac8dSLABBE Corentin .core_init = sun8i_dwmac_core_init, 10759f93ac8dSLABBE Corentin .set_mac = sun8i_dwmac_set_mac, 10769f93ac8dSLABBE Corentin .dump_regs = sun8i_dwmac_dump_mac_regs, 10779f93ac8dSLABBE Corentin .rx_ipc = sun8i_dwmac_rx_ipc_enable, 10789f93ac8dSLABBE Corentin .set_filter = sun8i_dwmac_set_filter, 10799f93ac8dSLABBE Corentin .flow_ctrl = sun8i_dwmac_flow_ctrl, 10809f93ac8dSLABBE Corentin .set_umac_addr = sun8i_dwmac_set_umac_addr, 10819f93ac8dSLABBE Corentin .get_umac_addr = sun8i_dwmac_get_umac_addr, 10828edb1271SCorentin Labbe .set_mac_loopback = sun8i_dwmac_set_mac_loopback, 10839f93ac8dSLABBE Corentin }; 10849f93ac8dSLABBE Corentin 10859f93ac8dSLABBE Corentin static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) 10869f93ac8dSLABBE Corentin { 10879f93ac8dSLABBE Corentin struct mac_device_info *mac; 10889f93ac8dSLABBE Corentin struct stmmac_priv *priv = ppriv; 10899f93ac8dSLABBE Corentin 10909f93ac8dSLABBE Corentin mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); 10919f93ac8dSLABBE Corentin if (!mac) 10929f93ac8dSLABBE Corentin return NULL; 10939f93ac8dSLABBE Corentin 10949f93ac8dSLABBE Corentin mac->pcsr = priv->ioaddr; 10959f93ac8dSLABBE Corentin mac->mac = &sun8i_dwmac_ops; 10969f93ac8dSLABBE Corentin mac->dma = &sun8i_dwmac_dma_ops; 10979f93ac8dSLABBE Corentin 1098d4c26eb6SCorentin Labbe priv->dev->priv_flags |= IFF_UNICAST_FLT; 1099d4c26eb6SCorentin Labbe 11009f93ac8dSLABBE Corentin /* The loopback bit seems to be re-set when link change 11019f93ac8dSLABBE Corentin * Simply mask it each time 11029f93ac8dSLABBE Corentin * Speed 10/100/1000 are set in BIT(2)/BIT(3) 11039f93ac8dSLABBE Corentin */ 11049f93ac8dSLABBE Corentin mac->link.speed_mask = GENMASK(3, 2) | EMAC_LOOPBACK; 11059f93ac8dSLABBE Corentin mac->link.speed10 = EMAC_SPEED_10; 11069f93ac8dSLABBE Corentin mac->link.speed100 = EMAC_SPEED_100; 11079f93ac8dSLABBE Corentin mac->link.speed1000 = EMAC_SPEED_1000; 11089f93ac8dSLABBE Corentin mac->link.duplex = EMAC_DUPLEX_FULL; 11099f93ac8dSLABBE Corentin mac->mii.addr = EMAC_MDIO_CMD; 11109f93ac8dSLABBE Corentin mac->mii.data = EMAC_MDIO_DATA; 11119f93ac8dSLABBE Corentin mac->mii.reg_shift = 4; 11129f93ac8dSLABBE Corentin mac->mii.reg_mask = GENMASK(8, 4); 11139f93ac8dSLABBE Corentin mac->mii.addr_shift = 12; 11149f93ac8dSLABBE Corentin mac->mii.addr_mask = GENMASK(16, 12); 11159f93ac8dSLABBE Corentin mac->mii.clk_csr_shift = 20; 11169f93ac8dSLABBE Corentin mac->mii.clk_csr_mask = GENMASK(22, 20); 11179f93ac8dSLABBE Corentin mac->unicast_filter_entries = 8; 11189f93ac8dSLABBE Corentin 11199f93ac8dSLABBE Corentin /* Synopsys Id is not available */ 11209f93ac8dSLABBE Corentin priv->synopsys_id = 0; 11219f93ac8dSLABBE Corentin 11229f93ac8dSLABBE Corentin return mac; 11239f93ac8dSLABBE Corentin } 11249f93ac8dSLABBE Corentin 112549a06caeSChen-Yu Tsai static struct regmap *sun8i_dwmac_get_syscon_from_dev(struct device_node *node) 112649a06caeSChen-Yu Tsai { 112749a06caeSChen-Yu Tsai struct device_node *syscon_node; 112849a06caeSChen-Yu Tsai struct platform_device *syscon_pdev; 112949a06caeSChen-Yu Tsai struct regmap *regmap = NULL; 113049a06caeSChen-Yu Tsai 113149a06caeSChen-Yu Tsai syscon_node = of_parse_phandle(node, "syscon", 0); 113249a06caeSChen-Yu Tsai if (!syscon_node) 113349a06caeSChen-Yu Tsai return ERR_PTR(-ENODEV); 113449a06caeSChen-Yu Tsai 113549a06caeSChen-Yu Tsai syscon_pdev = of_find_device_by_node(syscon_node); 113649a06caeSChen-Yu Tsai if (!syscon_pdev) { 113749a06caeSChen-Yu Tsai /* platform device might not be probed yet */ 113849a06caeSChen-Yu Tsai regmap = ERR_PTR(-EPROBE_DEFER); 113949a06caeSChen-Yu Tsai goto out_put_node; 114049a06caeSChen-Yu Tsai } 114149a06caeSChen-Yu Tsai 114249a06caeSChen-Yu Tsai /* If no regmap is found then the other device driver is at fault */ 114349a06caeSChen-Yu Tsai regmap = dev_get_regmap(&syscon_pdev->dev, NULL); 114449a06caeSChen-Yu Tsai if (!regmap) 114549a06caeSChen-Yu Tsai regmap = ERR_PTR(-EINVAL); 114649a06caeSChen-Yu Tsai 114749a06caeSChen-Yu Tsai platform_device_put(syscon_pdev); 114849a06caeSChen-Yu Tsai out_put_node: 114949a06caeSChen-Yu Tsai of_node_put(syscon_node); 115049a06caeSChen-Yu Tsai return regmap; 115149a06caeSChen-Yu Tsai } 115249a06caeSChen-Yu Tsai 11539f93ac8dSLABBE Corentin static int sun8i_dwmac_probe(struct platform_device *pdev) 11549f93ac8dSLABBE Corentin { 11559f93ac8dSLABBE Corentin struct plat_stmmacenet_data *plat_dat; 11569f93ac8dSLABBE Corentin struct stmmac_resources stmmac_res; 11579f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac; 11589f93ac8dSLABBE Corentin struct device *dev = &pdev->dev; 11590c65b2b9SAndrew Lunn phy_interface_t interface; 11609f93ac8dSLABBE Corentin int ret; 1161634db83bSCorentin Labbe struct stmmac_priv *priv; 1162634db83bSCorentin Labbe struct net_device *ndev; 116325ae15fbSChen-Yu Tsai struct regmap *regmap; 11649f93ac8dSLABBE Corentin 11659f93ac8dSLABBE Corentin ret = stmmac_get_platform_resources(pdev, &stmmac_res); 11669f93ac8dSLABBE Corentin if (ret) 11679f93ac8dSLABBE Corentin return ret; 11689f93ac8dSLABBE Corentin 11699f93ac8dSLABBE Corentin gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); 11709f93ac8dSLABBE Corentin if (!gmac) 11719f93ac8dSLABBE Corentin return -ENOMEM; 11729f93ac8dSLABBE Corentin 11739f93ac8dSLABBE Corentin gmac->variant = of_device_get_match_data(&pdev->dev); 11749f93ac8dSLABBE Corentin if (!gmac->variant) { 11759f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Missing dwmac-sun8i variant\n"); 11769f93ac8dSLABBE Corentin return -EINVAL; 11779f93ac8dSLABBE Corentin } 11789f93ac8dSLABBE Corentin 11799f93ac8dSLABBE Corentin /* Optional regulator for PHY */ 11809f93ac8dSLABBE Corentin gmac->regulator = devm_regulator_get_optional(dev, "phy"); 11819f93ac8dSLABBE Corentin if (IS_ERR(gmac->regulator)) { 11829f93ac8dSLABBE Corentin if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) 11839f93ac8dSLABBE Corentin return -EPROBE_DEFER; 11849f93ac8dSLABBE Corentin dev_info(dev, "No regulator found\n"); 11859f93ac8dSLABBE Corentin gmac->regulator = NULL; 11869f93ac8dSLABBE Corentin } 11879f93ac8dSLABBE Corentin 118849a06caeSChen-Yu Tsai /* The "GMAC clock control" register might be located in the 118949a06caeSChen-Yu Tsai * CCU address range (on the R40), or the system control address 119049a06caeSChen-Yu Tsai * range (on most other sun8i and later SoCs). 119149a06caeSChen-Yu Tsai * 119249a06caeSChen-Yu Tsai * The former controls most if not all clocks in the SoC. The 119349a06caeSChen-Yu Tsai * latter has an SoC identification register, and on some SoCs, 119449a06caeSChen-Yu Tsai * controls to map device specific SRAM to either the intended 119549a06caeSChen-Yu Tsai * peripheral, or the CPU address space. 119649a06caeSChen-Yu Tsai * 119749a06caeSChen-Yu Tsai * In either case, there should be a coordinated and restricted 119849a06caeSChen-Yu Tsai * method of accessing the register needed here. This is done by 119949a06caeSChen-Yu Tsai * having the device export a custom regmap, instead of a generic 120049a06caeSChen-Yu Tsai * syscon, which grants all access to all registers. 120149a06caeSChen-Yu Tsai * 120249a06caeSChen-Yu Tsai * To support old device trees, we fall back to using the syscon 120349a06caeSChen-Yu Tsai * interface if possible. 120449a06caeSChen-Yu Tsai */ 120549a06caeSChen-Yu Tsai regmap = sun8i_dwmac_get_syscon_from_dev(pdev->dev.of_node); 120649a06caeSChen-Yu Tsai if (IS_ERR(regmap)) 120749a06caeSChen-Yu Tsai regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 120849a06caeSChen-Yu Tsai "syscon"); 120925ae15fbSChen-Yu Tsai if (IS_ERR(regmap)) { 121025ae15fbSChen-Yu Tsai ret = PTR_ERR(regmap); 12119f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret); 12129f93ac8dSLABBE Corentin return ret; 12139f93ac8dSLABBE Corentin } 12149f93ac8dSLABBE Corentin 121525ae15fbSChen-Yu Tsai gmac->regmap_field = devm_regmap_field_alloc(dev, regmap, 121625ae15fbSChen-Yu Tsai *gmac->variant->syscon_field); 121725ae15fbSChen-Yu Tsai if (IS_ERR(gmac->regmap_field)) { 121825ae15fbSChen-Yu Tsai ret = PTR_ERR(gmac->regmap_field); 121925ae15fbSChen-Yu Tsai dev_err(dev, "Unable to map syscon register: %d\n", ret); 122025ae15fbSChen-Yu Tsai return ret; 122125ae15fbSChen-Yu Tsai } 122225ae15fbSChen-Yu Tsai 12230c65b2b9SAndrew Lunn ret = of_get_phy_mode(dev->of_node, &interface); 12240c65b2b9SAndrew Lunn if (ret) 12254ec850e5SKangjie Lu return -EINVAL; 12267eeecc4bSSamuel Holland 122783216e39SMichael Walle plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); 12287eeecc4bSSamuel Holland if (IS_ERR(plat_dat)) 12297eeecc4bSSamuel Holland return PTR_ERR(plat_dat); 12309f93ac8dSLABBE Corentin 12319f93ac8dSLABBE Corentin /* platform data specifying hardware features and callbacks. 12329f93ac8dSLABBE Corentin * hardware features were copied from Allwinner drivers. 12339f93ac8dSLABBE Corentin */ 12347eeecc4bSSamuel Holland plat_dat->interface = interface; 12359f93ac8dSLABBE Corentin plat_dat->rx_coe = STMMAC_RX_COE_TYPE2; 12369f93ac8dSLABBE Corentin plat_dat->tx_coe = 1; 1237d8daff28SBartosz Golaszewski plat_dat->flags |= STMMAC_FLAG_HAS_SUN8I; 12389f93ac8dSLABBE Corentin plat_dat->bsp_priv = gmac; 12399f93ac8dSLABBE Corentin plat_dat->init = sun8i_dwmac_init; 12409f93ac8dSLABBE Corentin plat_dat->exit = sun8i_dwmac_exit; 12419f93ac8dSLABBE Corentin plat_dat->setup = sun8i_dwmac_setup; 1242014dfa26SCorentin Labbe plat_dat->tx_fifo_size = 4096; 1243014dfa26SCorentin Labbe plat_dat->rx_fifo_size = 16384; 12449f93ac8dSLABBE Corentin 12459b1e39cfSSamuel Holland ret = sun8i_dwmac_set_syscon(&pdev->dev, plat_dat); 12469f93ac8dSLABBE Corentin if (ret) 12477eeecc4bSSamuel Holland goto dwmac_deconfig; 12489f93ac8dSLABBE Corentin 12499b1e39cfSSamuel Holland ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv); 12509b1e39cfSSamuel Holland if (ret) 12519b1e39cfSSamuel Holland goto dwmac_syscon; 12529b1e39cfSSamuel Holland 12539f93ac8dSLABBE Corentin ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 12549f93ac8dSLABBE Corentin if (ret) 1255634db83bSCorentin Labbe goto dwmac_exit; 12569f93ac8dSLABBE Corentin 1257634db83bSCorentin Labbe ndev = dev_get_drvdata(&pdev->dev); 1258634db83bSCorentin Labbe priv = netdev_priv(ndev); 12592743aa24SSamuel Holland 1260b76bbb34SJisheng Zhang /* the MAC is runtime suspended after stmmac_dvr_probe(), so we 1261b76bbb34SJisheng Zhang * need to ensure the MAC resume back before other operations such 1262b76bbb34SJisheng Zhang * as reset. 1263b76bbb34SJisheng Zhang */ 1264b76bbb34SJisheng Zhang pm_runtime_get_sync(&pdev->dev); 1265b76bbb34SJisheng Zhang 1266634db83bSCorentin Labbe /* The mux must be registered after parent MDIO 1267634db83bSCorentin Labbe * so after stmmac_dvr_probe() 1268634db83bSCorentin Labbe */ 1269634db83bSCorentin Labbe if (gmac->variant->soc_has_internal_phy) { 1270634db83bSCorentin Labbe ret = get_ephy_nodes(priv); 1271634db83bSCorentin Labbe if (ret) 12727eeecc4bSSamuel Holland goto dwmac_remove; 1273634db83bSCorentin Labbe ret = sun8i_dwmac_register_mdio_mux(priv); 1274634db83bSCorentin Labbe if (ret) { 1275634db83bSCorentin Labbe dev_err(&pdev->dev, "Failed to register mux\n"); 1276634db83bSCorentin Labbe goto dwmac_mux; 1277634db83bSCorentin Labbe } 1278634db83bSCorentin Labbe } else { 1279634db83bSCorentin Labbe ret = sun8i_dwmac_reset(priv); 1280634db83bSCorentin Labbe if (ret) 12817eeecc4bSSamuel Holland goto dwmac_remove; 1282634db83bSCorentin Labbe } 1283634db83bSCorentin Labbe 1284b76bbb34SJisheng Zhang pm_runtime_put(&pdev->dev); 1285b76bbb34SJisheng Zhang 12862743aa24SSamuel Holland return 0; 12872743aa24SSamuel Holland 1288634db83bSCorentin Labbe dwmac_mux: 128952925421SSamuel Holland reset_control_put(gmac->rst_ephy); 129052925421SSamuel Holland clk_put(gmac->ephy_clk); 12917eeecc4bSSamuel Holland dwmac_remove: 1292b76bbb34SJisheng Zhang pm_runtime_put_noidle(&pdev->dev); 12937eeecc4bSSamuel Holland stmmac_dvr_remove(&pdev->dev); 1294634db83bSCorentin Labbe dwmac_exit: 12957eeecc4bSSamuel Holland sun8i_dwmac_exit(pdev, gmac); 12969b1e39cfSSamuel Holland dwmac_syscon: 12979b1e39cfSSamuel Holland sun8i_dwmac_unset_syscon(gmac); 12987eeecc4bSSamuel Holland dwmac_deconfig: 12997eeecc4bSSamuel Holland stmmac_remove_config_dt(pdev, plat_dat); 13007eeecc4bSSamuel Holland 13019f93ac8dSLABBE Corentin return ret; 13029f93ac8dSLABBE Corentin } 13039f93ac8dSLABBE Corentin 1304cc708d4eSUwe Kleine-König static void sun8i_dwmac_remove(struct platform_device *pdev) 130552925421SSamuel Holland { 130652925421SSamuel Holland struct net_device *ndev = platform_get_drvdata(pdev); 130752925421SSamuel Holland struct stmmac_priv *priv = netdev_priv(ndev); 130852925421SSamuel Holland struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 130952925421SSamuel Holland 131052925421SSamuel Holland if (gmac->variant->soc_has_internal_phy) { 131152925421SSamuel Holland mdio_mux_uninit(gmac->mux_handle); 131252925421SSamuel Holland sun8i_dwmac_unpower_internal_phy(gmac); 131352925421SSamuel Holland reset_control_put(gmac->rst_ephy); 131452925421SSamuel Holland clk_put(gmac->ephy_clk); 131552925421SSamuel Holland } 131652925421SSamuel Holland 131752925421SSamuel Holland stmmac_pltfr_remove(pdev); 13189b1e39cfSSamuel Holland sun8i_dwmac_unset_syscon(gmac); 131952925421SSamuel Holland } 132052925421SSamuel Holland 132196be41d7SSamuel Holland static void sun8i_dwmac_shutdown(struct platform_device *pdev) 132296be41d7SSamuel Holland { 132396be41d7SSamuel Holland struct net_device *ndev = platform_get_drvdata(pdev); 132496be41d7SSamuel Holland struct stmmac_priv *priv = netdev_priv(ndev); 132596be41d7SSamuel Holland struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 132696be41d7SSamuel Holland 132796be41d7SSamuel Holland sun8i_dwmac_exit(pdev, gmac); 132896be41d7SSamuel Holland } 132996be41d7SSamuel Holland 13309f93ac8dSLABBE Corentin static const struct of_device_id sun8i_dwmac_match[] = { 1331a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun8i-h3-emac", 1332a8ff8ccbSCorentin Labbe .data = &emac_variant_h3 }, 1333a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun8i-v3s-emac", 1334a8ff8ccbSCorentin Labbe .data = &emac_variant_v3s }, 1335a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun8i-a83t-emac", 1336a8ff8ccbSCorentin Labbe .data = &emac_variant_a83t }, 13379bf5085aSChen-Yu Tsai { .compatible = "allwinner,sun8i-r40-gmac", 13389bf5085aSChen-Yu Tsai .data = &emac_variant_r40 }, 1339a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun50i-a64-emac", 1340a8ff8ccbSCorentin Labbe .data = &emac_variant_a64 }, 1341adadd38cSIcenowy Zheng { .compatible = "allwinner,sun50i-h6-emac", 1342adadd38cSIcenowy Zheng .data = &emac_variant_h6 }, 13439f93ac8dSLABBE Corentin { } 13449f93ac8dSLABBE Corentin }; 13459f93ac8dSLABBE Corentin MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); 13469f93ac8dSLABBE Corentin 13479f93ac8dSLABBE Corentin static struct platform_driver sun8i_dwmac_driver = { 13489f93ac8dSLABBE Corentin .probe = sun8i_dwmac_probe, 1349cc708d4eSUwe Kleine-König .remove_new = sun8i_dwmac_remove, 135096be41d7SSamuel Holland .shutdown = sun8i_dwmac_shutdown, 13519f93ac8dSLABBE Corentin .driver = { 13529f93ac8dSLABBE Corentin .name = "dwmac-sun8i", 13539f93ac8dSLABBE Corentin .pm = &stmmac_pltfr_pm_ops, 13549f93ac8dSLABBE Corentin .of_match_table = sun8i_dwmac_match, 13559f93ac8dSLABBE Corentin }, 13569f93ac8dSLABBE Corentin }; 13579f93ac8dSLABBE Corentin module_platform_driver(sun8i_dwmac_driver); 13589f93ac8dSLABBE Corentin 13599f93ac8dSLABBE Corentin MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>"); 13609f93ac8dSLABBE Corentin MODULE_DESCRIPTION("Allwinner sun8i DWMAC specific glue layer"); 13619f93ac8dSLABBE Corentin MODULE_LICENSE("GPL"); 1362