
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-keerthy@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