Commit 0934683d authored by Claudiu Beznea's avatar Claudiu Beznea Committed by Herbert Xu

hwrng: atmel - add wait for ready support on read

Add wait for ready support on read.
Signed-off-by: default avatarClaudiu Beznea <claudiu.beznea@microchip.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 0a2a464f
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/hw_random.h> #include <linux/hw_random.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#define TRNG_CR 0x00 #define TRNG_CR 0x00
#define TRNG_MR 0x04 #define TRNG_MR 0x04
#define TRNG_ISR 0x1c #define TRNG_ISR 0x1c
#define TRNG_ISR_DATRDY BIT(0)
#define TRNG_ODATA 0x50 #define TRNG_ODATA 0x50
#define TRNG_KEY 0x524e4700 /* RNG */ #define TRNG_KEY 0x524e4700 /* RNG */
...@@ -36,25 +38,40 @@ struct atmel_trng { ...@@ -36,25 +38,40 @@ struct atmel_trng {
struct hwrng rng; struct hwrng rng;
}; };
static bool atmel_trng_wait_ready(struct atmel_trng *trng, bool wait)
{
int ready;
ready = readl(trng->base + TRNG_ISR) & TRNG_ISR_DATRDY;
if (!ready && wait)
readl_poll_timeout(trng->base + TRNG_ISR, ready,
ready & TRNG_ISR_DATRDY, 1000, 20000);
return !!ready;
}
static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max, static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
bool wait) bool wait)
{ {
struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng); struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng);
u32 *data = buf; u32 *data = buf;
int ret;
ret = atmel_trng_wait_ready(trng, wait);
if (!ret)
goto out;
/* data ready? */ *data = readl(trng->base + TRNG_ODATA);
if (readl(trng->base + TRNG_ISR) & 1) { /*
*data = readl(trng->base + TRNG_ODATA); * ensure data ready is only set again AFTER the next data word is ready
/* * in case it got set between checking ISR and reading ODATA, so we
ensure data ready is only set again AFTER the next data * don't risk re-reading the same word
word is ready in case it got set between checking ISR */
and reading ODATA, so we don't risk re-reading the readl(trng->base + TRNG_ISR);
same word ret = 4;
*/
readl(trng->base + TRNG_ISR); out:
return 4; return ret;
} else
return 0;
} }
static void atmel_trng_enable(struct atmel_trng *trng) static void atmel_trng_enable(struct atmel_trng *trng)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment