1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright Altera Corporation (C) 2014. All rights reserved. 3 * 4 * Adopted from dwmac-sti.c 5 */ 6 7 #include <linux/mfd/altera-sysmgr.h> 8 #include <linux/of.h> 9 #include <linux/of_address.h> 10 #include <linux/of_net.h> 11 #include <linux/phy.h> 12 #include <linux/regmap.h> 13 #include <linux/reset.h> 14 #include <linux/stmmac.h> 15 16 #include "stmmac.h" 17 #include "stmmac_platform.h" 18 19 #include "altr_tse_pcs.h" 20 21 #define SGMII_ADAPTER_CTRL_REG 0x00 22 #define SGMII_ADAPTER_DISABLE 0x0001 23 24 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 25 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 26 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 27 #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 28 #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 29 #define SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK 0x00000010 30 31 #define SYSMGR_FPGAGRP_MODULE_REG 0x00000028 32 #define SYSMGR_FPGAGRP_MODULE_EMAC 0x00000004 33 34 #define EMAC_SPLITTER_CTRL_REG 0x0 35 #define EMAC_SPLITTER_CTRL_SPEED_MASK 0x3 36 #define EMAC_SPLITTER_CTRL_SPEED_10 0x2 37 #define EMAC_SPLITTER_CTRL_SPEED_100 0x3 38 #define EMAC_SPLITTER_CTRL_SPEED_1000 0x0 39 40 struct socfpga_dwmac { 41 int interface; 42 u32 reg_offset; 43 u32 reg_shift; 44 struct device *dev; 45 struct regmap *sys_mgr_base_addr; 46 struct reset_control *stmmac_rst; 47 struct reset_control *stmmac_ocp_rst; 48 void __iomem *splitter_base; 49 bool f2h_ptp_ref_clk; 50 struct tse_pcs pcs; 51 }; 52 53 static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) 54 { 55 struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; 56 void __iomem *splitter_base = dwmac->splitter_base; 57 void __iomem *tse_pcs_base = dwmac->pcs.tse_pcs_base; 58 void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base; 59 struct device *dev = dwmac->dev; 60 struct net_device *ndev = dev_get_drvdata(dev); 61 struct phy_device *phy_dev = ndev->phydev; 62 u32 val; 63 64 if ((tse_pcs_base) && (sgmii_adapter_base)) 65 writew(SGMII_ADAPTER_DISABLE, 66 sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); 67 68 if (splitter_base) { 69 val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); 70 val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; 71 72 switch (speed) { 73 case 1000: 74 val |= EMAC_SPLITTER_CTRL_SPEED_1000; 75 break; 76 case 100: 77 val |= EMAC_SPLITTER_CTRL_SPEED_100; 78 break; 79 case 10: 80 val |= EMAC_SPLITTER_CTRL_SPEED_10; 81 break; 82 default: 83 return; 84 } 85 writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); 86 } 87 88 if (tse_pcs_base && sgmii_adapter_base) 89 tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed); 90 } 91 92 static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) 93 { 94 struct device_node *np = dev->of_node; 95 struct regmap *sys_mgr_base_addr; 96 u32 reg_offset, reg_shift; 97 int ret, index; 98 struct device_node *np_splitter = NULL; 99 struct device_node *np_sgmii_adapter = NULL; 100 struct resource res_splitter; 101 struct resource res_tse_pcs; 102 struct resource res_sgmii_adapter; 103 104 dwmac->interface = of_get_phy_mode(np); 105 106 sys_mgr_base_addr = 107 altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); 108 if (IS_ERR(sys_mgr_base_addr)) { 109 dev_info(dev, "No sysmgr-syscon node found\n"); 110 return PTR_ERR(sys_mgr_base_addr); 111 } 112 113 ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset); 114 if (ret) { 115 dev_info(dev, "Could not read reg_offset from sysmgr-syscon!\n"); 116 return -EINVAL; 117 } 118 119 ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, ®_shift); 120 if (ret) { 121 dev_info(dev, "Could not read reg_shift from sysmgr-syscon!\n"); 122 return -EINVAL; 123 } 124 125 dwmac->f2h_ptp_ref_clk = of_property_read_bool(np, "altr,f2h_ptp_ref_clk"); 126 127 np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0); 128 if (np_splitter) { 129 ret = of_address_to_resource(np_splitter, 0, &res_splitter); 130 of_node_put(np_splitter); 131 if (ret) { 132 dev_info(dev, "Missing emac splitter address\n"); 133 return -EINVAL; 134 } 135 136 dwmac->splitter_base = devm_ioremap_resource(dev, &res_splitter); 137 if (IS_ERR(dwmac->splitter_base)) { 138 dev_info(dev, "Failed to mapping emac splitter\n"); 139 return PTR_ERR(dwmac->splitter_base); 140 } 141 } 142 143 np_sgmii_adapter = of_parse_phandle(np, 144 "altr,gmii-to-sgmii-converter", 0); 145 if (np_sgmii_adapter) { 146 index = of_property_match_string(np_sgmii_adapter, "reg-names", 147 "hps_emac_interface_splitter_avalon_slave"); 148 149 if (index >= 0) { 150 if (of_address_to_resource(np_sgmii_adapter, index, 151 &res_splitter)) { 152 dev_err(dev, 153 "%s: ERROR: missing emac splitter address\n", 154 __func__); 155 ret = -EINVAL; 156 goto err_node_put; 157 } 158 159 dwmac->splitter_base = 160 devm_ioremap_resource(dev, &res_splitter); 161 162 if (IS_ERR(dwmac->splitter_base)) { 163 ret = PTR_ERR(dwmac->splitter_base); 164 goto err_node_put; 165 } 166 } 167 168 index = of_property_match_string(np_sgmii_adapter, "reg-names", 169 "gmii_to_sgmii_adapter_avalon_slave"); 170 171 if (index >= 0) { 172 if (of_address_to_resource(np_sgmii_adapter, index, 173 &res_sgmii_adapter)) { 174 dev_err(dev, 175 "%s: ERROR: failed mapping adapter\n", 176 __func__); 177 ret = -EINVAL; 178 goto err_node_put; 179 } 180 181 dwmac->pcs.sgmii_adapter_base = 182 devm_ioremap_resource(dev, &res_sgmii_adapter); 183 184 if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) { 185 ret = PTR_ERR(dwmac->pcs.sgmii_adapter_base); 186 goto err_node_put; 187 } 188 } 189 190 index = of_property_match_string(np_sgmii_adapter, "reg-names", 191 "eth_tse_control_port"); 192 193 if (index >= 0) { 194 if (of_address_to_resource(np_sgmii_adapter, index, 195 &res_tse_pcs)) { 196 dev_err(dev, 197 "%s: ERROR: failed mapping tse control port\n", 198 __func__); 199 ret = -EINVAL; 200 goto err_node_put; 201 } 202 203 dwmac->pcs.tse_pcs_base = 204 devm_ioremap_resource(dev, &res_tse_pcs); 205 206 if (IS_ERR(dwmac->pcs.tse_pcs_base)) { 207 ret = PTR_ERR(dwmac->pcs.tse_pcs_base); 208 goto err_node_put; 209 } 210 } 211 } 212 dwmac->reg_offset = reg_offset; 213 dwmac->reg_shift = reg_shift; 214 dwmac->sys_mgr_base_addr = sys_mgr_base_addr; 215 dwmac->dev = dev; 216 of_node_put(np_sgmii_adapter); 217 218 return 0; 219 220 err_node_put: 221 of_node_put(np_sgmii_adapter); 222 return ret; 223 } 224 225 static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) 226 { 227 struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; 228 int phymode = dwmac->interface; 229 u32 reg_offset = dwmac->reg_offset; 230 u32 reg_shift = dwmac->reg_shift; 231 u32 ctrl, val, module; 232 233 switch (phymode) { 234 case PHY_INTERFACE_MODE_RGMII: 235 case PHY_INTERFACE_MODE_RGMII_ID: 236 val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; 237 break; 238 case PHY_INTERFACE_MODE_MII: 239 case PHY_INTERFACE_MODE_GMII: 240 case PHY_INTERFACE_MODE_SGMII: 241 val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; 242 break; 243 default: 244 dev_err(dwmac->dev, "bad phy mode %d\n", phymode); 245 return -EINVAL; 246 } 247 248 /* Overwrite val to GMII if splitter core is enabled. The phymode here 249 * is the actual phy mode on phy hardware, but phy interface from 250 * EMAC core is GMII. 251 */ 252 if (dwmac->splitter_base) 253 val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; 254 255 /* Assert reset to the enet controller before changing the phy mode */ 256 reset_control_assert(dwmac->stmmac_ocp_rst); 257 reset_control_assert(dwmac->stmmac_rst); 258 259 regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); 260 ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift); 261 ctrl |= val << reg_shift; 262 263 if (dwmac->f2h_ptp_ref_clk || 264 phymode == PHY_INTERFACE_MODE_MII || 265 phymode == PHY_INTERFACE_MODE_GMII || 266 phymode == PHY_INTERFACE_MODE_SGMII) { 267 ctrl |= SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2); 268 regmap_read(sys_mgr_base_addr, SYSMGR_FPGAGRP_MODULE_REG, 269 &module); 270 module |= (SYSMGR_FPGAGRP_MODULE_EMAC << (reg_shift / 2)); 271 regmap_write(sys_mgr_base_addr, SYSMGR_FPGAGRP_MODULE_REG, 272 module); 273 } else { 274 ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2)); 275 } 276 277 regmap_write(sys_mgr_base_addr, reg_offset, ctrl); 278 279 /* Deassert reset for the phy configuration to be sampled by 280 * the enet controller, and operation to start in requested mode 281 */ 282 reset_control_deassert(dwmac->stmmac_ocp_rst); 283 reset_control_deassert(dwmac->stmmac_rst); 284 if (phymode == PHY_INTERFACE_MODE_SGMII) { 285 if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { 286 dev_err(dwmac->dev, "Unable to initialize TSE PCS"); 287 return -EINVAL; 288 } 289 } 290 291 return 0; 292 } 293 294 static int socfpga_dwmac_probe(struct platform_device *pdev) 295 { 296 struct plat_stmmacenet_data *plat_dat; 297 struct stmmac_resources stmmac_res; 298 struct device *dev = &pdev->dev; 299 int ret; 300 struct socfpga_dwmac *dwmac; 301 struct net_device *ndev; 302 struct stmmac_priv *stpriv; 303 304 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 305 if (ret) 306 return ret; 307 308 plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 309 if (IS_ERR(plat_dat)) 310 return PTR_ERR(plat_dat); 311 312 dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); 313 if (!dwmac) { 314 ret = -ENOMEM; 315 goto err_remove_config_dt; 316 } 317 318 dwmac->stmmac_ocp_rst = devm_reset_control_get_optional(dev, "stmmaceth-ocp"); 319 if (IS_ERR(dwmac->stmmac_ocp_rst)) { 320 ret = PTR_ERR(dwmac->stmmac_ocp_rst); 321 dev_err(dev, "error getting reset control of ocp %d\n", ret); 322 goto err_remove_config_dt; 323 } 324 325 reset_control_deassert(dwmac->stmmac_ocp_rst); 326 327 ret = socfpga_dwmac_parse_data(dwmac, dev); 328 if (ret) { 329 dev_err(dev, "Unable to parse OF data\n"); 330 goto err_remove_config_dt; 331 } 332 333 plat_dat->bsp_priv = dwmac; 334 plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; 335 336 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 337 if (ret) 338 goto err_remove_config_dt; 339 340 ndev = platform_get_drvdata(pdev); 341 stpriv = netdev_priv(ndev); 342 343 /* The socfpga driver needs to control the stmmac reset to set the phy 344 * mode. Create a copy of the core reset handle so it can be used by 345 * the driver later. 346 */ 347 dwmac->stmmac_rst = stpriv->plat->stmmac_rst; 348 349 ret = socfpga_dwmac_set_phy_mode(dwmac); 350 if (ret) 351 goto err_dvr_remove; 352 353 return 0; 354 355 err_dvr_remove: 356 stmmac_dvr_remove(&pdev->dev); 357 err_remove_config_dt: 358 stmmac_remove_config_dt(pdev, plat_dat); 359 360 return ret; 361 } 362 363 #ifdef CONFIG_PM_SLEEP 364 static int socfpga_dwmac_resume(struct device *dev) 365 { 366 struct net_device *ndev = dev_get_drvdata(dev); 367 struct stmmac_priv *priv = netdev_priv(ndev); 368 369 socfpga_dwmac_set_phy_mode(priv->plat->bsp_priv); 370 371 /* Before the enet controller is suspended, the phy is suspended. 372 * This causes the phy clock to be gated. The enet controller is 373 * resumed before the phy, so the clock is still gated "off" when 374 * the enet controller is resumed. This code makes sure the phy 375 * is "resumed" before reinitializing the enet controller since 376 * the enet controller depends on an active phy clock to complete 377 * a DMA reset. A DMA reset will "time out" if executed 378 * with no phy clock input on the Synopsys enet controller. 379 * Verified through Synopsys Case #8000711656. 380 * 381 * Note that the phy clock is also gated when the phy is isolated. 382 * Phy "suspend" and "isolate" controls are located in phy basic 383 * control register 0, and can be modified by the phy driver 384 * framework. 385 */ 386 if (ndev->phydev) 387 phy_resume(ndev->phydev); 388 389 return stmmac_resume(dev); 390 } 391 #endif /* CONFIG_PM_SLEEP */ 392 393 static SIMPLE_DEV_PM_OPS(socfpga_dwmac_pm_ops, stmmac_suspend, 394 socfpga_dwmac_resume); 395 396 static const struct of_device_id socfpga_dwmac_match[] = { 397 { .compatible = "altr,socfpga-stmmac" }, 398 { } 399 }; 400 MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); 401 402 static struct platform_driver socfpga_dwmac_driver = { 403 .probe = socfpga_dwmac_probe, 404 .remove = stmmac_pltfr_remove, 405 .driver = { 406 .name = "socfpga-dwmac", 407 .pm = &socfpga_dwmac_pm_ops, 408 .of_match_table = socfpga_dwmac_match, 409 }, 410 }; 411 module_platform_driver(socfpga_dwmac_driver); 412 413 MODULE_LICENSE("GPL v2"); 414