arch/arm/rp23xx: Add hardware TRNG driver for /dev/random.

Add a driver for the rp2350 hardware true random number generator.

Enabling CONFIG_RP23XX_RNG selects ARCH_HAVE_RNG and builds the driver,
which registers /dev/random (and /dev/urandom when CONFIG_DEV_URANDOM
selects the architecture source, DEV_URANDOM_ARCH).  Each read enables
the entropy source, waits for a valid 192-bit entropy holding register
(EHR) sample, reads the six 32-bit EHR words, and repeats until the
request is satisfied.

Document the TRNG on the rp23xx platform page.

Assisted-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-07-24 22:06:29 +02:00 committed by Xiang Xiao
parent aa3157e234
commit 52e84e0c0a
6 changed files with 222 additions and 0 deletions

View file

@ -26,6 +26,7 @@ ignore-words-list =
BU,
DAA,
dout,
ehr,
emac,
eeeprom,
extint,

View file

@ -41,6 +41,7 @@ Flash ROM Boot Working Does not require boot2 from pico-sdk
If picotool is available a nuttx.uf2 file will be created
SRAM Boot Working Requires external SWD debugger
PSRAM Working Three modes of heap allocation described below
TRNG Working Hardware RNG at /dev/random and /dev/urandom
============== ============ =====
Installation
@ -203,6 +204,24 @@ GPIO 0 and 1 pins must be connected to the device such as USB-serial converter.
The `usbnsh` configuration provides the console access by USB CDC/ACM serial
device. The console is available by using a terminal software on the USB host.
TRNG
====
The rp2350 has a hardware true random number generator (TRNG). Enabling
``RP23XX_RNG`` builds the driver and selects ``ARCH_HAVE_RNG``, which in turn
makes ``DEV_RANDOM`` available.
With ``DEV_RANDOM`` enabled the driver registers ``/dev/random``. Enabling
``DEV_URANDOM`` additionally registers ``/dev/urandom``; when a hardware RNG is
present the architecture source (``DEV_URANDOM_ARCH``) is selected by default,
so ``/dev/urandom`` is served from the same TRNG rather than a software PRNG.
Each read collects entropy from the TRNG's 192-bit entropy holding register
(EHR): the source is enabled, the driver waits for ``TRNG_VALID``, reads the
six 32-bit EHR words, and repeats until the request is satisfied. For example::
nsh> dd if=/dev/random of=/dev/console bs=16 count=1
Supported Boards
================

View file

@ -60,6 +60,10 @@ if(CONFIG_RP23XX_I2C)
list(APPEND SRCS rp23xx_i2c.c)
endif()
if(CONFIG_RP23XX_RNG)
list(APPEND SRCS rp23xx_rng.c)
endif()
if(CONFIG_RP23XX_I2C_SLAVE)
list(APPEND SRCS rp23xx_i2c_slave.c)
endif()

View file

@ -740,6 +740,15 @@ endif # SPISD Configuration
# ADC Configuration
#####################################################################
config RP23XX_RNG
bool "Enable hardware TRNG (/dev/random)"
default n
select ARCH_HAVE_RNG
---help---
Enable the RP2350 hardware true random number generator. Provides
/dev/random (and /dev/urandom when CONFIG_DEV_URANDOM selects the
architecture source) via the TRNG entropy register (EHR).
config RP23XX_ADC
bool "Enable ADC Support"
default n

View file

@ -64,6 +64,10 @@ ifeq ($(CONFIG_RP23XX_I2C),y)
CHIP_CSRCS += rp23xx_i2c.c
endif
ifeq ($(CONFIG_RP23XX_RNG),y)
CHIP_CSRCS += rp23xx_rng.c
endif
ifeq ($(CONFIG_RP23XX_I2C_SLAVE),y)
CHIP_CSRCS += rp23xx_i2c_slave.c
endif

View file

