drivers/char/hw_random/airoha-trng.c

Source file repositories/reference/linux-study-clean/drivers/char/hw_random/airoha-trng.c

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/airoha-trng.c
Extension
.c
Size
6338 bytes
Lines
245
Domain
Driver Families
Bucket
drivers/char
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 airoha_trng {
	void __iomem *base;
	struct hwrng rng;
	struct device *dev;

	struct completion rng_op_done;
};

static int airoha_trng_irq_mask(struct airoha_trng *trng)
{
	u32 val;

	val = readl(trng->base + TRNG_INTR_EN);
	val |= INTR_MASK;
	writel(val, trng->base + TRNG_INTR_EN);

	return 0;
}

static int airoha_trng_irq_unmask(struct airoha_trng *trng)
{
	u32 val;

	val = readl(trng->base + TRNG_INTR_EN);
	val &= ~INTR_MASK;
	writel(val, trng->base + TRNG_INTR_EN);

	return 0;
}

static int airoha_trng_init(struct hwrng *rng)
{
	struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng);
	int ret;
	u32 val;

	val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN);
	val |= RNG_EN;
	writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN);

	/* Set out of SW Reset */
	airoha_trng_irq_unmask(trng);
	writel(0, trng->base + TRNG_HEALTH_TEST_SW_RST);

	ret = wait_for_completion_timeout(&trng->rng_op_done, BUSY_LOOP_TIMEOUT);
	if (ret <= 0) {
		dev_err(trng->dev, "Timeout waiting for Health Check\n");
		airoha_trng_irq_mask(trng);
		return -ENODEV;
	}

	/* Check if Health Test Failed */
	val = readl(trng->base + TRNG_HEALTH_TEST_STATUS);
	if (val & (RST_STARTUP_AP_TEST_FAIL | RST_STARTUP_RC_TEST_FAIL)) {
		dev_err(trng->dev, "Health Check fail: %s test fail\n",
			val & RST_STARTUP_AP_TEST_FAIL ? "AP" : "RC");
		return -ENODEV;
	}

	/* Check if IP is ready */
	ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val,
				 val & SAMPLE_RDY, 10, 1000);
	if (ret < 0) {
		dev_err(trng->dev, "Timeout waiting for IP ready");
		return -ENODEV;
	}

	/* CNT_TRANS must be 0x80 for IP to be considered ready */
	ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val,
				 FIELD_GET(CNT_TRANS, val) == TRNG_CNT_TRANS_VALID,
				 10, 1000);
	if (ret < 0) {
		dev_err(trng->dev, "Timeout waiting for IP ready");
		return -ENODEV;
	}

	return 0;
}

static void airoha_trng_cleanup(struct hwrng *rng)
{
	struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng);
	u32 val;

	val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN);
	val &= ~RNG_EN;
	writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN);

	/* Put it in SW Reset */
	writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST);

Annotation

Implementation Notes