drivers/phy/phy-xgene.c

Source file repositories/reference/linux-study-clean/drivers/phy/phy-xgene.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/phy-xgene.c
Extension
.c
Size
60598 bytes
Lines
1724
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 xgene_sata_override_param {
	u32 speed[MAX_LANE]; /* Index for override parameter per lane */
	u32 txspeed[3];			/* Tx speed */
	u32 txboostgain[MAX_LANE*3];	/* Tx freq boost and gain control */
	u32 txeyetuning[MAX_LANE*3];	/* Tx eye tuning */
	u32 txeyedirection[MAX_LANE*3]; /* Tx eye tuning direction */
	u32 txamplitude[MAX_LANE*3];	/* Tx amplitude control */
	u32 txprecursor_cn1[MAX_LANE*3]; /* Tx emphasis taps 1st pre-cursor */
	u32 txprecursor_cn2[MAX_LANE*3]; /* Tx emphasis taps 2nd pre-cursor */
	u32 txpostcursor_cp1[MAX_LANE*3]; /* Tx emphasis taps post-cursor */
};

struct xgene_phy_ctx {
	struct device *dev;
	struct phy *phy;
	enum xgene_phy_mode mode;		/* Mode of operation */
	enum clk_type_t clk_type;	/* Input clock selection */
	void __iomem *sds_base;		/* PHY CSR base addr */
	struct clk *clk;		/* Optional clock */

	/* Override Serdes parameters */
	struct xgene_sata_override_param sata_param;
};

/*
 * For chip earlier than A3 version, enable this flag.
 * To enable, pass boot argument phy_xgene.preA3Chip=1
 */
static int preA3Chip;
MODULE_PARM_DESC(preA3Chip, "Enable pre-A3 chip support (1=enable 0=disable)");
module_param_named(preA3Chip, preA3Chip, int, 0444);

static void sds_wr(void __iomem *csr_base, u32 indirect_cmd_reg,
		   u32 indirect_data_reg, u32 addr, u32 data)
{
	unsigned long deadline = jiffies + HZ;
	u32 val;
	u32 cmd;

	cmd = CFG_IND_WR_CMD_MASK | CFG_IND_CMD_DONE_MASK;
	cmd = CFG_IND_ADDR_SET(cmd, addr);
	writel(data, csr_base + indirect_data_reg);
	readl(csr_base + indirect_data_reg); /* Force a barrier */
	writel(cmd, csr_base + indirect_cmd_reg);
	readl(csr_base + indirect_cmd_reg); /* Force a barrier */
	do {
		val = readl(csr_base + indirect_cmd_reg);
	} while (!(val & CFG_IND_CMD_DONE_MASK) &&
		 time_before(jiffies, deadline));
	if (!(val & CFG_IND_CMD_DONE_MASK))
		pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
		       csr_base + indirect_cmd_reg, addr, data);
}

static void sds_rd(void __iomem *csr_base, u32 indirect_cmd_reg,
		   u32 indirect_data_reg, u32 addr, u32 *data)
{
	unsigned long deadline = jiffies + HZ;
	u32 val;
	u32 cmd;

	cmd = CFG_IND_RD_CMD_MASK | CFG_IND_CMD_DONE_MASK;
	cmd = CFG_IND_ADDR_SET(cmd, addr);
	writel(cmd, csr_base + indirect_cmd_reg);
	readl(csr_base + indirect_cmd_reg); /* Force a barrier */
	do {
		val = readl(csr_base + indirect_cmd_reg);
	} while (!(val & CFG_IND_CMD_DONE_MASK) &&
		 time_before(jiffies, deadline));
	*data = readl(csr_base + indirect_data_reg);
	if (!(val & CFG_IND_CMD_DONE_MASK))
		pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
		       csr_base + indirect_cmd_reg, addr, *data);
}

static void cmu_wr(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
		   u32 reg, u32 data)
{
	void __iomem *sds_base = ctx->sds_base;
	u32 val;

	if (cmu_type == REF_CMU)
		reg += SERDES_PLL_REF_INDIRECT_OFFSET;
	else
		reg += SERDES_PLL_INDIRECT_OFFSET;
	sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
		SATA_ENET_SDS_IND_WDATA_REG, reg, data);
	sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
		SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
	pr_debug("CMU WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data, val);

Annotation

Implementation Notes