drivers/char/hw_random/ks-sa-rng.c

Source file repositories/reference/linux-study-clean/drivers/char/hw_random/ks-sa-rng.c

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/ks-sa-rng.c
Extension
.c
Size
7249 bytes
Lines
276
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 trng_regs {
	u32	output_l;
	u32	output_h;
	u32	status;
	u32	intmask;
	u32	intack;
	u32	control;
	u32	config;
};

struct ks_sa_rng {
	struct hwrng	rng;
	struct clk	*clk;
	struct regmap	*regmap_cfg;
	struct trng_regs __iomem *reg_rng;
	u64 ready_ts;
	unsigned int refill_delay_ns;
};

static unsigned int cycles_to_ns(unsigned long clk_rate, unsigned int cycles)
{
	return DIV_ROUND_UP_ULL((TRNG_DEF_CLK_DIV_CYCLES + 1) * 1000000000ull *
				cycles, clk_rate);
}

static unsigned int startup_delay_ns(unsigned long clk_rate)
{
	if (!TRNG_DEF_STARTUP_CYCLES)
		return cycles_to_ns(clk_rate, BIT(24));
	return cycles_to_ns(clk_rate, 256 * TRNG_DEF_STARTUP_CYCLES);
}

static unsigned int refill_delay_ns(unsigned long clk_rate)
{
	if (!TRNG_DEF_MAX_REFILL_CYCLES)
		return cycles_to_ns(clk_rate, BIT(24));
	return cycles_to_ns(clk_rate, 256 * TRNG_DEF_MAX_REFILL_CYCLES);
}

static int ks_sa_rng_init(struct hwrng *rng)
{
	u32 value;
	struct ks_sa_rng *ks_sa_rng = container_of(rng, struct ks_sa_rng, rng);
	unsigned long clk_rate = clk_get_rate(ks_sa_rng->clk);

	/* Enable RNG module */
	regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
			  SA_CMD_STATUS_REG_TRNG_ENABLE,
			  SA_CMD_STATUS_REG_TRNG_ENABLE);

	/* Configure RNG module */
	writel(0, &ks_sa_rng->reg_rng->control);
	value = TRNG_DEF_STARTUP_CYCLES << TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT;
	writel(value, &ks_sa_rng->reg_rng->control);

	value =	(TRNG_DEF_MIN_REFILL_CYCLES <<
		 TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT) |
		(TRNG_DEF_MAX_REFILL_CYCLES <<
		 TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT) |
		(TRNG_DEF_CLK_DIV_CYCLES <<
		 TRNG_CFG_REG_SAMPLE_DIV_SHIFT);

	writel(value, &ks_sa_rng->reg_rng->config);

	/* Disable all interrupts from TRNG */
	writel(0, &ks_sa_rng->reg_rng->intmask);

	/* Enable RNG */
	value = readl(&ks_sa_rng->reg_rng->control);
	value |= TRNG_CNTL_REG_TRNG_ENABLE;
	writel(value, &ks_sa_rng->reg_rng->control);

	ks_sa_rng->refill_delay_ns = refill_delay_ns(clk_rate);
	ks_sa_rng->ready_ts = ktime_get_ns() +
			      startup_delay_ns(clk_rate);

	return 0;
}

static void ks_sa_rng_cleanup(struct hwrng *rng)
{
	struct ks_sa_rng *ks_sa_rng = container_of(rng, struct ks_sa_rng, rng);

	/* Disable RNG */
	writel(0, &ks_sa_rng->reg_rng->control);
	regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
			  SA_CMD_STATUS_REG_TRNG_ENABLE, 0);
}

static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)

Annotation

Implementation Notes