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

Merge branch 'net-stmmac-socfpga-add-agilex5-platform-support-and-enhancements'

Rohan G Thomas says:

====================
net: stmmac: socfpga: Add Agilex5 platform support and enhancements

This patch series adds support for the Agilex5 EMAC platform to the
dwmac-socfpga driver.

The series includes:
- Platform configuration for Agilex5 EMAC
- Enabling Time-Based Scheduling (TBS) for Tx queues 6 and 7
- Enabling TCP Segmentation Offload(TSO)
- Adding hardware-supported cross timestamping using the SMTG IP,
allowing precise synchronization between MAC and system time via
PTP_SYS_OFFSET_PRECISE.
====================

Link: https://patch.msgid.link/20251101-agilex5_ext-v2-0-a6b51b4dca4d@altera.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+168 -3
+163 -3
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
··· 5 5 */ 6 6 7 7 #include <linux/mfd/altera-sysmgr.h> 8 + #include <linux/clocksource_ids.h> 8 9 #include <linux/of.h> 9 10 #include <linux/of_address.h> 10 11 #include <linux/of_net.h> ··· 16 15 #include <linux/reset.h> 17 16 #include <linux/stmmac.h> 18 17 18 + #include "dwxgmac2.h" 19 19 #include "stmmac.h" 20 20 #include "stmmac_platform.h" 21 + #include "stmmac_ptp.h" 21 22 22 23 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 23 24 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 ··· 44 41 #define SGMII_ADAPTER_ENABLE 0x0000 45 42 #define SGMII_ADAPTER_DISABLE 0x0001 46 43 44 + #define SMTG_MDIO_ADDR 0x15 45 + #define SMTG_TSC_WORD0 0xC 46 + #define SMTG_TSC_WORD1 0xD 47 + #define SMTG_TSC_WORD2 0xE 48 + #define SMTG_TSC_WORD3 0xF 49 + #define SMTG_TSC_SHIFT 16 50 + 47 51 struct socfpga_dwmac; 48 52 struct socfpga_dwmac_ops { 49 53 int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv); 54 + void (*setup_plat_dat)(struct socfpga_dwmac *dwmac_priv); 50 55 }; 51 56 52 57 struct socfpga_dwmac { ··· 279 268 return 0; 280 269 } 281 270 271 + static void get_smtgtime(struct mii_bus *mii, int smtg_addr, u64 *smtg_time) 272 + { 273 + u64 ns; 274 + 275 + ns = mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD3); 276 + ns <<= SMTG_TSC_SHIFT; 277 + ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD2); 278 + ns <<= SMTG_TSC_SHIFT; 279 + ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD1); 280 + ns <<= SMTG_TSC_SHIFT; 281 + ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD0); 282 + 283 + *smtg_time = ns; 284 + } 285 + 286 + static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system, 287 + void *ctx) 288 + { 289 + struct stmmac_priv *priv = (struct stmmac_priv *)ctx; 290 + u32 num_snapshot, gpio_value, acr_value; 291 + void __iomem *ptpaddr = priv->ptpaddr; 292 + void __iomem *ioaddr = priv->hw->pcsr; 293 + unsigned long flags; 294 + u64 smtg_time = 0; 295 + u64 ptp_time = 0; 296 + int i, ret; 297 + u32 v; 298 + 299 + /* Both internal crosstimestamping and external triggered event 300 + * timestamping cannot be run concurrently. 301 + */ 302 + if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN) 303 + return -EBUSY; 304 + 305 + mutex_lock(&priv->aux_ts_lock); 306 + /* Enable Internal snapshot trigger */ 307 + acr_value = readl(ptpaddr + PTP_ACR); 308 + acr_value &= ~PTP_ACR_MASK; 309 + switch (priv->plat->int_snapshot_num) { 310 + case AUX_SNAPSHOT0: 311 + acr_value |= PTP_ACR_ATSEN0; 312 + break; 313 + case AUX_SNAPSHOT1: 314 + acr_value |= PTP_ACR_ATSEN1; 315 + break; 316 + case AUX_SNAPSHOT2: 317 + acr_value |= PTP_ACR_ATSEN2; 318 + break; 319 + case AUX_SNAPSHOT3: 320 + acr_value |= PTP_ACR_ATSEN3; 321 + break; 322 + default: 323 + mutex_unlock(&priv->aux_ts_lock); 324 + return -EINVAL; 325 + } 326 + writel(acr_value, ptpaddr + PTP_ACR); 327 + 328 + /* Clear FIFO */ 329 + acr_value = readl(ptpaddr + PTP_ACR); 330 + acr_value |= PTP_ACR_ATSFC; 331 + writel(acr_value, ptpaddr + PTP_ACR); 332 + /* Release the mutex */ 333 + mutex_unlock(&priv->aux_ts_lock); 334 + 335 + /* Trigger Internal snapshot signal. Create a rising edge by just toggle 336 + * the GPO0 to low and back to high. 337 + */ 338 + gpio_value = readl(ioaddr + XGMAC_GPIO_STATUS); 339 + gpio_value &= ~XGMAC_GPIO_GPO0; 340 + writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); 341 + gpio_value |= XGMAC_GPIO_GPO0; 342 + writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); 343 + 344 + /* Poll for time sync operation done */ 345 + ret = readl_poll_timeout(priv->ioaddr + XGMAC_INT_STATUS, v, 346 + (v & XGMAC_INT_TSIS), 100, 10000); 347 + if (ret) { 348 + netdev_err(priv->dev, "%s: Wait for time sync operation timeout\n", 349 + __func__); 350 + return ret; 351 + } 352 + 353 + *system = (struct system_counterval_t) { 354 + .cycles = 0, 355 + .cs_id = CSID_ARM_ARCH_COUNTER, 356 + .use_nsecs = false, 357 + }; 358 + 359 + num_snapshot = (readl(ioaddr + XGMAC_TIMESTAMP_STATUS) & 360 + XGMAC_TIMESTAMP_ATSNS_MASK) >> 361 + XGMAC_TIMESTAMP_ATSNS_SHIFT; 362 + 363 + /* Repeat until the timestamps are from the FIFO last segment */ 364 + for (i = 0; i < num_snapshot; i++) { 365 + read_lock_irqsave(&priv->ptp_lock, flags); 366 + stmmac_get_ptptime(priv, ptpaddr, &ptp_time); 367 + *device = ns_to_ktime(ptp_time); 368 + read_unlock_irqrestore(&priv->ptp_lock, flags); 369 + } 370 + 371 + get_smtgtime(priv->mii, SMTG_MDIO_ADDR, &smtg_time); 372 + system->cycles = smtg_time; 373 + 374 + return 0; 375 + } 376 + 282 377 static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac) 283 378 { 284 379 struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; ··· 558 441 return dwmac->ops->set_phy_mode(dwmac); 559 442 } 560 443 444 + static void socfpga_gen5_setup_plat_dat(struct socfpga_dwmac *dwmac) 445 + { 446 + struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat; 447 + 448 + plat_dat->core_type = DWMAC_CORE_GMAC; 449 + 450 + /* Rx watchdog timer in dwmac is buggy in this hw */ 451 + plat_dat->riwt_off = 1; 452 + } 453 + 454 + static void socfpga_agilex5_setup_plat_dat(struct socfpga_dwmac *dwmac) 455 + { 456 + struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat; 457 + 458 + plat_dat->core_type = DWMAC_CORE_XGMAC; 459 + 460 + /* Enable TSO */ 461 + plat_dat->flags |= STMMAC_FLAG_TSO_EN; 462 + 463 + /* Enable TBS */ 464 + switch (plat_dat->tx_queues_to_use) { 465 + case 8: 466 + plat_dat->tx_queues_cfg[7].tbs_en = true; 467 + fallthrough; 468 + case 7: 469 + plat_dat->tx_queues_cfg[6].tbs_en = true; 470 + break; 471 + default: 472 + /* Tx Queues 0 - 5 doesn't support TBS on Agilex5 */ 473 + break; 474 + } 475 + 476 + /* Hw supported cross-timestamp */ 477 + plat_dat->int_snapshot_num = AUX_SNAPSHOT0; 478 + plat_dat->crosststamp = smtg_crosststamp; 479 + } 480 + 561 481 static int socfpga_dwmac_probe(struct platform_device *pdev) 562 482 { 563 483 struct plat_stmmacenet_data *plat_dat; ··· 651 497 plat_dat->pcs_init = socfpga_dwmac_pcs_init; 652 498 plat_dat->pcs_exit = socfpga_dwmac_pcs_exit; 653 499 plat_dat->select_pcs = socfpga_dwmac_select_pcs; 654 - plat_dat->core_type = DWMAC_CORE_GMAC; 655 500 656 - plat_dat->riwt_off = 1; 501 + ops->setup_plat_dat(dwmac); 657 502 658 503 return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); 659 504 } 660 505 661 506 static const struct socfpga_dwmac_ops socfpga_gen5_ops = { 662 507 .set_phy_mode = socfpga_gen5_set_phy_mode, 508 + .setup_plat_dat = socfpga_gen5_setup_plat_dat, 663 509 }; 664 510 665 511 static const struct socfpga_dwmac_ops socfpga_gen10_ops = { 666 512 .set_phy_mode = socfpga_gen10_set_phy_mode, 513 + .setup_plat_dat = socfpga_gen5_setup_plat_dat, 514 + }; 515 + 516 + static const struct socfpga_dwmac_ops socfpga_agilex5_ops = { 517 + .set_phy_mode = socfpga_gen10_set_phy_mode, 518 + .setup_plat_dat = socfpga_agilex5_setup_plat_dat, 667 519 }; 668 520 669 521 static const struct of_device_id socfpga_dwmac_match[] = { 670 522 { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gen5_ops }, 671 523 { .compatible = "altr,socfpga-stmmac-a10-s10", .data = &socfpga_gen10_ops }, 672 - { .compatible = "altr,socfpga-stmmac-agilex5", .data = &socfpga_gen10_ops }, 524 + { .compatible = "altr,socfpga-stmmac-agilex5", .data = &socfpga_agilex5_ops }, 673 525 { } 674 526 }; 675 527 MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
+5
drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
··· 79 79 #define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8) 80 80 #define XGMAC_PSRQ_SHIFT(x) ((x) * 8) 81 81 #define XGMAC_INT_STATUS 0x000000b0 82 + #define XGMAC_INT_TSIS BIT(12) 82 83 #define XGMAC_LPIIS BIT(5) 83 84 #define XGMAC_PMTIS BIT(4) 84 85 #define XGMAC_INT_EN 0x000000b4 ··· 174 173 #define XGMAC_MDIO_ADDR 0x00000200 175 174 #define XGMAC_MDIO_DATA 0x00000204 176 175 #define XGMAC_MDIO_C22P 0x00000220 176 + #define XGMAC_GPIO_STATUS 0x0000027c 177 + #define XGMAC_GPIO_GPO0 BIT(16) 177 178 #define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8) 178 179 #define XGMAC_ADDR_MAX 32 179 180 #define XGMAC_AE BIT(31) ··· 223 220 #define XGMAC_OB BIT(0) 224 221 #define XGMAC_RSS_DATA 0x00000c8c 225 222 #define XGMAC_TIMESTAMP_STATUS 0x00000d20 223 + #define XGMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25) 224 + #define XGMAC_TIMESTAMP_ATSNS_SHIFT 25 226 225 #define XGMAC_TXTSC BIT(15) 227 226 #define XGMAC_TXTIMESTAMP_NSEC 0x00000d30 228 227 #define XGMAC_TXTSSTSLO GENMASK(30, 0)