diff mbox series

[v2,5/6] crypto: caam - replace DRNG with TRNG for use with hw_random

Message ID 20191118153843.28136-6-andrew.smirnov@gmail.com (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show
Series enable CAAM's HWRNG as default | expand

Commit Message

Andrey Smirnov Nov. 18, 2019, 3:38 p.m. UTC
In order to give CAAM-generated random data highest quarlity
raiting (999), replace current code that uses DRNG with code that
fetches data straight out of TRNG used to seed aforementioned DRNG.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Horia Geantă <horia.geanta@nxp.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
Cc: linux-imx@nxp.com
Cc: linux-crypto@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/crypto/caam/Kconfig   |  17 +-
 drivers/crypto/caam/Makefile  |   2 +-
 drivers/crypto/caam/caamrng.c | 351 ----------------------------------
 drivers/crypto/caam/ctrl.c    |   6 +
 drivers/crypto/caam/intern.h  |   9 +-
 drivers/crypto/caam/jr.c      |   2 -
 drivers/crypto/caam/regs.h    |   7 +-
 drivers/crypto/caam/trng.c    |  85 ++++++++
 8 files changed, 107 insertions(+), 372 deletions(-)
 delete mode 100644 drivers/crypto/caam/caamrng.c
 create mode 100644 drivers/crypto/caam/trng.c

Comments

Lucas Stach Nov. 18, 2019, 3:50 p.m. UTC | #1
On Mo, 2019-11-18 at 07:38 -0800, Andrey Smirnov wrote:
> In order to give CAAM-generated random data highest quarlity
> raiting (999), replace current code that uses DRNG with code that
> fetches data straight out of TRNG used to seed aforementioned DRNG.
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> Cc: Chris Healy <cphealy@gmail.com>
> Cc: Lucas Stach <l.stach@pengutronix.de>
> Cc: Horia Geantă <horia.geanta@nxp.com>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
> Cc: linux-imx@nxp.com
> Cc: linux-crypto@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> ---
[...]
> diff --git a/drivers/crypto/caam/trng.c b/drivers/crypto/caam/trng.c
> new file mode 100644
> index 000000000000..ab2af786543e
> --- /dev/null
> +++ b/drivers/crypto/caam/trng.c
> @@ -0,0 +1,85 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * hw_random interface for TRNG generator in CAAM RNG block
> + *
> + * Copyright 2019 Zoidac Inflight Innovations
                     ^ Zodiac

> + *
> + */
> +
> +#include <linux/hw_random.h>
> +
> +#include "compat.h"
> +#include "regs.h"
> +#include "intern.h"
> +
> +struct caam_trng_ctx {
> +	struct rng4tst __iomem *r4tst;
> +	struct hwrng rng;
> +};
> +
> +static bool caam_trng_busy(struct caam_trng_ctx *ctx)
> +{
> +	return !(rd_reg32(&ctx->r4tst->rtmctl) & RTMCTL_ENT_VAL);
> +}
> +
> +static int caam_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
> +{
> +	struct caam_trng_ctx *ctx = (void *)rng->priv;
> +	u32 rtent[ARRAY_SIZE(ctx->r4tst->rtent)];
> +	size_t residue = max;
> +
> +	clrsetbits_32(&ctx->r4tst->rtmctl, 0, RTMCTL_ACC);
> +
> +	do {
> +		const size_t chunk = min(residue, sizeof(rtent));
> +		unsigned int i;
> +
> +		while (caam_trng_busy(ctx)) {

The CAAM needs quite a bit of time to gather the 384bits of raw
entropy, in my testing it was almost 60ms. A busy loop (even with a
cpu_relax) for such an extended amount of time is probably not
appropriate, better sleep for some time here.

Also in the !wait case we are almost guaranteed to leave this function
without any entropy gathered. Maybe we should just bail out on !wait
without even trying to enable the TRNG access?

Regards,
Lucas

> +			if (wait)
> +				cpu_relax();
> +			else
> +				goto out;
> +		}
> +
> +		for (i = 0; i < DIV_ROUND_UP(chunk, sizeof(u32)); i++)
> +			rtent[i] = rd_reg32(&ctx->r4tst->rtent[i]);
> +
> +		memcpy(data, rtent, chunk);
> +
> +		residue -= chunk;
> +		data    += chunk;
> +	} while (residue);
> +
> +out:
> +	clrsetbits_32(&ctx->r4tst->rtmctl, RTMCTL_ACC, 0);
> +	return max - residue;
> +}
> +
> +int caam_trng_register(struct device *ctrldev)
> +{
> +	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
> +
> +	if (caam_has_rng(priv)) {
> +		struct caam_trng_ctx *ctx;
> +		int err;
> +
> +		ctx = devm_kzalloc(ctrldev, sizeof(*ctx), GFP_KERNEL);
> +		if (!ctx)
> +			return -ENOMEM;
> +
> +		ctx->r4tst = &priv->ctrl->r4tst[0];
> +
> +		ctx->rng.name = "trng-caam";
> +		ctx->rng.read = caam_trng_read;
> +		ctx->rng.priv = (unsigned long)ctx;
> +		ctx->rng.quality = 999;
> +
> +		dev_info(ctrldev, "registering %s\n", ctx->rng.name);
> +
> +		err = devm_hwrng_register(ctrldev, &ctx->rng);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
Andrey Smirnov Nov. 19, 2019, 3:28 p.m. UTC | #2
On Mon, Nov 18, 2019 at 7:50 AM Lucas Stach <l.stach@pengutronix.de> wrote:
>
> On Mo, 2019-11-18 at 07:38 -0800, Andrey Smirnov wrote:
> > In order to give CAAM-generated random data highest quarlity
> > raiting (999), replace current code that uses DRNG with code that
> > fetches data straight out of TRNG used to seed aforementioned DRNG.
> >
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > Cc: Chris Healy <cphealy@gmail.com>
> > Cc: Lucas Stach <l.stach@pengutronix.de>
> > Cc: Horia Geantă <horia.geanta@nxp.com>
> > Cc: Herbert Xu <herbert@gondor.apana.org.au>
> > Cc: Iuliana Prodan <iuliana.prodan@nxp.com>
> > Cc: linux-imx@nxp.com
> > Cc: linux-crypto@vger.kernel.org
> > Cc: linux-kernel@vger.kernel.org
> > ---
> [...]
> > diff --git a/drivers/crypto/caam/trng.c b/drivers/crypto/caam/trng.c
> > new file mode 100644
> > index 000000000000..ab2af786543e
> > --- /dev/null
> > +++ b/drivers/crypto/caam/trng.c
> > @@ -0,0 +1,85 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * hw_random interface for TRNG generator in CAAM RNG block
> > + *
> > + * Copyright 2019 Zoidac Inflight Innovations
>                      ^ Zodiac
>

Ugh, thanks for catching this, will fix in v3

> > + *
> > + */
> > +
> > +#include <linux/hw_random.h>
> > +
> > +#include "compat.h"
> > +#include "regs.h"
> > +#include "intern.h"
> > +
> > +struct caam_trng_ctx {
> > +     struct rng4tst __iomem *r4tst;
> > +     struct hwrng rng;
> > +};
> > +
> > +static bool caam_trng_busy(struct caam_trng_ctx *ctx)
> > +{
> > +     return !(rd_reg32(&ctx->r4tst->rtmctl) & RTMCTL_ENT_VAL);
> > +}
> > +
> > +static int caam_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
> > +{
> > +     struct caam_trng_ctx *ctx = (void *)rng->priv;
> > +     u32 rtent[ARRAY_SIZE(ctx->r4tst->rtent)];
> > +     size_t residue = max;
> > +
> > +     clrsetbits_32(&ctx->r4tst->rtmctl, 0, RTMCTL_ACC);
> > +
> > +     do {
> > +             const size_t chunk = min(residue, sizeof(rtent));
> > +             unsigned int i;
> > +
> > +             while (caam_trng_busy(ctx)) {
>
> The CAAM needs quite a bit of time to gather the 384bits of raw
> entropy, in my testing it was almost 60ms. A busy loop (even with a
> cpu_relax) for such an extended amount of time is probably not
> appropriate, better sleep for some time here.
>

Good point, will fix in v3.

> Also in the !wait case we are almost guaranteed to leave this function
> without any entropy gathered. Maybe we should just bail out on !wait
> without even trying to enable the TRNG access?
>

Yeah, I think you're right. Will change in v3.

Thanks,
Andrey Smirnov
diff mbox series

Patch

diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 137ed3df0c74..22116a8e2ff3 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -31,6 +31,14 @@  config CRYPTO_DEV_FSL_CAAM_DEBUG
 	  Selecting this will enable printing of various debug
 	  information in the CAAM driver.
 
+config CRYPTO_DEV_FSL_CAAM_RNG_API
+	bool "Register caam device for hwrng API"
+	default y
+	select HW_RANDOM
+	help
+	  Selecting this will register the hardware TRNG to
+	  the hw_random API for suppying the kernel entropy pool.
+
 menuconfig CRYPTO_DEV_FSL_CAAM_JR
 	tristate "Freescale CAAM Job Ring driver backend"
 	default y
@@ -138,15 +146,6 @@  config CRYPTO_DEV_FSL_CAAM_PKC_API
           Supported cryptographic primitives: encryption, decryption,
           signature and verification.
 
-config CRYPTO_DEV_FSL_CAAM_RNG_API
-	bool "Register caam device for hwrng API"
-	default y
-	select CRYPTO_RNG
-	select HW_RANDOM
-	help
-	  Selecting this will register the SEC4 hardware rng to
-	  the hw_random API for suppying the kernel entropy pool.
-
 endif # CRYPTO_DEV_FSL_CAAM_JR
 
 endif # CRYPTO_DEV_FSL_CAAM
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 68d5cc0f28e2..04884fc087f9 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -15,11 +15,11 @@  obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
 
 caam-y := ctrl.o
+caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += trng.o
 caam_jr-y := jr.o key_gen.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
-caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
 
 caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
deleted file mode 100644
index 70ddfbf90ac7..000000000000
--- a/drivers/crypto/caam/caamrng.c
+++ /dev/null
@@ -1,351 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * caam - Freescale FSL CAAM support for hw_random
- *
- * Copyright 2011 Freescale Semiconductor, Inc.
- * Copyright 2018-2019 NXP
- *
- * Based on caamalg.c crypto API driver.
- *
- * relationship between job descriptors to shared descriptors:
- *
- * ---------------                     --------------
- * | JobDesc #0  |-------------------->| ShareDesc  |
- * | *(buffer 0) |      |------------->| (generate) |
- * ---------------      |              | (move)     |
- *                      |              | (store)    |
- * ---------------      |              --------------
- * | JobDesc #1  |------|
- * | *(buffer 1) |
- * ---------------
- *
- * A job desc looks like this:
- *
- * ---------------------
- * | Header            |
- * | ShareDesc Pointer |
- * | SEQ_OUT_PTR       |
- * | (output buffer)   |
- * ---------------------
- *
- * The SharedDesc never changes, and each job descriptor points to one of two
- * buffers for each device, from which the data will be copied into the
- * requested destination
- */
-
-#include <linux/hw_random.h>
-#include <linux/completion.h>
-#include <linux/atomic.h>
-
-#include "compat.h"
-
-#include "regs.h"
-#include "intern.h"
-#include "desc_constr.h"
-#include "jr.h"
-#include "error.h"
-
-/*
- * Maximum buffer size: maximum number of random, cache-aligned bytes that
- * will be generated and moved to seq out ptr (extlen not allowed)
- */
-#define RN_BUF_SIZE			(0xffff / L1_CACHE_BYTES * \
-					 L1_CACHE_BYTES)
-
-/* length of descriptors */
-#define DESC_JOB_O_LEN			(CAAM_CMD_SZ * 2 + CAAM_PTR_SZ_MAX * 2)
-#define DESC_RNG_LEN			(3 * CAAM_CMD_SZ)
-
-/* Buffer, its dma address and lock */
-struct buf_data {
-	u8 buf[RN_BUF_SIZE] ____cacheline_aligned;
-	dma_addr_t addr;
-	struct completion filled;
-	u32 hw_desc[DESC_JOB_O_LEN];
-#define BUF_NOT_EMPTY 0
-#define BUF_EMPTY 1
-#define BUF_PENDING 2  /* Empty, but with job pending --don't submit another */
-	atomic_t empty;
-};
-
-/* rng per-device context */
-struct caam_rng_ctx {
-	struct device *jrdev;
-	dma_addr_t sh_desc_dma;
-	u32 sh_desc[DESC_RNG_LEN];
-	unsigned int cur_buf_idx;
-	int current_buf;
-	struct buf_data bufs[2];
-};
-
-static struct caam_rng_ctx *rng_ctx;
-
-/*
- * Variable used to avoid double free of resources in case
- * algorithm registration was unsuccessful
- */
-static bool init_done;
-
-static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd)
-{
-	if (bd->addr)
-		dma_unmap_single(jrdev, bd->addr, RN_BUF_SIZE,
-				 DMA_FROM_DEVICE);
-}
-
-static inline void rng_unmap_ctx(struct caam_rng_ctx *ctx)
-{
-	struct device *jrdev = ctx->jrdev;
-
-	if (ctx->sh_desc_dma)
-		dma_unmap_single(jrdev, ctx->sh_desc_dma,
-				 desc_bytes(ctx->sh_desc), DMA_TO_DEVICE);
-	rng_unmap_buf(jrdev, &ctx->bufs[0]);
-	rng_unmap_buf(jrdev, &ctx->bufs[1]);
-}
-
-static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context)
-{
-	struct buf_data *bd;
-
-	bd = container_of(desc, struct buf_data, hw_desc[0]);
-
-	if (err)
-		caam_jr_strstatus(jrdev, err);
-
-	atomic_set(&bd->empty, BUF_NOT_EMPTY);
-	complete(&bd->filled);
-
-	/* Buffer refilled, invalidate cache */
-	dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE);
-
-	print_hex_dump_debug("rng refreshed buf@: ", DUMP_PREFIX_ADDRESS, 16, 4,
-			     bd->buf, RN_BUF_SIZE, 1);
-}
-
-static inline int submit_job(struct caam_rng_ctx *ctx, int to_current)
-{
-	struct buf_data *bd = &ctx->bufs[!(to_current ^ ctx->current_buf)];
-	struct device *jrdev = ctx->jrdev;
-	u32 *desc = bd->hw_desc;
-	int err;
-
-	dev_dbg(jrdev, "submitting job %d\n", !(to_current ^ ctx->current_buf));
-	init_completion(&bd->filled);
-	err = caam_jr_enqueue(jrdev, desc, rng_done, ctx);
-	if (err)
-		complete(&bd->filled); /* don't wait on failed job*/
-	else
-		atomic_inc(&bd->empty); /* note if pending */
-
-	return err;
-}
-
-static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait)
-{
-	struct caam_rng_ctx *ctx = rng_ctx;
-	struct buf_data *bd = &ctx->bufs[ctx->current_buf];
-	int next_buf_idx, copied_idx;
-	int err;
-
-	if (atomic_read(&bd->empty)) {
-		/* try to submit job if there wasn't one */
-		if (atomic_read(&bd->empty) == BUF_EMPTY) {
-			err = submit_job(ctx, 1);
-			/* if can't submit job, can't even wait */
-			if (err)
-				return 0;
-		}
-		/* no immediate data, so exit if not waiting */
-		if (!wait)
-			return 0;
-
-		/* waiting for pending job */
-		if (atomic_read(&bd->empty))
-			wait_for_completion(&bd->filled);
-	}
-
-	next_buf_idx = ctx->cur_buf_idx + max;
-	dev_dbg(ctx->jrdev, "%s: start reading at buffer %d, idx %d\n",
-		 __func__, ctx->current_buf, ctx->cur_buf_idx);
-
-	/* if enough data in current buffer */
-	if (next_buf_idx < RN_BUF_SIZE) {
-		memcpy(data, bd->buf + ctx->cur_buf_idx, max);
-		ctx->cur_buf_idx = next_buf_idx;
-		return max;
-	}
-
-	/* else, copy what's left... */
-	copied_idx = RN_BUF_SIZE - ctx->cur_buf_idx;
-	memcpy(data, bd->buf + ctx->cur_buf_idx, copied_idx);
-	ctx->cur_buf_idx = 0;
-	atomic_set(&bd->empty, BUF_EMPTY);
-
-	/* ...refill... */
-	submit_job(ctx, 1);
-
-	/* and use next buffer */
-	ctx->current_buf = !ctx->current_buf;
-	dev_dbg(ctx->jrdev, "switched to buffer %d\n", ctx->current_buf);
-
-	/* since there already is some data read, don't wait */
-	return copied_idx + caam_read(rng, data + copied_idx,
-				      max - copied_idx, false);
-}
-
-static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx)
-{
-	struct device *jrdev = ctx->jrdev;
-	u32 *desc = ctx->sh_desc;
-
-	init_sh_desc(desc, HDR_SHARE_SERIAL);
-
-	/* Generate random bytes */
-	append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG |
-			 OP_ALG_PR_ON);
-
-	/* Store bytes */
-	append_seq_fifo_store(desc, RN_BUF_SIZE, FIFOST_TYPE_RNGSTORE);
-
-	ctx->sh_desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc),
-					  DMA_TO_DEVICE);
-	if (dma_mapping_error(jrdev, ctx->sh_desc_dma)) {
-		dev_err(jrdev, "unable to map shared descriptor\n");
-		return -ENOMEM;
-	}
-
-	print_hex_dump_debug("rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4,
-			     desc, desc_bytes(desc), 1);
-
-	return 0;
-}
-
-static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id)
-{
-	struct device *jrdev = ctx->jrdev;
-	struct buf_data *bd = &ctx->bufs[buf_id];
-	u32 *desc = bd->hw_desc;
-	int sh_len = desc_len(ctx->sh_desc);
-
-	init_job_desc_shared(desc, ctx->sh_desc_dma, sh_len, HDR_SHARE_DEFER |
-			     HDR_REVERSE);
-
-	bd->addr = dma_map_single(jrdev, bd->buf, RN_BUF_SIZE, DMA_FROM_DEVICE);
-	if (dma_mapping_error(jrdev, bd->addr)) {
-		dev_err(jrdev, "unable to map dst\n");
-		return -ENOMEM;
-	}
-
-	append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0);
-
-	print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4,
-			     desc, desc_bytes(desc), 1);
-
-	return 0;
-}
-
-static void caam_cleanup(struct hwrng *rng)
-{
-	int i;
-	struct buf_data *bd;
-
-	for (i = 0; i < 2; i++) {
-		bd = &rng_ctx->bufs[i];
-		if (atomic_read(&bd->empty) == BUF_PENDING)
-			wait_for_completion(&bd->filled);
-	}
-
-	rng_unmap_ctx(rng_ctx);
-}
-
-static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id)
-{
-	struct buf_data *bd = &ctx->bufs[buf_id];
-	int err;
-
-	err = rng_create_job_desc(ctx, buf_id);
-	if (err)
-		return err;
-
-	atomic_set(&bd->empty, BUF_EMPTY);
-	submit_job(ctx, buf_id == ctx->current_buf);
-	wait_for_completion(&bd->filled);
-
-	return 0;
-}
-
-static int caam_init_rng(struct caam_rng_ctx *ctx, struct device *jrdev)
-{
-	int err;
-
-	ctx->jrdev = jrdev;
-
-	err = rng_create_sh_desc(ctx);
-	if (err)
-		return err;
-
-	ctx->current_buf = 0;
-	ctx->cur_buf_idx = 0;
-
-	err = caam_init_buf(ctx, 0);
-	if (err)
-		return err;
-
-	return caam_init_buf(ctx, 1);
-}
-
-static struct hwrng caam_rng = {
-	.name		= "rng-caam",
-	.cleanup	= caam_cleanup,
-	.read		= caam_read,
-};
-
-void caam_rng_exit(void)
-{
-	if (!init_done)
-		return;
-
-	caam_jr_free(rng_ctx->jrdev);
-	hwrng_unregister(&caam_rng);
-	kfree(rng_ctx);
-}
-
-int caam_rng_init(struct device *ctrldev)
-{
-	struct device *dev;
-	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
-	int err;
-	init_done = false;
-
-	if (!caam_has_rng(priv))
-		return 0;
-
-	dev = caam_jr_alloc();
-	if (IS_ERR(dev)) {
-		pr_err("Job Ring Device allocation for transform failed\n");
-		return PTR_ERR(dev);
-	}
-	rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL);
-	if (!rng_ctx) {
-		err = -ENOMEM;
-		goto free_caam_alloc;
-	}
-	err = caam_init_rng(rng_ctx, dev);
-	if (err)
-		goto free_rng_ctx;
-
-	dev_info(dev, "registering rng-caam\n");
-
-	err = hwrng_register(&caam_rng);
-	if (!err) {
-		init_done = true;
-		return err;
-	}
-
-free_rng_ctx:
-	kfree(rng_ctx);
-free_caam_alloc:
-	caam_jr_free(dev);
-	return err;
-}
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 8054ec29d35a..adbdef06bcf9 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -907,6 +907,12 @@  static int caam_probe(struct platform_device *pdev)
 			    &ctrlpriv->ctl_tdsk_wrap);
 #endif
 
