drivers/char/hw_random/rockchip-rng.c

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

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/rockchip-rng.c
Extension
.c
Size
14190 bytes
Lines
493
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 rk_rng {
	struct hwrng rng;
	void __iomem *base;
	int clk_num;
	struct clk_bulk_data *clk_bulks;
	const struct rk_rng_soc_data *soc_data;
	struct device *dev;
};

struct rk_rng_soc_data {
	int (*rk_rng_init)(struct hwrng *rng);
	int (*rk_rng_read)(struct hwrng *rng, void *buf, size_t max, bool wait);
	void (*rk_rng_cleanup)(struct hwrng *rng);
	unsigned short quality;
	bool reset_optional;
};

/* The mask in the upper 16 bits determines the bits that are updated */
static void rk_rng_write_ctl(struct rk_rng *rng, u32 val, u32 mask)
{
	writel((mask << 16) | val, rng->base + TRNG_RNG_CTL);
}

static inline void rk_rng_writel(struct rk_rng *rng, u32 val, u32 offset)
{
	writel(val, rng->base + offset);
}

static inline u32 rk_rng_readl(struct rk_rng *rng, u32 offset)
{
	return readl(rng->base + offset);
}

static int rk_rng_enable_clks(struct rk_rng *rk_rng)
{
	int ret;
	/* start clocks */
	ret = clk_bulk_prepare_enable(rk_rng->clk_num, rk_rng->clk_bulks);
	if (ret < 0) {
		dev_err(rk_rng->dev, "Failed to enable clocks: %d\n", ret);
		return ret;
	}

	return 0;
}

static int rk3568_rng_init(struct hwrng *rng)
{
	struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
	int ret;

	ret = rk_rng_enable_clks(rk_rng);
	if (ret < 0)
		return ret;

	/* set the sample period */
	writel(RK_RNG_SAMPLE_CNT, rk_rng->base + TRNG_RNG_SAMPLE_CNT);

	/* set osc ring speed and enable it */
	rk_rng_write_ctl(rk_rng, TRNG_RNG_CTL_LEN_256_BIT |
				 TRNG_RNG_CTL_OSC_RING_SPEED_0 |
				 TRNG_RNG_CTL_ENABLE,
			 TRNG_RNG_CTL_MASK);

	return 0;
}

static void rk3568_rng_cleanup(struct hwrng *rng)
{
	struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);

	/* stop TRNG */
	rk_rng_write_ctl(rk_rng, 0, TRNG_RNG_CTL_MASK);

	/* stop clocks */
	clk_bulk_disable_unprepare(rk_rng->clk_num, rk_rng->clk_bulks);
}

static int rk3568_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
	struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
	size_t to_read = min_t(size_t, max, RK_RNG_MAX_BYTE);
	u32 reg;
	int ret = 0;

	ret = pm_runtime_resume_and_get(rk_rng->dev);
	if (ret < 0)
		return ret;

	/* Start collecting random data */

Annotation

Implementation Notes