drivers/char/hw_random/xilinx-trng.c

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

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/xilinx-trng.c
Extension
.c
Size
9415 bytes
Lines
342
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 xilinx_rng {
	void __iomem *rng_base;
	struct device *dev;
	struct hwrng trng;
};

static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value)
{
	u32 val;

	val = ioread32(addr);
	val = (val & (~mask)) | (mask & value);
	iowrite32(val, addr);
}

static void xtrng_trng_reset(void __iomem *addr)
{
	xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, TRNG_RESET_VAL_MASK);
	udelay(TRNG_RESET_DELAY);
	xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, 0);
}

static void xtrng_hold_reset(void __iomem *addr)
{
	xtrng_readwrite32(addr + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK,
			  TRNG_CTRL_PRNGSRST_MASK);
	iowrite32(TRNG_RESET_VAL_MASK, addr + TRNG_RESET_OFFSET);
	udelay(TRNG_RESET_DELAY);
}

static void xtrng_softreset(struct xilinx_rng *rng)
{
	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK,
			  TRNG_CTRL_PRNGSRST_MASK);
	udelay(TRNG_RESET_DELAY);
	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 0);
}

/* Return no. of bytes read */
static size_t xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks32, bool wait)
{
	int read = 0, ret;
	int timeout = 1;
	int i, idx;
	u32 val;

	if (wait)
		timeout = TRNG_DATA_READ_DELAY;

	for (i = 0; i < (blocks32 * 2); i++) {
		/* TRNG core generate data in 16 bytes. Read twice to complete 32 bytes read */
		ret = readl_poll_timeout(rng_base + TRNG_STATUS_OFFSET, val,
					 (val & TRNG_STATUS_QCNT_MASK) ==
					 TRNG_STATUS_QCNT_16_BYTES, !!wait, timeout);
		if (ret)
			break;

		for (idx = 0; idx < TRNG_READ_4_WORD; idx++) {
			*(buf + read) = cpu_to_be32(ioread32(rng_base + TRNG_CORE_OUTPUT_OFFSET));
			read += 1;
		}
	}
	return read * 4;
}

static int xtrng_collect_random_data(struct xilinx_rng *rng, u8 *rand_gen_buf,
				     int no_of_random_bytes, bool wait)
{
	u8 randbuf[TRNG_SEC_STRENGTH_BYTES];
	int byteleft, blocks, count = 0;
	int ret;

	byteleft = no_of_random_bytes & (TRNG_SEC_STRENGTH_BYTES - 1);
	blocks = no_of_random_bytes >> TRNG_SEC_STRENGTH_SHIFT;
	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK,
			  TRNG_CTRL_PRNGSTART_MASK);
	if (blocks) {
		ret = xtrng_readblock32(rng->rng_base, (__be32 *)rand_gen_buf, blocks, wait);
		if (!ret)
			return 0;
		count += ret;
	}

	if (byteleft) {
		ret = xtrng_readblock32(rng->rng_base, (__be32 *)randbuf, 1, wait);
		if (!ret)
			return count;
		memcpy(rand_gen_buf + (blocks * TRNG_SEC_STRENGTH_BYTES), randbuf, byteleft);
		count += byteleft;
	}

Annotation

Implementation Notes