+	ret = caam_trng_register(dev);
+	if (ret) {
+		dev_err(dev, "Failed to register HWRNG interface\n");
+		return ret;
+	}
+
 	ret = devm_of_platform_populate(dev);
 	if (ret)
 		dev_err(dev, "JR platform devices creation error\n");
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index f815e1ad4608..54bb04aa86bd 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -174,20 +174,15 @@  static inline void caam_pkc_exit(void)
 
 #ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API
 
-int caam_rng_init(struct device *dev);
-void caam_rng_exit(void);
+int caam_trng_register(struct device *dev);
 
 #else
 
-static inline int caam_rng_init(struct device *dev)
+static inline int caam_trng_register(struct device *dev)
 {
 	return 0;
 }
 
-static inline void caam_rng_exit(void)
-{
-}
-
 #endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */
 
 #ifdef CONFIG_CAAM_QI
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index fc97cde27059..c745b7044fe6 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -37,7 +37,6 @@  static void register_algs(struct device *dev)
 	caam_algapi_init(dev);
 	caam_algapi_hash_init(dev);
 	caam_pkc_init(dev);
-	caam_rng_init(dev);
 	caam_qi_algapi_init(dev);
 
 algs_unlock:
@@ -53,7 +52,6 @@  static void unregister_algs(void)
 
 	caam_qi_algapi_exit();
 
