/*! \file gd32w51x_hau.c \brief HAU driver \version 2021-10-30, V1.0.0, firmware for GD32W51x */ /* Copyright (c) 2021, GigaDevice Semiconductor Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gd32w51x_hau.h" #include "gd32w51x_rcu.h" #define HASH_CONTEXT_INTERNAL_REG 37U #define HMAC_CONTEXT_INTERNAL_REG 53U /*! \brief reset the HAU peripheral \param[in] none \param[out] none \retval none */ void hau_deinit(void) { /* enable HAU reset state */ rcu_periph_reset_enable(RCU_HAURST); /* release HAU from reset state */ rcu_periph_reset_disable(RCU_HAURST); } /*! \brief initialize the HAU peripheral parameters \param[in] initpara: HAU init parameter struct members of the structure and the member values are shown as below: algo: HAU_ALGO_SHA1, HAU_ALGO_SHA224, HAU_ALGO_SHA256, HAU_ALGO_MD5 mode: HAU_MODE_HASH, HAU_MODE_HMAC datatype: HAU_SWAPPING_32BIT, HAU_SWAPPING_16BIT, HAU_SWAPPING_8BIT, HAU_SWAPPING_1BIT keytype: HAU_KEY_SHORTER_64, HAU_KEY_LONGGER_64 \param[out] none \retval none */ void hau_init(hau_init_parameter_struct* initpara) { /* configure the algorithm, mode and the data type */ HAU_CTL &= ~(HAU_CTL_ALGM_0 | HAU_CTL_ALGM_1 | HAU_CTL_DATAM | HAU_CTL_HMS); HAU_CTL |= (initpara->algo | initpara->datatype | initpara->mode); /* when mode is HMAC, set the key */ if(HAU_MODE_HMAC == initpara->mode){ HAU_CTL &= ~HAU_CTL_KLM; HAU_CTL |= initpara->keytype; } /* start the digest of a new message */ HAU_CTL |= HAU_CTL_START; } /*! \brief initialize the sturct hau_initpara \param[in] initpara: HAU init parameter struct members of the structure and the member values are shown as below: algo: HAU_ALGO_SHA1, HAU_ALGO_SHA224, HAU_ALGO_SHA256, HAU_ALGO_MD5 mode: HAU_MODE_HASH, HAU_MODE_HMAC datatype: HAU_SWAPPING_32BIT, HAU_SWAPPING_16BIT, HAU_SWAPPING_8BIT, HAU_SWAPPING_1BIT keytype: HAU_KEY_SHORTER_64, HAU_KEY_LONGGER_64 \param[out] none \retval none */ void hau_init_struct_para_init(hau_init_parameter_struct* initpara) { initpara->algo = HAU_ALGO_SHA1; initpara->mode = HAU_MODE_HASH; initpara->datatype = HAU_SWAPPING_32BIT; initpara->keytype = HAU_KEY_SHORTER_64; } /*! \brief reset the HAU processor core \param[in] none \param[out] none \retval none */ void hau_reset(void) { /* set to 1 to reset the HAU processor core, then it is ready to start the digest calculation */ HAU_CTL |= HAU_CTL_START; } /*! \brief configure the number of valid bits in last word of the message \param[in] valid_num: number of valid bits in last word of the message only one parameter can be selected which is shown as below: \arg 0x00: all 32 bits of the last data written are valid \arg 0x01: only bit [31] of the last data written to HAU_DI after data swapping are valid \arg 0x02: only bits [31:30] of the last data written to HAU_DI after data swapping are valid \arg 0x03: only bits [31:29] of the last data written to HAU_DI after data swapping are valid ... \arg 0x1F: only bit [0] of the last data written to HAU_DI after data swapping are valid \param[out] none \retval none */ void hau_last_word_validbits_num_config(uint32_t valid_num) { HAU_CFG &= ~(HAU_CFG_VBL); HAU_CFG |= CFG_VBL(valid_num); } /*! \brief write data to the IN FIFO \param[in] data: data to write \param[out] none \retval none */ void hau_data_write(uint32_t data) { HAU_DI = data; } /*! \brief return the number of words already written into the IN FIFO \param[in] none \param[out] none \retval number of words in the input FIFO */ uint32_t hau_infifo_words_num_get(void) { uint32_t ret = 0U; ret = GET_CTL_NWIF(HAU_CTL); return ret; } /*! \brief read the message digest result \param[in] none \param[out] digestpara: HAU digest parameter struct out[7:0]: message digest result 0-7 \retval none */ void hau_digest_read(hau_digest_parameter_struct* digestpara) { digestpara->out[0] = HAU_DO0; digestpara->out[1] = HAU_DO1; digestpara->out[2] = HAU_DO2; digestpara->out[3] = HAU_DO3; digestpara->out[4] = HAU_DO4; digestpara->out[5] = HAU_DO5; digestpara->out[6] = HAU_DO6; digestpara->out[7] = HAU_DO7; } /*! \brief enable digest calculation \param[in] none \param[out] none \retval none */ void hau_digest_calculation_enable(void) { HAU_CFG |= HAU_CFG_CALEN; } /*! \brief configure single or multiple DMA is used, and digest calculation at the end of a DMA transfer or not \param[in] multi_single only one parameter can be selected which is shown as below \arg SINGLE_DMA_AUTO_DIGEST: message padding and message digest calculation at the end of a DMA transfer \arg MULTIPLE_DMA_NO_DIGEST: multiple DMA transfers needed and CALEN bit is not automatically set at the end of a DMA transfer \param[out] none \retval none */ void hau_multiple_single_dma_config(uint32_t multi_single) { HAU_CTL &= ~HAU_CTL_MDS; HAU_CTL |= multi_single; } /*! \brief enable the HAU DMA interface \param[in] none \param[out] none \retval none */ void hau_dma_enable(void) { HAU_CTL |= HAU_CTL_DMAE; } /*! \brief disable the HAU DMA interface \param[in] none \param[out] none \retval none */ void hau_dma_disable(void) { HAU_CTL &= ~HAU_CTL_DMAE; } /*! \brief initialize the struct context \param[in] context: HAU context parameter struct \param[out] none \retval none */ void hau_context_struct_para_init(hau_context_parameter_struct* context) { uint8_t i = 0U; /* initialize context parameter struct */ context->hau_inten_bak = 0U; context->hau_cfg_bak = 0U; context->hau_ctl_bak = 0U; for(i = 0U; i <= HMAC_CONTEXT_INTERNAL_REG; i++){ context->hau_ctxs_bak[i] = 0U; } } /*! \brief save the HAU peripheral context \param[in] none \param[out] context_save: pointer to a hau_context structure that contains the repository for current context \retval none */ void hau_context_save(hau_context_parameter_struct* context_save) { uint8_t i = 0U; uint8_t i_max = HASH_CONTEXT_INTERNAL_REG; hau_context_struct_para_init(context_save); /* save context registers */ context_save->hau_inten_bak = HAU_INTEN; context_save->hau_cfg_bak = HAU_CFG; context_save->hau_ctl_bak = HAU_CTL; if(0U != (HAU_CTL & HAU_CTL_HMS)){ i_max = HMAC_CONTEXT_INTERNAL_REG; } for(i = 0U; i <= i_max; i++){ context_save->hau_ctxs_bak[i] = HAU_CTXS(i); } } /*! \brief restore the HAU peripheral context \param[in] context_restore: pointer to a hau_context_parameter_struct structure that contains the repository for saved context \param[out] none \retval none */ void hau_context_restore(hau_context_parameter_struct* context_restore) { uint8_t i = 0U; uint8_t i_max = HASH_CONTEXT_INTERNAL_REG; /* restore context registers */ HAU_INTEN = context_restore->hau_inten_bak; HAU_CFG = context_restore->hau_cfg_bak; HAU_CTL = context_restore->hau_ctl_bak; /* Initialize the hash processor */ HAU_CTL |= HAU_CTL_START; /* continue restoring context registers */ if(0U != (HAU_CTL & HAU_CTL_HMS)){ i_max = HMAC_CONTEXT_INTERNAL_REG; } for(i = 0U; i <= i_max; i++){ HAU_CTXS(i) = context_restore->hau_ctxs_bak[i]; } } /*! \brief get the HAU flag status \param[in] flag: HAU flag status only one parameter can be selected which is shown as below: \arg HAU_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO \arg HAU_FLAG_CALCULATION_COMPLETE: digest calculation is completed \arg HAU_FLAG_DMA: DMA is enabled (DMAE =1) or a transfer is processing \arg HAU_FLAG_BUSY: data block is in process \arg HAU_FLAG_INFIFO_NO_EMPTY: the input FIFO is not empty \param[out] none \retval FlagStatus: SET or RESET */ FlagStatus hau_flag_get(uint32_t flag) { uint32_t ret = 0U; FlagStatus ret_flag = RESET; /* check if the flag is in HAU_CTL register */ if(RESET != (flag & HAU_FLAG_INFIFO_NO_EMPTY)){ ret = HAU_CTL; }else{ ret = HAU_STAT; } if (RESET != (ret & flag)){ ret_flag = SET; } return ret_flag; } /*! \brief clear the HAU flag status \param[in] flag: HAU flag status one or more parameters can be selected which are shown as below \arg HAU_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO \arg HAU_FLAG_CALCULATION_COMPLETE: digest calculation is completed \param[out] none \retval none */ void hau_flag_clear(uint32_t flag) { HAU_STAT = ~(uint32_t)(flag); } /*! \brief enable the HAU interrupts \param[in] interrupt: specify the HAU interrupt source to be enabled one or more parameters can be selected which are shown as below \arg HAU_INT_DATA_INPUT: a new block can be entered into the IN buffer \arg HAU_INT_CALCULATION_COMPLETE: calculation complete \param[out] none \retval none */ void hau_interrupt_enable(uint32_t interrupt) { HAU_INTEN |= interrupt; } /*! \brief disable the HAU interrupts \param[in] interrupt: specify the HAU interrupt source to be disabled one or more parameters can be selected which are shown as below \arg HAU_INT_DATA_INPUT: a new block can be entered into the IN buffer \arg HAU_INT_CALCULATION_COMPLETE: calculation complete \param[out] none \retval none */ void hau_interrupt_disable(uint32_t interrupt) { HAU_INTEN &= ~(uint32_t)(interrupt); } /*! \brief get the HAU interrupt flag status \param[in] int_flag: HAU interrupt flag status only one parameter can be selected which is shown as below \arg HAU_INT_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO \arg HAU_INT_FLAG_CALCULATION_COMPLETE: digest calculation is completed \param[out] none \retval FlagStatus: SET or RESET */ FlagStatus hau_interrupt_flag_get(uint32_t int_flag) { uint32_t ret = 0U; FlagStatus flag = RESET; /* return the status of the interrupt */ ret = HAU_STAT; if(RESET != ((HAU_INTEN & ret) & int_flag)){ flag = SET; } return flag; } /*! \brief clear the HAU interrupt flag status \param[in] int_flag: HAU interrupt flag status one or more parameters can be selected which are shown as below \arg HAU_INT_FLAG_DATA_INPUT: there is enough space (16 bytes) in the input FIFO \arg HAU_INT_FLAG_CALCULATION_COMPLETE: digest calculation is completed \param[out] none \retval none */ void hau_interrupt_flag_clear(uint32_t int_flag) { HAU_STAT = ~(uint32_t)(int_flag); }