Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ethernet: Add TSE PCS support to dwmac-socfpga

This adds support for TSE PCS that uses SGMII adapter when the phy-mode of
the dwmac is set to sgmii.

Signed-off-by: Tien Hock Loh <thloh@altera.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tien Hock Loh and committed by
David S. Miller
fb3bbdb8 927265bc

+448 -20
+19
Documentation/devicetree/bindings/net/socfpga-dwmac.txt
··· 17 17 Optional properties: 18 18 altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if 19 19 DWMAC controller is connected emac splitter. 20 + phy-mode: The phy mode the ethernet operates in 21 + altr,sgmii-to-sgmii-converter: phandle to the TSE SGMII converter 22 + 23 + This device node has additional phandle dependency, the sgmii converter: 24 + 25 + Required properties: 26 + - compatible : Should be altr,gmii-to-sgmii-2.0 27 + - reg-names : Should be "eth_tse_control_port" 20 28 21 29 Example: 30 + 31 + gmii_to_sgmii_converter: phy@0x100000240 { 32 + compatible = "altr,gmii-to-sgmii-2.0"; 33 + reg = <0x00000001 0x00000240 0x00000008>, 34 + <0x00000001 0x00000200 0x00000040>; 35 + reg-names = "eth_tse_control_port"; 36 + clocks = <&sgmii_1_clk_0 &emac1 1 &sgmii_clk_125 &sgmii_clk_125>; 37 + clock-names = "tse_pcs_ref_clk_clock_connection", "tse_rx_cdr_refclk"; 38 + }; 22 39 23 40 gmac0: ethernet@ff700000 { 24 41 compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; ··· 47 30 mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ 48 31 clocks = <&emac_0_clk>; 49 32 clock-names = "stmmaceth"; 33 + phy-mode = "sgmii"; 34 + altr,gmii-to-sgmii-converter = <&gmii_to_sgmii_converter>; 50 35 };
+2 -1
drivers/net/ethernet/stmicro/stmmac/Makefile
··· 11 11 obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o 12 12 obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o 13 13 obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o 14 - obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o 14 + obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o 15 15 obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o 16 16 obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o 17 17 obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o 18 18 stmmac-platform-objs:= stmmac_platform.o 19 + dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o 19 20 20 21 obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o 21 22 stmmac-pci-objs:= stmmac_pci.o
+274
drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
··· 1 + /* Copyright Altera Corporation (C) 2016. All rights reserved. 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License, version 2, 5 + * as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 + * 15 + * Author: Tien Hock Loh <thloh@altera.com> 16 + */ 17 + 18 + #include <linux/mfd/syscon.h> 19 + #include <linux/of.h> 20 + #include <linux/of_address.h> 21 + #include <linux/of_net.h> 22 + #include <linux/phy.h> 23 + #include <linux/regmap.h> 24 + #include <linux/reset.h> 25 + #include <linux/stmmac.h> 26 + 27 + #include "stmmac.h" 28 + #include "stmmac_platform.h" 29 + #include "altr_tse_pcs.h" 30 + 31 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0 32 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII BIT(1) 33 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII BIT(2) 34 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 35 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK GENMASK(1, 0) 36 + 37 + #define TSE_PCS_CONTROL_AN_EN_MASK BIT(12) 38 + #define TSE_PCS_CONTROL_REG 0x00 39 + #define TSE_PCS_CONTROL_RESTART_AN_MASK BIT(9) 40 + #define TSE_PCS_IF_MODE_REG 0x28 41 + #define TSE_PCS_LINK_TIMER_0_REG 0x24 42 + #define TSE_PCS_LINK_TIMER_1_REG 0x26 43 + #define TSE_PCS_SIZE 0x40 44 + #define TSE_PCS_STATUS_AN_COMPLETED_MASK BIT(5) 45 + #define TSE_PCS_STATUS_LINK_MASK 0x0004 46 + #define TSE_PCS_STATUS_REG 0x02 47 + #define TSE_PCS_SGMII_SPEED_1000 BIT(3) 48 + #define TSE_PCS_SGMII_SPEED_100 BIT(2) 49 + #define TSE_PCS_SGMII_SPEED_10 0x0 50 + #define TSE_PCS_SW_RST_MASK 0x8000 51 + #define TSE_PCS_PARTNER_ABILITY_REG 0x0A 52 + #define TSE_PCS_PARTNER_DUPLEX_FULL 0x1000 53 + #define TSE_PCS_PARTNER_DUPLEX_HALF 0x0000 54 + #define TSE_PCS_PARTNER_DUPLEX_MASK 0x1000 55 + #define TSE_PCS_PARTNER_SPEED_MASK GENMASK(11, 10) 56 + #define TSE_PCS_PARTNER_SPEED_1000 BIT(11) 57 + #define TSE_PCS_PARTNER_SPEED_100 BIT(10) 58 + #define TSE_PCS_PARTNER_SPEED_10 0x0000 59 + #define TSE_PCS_PARTNER_SPEED_1000 BIT(11) 60 + #define TSE_PCS_PARTNER_SPEED_100 BIT(10) 61 + #define TSE_PCS_PARTNER_SPEED_10 0x0000 62 + #define TSE_PCS_SGMII_SPEED_MASK GENMASK(3, 2) 63 + #define TSE_PCS_SGMII_LINK_TIMER_0 0x0D40 64 + #define TSE_PCS_SGMII_LINK_TIMER_1 0x0003 65 + #define TSE_PCS_SW_RESET_TIMEOUT 100 66 + #define TSE_PCS_USE_SGMII_AN_MASK BIT(2) 67 + #define TSE_PCS_USE_SGMII_ENA BIT(1) 68 + 69 + #define SGMII_ADAPTER_CTRL_REG 0x00 70 + #define SGMII_ADAPTER_DISABLE 0x0001 71 + #define SGMII_ADAPTER_ENABLE 0x0000 72 + 73 + #define AUTONEGO_LINK_TIMER 20 74 + 75 + static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs) 76 + { 77 + int counter = 0; 78 + u16 val; 79 + 80 + val = readw(base + TSE_PCS_CONTROL_REG); 81 + val |= TSE_PCS_SW_RST_MASK; 82 + writew(val, base + TSE_PCS_CONTROL_REG); 83 + 84 + while (counter < TSE_PCS_SW_RESET_TIMEOUT) { 85 + val = readw(base + TSE_PCS_CONTROL_REG); 86 + val &= TSE_PCS_SW_RST_MASK; 87 + if (val == 0) 88 + break; 89 + counter++; 90 + udelay(1); 91 + } 92 + if (counter >= TSE_PCS_SW_RESET_TIMEOUT) { 93 + dev_err(pcs->dev, "PCS could not get out of sw reset\n"); 94 + return -ETIMEDOUT; 95 + } 96 + 97 + return 0; 98 + } 99 + 100 + int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs) 101 + { 102 + int ret = 0; 103 + 104 + writew(TSE_PCS_USE_SGMII_ENA, base + TSE_PCS_IF_MODE_REG); 105 + 106 + writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG); 107 + writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG); 108 + 109 + ret = tse_pcs_reset(base, pcs); 110 + if (ret == 0) 111 + writew(SGMII_ADAPTER_ENABLE, 112 + pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); 113 + 114 + return ret; 115 + } 116 + 117 + static void pcs_link_timer_callback(unsigned long data) 118 + { 119 + u16 val = 0; 120 + struct tse_pcs *pcs = (struct tse_pcs *)data; 121 + void __iomem *tse_pcs_base = pcs->tse_pcs_base; 122 + void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; 123 + 124 + val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); 125 + val &= TSE_PCS_STATUS_LINK_MASK; 126 + 127 + if (val != 0) { 128 + dev_dbg(pcs->dev, "Adapter: Link is established\n"); 129 + writew(SGMII_ADAPTER_ENABLE, 130 + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); 131 + } else { 132 + mod_timer(&pcs->aneg_link_timer, jiffies + 133 + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); 134 + } 135 + } 136 + 137 + static void auto_nego_timer_callback(unsigned long data) 138 + { 139 + u16 val = 0; 140 + u16 speed = 0; 141 + u16 duplex = 0; 142 + struct tse_pcs *pcs = (struct tse_pcs *)data; 143 + void __iomem *tse_pcs_base = pcs->tse_pcs_base; 144 + void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; 145 + 146 + val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); 147 + val &= TSE_PCS_STATUS_AN_COMPLETED_MASK; 148 + 149 + if (val != 0) { 150 + dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n"); 151 + val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG); 152 + speed = val & TSE_PCS_PARTNER_SPEED_MASK; 153 + duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK; 154 + 155 + if (speed == TSE_PCS_PARTNER_SPEED_10 && 156 + duplex == TSE_PCS_PARTNER_DUPLEX_FULL) 157 + dev_dbg(pcs->dev, 158 + "Adapter: Link Partner is Up - 10/Full\n"); 159 + else if (speed == TSE_PCS_PARTNER_SPEED_100 && 160 + duplex == TSE_PCS_PARTNER_DUPLEX_FULL) 161 + dev_dbg(pcs->dev, 162 + "Adapter: Link Partner is Up - 100/Full\n"); 163 + else if (speed == TSE_PCS_PARTNER_SPEED_1000 && 164 + duplex == TSE_PCS_PARTNER_DUPLEX_FULL) 165 + dev_dbg(pcs->dev, 166 + "Adapter: Link Partner is Up - 1000/Full\n"); 167 + else if (speed == TSE_PCS_PARTNER_SPEED_10 && 168 + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) 169 + dev_err(pcs->dev, 170 + "Adapter does not support Half Duplex\n"); 171 + else if (speed == TSE_PCS_PARTNER_SPEED_100 && 172 + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) 173 + dev_err(pcs->dev, 174 + "Adapter does not support Half Duplex\n"); 175 + else if (speed == TSE_PCS_PARTNER_SPEED_1000 && 176 + duplex == TSE_PCS_PARTNER_DUPLEX_HALF) 177 + dev_err(pcs->dev, 178 + "Adapter does not support Half Duplex\n"); 179 + else 180 + dev_err(pcs->dev, 181 + "Adapter: Invalid Partner Speed and Duplex\n"); 182 + 183 + if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL && 184 + (speed == TSE_PCS_PARTNER_SPEED_10 || 185 + speed == TSE_PCS_PARTNER_SPEED_100 || 186 + speed == TSE_PCS_PARTNER_SPEED_1000)) 187 + writew(SGMII_ADAPTER_ENABLE, 188 + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); 189 + } else { 190 + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); 191 + val |= TSE_PCS_CONTROL_RESTART_AN_MASK; 192 + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); 193 + 194 + tse_pcs_reset(tse_pcs_base, pcs); 195 + mod_timer(&pcs->aneg_link_timer, jiffies + 196 + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); 197 + } 198 + } 199 + 200 + static void aneg_link_timer_callback(unsigned long data) 201 + { 202 + struct tse_pcs *pcs = (struct tse_pcs *)data; 203 + 204 + if (pcs->autoneg == AUTONEG_ENABLE) 205 + auto_nego_timer_callback(data); 206 + else if (pcs->autoneg == AUTONEG_DISABLE) 207 + pcs_link_timer_callback(data); 208 + } 209 + 210 + void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, 211 + unsigned int speed) 212 + { 213 + void __iomem *tse_pcs_base = pcs->tse_pcs_base; 214 + void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; 215 + u32 val; 216 + 217 + writew(SGMII_ADAPTER_ENABLE, 218 + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); 219 + 220 + pcs->autoneg = phy_dev->autoneg; 221 + 222 + if (phy_dev->autoneg == AUTONEG_ENABLE) { 223 + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); 224 + val |= TSE_PCS_CONTROL_AN_EN_MASK; 225 + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); 226 + 227 + val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); 228 + val |= TSE_PCS_USE_SGMII_AN_MASK; 229 + writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); 230 + 231 + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); 232 + val |= TSE_PCS_CONTROL_RESTART_AN_MASK; 233 + 234 + tse_pcs_reset(tse_pcs_base, pcs); 235 + 236 + setup_timer(&pcs->aneg_link_timer, 237 + aneg_link_timer_callback, (unsigned long)pcs); 238 + mod_timer(&pcs->aneg_link_timer, jiffies + 239 + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); 240 + } else if (phy_dev->autoneg == AUTONEG_DISABLE) { 241 + val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); 242 + val &= ~TSE_PCS_CONTROL_AN_EN_MASK; 243 + writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); 244 + 245 + val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); 246 + val &= ~TSE_PCS_USE_SGMII_AN_MASK; 247 + writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); 248 + 249 + val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); 250 + val &= ~TSE_PCS_SGMII_SPEED_MASK; 251 + 252 + switch (speed) { 253 + case 1000: 254 + val |= TSE_PCS_SGMII_SPEED_1000; 255 + break; 256 + case 100: 257 + val |= TSE_PCS_SGMII_SPEED_100; 258 + break; 259 + case 10: 260 + val |= TSE_PCS_SGMII_SPEED_10; 261 + break; 262 + default: 263 + return; 264 + } 265 + writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); 266 + 267 + tse_pcs_reset(tse_pcs_base, pcs); 268 + 269 + setup_timer(&pcs->aneg_link_timer, 270 + aneg_link_timer_callback, (unsigned long)pcs); 271 + mod_timer(&pcs->aneg_link_timer, jiffies + 272 + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); 273 + } 274 + }
+36
drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
··· 1 + /* Copyright Altera Corporation (C) 2016. All rights reserved. 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License, version 2, 5 + * as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 + * 15 + * Author: Tien Hock Loh <thloh@altera.com> 16 + */ 17 + 18 + #ifndef __TSE_PCS_H__ 19 + #define __TSE_PCS_H__ 20 + 21 + #include <linux/phy.h> 22 + #include <linux/timer.h> 23 + 24 + struct tse_pcs { 25 + struct device *dev; 26 + void __iomem *tse_pcs_base; 27 + void __iomem *sgmii_adapter_base; 28 + struct timer_list aneg_link_timer; 29 + int autoneg; 30 + }; 31 + 32 + int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs); 33 + void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, 34 + unsigned int speed); 35 + 36 + #endif /* __TSE_PCS_H__ */
+117 -19
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
··· 27 27 #include "stmmac.h" 28 28 #include "stmmac_platform.h" 29 29 30 + #include "altr_tse_pcs.h" 31 + 32 + #define SGMII_ADAPTER_CTRL_REG 0x00 33 + #define SGMII_ADAPTER_DISABLE 0x0001 34 + 30 35 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 31 36 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 32 37 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 ··· 57 52 struct reset_control *stmmac_rst; 58 53 void __iomem *splitter_base; 59 54 bool f2h_ptp_ref_clk; 55 + struct tse_pcs pcs; 60 56 }; 61 57 62 58 static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) 63 59 { 64 60 struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; 65 61 void __iomem *splitter_base = dwmac->splitter_base; 62 + void __iomem *tse_pcs_base = dwmac->pcs.tse_pcs_base; 63 + void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base; 64 + struct device *dev = dwmac->dev; 65 + struct net_device *ndev = dev_get_drvdata(dev); 66 + struct phy_device *phy_dev = ndev->phydev; 66 67 u32 val; 67 68 68 - if (!splitter_base) 69 - return; 69 + if ((tse_pcs_base) && (sgmii_adapter_base)) 70 + writew(SGMII_ADAPTER_DISABLE, 71 + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); 70 72 71 - val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); 72 - val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; 73 + if (splitter_base) { 74 + val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); 75 + val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; 73 76 74 - switch (speed) { 75 - case 1000: 76 - val |= EMAC_SPLITTER_CTRL_SPEED_1000; 77 - break; 78 - case 100: 79 - val |= EMAC_SPLITTER_CTRL_SPEED_100; 80 - break; 81 - case 10: 82 - val |= EMAC_SPLITTER_CTRL_SPEED_10; 83 - break; 84 - default: 85 - return; 77 + switch (speed) { 78 + case 1000: 79 + val |= EMAC_SPLITTER_CTRL_SPEED_1000; 80 + break; 81 + case 100: 82 + val |= EMAC_SPLITTER_CTRL_SPEED_100; 83 + break; 84 + case 10: 85 + val |= EMAC_SPLITTER_CTRL_SPEED_10; 86 + break; 87 + default: 88 + return; 89 + } 90 + writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); 86 91 } 87 92 88 - writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); 93 + if (tse_pcs_base && sgmii_adapter_base) 94 + tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed); 89 95 } 90 96 91 97 static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) ··· 104 88 struct device_node *np = dev->of_node; 105 89 struct regmap *sys_mgr_base_addr; 106 90 u32 reg_offset, reg_shift; 107 - int ret; 108 - struct device_node *np_splitter; 91 + int ret, index; 92 + struct device_node *np_splitter = NULL; 93 + struct device_node *np_sgmii_adapter = NULL; 109 94 struct resource res_splitter; 95 + struct resource res_tse_pcs; 96 + struct resource res_sgmii_adapter; 110 97 111 98 dwmac->interface = of_get_phy_mode(np); 112 99 ··· 147 128 } 148 129 } 149 130 131 + np_sgmii_adapter = of_parse_phandle(np, 132 + "altr,gmii-to-sgmii-converter", 0); 133 + if (np_sgmii_adapter) { 134 + index = of_property_match_string(np_sgmii_adapter, "reg-names", 135 + "hps_emac_interface_splitter_avalon_slave"); 136 + 137 + if (index >= 0) { 138 + if (of_address_to_resource(np_sgmii_adapter, index, 139 + &res_splitter)) { 140 + dev_err(dev, 141 + "%s: ERROR: missing emac splitter address\n", 142 + __func__); 143 + return -EINVAL; 144 + } 145 + 146 + dwmac->splitter_base = 147 + devm_ioremap_resource(dev, &res_splitter); 148 + 149 + if (IS_ERR(dwmac->splitter_base)) { 150 + dev_err(dev, 151 + "%s: ERROR: failed mapping emac splitter\n", 152 + __func__); 153 + return PTR_ERR(dwmac->splitter_base); 154 + } 155 + } 156 + 157 + index = of_property_match_string(np_sgmii_adapter, "reg-names", 158 + "gmii_to_sgmii_adapter_avalon_slave"); 159 + 160 + if (index >= 0) { 161 + if (of_address_to_resource(np_sgmii_adapter, index, 162 + &res_sgmii_adapter)) { 163 + dev_err(dev, 164 + "%s: ERROR: failed mapping adapter\n", 165 + __func__); 166 + return -EINVAL; 167 + } 168 + 169 + dwmac->pcs.sgmii_adapter_base = 170 + devm_ioremap_resource(dev, &res_sgmii_adapter); 171 + 172 + if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) { 173 + dev_err(dev, "%s: failed to mapping adapter\n", 174 + __func__); 175 + return PTR_ERR(dwmac->pcs.sgmii_adapter_base); 176 + } 177 + } 178 + 179 + index = of_property_match_string(np_sgmii_adapter, "reg-names", 180 + "eth_tse_control_port"); 181 + 182 + if (index >= 0) { 183 + if (of_address_to_resource(np_sgmii_adapter, index, 184 + &res_tse_pcs)) { 185 + dev_err(dev, 186 + "%s: ERROR: failed mapping tse control port\n", 187 + __func__); 188 + return -EINVAL; 189 + } 190 + 191 + dwmac->pcs.tse_pcs_base = 192 + devm_ioremap_resource(dev, &res_tse_pcs); 193 + 194 + if (IS_ERR(dwmac->pcs.tse_pcs_base)) { 195 + dev_err(dev, 196 + "%s: ERROR: failed mapping tse control port\n", 197 + __func__); 198 + return PTR_ERR(dwmac->pcs.sgmii_adapter_base); 199 + } 200 + } 201 + } 150 202 dwmac->reg_offset = reg_offset; 151 203 dwmac->reg_shift = reg_shift; 152 204 dwmac->sys_mgr_base_addr = sys_mgr_base_addr; ··· 241 151 break; 242 152 case PHY_INTERFACE_MODE_MII: 243 153 case PHY_INTERFACE_MODE_GMII: 154 + case PHY_INTERFACE_MODE_SGMII: 244 155 val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; 245 156 break; 246 157 default: ··· 282 191 */ 283 192 if (dwmac->stmmac_rst) 284 193 reset_control_deassert(dwmac->stmmac_rst); 194 + if (phymode == PHY_INTERFACE_MODE_SGMII) { 195 + if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { 196 + dev_err(dwmac->dev, "Unable to initialize TSE PCS"); 197 + return -EINVAL; 198 + } 199 + } 285 200 286 201 return 0; 287 202 } ··· 322 225 plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; 323 226 324 227 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 228 + 325 229 if (!ret) { 326 230 struct net_device *ndev = platform_get_drvdata(pdev); 327 231 struct stmmac_priv *stpriv = netdev_priv(ndev);