drivers/peci/controller/peci-aspeed.c

Source file repositories/reference/linux-study-clean/drivers/peci/controller/peci-aspeed.c

File Facts

System
Linux kernel
Corpus path
drivers/peci/controller/peci-aspeed.c
Extension
.c
Size
17781 bytes
Lines
603
Domain
Driver Families
Bucket
drivers/peci
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_peci {
	struct peci_controller *controller;
	struct device *dev;
	void __iomem *base;
	struct reset_control *rst;
	int irq;
	spinlock_t lock; /* to sync completion status handling */
	struct completion xfer_complete;
	struct clk *clk;
	u32 clk_frequency;
	u32 status;
	u32 cmd_timeout_ms;
};

struct clk_aspeed_peci {
	struct clk_hw hw;
	struct aspeed_peci *aspeed_peci;
};

static void aspeed_peci_controller_enable(struct aspeed_peci *priv)
{
	u32 val = readl(priv->base + ASPEED_PECI_CTRL);

	val |= ASPEED_PECI_CTRL_PECI_CLK_EN;
	val |= ASPEED_PECI_CTRL_PECI_EN;

	writel(val, priv->base + ASPEED_PECI_CTRL);
}

static void aspeed_peci_init_regs(struct aspeed_peci *priv)
{
	u32 val;

	/* Clear interrupts */
	writel(ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_STS);

	/* Set timing negotiation mode and enable interrupts */
	val = FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO);
	val |= ASPEED_PECI_INT_MASK;
	writel(val, priv->base + ASPEED_PECI_INT_CTRL);

	val = FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT);
	writel(val, priv->base + ASPEED_PECI_CTRL);
}

static int aspeed_peci_check_idle(struct aspeed_peci *priv)
{
	u32 cmd_sts = readl(priv->base + ASPEED_PECI_CMD);
	int ret;

	/*
	 * Under normal circumstances, we expect to be idle here.
	 * In case there were any errors/timeouts that led to the situation
	 * where the hardware is not in idle state - we need to reset and
	 * reinitialize it to avoid potential controller hang.
	 */
	if (FIELD_GET(ASPEED_PECI_CMD_STS_MASK, cmd_sts)) {
		ret = reset_control_assert(priv->rst);
		if (ret) {
			dev_err(priv->dev, "cannot assert reset control\n");
			return ret;
		}

		ret = reset_control_deassert(priv->rst);
		if (ret) {
			dev_err(priv->dev, "cannot deassert reset control\n");
			return ret;
		}

		aspeed_peci_init_regs(priv);

		ret = clk_set_rate(priv->clk, priv->clk_frequency);
		if (ret < 0) {
			dev_err(priv->dev, "cannot set clock frequency\n");
			return ret;
		}

		aspeed_peci_controller_enable(priv);
	}

	return readl_poll_timeout(priv->base + ASPEED_PECI_CMD,
				  cmd_sts,
				  !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK),
				  ASPEED_PECI_IDLE_CHECK_INTERVAL_US,
				  ASPEED_PECI_IDLE_CHECK_TIMEOUT_US);
}

static int aspeed_peci_xfer(struct peci_controller *controller,
			    u8 addr, struct peci_request *req)
{

Annotation

Implementation Notes