Skip to content

Commit 51930d9

Browse files
committed
drivers: entropy: Add SAM0 entropy driver
This adds a driver for the True Random Number Generator found in some Atmel SAM0 SoCs. The Code is based on the driver for the SAM TRNG, but uses different register and clock definitions. Signed-off-by: Benjamin Valentin <[email protected]>
1 parent 8370856 commit 51930d9

File tree

6 files changed

+196
-0
lines changed

6 files changed

+196
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
/drivers/ps2/ @albertofloyd @franciscomunoz @scottwcpg
130130
/drivers/kscan/ @albertofloyd @franciscomunoz @scottwcpg
131131
/drivers/ethernet/ @jukkar @tbursztyka @pfalcon
132+
/drivers/entropy/*sam0* @benpicco
132133
/drivers/flash/ @nashif @nvlsianpu
133134
/drivers/flash/*native_posix* @vanwinkeljan @aescolar
134135
/drivers/flash/*nrf* @nvlsianpu

drivers/entropy/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_RNGA entropy_mcux_rnga
88
zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_TRNG entropy_mcux_trng.c)
99
zephyr_library_sources_ifdef(CONFIG_ENTROPY_NRF5_RNG entropy_nrf5.c)
1010
zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM_RNG entropy_sam.c)
11+
zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM0_RNG entropy_sam0.c)
1112
zephyr_library_sources_ifdef(CONFIG_ENTROPY_STM32_RNG entropy_stm32.c)
1213
zephyr_library_sources_ifdef(CONFIG_FAKE_ENTROPY_NATIVE_POSIX fake_entropy_native_posix.c)
1314
zephyr_library_sources_ifdef(CONFIG_USERSPACE entropy_handlers.c)

drivers/entropy/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ source "drivers/entropy/Kconfig.stm32"
1919
source "drivers/entropy/Kconfig.esp32"
2020
source "drivers/entropy/Kconfig.nrf5"
2121
source "drivers/entropy/Kconfig.sam"
22+
source "drivers/entropy/Kconfig.sam0"
2223
source "drivers/entropy/Kconfig.native_posix"
2324

2425
config ENTROPY_HAS_DRIVER

drivers/entropy/Kconfig.sam0

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Kconfig.sam - Atmel SAM0 TRNG configuration
2+
#
3+
# Copyright (c) 2019 Benjamin Valentin
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
config ENTROPY_SAM0_RNG
8+
bool "Atmel SAM0 MCU Family True Random Number Generator (TRNG) Driver"
9+
depends on SOC_FAMILY_SAM0
10+
select ENTROPY_HAS_DRIVER
11+
select HAS_DTS_ENTROPY
12+
help
13+
Enable True Random Number Generator (TRNG) driver for Atmel SAM0 MCUs.

drivers/entropy/entropy_sam0.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* Copyright (c) 2019 ML!PA Consulting GmbH
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <device.h>
8+
#include <drivers/entropy.h>
9+
#include <errno.h>
10+
#include <init.h>
11+
#include <soc.h>
12+
#include <string.h>
13+
14+
struct trng_sam0_dev_cfg {
15+
Trng *regs;
16+
};
17+
18+
#define DEV_CFG(dev) \
19+
((const struct trng_sam0_dev_cfg *const)(dev)->config->config_info)
20+
21+
static int entropy_sam0_wait_ready(Trng *const trng, u32_t flags)
22+
{
23+
/* According to the reference manual, the generator provides
24+
* one 32-bit random value every 84 peripheral clock cycles.
25+
* MCK may not be smaller than HCLK/4, so it should not take
26+
* more than 336 HCLK ticks. Assuming the CPU can do 1
27+
* instruction per HCLK the number of times to loop before
28+
* the TRNG is ready is less than 1000. And that is when
29+
* assuming the loop only takes 1 instruction. So looping a
30+
* million times should be more than enough.
31+
*/
32+
int timeout = 1000000;
33+
34+
while (!trng->INTFLAG.bit.DATARDY) {
35+
if (timeout-- == 0) {
36+
return -ETIMEDOUT;
37+
}
38+
39+
if ((flags & ENTROPY_BUSYWAIT) == 0U) {
40+
/* This internal function is used by both get_entropy,
41+
* and get_entropy_isr APIs. The later may call this
42+
* function with the ENTROPY_BUSYWAIT flag set. In
43+
* that case make no assumption that the kernel is
44+
* initialized when the function is called; so, just
45+
* do busy-wait for the random data to be ready.
46+
*/
47+
k_yield();
48+
}
49+
}
50+
51+
return 0;
52+
}
53+
54+
static int entropy_sam0_get_entropy_internal(struct device *dev, u8_t *buffer,
55+
u16_t length, u32_t flags)
56+
{
57+
Trng *const trng = DEV_CFG(dev)->regs;
58+
59+
while (length > 0) {
60+
size_t to_copy;
61+
u32_t value;
62+
int res;
63+
64+
res = entropy_sam0_wait_ready(trng, flags);
65+
if (res < 0) {
66+
return res;
67+
}
68+
69+
value = TRNG->DATA.reg;
70+
to_copy = MIN(length, sizeof(value));
71+
72+
memcpy(buffer, &value, to_copy);
73+
buffer += to_copy;
74+
length -= to_copy;
75+
}
76+
77+
return 0;
78+
}
79+
80+
static int entropy_sam0_get_entropy(struct device *dev, u8_t *buffer,
81+
u16_t length)
82+
{
83+
return entropy_sam0_get_entropy_internal(dev, buffer, length, 0);
84+
}
85+
86+
static int entropy_sam0_get_entropy_isr(struct device *dev, u8_t *buffer,
87+
u16_t length, u32_t flags)
88+
{
89+
u16_t cnt = length;
90+
91+
92+
if ((flags & ENTROPY_BUSYWAIT) == 0U) {
93+
94+
/* No busy wait; return whatever data is available. */
95+
96+
Trng *const trng = DEV_CFG(dev)->regs;
97+
98+
do {
99+
size_t to_copy;
100+
u32_t value;
101+
102+
if (!(trng->INTFLAG.bit.DATARDY)) {
103+
104+
/* Data not ready */
105+
break;
106+
}
107+
108+
value = TRNG->DATA.reg;
109+
to_copy = MIN(length, sizeof(value));
110+
111+
memcpy(buffer, &value, to_copy);
112+
buffer += to_copy;
113+
length -= to_copy;
114+
115+
} while (length > 0);
116+
117+
return cnt - length;
118+
119+
} else {
120+
/* Allowed to busy-wait */
121+
int ret =
122+
entropy_sam0_get_entropy_internal(dev,
123+
buffer, length, flags);
124+
125+
if (ret == 0) {
126+
/* Data retrieved successfully. */
127+
return cnt;
128+
}
129+
130+
return ret;
131+
}
132+
}
133+
134+
static int entropy_sam0_init(struct device *dev)
135+
{
136+
Trng *const trng = DEV_CFG(dev)->regs;
137+
138+
/* Enable the MCLK */
139+
MCLK->APBCMASK.bit.TRNG_ = 1;
140+
141+
/* Enable the TRNG */
142+
trng->CTRLA.bit.ENABLE = 1;
143+
144+
return 0;
145+
}
146+
147+
static const struct entropy_driver_api entropy_sam0_api = {
148+
.get_entropy = entropy_sam0_get_entropy,
149+
.get_entropy_isr = entropy_sam0_get_entropy_isr
150+
};
151+
152+
static const struct trng_sam0_dev_cfg trng_sam0_cfg = {
153+
.regs = (Trng *)DT_ATMEL_SAM0_TRNG_0_BASE_ADDRESS,
154+
};
155+
156+
DEVICE_AND_API_INIT(entropy_sam0, CONFIG_ENTROPY_NAME,
157+
entropy_sam0_init, NULL, &trng_sam0_cfg,
158+
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
159+
&entropy_sam0_api);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2019 ML!PA Consulting GmbH
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
title: Atmel SAM0 TRNG (True Random Number Generator)
5+
6+
description: >
7+
This binding gives a base representation of the Atmel SAM0 RNG
8+
9+
compatible: "atmel,sam0-trng"
10+
11+
include: base.yaml
12+
13+
properties:
14+
reg:
15+
required: true
16+
17+
interrupts:
18+
required: true
19+
20+
label:
21+
required: true

0 commit comments

Comments
 (0)