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

Reply via email to