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

net: ti: icssm-prueth: Adds ICSSM Ethernet driver

Updates Kernel configuration to enable PRUETH driver and its dependencies
along with makefile changes to add the new PRUETH driver.

Changes includes init and deinit of ICSSM PRU Ethernet driver including
net dev registration and firmware loading for DUAL-MAC mode running on
PRU-ICSS2 instance.

Changes also includes link handling, PRU booting, default firmware loading
and PRU stopping using existing remoteproc driver APIs.

Reviewed-by: Mohan Reddy Putluru <pmohan@couthit.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath@couthit.com>
Signed-off-by: Parvathi Pudi <parvathi@couthit.com>
Link: https://patch.msgid.link/20250912104741.528721-3-parvathi@couthit.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Roger Quadros and committed by
Jakub Kicinski
511f6c1a eb391228

+727
+12
drivers/net/ethernet/ti/Kconfig
··· 229 229 To compile this driver as a module, choose M here. The module 230 230 will be called icss_iep. 231 231 232 + config TI_PRUETH 233 + tristate "TI PRU Ethernet EMAC driver" 234 + depends on PRU_REMOTEPROC 235 + depends on NET_SWITCHDEV 236 + select TI_ICSS_IEP 237 + imply PTP_1588_CLOCK 238 + help 239 + Some TI SoCs has Programmable Realtime Unit (PRU) cores which can 240 + support Single or Dual Ethernet ports with the help of firmware code 241 + running on PRU cores. This driver supports remoteproc based 242 + communication to PRU firmware to expose Ethernet interface to Linux. 243 + 232 244 endif # NET_VENDOR_TI
+3
drivers/net/ethernet/ti/Makefile
··· 3 3 # Makefile for the TI network device drivers. 4 4 # 5 5 6 + obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o 7 + icssm-prueth-y := icssm/icssm_prueth.o 8 + 6 9 obj-$(CONFIG_TI_CPSW) += cpsw-common.o 7 10 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o 8 11 obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o
+612
drivers/net/ethernet/ti/icssm/icssm_prueth.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Texas Instruments ICSSM Ethernet Driver 4 + * 5 + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ 6 + * 7 + */ 8 + 9 + #include <linux/etherdevice.h> 10 + #include <linux/genalloc.h> 11 + #include <linux/if_bridge.h> 12 + #include <linux/if_hsr.h> 13 + #include <linux/if_vlan.h> 14 + #include <linux/interrupt.h> 15 + #include <linux/kernel.h> 16 + #include <linux/mfd/syscon.h> 17 + #include <linux/module.h> 18 + #include <linux/net_tstamp.h> 19 + #include <linux/of.h> 20 + #include <linux/of_irq.h> 21 + #include <linux/of_mdio.h> 22 + #include <linux/of_net.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/phy.h> 25 + #include <linux/remoteproc/pruss.h> 26 + #include <linux/ptp_classify.h> 27 + #include <linux/regmap.h> 28 + #include <linux/remoteproc.h> 29 + #include <net/pkt_cls.h> 30 + 31 + #include "icssm_prueth.h" 32 + 33 + /* called back by PHY layer if there is change in link state of hw port*/ 34 + static void icssm_emac_adjust_link(struct net_device *ndev) 35 + { 36 + struct prueth_emac *emac = netdev_priv(ndev); 37 + struct phy_device *phydev = emac->phydev; 38 + bool new_state = false; 39 + unsigned long flags; 40 + 41 + spin_lock_irqsave(&emac->lock, flags); 42 + 43 + if (phydev->link) { 44 + /* check the mode of operation */ 45 + if (phydev->duplex != emac->duplex) { 46 + new_state = true; 47 + emac->duplex = phydev->duplex; 48 + } 49 + if (phydev->speed != emac->speed) { 50 + new_state = true; 51 + emac->speed = phydev->speed; 52 + } 53 + if (!emac->link) { 54 + new_state = true; 55 + emac->link = 1; 56 + } 57 + } else if (emac->link) { 58 + new_state = true; 59 + emac->link = 0; 60 + } 61 + 62 + if (new_state) 63 + phy_print_status(phydev); 64 + 65 + if (emac->link) { 66 + /* reactivate the transmit queue if it is stopped */ 67 + if (netif_running(ndev) && netif_queue_stopped(ndev)) 68 + netif_wake_queue(ndev); 69 + } else { 70 + if (!netif_queue_stopped(ndev)) 71 + netif_stop_queue(ndev); 72 + } 73 + 74 + spin_unlock_irqrestore(&emac->lock, flags); 75 + } 76 + 77 + static int icssm_emac_set_boot_pru(struct prueth_emac *emac, 78 + struct net_device *ndev) 79 + { 80 + const struct prueth_firmware *pru_firmwares; 81 + struct prueth *prueth = emac->prueth; 82 + const char *fw_name; 83 + int ret; 84 + 85 + pru_firmwares = &prueth->fw_data->fw_pru[emac->port_id - 1]; 86 + fw_name = pru_firmwares->fw_name[prueth->eth_type]; 87 + if (!fw_name) { 88 + netdev_err(ndev, "eth_type %d not supported\n", 89 + prueth->eth_type); 90 + return -ENODEV; 91 + } 92 + 93 + ret = rproc_set_firmware(emac->pru, fw_name); 94 + if (ret) { 95 + netdev_err(ndev, "failed to set %s firmware: %d\n", 96 + fw_name, ret); 97 + return ret; 98 + } 99 + 100 + ret = rproc_boot(emac->pru); 101 + if (ret) { 102 + netdev_err(ndev, "failed to boot %s firmware: %d\n", 103 + fw_name, ret); 104 + return ret; 105 + } 106 + 107 + return ret; 108 + } 109 + 110 + /** 111 + * icssm_emac_ndo_open - EMAC device open 112 + * @ndev: network adapter device 113 + * 114 + * Called when system wants to start the interface. 115 + * 116 + * Return: 0 for a successful open, or appropriate error code 117 + */ 118 + static int icssm_emac_ndo_open(struct net_device *ndev) 119 + { 120 + struct prueth_emac *emac = netdev_priv(ndev); 121 + int ret; 122 + 123 + ret = icssm_emac_set_boot_pru(emac, ndev); 124 + if (ret) 125 + return ret; 126 + 127 + /* start PHY */ 128 + phy_start(emac->phydev); 129 + 130 + return 0; 131 + } 132 + 133 + /** 134 + * icssm_emac_ndo_stop - EMAC device stop 135 + * @ndev: network adapter device 136 + * 137 + * Called when system wants to stop or down the interface. 138 + * 139 + * Return: Always 0 (Success) 140 + */ 141 + static int icssm_emac_ndo_stop(struct net_device *ndev) 142 + { 143 + struct prueth_emac *emac = netdev_priv(ndev); 144 + 145 + /* stop PHY */ 146 + phy_stop(emac->phydev); 147 + 148 + rproc_shutdown(emac->pru); 149 + 150 + return 0; 151 + } 152 + 153 + static const struct net_device_ops emac_netdev_ops = { 154 + .ndo_open = icssm_emac_ndo_open, 155 + .ndo_stop = icssm_emac_ndo_stop, 156 + }; 157 + 158 + /* get emac_port corresponding to eth_node name */ 159 + static int icssm_prueth_node_port(struct device_node *eth_node) 160 + { 161 + u32 port_id; 162 + int ret; 163 + 164 + ret = of_property_read_u32(eth_node, "reg", &port_id); 165 + if (ret) 166 + return ret; 167 + 168 + if (port_id == 0) 169 + return PRUETH_PORT_MII0; 170 + else if (port_id == 1) 171 + return PRUETH_PORT_MII1; 172 + else 173 + return PRUETH_PORT_INVALID; 174 + } 175 + 176 + /* get MAC instance corresponding to eth_node name */ 177 + static int icssm_prueth_node_mac(struct device_node *eth_node) 178 + { 179 + u32 port_id; 180 + int ret; 181 + 182 + ret = of_property_read_u32(eth_node, "reg", &port_id); 183 + if (ret) 184 + return ret; 185 + 186 + if (port_id == 0) 187 + return PRUETH_MAC0; 188 + else if (port_id == 1) 189 + return PRUETH_MAC1; 190 + else 191 + return PRUETH_MAC_INVALID; 192 + } 193 + 194 + static int icssm_prueth_netdev_init(struct prueth *prueth, 195 + struct device_node *eth_node) 196 + { 197 + struct prueth_emac *emac; 198 + struct net_device *ndev; 199 + enum prueth_port port; 200 + enum prueth_mac mac; 201 + int ret; 202 + 203 + port = icssm_prueth_node_port(eth_node); 204 + if (port == PRUETH_PORT_INVALID) 205 + return -EINVAL; 206 + 207 + mac = icssm_prueth_node_mac(eth_node); 208 + if (mac == PRUETH_MAC_INVALID) 209 + return -EINVAL; 210 + 211 + ndev = devm_alloc_etherdev(prueth->dev, sizeof(*emac)); 212 + if (!ndev) 213 + return -ENOMEM; 214 + 215 + SET_NETDEV_DEV(ndev, prueth->dev); 216 + emac = netdev_priv(ndev); 217 + prueth->emac[mac] = emac; 218 + emac->prueth = prueth; 219 + emac->ndev = ndev; 220 + emac->port_id = port; 221 + 222 + /* by default eth_type is EMAC */ 223 + switch (port) { 224 + case PRUETH_PORT_MII0: 225 + emac->pru = prueth->pru0; 226 + break; 227 + case PRUETH_PORT_MII1: 228 + emac->pru = prueth->pru1; 229 + break; 230 + default: 231 + return -EINVAL; 232 + } 233 + /* get mac address from DT and set private and netdev addr */ 234 + ret = of_get_ethdev_address(eth_node, ndev); 235 + if (!is_valid_ether_addr(ndev->dev_addr)) { 236 + eth_hw_addr_random(ndev); 237 + dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n", 238 + port, ndev->dev_addr); 239 + } 240 + ether_addr_copy(emac->mac_addr, ndev->dev_addr); 241 + 242 + /* connect PHY */ 243 + emac->phydev = of_phy_get_and_connect(ndev, eth_node, 244 + icssm_emac_adjust_link); 245 + if (!emac->phydev) { 246 + dev_dbg(prueth->dev, "PHY connection failed\n"); 247 + ret = -ENODEV; 248 + goto free; 249 + } 250 + 251 + /* remove unsupported modes */ 252 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); 253 + 254 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); 255 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); 256 + 257 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT); 258 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); 259 + 260 + ndev->dev.of_node = eth_node; 261 + ndev->netdev_ops = &emac_netdev_ops; 262 + 263 + return 0; 264 + free: 265 + emac->ndev = NULL; 266 + prueth->emac[mac] = NULL; 267 + 268 + return ret; 269 + } 270 + 271 + static void icssm_prueth_netdev_exit(struct prueth *prueth, 272 + struct device_node *eth_node) 273 + { 274 + struct prueth_emac *emac; 275 + enum prueth_mac mac; 276 + 277 + mac = icssm_prueth_node_mac(eth_node); 278 + if (mac == PRUETH_MAC_INVALID) 279 + return; 280 + 281 + emac = prueth->emac[mac]; 282 + if (!emac) 283 + return; 284 + 285 + phy_disconnect(emac->phydev); 286 + 287 + prueth->emac[mac] = NULL; 288 + } 289 + 290 + static int icssm_prueth_probe(struct platform_device *pdev) 291 + { 292 + struct device_node *eth0_node = NULL, *eth1_node = NULL; 293 + struct device_node *eth_node, *eth_ports_node; 294 + enum pruss_pru_id pruss_id0, pruss_id1; 295 + struct device *dev = &pdev->dev; 296 + struct device_node *np; 297 + struct prueth *prueth; 298 + int i, ret; 299 + 300 + np = dev->of_node; 301 + if (!np) 302 + return -ENODEV; /* we don't support non DT */ 303 + 304 + prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); 305 + if (!prueth) 306 + return -ENOMEM; 307 + 308 + platform_set_drvdata(pdev, prueth); 309 + prueth->dev = dev; 310 + prueth->fw_data = device_get_match_data(dev); 311 + 312 + eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); 313 + if (!eth_ports_node) 314 + return -ENOENT; 315 + 316 + for_each_child_of_node(eth_ports_node, eth_node) { 317 + u32 reg; 318 + 319 + if (strcmp(eth_node->name, "ethernet-port")) 320 + continue; 321 + ret = of_property_read_u32(eth_node, "reg", &reg); 322 + if (ret < 0) { 323 + dev_err(dev, "%pOF error reading port_id %d\n", 324 + eth_node, ret); 325 + of_node_put(eth_node); 326 + return ret; 327 + } 328 + 329 + of_node_get(eth_node); 330 + 331 + if (reg == 0 && !eth0_node) { 332 + eth0_node = eth_node; 333 + if (!of_device_is_available(eth0_node)) { 334 + of_node_put(eth0_node); 335 + eth0_node = NULL; 336 + } 337 + } else if (reg == 1 && !eth1_node) { 338 + eth1_node = eth_node; 339 + if (!of_device_is_available(eth1_node)) { 340 + of_node_put(eth1_node); 341 + eth1_node = NULL; 342 + } 343 + } else { 344 + if (reg == 0 || reg == 1) 345 + dev_err(dev, "duplicate port reg value: %d\n", 346 + reg); 347 + else 348 + dev_err(dev, "invalid port reg value: %d\n", 349 + reg); 350 + 351 + of_node_put(eth_node); 352 + } 353 + } 354 + 355 + of_node_put(eth_ports_node); 356 + 357 + /* At least one node must be present and available else we fail */ 358 + if (!eth0_node && !eth1_node) { 359 + dev_err(dev, "neither port0 nor port1 node available\n"); 360 + return -ENODEV; 361 + } 362 + 363 + prueth->eth_node[PRUETH_MAC0] = eth0_node; 364 + prueth->eth_node[PRUETH_MAC1] = eth1_node; 365 + 366 + if (eth0_node) { 367 + prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0); 368 + if (IS_ERR(prueth->pru0)) { 369 + ret = PTR_ERR(prueth->pru0); 370 + dev_err_probe(dev, ret, "unable to get PRU0"); 371 + goto put_pru; 372 + } 373 + } 374 + 375 + if (eth1_node) { 376 + prueth->pru1 = pru_rproc_get(np, 1, &pruss_id1); 377 + if (IS_ERR(prueth->pru1)) { 378 + ret = PTR_ERR(prueth->pru1); 379 + dev_err_probe(dev, ret, "unable to get PRU1"); 380 + goto put_pru; 381 + } 382 + } 383 + 384 + /* setup netdev interfaces */ 385 + if (eth0_node) { 386 + ret = icssm_prueth_netdev_init(prueth, eth0_node); 387 + if (ret) { 388 + if (ret != -EPROBE_DEFER) { 389 + dev_err(dev, "netdev init %s failed: %d\n", 390 + eth0_node->name, ret); 391 + } 392 + goto put_pru; 393 + } 394 + } 395 + 396 + if (eth1_node) { 397 + ret = icssm_prueth_netdev_init(prueth, eth1_node); 398 + if (ret) { 399 + if (ret != -EPROBE_DEFER) { 400 + dev_err(dev, "netdev init %s failed: %d\n", 401 + eth1_node->name, ret); 402 + } 403 + goto netdev_exit; 404 + } 405 + } 406 + 407 + /* register the network devices */ 408 + if (eth0_node) { 409 + ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); 410 + if (ret) { 411 + dev_err(dev, "can't register netdev for port MII0"); 412 + goto netdev_exit; 413 + } 414 + 415 + prueth->registered_netdevs[PRUETH_MAC0] = 416 + prueth->emac[PRUETH_MAC0]->ndev; 417 + } 418 + 419 + if (eth1_node) { 420 + ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); 421 + if (ret) { 422 + dev_err(dev, "can't register netdev for port MII1"); 423 + goto netdev_unregister; 424 + } 425 + 426 + prueth->registered_netdevs[PRUETH_MAC1] = 427 + prueth->emac[PRUETH_MAC1]->ndev; 428 + } 429 + 430 + if (eth1_node) 431 + of_node_put(eth1_node); 432 + if (eth0_node) 433 + of_node_put(eth0_node); 434 + return 0; 435 + 436 + netdev_unregister: 437 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 438 + if (!prueth->registered_netdevs[i]) 439 + continue; 440 + unregister_netdev(prueth->registered_netdevs[i]); 441 + } 442 + 443 + netdev_exit: 444 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 445 + eth_node = prueth->eth_node[i]; 446 + if (!eth_node) 447 + continue; 448 + 449 + icssm_prueth_netdev_exit(prueth, eth_node); 450 + } 451 + 452 + put_pru: 453 + if (eth1_node) { 454 + if (prueth->pru1) 455 + pru_rproc_put(prueth->pru1); 456 + of_node_put(eth1_node); 457 + } 458 + 459 + if (eth0_node) { 460 + if (prueth->pru0) 461 + pru_rproc_put(prueth->pru0); 462 + of_node_put(eth0_node); 463 + } 464 + 465 + return ret; 466 + } 467 + 468 + static void icssm_prueth_remove(struct platform_device *pdev) 469 + { 470 + struct prueth *prueth = platform_get_drvdata(pdev); 471 + struct device_node *eth_node; 472 + int i; 473 + 474 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 475 + if (!prueth->registered_netdevs[i]) 476 + continue; 477 + unregister_netdev(prueth->registered_netdevs[i]); 478 + } 479 + 480 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 481 + eth_node = prueth->eth_node[i]; 482 + if (!eth_node) 483 + continue; 484 + 485 + icssm_prueth_netdev_exit(prueth, eth_node); 486 + of_node_put(eth_node); 487 + } 488 + 489 + pruss_put(prueth->pruss); 490 + 491 + if (prueth->eth_node[PRUETH_MAC0]) 492 + pru_rproc_put(prueth->pru0); 493 + if (prueth->eth_node[PRUETH_MAC1]) 494 + pru_rproc_put(prueth->pru1); 495 + } 496 + 497 + #ifdef CONFIG_PM_SLEEP 498 + static int icssm_prueth_suspend(struct device *dev) 499 + { 500 + struct prueth *prueth = dev_get_drvdata(dev); 501 + struct net_device *ndev; 502 + int i, ret; 503 + 504 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 505 + ndev = prueth->registered_netdevs[i]; 506 + 507 + if (!ndev) 508 + continue; 509 + 510 + if (netif_running(ndev)) { 511 + netif_device_detach(ndev); 512 + ret = icssm_emac_ndo_stop(ndev); 513 + if (ret < 0) { 514 + netdev_err(ndev, "failed to stop: %d", ret); 515 + return ret; 516 + } 517 + } 518 + } 519 + 520 + return 0; 521 + } 522 + 523 + static int icssm_prueth_resume(struct device *dev) 524 + { 525 + struct prueth *prueth = dev_get_drvdata(dev); 526 + struct net_device *ndev; 527 + int i, ret; 528 + 529 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 530 + ndev = prueth->registered_netdevs[i]; 531 + 532 + if (!ndev) 533 + continue; 534 + 535 + if (netif_running(ndev)) { 536 + ret = icssm_emac_ndo_open(ndev); 537 + if (ret < 0) { 538 + netdev_err(ndev, "failed to start: %d", ret); 539 + return ret; 540 + } 541 + netif_device_attach(ndev); 542 + } 543 + } 544 + 545 + return 0; 546 + } 547 + 548 + #endif /* CONFIG_PM_SLEEP */ 549 + 550 + static const struct dev_pm_ops prueth_dev_pm_ops = { 551 + SET_SYSTEM_SLEEP_PM_OPS(icssm_prueth_suspend, icssm_prueth_resume) 552 + }; 553 + 554 + /* AM335x SoC-specific firmware data */ 555 + static struct prueth_private_data am335x_prueth_pdata = { 556 + .fw_pru[PRUSS_PRU0] = { 557 + .fw_name[PRUSS_ETHTYPE_EMAC] = 558 + "ti-pruss/am335x-pru0-prueth-fw.elf", 559 + }, 560 + .fw_pru[PRUSS_PRU1] = { 561 + .fw_name[PRUSS_ETHTYPE_EMAC] = 562 + "ti-pruss/am335x-pru1-prueth-fw.elf", 563 + }, 564 + }; 565 + 566 + /* AM437x SoC-specific firmware data */ 567 + static struct prueth_private_data am437x_prueth_pdata = { 568 + .fw_pru[PRUSS_PRU0] = { 569 + .fw_name[PRUSS_ETHTYPE_EMAC] = 570 + "ti-pruss/am437x-pru0-prueth-fw.elf", 571 + }, 572 + .fw_pru[PRUSS_PRU1] = { 573 + .fw_name[PRUSS_ETHTYPE_EMAC] = 574 + "ti-pruss/am437x-pru1-prueth-fw.elf", 575 + }, 576 + }; 577 + 578 + /* AM57xx SoC-specific firmware data */ 579 + static struct prueth_private_data am57xx_prueth_pdata = { 580 + .fw_pru[PRUSS_PRU0] = { 581 + .fw_name[PRUSS_ETHTYPE_EMAC] = 582 + "ti-pruss/am57xx-pru0-prueth-fw.elf", 583 + }, 584 + .fw_pru[PRUSS_PRU1] = { 585 + .fw_name[PRUSS_ETHTYPE_EMAC] = 586 + "ti-pruss/am57xx-pru1-prueth-fw.elf", 587 + }, 588 + }; 589 + 590 + static const struct of_device_id prueth_dt_match[] = { 591 + { .compatible = "ti,am57-prueth", .data = &am57xx_prueth_pdata, }, 592 + { .compatible = "ti,am4376-prueth", .data = &am437x_prueth_pdata, }, 593 + { .compatible = "ti,am3359-prueth", .data = &am335x_prueth_pdata, }, 594 + { /* sentinel */ } 595 + }; 596 + MODULE_DEVICE_TABLE(of, prueth_dt_match); 597 + 598 + static struct platform_driver prueth_driver = { 599 + .probe = icssm_prueth_probe, 600 + .remove = icssm_prueth_remove, 601 + .driver = { 602 + .name = "prueth", 603 + .of_match_table = prueth_dt_match, 604 + .pm = &prueth_dev_pm_ops, 605 + }, 606 + }; 607 + module_platform_driver(prueth_driver); 608 + 609 + MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); 610 + MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 611 + MODULE_DESCRIPTION("PRUSS ICSSM Ethernet Driver"); 612 + MODULE_LICENSE("GPL");
+100
drivers/net/ethernet/ti/icssm/icssm_prueth.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Texas Instruments ICSSM Ethernet driver 3 + * 4 + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ 5 + * 6 + */ 7 + 8 + #ifndef __NET_TI_PRUETH_H 9 + #define __NET_TI_PRUETH_H 10 + 11 + #include <linux/phy.h> 12 + #include <linux/types.h> 13 + #include <linux/pruss_driver.h> 14 + #include <linux/remoteproc/pruss.h> 15 + 16 + /* PRU Ethernet Type - Ethernet functionality (protocol 17 + * implemented) provided by the PRU firmware being loaded. 18 + */ 19 + enum pruss_ethtype { 20 + PRUSS_ETHTYPE_EMAC = 0, 21 + PRUSS_ETHTYPE_HSR, 22 + PRUSS_ETHTYPE_PRP, 23 + PRUSS_ETHTYPE_SWITCH, 24 + PRUSS_ETHTYPE_MAX, 25 + }; 26 + 27 + /* In switch mode there are 3 real ports i.e. 3 mac addrs. 28 + * however Linux sees only the host side port. The other 2 ports 29 + * are the switch ports. 30 + * In emac mode there are 2 real ports i.e. 2 mac addrs. 31 + * Linux sees both the ports. 32 + */ 33 + enum prueth_port { 34 + PRUETH_PORT_HOST = 0, /* host side port */ 35 + PRUETH_PORT_MII0, /* physical port MII 0 */ 36 + PRUETH_PORT_MII1, /* physical port MII 1 */ 37 + PRUETH_PORT_INVALID, /* Invalid prueth port */ 38 + }; 39 + 40 + enum prueth_mac { 41 + PRUETH_MAC0 = 0, 42 + PRUETH_MAC1, 43 + PRUETH_NUM_MACS, 44 + PRUETH_MAC_INVALID, 45 + }; 46 + 47 + /** 48 + * struct prueth_firmware - PRU Ethernet FW data 49 + * @fw_name: firmware names of firmware to run on PRU 50 + */ 51 + struct prueth_firmware { 52 + const char *fw_name[PRUSS_ETHTYPE_MAX]; 53 + }; 54 + 55 + /** 56 + * struct prueth_private_data - PRU Ethernet private data 57 + * @fw_pru: firmware names to be used for PRUSS ethernet usecases 58 + */ 59 + struct prueth_private_data { 60 + const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS]; 61 + }; 62 + 63 + /* data for each emac port */ 64 + struct prueth_emac { 65 + struct prueth *prueth; 66 + struct net_device *ndev; 67 + 68 + struct rproc *pru; 69 + struct phy_device *phydev; 70 + 71 + int link; 72 + int speed; 73 + int duplex; 74 + 75 + enum prueth_port port_id; 76 + const char *phy_id; 77 + u8 mac_addr[6]; 78 + phy_interface_t phy_if; 79 + 80 + /* spin lock used to protect 81 + * during link configuration 82 + */ 83 + spinlock_t lock; 84 + }; 85 + 86 + struct prueth { 87 + struct device *dev; 88 + struct pruss *pruss; 89 + struct rproc *pru0, *pru1; 90 + 91 + const struct prueth_private_data *fw_data; 92 + struct prueth_fw_offsets *fw_offsets; 93 + 94 + struct device_node *eth_node[PRUETH_NUM_MACS]; 95 + struct prueth_emac *emac[PRUETH_NUM_MACS]; 96 + struct net_device *registered_netdevs[PRUETH_NUM_MACS]; 97 + 98 + unsigned int eth_type; 99 + }; 100 + #endif /* __NET_TI_PRUETH_H */