blob: bf54aec4f1f21b5da9eab3c13ee33b9b71ad1274 [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
Andre Przywara8a457ad2023-08-30 12:32:30 +010012#include <dm.h>
Andre Przywara8a457ad2023-08-30 12:32:30 +010013#include <rng.h>
14#include <asm/system.h>
Heinrich Schuchardt10a45cc2024-02-13 00:44:47 +010015#include <linux/kernel.h>
Andre Przywara8a457ad2023-08-30 12:32:30 +010016
17#define DRIVER_NAME "arm-rndr"
18
19static bool cpu_has_rndr(void)
20{
21 uint64_t reg;
22
23 __asm__ volatile("mrs %0, ID_AA64ISAR0_EL1\n" : "=r" (reg));
24 return !!(reg & ID_AA64ISAR0_EL1_RNDR);
25}
26
27/*
28 * The system register name is RNDR, but this isn't widely known among older
29 * toolchains, and also triggers errors because of it being an architecture
30 * extension. Since we check the availability of the register before, it's
31 * fine to use here, though.
32 */
33#define RNDR "S3_3_C2_C4_0"
34
35static uint64_t read_rndr(void)
36{
37 uint64_t reg;
38
39 __asm__ volatile("mrs %0, " RNDR "\n" : "=r" (reg));
40
41 return reg;
42}
43
44static int arm_rndr_read(struct udevice *dev, void *data, size_t len)
45{
46 uint64_t random;
47
48 while (len) {
49 int tocopy = min(sizeof(uint64_t), len);
50
51 random = read_rndr();
52 memcpy(data, &random, tocopy);
53 len -= tocopy;
54 data += tocopy;
55 }
56
57 return 0;
58}
59
60static const struct dm_rng_ops arm_rndr_ops = {
61 .read = arm_rndr_read,
62};
63
Heinrich Schuchardt84020d02023-11-04 09:00:07 +020064static int arm_rndr_bind(struct udevice *dev)
Andre Przywara8a457ad2023-08-30 12:32:30 +010065{
66 if (!cpu_has_rndr())
Heinrich Schuchardt84020d02023-11-04 09:00:07 +020067 return -ENOENT;
Andre Przywara8a457ad2023-08-30 12:32:30 +010068
69 return 0;
70}
71
72U_BOOT_DRIVER(arm_rndr) = {
73 .name = DRIVER_NAME,
74 .id = UCLASS_RNG,
75 .ops = &arm_rndr_ops,
Heinrich Schuchardt84020d02023-11-04 09:00:07 +020076 .bind = arm_rndr_bind,
Andre Przywara8a457ad2023-08-30 12:32:30 +010077};
78
79U_BOOT_DRVINFO(cpu_arm_rndr) = {
80 .name = DRIVER_NAME,
81};