| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* Copyright Altera Corporation (C) 2014. 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 | 3 | * |
|---|
| 15 | 4 | * Adopted from dwmac-sti.c |
|---|
| 16 | 5 | */ |
|---|
| 17 | 6 | |
|---|
| 18 | | -#include <linux/mfd/syscon.h> |
|---|
| 7 | +#include <linux/mfd/altera-sysmgr.h> |
|---|
| 19 | 8 | #include <linux/of.h> |
|---|
| 20 | 9 | #include <linux/of_address.h> |
|---|
| 21 | 10 | #include <linux/of_net.h> |
|---|
| .. | .. |
|---|
| 29 | 18 | |
|---|
| 30 | 19 | #include "altr_tse_pcs.h" |
|---|
| 31 | 20 | |
|---|
| 32 | | -#define SGMII_ADAPTER_CTRL_REG 0x00 |
|---|
| 33 | | -#define SGMII_ADAPTER_DISABLE 0x0001 |
|---|
| 34 | | - |
|---|
| 35 | 21 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 |
|---|
| 36 | 22 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 |
|---|
| 37 | 23 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 |
|---|
| 38 | 24 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 |
|---|
| 39 | 25 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 |
|---|
| 40 | 26 | #define SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK 0x00000010 |
|---|
| 27 | +#define SYSMGR_GEN10_EMACGRP_CTRL_PTP_REF_CLK_MASK 0x00000100 |
|---|
| 41 | 28 | |
|---|
| 42 | 29 | #define SYSMGR_FPGAGRP_MODULE_REG 0x00000028 |
|---|
| 43 | 30 | #define SYSMGR_FPGAGRP_MODULE_EMAC 0x00000004 |
|---|
| 31 | +#define SYSMGR_FPGAINTF_EMAC_REG 0x00000070 |
|---|
| 32 | +#define SYSMGR_FPGAINTF_EMAC_BIT 0x1 |
|---|
| 44 | 33 | |
|---|
| 45 | 34 | #define EMAC_SPLITTER_CTRL_REG 0x0 |
|---|
| 46 | 35 | #define EMAC_SPLITTER_CTRL_SPEED_MASK 0x3 |
|---|
| .. | .. |
|---|
| 48 | 37 | #define EMAC_SPLITTER_CTRL_SPEED_100 0x3 |
|---|
| 49 | 38 | #define EMAC_SPLITTER_CTRL_SPEED_1000 0x0 |
|---|
| 50 | 39 | |
|---|
| 40 | +struct socfpga_dwmac; |
|---|
| 41 | +struct socfpga_dwmac_ops { |
|---|
| 42 | + int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv); |
|---|
| 43 | +}; |
|---|
| 44 | + |
|---|
| 51 | 45 | struct socfpga_dwmac { |
|---|
| 52 | | - int interface; |
|---|
| 53 | 46 | u32 reg_offset; |
|---|
| 54 | 47 | u32 reg_shift; |
|---|
| 55 | 48 | struct device *dev; |
|---|
| .. | .. |
|---|
| 59 | 52 | void __iomem *splitter_base; |
|---|
| 60 | 53 | bool f2h_ptp_ref_clk; |
|---|
| 61 | 54 | struct tse_pcs pcs; |
|---|
| 55 | + const struct socfpga_dwmac_ops *ops; |
|---|
| 62 | 56 | }; |
|---|
| 63 | 57 | |
|---|
| 64 | 58 | static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) |
|---|
| 65 | 59 | { |
|---|
| 66 | 60 | struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; |
|---|
| 67 | 61 | void __iomem *splitter_base = dwmac->splitter_base; |
|---|
| 68 | | - void __iomem *tse_pcs_base = dwmac->pcs.tse_pcs_base; |
|---|
| 69 | 62 | void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base; |
|---|
| 70 | 63 | struct device *dev = dwmac->dev; |
|---|
| 71 | 64 | struct net_device *ndev = dev_get_drvdata(dev); |
|---|
| 72 | 65 | struct phy_device *phy_dev = ndev->phydev; |
|---|
| 73 | 66 | u32 val; |
|---|
| 74 | 67 | |
|---|
| 75 | | - if ((tse_pcs_base) && (sgmii_adapter_base)) |
|---|
| 68 | + if (sgmii_adapter_base) |
|---|
| 76 | 69 | writew(SGMII_ADAPTER_DISABLE, |
|---|
| 77 | 70 | sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); |
|---|
| 78 | 71 | |
|---|
| .. | .. |
|---|
| 96 | 89 | writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); |
|---|
| 97 | 90 | } |
|---|
| 98 | 91 | |
|---|
| 99 | | - if (tse_pcs_base && sgmii_adapter_base) |
|---|
| 92 | + if (phy_dev && sgmii_adapter_base) { |
|---|
| 93 | + writew(SGMII_ADAPTER_ENABLE, |
|---|
| 94 | + sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); |
|---|
| 100 | 95 | tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed); |
|---|
| 96 | + } |
|---|
| 101 | 97 | } |
|---|
| 102 | 98 | |
|---|
| 103 | 99 | static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) |
|---|
| .. | .. |
|---|
| 112 | 108 | struct resource res_tse_pcs; |
|---|
| 113 | 109 | struct resource res_sgmii_adapter; |
|---|
| 114 | 110 | |
|---|
| 115 | | - dwmac->interface = of_get_phy_mode(np); |
|---|
| 116 | | - |
|---|
| 117 | | - sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); |
|---|
| 111 | + sys_mgr_base_addr = |
|---|
| 112 | + altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); |
|---|
| 118 | 113 | if (IS_ERR(sys_mgr_base_addr)) { |
|---|
| 119 | 114 | dev_info(dev, "No sysmgr-syscon node found\n"); |
|---|
| 120 | 115 | return PTR_ERR(sys_mgr_base_addr); |
|---|
| .. | .. |
|---|
| 232 | 227 | return ret; |
|---|
| 233 | 228 | } |
|---|
| 234 | 229 | |
|---|
| 235 | | -static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) |
|---|
| 230 | +static int socfpga_get_plat_phymode(struct socfpga_dwmac *dwmac) |
|---|
| 236 | 231 | { |
|---|
| 237 | | - struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; |
|---|
| 238 | | - int phymode = dwmac->interface; |
|---|
| 239 | | - u32 reg_offset = dwmac->reg_offset; |
|---|
| 240 | | - u32 reg_shift = dwmac->reg_shift; |
|---|
| 241 | | - u32 ctrl, val, module; |
|---|
| 232 | + struct net_device *ndev = dev_get_drvdata(dwmac->dev); |
|---|
| 233 | + struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 242 | 234 | |
|---|
| 235 | + return priv->plat->interface; |
|---|
| 236 | +} |
|---|
| 237 | + |
|---|
| 238 | +static int socfpga_set_phy_mode_common(int phymode, u32 *val) |
|---|
| 239 | +{ |
|---|
| 243 | 240 | switch (phymode) { |
|---|
| 244 | 241 | case PHY_INTERFACE_MODE_RGMII: |
|---|
| 245 | 242 | case PHY_INTERFACE_MODE_RGMII_ID: |
|---|
| 246 | | - val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; |
|---|
| 243 | + case PHY_INTERFACE_MODE_RGMII_RXID: |
|---|
| 244 | + case PHY_INTERFACE_MODE_RGMII_TXID: |
|---|
| 245 | + *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; |
|---|
| 247 | 246 | break; |
|---|
| 248 | 247 | case PHY_INTERFACE_MODE_MII: |
|---|
| 249 | 248 | case PHY_INTERFACE_MODE_GMII: |
|---|
| 250 | 249 | case PHY_INTERFACE_MODE_SGMII: |
|---|
| 251 | | - val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; |
|---|
| 250 | + *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; |
|---|
| 251 | + break; |
|---|
| 252 | + case PHY_INTERFACE_MODE_RMII: |
|---|
| 253 | + *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII; |
|---|
| 252 | 254 | break; |
|---|
| 253 | 255 | default: |
|---|
| 256 | + return -EINVAL; |
|---|
| 257 | + } |
|---|
| 258 | + return 0; |
|---|
| 259 | +} |
|---|
| 260 | + |
|---|
| 261 | +static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac) |
|---|
| 262 | +{ |
|---|
| 263 | + struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; |
|---|
| 264 | + int phymode = socfpga_get_plat_phymode(dwmac); |
|---|
| 265 | + u32 reg_offset = dwmac->reg_offset; |
|---|
| 266 | + u32 reg_shift = dwmac->reg_shift; |
|---|
| 267 | + u32 ctrl, val, module; |
|---|
| 268 | + |
|---|
| 269 | + if (socfpga_set_phy_mode_common(phymode, &val)) { |
|---|
| 254 | 270 | dev_err(dwmac->dev, "bad phy mode %d\n", phymode); |
|---|
| 255 | 271 | return -EINVAL; |
|---|
| 256 | 272 | } |
|---|
| .. | .. |
|---|
| 304 | 320 | return 0; |
|---|
| 305 | 321 | } |
|---|
| 306 | 322 | |
|---|
| 323 | +static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac) |
|---|
| 324 | +{ |
|---|
| 325 | + struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; |
|---|
| 326 | + int phymode = socfpga_get_plat_phymode(dwmac); |
|---|
| 327 | + u32 reg_offset = dwmac->reg_offset; |
|---|
| 328 | + u32 reg_shift = dwmac->reg_shift; |
|---|
| 329 | + u32 ctrl, val, module; |
|---|
| 330 | + |
|---|
| 331 | + if (socfpga_set_phy_mode_common(phymode, &val)) |
|---|
| 332 | + return -EINVAL; |
|---|
| 333 | + |
|---|
| 334 | + /* Overwrite val to GMII if splitter core is enabled. The phymode here |
|---|
| 335 | + * is the actual phy mode on phy hardware, but phy interface from |
|---|
| 336 | + * EMAC core is GMII. |
|---|
| 337 | + */ |
|---|
| 338 | + if (dwmac->splitter_base) |
|---|
| 339 | + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; |
|---|
| 340 | + |
|---|
| 341 | + /* Assert reset to the enet controller before changing the phy mode */ |
|---|
| 342 | + reset_control_assert(dwmac->stmmac_ocp_rst); |
|---|
| 343 | + reset_control_assert(dwmac->stmmac_rst); |
|---|
| 344 | + |
|---|
| 345 | + regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); |
|---|
| 346 | + ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK); |
|---|
| 347 | + ctrl |= val; |
|---|
| 348 | + |
|---|
| 349 | + if (dwmac->f2h_ptp_ref_clk || |
|---|
| 350 | + phymode == PHY_INTERFACE_MODE_MII || |
|---|
| 351 | + phymode == PHY_INTERFACE_MODE_GMII || |
|---|
| 352 | + phymode == PHY_INTERFACE_MODE_SGMII) { |
|---|
| 353 | + ctrl |= SYSMGR_GEN10_EMACGRP_CTRL_PTP_REF_CLK_MASK; |
|---|
| 354 | + regmap_read(sys_mgr_base_addr, SYSMGR_FPGAINTF_EMAC_REG, |
|---|
| 355 | + &module); |
|---|
| 356 | + module |= (SYSMGR_FPGAINTF_EMAC_BIT << reg_shift); |
|---|
| 357 | + regmap_write(sys_mgr_base_addr, SYSMGR_FPGAINTF_EMAC_REG, |
|---|
| 358 | + module); |
|---|
| 359 | + } else { |
|---|
| 360 | + ctrl &= ~SYSMGR_GEN10_EMACGRP_CTRL_PTP_REF_CLK_MASK; |
|---|
| 361 | + } |
|---|
| 362 | + |
|---|
| 363 | + regmap_write(sys_mgr_base_addr, reg_offset, ctrl); |
|---|
| 364 | + |
|---|
| 365 | + /* Deassert reset for the phy configuration to be sampled by |
|---|
| 366 | + * the enet controller, and operation to start in requested mode |
|---|
| 367 | + */ |
|---|
| 368 | + reset_control_deassert(dwmac->stmmac_ocp_rst); |
|---|
| 369 | + reset_control_deassert(dwmac->stmmac_rst); |
|---|
| 370 | + if (phymode == PHY_INTERFACE_MODE_SGMII) { |
|---|
| 371 | + if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { |
|---|
| 372 | + dev_err(dwmac->dev, "Unable to initialize TSE PCS"); |
|---|
| 373 | + return -EINVAL; |
|---|
| 374 | + } |
|---|
| 375 | + } |
|---|
| 376 | + return 0; |
|---|
| 377 | +} |
|---|
| 378 | + |
|---|
| 307 | 379 | static int socfpga_dwmac_probe(struct platform_device *pdev) |
|---|
| 308 | 380 | { |
|---|
| 309 | 381 | struct plat_stmmacenet_data *plat_dat; |
|---|
| .. | .. |
|---|
| 313 | 385 | struct socfpga_dwmac *dwmac; |
|---|
| 314 | 386 | struct net_device *ndev; |
|---|
| 315 | 387 | struct stmmac_priv *stpriv; |
|---|
| 388 | + const struct socfpga_dwmac_ops *ops; |
|---|
| 389 | + |
|---|
| 390 | + ops = device_get_match_data(&pdev->dev); |
|---|
| 391 | + if (!ops) { |
|---|
| 392 | + dev_err(&pdev->dev, "no of match data provided\n"); |
|---|
| 393 | + return -EINVAL; |
|---|
| 394 | + } |
|---|
| 316 | 395 | |
|---|
| 317 | 396 | ret = stmmac_get_platform_resources(pdev, &stmmac_res); |
|---|
| 318 | 397 | if (ret) |
|---|
| .. | .. |
|---|
| 343 | 422 | goto err_remove_config_dt; |
|---|
| 344 | 423 | } |
|---|
| 345 | 424 | |
|---|
| 425 | + dwmac->ops = ops; |
|---|
| 346 | 426 | plat_dat->bsp_priv = dwmac; |
|---|
| 347 | 427 | plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; |
|---|
| 348 | 428 | |
|---|
| .. | .. |
|---|
| 359 | 439 | */ |
|---|
| 360 | 440 | dwmac->stmmac_rst = stpriv->plat->stmmac_rst; |
|---|
| 361 | 441 | |
|---|
| 362 | | - ret = socfpga_dwmac_set_phy_mode(dwmac); |
|---|
| 442 | + ret = ops->set_phy_mode(dwmac); |
|---|
| 363 | 443 | if (ret) |
|---|
| 364 | 444 | goto err_dvr_remove; |
|---|
| 365 | 445 | |
|---|
| .. | .. |
|---|
| 378 | 458 | { |
|---|
| 379 | 459 | struct net_device *ndev = dev_get_drvdata(dev); |
|---|
| 380 | 460 | struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 461 | + struct socfpga_dwmac *dwmac_priv = get_stmmac_bsp_priv(dev); |
|---|
| 381 | 462 | |
|---|
| 382 | | - socfpga_dwmac_set_phy_mode(priv->plat->bsp_priv); |
|---|
| 463 | + dwmac_priv->ops->set_phy_mode(priv->plat->bsp_priv); |
|---|
| 383 | 464 | |
|---|
| 384 | 465 | /* Before the enet controller is suspended, the phy is suspended. |
|---|
| 385 | 466 | * This causes the phy clock to be gated. The enet controller is |
|---|
| .. | .. |
|---|
| 403 | 484 | } |
|---|
| 404 | 485 | #endif /* CONFIG_PM_SLEEP */ |
|---|
| 405 | 486 | |
|---|
| 406 | | -static SIMPLE_DEV_PM_OPS(socfpga_dwmac_pm_ops, stmmac_suspend, |
|---|
| 407 | | - socfpga_dwmac_resume); |
|---|
| 487 | +static int __maybe_unused socfpga_dwmac_runtime_suspend(struct device *dev) |
|---|
| 488 | +{ |
|---|
| 489 | + struct net_device *ndev = dev_get_drvdata(dev); |
|---|
| 490 | + struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 491 | + |
|---|
| 492 | + stmmac_bus_clks_config(priv, false); |
|---|
| 493 | + |
|---|
| 494 | + return 0; |
|---|
| 495 | +} |
|---|
| 496 | + |
|---|
| 497 | +static int __maybe_unused socfpga_dwmac_runtime_resume(struct device *dev) |
|---|
| 498 | +{ |
|---|
| 499 | + struct net_device *ndev = dev_get_drvdata(dev); |
|---|
| 500 | + struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 501 | + |
|---|
| 502 | + return stmmac_bus_clks_config(priv, true); |
|---|
| 503 | +} |
|---|
| 504 | + |
|---|
| 505 | +static const struct dev_pm_ops socfpga_dwmac_pm_ops = { |
|---|
| 506 | + SET_SYSTEM_SLEEP_PM_OPS(stmmac_suspend, socfpga_dwmac_resume) |
|---|
| 507 | + SET_RUNTIME_PM_OPS(socfpga_dwmac_runtime_suspend, socfpga_dwmac_runtime_resume, NULL) |
|---|
| 508 | +}; |
|---|
| 509 | + |
|---|
| 510 | +static const struct socfpga_dwmac_ops socfpga_gen5_ops = { |
|---|
| 511 | + .set_phy_mode = socfpga_gen5_set_phy_mode, |
|---|
| 512 | +}; |
|---|
| 513 | + |
|---|
| 514 | +static const struct socfpga_dwmac_ops socfpga_gen10_ops = { |
|---|
| 515 | + .set_phy_mode = socfpga_gen10_set_phy_mode, |
|---|
| 516 | +}; |
|---|
| 408 | 517 | |
|---|
| 409 | 518 | static const struct of_device_id socfpga_dwmac_match[] = { |
|---|
| 410 | | - { .compatible = "altr,socfpga-stmmac" }, |
|---|
| 519 | + { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gen5_ops }, |
|---|
| 520 | + { .compatible = "altr,socfpga-stmmac-a10-s10", .data = &socfpga_gen10_ops }, |
|---|
| 411 | 521 | { } |
|---|
| 412 | 522 | }; |
|---|
| 413 | 523 | MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); |
|---|