drivers/net/mdio/mdio-aspeed.c

Source file repositories/reference/linux-study-clean/drivers/net/mdio/mdio-aspeed.c

File Facts

System
Linux kernel
Corpus path
drivers/net/mdio/mdio-aspeed.c
Extension
.c
Size
5716 bytes
Lines
216
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

struct aspeed_mdio {
	void __iomem *base;
	struct reset_control *reset;
};

static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad,
			  u16 data)
{
	struct aspeed_mdio *ctx = bus->priv;
	u32 ctrl;

	dev_dbg(&bus->dev, "%s: st: %u op: %u, phyad: %u, regad: %u, data: %u\n",
		__func__, st, op, phyad, regad, data);

	ctrl = ASPEED_MDIO_CTRL_FIRE
		| FIELD_PREP(ASPEED_MDIO_CTRL_ST, st)
		| FIELD_PREP(ASPEED_MDIO_CTRL_OP, op)
		| FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, phyad)
		| FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regad)
		| FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data);

	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);

	/* Workaround for read-after-write issue.
	 * The controller may return stale data if a read follows immediately
	 * after a write. A dummy read forces the hardware to update its
	 * internal state, ensuring that the next real read returns correct data.
	 */
	ioread32(ctx->base + ASPEED_MDIO_CTRL);

	return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
				!(ctrl & ASPEED_MDIO_CTRL_FIRE),
				ASPEED_MDIO_INTERVAL_US,
				ASPEED_MDIO_TIMEOUT_US);
}

static int aspeed_mdio_get_data(struct mii_bus *bus)
{
	struct aspeed_mdio *ctx = bus->priv;
	u32 data;
	int rc;

	rc = readl_poll_timeout(ctx->base + ASPEED_MDIO_DATA, data,
				data & ASPEED_MDIO_DATA_IDLE,
				ASPEED_MDIO_INTERVAL_US,
				ASPEED_MDIO_TIMEOUT_US);
	if (rc < 0)
		return rc;

	return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
}

static int aspeed_mdio_read_c22(struct mii_bus *bus, int addr, int regnum)
{
	int rc;

	rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C22, MDIO_C22_OP_READ,
			    addr, regnum, 0);
	if (rc < 0)
		return rc;

	return aspeed_mdio_get_data(bus);
}

static int aspeed_mdio_write_c22(struct mii_bus *bus, int addr, int regnum,
				 u16 val)
{
	return aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C22, MDIO_C22_OP_WRITE,
			      addr, regnum, val);
}

static int aspeed_mdio_read_c45(struct mii_bus *bus, int addr, int devad,
				int regnum)
{
	int rc;

	rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_ADDR,
			    addr, devad, regnum);
	if (rc < 0)
		return rc;

	rc = aspeed_mdio_op(bus, ASPEED_MDIO_CTRL_ST_C45, MDIO_C45_OP_READ,
			    addr, devad, 0);
	if (rc < 0)
		return rc;

	return aspeed_mdio_get_data(bus);
}

static int aspeed_mdio_write_c45(struct mii_bus *bus, int addr, int devad,

Annotation

Implementation Notes