drivers/net/ethernet/spacemit/k1_emac.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/spacemit/k1_emac.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/spacemit/k1_emac.c
Extension
.c
Size
51949 bytes
Lines
2087
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops emac_netdev_ops = {
	.ndo_open               = emac_open,
	.ndo_stop               = emac_stop,
	.ndo_start_xmit         = emac_start_xmit,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address    = emac_set_mac_address,
	.ndo_eth_ioctl          = phy_do_ioctl_running,
	.ndo_change_mtu         = emac_change_mtu,
	.ndo_tx_timeout         = emac_tx_timeout,
	.ndo_set_rx_mode        = emac_set_rx_mode,
	.ndo_get_stats64	= emac_get_stats64,
};

/* Currently we always use 15.6 ps/step for the delay line */

static u32 delay_ps_to_unit(u32 ps)
{
	return DIV_ROUND_CLOSEST(ps * 10, 156);
}

static u32 delay_unit_to_ps(u32 unit)
{
	return DIV_ROUND_CLOSEST(unit * 156, 10);
}

#define EMAC_MAX_DELAY_UNIT	FIELD_MAX(EMAC_TX_DLINE_CODE_MASK)

/* Minus one just to be safe from rounding errors */
#define EMAC_MAX_DELAY_PS	(delay_unit_to_ps(EMAC_MAX_DELAY_UNIT - 1))

static int emac_config_dt(struct platform_device *pdev, struct emac_priv *priv)
{
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	u8 mac_addr[ETH_ALEN] = { 0 };
	int ret;

	priv->iobase = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(priv->iobase))
		return dev_err_probe(dev, PTR_ERR(priv->iobase),
				     "ioremap failed\n");

	priv->regmap_apmu =
		syscon_regmap_lookup_by_phandle_args(np, "spacemit,apmu", 1,
						     &priv->regmap_apmu_offset);

	if (IS_ERR(priv->regmap_apmu))
		return dev_err_probe(dev, PTR_ERR(priv->regmap_apmu),
				     "failed to get syscon\n");

	priv->irq = platform_get_irq(pdev, 0);
	if (priv->irq < 0)
		return priv->irq;

	ret = of_get_mac_address(np, mac_addr);
	if (ret) {
		if (ret == -EPROBE_DEFER)
			return dev_err_probe(dev, ret,
					     "Can't get MAC address\n");

		dev_info(&pdev->dev, "Using random MAC address\n");
		eth_hw_addr_random(priv->ndev);
	} else {
		eth_hw_addr_set(priv->ndev, mac_addr);
	}

	priv->tx_delay = 0;
	priv->rx_delay = 0;

	of_property_read_u32(np, "tx-internal-delay-ps", &priv->tx_delay);
	of_property_read_u32(np, "rx-internal-delay-ps", &priv->rx_delay);

	if (priv->tx_delay > EMAC_MAX_DELAY_PS) {
		dev_err(&pdev->dev,
			"tx-internal-delay-ps too large: max %d, got %d",
			EMAC_MAX_DELAY_PS, priv->tx_delay);
		return -EINVAL;
	}

	if (priv->rx_delay > EMAC_MAX_DELAY_PS) {
		dev_err(&pdev->dev,
			"rx-internal-delay-ps too large: max %d, got %d",
			EMAC_MAX_DELAY_PS, priv->rx_delay);
		return -EINVAL;
	}

	priv->tx_delay = delay_ps_to_unit(priv->tx_delay);
	priv->rx_delay = delay_ps_to_unit(priv->rx_delay);

	return 0;

Annotation

Implementation Notes