/* * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and * its subsidiaries and affiliates (collectly called MKSEMI). * * All rights reserved. * * 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, except as embedded into an MKSEMI * integrated circuit in a product or a software update for such product, * 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 MKSEMI nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * 4. This software, with or without modification, must only be used with a * MKSEMI integrated circuit. * * 5. Any software provided in binary form under this license must not be * reverse engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL MKSEMI 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 "mk_trng.h" #include "mk_clock.h" #include "mk_reset.h" static struct TRNG_HANDLE_T trng_handle = { .base = TRNG, .irq = TRNG_IRQn, .cfg = TRNG_CFG_1LSB_VN, .data = 0, .number = 0, .int_en = false, .callback = NULL, }; int trng_open(void) { // enable TRNG clock clock_enable(CLOCK_TRNG); reset_module(RESET_MODULE_TRNG); trng_handle.base->CTRL0 = TRNG_CTRL0_LSB_CFG(trng_handle.cfg); #if TRNG_INT_MODE_EN if (trng_handle.int_en) { NVIC_SetPriority(trng_handle.irq, IRQ_PRIORITY_NORMAL); NVIC_ClearPendingIRQ(trng_handle.irq); NVIC_EnableIRQ(trng_handle.irq); } #endif trng_handle.state = TRNG_STATE_READY; return DRV_OK; } int trng_close(void) { #if TRNG_INT_MODE_EN if (trng_handle.int_en) { NVIC_DisableIRQ(trng_handle.irq); NVIC_ClearPendingIRQ(trng_handle.irq); } #endif // disable TRNG clock clock_disable(CLOCK_TRNG); trng_handle.state = TRNG_STATE_RESET; return DRV_OK; } int trng_get(uint32_t *data, uint32_t number, drv_callback_t callback) { uint32_t lock = int_lock(); // update state switch (trng_handle.state) { case TRNG_STATE_READY: trng_handle.state = TRNG_STATE_BUSY; break; case TRNG_STATE_BUSY: int_unlock(lock); return DRV_BUSY; case TRNG_STATE_RESET: case TRNG_STATE_TIMEOUT: case TRNG_STATE_ERROR: int_unlock(lock); return DRV_ERROR; } trng_handle.data = data; trng_handle.number = number; trng_handle.count = number; trng_handle.callback = callback; int_unlock(lock); if (trng_handle.int_en) { #if TRNG_INT_MODE_EN // enable interrupt trng_handle.base->INTR_EN = TRNG_INTR_EN_MSK; trng_handle.base->CTRL1 = TRNG_CTRL1_TRNG_REQ_MSK; #endif } else { #if TRNG_POLL_MODE_EN // polling while (trng_handle.count > 0) { trng_handle.base->CTRL1 = TRNG_CTRL1_TRNG_REQ_MSK; while ((trng_handle.base->STATUS & TRNG_STATUS_DONE_MSK) == 0) { } for (uint8_t i = 0; i < 4; i++) { if (trng_handle.count) { *trng_handle.data++ = trng_handle.base->DATA[i]; trng_handle.count--; } else { break; } } } // update state trng_handle.state = TRNG_STATE_READY; if (trng_handle.callback) { trng_handle.callback(trng_handle.data - trng_handle.number, trng_handle.number); } #endif } return DRV_OK; } void TRNG_IRQHandler(void) { #if TRNG_INT_MODE_EN trng_handle.base->INTR_CLR = TRNG_INTR_CLR_MSK; for (uint8_t i = 0; i < 4; i++) { if (trng_handle.count) { *trng_handle.data++ = trng_handle.base->DATA[i]; trng_handle.count--; } else { break; } } if (trng_handle.count) { // continue trng_handle.base->CTRL1 = TRNG_CTRL1_TRNG_REQ_MSK; } else { // finished - update state trng_handle.state = TRNG_STATE_READY; if (trng_handle.callback) { trng_handle.callback(trng_handle.data - trng_handle.number, trng_handle.number); } } #endif }