drivers/phy/renesas/r8a779f0-ether-serdes.c

Source file repositories/reference/linux-study-clean/drivers/phy/renesas/r8a779f0-ether-serdes.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/renesas/r8a779f0-ether-serdes.c
Extension
.c
Size
14987 bytes
Lines
490
Domain
Driver Families
Bucket
drivers/phy
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 r8a779f0_eth_serdes_channel {
	struct r8a779f0_eth_serdes_drv_data *dd;
	struct phy *phy;
	void __iomem *addr;
	phy_interface_t phy_interface;
	int speed;
	int index;
};

struct r8a779f0_eth_serdes_drv_data {
	void __iomem *addr;
	struct platform_device *pdev;
	struct reset_control *reset;
	struct r8a779f0_eth_serdes_channel channel[R8A779F0_ETH_SERDES_NUM];
	bool initialized;
};

/*
 * The datasheet describes initialization procedure without any information
 * about registers' name/bits. So, this is all black magic to initialize
 * the hardware.
 */
static void r8a779f0_eth_serdes_write32(void __iomem *addr, u32 offs, u32 bank, u32 data)
{
	iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT);
	iowrite32(data, addr + offs);
}

static u32 r8a779f0_eth_serdes_read32(void __iomem *addr, u32 offs,  u32 bank)
{
	iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT);

	return ioread32(addr + offs);
}

static int
r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel *channel,
			     u32 offs, u32 bank, u32 mask, u32 expected)
{
	int ret;
	u32 val;

	iowrite32(bank, channel->addr + R8A779F0_ETH_SERDES_BANK_SELECT);

	ret = readl_poll_timeout_atomic(channel->addr + offs, val,
					(val & mask) == expected,
					1, R8A779F0_ETH_SERDES_TIMEOUT_US);
	if (ret)
		dev_dbg(&channel->phy->dev,
			"%s: index %d, offs %x, bank %x, mask %x, expected %x\n",
			 __func__, channel->index, offs, bank, mask, expected);

	return ret;
}

static int
r8a779f0_eth_serdes_common_init_ram(struct r8a779f0_eth_serdes_drv_data *dd)
{
	struct r8a779f0_eth_serdes_channel *channel;
	int i, ret;

	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
		channel = &dd->channel[i];
		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01);
		if (ret)
			return ret;
	}

	r8a779f0_eth_serdes_write32(dd->addr, 0x026c, 0x180, 0x03);

	return ret;
}

static int
r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel *channel)
{
	struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;

	/* Set combination mode */
	r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x00d7);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01cc, 0x180, 0xc200);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01c4, 0x180, 0x0042);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01c8, 0x180, 0x0000);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01dc, 0x180, 0x002f);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000);
	r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d);

	return 0;

Annotation

Implementation Notes