blob: 111b3b6c6184eb17606c03b4784e9f0f158283f7 [file] [log] [blame]
Antonio Nino Diaz12f73ff2018-07-13 09:27:16 +01001/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <mmio.h>
9#include <string.h>
10
11#include "rpi3_hw.h"
12
13/* Initial amount of values to discard */
14#define RNG_WARMUP_COUNT U(0x40000)
15
16static void rpi3_rng_initialize(void)
17{
18 uint32_t int_mask, ctrl;
19
20 /* Return if it is already enabled */
21 ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET);
22 if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) {
23 return;
24 }
25
26 /* Mask interrupts */
27 int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET);
28 int_mask |= RPI3_RNG_INT_MASK_DISABLE;
29 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask);
30
31 /* Discard several values when initializing to give it time to warmup */
32 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT);
33
34 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET,
35 RPI3_RNG_CTRL_ENABLE);
36}
37
38static uint32_t rpi3_rng_get_word(void)
39{
40 size_t nwords;
41
42 do {
43 /* Get number of available words to read */
44 nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET)
45 >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT)
46 & RPI3_RNG_STATUS_NUM_WORDS_MASK;
47 } while (nwords == 0U);
48
49 return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET);
50}
51
52void rpi3_rng_read(void *buf, size_t len)
53{
54 uint32_t data;
55 size_t left = len;
56 uint32_t *dst = buf;
57
58 assert(buf != NULL);
59 assert(len != 0U);
60 assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0);
61
62 rpi3_rng_initialize();
63
64 while (left >= sizeof(uint32_t)) {
65 data = rpi3_rng_get_word();
66 *dst++ = data;
67 left -= sizeof(uint32_t);
68 }
69
70 if (left > 0U) {
71 data = rpi3_rng_get_word();
72 memcpy(dst, &data, left);
73 }
74}