1 /*
2 * Copyright (c) 2020 Lemonbeat GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT silabs_gecko_trng
8
9 #include <zephyr/drivers/entropy.h>
10 #include <string.h>
11 #include "soc.h"
12 #include "em_cmu.h"
13
14 #if defined(CONFIG_CRYPTO_ACC_GECKO_TRNG)
15
16 /*
17 * Select the correct Crypto ACC FIFO memory base address.
18 *
19 * Problem: Gecko SDK doesn't provide macros that check if SL_TRUSTZONE is used or not for Crypto
20 * ACC RNGOUT FIFO memory base address, like it does for register address definitions.
21 *
22 * Solution: Check which register base address is used for the Crypto ACC peripheral and select an
23 * appropriate FIFO memory base address.
24 */
25 #if (CRYPTOACC_BASE == CRYPTOACC_S_BASE)
26 #define S2_FIFO_BASE CRYPTOACC_RNGOUT_FIFO_S_MEM_BASE
27 #else
28 #define S2_FIFO_BASE CRYPTOACC_RNGOUT_FIFO_MEM_BASE
29 #endif
30
31 /**
32 * Series 2 SoCs have different TRNG register definitions
33 */
34 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) /* xG22 */
35 #define S2_FIFO_LEVEL (CRYPTOACC_RNGCTRL->FIFOLEVEL)
36 #define S2_CTRL (CRYPTOACC_RNGCTRL->RNGCTRL)
37 #define S2_CTRL_ENABLE (CRYPTOACC_RNGCTRL_ENABLE)
38 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7) /* xG27 */
39 #define S2_FIFO_LEVEL (CRYPTOACC->NDRNG_FIFOLEVEL)
40 #define S2_CTRL (CRYPTOACC->NDRNG_CONTROL)
41 #define S2_CTRL_ENABLE (CRYPTOACC_NDRNG_CONTROL_ENABLE)
42 #else /* _SILICON_LABS_32B_SERIES_2_CONFIG_* */
43 #error "Building for unsupported Series 2 SoC"
44 #endif /* _SILICON_LABS_32B_SERIES_2_CONFIG_* */
45 #endif /* CONFIG_CRYPTO_ACC_GECKO_TRNG */
46
entropy_gecko_trng_read(uint8_t * output,size_t len)47 static void entropy_gecko_trng_read(uint8_t *output, size_t len)
48 {
49 #ifndef CONFIG_CRYPTO_ACC_GECKO_TRNG
50 uint32_t tmp;
51 uint32_t *data = (uint32_t *) output;
52
53 /* Read known good available data. */
54 while (len >= 4) {
55 *data++ = TRNG0->FIFO;
56 len -= 4;
57 }
58 if (len > 0) {
59 /* Handle the case where len is not a multiple of 4
60 * and FIFO data is available.
61 */
62 tmp = TRNG0->FIFO;
63 memcpy(data, (const uint8_t *) &tmp, len);
64 }
65 #else
66 memcpy(output, ((const uint8_t *) S2_FIFO_BASE), len);
67 #endif
68 }
69
entropy_gecko_trng_get_entropy(const struct device * dev,uint8_t * buffer,uint16_t length)70 static int entropy_gecko_trng_get_entropy(const struct device *dev,
71 uint8_t *buffer,
72 uint16_t length)
73 {
74 size_t count = 0;
75 size_t available;
76
77 ARG_UNUSED(dev);
78
79 while (length) {
80 #ifndef CONFIG_CRYPTO_ACC_GECKO_TRNG
81 available = TRNG0->FIFOLEVEL * 4;
82 #else
83 available = S2_FIFO_LEVEL * 4;
84 #endif
85 if (available == 0) {
86 return -EINVAL;
87 }
88
89 count = SL_MIN(length, available);
90 entropy_gecko_trng_read(buffer, count);
91 buffer += count;
92 length -= count;
93 }
94
95 return 0;
96 }
97
entropy_gecko_trng_get_entropy_isr(const struct device * dev,uint8_t * buf,uint16_t len,uint32_t flags)98 static int entropy_gecko_trng_get_entropy_isr(const struct device *dev,
99 uint8_t *buf,
100 uint16_t len, uint32_t flags)
101 {
102
103 if ((flags & ENTROPY_BUSYWAIT) == 0U) {
104
105 /* No busy wait; return whatever data is available. */
106 size_t count;
107 #ifndef CONFIG_CRYPTO_ACC_GECKO_TRNG
108 size_t available = TRNG0->FIFOLEVEL * 4;
109 #else
110 size_t available = S2_FIFO_LEVEL * 4;
111 #endif
112
113 if (available == 0) {
114 return -ENODATA;
115 }
116 count = SL_MIN(len, available);
117 entropy_gecko_trng_read(buf, count);
118 return count;
119
120 } else {
121 /* Allowed to busy-wait */
122 int ret = entropy_gecko_trng_get_entropy(dev, buf, len);
123
124 if (ret == 0) {
125 /* Data retrieved successfully. */
126 return len;
127 }
128 return ret;
129 }
130 }
131
entropy_gecko_trng_init(const struct device * dev)132 static int entropy_gecko_trng_init(const struct device *dev)
133 {
134 /* Enable the TRNG0 clock. */
135 #ifndef CONFIG_CRYPTO_ACC_GECKO_TRNG
136 CMU_ClockEnable(cmuClock_TRNG0, true);
137
138 /* Enable TRNG0. */
139 TRNG0->CONTROL = TRNG_CONTROL_ENABLE;
140 #else
141 /* Enable the CRYPTO ACC clock. */
142 CMU_ClockEnable(cmuClock_CRYPTOACC, true);
143
144 /* Enable TRNG */
145 S2_CTRL |= S2_CTRL_ENABLE;
146 #endif
147
148 return 0;
149 }
150
151 static struct entropy_driver_api entropy_gecko_trng_api_funcs = {
152 .get_entropy = entropy_gecko_trng_get_entropy,
153 .get_entropy_isr = entropy_gecko_trng_get_entropy_isr
154 };
155
156 DEVICE_DT_INST_DEFINE(0,
157 entropy_gecko_trng_init, NULL,
158 NULL, NULL,
159 PRE_KERNEL_1, CONFIG_ENTROPY_INIT_PRIORITY,
160 &entropy_gecko_trng_api_funcs);
161