blob: 16733e15c443f90adb9fd813f4e1de260bb4f108 [file] [log] [blame]
Antonio Nino Diaz12f73ff2018-07-13 09:27:16 +01001/*
Mario Bălănicăcb759ff2023-12-06 21:36:25 +02002 * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
Antonio Nino Diaz12f73ff2018-07-13 09:27:16 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Antonio Nino Diaz12f73ff2018-07-13 09:27:16 +01008#include <string.h>
9
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <lib/mmio.h>
11
Andre Przywarabb6ef152019-07-09 11:44:14 +010012#include <rpi_hw.h>
Antonio Nino Diaz12f73ff2018-07-13 09:27:16 +010013
Mario Bălănicăcb759ff2023-12-06 21:36:25 +020014#define RPI3_RNG_CTRL_OFFSET ULL(0x00000000)
15#define RPI3_RNG_STATUS_OFFSET ULL(0x00000004)
16#define RPI3_RNG_DATA_OFFSET ULL(0x00000008)
17#define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010)
18/* Enable/disable RNG */
19#define RPI3_RNG_CTRL_ENABLE U(0x1)
20#define RPI3_RNG_CTRL_DISABLE U(0x0)
21/* Number of currently available words */
22#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24)
23#define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF)
24/* Value to mask interrupts caused by the RNG */
25#define RPI3_RNG_INT_MASK_DISABLE U(0x1)
26
Antonio Nino Diaz12f73ff2018-07-13 09:27:16 +010027/* Initial amount of values to discard */
28#define RNG_WARMUP_COUNT U(0x40000)
29
30static void rpi3_rng_initialize(void)
31{
32 uint32_t int_mask, ctrl;
33
34 /* Return if it is already enabled */
35 ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET);
36 if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) {
37 return;
38 }
39
40 /* Mask interrupts */
41 int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET);
42 int_mask |= RPI3_RNG_INT_MASK_DISABLE;
43 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask);
44
45 /* Discard several values when initializing to give it time to warmup */
46 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT);
47
48 mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET,
49 RPI3_RNG_CTRL_ENABLE);
50}
51
52static uint32_t rpi3_rng_get_word(void)
53{
54 size_t nwords;
55
56 do {
57 /* Get number of available words to read */
58 nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET)
59 >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT)
60 & RPI3_RNG_STATUS_NUM_WORDS_MASK;
61 } while (nwords == 0U);
62
63 return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET);
64}
65
66void rpi3_rng_read(void *buf, size_t len)
67{
68 uint32_t data;
69 size_t left = len;
70 uint32_t *dst = buf;
71
72 assert(buf != NULL);
73 assert(len != 0U);
74 assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0);
75
76 rpi3_rng_initialize();
77
78 while (left >= sizeof(uint32_t)) {
79 data = rpi3_rng_get_word();
80 *dst++ = data;
81 left -= sizeof(uint32_t);
82 }
83
84 if (left > 0U) {
85 data = rpi3_rng_get_word();
86 memcpy(dst, &data, left);
87 }
88}