@ -0,0 +1,185 @@
/****************************************************************************
* arch/arm/src/rp23xx/rp23xx_rng.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mutex.h>
#include <nuttx/drivers/drivers.h>
#include "arm_internal.h"
#include "hardware/rp23xx_trng.h"
#if defined(CONFIG_DEV_RANDOM) || defined(CONFIG_DEV_URANDOM_ARCH)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* The TRNG delivers entropy 192 bits (six 32-bit EHR words) at a time. */
#define RP23XX_TRNG_EHR_WORDS 6
#define RP23XX_TRNG_EHR_BYTES (RP23XX_TRNG_EHR_WORDS * sizeof(uint32_t))
/* TRNG_VALID.EHR_VALID: the EHR holds a fresh 192-bit sample. */
#define RP23XX_TRNG_EHR_VALID (1 << 0)
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static ssize_t rp23xx_rng_read(struct file *filep, char *buffer,
size_t buflen);
/****************************************************************************
* Private Data
****************************************************************************/
static mutex_t g_rng_lock = NXMUTEX_INITIALIZER;
static const struct file_operations g_rngops =
{
NULL, /* open */
NULL, /* close */
rp23xx_rng_read, /* read */
NULL, /* write */
NULL, /* seek */
NULL, /* ioctl */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: rp23xx_rng_read
*
* Description:
* Fill 'buffer' with 'buflen' bytes of hardware entropy. Enables the ring
* -oscillator source, then repeatedly waits for a valid 192-bit EHR and
* copies it out until the request is satisfied.
*
****************************************************************************/
static ssize_t rp23xx_rng_read(struct file *filep, char *buffer,
size_t buflen)
{
size_t nread = 0;
int ret;
ret = nxmutex_lock(&g_rng_lock);
if (ret < 0)
{
return ret;
}
/* Enable the entropy source. */
putreg32(1, RP23XX_TRNG_RND_SOURCE_ENABLE);
while (nread < buflen)
{
uint32_t ehr[RP23XX_TRNG_EHR_WORDS];
size_t chunk;
int i;
/* Wait for the next 192-bit sample to become valid. */
while ((getreg32(RP23XX_TRNG_TRNG_VALID) & RP23XX_TRNG_EHR_VALID) == 0)
{
}
for (i = 0; i < RP23XX_TRNG_EHR_WORDS; i++)
{
ehr[i] = getreg32(RP23XX_TRNG_EHR_DATA(i));
}
/* Acknowledge the sample so the engine collects the next one. */
putreg32(0xffffffff, RP23XX_TRNG_RNG_ICR);
chunk = buflen - nread;
if (chunk > RP23XX_TRNG_EHR_BYTES)
{
chunk = RP23XX_TRNG_EHR_BYTES;
}
memcpy(buffer + nread, ehr, chunk);
nread += chunk;
}
/* Leave the source disabled to save power. */
putreg32(0, RP23XX_TRNG_RND_SOURCE_ENABLE);
nxmutex_unlock(&g_rng_lock);
return (ssize_t)nread;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: devrandom_register
*
* Description:
* Register /dev/random, backed by the RP2350 hardware TRNG. Called
* automatically from drivers_initialize() when CONFIG_DEV_RANDOM is set.
*
****************************************************************************/
#ifdef CONFIG_DEV_RANDOM
void devrandom_register(void)
{
register_driver("/dev/random", &g_rngops, 0444, NULL);
}
#endif
/****************************************************************************
* Name: devurandom_register
*
* Description:
* Register /dev/urandom, backed by the same hardware TRNG. Called from
* drivers_initialize() when CONFIG_DEV_URANDOM selects the arch source.
*
****************************************************************************/
#ifdef CONFIG_DEV_URANDOM_ARCH
void devurandom_register(void)
{
register_driver("/dev/urandom", &g_rngops, 0444, NULL);
}
#endif
#endif /* CONFIG_DEV_RANDOM || CONFIG_DEV_URANDOM_ARCH */