| /* |
| * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved. |
| * |
| * Licensed 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. |
| */ |
| |
| /****************************************************************************** |
| * @file ck_trng.c |
| * @brief CSI Source File for TRNG Driver |
| * @version V1.0 |
| * @date 02. June 2017 |
| ******************************************************************************/ |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "drv_trng.h" |
| #include "ck_trng.h" |
| |
| |
| #define ERR_TRNG(errno) (CSI_DRV_ERRNO_TRNG_BASE | errno) |
| #define TRNG_NULL_PARAM_CHK(para) \ |
| do { \ |
| if (para == NULL) { \ |
| return ERR_TRNG(EDRV_PARAMETER); \ |
| } \ |
| } while (0) |
| |
| typedef struct { |
| uint32_t base; |
| trng_event_cb_t cb; |
| trng_status_t status; |
| } ck_trng_priv_t; |
| |
| extern int32_t target_get_trng_count(void); |
| extern int32_t target_get_trng(int32_t idx, uint32_t *base); |
| |
| static ck_trng_priv_t trng_handle[CONFIG_TRNG_NUM]; |
| |
| /* Driver Capabilities */ |
| static const trng_capabilities_t driver_capabilities = { |
| .lowper_mode = 1 /* low power mode */ |
| }; |
| |
| extern int32_t target_get_trng(int32_t idx, uint32_t *base); |
| extern int32_t target_get_trng_count(void); |
| // |
| // Functions |
| // |
| |
| ck_trng_reg_t *trng_reg = NULL; |
| |
| static int32_t trng_enable(void) |
| { |
| trng_reg->TCR |= TRNG_EN; |
| return 0; |
| } |
| |
| static int32_t trng_get_data(void) |
| { |
| int data = trng_reg->TDR; |
| return data; |
| } |
| |
| static int32_t trng_data_is_ready(void) |
| { |
| int flag = (trng_reg->TCR & TRNG_DATA_READY); |
| return flag; |
| } |
| |
| /** |
| \brief get trng handle count. |
| \return trng handle count |
| */ |
| int32_t csi_trng_get_instance_count(void) |
| { |
| return target_get_trng_count(); |
| } |
| |
| /** |
| \brief Initialize TRNG Interface. 1. Initializes the resources needed for the TRNG interface 2.registers event callback function |
| \param[in] idx must not exceed return value of csi_trng_get_instance_count() |
| \param[in] cb_event Pointer to \ref trng_event_cb_t |
| \return pointer to trng handle |
| */ |
| trng_handle_t csi_trng_initialize(int32_t idx, trng_event_cb_t cb_event) |
| { |
| |
| if (idx < 0 || idx >= CONFIG_TRNG_NUM) { |
| return NULL; |
| } |
| |
| /* obtain the trng information */ |
| uint32_t base = 0u; |
| int32_t real_idx = target_get_trng(idx, &base); |
| |
| if (real_idx != idx) { |
| return NULL; |
| } |
| |
| ck_trng_priv_t *trng_priv = &trng_handle[idx]; |
| trng_priv->base = base; |
| |
| /* initialize the trng context */ |
| trng_reg = (ck_trng_reg_t *)(trng_priv->base); |
| trng_priv->cb = cb_event; |
| trng_priv->status.busy = 0; |
| trng_priv->status.data_valid = 0; |
| |
| return (trng_handle_t)trng_priv; |
| } |
| |
| /** |
| \brief De-initialize TRNG Interface. stops operation and releases the software resources used by the interface |
| \param[in] handle trng handle to operate. |
| \return error code |
| */ |
| int32_t csi_trng_uninitialize(trng_handle_t handle) |
| { |
| TRNG_NULL_PARAM_CHK(handle); |
| |
| ck_trng_priv_t *trng_priv = handle; |
| trng_priv->cb = NULL; |
| |
| return 0; |
| } |
| |
| /** |
| \brief Get driver capabilities. |
| \param[in] trng handle to operate. |
| \return \ref trng_capabilities_t |
| */ |
| trng_capabilities_t csi_trng_get_capabilities(trng_handle_t handle) |
| { |
| return driver_capabilities; |
| } |
| |
| /** |
| \brief Get data from the TRNG. |
| \param[in] handle trng handle to operate. |
| \param[out] data Pointer to buffer with data get from TRNG |
| \param[in] num Number of data items to obtain |
| \return error code |
| */ |
| int32_t csi_trng_get_data(trng_handle_t handle, void *data, uint32_t num) |
| { |
| TRNG_NULL_PARAM_CHK(handle); |
| TRNG_NULL_PARAM_CHK(data); |
| TRNG_NULL_PARAM_CHK(num); |
| |
| ck_trng_priv_t *trng_priv = handle; |
| |
| trng_priv->status.busy = 1U; |
| trng_priv->status.data_valid = 0U; |
| |
| uint8_t left_len = (uint32_t)data & 0x3; |
| uint32_t result = 0; |
| |
| /* if the data addr is not aligned by word */ |
| if (left_len) { |
| trng_enable(); |
| while (!trng_data_is_ready()); |
| result = trng_get_data(); |
| /* wait the data is ready */ |
| while (trng_data_is_ready()); |
| |
| if (num > (4 - left_len)) { |
| memcpy(data, &result, 4 - left_len); |
| } else { |
| memcpy(data, &result, num); |
| trng_priv->status.busy = 0U; |
| trng_priv->status.data_valid = 1U; |
| |
| if (trng_priv->cb) { |
| trng_priv->cb(TRNG_EVENT_DATA_GENERATE_COMPLETE); |
| } |
| return 0; |
| } |
| num -= (4 - left_len); |
| data += (4 - left_len); |
| } |
| |
| uint32_t word_len = num >> 2; |
| left_len = num & 0x3; |
| |
| /* obtain the data by word */ |
| while (word_len--) { |
| trng_enable(); |
| while (!trng_data_is_ready()); |
| result = trng_get_data(); |
| while (trng_data_is_ready()); |
| *(uint32_t *)data = result; |
| data = (void *)((uint32_t)data + 4); |
| } |
| |
| /* if the num is not aligned by word */ |
| if (left_len) { |
| trng_enable(); |
| while (!trng_data_is_ready()); |
| result = trng_get_data(); |
| while (trng_data_is_ready()); |
| memcpy(data, &result, left_len); |
| } |
| |
| trng_priv->status.busy = 0U; |
| trng_priv->status.data_valid = 1U; |
| |
| if (trng_priv->cb) { |
| trng_priv->cb(TRNG_EVENT_DATA_GENERATE_COMPLETE); |
| } |
| |
| return 0; |
| } |
| |
| /** |
| \brief Get TRNG status. |
| \param[in] handle trng handle to operate. |
| \return TRNG status \ref trng_status_t |
| */ |
| trng_status_t csi_trng_get_status(trng_handle_t handle) |
| { |
| ck_trng_priv_t *trng_priv = handle; |
| return trng_priv->status; |
| } |