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> 20634db83bSCorentin Labbe #include <linux/mdio-mux.h> 219f93ac8dSLABBE Corentin #include <linux/mfd/syscon.h> 229f93ac8dSLABBE Corentin #include <linux/module.h> 239f93ac8dSLABBE Corentin #include <linux/of_device.h> 249f93ac8dSLABBE Corentin #include <linux/of_mdio.h> 259f93ac8dSLABBE Corentin #include <linux/of_net.h> 269f93ac8dSLABBE Corentin #include <linux/phy.h> 279f93ac8dSLABBE Corentin #include <linux/platform_device.h> 289f93ac8dSLABBE Corentin #include <linux/regulator/consumer.h> 299f93ac8dSLABBE Corentin #include <linux/regmap.h> 309f93ac8dSLABBE Corentin #include <linux/stmmac.h> 319f93ac8dSLABBE Corentin 329f93ac8dSLABBE Corentin #include "stmmac.h" 339f93ac8dSLABBE Corentin #include "stmmac_platform.h" 349f93ac8dSLABBE Corentin 359f93ac8dSLABBE Corentin /* General notes on dwmac-sun8i: 369f93ac8dSLABBE Corentin * Locking: no locking is necessary in this file because all necessary locking 379f93ac8dSLABBE Corentin * is done in the "stmmac files" 389f93ac8dSLABBE Corentin */ 399f93ac8dSLABBE Corentin 409f93ac8dSLABBE Corentin /* struct emac_variant - Descrive dwmac-sun8i hardware variant 419f93ac8dSLABBE Corentin * @default_syscon_value: The default value of the EMAC register in syscon 429f93ac8dSLABBE Corentin * This value is used for disabling properly EMAC 439f93ac8dSLABBE Corentin * and used as a good starting value in case of the 449f93ac8dSLABBE Corentin * boot process(uboot) leave some stuff. 4525ae15fbSChen-Yu Tsai * @syscon_field reg_field for the syscon's gmac register 46634db83bSCorentin Labbe * @soc_has_internal_phy: Does the MAC embed an internal PHY 479f93ac8dSLABBE Corentin * @support_mii: Does the MAC handle MII 489f93ac8dSLABBE Corentin * @support_rmii: Does the MAC handle RMII 499f93ac8dSLABBE Corentin * @support_rgmii: Does the MAC handle RGMII 507b270b72SChen-Yu Tsai * 517b270b72SChen-Yu Tsai * @rx_delay_max: Maximum raw value for RX delay chain 527b270b72SChen-Yu Tsai * @tx_delay_max: Maximum raw value for TX delay chain 537b270b72SChen-Yu Tsai * These two also indicate the bitmask for 547b270b72SChen-Yu Tsai * the RX and TX delay chain registers. A 557b270b72SChen-Yu Tsai * value of zero indicates this is not supported. 569f93ac8dSLABBE Corentin */ 579f93ac8dSLABBE Corentin struct emac_variant { 589f93ac8dSLABBE Corentin u32 default_syscon_value; 5925ae15fbSChen-Yu Tsai const struct reg_field *syscon_field; 60634db83bSCorentin Labbe bool soc_has_internal_phy; 619f93ac8dSLABBE Corentin bool support_mii; 629f93ac8dSLABBE Corentin bool support_rmii; 639f93ac8dSLABBE Corentin bool support_rgmii; 647b270b72SChen-Yu Tsai u8 rx_delay_max; 657b270b72SChen-Yu Tsai u8 tx_delay_max; 669f93ac8dSLABBE Corentin }; 679f93ac8dSLABBE Corentin 689f93ac8dSLABBE Corentin /* struct sunxi_priv_data - hold all sunxi private data 699f93ac8dSLABBE Corentin * @tx_clk: reference to MAC TX clock 709f93ac8dSLABBE Corentin * @ephy_clk: reference to the optional EPHY clock for the internal PHY 719f93ac8dSLABBE Corentin * @regulator: reference to the optional regulator 729f93ac8dSLABBE Corentin * @rst_ephy: reference to the optional EPHY reset for the internal PHY 739f93ac8dSLABBE Corentin * @variant: reference to the current board variant 749f93ac8dSLABBE Corentin * @regmap: regmap for using the syscon 75634db83bSCorentin Labbe * @internal_phy_powered: Does the internal PHY is enabled 76634db83bSCorentin Labbe * @mux_handle: Internal pointer used by mdio-mux lib 779f93ac8dSLABBE Corentin */ 789f93ac8dSLABBE Corentin struct sunxi_priv_data { 799f93ac8dSLABBE Corentin struct clk *tx_clk; 809f93ac8dSLABBE Corentin struct clk *ephy_clk; 819f93ac8dSLABBE Corentin struct regulator *regulator; 829f93ac8dSLABBE Corentin struct reset_control *rst_ephy; 839f93ac8dSLABBE Corentin const struct emac_variant *variant; 8425ae15fbSChen-Yu Tsai struct regmap_field *regmap_field; 85634db83bSCorentin Labbe bool internal_phy_powered; 86634db83bSCorentin Labbe void *mux_handle; 879f93ac8dSLABBE Corentin }; 889f93ac8dSLABBE Corentin 8925ae15fbSChen-Yu Tsai /* EMAC clock register @ 0x30 in the "system control" address range */ 9025ae15fbSChen-Yu Tsai static const struct reg_field sun8i_syscon_reg_field = { 9125ae15fbSChen-Yu Tsai .reg = 0x30, 9225ae15fbSChen-Yu Tsai .lsb = 0, 9325ae15fbSChen-Yu Tsai .msb = 31, 9425ae15fbSChen-Yu Tsai }; 9525ae15fbSChen-Yu Tsai 969bf5085aSChen-Yu Tsai /* EMAC clock register @ 0x164 in the CCU address range */ 979bf5085aSChen-Yu Tsai static const struct reg_field sun8i_ccu_reg_field = { 989bf5085aSChen-Yu Tsai .reg = 0x164, 999bf5085aSChen-Yu Tsai .lsb = 0, 1009bf5085aSChen-Yu Tsai .msb = 31, 1019bf5085aSChen-Yu Tsai }; 1029bf5085aSChen-Yu Tsai 1039f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_h3 = { 1049f93ac8dSLABBE Corentin .default_syscon_value = 0x58000, 10525ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 106634db83bSCorentin Labbe .soc_has_internal_phy = true, 1079f93ac8dSLABBE Corentin .support_mii = true, 1089f93ac8dSLABBE Corentin .support_rmii = true, 1097b270b72SChen-Yu Tsai .support_rgmii = true, 1107b270b72SChen-Yu Tsai .rx_delay_max = 31, 1117b270b72SChen-Yu Tsai .tx_delay_max = 7, 1129f93ac8dSLABBE Corentin }; 1139f93ac8dSLABBE Corentin 11457fde47dSIcenowy Zheng static const struct emac_variant emac_variant_v3s = { 11557fde47dSIcenowy Zheng .default_syscon_value = 0x38000, 11625ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 117634db83bSCorentin Labbe .soc_has_internal_phy = true, 11857fde47dSIcenowy Zheng .support_mii = true 11957fde47dSIcenowy Zheng }; 12057fde47dSIcenowy Zheng 1219f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_a83t = { 1229f93ac8dSLABBE Corentin .default_syscon_value = 0, 12325ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 124634db83bSCorentin Labbe .soc_has_internal_phy = false, 1259f93ac8dSLABBE Corentin .support_mii = true, 1267b270b72SChen-Yu Tsai .support_rgmii = true, 1277b270b72SChen-Yu Tsai .rx_delay_max = 31, 1287b270b72SChen-Yu Tsai .tx_delay_max = 7, 1299f93ac8dSLABBE Corentin }; 1309f93ac8dSLABBE Corentin 1319bf5085aSChen-Yu Tsai static const struct emac_variant emac_variant_r40 = { 1329bf5085aSChen-Yu Tsai .default_syscon_value = 0, 1339bf5085aSChen-Yu Tsai .syscon_field = &sun8i_ccu_reg_field, 1349bf5085aSChen-Yu Tsai .support_mii = true, 1359bf5085aSChen-Yu Tsai .support_rgmii = true, 1369bf5085aSChen-Yu Tsai .rx_delay_max = 7, 1379bf5085aSChen-Yu Tsai }; 1389bf5085aSChen-Yu Tsai 1399f93ac8dSLABBE Corentin static const struct emac_variant emac_variant_a64 = { 1409f93ac8dSLABBE Corentin .default_syscon_value = 0, 14125ae15fbSChen-Yu Tsai .syscon_field = &sun8i_syscon_reg_field, 142634db83bSCorentin Labbe .soc_has_internal_phy = false, 1439f93ac8dSLABBE Corentin .support_mii = true, 1449f93ac8dSLABBE Corentin .support_rmii = true, 1457b270b72SChen-Yu Tsai .support_rgmii = true, 1467b270b72SChen-Yu Tsai .rx_delay_max = 31, 1477b270b72SChen-Yu Tsai .tx_delay_max = 7, 1489f93ac8dSLABBE Corentin }; 1499f93ac8dSLABBE Corentin 1509f93ac8dSLABBE Corentin #define EMAC_BASIC_CTL0 0x00 1519f93ac8dSLABBE Corentin #define EMAC_BASIC_CTL1 0x04 1529f93ac8dSLABBE Corentin #define EMAC_INT_STA 0x08 1539f93ac8dSLABBE Corentin #define EMAC_INT_EN 0x0C 1549f93ac8dSLABBE Corentin #define EMAC_TX_CTL0 0x10 1559f93ac8dSLABBE Corentin #define EMAC_TX_CTL1 0x14 1569f93ac8dSLABBE Corentin #define EMAC_TX_FLOW_CTL 0x1C 1579f93ac8dSLABBE Corentin #define EMAC_TX_DESC_LIST 0x20 1589f93ac8dSLABBE Corentin #define EMAC_RX_CTL0 0x24 1599f93ac8dSLABBE Corentin #define EMAC_RX_CTL1 0x28 1609f93ac8dSLABBE Corentin #define EMAC_RX_DESC_LIST 0x34 1619f93ac8dSLABBE Corentin #define EMAC_RX_FRM_FLT 0x38 1629f93ac8dSLABBE Corentin #define EMAC_MDIO_CMD 0x48 1639f93ac8dSLABBE Corentin #define EMAC_MDIO_DATA 0x4C 1649f93ac8dSLABBE Corentin #define EMAC_MACADDR_HI(reg) (0x50 + (reg) * 8) 1659f93ac8dSLABBE Corentin #define EMAC_MACADDR_LO(reg) (0x54 + (reg) * 8) 1669f93ac8dSLABBE Corentin #define EMAC_TX_DMA_STA 0xB0 1679f93ac8dSLABBE Corentin #define EMAC_TX_CUR_DESC 0xB4 1689f93ac8dSLABBE Corentin #define EMAC_TX_CUR_BUF 0xB8 1699f93ac8dSLABBE Corentin #define EMAC_RX_DMA_STA 0xC0 1709f93ac8dSLABBE Corentin #define EMAC_RX_CUR_DESC 0xC4 1719f93ac8dSLABBE Corentin #define EMAC_RX_CUR_BUF 0xC8 1729f93ac8dSLABBE Corentin 1739f93ac8dSLABBE Corentin /* Use in EMAC_BASIC_CTL0 */ 1749f93ac8dSLABBE Corentin #define EMAC_DUPLEX_FULL BIT(0) 1759f93ac8dSLABBE Corentin #define EMAC_LOOPBACK BIT(1) 1769f93ac8dSLABBE Corentin #define EMAC_SPEED_1000 0 1779f93ac8dSLABBE Corentin #define EMAC_SPEED_100 (0x03 << 2) 1789f93ac8dSLABBE Corentin #define EMAC_SPEED_10 (0x02 << 2) 1799f93ac8dSLABBE Corentin 1809f93ac8dSLABBE Corentin /* Use in EMAC_BASIC_CTL1 */ 1819f93ac8dSLABBE Corentin #define EMAC_BURSTLEN_SHIFT 24 1829f93ac8dSLABBE Corentin 1839f93ac8dSLABBE Corentin /* Used in EMAC_RX_FRM_FLT */ 1849f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_RXALL BIT(0) 1859f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_CTL BIT(13) 1869f93ac8dSLABBE Corentin #define EMAC_FRM_FLT_MULTICAST BIT(16) 1879f93ac8dSLABBE Corentin 1889f93ac8dSLABBE Corentin /* Used in RX_CTL1*/ 1899f93ac8dSLABBE Corentin #define EMAC_RX_MD BIT(1) 1909f93ac8dSLABBE Corentin #define EMAC_RX_TH_MASK GENMASK(4, 5) 1919f93ac8dSLABBE Corentin #define EMAC_RX_TH_32 0 1929f93ac8dSLABBE Corentin #define EMAC_RX_TH_64 (0x1 << 4) 1939f93ac8dSLABBE Corentin #define EMAC_RX_TH_96 (0x2 << 4) 1949f93ac8dSLABBE Corentin #define EMAC_RX_TH_128 (0x3 << 4) 1959f93ac8dSLABBE Corentin #define EMAC_RX_DMA_EN BIT(30) 1969f93ac8dSLABBE Corentin #define EMAC_RX_DMA_START BIT(31) 1979f93ac8dSLABBE Corentin 1989f93ac8dSLABBE Corentin /* Used in TX_CTL1*/ 1999f93ac8dSLABBE Corentin #define EMAC_TX_MD BIT(1) 2009f93ac8dSLABBE Corentin #define EMAC_TX_NEXT_FRM BIT(2) 2019f93ac8dSLABBE Corentin #define EMAC_TX_TH_MASK GENMASK(8, 10) 2029f93ac8dSLABBE Corentin #define EMAC_TX_TH_64 0 2039f93ac8dSLABBE Corentin #define EMAC_TX_TH_128 (0x1 << 8) 2049f93ac8dSLABBE Corentin #define EMAC_TX_TH_192 (0x2 << 8) 2059f93ac8dSLABBE Corentin #define EMAC_TX_TH_256 (0x3 << 8) 2069f93ac8dSLABBE Corentin #define EMAC_TX_DMA_EN BIT(30) 2079f93ac8dSLABBE Corentin #define EMAC_TX_DMA_START BIT(31) 2089f93ac8dSLABBE Corentin 2099f93ac8dSLABBE Corentin /* Used in RX_CTL0 */ 2109f93ac8dSLABBE Corentin #define EMAC_RX_RECEIVER_EN BIT(31) 2119f93ac8dSLABBE Corentin #define EMAC_RX_DO_CRC BIT(27) 2129f93ac8dSLABBE Corentin #define EMAC_RX_FLOW_CTL_EN BIT(16) 2139f93ac8dSLABBE Corentin 2149f93ac8dSLABBE Corentin /* Used in TX_CTL0 */ 2159f93ac8dSLABBE Corentin #define EMAC_TX_TRANSMITTER_EN BIT(31) 2169f93ac8dSLABBE Corentin 2179f93ac8dSLABBE Corentin /* Used in EMAC_TX_FLOW_CTL */ 2189f93ac8dSLABBE Corentin #define EMAC_TX_FLOW_CTL_EN BIT(0) 2199f93ac8dSLABBE Corentin 2209f93ac8dSLABBE Corentin /* Used in EMAC_INT_STA */ 2219f93ac8dSLABBE Corentin #define EMAC_TX_INT BIT(0) 2229f93ac8dSLABBE Corentin #define EMAC_TX_DMA_STOP_INT BIT(1) 2239f93ac8dSLABBE Corentin #define EMAC_TX_BUF_UA_INT BIT(2) 2249f93ac8dSLABBE Corentin #define EMAC_TX_TIMEOUT_INT BIT(3) 2259f93ac8dSLABBE Corentin #define EMAC_TX_UNDERFLOW_INT BIT(4) 2269f93ac8dSLABBE Corentin #define EMAC_TX_EARLY_INT BIT(5) 2279f93ac8dSLABBE Corentin #define EMAC_RX_INT BIT(8) 2289f93ac8dSLABBE Corentin #define EMAC_RX_BUF_UA_INT BIT(9) 2299f93ac8dSLABBE Corentin #define EMAC_RX_DMA_STOP_INT BIT(10) 2309f93ac8dSLABBE Corentin #define EMAC_RX_TIMEOUT_INT BIT(11) 2319f93ac8dSLABBE Corentin #define EMAC_RX_OVERFLOW_INT BIT(12) 2329f93ac8dSLABBE Corentin #define EMAC_RX_EARLY_INT BIT(13) 2339f93ac8dSLABBE Corentin #define EMAC_RGMII_STA_INT BIT(16) 2349f93ac8dSLABBE Corentin 2359f93ac8dSLABBE Corentin #define MAC_ADDR_TYPE_DST BIT(31) 2369f93ac8dSLABBE Corentin 2379f93ac8dSLABBE Corentin /* H3 specific bits for EPHY */ 2389f93ac8dSLABBE Corentin #define H3_EPHY_ADDR_SHIFT 20 2391450ba8aSIcenowy Zheng #define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */ 2409f93ac8dSLABBE Corentin #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ 2419f93ac8dSLABBE Corentin #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ 2429f93ac8dSLABBE Corentin #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ 243634db83bSCorentin Labbe #define H3_EPHY_MUX_MASK (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT) 244634db83bSCorentin Labbe #define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID 1 245634db83bSCorentin Labbe #define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID 2 2469f93ac8dSLABBE Corentin 2479f93ac8dSLABBE Corentin /* H3/A64 specific bits */ 2489f93ac8dSLABBE Corentin #define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ 2499f93ac8dSLABBE Corentin 2509f93ac8dSLABBE Corentin /* Generic system control EMAC_CLK bits */ 2519f93ac8dSLABBE Corentin #define SYSCON_ETXDC_SHIFT 10 2529f93ac8dSLABBE Corentin #define SYSCON_ERXDC_SHIFT 5 2539f93ac8dSLABBE Corentin /* EMAC PHY Interface Type */ 2549f93ac8dSLABBE Corentin #define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ 2559f93ac8dSLABBE Corentin #define SYSCON_ETCS_MASK GENMASK(1, 0) 2569f93ac8dSLABBE Corentin #define SYSCON_ETCS_MII 0x0 2579f93ac8dSLABBE Corentin #define SYSCON_ETCS_EXT_GMII 0x1 2589f93ac8dSLABBE Corentin #define SYSCON_ETCS_INT_GMII 0x2 2599f93ac8dSLABBE Corentin 2609f93ac8dSLABBE Corentin /* sun8i_dwmac_dma_reset() - reset the EMAC 2619f93ac8dSLABBE Corentin * Called from stmmac via stmmac_dma_ops->reset 2629f93ac8dSLABBE Corentin */ 2639f93ac8dSLABBE Corentin static int sun8i_dwmac_dma_reset(void __iomem *ioaddr) 2649f93ac8dSLABBE Corentin { 2659f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_CTL1); 2669f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_TX_CTL1); 2679f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_FRM_FLT); 2689f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_RX_DESC_LIST); 2699f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_TX_DESC_LIST); 2709f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_INT_EN); 2719f93ac8dSLABBE Corentin writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); 2729f93ac8dSLABBE Corentin return 0; 2739f93ac8dSLABBE Corentin } 2749f93ac8dSLABBE Corentin 2759f93ac8dSLABBE Corentin /* sun8i_dwmac_dma_init() - initialize the EMAC 2769f93ac8dSLABBE Corentin * Called from stmmac via stmmac_dma_ops->init 2779f93ac8dSLABBE Corentin */ 2789f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_init(void __iomem *ioaddr, 2799f93ac8dSLABBE Corentin struct stmmac_dma_cfg *dma_cfg, 2809f93ac8dSLABBE Corentin u32 dma_tx, u32 dma_rx, int atds) 2819f93ac8dSLABBE Corentin { 2829f93ac8dSLABBE Corentin /* Write TX and RX descriptors address */ 2839f93ac8dSLABBE Corentin writel(dma_rx, ioaddr + EMAC_RX_DESC_LIST); 2849f93ac8dSLABBE Corentin writel(dma_tx, ioaddr + EMAC_TX_DESC_LIST); 2859f93ac8dSLABBE Corentin 2869f93ac8dSLABBE Corentin writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); 2879f93ac8dSLABBE Corentin writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); 2889f93ac8dSLABBE Corentin } 2899f93ac8dSLABBE Corentin 2909f93ac8dSLABBE Corentin /* sun8i_dwmac_dump_regs() - Dump EMAC address space 2919f93ac8dSLABBE Corentin * Called from stmmac_dma_ops->dump_regs 2929f93ac8dSLABBE Corentin * Used for ethtool 2939f93ac8dSLABBE Corentin */ 2949f93ac8dSLABBE Corentin static void sun8i_dwmac_dump_regs(void __iomem *ioaddr, u32 *reg_space) 2959f93ac8dSLABBE Corentin { 2969f93ac8dSLABBE Corentin int i; 2979f93ac8dSLABBE Corentin 2989f93ac8dSLABBE Corentin for (i = 0; i < 0xC8; i += 4) { 2999f93ac8dSLABBE Corentin if (i == 0x32 || i == 0x3C) 3009f93ac8dSLABBE Corentin continue; 3019f93ac8dSLABBE Corentin reg_space[i / 4] = readl(ioaddr + i); 3029f93ac8dSLABBE Corentin } 3039f93ac8dSLABBE Corentin } 3049f93ac8dSLABBE Corentin 3059f93ac8dSLABBE Corentin /* sun8i_dwmac_dump_mac_regs() - Dump EMAC address space 3069f93ac8dSLABBE Corentin * Called from stmmac_ops->dump_regs 3079f93ac8dSLABBE Corentin * Used for ethtool 3089f93ac8dSLABBE Corentin */ 3099f93ac8dSLABBE Corentin static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw, 3109f93ac8dSLABBE Corentin u32 *reg_space) 3119f93ac8dSLABBE Corentin { 3129f93ac8dSLABBE Corentin int i; 3139f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 3149f93ac8dSLABBE Corentin 3159f93ac8dSLABBE Corentin for (i = 0; i < 0xC8; i += 4) { 3169f93ac8dSLABBE Corentin if (i == 0x32 || i == 0x3C) 3179f93ac8dSLABBE Corentin continue; 3189f93ac8dSLABBE Corentin reg_space[i / 4] = readl(ioaddr + i); 3199f93ac8dSLABBE Corentin } 3209f93ac8dSLABBE Corentin } 3219f93ac8dSLABBE Corentin 3229f93ac8dSLABBE Corentin static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) 3239f93ac8dSLABBE Corentin { 3249f93ac8dSLABBE Corentin writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); 3259f93ac8dSLABBE Corentin } 3269f93ac8dSLABBE Corentin 3279f93ac8dSLABBE Corentin static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) 3289f93ac8dSLABBE Corentin { 3299f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_INT_EN); 3309f93ac8dSLABBE Corentin } 3319f93ac8dSLABBE Corentin 3329f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan) 3339f93ac8dSLABBE Corentin { 3349f93ac8dSLABBE Corentin u32 v; 3359f93ac8dSLABBE Corentin 3369f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 3379f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_START; 3389f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_EN; 3399f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 3409f93ac8dSLABBE Corentin } 3419f93ac8dSLABBE Corentin 3429f93ac8dSLABBE Corentin static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr) 3439f93ac8dSLABBE Corentin { 3449f93ac8dSLABBE Corentin u32 v; 3459f93ac8dSLABBE Corentin 3469f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 3479f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_START; 3489f93ac8dSLABBE Corentin v |= EMAC_TX_DMA_EN; 3499f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 3509f93ac8dSLABBE Corentin } 3519f93ac8dSLABBE Corentin 3529f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan) 3539f93ac8dSLABBE Corentin { 3549f93ac8dSLABBE Corentin u32 v; 3559f93ac8dSLABBE Corentin 3569f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 3579f93ac8dSLABBE Corentin v &= ~EMAC_TX_DMA_EN; 3589f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 3599f93ac8dSLABBE Corentin } 3609f93ac8dSLABBE Corentin 3619f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan) 3629f93ac8dSLABBE Corentin { 3639f93ac8dSLABBE Corentin u32 v; 3649f93ac8dSLABBE Corentin 3659f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 3669f93ac8dSLABBE Corentin v |= EMAC_RX_DMA_START; 3679f93ac8dSLABBE Corentin v |= EMAC_RX_DMA_EN; 3689f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 3699f93ac8dSLABBE Corentin } 3709f93ac8dSLABBE Corentin 3719f93ac8dSLABBE Corentin static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan) 3729f93ac8dSLABBE Corentin { 3739f93ac8dSLABBE Corentin u32 v; 3749f93ac8dSLABBE Corentin 3759f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL1); 3769f93ac8dSLABBE Corentin v &= ~EMAC_RX_DMA_EN; 3779f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL1); 3789f93ac8dSLABBE Corentin } 3799f93ac8dSLABBE Corentin 3809f93ac8dSLABBE Corentin static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr, 3819f93ac8dSLABBE Corentin struct stmmac_extra_stats *x, u32 chan) 3829f93ac8dSLABBE Corentin { 3839f93ac8dSLABBE Corentin u32 v; 3849f93ac8dSLABBE Corentin int ret = 0; 3859f93ac8dSLABBE Corentin 3869f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_INT_STA); 3879f93ac8dSLABBE Corentin 3889f93ac8dSLABBE Corentin if (v & EMAC_TX_INT) { 3899f93ac8dSLABBE Corentin ret |= handle_tx; 3909f93ac8dSLABBE Corentin x->tx_normal_irq_n++; 3919f93ac8dSLABBE Corentin } 3929f93ac8dSLABBE Corentin 3939f93ac8dSLABBE Corentin if (v & EMAC_TX_DMA_STOP_INT) 3949f93ac8dSLABBE Corentin x->tx_process_stopped_irq++; 3959f93ac8dSLABBE Corentin 3969f93ac8dSLABBE Corentin if (v & EMAC_TX_BUF_UA_INT) 3979f93ac8dSLABBE Corentin x->tx_process_stopped_irq++; 3989f93ac8dSLABBE Corentin 3999f93ac8dSLABBE Corentin if (v & EMAC_TX_TIMEOUT_INT) 4009f93ac8dSLABBE Corentin ret |= tx_hard_error; 4019f93ac8dSLABBE Corentin 4029f93ac8dSLABBE Corentin if (v & EMAC_TX_UNDERFLOW_INT) { 4039f93ac8dSLABBE Corentin ret |= tx_hard_error; 4049f93ac8dSLABBE Corentin x->tx_undeflow_irq++; 4059f93ac8dSLABBE Corentin } 4069f93ac8dSLABBE Corentin 4079f93ac8dSLABBE Corentin if (v & EMAC_TX_EARLY_INT) 4089f93ac8dSLABBE Corentin x->tx_early_irq++; 4099f93ac8dSLABBE Corentin 4109f93ac8dSLABBE Corentin if (v & EMAC_RX_INT) { 4119f93ac8dSLABBE Corentin ret |= handle_rx; 4129f93ac8dSLABBE Corentin x->rx_normal_irq_n++; 4139f93ac8dSLABBE Corentin } 4149f93ac8dSLABBE Corentin 4159f93ac8dSLABBE Corentin if (v & EMAC_RX_BUF_UA_INT) 4169f93ac8dSLABBE Corentin x->rx_buf_unav_irq++; 4179f93ac8dSLABBE Corentin 4189f93ac8dSLABBE Corentin if (v & EMAC_RX_DMA_STOP_INT) 4199f93ac8dSLABBE Corentin x->rx_process_stopped_irq++; 4209f93ac8dSLABBE Corentin 4219f93ac8dSLABBE Corentin if (v & EMAC_RX_TIMEOUT_INT) 4229f93ac8dSLABBE Corentin ret |= tx_hard_error; 4239f93ac8dSLABBE Corentin 4249f93ac8dSLABBE Corentin if (v & EMAC_RX_OVERFLOW_INT) { 4259f93ac8dSLABBE Corentin ret |= tx_hard_error; 4269f93ac8dSLABBE Corentin x->rx_overflow_irq++; 4279f93ac8dSLABBE Corentin } 4289f93ac8dSLABBE Corentin 4299f93ac8dSLABBE Corentin if (v & EMAC_RX_EARLY_INT) 4309f93ac8dSLABBE Corentin x->rx_early_irq++; 4319f93ac8dSLABBE Corentin 4329f93ac8dSLABBE Corentin if (v & EMAC_RGMII_STA_INT) 4339f93ac8dSLABBE Corentin x->irq_rgmii_n++; 4349f93ac8dSLABBE Corentin 4359f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_INT_STA); 4369f93ac8dSLABBE Corentin 4379f93ac8dSLABBE Corentin return ret; 4389f93ac8dSLABBE Corentin } 4399f93ac8dSLABBE Corentin 440ab0204e3SJose Abreu static void sun8i_dwmac_dma_operation_mode_rx(void __iomem *ioaddr, int mode, 441ab0204e3SJose Abreu u32 channel, int fifosz, u8 qmode) 442ab0204e3SJose Abreu { 443ab0204e3SJose Abreu u32 v; 444ab0204e3SJose Abreu 445ab0204e3SJose Abreu v = readl(ioaddr + EMAC_RX_CTL1); 446ab0204e3SJose Abreu if (mode == SF_DMA_MODE) { 447ab0204e3SJose Abreu v |= EMAC_RX_MD; 448ab0204e3SJose Abreu } else { 449ab0204e3SJose Abreu v &= ~EMAC_RX_MD; 450ab0204e3SJose Abreu v &= ~EMAC_RX_TH_MASK; 451ab0204e3SJose Abreu if (mode < 32) 452ab0204e3SJose Abreu v |= EMAC_RX_TH_32; 453ab0204e3SJose Abreu else if (mode < 64) 454ab0204e3SJose Abreu v |= EMAC_RX_TH_64; 455ab0204e3SJose Abreu else if (mode < 96) 456ab0204e3SJose Abreu v |= EMAC_RX_TH_96; 457ab0204e3SJose Abreu else if (mode < 128) 458ab0204e3SJose Abreu v |= EMAC_RX_TH_128; 459ab0204e3SJose Abreu } 460ab0204e3SJose Abreu writel(v, ioaddr + EMAC_RX_CTL1); 461ab0204e3SJose Abreu } 462ab0204e3SJose Abreu 463ab0204e3SJose Abreu static void sun8i_dwmac_dma_operation_mode_tx(void __iomem *ioaddr, int mode, 464ab0204e3SJose Abreu u32 channel, int fifosz, u8 qmode) 4659f93ac8dSLABBE Corentin { 4669f93ac8dSLABBE Corentin u32 v; 4679f93ac8dSLABBE Corentin 4689f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_CTL1); 469ab0204e3SJose Abreu if (mode == SF_DMA_MODE) { 4709f93ac8dSLABBE Corentin v |= EMAC_TX_MD; 4719f93ac8dSLABBE Corentin /* Undocumented bit (called TX_NEXT_FRM in BSP), the original 4729f93ac8dSLABBE Corentin * comment is 4739f93ac8dSLABBE Corentin * "Operating on second frame increase the performance 4749f93ac8dSLABBE Corentin * especially when transmit store-and-forward is used." 4759f93ac8dSLABBE Corentin */ 4769f93ac8dSLABBE Corentin v |= EMAC_TX_NEXT_FRM; 4779f93ac8dSLABBE Corentin } else { 4789f93ac8dSLABBE Corentin v &= ~EMAC_TX_MD; 4799f93ac8dSLABBE Corentin v &= ~EMAC_TX_TH_MASK; 480ab0204e3SJose Abreu if (mode < 64) 4819f93ac8dSLABBE Corentin v |= EMAC_TX_TH_64; 482ab0204e3SJose Abreu else if (mode < 128) 4839f93ac8dSLABBE Corentin v |= EMAC_TX_TH_128; 484ab0204e3SJose Abreu else if (mode < 192) 4859f93ac8dSLABBE Corentin v |= EMAC_TX_TH_192; 486ab0204e3SJose Abreu else if (mode < 256) 4879f93ac8dSLABBE Corentin v |= EMAC_TX_TH_256; 4889f93ac8dSLABBE Corentin } 4899f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_CTL1); 4909f93ac8dSLABBE Corentin } 4919f93ac8dSLABBE Corentin 4929f93ac8dSLABBE Corentin static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { 4939f93ac8dSLABBE Corentin .reset = sun8i_dwmac_dma_reset, 4949f93ac8dSLABBE Corentin .init = sun8i_dwmac_dma_init, 4959f93ac8dSLABBE Corentin .dump_regs = sun8i_dwmac_dump_regs, 496ab0204e3SJose Abreu .dma_rx_mode = sun8i_dwmac_dma_operation_mode_rx, 497ab0204e3SJose Abreu .dma_tx_mode = sun8i_dwmac_dma_operation_mode_tx, 4989f93ac8dSLABBE Corentin .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission, 4999f93ac8dSLABBE Corentin .enable_dma_irq = sun8i_dwmac_enable_dma_irq, 5009f93ac8dSLABBE Corentin .disable_dma_irq = sun8i_dwmac_disable_dma_irq, 5019f93ac8dSLABBE Corentin .start_tx = sun8i_dwmac_dma_start_tx, 5029f93ac8dSLABBE Corentin .stop_tx = sun8i_dwmac_dma_stop_tx, 5039f93ac8dSLABBE Corentin .start_rx = sun8i_dwmac_dma_start_rx, 5049f93ac8dSLABBE Corentin .stop_rx = sun8i_dwmac_dma_stop_rx, 5059f93ac8dSLABBE Corentin .dma_interrupt = sun8i_dwmac_dma_interrupt, 5069f93ac8dSLABBE Corentin }; 5079f93ac8dSLABBE Corentin 5089f93ac8dSLABBE Corentin static int sun8i_dwmac_init(struct platform_device *pdev, void *priv) 5099f93ac8dSLABBE Corentin { 5109f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv; 5119f93ac8dSLABBE Corentin int ret; 5129f93ac8dSLABBE Corentin 5139f93ac8dSLABBE Corentin if (gmac->regulator) { 5149f93ac8dSLABBE Corentin ret = regulator_enable(gmac->regulator); 5159f93ac8dSLABBE Corentin if (ret) { 5169f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Fail to enable regulator\n"); 5179f93ac8dSLABBE Corentin return ret; 5189f93ac8dSLABBE Corentin } 5199f93ac8dSLABBE Corentin } 5209f93ac8dSLABBE Corentin 5219f93ac8dSLABBE Corentin ret = clk_prepare_enable(gmac->tx_clk); 5229f93ac8dSLABBE Corentin if (ret) { 5239f93ac8dSLABBE Corentin if (gmac->regulator) 5249f93ac8dSLABBE Corentin regulator_disable(gmac->regulator); 5259f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Could not enable AHB clock\n"); 5269f93ac8dSLABBE Corentin return ret; 5279f93ac8dSLABBE Corentin } 5289f93ac8dSLABBE Corentin 5299f93ac8dSLABBE Corentin return 0; 5309f93ac8dSLABBE Corentin } 5319f93ac8dSLABBE Corentin 5328cad443eSFlorian Fainelli static void sun8i_dwmac_core_init(struct mac_device_info *hw, 5338cad443eSFlorian Fainelli struct net_device *dev) 5349f93ac8dSLABBE Corentin { 5359f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5369f93ac8dSLABBE Corentin u32 v; 5379f93ac8dSLABBE Corentin 5389f93ac8dSLABBE Corentin v = (8 << EMAC_BURSTLEN_SHIFT); /* burst len */ 5399f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_BASIC_CTL1); 5409f93ac8dSLABBE Corentin } 5419f93ac8dSLABBE Corentin 5429f93ac8dSLABBE Corentin static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable) 5439f93ac8dSLABBE Corentin { 5449f93ac8dSLABBE Corentin u32 t, r; 5459f93ac8dSLABBE Corentin 5469f93ac8dSLABBE Corentin t = readl(ioaddr + EMAC_TX_CTL0); 5479f93ac8dSLABBE Corentin r = readl(ioaddr + EMAC_RX_CTL0); 5489f93ac8dSLABBE Corentin if (enable) { 5499f93ac8dSLABBE Corentin t |= EMAC_TX_TRANSMITTER_EN; 5509f93ac8dSLABBE Corentin r |= EMAC_RX_RECEIVER_EN; 5519f93ac8dSLABBE Corentin } else { 5529f93ac8dSLABBE Corentin t &= ~EMAC_TX_TRANSMITTER_EN; 5539f93ac8dSLABBE Corentin r &= ~EMAC_RX_RECEIVER_EN; 5549f93ac8dSLABBE Corentin } 5559f93ac8dSLABBE Corentin writel(t, ioaddr + EMAC_TX_CTL0); 5569f93ac8dSLABBE Corentin writel(r, ioaddr + EMAC_RX_CTL0); 5579f93ac8dSLABBE Corentin } 5589f93ac8dSLABBE Corentin 5599f93ac8dSLABBE Corentin /* Set MAC address at slot reg_n 5609f93ac8dSLABBE Corentin * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST 5619f93ac8dSLABBE Corentin * If addr is NULL, clear the slot 5629f93ac8dSLABBE Corentin */ 5639f93ac8dSLABBE Corentin static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw, 5649f93ac8dSLABBE Corentin unsigned char *addr, 5659f93ac8dSLABBE Corentin unsigned int reg_n) 5669f93ac8dSLABBE Corentin { 5679f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5689f93ac8dSLABBE Corentin u32 v; 5699f93ac8dSLABBE Corentin 5709f93ac8dSLABBE Corentin if (!addr) { 5719f93ac8dSLABBE Corentin writel(0, ioaddr + EMAC_MACADDR_HI(reg_n)); 5729f93ac8dSLABBE Corentin return; 5739f93ac8dSLABBE Corentin } 5749f93ac8dSLABBE Corentin 5759f93ac8dSLABBE Corentin stmmac_set_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), 5769f93ac8dSLABBE Corentin EMAC_MACADDR_LO(reg_n)); 5779f93ac8dSLABBE Corentin if (reg_n > 0) { 5789f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_MACADDR_HI(reg_n)); 5799f93ac8dSLABBE Corentin v |= MAC_ADDR_TYPE_DST; 5809f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_MACADDR_HI(reg_n)); 5819f93ac8dSLABBE Corentin } 5829f93ac8dSLABBE Corentin } 5839f93ac8dSLABBE Corentin 5849f93ac8dSLABBE Corentin static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw, 5859f93ac8dSLABBE Corentin unsigned char *addr, 5869f93ac8dSLABBE Corentin unsigned int reg_n) 5879f93ac8dSLABBE Corentin { 5889f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5899f93ac8dSLABBE Corentin 5909f93ac8dSLABBE Corentin stmmac_get_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), 5919f93ac8dSLABBE Corentin EMAC_MACADDR_LO(reg_n)); 5929f93ac8dSLABBE Corentin } 5939f93ac8dSLABBE Corentin 5949f93ac8dSLABBE Corentin /* caution this function must return non 0 to work */ 5959f93ac8dSLABBE Corentin static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw) 5969f93ac8dSLABBE Corentin { 5979f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 5989f93ac8dSLABBE Corentin u32 v; 5999f93ac8dSLABBE Corentin 6009f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL0); 6019f93ac8dSLABBE Corentin v |= EMAC_RX_DO_CRC; 6029f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL0); 6039f93ac8dSLABBE Corentin 6049f93ac8dSLABBE Corentin return 1; 6059f93ac8dSLABBE Corentin } 6069f93ac8dSLABBE Corentin 6079f93ac8dSLABBE Corentin static void sun8i_dwmac_set_filter(struct mac_device_info *hw, 6089f93ac8dSLABBE Corentin struct net_device *dev) 6099f93ac8dSLABBE Corentin { 6109f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6119f93ac8dSLABBE Corentin u32 v; 6129f93ac8dSLABBE Corentin int i = 1; 6139f93ac8dSLABBE Corentin struct netdev_hw_addr *ha; 6149f93ac8dSLABBE Corentin int macaddrs = netdev_uc_count(dev) + netdev_mc_count(dev) + 1; 6159f93ac8dSLABBE Corentin 6169f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_CTL; 6179f93ac8dSLABBE Corentin 6189f93ac8dSLABBE Corentin if (dev->flags & IFF_PROMISC) { 6199f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_RXALL; 6209f93ac8dSLABBE Corentin } else if (dev->flags & IFF_ALLMULTI) { 6219f93ac8dSLABBE Corentin v |= EMAC_FRM_FLT_MULTICAST; 6229f93ac8dSLABBE Corentin } else if (macaddrs <= hw->unicast_filter_entries) { 6239f93ac8dSLABBE Corentin if (!netdev_mc_empty(dev)) { 6249f93ac8dSLABBE Corentin netdev_for_each_mc_addr(ha, dev) { 6259f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, ha->addr, i); 6269f93ac8dSLABBE Corentin i++; 6279f93ac8dSLABBE Corentin } 6289f93ac8dSLABBE Corentin } 6299f93ac8dSLABBE Corentin if (!netdev_uc_empty(dev)) { 6309f93ac8dSLABBE Corentin netdev_for_each_uc_addr(ha, dev) { 6319f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, ha->addr, i); 6329f93ac8dSLABBE Corentin i++; 6339f93ac8dSLABBE Corentin } 6349f93ac8dSLABBE Corentin } 6359f93ac8dSLABBE Corentin } else { 6369f93ac8dSLABBE Corentin netdev_info(dev, "Too many address, switching to promiscuous\n"); 6379f93ac8dSLABBE Corentin v = EMAC_FRM_FLT_RXALL; 6389f93ac8dSLABBE Corentin } 6399f93ac8dSLABBE Corentin 6409f93ac8dSLABBE Corentin /* Disable unused address filter slots */ 6419f93ac8dSLABBE Corentin while (i < hw->unicast_filter_entries) 6429f93ac8dSLABBE Corentin sun8i_dwmac_set_umac_addr(hw, NULL, i++); 6439f93ac8dSLABBE Corentin 6449f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_FRM_FLT); 6459f93ac8dSLABBE Corentin } 6469f93ac8dSLABBE Corentin 6479f93ac8dSLABBE Corentin static void sun8i_dwmac_flow_ctrl(struct mac_device_info *hw, 6489f93ac8dSLABBE Corentin unsigned int duplex, unsigned int fc, 6499f93ac8dSLABBE Corentin unsigned int pause_time, u32 tx_cnt) 6509f93ac8dSLABBE Corentin { 6519f93ac8dSLABBE Corentin void __iomem *ioaddr = hw->pcsr; 6529f93ac8dSLABBE Corentin u32 v; 6539f93ac8dSLABBE Corentin 6549f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_RX_CTL0); 6559f93ac8dSLABBE Corentin if (fc == FLOW_AUTO) 6569f93ac8dSLABBE Corentin v |= EMAC_RX_FLOW_CTL_EN; 6579f93ac8dSLABBE Corentin else 6589f93ac8dSLABBE Corentin v &= ~EMAC_RX_FLOW_CTL_EN; 6599f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_RX_CTL0); 6609f93ac8dSLABBE Corentin 6619f93ac8dSLABBE Corentin v = readl(ioaddr + EMAC_TX_FLOW_CTL); 6629f93ac8dSLABBE Corentin if (fc == FLOW_AUTO) 6639f93ac8dSLABBE Corentin v |= EMAC_TX_FLOW_CTL_EN; 6649f93ac8dSLABBE Corentin else 6659f93ac8dSLABBE Corentin v &= ~EMAC_TX_FLOW_CTL_EN; 6669f93ac8dSLABBE Corentin writel(v, ioaddr + EMAC_TX_FLOW_CTL); 6679f93ac8dSLABBE Corentin } 6689f93ac8dSLABBE Corentin 6699f93ac8dSLABBE Corentin static int sun8i_dwmac_reset(struct stmmac_priv *priv) 6709f93ac8dSLABBE Corentin { 6719f93ac8dSLABBE Corentin u32 v; 6729f93ac8dSLABBE Corentin int err; 6739f93ac8dSLABBE Corentin 6749f93ac8dSLABBE Corentin v = readl(priv->ioaddr + EMAC_BASIC_CTL1); 6759f93ac8dSLABBE Corentin writel(v | 0x01, priv->ioaddr + EMAC_BASIC_CTL1); 6769f93ac8dSLABBE Corentin 6779f93ac8dSLABBE Corentin /* The timeout was previoulsy set to 10ms, but some board (OrangePI0) 6789f93ac8dSLABBE Corentin * need more if no cable plugged. 100ms seems OK 6799f93ac8dSLABBE Corentin */ 6809f93ac8dSLABBE Corentin err = readl_poll_timeout(priv->ioaddr + EMAC_BASIC_CTL1, v, 6819f93ac8dSLABBE Corentin !(v & 0x01), 100, 100000); 6829f93ac8dSLABBE Corentin 6839f93ac8dSLABBE Corentin if (err) { 6849f93ac8dSLABBE Corentin dev_err(priv->device, "EMAC reset timeout\n"); 6859f93ac8dSLABBE Corentin return -EFAULT; 6869f93ac8dSLABBE Corentin } 6879f93ac8dSLABBE Corentin return 0; 6889f93ac8dSLABBE Corentin } 6899f93ac8dSLABBE Corentin 690634db83bSCorentin Labbe /* Search in mdio-mux node for internal PHY node and get its clk/reset */ 691634db83bSCorentin Labbe static int get_ephy_nodes(struct stmmac_priv *priv) 692634db83bSCorentin Labbe { 693634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 694634db83bSCorentin Labbe struct device_node *mdio_mux, *iphynode; 695634db83bSCorentin Labbe struct device_node *mdio_internal; 696634db83bSCorentin Labbe int ret; 697634db83bSCorentin Labbe 698634db83bSCorentin Labbe mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux"); 699634db83bSCorentin Labbe if (!mdio_mux) { 700634db83bSCorentin Labbe dev_err(priv->device, "Cannot get mdio-mux node\n"); 701634db83bSCorentin Labbe return -ENODEV; 702634db83bSCorentin Labbe } 703634db83bSCorentin Labbe 704634db83bSCorentin Labbe mdio_internal = of_find_compatible_node(mdio_mux, NULL, 705634db83bSCorentin Labbe "allwinner,sun8i-h3-mdio-internal"); 706634db83bSCorentin Labbe if (!mdio_internal) { 707634db83bSCorentin Labbe dev_err(priv->device, "Cannot get internal_mdio node\n"); 708634db83bSCorentin Labbe return -ENODEV; 709634db83bSCorentin Labbe } 710634db83bSCorentin Labbe 711634db83bSCorentin Labbe /* Seek for internal PHY */ 712634db83bSCorentin Labbe for_each_child_of_node(mdio_internal, iphynode) { 713634db83bSCorentin Labbe gmac->ephy_clk = of_clk_get(iphynode, 0); 714634db83bSCorentin Labbe if (IS_ERR(gmac->ephy_clk)) 715634db83bSCorentin Labbe continue; 716634db83bSCorentin Labbe gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL); 717634db83bSCorentin Labbe if (IS_ERR(gmac->rst_ephy)) { 718634db83bSCorentin Labbe ret = PTR_ERR(gmac->rst_ephy); 719634db83bSCorentin Labbe if (ret == -EPROBE_DEFER) 720634db83bSCorentin Labbe return ret; 721634db83bSCorentin Labbe continue; 722634db83bSCorentin Labbe } 723634db83bSCorentin Labbe dev_info(priv->device, "Found internal PHY node\n"); 724634db83bSCorentin Labbe return 0; 725634db83bSCorentin Labbe } 726634db83bSCorentin Labbe return -ENODEV; 727634db83bSCorentin Labbe } 728634db83bSCorentin Labbe 729634db83bSCorentin Labbe static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv) 730634db83bSCorentin Labbe { 731634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 732634db83bSCorentin Labbe int ret; 733634db83bSCorentin Labbe 734634db83bSCorentin Labbe if (gmac->internal_phy_powered) { 735634db83bSCorentin Labbe dev_warn(priv->device, "Internal PHY already powered\n"); 736634db83bSCorentin Labbe return 0; 737634db83bSCorentin Labbe } 738634db83bSCorentin Labbe 739634db83bSCorentin Labbe dev_info(priv->device, "Powering internal PHY\n"); 740634db83bSCorentin Labbe ret = clk_prepare_enable(gmac->ephy_clk); 741634db83bSCorentin Labbe if (ret) { 742634db83bSCorentin Labbe dev_err(priv->device, "Cannot enable internal PHY\n"); 743634db83bSCorentin Labbe return ret; 744634db83bSCorentin Labbe } 745634db83bSCorentin Labbe 746634db83bSCorentin Labbe /* Make sure the EPHY is properly reseted, as U-Boot may leave 747634db83bSCorentin Labbe * it at deasserted state, and thus it may fail to reset EMAC. 748634db83bSCorentin Labbe */ 749634db83bSCorentin Labbe reset_control_assert(gmac->rst_ephy); 750634db83bSCorentin Labbe 751634db83bSCorentin Labbe ret = reset_control_deassert(gmac->rst_ephy); 752634db83bSCorentin Labbe if (ret) { 753634db83bSCorentin Labbe dev_err(priv->device, "Cannot deassert internal phy\n"); 754634db83bSCorentin Labbe clk_disable_unprepare(gmac->ephy_clk); 755634db83bSCorentin Labbe return ret; 756634db83bSCorentin Labbe } 757634db83bSCorentin Labbe 758634db83bSCorentin Labbe gmac->internal_phy_powered = true; 759634db83bSCorentin Labbe 760634db83bSCorentin Labbe return 0; 761634db83bSCorentin Labbe } 762634db83bSCorentin Labbe 763634db83bSCorentin Labbe static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac) 764634db83bSCorentin Labbe { 765634db83bSCorentin Labbe if (!gmac->internal_phy_powered) 766634db83bSCorentin Labbe return 0; 767634db83bSCorentin Labbe 768634db83bSCorentin Labbe clk_disable_unprepare(gmac->ephy_clk); 769634db83bSCorentin Labbe reset_control_assert(gmac->rst_ephy); 770634db83bSCorentin Labbe gmac->internal_phy_powered = false; 771634db83bSCorentin Labbe return 0; 772634db83bSCorentin Labbe } 773634db83bSCorentin Labbe 774634db83bSCorentin Labbe /* MDIO multiplexing switch function 775634db83bSCorentin Labbe * This function is called by the mdio-mux layer when it thinks the mdio bus 776634db83bSCorentin Labbe * multiplexer needs to switch. 777634db83bSCorentin Labbe * 'current_child' is the current value of the mux register 778634db83bSCorentin Labbe * 'desired_child' is the value of the 'reg' property of the target child MDIO 779634db83bSCorentin Labbe * node. 780634db83bSCorentin Labbe * The first time this function is called, current_child == -1. 781634db83bSCorentin Labbe * If current_child == desired_child, then the mux is already set to the 782634db83bSCorentin Labbe * correct bus. 783634db83bSCorentin Labbe */ 784634db83bSCorentin Labbe static int mdio_mux_syscon_switch_fn(int current_child, int desired_child, 785634db83bSCorentin Labbe void *data) 786634db83bSCorentin Labbe { 787634db83bSCorentin Labbe struct stmmac_priv *priv = data; 788634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 789634db83bSCorentin Labbe u32 reg, val; 790634db83bSCorentin Labbe int ret = 0; 791634db83bSCorentin Labbe bool need_power_ephy = false; 792634db83bSCorentin Labbe 793634db83bSCorentin Labbe if (current_child ^ desired_child) { 79425ae15fbSChen-Yu Tsai regmap_field_read(gmac->regmap_field, ®); 795634db83bSCorentin Labbe switch (desired_child) { 796634db83bSCorentin Labbe case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID: 797634db83bSCorentin Labbe dev_info(priv->device, "Switch mux to internal PHY"); 798634db83bSCorentin Labbe val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT; 799634db83bSCorentin Labbe 800634db83bSCorentin Labbe need_power_ephy = true; 801634db83bSCorentin Labbe break; 802634db83bSCorentin Labbe case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID: 803634db83bSCorentin Labbe dev_info(priv->device, "Switch mux to external PHY"); 804634db83bSCorentin Labbe val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN; 805634db83bSCorentin Labbe need_power_ephy = false; 806634db83bSCorentin Labbe break; 807634db83bSCorentin Labbe default: 808634db83bSCorentin Labbe dev_err(priv->device, "Invalid child ID %x\n", 809634db83bSCorentin Labbe desired_child); 810634db83bSCorentin Labbe return -EINVAL; 811634db83bSCorentin Labbe } 81225ae15fbSChen-Yu Tsai regmap_field_write(gmac->regmap_field, val); 813634db83bSCorentin Labbe if (need_power_ephy) { 814634db83bSCorentin Labbe ret = sun8i_dwmac_power_internal_phy(priv); 815634db83bSCorentin Labbe if (ret) 816634db83bSCorentin Labbe return ret; 817634db83bSCorentin Labbe } else { 818634db83bSCorentin Labbe sun8i_dwmac_unpower_internal_phy(gmac); 819634db83bSCorentin Labbe } 820634db83bSCorentin Labbe /* After changing syscon value, the MAC need reset or it will 821634db83bSCorentin Labbe * use the last value (and so the last PHY set). 822634db83bSCorentin Labbe */ 823634db83bSCorentin Labbe ret = sun8i_dwmac_reset(priv); 824634db83bSCorentin Labbe } 825634db83bSCorentin Labbe return ret; 826634db83bSCorentin Labbe } 827634db83bSCorentin Labbe 828634db83bSCorentin Labbe static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv) 829634db83bSCorentin Labbe { 830634db83bSCorentin Labbe int ret; 831634db83bSCorentin Labbe struct device_node *mdio_mux; 832634db83bSCorentin Labbe struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 833634db83bSCorentin Labbe 834634db83bSCorentin Labbe mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux"); 835634db83bSCorentin Labbe if (!mdio_mux) 836634db83bSCorentin Labbe return -ENODEV; 837634db83bSCorentin Labbe 838634db83bSCorentin Labbe ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn, 839634db83bSCorentin Labbe &gmac->mux_handle, priv, priv->mii); 840634db83bSCorentin Labbe return ret; 841634db83bSCorentin Labbe } 842634db83bSCorentin Labbe 8439f93ac8dSLABBE Corentin static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) 8449f93ac8dSLABBE Corentin { 8459f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv->plat->bsp_priv; 8469f93ac8dSLABBE Corentin struct device_node *node = priv->device->of_node; 847d93b07f8SLABBE Corentin int ret; 8489f93ac8dSLABBE Corentin u32 reg, val; 8499f93ac8dSLABBE Corentin 85025ae15fbSChen-Yu Tsai regmap_field_read(gmac->regmap_field, &val); 8519f93ac8dSLABBE Corentin reg = gmac->variant->default_syscon_value; 8529f93ac8dSLABBE Corentin if (reg != val) 8539f93ac8dSLABBE Corentin dev_warn(priv->device, 8549f93ac8dSLABBE Corentin "Current syscon value is not the default %x (expect %x)\n", 8559f93ac8dSLABBE Corentin val, reg); 8569f93ac8dSLABBE Corentin 857634db83bSCorentin Labbe if (gmac->variant->soc_has_internal_phy) { 8581c08ac0cSCorentin Labbe if (of_property_read_bool(node, "allwinner,leds-active-low")) 8599f93ac8dSLABBE Corentin reg |= H3_EPHY_LED_POL; 8609f93ac8dSLABBE Corentin else 8619f93ac8dSLABBE Corentin reg &= ~H3_EPHY_LED_POL; 8629f93ac8dSLABBE Corentin 8631450ba8aSIcenowy Zheng /* Force EPHY xtal frequency to 24MHz. */ 8641450ba8aSIcenowy Zheng reg |= H3_EPHY_CLK_SEL; 8651450ba8aSIcenowy Zheng 866634db83bSCorentin Labbe ret = of_mdio_parse_addr(priv->device, priv->plat->phy_node); 8679f93ac8dSLABBE Corentin if (ret < 0) { 8689f93ac8dSLABBE Corentin dev_err(priv->device, "Could not parse MDIO addr\n"); 8699f93ac8dSLABBE Corentin return ret; 8709f93ac8dSLABBE Corentin } 8719f93ac8dSLABBE Corentin /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY 8729f93ac8dSLABBE Corentin * address. No need to mask it again. 8739f93ac8dSLABBE Corentin */ 874634db83bSCorentin Labbe reg |= 1 << H3_EPHY_ADDR_SHIFT; 8759f93ac8dSLABBE Corentin } 8769f93ac8dSLABBE Corentin 8779f93ac8dSLABBE Corentin if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) { 8789f93ac8dSLABBE Corentin if (val % 100) { 8799f93ac8dSLABBE Corentin dev_err(priv->device, "tx-delay must be a multiple of 100\n"); 8809f93ac8dSLABBE Corentin return -EINVAL; 8819f93ac8dSLABBE Corentin } 8829f93ac8dSLABBE Corentin val /= 100; 8839f93ac8dSLABBE Corentin dev_dbg(priv->device, "set tx-delay to %x\n", val); 8847b270b72SChen-Yu Tsai if (val <= gmac->variant->tx_delay_max) { 8857b270b72SChen-Yu Tsai reg &= ~(gmac->variant->tx_delay_max << 8867b270b72SChen-Yu Tsai SYSCON_ETXDC_SHIFT); 8879f93ac8dSLABBE Corentin reg |= (val << SYSCON_ETXDC_SHIFT); 8889f93ac8dSLABBE Corentin } else { 8899f93ac8dSLABBE Corentin dev_err(priv->device, "Invalid TX clock delay: %d\n", 8909f93ac8dSLABBE Corentin val); 8919f93ac8dSLABBE Corentin return -EINVAL; 8929f93ac8dSLABBE Corentin } 8939f93ac8dSLABBE Corentin } 8949f93ac8dSLABBE Corentin 8959f93ac8dSLABBE Corentin if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) { 8969f93ac8dSLABBE Corentin if (val % 100) { 8979f93ac8dSLABBE Corentin dev_err(priv->device, "rx-delay must be a multiple of 100\n"); 8989f93ac8dSLABBE Corentin return -EINVAL; 8999f93ac8dSLABBE Corentin } 9009f93ac8dSLABBE Corentin val /= 100; 9019f93ac8dSLABBE Corentin dev_dbg(priv->device, "set rx-delay to %x\n", val); 9027b270b72SChen-Yu Tsai if (val <= gmac->variant->rx_delay_max) { 9037b270b72SChen-Yu Tsai reg &= ~(gmac->variant->rx_delay_max << 9047b270b72SChen-Yu Tsai SYSCON_ERXDC_SHIFT); 9059f93ac8dSLABBE Corentin reg |= (val << SYSCON_ERXDC_SHIFT); 9069f93ac8dSLABBE Corentin } else { 9079f93ac8dSLABBE Corentin dev_err(priv->device, "Invalid RX clock delay: %d\n", 9089f93ac8dSLABBE Corentin val); 9099f93ac8dSLABBE Corentin return -EINVAL; 9109f93ac8dSLABBE Corentin } 9119f93ac8dSLABBE Corentin } 9129f93ac8dSLABBE Corentin 9139f93ac8dSLABBE Corentin /* Clear interface mode bits */ 9149f93ac8dSLABBE Corentin reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT); 9159f93ac8dSLABBE Corentin if (gmac->variant->support_rmii) 9169f93ac8dSLABBE Corentin reg &= ~SYSCON_RMII_EN; 9179f93ac8dSLABBE Corentin 918d93b07f8SLABBE Corentin switch (priv->plat->interface) { 9199f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_MII: 9209f93ac8dSLABBE Corentin /* default */ 9219f93ac8dSLABBE Corentin break; 9229f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_RGMII: 9239f93ac8dSLABBE Corentin reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; 9249f93ac8dSLABBE Corentin break; 9259f93ac8dSLABBE Corentin case PHY_INTERFACE_MODE_RMII: 9269f93ac8dSLABBE Corentin reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII; 9279f93ac8dSLABBE Corentin break; 9289f93ac8dSLABBE Corentin default: 9299f93ac8dSLABBE Corentin dev_err(priv->device, "Unsupported interface mode: %s", 9309f93ac8dSLABBE Corentin phy_modes(priv->plat->interface)); 9319f93ac8dSLABBE Corentin return -EINVAL; 9329f93ac8dSLABBE Corentin } 9339f93ac8dSLABBE Corentin 93425ae15fbSChen-Yu Tsai regmap_field_write(gmac->regmap_field, reg); 9359f93ac8dSLABBE Corentin 9369f93ac8dSLABBE Corentin return 0; 9379f93ac8dSLABBE Corentin } 9389f93ac8dSLABBE Corentin 9399f93ac8dSLABBE Corentin static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac) 9409f93ac8dSLABBE Corentin { 9419f93ac8dSLABBE Corentin u32 reg = gmac->variant->default_syscon_value; 9429f93ac8dSLABBE Corentin 94325ae15fbSChen-Yu Tsai regmap_field_write(gmac->regmap_field, reg); 9449f93ac8dSLABBE Corentin } 9459f93ac8dSLABBE Corentin 9469f93ac8dSLABBE Corentin static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) 9479f93ac8dSLABBE Corentin { 9489f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac = priv; 9499f93ac8dSLABBE Corentin 950634db83bSCorentin Labbe if (gmac->variant->soc_has_internal_phy) { 951634db83bSCorentin Labbe /* sun8i_dwmac_exit could be called with mdiomux uninit */ 952634db83bSCorentin Labbe if (gmac->mux_handle) 953634db83bSCorentin Labbe mdio_mux_uninit(gmac->mux_handle); 954634db83bSCorentin Labbe if (gmac->internal_phy_powered) 955634db83bSCorentin Labbe sun8i_dwmac_unpower_internal_phy(gmac); 956634db83bSCorentin Labbe } 957634db83bSCorentin Labbe 958634db83bSCorentin Labbe sun8i_dwmac_unset_syscon(gmac); 959634db83bSCorentin Labbe 960634db83bSCorentin Labbe reset_control_put(gmac->rst_ephy); 9619f93ac8dSLABBE Corentin 9629f93ac8dSLABBE Corentin clk_disable_unprepare(gmac->tx_clk); 9639f93ac8dSLABBE Corentin 9649f93ac8dSLABBE Corentin if (gmac->regulator) 9659f93ac8dSLABBE Corentin regulator_disable(gmac->regulator); 9669f93ac8dSLABBE Corentin } 9679f93ac8dSLABBE Corentin 9689f93ac8dSLABBE Corentin static const struct stmmac_ops sun8i_dwmac_ops = { 9699f93ac8dSLABBE Corentin .core_init = sun8i_dwmac_core_init, 9709f93ac8dSLABBE Corentin .set_mac = sun8i_dwmac_set_mac, 9719f93ac8dSLABBE Corentin .dump_regs = sun8i_dwmac_dump_mac_regs, 9729f93ac8dSLABBE Corentin .rx_ipc = sun8i_dwmac_rx_ipc_enable, 9739f93ac8dSLABBE Corentin .set_filter = sun8i_dwmac_set_filter, 9749f93ac8dSLABBE Corentin .flow_ctrl = sun8i_dwmac_flow_ctrl, 9759f93ac8dSLABBE Corentin .set_umac_addr = sun8i_dwmac_set_umac_addr, 9769f93ac8dSLABBE Corentin .get_umac_addr = sun8i_dwmac_get_umac_addr, 9779f93ac8dSLABBE Corentin }; 9789f93ac8dSLABBE Corentin 9799f93ac8dSLABBE Corentin static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) 9809f93ac8dSLABBE Corentin { 9819f93ac8dSLABBE Corentin struct mac_device_info *mac; 9829f93ac8dSLABBE Corentin struct stmmac_priv *priv = ppriv; 9839f93ac8dSLABBE Corentin int ret; 9849f93ac8dSLABBE Corentin 9859f93ac8dSLABBE Corentin mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); 9869f93ac8dSLABBE Corentin if (!mac) 9879f93ac8dSLABBE Corentin return NULL; 9889f93ac8dSLABBE Corentin 989634db83bSCorentin Labbe ret = sun8i_dwmac_set_syscon(priv); 9909f93ac8dSLABBE Corentin if (ret) 9919f93ac8dSLABBE Corentin return NULL; 9929f93ac8dSLABBE Corentin 9939f93ac8dSLABBE Corentin mac->pcsr = priv->ioaddr; 9949f93ac8dSLABBE Corentin mac->mac = &sun8i_dwmac_ops; 9959f93ac8dSLABBE Corentin mac->dma = &sun8i_dwmac_dma_ops; 9969f93ac8dSLABBE Corentin 9979f93ac8dSLABBE Corentin /* The loopback bit seems to be re-set when link change 9989f93ac8dSLABBE Corentin * Simply mask it each time 9999f93ac8dSLABBE Corentin * Speed 10/100/1000 are set in BIT(2)/BIT(3) 10009f93ac8dSLABBE Corentin */ 10019f93ac8dSLABBE Corentin mac->link.speed_mask = GENMASK(3, 2) | EMAC_LOOPBACK; 10029f93ac8dSLABBE Corentin mac->link.speed10 = EMAC_SPEED_10; 10039f93ac8dSLABBE Corentin mac->link.speed100 = EMAC_SPEED_100; 10049f93ac8dSLABBE Corentin mac->link.speed1000 = EMAC_SPEED_1000; 10059f93ac8dSLABBE Corentin mac->link.duplex = EMAC_DUPLEX_FULL; 10069f93ac8dSLABBE Corentin mac->mii.addr = EMAC_MDIO_CMD; 10079f93ac8dSLABBE Corentin mac->mii.data = EMAC_MDIO_DATA; 10089f93ac8dSLABBE Corentin mac->mii.reg_shift = 4; 10099f93ac8dSLABBE Corentin mac->mii.reg_mask = GENMASK(8, 4); 10109f93ac8dSLABBE Corentin mac->mii.addr_shift = 12; 10119f93ac8dSLABBE Corentin mac->mii.addr_mask = GENMASK(16, 12); 10129f93ac8dSLABBE Corentin mac->mii.clk_csr_shift = 20; 10139f93ac8dSLABBE Corentin mac->mii.clk_csr_mask = GENMASK(22, 20); 10149f93ac8dSLABBE Corentin mac->unicast_filter_entries = 8; 10159f93ac8dSLABBE Corentin 10169f93ac8dSLABBE Corentin /* Synopsys Id is not available */ 10179f93ac8dSLABBE Corentin priv->synopsys_id = 0; 10189f93ac8dSLABBE Corentin 10199f93ac8dSLABBE Corentin return mac; 10209f93ac8dSLABBE Corentin } 10219f93ac8dSLABBE Corentin 102249a06caeSChen-Yu Tsai static struct regmap *sun8i_dwmac_get_syscon_from_dev(struct device_node *node) 102349a06caeSChen-Yu Tsai { 102449a06caeSChen-Yu Tsai struct device_node *syscon_node; 102549a06caeSChen-Yu Tsai struct platform_device *syscon_pdev; 102649a06caeSChen-Yu Tsai struct regmap *regmap = NULL; 102749a06caeSChen-Yu Tsai 102849a06caeSChen-Yu Tsai syscon_node = of_parse_phandle(node, "syscon", 0); 102949a06caeSChen-Yu Tsai if (!syscon_node) 103049a06caeSChen-Yu Tsai return ERR_PTR(-ENODEV); 103149a06caeSChen-Yu Tsai 103249a06caeSChen-Yu Tsai syscon_pdev = of_find_device_by_node(syscon_node); 103349a06caeSChen-Yu Tsai if (!syscon_pdev) { 103449a06caeSChen-Yu Tsai /* platform device might not be probed yet */ 103549a06caeSChen-Yu Tsai regmap = ERR_PTR(-EPROBE_DEFER); 103649a06caeSChen-Yu Tsai goto out_put_node; 103749a06caeSChen-Yu Tsai } 103849a06caeSChen-Yu Tsai 103949a06caeSChen-Yu Tsai /* If no regmap is found then the other device driver is at fault */ 104049a06caeSChen-Yu Tsai regmap = dev_get_regmap(&syscon_pdev->dev, NULL); 104149a06caeSChen-Yu Tsai if (!regmap) 104249a06caeSChen-Yu Tsai regmap = ERR_PTR(-EINVAL); 104349a06caeSChen-Yu Tsai 104449a06caeSChen-Yu Tsai platform_device_put(syscon_pdev); 104549a06caeSChen-Yu Tsai out_put_node: 104649a06caeSChen-Yu Tsai of_node_put(syscon_node); 104749a06caeSChen-Yu Tsai return regmap; 104849a06caeSChen-Yu Tsai } 104949a06caeSChen-Yu Tsai 10509f93ac8dSLABBE Corentin static int sun8i_dwmac_probe(struct platform_device *pdev) 10519f93ac8dSLABBE Corentin { 10529f93ac8dSLABBE Corentin struct plat_stmmacenet_data *plat_dat; 10539f93ac8dSLABBE Corentin struct stmmac_resources stmmac_res; 10549f93ac8dSLABBE Corentin struct sunxi_priv_data *gmac; 10559f93ac8dSLABBE Corentin struct device *dev = &pdev->dev; 10569f93ac8dSLABBE Corentin int ret; 1057634db83bSCorentin Labbe struct stmmac_priv *priv; 1058634db83bSCorentin Labbe struct net_device *ndev; 105925ae15fbSChen-Yu Tsai struct regmap *regmap; 10609f93ac8dSLABBE Corentin 10619f93ac8dSLABBE Corentin ret = stmmac_get_platform_resources(pdev, &stmmac_res); 10629f93ac8dSLABBE Corentin if (ret) 10639f93ac8dSLABBE Corentin return ret; 10649f93ac8dSLABBE Corentin 10659f93ac8dSLABBE Corentin plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 10669f93ac8dSLABBE Corentin if (IS_ERR(plat_dat)) 10679f93ac8dSLABBE Corentin return PTR_ERR(plat_dat); 10689f93ac8dSLABBE Corentin 10699f93ac8dSLABBE Corentin gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); 10709f93ac8dSLABBE Corentin if (!gmac) 10719f93ac8dSLABBE Corentin return -ENOMEM; 10729f93ac8dSLABBE Corentin 10739f93ac8dSLABBE Corentin gmac->variant = of_device_get_match_data(&pdev->dev); 10749f93ac8dSLABBE Corentin if (!gmac->variant) { 10759f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Missing dwmac-sun8i variant\n"); 10769f93ac8dSLABBE Corentin return -EINVAL; 10779f93ac8dSLABBE Corentin } 10789f93ac8dSLABBE Corentin 10799f93ac8dSLABBE Corentin gmac->tx_clk = devm_clk_get(dev, "stmmaceth"); 10809f93ac8dSLABBE Corentin if (IS_ERR(gmac->tx_clk)) { 10819f93ac8dSLABBE Corentin dev_err(dev, "Could not get TX clock\n"); 10829f93ac8dSLABBE Corentin return PTR_ERR(gmac->tx_clk); 10839f93ac8dSLABBE Corentin } 10849f93ac8dSLABBE Corentin 10859f93ac8dSLABBE Corentin /* Optional regulator for PHY */ 10869f93ac8dSLABBE Corentin gmac->regulator = devm_regulator_get_optional(dev, "phy"); 10879f93ac8dSLABBE Corentin if (IS_ERR(gmac->regulator)) { 10889f93ac8dSLABBE Corentin if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) 10899f93ac8dSLABBE Corentin return -EPROBE_DEFER; 10909f93ac8dSLABBE Corentin dev_info(dev, "No regulator found\n"); 10919f93ac8dSLABBE Corentin gmac->regulator = NULL; 10929f93ac8dSLABBE Corentin } 10939f93ac8dSLABBE Corentin 109449a06caeSChen-Yu Tsai /* The "GMAC clock control" register might be located in the 109549a06caeSChen-Yu Tsai * CCU address range (on the R40), or the system control address 109649a06caeSChen-Yu Tsai * range (on most other sun8i and later SoCs). 109749a06caeSChen-Yu Tsai * 109849a06caeSChen-Yu Tsai * The former controls most if not all clocks in the SoC. The 109949a06caeSChen-Yu Tsai * latter has an SoC identification register, and on some SoCs, 110049a06caeSChen-Yu Tsai * controls to map device specific SRAM to either the intended 110149a06caeSChen-Yu Tsai * peripheral, or the CPU address space. 110249a06caeSChen-Yu Tsai * 110349a06caeSChen-Yu Tsai * In either case, there should be a coordinated and restricted 110449a06caeSChen-Yu Tsai * method of accessing the register needed here. This is done by 110549a06caeSChen-Yu Tsai * having the device export a custom regmap, instead of a generic 110649a06caeSChen-Yu Tsai * syscon, which grants all access to all registers. 110749a06caeSChen-Yu Tsai * 110849a06caeSChen-Yu Tsai * To support old device trees, we fall back to using the syscon 110949a06caeSChen-Yu Tsai * interface if possible. 111049a06caeSChen-Yu Tsai */ 111149a06caeSChen-Yu Tsai regmap = sun8i_dwmac_get_syscon_from_dev(pdev->dev.of_node); 111249a06caeSChen-Yu Tsai if (IS_ERR(regmap)) 111349a06caeSChen-Yu Tsai regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 111449a06caeSChen-Yu Tsai "syscon"); 111525ae15fbSChen-Yu Tsai if (IS_ERR(regmap)) { 111625ae15fbSChen-Yu Tsai ret = PTR_ERR(regmap); 11179f93ac8dSLABBE Corentin dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret); 11189f93ac8dSLABBE Corentin return ret; 11199f93ac8dSLABBE Corentin } 11209f93ac8dSLABBE Corentin 112125ae15fbSChen-Yu Tsai gmac->regmap_field = devm_regmap_field_alloc(dev, regmap, 112225ae15fbSChen-Yu Tsai *gmac->variant->syscon_field); 112325ae15fbSChen-Yu Tsai if (IS_ERR(gmac->regmap_field)) { 112425ae15fbSChen-Yu Tsai ret = PTR_ERR(gmac->regmap_field); 112525ae15fbSChen-Yu Tsai dev_err(dev, "Unable to map syscon register: %d\n", ret); 112625ae15fbSChen-Yu Tsai return ret; 112725ae15fbSChen-Yu Tsai } 112825ae15fbSChen-Yu Tsai 11299f93ac8dSLABBE Corentin plat_dat->interface = of_get_phy_mode(dev->of_node); 11309f93ac8dSLABBE Corentin 11319f93ac8dSLABBE Corentin /* platform data specifying hardware features and callbacks. 11329f93ac8dSLABBE Corentin * hardware features were copied from Allwinner drivers. 11339f93ac8dSLABBE Corentin */ 11349f93ac8dSLABBE Corentin plat_dat->rx_coe = STMMAC_RX_COE_TYPE2; 11359f93ac8dSLABBE Corentin plat_dat->tx_coe = 1; 11369f93ac8dSLABBE Corentin plat_dat->has_sun8i = true; 11379f93ac8dSLABBE Corentin plat_dat->bsp_priv = gmac; 11389f93ac8dSLABBE Corentin plat_dat->init = sun8i_dwmac_init; 11399f93ac8dSLABBE Corentin plat_dat->exit = sun8i_dwmac_exit; 11409f93ac8dSLABBE Corentin plat_dat->setup = sun8i_dwmac_setup; 11419f93ac8dSLABBE Corentin 11429f93ac8dSLABBE Corentin ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv); 11439f93ac8dSLABBE Corentin if (ret) 11449f93ac8dSLABBE Corentin return ret; 11459f93ac8dSLABBE Corentin 11469f93ac8dSLABBE Corentin ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 11479f93ac8dSLABBE Corentin if (ret) 1148634db83bSCorentin Labbe goto dwmac_exit; 11499f93ac8dSLABBE Corentin 1150634db83bSCorentin Labbe ndev = dev_get_drvdata(&pdev->dev); 1151634db83bSCorentin Labbe priv = netdev_priv(ndev); 1152634db83bSCorentin Labbe /* The mux must be registered after parent MDIO 1153634db83bSCorentin Labbe * so after stmmac_dvr_probe() 1154634db83bSCorentin Labbe */ 1155634db83bSCorentin Labbe if (gmac->variant->soc_has_internal_phy) { 1156634db83bSCorentin Labbe ret = get_ephy_nodes(priv); 1157634db83bSCorentin Labbe if (ret) 1158634db83bSCorentin Labbe goto dwmac_exit; 1159634db83bSCorentin Labbe ret = sun8i_dwmac_register_mdio_mux(priv); 1160634db83bSCorentin Labbe if (ret) { 1161634db83bSCorentin Labbe dev_err(&pdev->dev, "Failed to register mux\n"); 1162634db83bSCorentin Labbe goto dwmac_mux; 1163634db83bSCorentin Labbe } 1164634db83bSCorentin Labbe } else { 1165634db83bSCorentin Labbe ret = sun8i_dwmac_reset(priv); 1166634db83bSCorentin Labbe if (ret) 1167634db83bSCorentin Labbe goto dwmac_exit; 1168634db83bSCorentin Labbe } 1169634db83bSCorentin Labbe 1170634db83bSCorentin Labbe return ret; 1171634db83bSCorentin Labbe dwmac_mux: 1172634db83bSCorentin Labbe sun8i_dwmac_unset_syscon(gmac); 1173634db83bSCorentin Labbe dwmac_exit: 1174634db83bSCorentin Labbe sun8i_dwmac_exit(pdev, plat_dat->bsp_priv); 11759f93ac8dSLABBE Corentin return ret; 11769f93ac8dSLABBE Corentin } 11779f93ac8dSLABBE Corentin 11789f93ac8dSLABBE Corentin static const struct of_device_id sun8i_dwmac_match[] = { 1179a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun8i-h3-emac", 1180a8ff8ccbSCorentin Labbe .data = &emac_variant_h3 }, 1181a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun8i-v3s-emac", 1182a8ff8ccbSCorentin Labbe .data = &emac_variant_v3s }, 1183a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun8i-a83t-emac", 1184a8ff8ccbSCorentin Labbe .data = &emac_variant_a83t }, 11859bf5085aSChen-Yu Tsai { .compatible = "allwinner,sun8i-r40-gmac", 11869bf5085aSChen-Yu Tsai .data = &emac_variant_r40 }, 1187a8ff8ccbSCorentin Labbe { .compatible = "allwinner,sun50i-a64-emac", 1188a8ff8ccbSCorentin Labbe .data = &emac_variant_a64 }, 11899f93ac8dSLABBE Corentin { } 11909f93ac8dSLABBE Corentin }; 11919f93ac8dSLABBE Corentin MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); 11929f93ac8dSLABBE Corentin 11939f93ac8dSLABBE Corentin static struct platform_driver sun8i_dwmac_driver = { 11949f93ac8dSLABBE Corentin .probe = sun8i_dwmac_probe, 11959f93ac8dSLABBE Corentin .remove = stmmac_pltfr_remove, 11969f93ac8dSLABBE Corentin .driver = { 11979f93ac8dSLABBE Corentin .name = "dwmac-sun8i", 11989f93ac8dSLABBE Corentin .pm = &stmmac_pltfr_pm_ops, 11999f93ac8dSLABBE Corentin .of_match_table = sun8i_dwmac_match, 12009f93ac8dSLABBE Corentin }, 12019f93ac8dSLABBE Corentin }; 12029f93ac8dSLABBE Corentin module_platform_driver(sun8i_dwmac_driver); 12039f93ac8dSLABBE Corentin 12049f93ac8dSLABBE Corentin MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>"); 12059f93ac8dSLABBE Corentin MODULE_DESCRIPTION("Allwinner sun8i DWMAC specific glue layer"); 12069f93ac8dSLABBE Corentin MODULE_LICENSE("GPL"); 1207