-	caam_rng_exit();
 	caam_pkc_exit();
 	caam_algapi_hash_exit();
 	caam_algapi_exit();
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index fe1f8c1409fd..262399387e27 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -488,6 +488,7 @@  struct rngtst {
 /* RNG4 TRNG test registers */
 struct rng4tst {
 #define RTMCTL_ACC  BIT(5)  /* TRNG access mode */
+#define RTMCTL_ENT_VAL BIT(10)
 #define RTMCTL_PRGM BIT(16) /* 1 -> program mode, 0 -> run mode */
 #define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC	0 /* use von Neumann data in
 						     both entropy shifter and
@@ -521,7 +522,9 @@  struct rng4tst {
 		u32 rtfrqmax;	/* PRGM=1: freq. count max. limit register */
 		u32 rtfrqcnt;	/* PRGM=0: freq. count register */
 	};
-	u32 rsvd1[40];
+	u32 rsvd1[8];
+	u32 rtent[16];		/* RTENT0 - RTENT15 */
+	u32 rsvd2[16];		/* RTPKRCNTn */
 #define RDSTA_SKVT 0x80000000
 #define RDSTA_SKVN 0x40000000
 #define RDSTA_PR0 BIT(4)
@@ -530,7 +533,7 @@  struct rng4tst {
 #define RDSTA_IF1 0x00000002
 #define RDSTA_IFMASK (RDSTA_PR1 | RDSTA_PR0 | RDSTA_IF1 | RDSTA_IF0)
 	u32 rdsta;
-	u32 rsvd2[15];
+	u32 rsvd3[15];
 };
 
 /*
diff --git a/drivers/crypto/caam/trng.c b/drivers/crypto/caam/trng.c
new file mode 100644
index 000000000000..ab2af786543e
--- /dev/null
+++ b/drivers/crypto/caam/trng.c
@@ -0,0 +1,85 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * hw_random interface for TRNG generator in CAAM RNG block
+ *
+ * Copyright 2019 Zoidac Inflight Innovations
+ *
+ */
+
+#include <linux/hw_random.h>
+
+#include "compat.h"
+#include "regs.h"
+#include "intern.h"
+
+struct caam_trng_ctx {
+	struct rng4tst __iomem *r4tst;
+	struct hwrng rng;
+};
+
+static bool caam_trng_busy(struct caam_trng_ctx *ctx)
+{
+	return !(rd_reg32(&ctx->r4tst->rtmctl) & RTMCTL_ENT_VAL);
+}
+
+static int caam_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+	struct caam_trng_ctx *ctx = (void *)rng->priv;
+	u32 rtent[ARRAY_SIZE(ctx->r4tst->rtent)];
+	size_t residue = max;
+
+	clrsetbits_32(&ctx->r4tst->rtmctl, 0, RTMCTL_ACC);
+
+	do {
+		const size_t chunk = min(residue, sizeof(rtent));
+		unsigned int i;
+
+		while (caam_trng_busy(ctx)) {
+			if (wait)
+				cpu_relax();
+			else
+				goto out;
+		}
+
+		for (i = 0; i < DIV_ROUND_UP(chunk, sizeof(u32)); i++)
+			rtent[i] = rd_reg32(&ctx->r4tst->rtent[i]);
+
+		memcpy(data, rtent, chunk);
+
+		residue -= chunk;
+		data    += chunk;
+	} while (residue);
+
+out:
+	clrsetbits_32(&ctx->r4tst->rtmctl, RTMCTL_ACC, 0);
+	return max - residue;
+}
+
+int caam_trng_register(struct device *ctrldev)
+{
+	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
+
+	if (caam_has_rng(priv)) {
+		struct caam_trng_ctx *ctx;
+		int err;
+
+		ctx = devm_kzalloc(ctrldev, sizeof(*ctx), GFP_KERNEL);
+		if (!ctx)
+			return -ENOMEM;
+
+		ctx->r4tst = &priv->ctrl->r4tst[0];
+
+		ctx->rng.name = "trng-caam";
+		ctx->rng.read = caam_trng_read;
+		ctx->rng.priv = (unsigned long)ctx;
+		ctx->rng.quality = 999;
+
+		dev_info(ctrldev, "registering %s\n", ctx->rng.name);
+
+		err = devm_hwrng_register(ctrldev, &ctx->rng);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}