[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240618115716.GA1186487@maili.marvell.com>
Date: Tue, 18 Jun 2024 17:27:16 +0530
From: Ratheesh Kannoth <rkannoth@...vell.com>
To: Niklas Söderlund
<niklas.soderlund+renesas@...natech.se>
CC: Yoshihiro Shimoda <yoshihiro.shimoda.uh@...esas.com>,
"David S. Miller"
<davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski
<kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>, Andrew Lunn
<andrew@...n.ch>,
<netdev@...r.kernel.org>, <linux-renesas-soc@...r.kernel.org>
Subject: Re: [net-next,v9] net: ethernet: rtsn: Add support for Renesas
Ethernet-TSN
On 2024-06-18 at 14:38:24, Niklas Söderlund (niklas.soderlund+renesas@...natech.se) wrote:
> Add initial support for Renesas Ethernet-TSN End-station device of R-Car
> V4H. The Ethernet End-station can connect to an Ethernet network using a
> 10 Mbps, 100 Mbps, or 1 Gbps full-duplex link via MII/GMII/RMII/RGMII.
> Depending on the connected PHY.
>
> The driver supports Rx checksum and offload and hardware timestamps.
>
> While full power management and suspend/resume is not yet supported the
> driver enables runtime PM in order to enable the module clock. While
> explicit clock management using clk_enable() would suffice for the
> supported SoC, the module could be reused on SoCs where the module is
> part of a power domain.
>
> Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@...natech.se>
> ---
> +static int rtsn_tx_free(struct net_device *ndev, bool free_txed_only)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> + struct rtsn_ext_desc *desc;
> + struct sk_buff *skb;
> + int free_num = 0;
> + int entry, size;
> +
> + for (; priv->cur_tx - priv->dirty_tx > 0; priv->dirty_tx++) {
> + entry = priv->dirty_tx % priv->num_tx_ring;
> + desc = &priv->tx_ring[entry];
> + if (free_txed_only && (desc->die_dt & DT_MASK) != DT_FEMPTY)
> + break;
> +
> + dma_rmb();
> + size = le16_to_cpu(desc->info_ds) & TX_DS;
> + skb = priv->tx_skb[entry];
> + if (skb) {
> + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
> + struct skb_shared_hwtstamps shhwtstamps;
> + struct timespec64 ts;
> +
> + rtsn_get_timestamp(priv, &ts);
> + memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> + shhwtstamps.hwtstamp = timespec64_to_ktime(ts);
> + skb_tstamp_tx(skb, &shhwtstamps);
> + }
> + dma_unmap_single(ndev->dev.parent,
> + le32_to_cpu(desc->dptr),
> + size, DMA_TO_DEVICE);
> + dev_kfree_skb_any(priv->tx_skb[entry]);
> + free_num++;
> + }
> + desc->die_dt = DT_EEMPTY;
> + priv->stats.tx_packets++;
if (!skb) case also, incrementing the tx_packets. Is this correct ?
> + priv->stats.tx_bytes += size;
> + }
> +
> + desc = &priv->tx_ring[priv->num_tx_ring];
> + desc->die_dt = DT_LINK;
> +
> + return free_num;
> +}
> +
> +
> +static int rtsn_dmac_init(struct rtsn_private *priv)
> +{
> + int ret;
> +
> + ret = rtsn_chain_init(priv, TX_CHAIN_SIZE, RX_CHAIN_SIZE);
> + if (ret)
> + return ret;
> +
> + rtsn_chain_format(priv);
> +
> + return 0;
> +}
> +
> +static enum rtsn_mode rtsn_read_mode(struct rtsn_private *priv)
> +{
> + return (rtsn_read(priv, OSR) & OSR_OPS) >> 1;
> +}
> +
> +static int rtsn_wait_mode(struct rtsn_private *priv, enum rtsn_mode mode)
> +{
> + unsigned int i;
> +
> + /* Need to busy loop as mode changes can happen in atomic context. */
> + for (i = 0; i < RTSN_TIMEOUT_US / RTSN_INTERVAL_US; i++) {
> + if (rtsn_read_mode(priv) == mode)
> + return 0;
> +
> + udelay(RTSN_INTERVAL_US);
> + }
> +
> + return -ETIMEDOUT;
> +}
> +
> +static int rtsn_change_mode(struct rtsn_private *priv, enum rtsn_mode mode)
> +{
> + int ret;
> +
> + rtsn_write(priv, OCR, mode);
> + ret = rtsn_wait_mode(priv, mode);
> + if (ret)
> + netdev_err(priv->ndev, "Failed to switch operation mode\n");
> + return ret;
> +}
> +
> +static int rtsn_get_data_irq_status(struct rtsn_private *priv)
> +{
> + u32 val;
> +
> + val = rtsn_read(priv, TDIS0) | TDIS_TDS(TX_CHAIN_IDX);
> + val |= rtsn_read(priv, RDIS0) | RDIS_RDS(RX_CHAIN_IDX);
> +
> + return val;
> +}
> +
> +static irqreturn_t rtsn_irq(int irq, void *dev_id)
> +{
> + struct rtsn_private *priv = dev_id;
> + int ret = IRQ_NONE;
> +
> + spin_lock(&priv->lock);
> +
> + if (rtsn_get_data_irq_status(priv)) {
> + /* Clear TX/RX irq status */
> + rtsn_write(priv, TDIS0, TDIS_TDS(TX_CHAIN_IDX));
> + rtsn_write(priv, RDIS0, RDIS_RDS(RX_CHAIN_IDX));
> +
> + if (napi_schedule_prep(&priv->napi)) {
> + /* Disable TX/RX interrupts */
> + rtsn_ctrl_data_irq(priv, false);
> +
> + __napi_schedule(&priv->napi);
> + }
> +
> + ret = IRQ_HANDLED;
> + }
> +
> + spin_unlock(&priv->lock);
> +
> + return ret;
> +}
> +
> +static int rtsn_request_irq(unsigned int irq, irq_handler_t handler,
> + unsigned long flags, struct rtsn_private *priv,
> + const char *ch)
> +{
> + char *name;
> + int ret;
> +
> + name = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, "%s:%s",
> + priv->ndev->name, ch);
> + if (!name)
> + return -ENOMEM;
> +
> + ret = request_irq(irq, handler, flags, name, priv);
> + if (ret)
> + netdev_err(priv->ndev, "Cannot request IRQ %s\n", name);
> +
> + return ret;
> +}
> +
> +static void rtsn_free_irqs(struct rtsn_private *priv)
> +{
> + free_irq(priv->tx_data_irq, priv);
> + free_irq(priv->rx_data_irq, priv);
> +}
> +
> +static int rtsn_request_irqs(struct rtsn_private *priv)
> +{
> + int ret;
> +
> + priv->rx_data_irq = platform_get_irq_byname(priv->pdev, "rx");
> + if (priv->rx_data_irq < 0)
> + return priv->rx_data_irq;
> +
> + priv->tx_data_irq = platform_get_irq_byname(priv->pdev, "tx");
> + if (priv->tx_data_irq < 0)
> + return priv->tx_data_irq;
> +
> + ret = rtsn_request_irq(priv->tx_data_irq, rtsn_irq, 0, priv, "tx");
> + if (ret)
> + return ret;
> +
> + ret = rtsn_request_irq(priv->rx_data_irq, rtsn_irq, 0, priv, "rx");
> + if (ret) {
> + free_irq(priv->tx_data_irq, priv);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int rtsn_reset(struct rtsn_private *priv)
> +{
> + reset_control_reset(priv->reset);
> + mdelay(1);
> +
> + return rtsn_wait_mode(priv, OCR_OPC_DISABLE);
> +}
> +
> +static int rtsn_axibmi_init(struct rtsn_private *priv)
> +{
> + int ret;
> +
> + ret = rtsn_reg_wait(priv, RR, RR_RST, RR_RST_COMPLETE);
> + if (ret)
> + return ret;
> +
> + /* Set AXIWC */
> + rtsn_write(priv, AXIWC, AXIWC_DEFAULT);
> +
> + /* Set AXIRC */
> + rtsn_write(priv, AXIRC, AXIRC_DEFAULT);
> +
> + /* TX Descriptor chain setting */
> + rtsn_write(priv, TATLS0, TATLS0_TEDE | TATLS0_TATEN(TX_CHAIN_IDX));
> + rtsn_write(priv, TATLS1, priv->tx_desc_bat_dma + TX_CHAIN_ADDR_OFFSET);
> + rtsn_write(priv, TATLR, TATLR_TATL);
> +
> + ret = rtsn_reg_wait(priv, TATLR, TATLR_TATL, 0);
> + if (ret)
> + return ret;
> +
> + /* RX Descriptor chain setting */
> + rtsn_write(priv, RATLS0,
> + RATLS0_RETS | RATLS0_REDE | RATLS0_RATEN(RX_CHAIN_IDX));
> + rtsn_write(priv, RATLS1, priv->rx_desc_bat_dma + RX_CHAIN_ADDR_OFFSET);
> + rtsn_write(priv, RATLR, RATLR_RATL);
> +
> + ret = rtsn_reg_wait(priv, RATLR, RATLR_RATL, 0);
> + if (ret)
> + return ret;
> +
> + /* Enable TX/RX interrupts */
> + rtsn_ctrl_data_irq(priv, true);
> +
> + return 0;
> +}
> +
> +static void rtsn_mhd_init(struct rtsn_private *priv)
> +{
> + /* TX General setting */
> + rtsn_write(priv, TGC1, TGC1_STTV_DEFAULT | TGC1_TQTM_SFM);
> + rtsn_write(priv, TMS0, TMS_MFS_MAX);
> +
> + /* RX Filter IP */
> + rtsn_write(priv, CFCR0, CFCR_SDID(RX_CHAIN_IDX));
> + rtsn_write(priv, FMSCR, FMSCR_FMSIE(RX_CHAIN_IDX));
> +}
> +
> +static int rtsn_get_phy_params(struct rtsn_private *priv)
> +{
> + int ret;
> +
> + ret = of_get_phy_mode(priv->pdev->dev.of_node, &priv->iface);
> + if (ret)
> + return ret;
> +
> + switch (priv->iface) {
> + case PHY_INTERFACE_MODE_MII:
> + priv->speed = 100;
> + break;
> + case PHY_INTERFACE_MODE_RGMII:
> + case PHY_INTERFACE_MODE_RGMII_ID:
> + case PHY_INTERFACE_MODE_RGMII_RXID:
> + case PHY_INTERFACE_MODE_RGMII_TXID:
> + priv->speed = 1000;
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static void rtsn_set_phy_interface(struct rtsn_private *priv)
> +{
> + u32 val;
> +
> + switch (priv->iface) {
> + case PHY_INTERFACE_MODE_MII:
> + val = MPIC_PIS_MII;
> + break;
> + case PHY_INTERFACE_MODE_RGMII:
> + case PHY_INTERFACE_MODE_RGMII_ID:
> + case PHY_INTERFACE_MODE_RGMII_RXID:
> + case PHY_INTERFACE_MODE_RGMII_TXID:
> + val = MPIC_PIS_GMII;
> + break;
> + default:
> + return;
> + }
> +
> + rtsn_modify(priv, MPIC, MPIC_PIS_MASK, val);
> +}
> +
> +static void rtsn_set_rate(struct rtsn_private *priv)
> +{
> + u32 val;
> +
> + switch (priv->speed) {
> + case 10:
> + val = MPIC_LSC_10M;
> + break;
> + case 100:
> + val = MPIC_LSC_100M;
> + break;
> + case 1000:
> + val = MPIC_LSC_1G;
> + break;
> + default:
> + return;
> + }
> +
> + rtsn_modify(priv, MPIC, MPIC_LSC_MASK, val);
> +}
> +
> +static int rtsn_rmac_init(struct rtsn_private *priv)
> +{
> + const u8 *mac_addr = priv->ndev->dev_addr;
> + int ret;
> +
> + /* Set MAC address */
> + rtsn_write(priv, MRMAC0, (mac_addr[0] << 8) | mac_addr[1]);
> + rtsn_write(priv, MRMAC1, (mac_addr[2] << 24) | (mac_addr[3] << 16) |
> + (mac_addr[4] << 8) | mac_addr[5]);
> +
> + /* Set xMII type */
> + rtsn_set_phy_interface(priv);
> + rtsn_set_rate(priv);
> +
> + /* Enable MII */
> + rtsn_modify(priv, MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK,
> + MPIC_PSMCS_DEFAULT | MPIC_PSMHT_DEFAULT);
> +
> + /* Link verification */
> + rtsn_modify(priv, MLVC, MLVC_PLV, MLVC_PLV);
> + ret = rtsn_reg_wait(priv, MLVC, MLVC_PLV, 0);
> + if (ret)
> + return ret;
> +
> + return ret;
> +}
> +
> +static int rtsn_hw_init(struct rtsn_private *priv)
> +{
> + int ret;
> +
> + ret = rtsn_reset(priv);
> + if (ret)
> + return ret;
> +
> + /* Change to CONFIG mode */
> + ret = rtsn_change_mode(priv, OCR_OPC_CONFIG);
> + if (ret)
> + return ret;
> +
> + ret = rtsn_axibmi_init(priv);
> + if (ret)
> + return ret;
> +
> + rtsn_mhd_init(priv);
> +
> + ret = rtsn_rmac_init(priv);
> + if (ret)
> + return ret;
> +
> + ret = rtsn_change_mode(priv, OCR_OPC_DISABLE);
> + if (ret)
> + return ret;
> +
> + /* Change to OPERATION mode */
> + ret = rtsn_change_mode(priv, OCR_OPC_OPERATION);
> +
> + return ret;
> +}
> +
> +static int rtsn_mii_access(struct mii_bus *bus, bool read, int phyad,
> + int regad, u16 data)
> +{
> + struct rtsn_private *priv = bus->priv;
> + u32 val;
> + int ret;
> +
> + val = MPSM_PDA(phyad) | MPSM_PRA(regad) | MPSM_PSME;
> +
> + if (!read)
> + val |= MPSM_PSMAD | MPSM_PRD_SET(data);
> +
> + rtsn_write(priv, MPSM, val);
> +
> + ret = rtsn_reg_wait(priv, MPSM, MPSM_PSME, 0);
> + if (ret)
> + return ret;
> +
> + if (read)
> + ret = MPSM_PRD_GET(rtsn_read(priv, MPSM));
> +
> + return ret;
> +}
> +
> +static int rtsn_mii_read(struct mii_bus *bus, int addr, int regnum)
> +{
> + return rtsn_mii_access(bus, true, addr, regnum, 0);
> +}
> +
> +static int rtsn_mii_write(struct mii_bus *bus, int addr, int regnum, u16 val)
> +{
> + return rtsn_mii_access(bus, false, addr, regnum, val);
> +}
> +
> +static int rtsn_mdio_alloc(struct rtsn_private *priv)
> +{
> + struct platform_device *pdev = priv->pdev;
> + struct device *dev = &pdev->dev;
> + struct device_node *mdio_node;
> + struct mii_bus *mii;
> + int ret;
> +
> + mii = mdiobus_alloc();
> + if (!mii)
> + return -ENOMEM;
> +
> + mdio_node = of_get_child_by_name(dev->of_node, "mdio");
> + if (!mdio_node) {
> + ret = -ENODEV;
> + goto out_free_bus;
> + }
> +
> + /* Enter config mode before registering the MDIO bus */
> + ret = rtsn_reset(priv);
> + if (ret)
> + goto out_free_bus;
> +
> + ret = rtsn_change_mode(priv, OCR_OPC_CONFIG);
> + if (ret)
> + goto out_free_bus;
> +
> + rtsn_modify(priv, MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK,
> + MPIC_PSMCS_DEFAULT | MPIC_PSMHT_DEFAULT);
> +
> + /* Register the MDIO bus */
> + mii->name = "rtsn_mii";
> + snprintf(mii->id, MII_BUS_ID_SIZE, "%s-%x",
> + pdev->name, pdev->id);
> + mii->priv = priv;
> + mii->read = rtsn_mii_read;
> + mii->write = rtsn_mii_write;
> + mii->parent = dev;
> +
> + ret = of_mdiobus_register(mii, mdio_node);
> + of_node_put(mdio_node);
> + if (ret)
> + goto out_free_bus;
> +
> + priv->mii = mii;
> +
> + return 0;
> +
> +out_free_bus:
> + mdiobus_free(mii);
> + return ret;
> +}
> +
> +static void rtsn_mdio_free(struct rtsn_private *priv)
> +{
> + mdiobus_unregister(priv->mii);
> + mdiobus_free(priv->mii);
> + priv->mii = NULL;
> +}
> +
> +static void rtsn_adjust_link(struct net_device *ndev)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> + struct phy_device *phydev = ndev->phydev;
> + bool new_state = false;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + if (phydev->link) {
> + if (phydev->speed != priv->speed) {
> + new_state = true;
> + priv->speed = phydev->speed;
> + }
> +
> + if (!priv->link) {
> + new_state = true;
> + priv->link = phydev->link;
> + }
> + } else if (priv->link) {
> + new_state = true;
> + priv->link = 0;
> + priv->speed = 0;
> + }
> +
> + if (new_state) {
> + /* Need to transition to CONFIG mode before reconfiguring and
> + * then back to the original mode. Any state change to/from
> + * CONFIG or OPERATION must go over DISABLED to stop Rx/Tx.
> + */
> + enum rtsn_mode orgmode = rtsn_read_mode(priv);
> +
> + /* Transit to CONFIG */
> + if (orgmode != OCR_OPC_CONFIG) {
> + if (orgmode != OCR_OPC_DISABLE &&
> + rtsn_change_mode(priv, OCR_OPC_DISABLE))
> + goto out;
> + if (rtsn_change_mode(priv, OCR_OPC_CONFIG))
> + goto out;
> + }
> +
> + rtsn_set_rate(priv);
> +
> + /* Transition to original mode */
> + if (orgmode != OCR_OPC_CONFIG) {
> + if (rtsn_change_mode(priv, OCR_OPC_DISABLE))
> + goto out;
> + if (orgmode != OCR_OPC_DISABLE &&
> + rtsn_change_mode(priv, orgmode))
> + goto out;
> + }
> + }
> +out:
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> + if (new_state)
> + phy_print_status(phydev);
> +}
> +
> +static int rtsn_phy_init(struct rtsn_private *priv)
> +{
> + struct device_node *np = priv->ndev->dev.parent->of_node;
> + struct phy_device *phydev;
> + struct device_node *phy;
> +
> + priv->link = 0;
> +
> + phy = of_parse_phandle(np, "phy-handle", 0);
> + if (!phy)
> + return -ENOENT;
> +
> + phydev = of_phy_connect(priv->ndev, phy, rtsn_adjust_link, 0,
> + priv->iface);
> + of_node_put(phy);
> + if (!phydev)
> + return -ENOENT;
> +
> + /* Only support full-duplex mode */
> + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
> + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
> + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
> +
> + phy_attached_info(phydev);
> +
> + return 0;
> +}
> +
> +static void rtsn_phy_deinit(struct rtsn_private *priv)
> +{
> + phy_disconnect(priv->ndev->phydev);
> + priv->ndev->phydev = NULL;
> +}
> +
> +static int rtsn_init(struct rtsn_private *priv)
> +{
> + int ret;
> +
> + ret = rtsn_desc_alloc(priv);
> + if (ret)
> + return ret;
> +
> + ret = rtsn_dmac_init(priv);
> + if (ret)
> + goto error_free_desc;
> +
> + ret = rtsn_hw_init(priv);
> + if (ret)
> + goto error_free_chain;
> +
> + ret = rtsn_phy_init(priv);
> + if (ret)
> + goto error_free_chain;
> +
> + ret = rtsn_request_irqs(priv);
> + if (ret)
> + goto error_free_phy;
> +
> + return 0;
> +error_free_phy:
> + rtsn_phy_deinit(priv);
> +error_free_chain:
> + rtsn_chain_free(priv);
> +error_free_desc:
> + rtsn_desc_free(priv);
> + return ret;
> +}
> +
> +static void rtsn_deinit(struct rtsn_private *priv)
> +{
> + rtsn_free_irqs(priv);
> + rtsn_phy_deinit(priv);
> + rtsn_chain_free(priv);
> + rtsn_desc_free(priv);
> +}
> +
> +static void rtsn_parse_mac_address(struct device_node *np,
> + struct net_device *ndev)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> + u8 addr[ETH_ALEN];
> + u32 mrmac0;
> + u32 mrmac1;
> +
> + /* Try to read address from Device Tree. */
> + if (!of_get_mac_address(np, addr)) {
> + eth_hw_addr_set(ndev, addr);
> + return;
> + }
> +
> + /* Try to read address from device. */
> + mrmac0 = rtsn_read(priv, MRMAC0);
> + mrmac1 = rtsn_read(priv, MRMAC1);
> +
> + addr[0] = (mrmac0 >> 8) & 0xff;
> + addr[1] = (mrmac0 >> 0) & 0xff;
> + addr[2] = (mrmac1 >> 24) & 0xff;
> + addr[3] = (mrmac1 >> 16) & 0xff;
> + addr[4] = (mrmac1 >> 8) & 0xff;
> + addr[5] = (mrmac1 >> 0) & 0xff;
> +
> + if (is_valid_ether_addr(addr)) {
> + eth_hw_addr_set(ndev, addr);
> + return;
> + }
> +
> + /* Fallback to a random address */
> + eth_hw_addr_random(ndev);
> +}
> +
> +static int rtsn_open(struct net_device *ndev)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> + int ret;
> +
> + napi_enable(&priv->napi);
> +
> + ret = rtsn_init(priv);
> + if (ret) {
> + napi_disable(&priv->napi);
> + return ret;
> + }
> +
> + phy_start(ndev->phydev);
> +
> + netif_start_queue(ndev);
> +
> + return 0;
> +}
> +
> +static int rtsn_stop(struct net_device *ndev)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> +
> + phy_stop(priv->ndev->phydev);
> + napi_disable(&priv->napi);
> + rtsn_change_mode(priv, OCR_OPC_DISABLE);
> + rtsn_deinit(priv);
> +
> + return 0;
> +}
> +
> +static netdev_tx_t rtsn_start_xmit(struct sk_buff *skb, struct net_device *ndev)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> + struct rtsn_ext_desc *desc;
> + int ret = NETDEV_TX_OK;
> + unsigned long flags;
> + dma_addr_t dma_addr;
> + int entry;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + /* Drop packet if it won't fit in a single descriptor. */
> + if (skb->len >= TX_DS) {
> + priv->stats.tx_dropped++;
> + priv->stats.tx_errors++;
> + goto out;
> + }
> +
> + if (priv->cur_tx - priv->dirty_tx > priv->num_tx_ring) {
> + netif_stop_subqueue(ndev, 0);
> + ret = NETDEV_TX_BUSY;
> + goto out;
> + }
> +
> + if (skb_put_padto(skb, ETH_ZLEN))
> + goto out;
> +
> + dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len,
> + DMA_TO_DEVICE);
> + if (dma_mapping_error(ndev->dev.parent, dma_addr)) {
> + dev_kfree_skb_any(skb);
> + goto out;
> + }
> +
> + entry = priv->cur_tx % priv->num_tx_ring;
> + priv->tx_skb[entry] = skb;
> + desc = &priv->tx_ring[entry];
> + desc->dptr = cpu_to_le32(dma_addr);
> + desc->info_ds = cpu_to_le16(skb->len);
> + desc->info1 = cpu_to_le64(skb->len);
> +
> + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
> + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> + priv->ts_tag++;
> + desc->info_ds |= cpu_to_le16(TXC);
> + desc->info = priv->ts_tag;
> + }
> +
> + skb_tx_timestamp(skb);
> + dma_wmb();
> +
> + desc->die_dt = DT_FSINGLE | D_DIE;
> + priv->cur_tx++;
> +
> + /* Start xmit */
> + rtsn_write(priv, TRCR0, BIT(TX_CHAIN_IDX));
> +out:
> + spin_unlock_irqrestore(&priv->lock, flags);
> + return ret;
> +}
> +
> +static void rtsn_get_stats64(struct net_device *ndev,
> + struct rtnl_link_stats64 *storage)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> + *storage = priv->stats;
> +}
> +
> +static int rtsn_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
> +{
> + if (!netif_running(ndev))
> + return -ENODEV;
> +
> + return phy_do_ioctl_running(ndev, ifr, cmd);
> +}
> +
> +static int rtsn_hwtstamp_get(struct net_device *ndev,
> + struct kernel_hwtstamp_config *config)
> +{
> + struct rcar_gen4_ptp_private *ptp_priv;
> + struct rtsn_private *priv;
> +
> + if (!netif_running(ndev))
> + return -ENODEV;
> +
> + priv = netdev_priv(ndev);
> + ptp_priv = priv->ptp_priv;
> +
> + config->flags = 0;
> +
> + config->tx_type =
> + ptp_priv->tstamp_tx_ctrl ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
> +
> + switch (ptp_priv->tstamp_rx_ctrl & RCAR_GEN4_RXTSTAMP_TYPE) {
> + case RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT:
> + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
> + break;
> + case RCAR_GEN4_RXTSTAMP_TYPE_ALL:
> + config->rx_filter = HWTSTAMP_FILTER_ALL;
> + break;
> + default:
> + config->rx_filter = HWTSTAMP_FILTER_NONE;
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int rtsn_hwtstamp_set(struct net_device *ndev,
> + struct kernel_hwtstamp_config *config,
> + struct netlink_ext_ack *extack)
> +{
> + struct rcar_gen4_ptp_private *ptp_priv;
> + struct rtsn_private *priv;
> + u32 tstamp_rx_ctrl;
> + u32 tstamp_tx_ctrl;
> +
> + if (!netif_running(ndev))
> + return -ENODEV;
> +
> + priv = netdev_priv(ndev);
> + ptp_priv = priv->ptp_priv;
> +
> + if (config->flags)
> + return -EINVAL;
> +
> + switch (config->tx_type) {
> + case HWTSTAMP_TX_OFF:
> + tstamp_tx_ctrl = 0;
> + break;
> + case HWTSTAMP_TX_ON:
> + tstamp_tx_ctrl = RCAR_GEN4_TXTSTAMP_ENABLED;
> + break;
> + default:
> + return -ERANGE;
> + }
> +
> + switch (config->rx_filter) {
> + case HWTSTAMP_FILTER_NONE:
> + tstamp_rx_ctrl = 0;
> + break;
> + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
> + tstamp_rx_ctrl = RCAR_GEN4_RXTSTAMP_ENABLED |
> + RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT;
> + break;
> + default:
> + config->rx_filter = HWTSTAMP_FILTER_ALL;
> + tstamp_rx_ctrl = RCAR_GEN4_RXTSTAMP_ENABLED |
> + RCAR_GEN4_RXTSTAMP_TYPE_ALL;
> + break;
> + }
> +
> + ptp_priv->tstamp_tx_ctrl = tstamp_tx_ctrl;
> + ptp_priv->tstamp_rx_ctrl = tstamp_rx_ctrl;
> +
> + return 0;
> +}
> +
> +static const struct net_device_ops rtsn_netdev_ops = {
> + .ndo_open = rtsn_open,
> + .ndo_stop = rtsn_stop,
> + .ndo_start_xmit = rtsn_start_xmit,
> + .ndo_get_stats64 = rtsn_get_stats64,
> + .ndo_eth_ioctl = rtsn_do_ioctl,
> + .ndo_validate_addr = eth_validate_addr,
> + .ndo_set_mac_address = eth_mac_addr,
> + .ndo_hwtstamp_set = rtsn_hwtstamp_set,
> + .ndo_hwtstamp_get = rtsn_hwtstamp_get,
> +};
> +
> +static int rtsn_get_ts_info(struct net_device *ndev,
> + struct ethtool_ts_info *info)
> +{
> + struct rtsn_private *priv = netdev_priv(ndev);
> +
> + info->phc_index = ptp_clock_index(priv->ptp_priv->clock);
> + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
> + SOF_TIMESTAMPING_RX_SOFTWARE |
> + SOF_TIMESTAMPING_SOFTWARE |
> + SOF_TIMESTAMPING_TX_HARDWARE |
> + SOF_TIMESTAMPING_RX_HARDWARE |
> + SOF_TIMESTAMPING_RAW_HARDWARE;
> + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
> + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
> +
> + return 0;
> +}
> +
> +static const struct ethtool_ops rtsn_ethtool_ops = {
> + .nway_reset = phy_ethtool_nway_reset,
> + .get_link = ethtool_op_get_link,
> + .get_ts_info = rtsn_get_ts_info,
> + .get_link_ksettings = phy_ethtool_get_link_ksettings,
> + .set_link_ksettings = phy_ethtool_set_link_ksettings,
> +};
> +
> +static const struct of_device_id rtsn_match_table[] = {
> + { .compatible = "renesas,r8a779g0-ethertsn", },
> + { /* Sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, rtsn_match_table);
> +
> +static int rtsn_probe(struct platform_device *pdev)
> +{
> + struct rtsn_private *priv;
> + struct net_device *ndev;
> + struct resource *res;
> + int ret;
> +
> + ndev = alloc_etherdev_mqs(sizeof(struct rtsn_private), TX_NUM_CHAINS,
> + RX_NUM_CHAINS);
> + if (!ndev)
> + return -ENOMEM;
> +
> + priv = netdev_priv(ndev);
> + priv->pdev = pdev;
> + priv->ndev = ndev;
> + priv->ptp_priv = rcar_gen4_ptp_alloc(pdev);
> +
> + spin_lock_init(&priv->lock);
> + platform_set_drvdata(pdev, priv);
> +
> + priv->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(priv->clk)) {
> + ret = PTR_ERR(priv->clk);
> + goto error_free;
> + }
> +
> + priv->reset = devm_reset_control_get(&pdev->dev, NULL);
> + if (IS_ERR(priv->reset)) {
> + ret = PTR_ERR(priv->reset);
> + goto error_free;
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tsnes");
> + if (!res) {
> + dev_err(&pdev->dev, "Can't find tsnes resource\n");
> + ret = -EINVAL;
> + goto error_free;
> + }
> +
> + priv->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(priv->base)) {
> + ret = PTR_ERR(priv->base);
> + goto error_free;
> + }
> +
> + SET_NETDEV_DEV(ndev, &pdev->dev);
> +
> + ndev->features = NETIF_F_RXCSUM;
> + ndev->hw_features = NETIF_F_RXCSUM;
> + ndev->base_addr = res->start;
> + ndev->netdev_ops = &rtsn_netdev_ops;
> + ndev->ethtool_ops = &rtsn_ethtool_ops;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gptp");
> + if (!res) {
> + dev_err(&pdev->dev, "Can't find gptp resource\n");
> + ret = -EINVAL;
> + goto error_free;
> + }
> +
> + priv->ptp_priv->addr = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(priv->ptp_priv->addr)) {
> + ret = PTR_ERR(priv->ptp_priv->addr);
> + goto error_free;
> + }
> +
> + ret = rtsn_get_phy_params(priv);
> + if (ret)
> + goto error_free;
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_get_sync(&pdev->dev);
> +
> + netif_napi_add(ndev, &priv->napi, rtsn_poll);
> +
> + rtsn_parse_mac_address(pdev->dev.of_node, ndev);
> +
> + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
> +
> + device_set_wakeup_capable(&pdev->dev, 1);
> +
> + ret = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT,
> + clk_get_rate(priv->clk));
> + if (ret)
> + goto error_pm;
> +
> + ret = rtsn_mdio_alloc(priv);
> + if (ret)
> + goto error_ptp;
> +
> + ret = register_netdev(ndev);
> + if (ret)
> + goto error_mdio;
> +
> + netdev_info(ndev, "MAC address %pM\n", ndev->dev_addr);
> +
> + return 0;
> +
> +error_mdio:
> + rtsn_mdio_free(priv);
> +error_ptp:
> + rcar_gen4_ptp_unregister(priv->ptp_priv);
> +error_pm:
> + netif_napi_del(&priv->napi);
> + rtsn_change_mode(priv, OCR_OPC_DISABLE);
> + pm_runtime_put_sync(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> +error_free:
> + free_netdev(ndev);
> +
> + return ret;
> +}
> +
> +static int rtsn_remove(struct platform_device *pdev)
> +{
> + struct rtsn_private *priv = platform_get_drvdata(pdev);
> +
> + unregister_netdev(priv->ndev);
> + rtsn_mdio_free(priv);
> + rcar_gen4_ptp_unregister(priv->ptp_priv);
> + rtsn_change_mode(priv, OCR_OPC_DISABLE);
> + netif_napi_del(&priv->napi);
> +
> + pm_runtime_put_sync(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> +
> + free_netdev(priv->ndev);
> +
> + return 0;
> +}
> +
> +static struct platform_driver rtsn_driver = {
> + .probe = rtsn_probe,
> + .remove = rtsn_remove,
> + .driver = {
> + .name = "rtsn",
> + .of_match_table = rtsn_match_table,
> + }
> +};
> +module_platform_driver(rtsn_driver);
> +
> +MODULE_AUTHOR("Phong Hoang, Niklas Söderlund");
> +MODULE_DESCRIPTION("Renesas Ethernet-TSN device driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/net/ethernet/renesas/rtsn.h b/drivers/net/ethernet/renesas/rtsn.h
> new file mode 100644
> index 000000000000..3183e80d7e6b
> --- /dev/null
> +++ b/drivers/net/ethernet/renesas/rtsn.h
> @@ -0,0 +1,464 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/* Renesas Ethernet-TSN device driver
> + *
> + * Copyright (C) 2022 Renesas Electronics Corporation
> + * Copyright (C) 2023 Niklas Söderlund <niklas.soderlund@...natech.se>
> + */
> +
> +#ifndef __RTSN_H__
> +#define __RTSN_H__
> +
> +#include <linux/types.h>
> +
> +#define AXIBMI 0x0000
> +#define TSNMHD 0x1000
> +#define RMSO 0x2000
> +#define RMRO 0x3800
> +
> +enum rtsn_reg {
> + AXIWC = AXIBMI + 0x0000,
> + AXIRC = AXIBMI + 0x0004,
> + TDPC0 = AXIBMI + 0x0010,
> + TFT = AXIBMI + 0x0090,
> + TATLS0 = AXIBMI + 0x00a0,
> + TATLS1 = AXIBMI + 0x00a4,
> + TATLR = AXIBMI + 0x00a8,
> + RATLS0 = AXIBMI + 0x00b0,
> + RATLS1 = AXIBMI + 0x00b4,
> + RATLR = AXIBMI + 0x00b8,
> + TSA0 = AXIBMI + 0x00c0,
> + TSS0 = AXIBMI + 0x00c4,
> + TRCR0 = AXIBMI + 0x0140,
> + RIDAUAS0 = AXIBMI + 0x0180,
> + RR = AXIBMI + 0x0200,
> + TATS = AXIBMI + 0x0210,
> + TATSR0 = AXIBMI + 0x0214,
> + TATSR1 = AXIBMI + 0x0218,
> + TATSR2 = AXIBMI + 0x021c,
> + RATS = AXIBMI + 0x0220,
> + RATSR0 = AXIBMI + 0x0224,
> + RATSR1 = AXIBMI + 0x0228,
> + RATSR2 = AXIBMI + 0x022c,
> + RIDASM0 = AXIBMI + 0x0240,
> + RIDASAM0 = AXIBMI + 0x0244,
> + RIDACAM0 = AXIBMI + 0x0248,
> + EIS0 = AXIBMI + 0x0300,
> + EIE0 = AXIBMI + 0x0304,
> + EID0 = AXIBMI + 0x0308,
> + EIS1 = AXIBMI + 0x0310,
> + EIE1 = AXIBMI + 0x0314,
> + EID1 = AXIBMI + 0x0318,
> + TCEIS0 = AXIBMI + 0x0340,
> + TCEIE0 = AXIBMI + 0x0344,
> + TCEID0 = AXIBMI + 0x0348,
> + RFSEIS0 = AXIBMI + 0x04c0,
> + RFSEIE0 = AXIBMI + 0x04c4,
> + RFSEID0 = AXIBMI + 0x04c8,
> + RFEIS0 = AXIBMI + 0x0540,
> + RFEIE0 = AXIBMI + 0x0544,
> + RFEID0 = AXIBMI + 0x0548,
> + RCEIS0 = AXIBMI + 0x05c0,
> + RCEIE0 = AXIBMI + 0x05c4,
> + RCEID0 = AXIBMI + 0x05c8,
> + RIDAOIS = AXIBMI + 0x0640,
> + RIDAOIE = AXIBMI + 0x0644,
> + RIDAOID = AXIBMI + 0x0648,
> + TSFEIS = AXIBMI + 0x06c0,
> + TSFEIE = AXIBMI + 0x06c4,
> + TSFEID = AXIBMI + 0x06c8,
> + TSCEIS = AXIBMI + 0x06d0,
> + TSCEIE = AXIBMI + 0x06d4,
> + TSCEID = AXIBMI + 0x06d8,
> + DIS = AXIBMI + 0x0b00,
> + DIE = AXIBMI + 0x0b04,
> + DID = AXIBMI + 0x0b08,
> + TDIS0 = AXIBMI + 0x0b10,
> + TDIE0 = AXIBMI + 0x0b14,
> + TDID0 = AXIBMI + 0x0b18,
> + RDIS0 = AXIBMI + 0x0b90,
> + RDIE0 = AXIBMI + 0x0b94,
> + RDID0 = AXIBMI + 0x0b98,
> + TSDIS = AXIBMI + 0x0c10,
> + TSDIE = AXIBMI + 0x0c14,
> + TSDID = AXIBMI + 0x0c18,
> + GPOUT = AXIBMI + 0x6000,
> +
> + OCR = TSNMHD + 0x0000,
> + OSR = TSNMHD + 0x0004,
> + SWR = TSNMHD + 0x0008,
> + SIS = TSNMHD + 0x000c,
> + GIS = TSNMHD + 0x0010,
> + GIE = TSNMHD + 0x0014,
> + GID = TSNMHD + 0x0018,
> + TIS1 = TSNMHD + 0x0020,
> + TIE1 = TSNMHD + 0x0024,
> + TID1 = TSNMHD + 0x0028,
> + TIS2 = TSNMHD + 0x0030,
> + TIE2 = TSNMHD + 0x0034,
> + TID2 = TSNMHD + 0x0038,
> + RIS = TSNMHD + 0x0040,
> + RIE = TSNMHD + 0x0044,
> + RID = TSNMHD + 0x0048,
> + TGC1 = TSNMHD + 0x0050,
> + TGC2 = TSNMHD + 0x0054,
> + TFS0 = TSNMHD + 0x0060,
> + TCF0 = TSNMHD + 0x0070,
> + TCR1 = TSNMHD + 0x0080,
> + TCR2 = TSNMHD + 0x0084,
> + TCR3 = TSNMHD + 0x0088,
> + TCR4 = TSNMHD + 0x008c,
> + TMS0 = TSNMHD + 0x0090,
> + TSR1 = TSNMHD + 0x00b0,
> + TSR2 = TSNMHD + 0x00b4,
> + TSR3 = TSNMHD + 0x00b8,
> + TSR4 = TSNMHD + 0x00bc,
> + TSR5 = TSNMHD + 0x00c0,
> + RGC = TSNMHD + 0x00d0,
> + RDFCR = TSNMHD + 0x00d4,
> + RCFCR = TSNMHD + 0x00d8,
> + REFCNCR = TSNMHD + 0x00dc,
> + RSR1 = TSNMHD + 0x00e0,
> + RSR2 = TSNMHD + 0x00e4,
> + RSR3 = TSNMHD + 0x00e8,
> + TCIS = TSNMHD + 0x01e0,
> + TCIE = TSNMHD + 0x01e4,
> + TCID = TSNMHD + 0x01e8,
> + TPTPC = TSNMHD + 0x01f0,
> + TTML = TSNMHD + 0x01f4,
> + TTJ = TSNMHD + 0x01f8,
> + TCC = TSNMHD + 0x0200,
> + TCS = TSNMHD + 0x0204,
> + TGS = TSNMHD + 0x020c,
> + TACST0 = TSNMHD + 0x0210,
> + TACST1 = TSNMHD + 0x0214,
> + TACST2 = TSNMHD + 0x0218,
> + TALIT0 = TSNMHD + 0x0220,
> + TALIT1 = TSNMHD + 0x0224,
> + TALIT2 = TSNMHD + 0x0228,
> + TAEN0 = TSNMHD + 0x0230,
> + TAEN1 = TSNMHD + 0x0234,
> + TASFE = TSNMHD + 0x0240,
> + TACLL0 = TSNMHD + 0x0250,
> + TACLL1 = TSNMHD + 0x0254,
> + TACLL2 = TSNMHD + 0x0258,
> + CACC = TSNMHD + 0x0260,
> + CCS = TSNMHD + 0x0264,
> + CAIV0 = TSNMHD + 0x0270,
> + CAUL0 = TSNMHD + 0x0290,
> + TOCST0 = TSNMHD + 0x0300,
> + TOCST1 = TSNMHD + 0x0304,
> + TOCST2 = TSNMHD + 0x0308,
> + TOLIT0 = TSNMHD + 0x0310,
> + TOLIT1 = TSNMHD + 0x0314,
> + TOLIT2 = TSNMHD + 0x0318,
> + TOEN0 = TSNMHD + 0x0320,
> + TOEN1 = TSNMHD + 0x0324,
> + TOSFE = TSNMHD + 0x0330,
> + TCLR0 = TSNMHD + 0x0340,
> + TCLR1 = TSNMHD + 0x0344,
> + TCLR2 = TSNMHD + 0x0348,
> + TSMS = TSNMHD + 0x0350,
> + COCC = TSNMHD + 0x0360,
> + COIV0 = TSNMHD + 0x03b0,
> + COUL0 = TSNMHD + 0x03d0,
> + QSTMACU0 = TSNMHD + 0x0400,
> + QSTMACD0 = TSNMHD + 0x0404,
> + QSTMAMU0 = TSNMHD + 0x0408,
> + QSTMAMD0 = TSNMHD + 0x040c,
> + QSFTVL0 = TSNMHD + 0x0410,
> + QSFTVLM0 = TSNMHD + 0x0414,
> + QSFTMSD0 = TSNMHD + 0x0418,
> + QSFTGMI0 = TSNMHD + 0x041c,
> + QSFTLS = TSNMHD + 0x0600,
> + QSFTLIS = TSNMHD + 0x0604,
> + QSFTLIE = TSNMHD + 0x0608,
> + QSFTLID = TSNMHD + 0x060c,
> + QSMSMC = TSNMHD + 0x0610,
> + QSGTMC = TSNMHD + 0x0614,
> + QSEIS = TSNMHD + 0x0618,
> + QSEIE = TSNMHD + 0x061c,
> + QSEID = TSNMHD + 0x0620,
> + QGACST0 = TSNMHD + 0x0630,
> + QGACST1 = TSNMHD + 0x0634,
> + QGACST2 = TSNMHD + 0x0638,
> + QGALIT1 = TSNMHD + 0x0640,
> + QGALIT2 = TSNMHD + 0x0644,
> + QGAEN0 = TSNMHD + 0x0648,
> + QGAEN1 = TSNMHD + 0x074c,
> + QGIGS = TSNMHD + 0x0650,
> + QGGC = TSNMHD + 0x0654,
> + QGATL0 = TSNMHD + 0x0664,
> + QGATL1 = TSNMHD + 0x0668,
> + QGATL2 = TSNMHD + 0x066c,
> + QGOCST0 = TSNMHD + 0x0670,
> + QGOCST1 = TSNMHD + 0x0674,
> + QGOCST2 = TSNMHD + 0x0678,
> + QGOLIT0 = TSNMHD + 0x067c,
> + QGOLIT1 = TSNMHD + 0x0680,
> + QGOLIT2 = TSNMHD + 0x0684,
> + QGOEN0 = TSNMHD + 0x0688,
> + QGOEN1 = TSNMHD + 0x068c,
> + QGTRO = TSNMHD + 0x0690,
> + QGTR1 = TSNMHD + 0x0694,
> + QGTR2 = TSNMHD + 0x0698,
> + QGFSMS = TSNMHD + 0x069c,
> + QTMIS = TSNMHD + 0x06e0,
> + QTMIE = TSNMHD + 0x06e4,
> + QTMID = TSNMHD + 0x06e8,
> + QMEC = TSNMHD + 0x0700,
> + QMMC = TSNMHD + 0x0704,
> + QRFDC = TSNMHD + 0x0708,
> + QYFDC = TSNMHD + 0x070c,
> + QVTCMC0 = TSNMHD + 0x0710,
> + QMCBSC0 = TSNMHD + 0x0750,
> + QMCIRC0 = TSNMHD + 0x0790,
> + QMEBSC0 = TSNMHD + 0x07d0,
> + QMEIRC0 = TSNMHD + 0x0710,
> + QMCFC = TSNMHD + 0x0850,
> + QMEIS = TSNMHD + 0x0860,
> + QMEIE = TSNMHD + 0x0864,
> + QMEID = TSNMHD + 0x086c,
> + QSMFC0 = TSNMHD + 0x0870,
> + QMSPPC0 = TSNMHD + 0x08b0,
> + QMSRPC0 = TSNMHD + 0x08f0,
> + QGPPC0 = TSNMHD + 0x0930,
> + QGRPC0 = TSNMHD + 0x0950,
> + QMDPC0 = TSNMHD + 0x0970,
> + QMGPC0 = TSNMHD + 0x09b0,
> + QMYPC0 = TSNMHD + 0x09f0,
> + QMRPC0 = TSNMHD + 0x0a30,
> + MQSTMACU = TSNMHD + 0x0a70,
> + MQSTMACD = TSNMHD + 0x0a74,
> + MQSTMAMU = TSNMHD + 0x0a78,
> + MQSTMAMD = TSNMHD + 0x0a7c,
> + MQSFTVL = TSNMHD + 0x0a80,
> + MQSFTVLM = TSNMHD + 0x0a84,
> + MQSFTMSD = TSNMHD + 0x0a88,
> + MQSFTGMI = TSNMHD + 0x0a8c,
> +
> + CFCR0 = RMSO + 0x0800,
> + FMSCR = RMSO + 0x0c10,
> +
> + MMC = RMRO + 0x0000,
> + MPSM = RMRO + 0x0010,
> + MPIC = RMRO + 0x0014,
> + MTFFC = RMRO + 0x0020,
> + MTPFC = RMRO + 0x0024,
> + MTATC0 = RMRO + 0x0040,
> + MRGC = RMRO + 0x0080,
> + MRMAC0 = RMRO + 0x0084,
> + MRMAC1 = RMRO + 0x0088,
> + MRAFC = RMRO + 0x008c,
> + MRSCE = RMRO + 0x0090,
> + MRSCP = RMRO + 0x0094,
> + MRSCC = RMRO + 0x0098,
> + MRFSCE = RMRO + 0x009c,
> + MRFSCP = RMRO + 0x00a0,
> + MTRC = RMRO + 0x00a4,
> + MPFC = RMRO + 0x0100,
> + MLVC = RMRO + 0x0340,
> + MEEEC = RMRO + 0x0350,
> + MLBC = RMRO + 0x0360,
> + MGMR = RMRO + 0x0400,
> + MMPFTCT = RMRO + 0x0410,
> + MAPFTCT = RMRO + 0x0414,
> + MPFRCT = RMRO + 0x0418,
> + MFCICT = RMRO + 0x041c,
> + MEEECT = RMRO + 0x0420,
> + MEIS = RMRO + 0x0500,
> + MEIE = RMRO + 0x0504,
> + MEID = RMRO + 0x0508,
> + MMIS0 = RMRO + 0x0510,
> + MMIE0 = RMRO + 0x0514,
> + MMID0 = RMRO + 0x0518,
> + MMIS1 = RMRO + 0x0520,
> + MMIE1 = RMRO + 0x0524,
> + MMID1 = RMRO + 0x0528,
> + MMIS2 = RMRO + 0x0530,
> + MMIE2 = RMRO + 0x0534,
> + MMID2 = RMRO + 0x0538,
> + MXMS = RMRO + 0x0600,
> +
> +};
> +
> +/* AXIBMI */
> +#define RR_RATRR BIT(0)
> +#define RR_TATRR BIT(1)
> +#define RR_RST (RR_RATRR | RR_TATRR)
> +#define RR_RST_COMPLETE 0x03
> +
> +#define AXIWC_DEFAULT 0xffff
> +#define AXIRC_DEFAULT 0xffff
> +
> +#define TATLS0_TEDE BIT(1)
> +#define TATLS0_TATEN_SHIFT 24
> +#define TATLS0_TATEN(n) ((n) << TATLS0_TATEN_SHIFT)
> +#define TATLR_TATL BIT(31)
> +
> +#define RATLS0_RETS BIT(2)
> +#define RATLS0_REDE BIT(3)
> +#define RATLS0_RATEN_SHIFT 24
> +#define RATLS0_RATEN(n) ((n) << RATLS0_RATEN_SHIFT)
> +#define RATLR_RATL BIT(31)
> +
> +#define DIE_DID_TDICX(n) BIT((n))
> +#define DIE_DID_RDICX(n) BIT((n) + 8)
> +#define TDIE_TDID_TDX(n) BIT(n)
> +#define RDIE_RDID_RDX(n) BIT(n)
> +#define TDIS_TDS(n) BIT(n)
> +#define RDIS_RDS(n) BIT(n)
> +
> +/* MHD */
> +#define OSR_OPS 0x07
> +#define SWR_SWR BIT(0)
> +
> +#define TGC1_TQTM_SFM 0xff00
> +#define TGC1_STTV_DEFAULT 0x03
> +
> +#define TMS_MFS_MAX 0x2800
> +
> +/* RMAC System */
> +#define CFCR_SDID(n) ((n) << 16)
> +#define FMSCR_FMSIE(n) ((n) << 0)
> +
> +/* RMAC */
> +#define MPIC_PIS_MASK GENMASK(1, 0)
> +#define MPIC_PIS_MII 0
> +#define MPIC_PIS_RMII 0x01
> +#define MPIC_PIS_GMII 0x02
> +#define MPIC_PIS_RGMII 0x03
> +#define MPIC_LSC_SHIFT 2
> +#define MPIC_LSC_MASK GENMASK(3, MPIC_LSC_SHIFT)
> +#define MPIC_LSC_10M (0 << MPIC_LSC_SHIFT)
> +#define MPIC_LSC_100M (0x01 << MPIC_LSC_SHIFT)
> +#define MPIC_LSC_1G (0x02 << MPIC_LSC_SHIFT)
> +#define MPIC_PSMCS_SHIFT 16
> +#define MPIC_PSMCS_MASK GENMASK(21, MPIC_PSMCS_SHIFT)
> +#define MPIC_PSMCS_DEFAULT (0x0a << MPIC_PSMCS_SHIFT)
> +#define MPIC_PSMHT_SHIFT 24
> +#define MPIC_PSMHT_MASK GENMASK(26, MPIC_PSMHT_SHIFT)
> +#define MPIC_PSMHT_DEFAULT (0x07 << MPIC_PSMHT_SHIFT)
> +
> +#define MLVC_PASE BIT(8)
> +#define MLVC_PSE BIT(16)
> +#define MLVC_PLV BIT(17)
> +
> +#define MPSM_PSME BIT(0)
> +#define MPSM_PSMAD BIT(1)
> +#define MPSM_PDA_SHIFT 3
> +#define MPSM_PDA_MASK GENMASK(7, 3)
> +#define MPSM_PDA(n) (((n) << MPSM_PDA_SHIFT) & MPSM_PDA_MASK)
> +#define MPSM_PRA_SHIFT 8
> +#define MPSM_PRA_MASK GENMASK(12, 8)
> +#define MPSM_PRA(n) (((n) << MPSM_PRA_SHIFT) & MPSM_PRA_MASK)
> +#define MPSM_PRD_SHIFT 16
> +#define MPSM_PRD_SET(n) ((n) << MPSM_PRD_SHIFT)
> +#define MPSM_PRD_GET(n) ((n) >> MPSM_PRD_SHIFT)
> +
> +#define GPOUT_RDM BIT(13)
> +#define GPOUT_TDM BIT(14)
> +
> +/* RTSN */
> +#define RTSN_INTERVAL_US 1000
> +#define RTSN_TIMEOUT_US 1000000
> +
> +#define TX_NUM_CHAINS 1
> +#define RX_NUM_CHAINS 1
> +
> +#define TX_CHAIN_SIZE 1024
> +#define RX_CHAIN_SIZE 1024
> +
> +#define TX_CHAIN_IDX 0
> +#define RX_CHAIN_IDX 0
> +
> +#define TX_CHAIN_ADDR_OFFSET (sizeof(struct rtsn_desc) * TX_CHAIN_IDX)
> +#define RX_CHAIN_ADDR_OFFSET (sizeof(struct rtsn_desc) * RX_CHAIN_IDX)
> +
> +#define PKT_BUF_SZ 1584
> +#define RTSN_ALIGN 128
> +
> +enum rtsn_mode {
> + OCR_OPC_DISABLE,
> + OCR_OPC_CONFIG,
> + OCR_OPC_OPERATION,
> +};
> +
> +/* Descriptors */
> +enum RX_DS_CC_BIT {
> + RX_DS = 0x0fff, /* Data size */
> + RX_TR = 0x1000, /* Truncation indication */
> + RX_EI = 0x2000, /* Error indication */
> + RX_PS = 0xc000, /* Padding selection */
> +};
> +
> +enum TX_FS_TAGL_BIT {
> + TX_DS = 0x0fff, /* Data size */
> + TX_TAGL = 0xf000, /* Frame tag LSBs */
> +};
> +
> +enum DIE_DT {
> + /* HW/SW arbitration */
> + DT_FEMPTY_IS = 0x10,
> + DT_FEMPTY_IC = 0x20,
> + DT_FEMPTY_ND = 0x30,
> + DT_FEMPTY = 0x40,
> + DT_FEMPTY_START = 0x50,
> + DT_FEMPTY_MID = 0x60,
> + DT_FEMPTY_END = 0x70,
> +
> + /* Frame data */
> + DT_FSINGLE = 0x80,
> + DT_FSTART = 0x90,
> + DT_FMID = 0xa0,
> + DT_FEND = 0xb0,
> +
> + /* Chain control */
> + DT_LEMPTY = 0xc0,
> + DT_EEMPTY = 0xd0,
> + DT_LINK = 0xe0,
> + DT_EOS = 0xf0,
> +
> + DT_MASK = 0xf0,
> + D_DIE = 0x08,
> +};
> +
> +struct rtsn_desc {
> + __le16 info_ds;
> + __u8 info;
> + u8 die_dt;
> + __le32 dptr;
> +} __packed;
> +
> +struct rtsn_ts_desc {
> + __le16 info_ds;
> + __u8 info;
> + u8 die_dt;
> + __le32 dptr;
> + __le32 ts_nsec;
> + __le32 ts_sec;
> +} __packed;
> +
> +struct rtsn_ext_desc {
> + __le16 info_ds;
> + __u8 info;
> + u8 die_dt;
> + __le32 dptr;
> + __le64 info1;
> +} __packed;
> +
> +struct rtsn_ext_ts_desc {
> + __le16 info_ds;
> + __u8 info;
> + u8 die_dt;
> + __le32 dptr;
> + __le64 info1;
> + __le32 ts_nsec;
> + __le32 ts_sec;
> +} __packed;
> +
> +enum EXT_INFO_DS_BIT {
> + TXC = 0x4000,
> +};
> +
> +#endif
> --
> 2.45.2
>
Powered by blists - more mailing lists