1 /*
2 * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /******************************************************************************
18 * @file ck_trng.c
19 * @brief CSI Source File for TRNG Driver
20 * @version V1.0
21 * @date 02. June 2017
22 ******************************************************************************/
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "drv_trng.h"
27 #include "ck_trng.h"
28
29
30 #define ERR_TRNG(errno) (CSI_DRV_ERRNO_TRNG_BASE | errno)
31 #define TRNG_NULL_PARAM_CHK(para) \
32 do { \
33 if (para == NULL) { \
34 return ERR_TRNG(EDRV_PARAMETER); \
35 } \
36 } while (0)
37
38 typedef struct {
39 uint32_t base;
40 trng_event_cb_t cb;
41 trng_status_t status;
42 } ck_trng_priv_t;
43
44 static ck_trng_priv_t trng_handle[CONFIG_TRNG_NUM];
45
46 /* Driver Capabilities */
47 static const trng_capabilities_t driver_capabilities = {
48 .lowper_mode = 1 /* low power mode */
49 };
50
51 //
52 // Functions
53 //
54
55 ck_trng_reg_t *trng_reg = NULL;
56
trng_enable(void)57 static int32_t trng_enable(void)
58 {
59 trng_reg->TCR |= TRNG_EN;
60 return 0;
61 }
62
trng_get_data(void)63 static int32_t trng_get_data(void)
64 {
65 int data = trng_reg->TDR;
66 return data;
67 }
68
trng_data_is_ready(void)69 static int32_t trng_data_is_ready(void)
70 {
71 int flag = (trng_reg->TCR & TRNG_DATA_READY);
72 return flag;
73 }
74
75
target_get_trng_count(void)76 int32_t __attribute__((weak)) target_get_trng_count(void)
77 {
78 return 0;
79 }
80
target_get_trng(int32_t idx,uint32_t * base)81 int32_t __attribute__((weak)) target_get_trng(int32_t idx, uint32_t *base)
82 {
83 return NULL;
84 }
85 /**
86 \brief get trng handle count.
87 \return trng handle count
88 */
csi_trng_get_instance_count(void)89 int32_t csi_trng_get_instance_count(void)
90 {
91 return target_get_trng_count();
92 }
93
94 /**
95 \brief Initialize TRNG Interface. 1. Initializes the resources needed for the TRNG interface 2.registers event callback function
96 \param[in] idx must not exceed return value of csi_trng_get_instance_count()
97 \param[in] cb_event Pointer to \ref trng_event_cb_t
98 \return pointer to trng handle
99 */
csi_trng_initialize(int32_t idx,trng_event_cb_t cb_event)100 trng_handle_t csi_trng_initialize(int32_t idx, trng_event_cb_t cb_event)
101 {
102
103 if (idx < 0 || idx >= CONFIG_TRNG_NUM) {
104 return NULL;
105 }
106
107 /* obtain the trng information */
108 uint32_t base = 0u;
109 int32_t real_idx = target_get_trng(idx, &base);
110
111 if (real_idx != idx) {
112 return NULL;
113 }
114
115 ck_trng_priv_t *trng_priv = &trng_handle[idx];
116 trng_priv->base = base;
117
118 /* initialize the trng context */
119 trng_reg = (ck_trng_reg_t *)(trng_priv->base);
120 trng_priv->cb = cb_event;
121 trng_priv->status.busy = 0;
122 trng_priv->status.data_valid = 0;
123
124 return (trng_handle_t)trng_priv;
125 }
126
127 /**
128 \brief De-initialize TRNG Interface. stops operation and releases the software resources used by the interface
129 \param[in] handle trng handle to operate.
130 \return error code
131 */
csi_trng_uninitialize(trng_handle_t handle)132 int32_t csi_trng_uninitialize(trng_handle_t handle)
133 {
134 TRNG_NULL_PARAM_CHK(handle);
135
136 ck_trng_priv_t *trng_priv = handle;
137 trng_priv->cb = NULL;
138
139 return 0;
140 }
141
142 /**
143 \brief Get driver capabilities.
144 \param[in] trng handle to operate.
145 \return \ref trng_capabilities_t
146 */
csi_trng_get_capabilities(trng_handle_t handle)147 trng_capabilities_t csi_trng_get_capabilities(trng_handle_t handle)
148 {
149 return driver_capabilities;
150 }
151
152 /**
153 \brief Get data from the TRNG.
154 \param[in] handle trng handle to operate.
155 \param[out] data Pointer to buffer with data get from TRNG
156 \param[in] num Number of data items to obtain
157 \return error code
158 */
csi_trng_get_data(trng_handle_t handle,void * data,uint32_t num)159 int32_t csi_trng_get_data(trng_handle_t handle, void *data, uint32_t num)
160 {
161 TRNG_NULL_PARAM_CHK(handle);
162 TRNG_NULL_PARAM_CHK(data);
163 TRNG_NULL_PARAM_CHK(num);
164
165 ck_trng_priv_t *trng_priv = handle;
166
167 trng_priv->status.busy = 1U;
168 trng_priv->status.data_valid = 0U;
169
170 uint8_t left_len = (uint32_t)data & 0x3;
171 uint32_t result = 0;
172
173 /* if the data addr is not aligned by word */
174 if (left_len) {
175 trng_enable();
176 while (!trng_data_is_ready());
177 result = trng_get_data();
178 /* wait the data is ready */
179 while (trng_data_is_ready());
180
181 if (num > (4 - left_len)) {
182 memcpy(data, &result, 4 - left_len);
183 } else {
184 memcpy(data, &result, num);
185 trng_priv->status.busy = 0U;
186 trng_priv->status.data_valid = 1U;
187
188 if (trng_priv->cb) {
189 trng_priv->cb(TRNG_EVENT_DATA_GENERATE_COMPLETE);
190 }
191 return 0;
192 }
193 num -= (4 - left_len);
194 }
195
196 uint32_t word_len = num >> 2;
197 left_len = num & 0x3;
198
199 /* obtain the data by word */
200 while (word_len--) {
201 trng_enable();
202 while (!trng_data_is_ready());
203 result = trng_get_data();
204 while (trng_data_is_ready());
205 *(uint32_t *)data = result;
206 data += 4;
207 }
208
209 /* if the num is not aligned by word */
210 if (left_len) {
211 trng_enable();
212 while (!trng_data_is_ready());
213 result = trng_get_data();
214 while (trng_data_is_ready());
215 memcpy(data, &result, left_len);
216 }
217
218 trng_priv->status.busy = 0U;
219 trng_priv->status.data_valid = 1U;
220
221 if (trng_priv->cb) {
222 trng_priv->cb(TRNG_EVENT_DATA_GENERATE_COMPLETE);
223 }
224
225 return 0;
226 }
227
228 /**
229 \brief Get TRNG status.
230 \param[in] handle trng handle to operate.
231 \return TRNG status \ref trng_status_t
232 */
csi_trng_get_status(trng_handle_t handle)233 trng_status_t csi_trng_get_status(trng_handle_t handle)
234 {
235 ck_trng_priv_t *trng_priv = handle;
236 return trng_priv->status;
237 }
238