Re: [net-next,v9] net: ethernet: rtsn: Add support for Renesas Ethernet-TSN

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2024-06-18 at 14:38:24, Niklas Söderlund (niklas.soderlund+renesas@xxxxxxxxxxxx) 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@xxxxxxxxxxxx>
> ---
> +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@xxxxxxxxxxxx>
> + */
> +
> +#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
>




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux