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, BU,
DAA, DAA,
dout, dout,
ehr,
emac, emac,
eeeprom, eeeprom,
extint, 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 If picotool is available a nuttx.uf2 file will be created
SRAM Boot Working Requires external SWD debugger SRAM Boot Working Requires external SWD debugger
PSRAM Working Three modes of heap allocation described below PSRAM Working Three modes of heap allocation described below
TRNG Working Hardware RNG at /dev/random and /dev/urandom
============== ============ ===== ============== ============ =====
Installation 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 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. 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 Supported Boards
================ ================

View file

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

View file

@ -740,6 +740,15 @@ endif # SPISD Configuration
# ADC 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 config RP23XX_ADC
bool "Enable ADC Support" bool "Enable ADC Support"
default n default n

View file

@ -64,6 +64,10 @@ ifeq ($(CONFIG_RP23XX_I2C),y)
CHIP_CSRCS += rp23xx_i2c.c CHIP_CSRCS += rp23xx_i2c.c
endif endif
ifeq ($(CONFIG_RP23XX_RNG),y)
CHIP_CSRCS += rp23xx_rng.c
endif
ifeq ($(CONFIG_RP23XX_I2C_SLAVE),y) ifeq ($(CONFIG_RP23XX_I2C_SLAVE),y)
CHIP_CSRCS += rp23xx_i2c_slave.c CHIP_CSRCS += rp23xx_i2c_slave.c
endif 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 */