On Tue, Aug 06, 2019 at 04:08:36PM +0530, Keerthy wrote: > This is the Ethernet driver for TI SoCs with the > ICSSG PRU Sub-system running EMAC firmware. > This driver caters to either of the slices(pru/rtu pair) > of the icssg subsystem. > > Following are the firmwares needed to run cores: > > am65x-pru0-prueth-fw.elf for pru0 of slice0 > am65x-rtu0-prueth-fw.elf for rtu0 of slice0 > am65x-pru1-prueth-fw.elf for pru1 of slice1 > am65x-rtu1-prueth-fw.elf for rtu1 of slice1 > > One and exactly one of the slices is supported > as the u-boot ethernet supports probing one interface > at a time. > > Signed-off-by: Keerthy <j-keer...@ti.com> > --- > drivers/net/ti/Kconfig | 8 + > drivers/net/ti/Makefile | 1 + > drivers/net/ti/icssg-prueth.c | 517 ++++++++++++++++++++++++++++++ > drivers/net/ti/icssg.h | 31 ++ > drivers/net/ti/icssg_classifier.c | 397 +++++++++++++++++++++++ > 5 files changed, 954 insertions(+) > create mode 100644 drivers/net/ti/icssg-prueth.c > create mode 100644 drivers/net/ti/icssg.h > create mode 100644 drivers/net/ti/icssg_classifier.c > > diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig > index ecf642de10..1b6285709f 100644 > --- a/drivers/net/ti/Kconfig > +++ b/drivers/net/ti/Kconfig > @@ -26,3 +26,11 @@ config TI_AM65_CPSW_NUSS > help > This driver supports TI K3 MCU CPSW Nuss Ethernet controller > in Texas Instruments K3 AM65x SoCs. > + > +config TI_AM64_ICSSG_PRUETH > + bool "TI Gigabit PRU Ethernet driver" > + depends on ARCH_K3 > + select PHYLIB > + help > + Support Gigabit Ethernet ports over the ICSSG PRU Subsystem > + This subsystem is available starting with the AM65 platform. > diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile > index 8d3808bb4b..b486498909 100644 > --- a/drivers/net/ti/Makefile > +++ b/drivers/net/ti/Makefile > @@ -6,3 +6,4 @@ obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o > cpsw_mdio.o > obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o > obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o > obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o cpsw_mdio.o > +obj-$(CONFIG_TI_AM64_ICSSG_PRUETH) += icssg-prueth.o cpsw_mdio.o > icssg_classifier.o > diff --git a/drivers/net/ti/icssg-prueth.c b/drivers/net/ti/icssg-prueth.c > new file mode 100644 > index 0000000000..f8935ee087 > --- /dev/null > +++ b/drivers/net/ti/icssg-prueth.c > @@ -0,0 +1,517 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Texas Instruments K3 AM65 PRU Ethernet Driver
If the driver is AM65x specific that should be reflected in the driver name, like already done for CPSW_NUSS, for consistency and scalability sake. > + * > + * Copyright (C) 2019, Texas Instruments, Incorporated > + * > + */ > + > +#include <common.h> > +#include <asm/io.h> > +#include <asm/processor.h> > +#include <clk.h> > +#include <dm.h> > +#include <dm/lists.h> > +#include <dm/device.h> > +#include <dma-uclass.h> > +#include <dm/of_access.h> > +#include <fs_loader.h> > +#include <miiphy.h> > +#include <misc.h> > +#include <net.h> > +#include <phy.h> > +#include <power-domain.h> > +#include <linux/soc/ti/ti-udma.h> > +#include <regmap.h> > +#include <remoteproc.h> > +#include <syscon.h> > +#include <ti-pruss.h> > + > +#include "cpsw_mdio.h" > +#include "icssg.h" > + > +#define ICSS_SLICE0 0 > +#define ICSS_SLICE1 1 > + > +#ifdef PKTSIZE_ALIGN > +#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN > +#else > +#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN) > +#endif > + > +#ifdef PKTBUFSRX > +#define UDMA_RX_DESC_NUM PKTBUFSRX > +#else > +#define UDMA_RX_DESC_NUM 4 > +#endif > + > +enum prueth_mac { > + PRUETH_MAC0 = 0, > + PRUETH_MAC1, > + PRUETH_NUM_MACS, > +}; > + > +enum prueth_port { > + PRUETH_PORT_HOST = 0, /* host side port */ > + PRUETH_PORT_MII0, /* physical port MII 0 */ > + PRUETH_PORT_MII1, /* physical port MII 1 */ > +}; > + > +/* Config region lies in shared RAM */ > +#define ICSS_CONFIG_OFFSET_SLICE0 0 > +#define ICSS_CONFIG_OFFSET_SLICE1 0x8000 > + > +/* Firmware flags */ > +#define ICSS_SET_RUN_FLAG_VLAN_ENABLE BIT(0) /* switch only > */ > +#define ICSS_SET_RUN_FLAG_FLOOD_UNICAST BIT(1) /* switch only > */ > +#define ICSS_SET_RUN_FLAG_PROMISC BIT(2) /* MAC only */ > +#define ICSS_SET_RUN_FLAG_MULTICAST_PROMISC BIT(3) /* MAC only */ > + > +/* CTRLMMR_ICSSG_RGMII_CTRL register bits */ > +#define ICSSG_CTRL_RGMII_ID_MODE BIT(24) > + > +/** > + * enum pruss_pru_id - PRU core identifiers > + */ > +enum pruss_pru_id { > + PRUSS_PRU0 = 0, > + PRUSS_PRU1, > + PRUSS_NUM_PRUS, > +}; > + > +struct prueth { > + struct udevice *dev; > + struct regmap *miig_rt; > + fdt_addr_t mdio_base; > + phys_addr_t pruss_shrdram2; > + struct mii_dev *bus; > + u32 port_id; > + u32 sram_pa; > + struct phy_device *phydev; > + bool has_phy; > + ofnode phy_node; > + u32 phy_addr; > + ofnode eth_node[PRUETH_NUM_MACS]; > + struct icssg_config config[PRUSS_NUM_PRUS]; > + u32 mdio_freq; > + int phy_interface; > + struct clk mdiofck; > + struct dma dma_tx; > + struct dma dma_rx; > + u32 rx_next; > + u32 rx_pend; > + int slice; > +}; > + > +static int icssg_phy_init(struct udevice *dev) > +{ > + struct prueth *priv = dev_get_priv(dev); > + struct phy_device *phydev; > + u32 supported = PHY_GBIT_FEATURES; > + int ret; > + > + phydev = phy_connect(priv->bus, > + priv->phy_addr, > + priv->dev, > + priv->phy_interface); > + > + if (!phydev) { > + dev_err(dev, "phy_connect() failed\n"); > + return -ENODEV; > + } > + > + phydev->supported &= supported; > + phydev->advertising = phydev->supported; > + > +#ifdef CONFIG_DM_ETH > + if (ofnode_valid(priv->phy_node)) > + phydev->node = priv->phy_node; > +#endif > + > + priv->phydev = phydev; > + ret = phy_config(phydev); > + if (ret < 0) > + pr_err("phy_config() failed: %d", ret); > + > + return ret; > +} > + > +static int icssg_mdio_init(struct udevice *dev) > +{ > + struct prueth *prueth = dev_get_priv(dev); > + > + prueth->bus = cpsw_mdio_init(dev->name, prueth->mdio_base, > + prueth->mdio_freq, > + clk_get_rate(&prueth->mdiofck)); > + if (!prueth->bus) > + return -EFAULT; > + > + return 0; > +} > + > +static void icssg_config_set(struct prueth *prueth) > +{ > + void __iomem *va; > + > + va = (void __iomem *)prueth->pruss_shrdram2 + prueth->slice * > + ICSSG_CONFIG_OFFSET_SLICE1; > + > + memcpy_toio(va, &prueth->config[0], sizeof(prueth->config[0])); > +} > + > +static int prueth_start(struct udevice *dev) > +{ > + struct prueth *priv = dev_get_priv(dev); > + struct eth_pdata *pdata = dev->platdata; > + int ret, i; > + char tx_chn_name[16]; > + char rx_chn_name[16]; > + > + icssg_class_set_mac_addr(priv->miig_rt, priv->slice, > + (u8 *)pdata->enetaddr); > + icssg_class_default(priv->miig_rt, priv->slice); > + > + /* To differentiate channels for SLICE0 vs SLICE1 */ > + snprintf(tx_chn_name, sizeof(tx_chn_name), "tx%d-0", priv->slice); > + snprintf(rx_chn_name, sizeof(rx_chn_name), "rx%d", priv->slice); > + > + ret = dma_get_by_name(dev, tx_chn_name, &priv->dma_tx); > + if (ret) > + dev_err(dev, "TX dma get failed %d\n", ret); Should we return on errors? Same comment applies to the statements immediately following this... > + > + ret = dma_get_by_name(dev, rx_chn_name, &priv->dma_rx); > + if (ret) > + dev_err(dev, "RX dma get failed %d\n", ret); > + > + for (i = 0; i < UDMA_RX_DESC_NUM; i++) { > + ret = dma_prepare_rcv_buf(&priv->dma_rx, > + net_rx_packets[i], > + UDMA_RX_BUF_SIZE); > + if (ret) > + dev_err(dev, "RX dma add buf failed %d\n", ret); > + } > + > + ret = dma_enable(&priv->dma_tx); > + if (ret) { > + dev_err(dev, "TX dma_enable failed %d\n", ret); > + return ret; > + } > + > + ret = dma_enable(&priv->dma_rx); > + if (ret) { > + dev_err(dev, "RX dma_enable failed %d\n", ret); > + goto rx_fail; > + } > + > + ret = phy_startup(priv->phydev); > + if (ret) { > + dev_err(dev, "phy_startup failed\n"); > + goto phy_fail; > + } > + > + return 0; > +phy_fail: > + dma_disable(&priv->dma_rx); > +rx_fail: > + dma_disable(&priv->dma_tx); > + > + return ret; > +} > + > +void prueth_print_buf(ulong addr, const void *data, uint width, > + uint count, uint linelen) > +{ > + print_buffer(addr, data, width, count, linelen); > +} This function does not appear to be used? If so please remove... > + > +static int prueth_send(struct udevice *dev, void *packet, int length) > +{ > + struct prueth *priv = dev_get_priv(dev); > + int ret; > + > + ret = dma_send(&priv->dma_tx, packet, length, NULL); > + > + return ret; > +} > + > +static int prueth_recv(struct udevice *dev, int flags, uchar **packetp) > +{ > + struct prueth *priv = dev_get_priv(dev); > + int ret; > + > + /* try to receive a new packet */ > + ret = dma_receive(&priv->dma_rx, (void **)packetp, NULL); > + > + return ret; > +} > + > +static int prueth_free_pkt(struct udevice *dev, uchar *packet, int length) > +{ > + struct prueth *priv = dev_get_priv(dev); > + int ret = 0; > + > + if (length > 0) { > + u32 pkt = priv->rx_next % UDMA_RX_DESC_NUM; > + > + dev_dbg(dev, "%s length:%d pkt:%u\n", __func__, length, pkt); > + > + ret = dma_prepare_rcv_buf(&priv->dma_rx, > + net_rx_packets[pkt], > + UDMA_RX_BUF_SIZE); > + priv->rx_next++; > + } > + > + return ret; > +} > + > +static void prueth_stop(struct udevice *dev) > +{ > + struct prueth *priv = dev_get_priv(dev); > + > + icssg_class_disable(priv->miig_rt, priv->slice); > + > + phy_shutdown(priv->phydev); > + > + dma_disable(&priv->dma_tx); > + dma_free(&priv->dma_tx); > + > + dma_disable(&priv->dma_rx); > + dma_free(&priv->dma_rx); > +} > + > +static const struct eth_ops prueth_ops = { > + .start = prueth_start, > + .send = prueth_send, > + .recv = prueth_recv, > + .free_pkt = prueth_free_pkt, > + .stop = prueth_stop, > +}; > + > +static int icssg_ofdata_parse_phy(struct udevice *dev, ofnode port_np) > +{ > + struct prueth *priv = dev_get_priv(dev); > + struct ofnode_phandle_args out_args; > + const char *phy_mode; > + int ret = 0; > + > + phy_mode = ofnode_read_string(port_np, "phy-mode"); > + if (phy_mode) { > + priv->phy_interface = > + phy_get_interface_by_name(phy_mode); > + if (priv->phy_interface == -1) { > + dev_err(dev, "Invalid PHY mode '%s'\n", > + phy_mode); > + ret = -EINVAL; > + goto out; > + } > + } > + > + ret = ofnode_parse_phandle_with_args(port_np, "phy-handle", > + NULL, 0, 0, &out_args); > + if (ret) { > + dev_err(dev, "can't parse phy-handle port (%d)\n", ret); > + ret = 0; > + } > + > + priv->phy_node = out_args.node; > + ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr); > + if (ret) > + dev_err(dev, "failed to get phy_addr port (%d)\n", ret); > + > +out: > + return ret; > +} > + > +static int prueth_config_rgmiidelay(struct prueth *prueth, > + ofnode eth_np) > +{ > + struct regmap *ctrl_mmr; > + u32 val; > + int ret = 0; > + ofnode node; > + u32 tmp[2]; > + > + ret = ofnode_read_u32_array(eth_np, "syscon-rgmii-delay", tmp, 2); > + if (ret) { > + dev_err(dev, "no syscon-rgmii-delay\n"); > + return ret; > + } > + > + node = ofnode_get_by_phandle(tmp[0]); > + if (!ofnode_valid(node)) { > + dev_err(dev, "can't get syscon-rgmii-delay node\n"); > + return -EINVAL; > + } > + > + ctrl_mmr = syscon_node_to_regmap(node); > + if (!ctrl_mmr) { > + dev_err(dev, "can't get ctrl_mmr regmap\n"); > + return -EINVAL; > + } > + > + if (ofnode_read_bool(eth_np, "enable-rgmii-delay")) > + val = 0; > + else > + val = ICSSG_CTRL_RGMII_ID_MODE; > + > + regmap_update_bits(ctrl_mmr, tmp[1], ICSSG_CTRL_RGMII_ID_MODE, val); > + > + return 0; > +} > + > +static int prueth_probe(struct udevice *dev) > +{ > + struct prueth *prueth; > + int ret = 0, i; > + ofnode eth0_node, eth1_node, node, pruss_node, mdio_node, sram_node; > + u32 phandle, err, sp; > + struct udevice **prussdev = NULL; > + struct icssg_config *config; > + > + prueth = dev_get_priv(dev); > + prueth->dev = dev; > + err = ofnode_read_u32(dev_ofnode(dev), "prus", &phandle); > + if (err) > + return err; > + > + node = ofnode_get_by_phandle(phandle); > + if (!ofnode_valid(node)) > + return -EINVAL; > + > + pruss_node = ofnode_get_parent(node); > + err = misc_init_by_ofnode(pruss_node); > + if (err) > + return err; > + > + ret = device_find_global_by_ofnode(pruss_node, prussdev); > + if (ret) > + dev_err(dev, "error getting the pruss dev\n"); Should we not exit here? > + > + ret = pruss_request_shrmem_region(*prussdev, &prueth->pruss_shrdram2); > + if (ret) > + return ret; > + > + node = dev_ofnode(dev); > + eth0_node = ofnode_find_subnode(node, "ethernet-mii0"); > + eth1_node = ofnode_find_subnode(node, "ethernet-mii1"); > + /* one node must be present and available else we fail */ > + if (!ofnode_valid(eth0_node) && !ofnode_valid(eth1_node)) { > + dev_err(dev, "neither ethernet-mii0 nor ethernet-mii1 node > available\n"); > + return -ENODEV; > + } > + > + /* > + * Exactly one node must be present as uboot ethernet framework does > + * not support two interfaces in a single probe. So Device Tree should > + * have exactly one of mii0 or mii1 interface. > + */ > + if (ofnode_valid(eth0_node) && ofnode_valid(eth1_node)) { > + dev_err(dev, "Both slices cannot be supported\n"); > + return -EINVAL; > + } > + > + if (ofnode_valid(eth0_node)) { > + prueth->slice = 0; > + icssg_ofdata_parse_phy(dev, eth0_node); > + prueth->eth_node[PRUETH_MAC0] = eth0_node; > + } > + > + if (ofnode_valid(eth1_node)) { > + prueth->slice = 1; > + icssg_ofdata_parse_phy(dev, eth1_node); > + prueth->eth_node[PRUETH_MAC0] = eth1_node; > + } > + > + prueth->miig_rt = syscon_regmap_lookup_by_phandle(dev, "mii-g-rt"); > + if (!prueth->miig_rt) { > + dev_err(dev, "couldn't get mii-g-rt syscon regmap\n"); > + return -ENODEV; > + } > + > + ret = clk_get_by_name(dev, "mdio_fck", &prueth->mdiofck); > + if (ret) { > + dev_err(dev, "failed to get clock %d\n", ret); > + return ret; > + } Blank line here for consistency with other statements. > + ret = clk_enable(&prueth->mdiofck); > + if (ret) { > + dev_err(dev, "clk_enable failed %d\n", ret); > + return ret; > + } > + > + ret = ofnode_read_u32(dev_ofnode(dev), "sram", &sp); > + if (ret) { > + dev_err(dev, "sram node fetch failed %d\n", ret); > + return ret; > + } > + > + sram_node = ofnode_get_by_phandle(sp); > + if (!ofnode_valid(node)) > + return -EINVAL; > + > + prueth->sram_pa = ofnode_get_addr(sram_node); > + > + if (!prueth->slice) { > + ret = prueth_config_rgmiidelay(prueth, eth0_node); > + if (ret) { > + dev_err(dev, "prueth_config_rgmiidelay failed\n"); > + return ret; > + } > + } else { > + ret = prueth_config_rgmiidelay(prueth, eth1_node); > + if (ret) { > + dev_err(dev, "prueth_config_rgmiidelay failed\n"); > + return ret; > + } > + } > + > + mdio_node = ofnode_find_subnode(pruss_node, "mdio"); > + prueth->mdio_base = ofnode_get_addr(mdio_node); > + ofnode_read_u32(mdio_node, "bus_freq", &prueth->mdio_freq); > + > + ret = icssg_mdio_init(dev); > + if (ret) > + return ret; > + > + ret = icssg_phy_init(dev); > + if (ret) { > + dev_err(dev, "phy_init failed\n"); > + goto out; > + } > + > + /* Set Load time configuration */ > + config = &prueth->config[0]; > + memset(config, 0, sizeof(*config)); > + config->addr_lo = cpu_to_le32(lower_32_bits(prueth->sram_pa)); > + config->addr_hi = cpu_to_le32(upper_32_bits(prueth->sram_pa)); > + config->num_tx_threads = 0; > + config->rx_flow_id = 0; /* flow id for host port */ > + > + for (i = 8; i < 16; i++) tx_buf_sz is 16 elements in size. What is different about elements 0...7 so that they don't need to get intialized? > + config->tx_buf_sz[i] = cpu_to_le32(0x1800); > + > + icssg_config_set(prueth); > + > + return 0; > +out: > + cpsw_mdio_free(prueth->bus); > + clk_disable(&prueth->mdiofck); > + > + return ret; > +} > + > +static const struct udevice_id prueth_ids[] = { > + { .compatible = "ti,am654-icssg-prueth" }, > + { } > +}; > + > +U_BOOT_DRIVER(prueth) = { > + .name = "prueth", > + .id = UCLASS_ETH, > + .of_match = prueth_ids, > + .probe = prueth_probe, > + .ops = &prueth_ops, > + .priv_auto_alloc_size = sizeof(struct prueth), > + .platdata_auto_alloc_size = sizeof(struct eth_pdata), > + .flags = DM_FLAG_ALLOC_PRIV_DMA, > +}; > diff --git a/drivers/net/ti/icssg.h b/drivers/net/ti/icssg.h > new file mode 100644 > index 0000000000..2e881e6eb3 > --- /dev/null > +++ b/drivers/net/ti/icssg.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver > + * > + * Copyright (C) 2019, Texas Instruments, Incorporated > + * > + */ Header file needs include guards. Needs blank line here. > +void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac); > +void icssg_class_disable(struct regmap *miig_rt, int slice); > +void icssg_class_default(struct regmap *miig_rt, int slice); > +void icssg_class_promiscuous(struct regmap *miig_rt, int slice); > + Typically the order of declarations in header files is... 1) defines 2) types 3) function prototypes > +/* Config area lies in shared RAM */ > +#define ICSSG_CONFIG_OFFSET_SLICE0 0 > +#define ICSSG_CONFIG_OFFSET_SLICE1 0x8000 > + > +/* Load time Fiwmware Configuration */ > +struct icssg_config { > + __le32 status; /* Firmware status */ > + __le32 addr_lo; /* MSMC Buffer pool base address low. */ > + __le32 addr_hi; /* MSMC Buffer pool base address high. Must be 0 */ > + __le32 tx_buf_sz[16]; /* Array of buffer pool sizes */ > + __le32 num_tx_threads; /* Number of active egress threads, 1 to 4 */ > + __le32 tx_rate_lim_en; /* Bitmask: Egress rate limit enable per thread > */ > + __le32 rx_flow_id; /* RX flow id for first rx ring */ > + __le32 rx_mgr_flow_id; /* RX flow id for the first management ring */ > + __le32 flags; /* TBD */ > + __le32 n_burst; /* for debug */ > + __le32 rtu_status; /* RTU status */ > + __le32 info; /* reserved */ > +} __packed; > diff --git a/drivers/net/ti/icssg_classifier.c > b/drivers/net/ti/icssg_classifier.c > new file mode 100644 > index 0000000000..2af14ed5b2 > --- /dev/null > +++ b/drivers/net/ti/icssg_classifier.c > @@ -0,0 +1,397 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Texas Instruments ICSSG Ethernet Driver > + * > + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 2019 > + * > + */ > + > +#include <common.h> > +#include <asm/io.h> > +#include <asm/processor.h> > +#include <clk.h> > +#include <dm.h> > +#include <dm/lists.h> > +#include <dm/device.h> > +#include <dma-uclass.h> > +#include <dm/of_access.h> > +#include <miiphy.h> > +#include <net.h> > +#include <phy.h> > +#include <power-domain.h> > +#include <linux/soc/ti/ti-udma.h> > +#include <syscon.h> > +#include <ti-pruss.h> > +#include <regmap.h> > + > +#include "cpsw_mdio.h" > +#include "icssg.h" > + > +#define ICSSG_NUM_CLASSIFIERS 16 > +#define ICSSG_NUM_FT1_SLOTS 8 > +#define ICSSG_NUM_FT3_SLOTS 16 > + > +/* Filter 1 - FT1 */ > +#define FT1_NUM_SLOTS 8 > +#define FT1_SLOT_SIZE 0x10 /* bytes */ > + > +/* offsets from FT1 slot base i.e. slot 1 start */ > +#define FT1_DA0 0x0 > +#define FT1_DA1 0x4 > +#define FT1_DA0_MASK 0x8 > +#define FT1_DA1_MASK 0xc > + > +#define FT1_N_REG(slize, n, reg) (offs[slice].ft1_slot_base + > FT1_SLOT_SIZE * (n) + (reg)) > + > +#define FT1_LEN_MASK GENMASK(19, 16) > +#define FT1_LEN_SHIFT 16 > +#define FT1_LEN(len) (((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK) > + > +#define FT1_MATCH_SLOT(n) (GENMASK(23, 16) & (BIT(n) << 16)) > + > +enum ft1_cfg_type { > + FT1_CFG_TYPE_DISABLED = 0, > + FT1_CFG_TYPE_EQ, > + FT1_CFG_TYPE_GT, > + FT1_CFG_TYPE_LT, > +}; > + > +#define FT1_CFG_SHIFT(n) (2 * (n)) > +#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) > + > +/* Filter 3 - FT3 */ > +#define FT3_NUM_SLOTS 16 > +#define FT3_SLOT_SIZE 0x20 /* bytes */ > + > +/* offsets from FT3 slot n's base */ > +#define FT3_START 0 > +#define FT3_START_AUTO 0x4 > +#define FT3_START_OFFSET 0x8 > +#define FT3_JUMP_OFFSET 0xc > +#define FT3_LEN 0x10 > +#define FT3_CFG 0x14 > +#define FT3_T 0x18 > +#define FT3_T_MASK 0x1c > + > +#define FT3_N_REG(slize, n, reg) (offs[slice].ft3_slot_base + > FT3_SLOT_SIZE * (n) + (reg)) > + > +/* offsets from rx_class n's base */ > +#define RX_CLASS_AND_EN 0 > +#define RX_CLASS_OR_EN 0x4 > + > +#define RX_CLASS_NUM_SLOTS 16 > +#define RX_CLASS_EN_SIZE 0x8 /* bytes */ > + > +#define RX_CLASS_N_REG(slice, n, reg) (offs[slice].rx_class_base + > RX_CLASS_EN_SIZE * (n) + (reg)) > + > +/* RX Class Gates */ > +#define RX_CLASS_GATES_SIZE 0x4 /* bytes */ > + > +#define RX_CLASS_GATES_N_REG(slice, n) > (offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n)) > + > +#define RX_CLASS_GATES_ALLOW_MASK BIT(6) > +#define RX_CLASS_GATES_RAW_MASK BIT(5) > +#define RX_CLASS_GATES_PHASE_MASK BIT(4) > + > +/* RX Class traffic data matching bits */ > +#define RX_CLASS_FT_UC BIT(31) > +#define RX_CLASS_FT_MC BIT(30) > +#define RX_CLASS_FT_BC BIT(29) > +#define RX_CLASS_FT_FW BIT(28) > +#define RX_CLASS_FT_RCV BIT(27) > +#define RX_CLASS_FT_VLAN BIT(26) > +#define RX_CLASS_FT_DA_P BIT(25) > +#define RX_CLASS_FT_DA_I BIT(24) > +#define RX_CLASS_FT_FT1_MATCH_MASK GENMASK(23, 16) > +#define RX_CLASS_FT_FT1_MATCH_SHIFT 16 > +#define RX_CLASS_FT_FT3_MATCH_MASK GENMASK(15, 0) > +#define RX_CLASS_FT_FT3_MATCH_SHIFT 0 > + > +enum rx_class_sel_type { > + RX_CLASS_SEL_TYPE_OR = 0, > + RX_CLASS_SEL_TYPE_AND = 1, > + RX_CLASS_SEL_TYPE_OR_AND_AND = 2, > + RX_CLASS_SEL_TYPE_OR_OR_AND = 3, > +}; > + > +#define FT1_CFG_SHIFT(n) (2 * (n)) > +#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) > + > +#define RX_CLASS_SEL_SHIFT(n) (2 * (n)) > +#define RX_CLASS_SEL_MASK(n) (0x3 << RX_CLASS_SEL_SHIFT((n))) > + > +#define ICSSG_CFG_OFFSET 0 > +#define RGMII_CFG_OFFSET 4 > + > +#define ICSSG_CFG_RX_L2_G_EN BIT(2) > + > +/* these are register offsets per PRU */ > +struct miig_rt_offsets { > + u32 mac0; > + u32 mac1; > + u32 ft1_start_len; > + u32 ft1_cfg; > + u32 ft1_slot_base; > + u32 ft3_slot_base; > + u32 ft3_p_base; > + u32 ft_rx_ptr; > + u32 rx_class_base; > + u32 rx_class_cfg1; > + u32 rx_class_cfg2; > + u32 rx_class_gates_base; > + u32 rx_green; > + u32 rx_rate_cfg_base; > + u32 rx_rate_src_sel0; > + u32 rx_rate_src_sel1; > + u32 tx_rate_cfg_base; > + u32 stat_base; > + u32 tx_hsr_tag; > + u32 tx_hsr_seq; > + u32 tx_vlan_type; > + u32 tx_vlan_ins; > +}; > + > +static struct miig_rt_offsets offs[] = { > + /* PRU0 */ > + { > + 0x8, > + 0xc, > + 0x80, > + 0x84, > + 0x88, > + 0x108, > + 0x308, > + 0x408, > + 0x40c, > + 0x48c, > + 0x490, > + 0x494, > + 0x4d4, > + 0x4e4, > + 0x504, > + 0x508, > + 0x50c, > + 0x54c, > + 0x63c, > + 0x640, > + 0x644, > + 0x648, > + }, > + /* PRU1 */ > + { > + 0x10, > + 0x14, > + 0x64c, > + 0x650, > + 0x654, > + 0x6d4, > + 0x8d4, > + 0x9d4, > + 0x9d8, > + 0xa58, > + 0xa5c, > + 0xa60, > + 0xaa0, > + 0xab0, > + 0xad0, > + 0xad4, > + 0xad8, > + 0xb18, > + 0xc08, > + 0xc0c, > + 0xc10, > + 0xc14, > + }, > +}; > + > +static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int > n, > + enum ft1_cfg_type type) > +{ > + u32 offset; > + > + offset = offs[slice].ft1_cfg; > + regmap_update_bits(miig_rt, offset, FT1_CFG_MASK(n), > + type << FT1_CFG_SHIFT(n)); > +} > + > +static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n, > + enum rx_class_sel_type type) > +{ > + u32 offset; > + > + offset = offs[slice].rx_class_cfg1; > + regmap_update_bits(miig_rt, offset, RX_CLASS_SEL_MASK(n), > + type << RX_CLASS_SEL_SHIFT(n)); > +} > + > +static void rx_class_set_and(struct regmap *miig_rt, int slice, int n, > + u32 data) > +{ > + u32 offset; > + > + offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN); > + regmap_write(miig_rt, offset, data); > +} > + > +static void rx_class_set_or(struct regmap *miig_rt, int slice, int n, > + u32 data) > +{ > + u32 offset; > + > + offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN); > + regmap_write(miig_rt, offset, data); > +} > + > +/* disable all RX traffic */ > +void icssg_class_disable(struct regmap *miig_rt, int slice) > +{ > + u32 data, offset; > + int n; > + > + /* Enable RX_L2_G */ > + regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN, > + ICSSG_CFG_RX_L2_G_EN); > + > + for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++) { > + /* AND_EN = 0 */ > + rx_class_set_and(miig_rt, slice, n, 0); > + /* OR_EN = 0 */ > + rx_class_set_or(miig_rt, slice, n, 0); > + > + /* set CFG1 to OR */ > + rx_class_sel_set_type(miig_rt, slice, n, RX_CLASS_SEL_TYPE_OR); > + > + /* configure gate */ > + offset = RX_CLASS_GATES_N_REG(slice, n); > + regmap_read(miig_rt, offset, &data); > + /* clear class_raw */ > + data &= ~RX_CLASS_GATES_RAW_MASK; > + /* set allow and phase mask */ > + data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK; > + regmap_write(miig_rt, offset, data); > + } > + > + /* FT1 uses 6 bytes of DA address */ > + offset = offs[slice].ft1_start_len; > + regmap_write(miig_rt, offset, FT1_LEN(6)); > + > + /* FT1 type EQ */ > + for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) > + rx_class_ft1_cfg_set_type(miig_rt, slice, n, FT1_CFG_TYPE_EQ); > + > + /* FT1[0] DA compare address 00-00-00-00-00-00 */ > + offset = FT1_N_REG(slice, 0, FT1_DA0); > + regmap_write(miig_rt, offset, 0); > + offset = FT1_N_REG(slice, 0, FT1_DA1); > + regmap_write(miig_rt, offset, 0); > + > + /* FT1[0] mask FE-FF-FF-FF-FF-FF */ > + offset = FT1_N_REG(slice, 0, FT1_DA0_MASK); > + regmap_write(miig_rt, offset, 0); > + offset = FT1_N_REG(slice, 0, FT1_DA1_MASK); > + regmap_write(miig_rt, offset, 0); > + > + /* clear CFG2 */ > + regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); > +} > + > +void icssg_class_default(struct regmap *miig_rt, int slice) > +{ > + u32 offset, data; > + int n; > + > + /* defaults */ > + icssg_class_disable(miig_rt, slice); > + > + /* FT1 uses 6 bytes of DA address */ > + offset = offs[slice].ft1_start_len; > + regmap_write(miig_rt, offset, FT1_LEN(6)); > + > + /* FT1 slots to EQ */ > + for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) > + rx_class_ft1_cfg_set_type(miig_rt, slice, n, FT1_CFG_TYPE_EQ); > + > + /* FT1[0] DA compare address 00-00-00-00-00-00 */ > + offset = FT1_N_REG(slice, 0, FT1_DA0); > + regmap_write(miig_rt, offset, 0); > + offset = FT1_N_REG(slice, 0, FT1_DA1); > + regmap_write(miig_rt, offset, 0); > + > + /* FT1[0] mask 00-00-00-00-00-00 */ > + offset = FT1_N_REG(slice, 0, FT1_DA0_MASK); > + regmap_write(miig_rt, offset, 0); > + offset = FT1_N_REG(slice, 0, FT1_DA1_MASK); > + regmap_write(miig_rt, offset, 0); > + > + /* Setup Classifier 4 */ > + /* match on Broadcast or MAC_PRU address */ > + data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P; > + rx_class_set_or(miig_rt, slice, 4, data); > + > + /* set CFG1 for OR_OR_AND for classifier 4 */ > + rx_class_sel_set_type(miig_rt, slice, 4, RX_CLASS_SEL_TYPE_OR_OR_AND); > + > + /* ungate classifier 4 */ > + offset = RX_CLASS_GATES_N_REG(slice, 4); > + regmap_read(miig_rt, offset, &data); > + data |= RX_CLASS_GATES_RAW_MASK; > + regmap_write(miig_rt, offset, data); > + > + /* clear CFG2 */ > + regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); > +} > + > +void icssg_class_promiscuous(struct regmap *miig_rt, int slice) > +{ > + u32 data; > + u32 offset; > + int n; > + > + /* defaults */ > + icssg_class_disable(miig_rt, slice); > + > + /* FT1 uses 6 bytes of DA address */ > + offset = offs[slice].ft1_start_len; > + regmap_write(miig_rt, offset, FT1_LEN(6)); > + > + /* FT1 type EQ */ > + for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) > + rx_class_ft1_cfg_set_type(miig_rt, slice, n, FT1_CFG_TYPE_EQ); > + > + /* FT1[0] DA compare address 00-00-00-00-00-00 */ > + offset = FT1_N_REG(slice, 0, FT1_DA0); > + regmap_write(miig_rt, offset, 0); > + offset = FT1_N_REG(slice, 0, FT1_DA1); > + regmap_write(miig_rt, offset, 0); > + > + /* FT1[0] mask FE-FF-FF-FF-FF-FF */ > + offset = FT1_N_REG(slice, 0, FT1_DA0_MASK); > + regmap_write(miig_rt, offset, 0xfffffffe); > + offset = FT1_N_REG(slice, 0, FT1_DA1_MASK); > + regmap_write(miig_rt, offset, 0xffff); > + > + /* Setup Classifier 4 */ > + /* match on multicast, broadcast or unicast (ft1-0 address) */ > + data = RX_CLASS_FT_MC | RX_CLASS_FT_BC | FT1_MATCH_SLOT(0); > + rx_class_set_or(miig_rt, slice, 4, data); > + > + /* set CFG1 for OR_OR_AND for classifier 4 */ > + rx_class_sel_set_type(miig_rt, slice, 4, RX_CLASS_SEL_TYPE_OR_OR_AND); > + > + /* ungate classifier 4 */ > + offset = RX_CLASS_GATES_N_REG(slice, 4); > + regmap_read(miig_rt, offset, &data); > + data |= RX_CLASS_GATES_RAW_MASK; > + regmap_write(miig_rt, offset, data); > +} > + > +void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac) > +{ > + u32 mac0, mac1; > + > + mac0 = mac[0] | mac[1] << 8 | > + mac[2] << 16 | mac[3] << 24; This could be in one line ^^ -- Andreas Dannenberg Texas Instruments Inc > + mac1 = mac[4] | mac[5] << 8; > + > + regmap_write(miig_rt, offs[slice].mac0, mac0); > + regmap_write(miig_rt, offs[slice].mac1, mac1); > +} > -- > 2.17.1 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > https://lists.denx.de/listinfo/u-boot _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot