blob: 55989743eaee37a09cf61ad4ff7fbe9a64a8742c [file] [log] [blame]
Andre Przywara8a457ad2023-08-30 12:32:30 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2023, Arm Ltd.
4 *
5 * Use the (optional) ARMv8.5 RNDR register to provide random numbers to
6 * U-Boot's UCLASS_RNG users.
7 * Detection is done at runtime using the CPU ID registers.
8 */
9
10#define LOG_CATEGORY UCLASS_RNG
11
12#include <common.h>
13#include <dm.h>
14#include <linux/kernel.h>
15#include <rng.h>
16#include <asm/system.h>
17
18#define DRIVER_NAME "arm-rndr"
19
20static bool cpu_has_rndr(void)
21{
22 uint64_t reg;
23
24 __asm__ volatile("mrs %0, ID_AA64ISAR0_EL1\n" : "=r" (reg));
25 return !!(reg & ID_AA64ISAR0_EL1_RNDR);
26}
27
28/*
29 * The system register name is RNDR, but this isn't widely known among older
30 * toolchains, and also triggers errors because of it being an architecture
31 * extension. Since we check the availability of the register before, it's
32 * fine to use here, though.
33 */
34#define RNDR "S3_3_C2_C4_0"
35
36static uint64_t read_rndr(void)
37{
38 uint64_t reg;
39
40 __asm__ volatile("mrs %0, " RNDR "\n" : "=r" (reg));
41
42 return reg;
43}
44
45static int arm_rndr_read(struct udevice *dev, void *data, size_t len)
46{
47 uint64_t random;
48
49 while (len) {
50 int tocopy = min(sizeof(uint64_t), len);
51
52 random = read_rndr();
53 memcpy(data, &random, tocopy);
54 len -= tocopy;
55 data += tocopy;
56 }
57
58 return 0;
59}
60
61static const struct dm_rng_ops arm_rndr_ops = {
62 .read = arm_rndr_read,
63};
64
65static int arm_rndr_probe(struct udevice *dev)
66{
67 if (!cpu_has_rndr())
68 return -ENODEV;
69
70 return 0;
71}
72
73U_BOOT_DRIVER(arm_rndr) = {
74 .name = DRIVER_NAME,
75 .id = UCLASS_RNG,
76 .ops = &arm_rndr_ops,
77 .probe = arm_rndr_probe,
78};
79
80U_BOOT_DRVINFO(cpu_arm_rndr) = {
81 .name = DRIVER_NAME,
82};