.. | .. |
---|
| 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); |
---|