Files
2026-08-24 10:03:24 +08:00

284 lines
6.9 KiB
C

/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <FreeRTOS.h>
#include <semphr.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
//#include "printf.h"
#include "hwcrypto.h"
#include "interrupt.h"
SemaphoreHandle_t dma_mutex;
uint8_t dma_init_done;
struct dma_dsc g_dsc[MAX_DESCRIPTORS] __section(".dma_buffer") __aligned(64);
#if configCryptoDmaUseIsr
SemaphoreHandle_t isr_binary_semaphore;
static inline void prvCryptoDmaInterruptHandler(uint32_t thread __unused)
{
if (thread == cryptCRYPTO_THREAD_IDX) {
BaseType_t xTaskWoken = pdFALSE;
REG32(cryptDMA_STATUS_REG(thread)) = 0xf;
xSemaphoreGiveFromISR(isr_binary_semaphore, &xTaskWoken);
portYIELD_FROM_ISR(xTaskWoken);
} else {
#if AML_CRYPTO_DEBUG
printf("Error: Isr is called with thread(%d), but actual is (%d)\n",
thread, cryptCRYPTO_THREAD_IDX);
#endif
}
}
#endif
static void vDmaInit(void)
{
dma_mutex = xSemaphoreCreateMutex();
REG32(cryptDMA_STATUS_REG(cryptCRYPTO_THREAD_IDX)) = 0xffff;
#if configCryptoDmaUseIsr
//TODO: Register ISR
#endif
if (dma_mutex)
dma_init_done = 1;
if (!dma_init_done)
printf("dma init failed\n");
}
#if AML_CRYPTO_DEBUG
static void prvAmlDmaDebug(struct dma_dsc *dsc __unused,
uint8_t threadidx __unused,
uint32_t nents __unused, const char *msg __unused)
{
uint32_t i = 0;
printf("begin %s\n", msg);
printf("thread reg(%x) = 0x%x\n",
(uintptr_t) (cryptDMA_THREAD_REG(threadidx)),
REG32(cryptDMA_THREAD_REG(threadidx)));
printf("status reg(%x) = 0x%x\n",
(uintptr_t) (cryptDMA_STATUS_REG(threadidx)),
REG32(cryptDMA_STATUS_REG(threadidx)));
printf("main dsc: 0x%x\n", (uintptr_t)dsc);
for (i = 0; i < nents; i++) {
printf("desc (%x) (len) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.length);
printf("desc (%x) (irq) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.irq);
printf("desc (%x) (eoc) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.eoc);
printf("desc (%x) (lop) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.loop);
printf("desc (%x) (mod) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.mode);
printf("desc (%x) (beg) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.begin);
printf("desc (%x) (end) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.end);
printf("desc (%x) (opm) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.op_mode);
printf("desc (%x) (enc) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.enc_sha_only);
printf("desc (%x) (blk) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.block);
printf("desc (%x) (lnk_err) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.link_error);
printf("desc (%x) (own) = 0x%x\n", i,
(int)dsc[i].dsc_cfg.b.owner);
#if DMA_64_BIT
printf("desc (%x) (src) = 0x%llx\n", i, (int)dsc[i].src_addr);
printf("desc (%x) (tgt) = 0x%llx\n", i, (int)dsc[i].tgt_addr);
#else
printf("desc (%x) (src) = 0x%x\n", i, (int)dsc[i].src_addr);
printf("desc (%x) (tgt) = 0x%x\n", i, (int)dsc[i].tgt_addr);
#endif
}
printf("end %s\n", msg);
}
#endif
static int xAmlMemcpyWithDSC(void *dest, const void *src, size_t n)
{
uint32_t i = 0;
uint32_t cnt = 0;
uint32_t nb, b;
const uint32_t thread = cryptCRYPTO_THREAD_IDX;
//printf("%s:%d: main dsc: 0x%x\n", __func__, __LINE__, (uintptr_t)g_dsc);
/* sanity check */
if (!dest || !src || !n)
return -pdFREERTOS_ERRNO_EINVAL;
if ((uintptr_t)dest >= UNSUPPORT_ADDR_START && (uintptr_t)dest < UNSUPPORT_ADDR_END) {
printf("dst(%p) unsupported.\n", dest);
return -pdFREERTOS_ERRNO_EINVAL;
}
if ((uintptr_t)src >= UNSUPPORT_ADDR_START && (uintptr_t)src < UNSUPPORT_ADDR_END) {
printf("src(%p) unsupported.\n", src);
return -pdFREERTOS_ERRNO_EINVAL;
}
if (n > MAX_BYTES_TRANSFER) {
printf("size(%u) too big.\n", n);
return -pdFREERTOS_ERRNO_EINVAL;
}
xSemaphoreTake(dma_mutex, portMAX_DELAY);
memset(&g_dsc, 0, sizeof(g_dsc));
nb = n & (cryptDMA_BLOCK_SIZE - 1);
b = (n - nb) >> cryptDMA_BLOCK_SIZE_SHIFT;
//printf("%s:%d: b(%u) nb(%u)\n", __func__, __LINE__, b, nb);
if (b) {
g_dsc[i].src_addr = (uintptr_t)src;
g_dsc[i].tgt_addr = (uintptr_t)dest;
g_dsc[i].dsc_cfg.d32 = 0;
g_dsc[i].dsc_cfg.b.block = 1; /* block mode */
g_dsc[i].dsc_cfg.b.length = b;
g_dsc[i].dsc_cfg.b.mode = cryptDMA_MODE_DMA; /* copy */
g_dsc[i].dsc_cfg.b.owner = 1;
i++;
}
if (nb) {
g_dsc[i].src_addr = (uintptr_t)((uint8_t *)src + b * cryptDMA_BLOCK_SIZE);
g_dsc[i].tgt_addr = (uintptr_t)((uint8_t *)dest + b * cryptDMA_BLOCK_SIZE);
g_dsc[i].dsc_cfg.d32 = 0;
g_dsc[i].dsc_cfg.b.length = nb;
g_dsc[i].dsc_cfg.b.mode = cryptDMA_MODE_DMA; /* copy */
g_dsc[i].dsc_cfg.b.owner = 1;
i++;
}
g_dsc[i-1].dsc_cfg.b.eoc = 1;
REG32(cryptDMA_STATUS_REG(thread)) = 0xffff;
#if AML_CRYPTO_DEBUG
prvAmlDmaDebug(g_dsc, thread, i, "memcpy start");
#endif
REG32(cryptDMA_THREAD_REG(thread)) = (uintptr_t)&g_dsc | 2;
while ((REG32(cryptDMA_STATUS_REG(thread)) == 0) && cnt < DMA_TIME_OUT)
cnt++;
xSemaphoreGive(dma_mutex);
#if AML_CRYPTO_DEBUG
prvAmlDmaDebug(g_dsc, thread, i, "memcpy end");
#endif
if (REG32(cryptDMA_STATUS_REG(thread)) &
(cryptoDMA_STS_ERROR | cryptoDMA_STS_ERROR_REASON)) {
printf("DMA failed(%x)\n", REG32(cryptDMA_STATUS_REG(thread)));
return -pdFREERTOS_ERRNO_ENXIO;
}
if (cnt >= DMA_TIME_OUT) {
printf("DMA timeout\n");
return -pdFREERTOS_ERRNO_ETIMEDOUT;
}
return pdFREERTOS_ERRNO_NONE;
}
#if AML_CRYPTO_TEST
enum {
SRAM_TO_SRAM = 0,
SRAM_TO_DDR = 1,
DDR_TO_DDR = 2,
DDR_TO_SRAM = 3,
};
static uint8_t from[SZ], to[SZ];
void xDmaTest(uint32_t dir)
{
uint8_t i = 0;
uint8_t *f, *t;
uint32_t printed = 0;
uint32_t ret = 0;
if (dir == SRAM_TO_SRAM) {
#if AML_CRYPTO_DEBUG
printf("Test DMA(SRAM -> SRAM)\n");
#endif
f = from;
t = to;
memset(from, MAGIC, SZ);
memset(to, 0x0, SZ);
} else if (dir == SRAM_TO_DDR) {
#if AML_CRYPTO_DEBUG
printf("Test DMA(sram -> DDR)\n");
#endif
f = from;
t = (uint8_t *)TEST_DDR_OUT;
memset(from, MAGIC, SZ);
} else if (dir == DDR_TO_DDR) {
#if AML_CRYPTO_DEBUG
printf("Test DMA(DDR -> DDR)\n");
#endif
f = (uint8_t *)TEST_DDR_IN;
t = (uint8_t *)TEST_DDR_OUT;
} else if (dir == DDR_TO_SRAM) {
#if AML_CRYPTO_DEBUG
printf("Test DMA(DDR -> SRAM)\n");
#endif
f = (uint8_t *)TEST_DDR_IN;
t = to;
memset(to, 0x0, SZ);
memset(from, MAGIC, SZ);
} else {
#if AML_CRYPTO_DEBUG
printf("Invalid direction %u\n", dir);
#endif
return;
}
if (xAmlMemcpyWithDSC(t, f, SZ) < 0) {
#if AML_CRYPTO_DEBUG
printf("xAmlMemcpyWithDSC failed.\n");
#endif
return;
}
if (dir == SRAM_TO_SRAM)
ret = memcmp(t, f, SZ);
else if (dir == DDR_TO_SRAM)
ret = memcmp(from, t, SZ);
#if AML_CRYPTO_DEBUG
if (ret) {
printf("DMA memcpy failed\n");
} else {
if (dir == SRAM_TO_DDR || dir == DDR_TO_DDR)
printf("Pls check content at addr(%x)\n", TEST_DDR_OUT);
else
printf("DMA memcpy successful.\n");
}
#endif
}
#endif
void vVDMAInit(void)
{
vDmaInit();
}
int xVDMATransfer(struct vdma_info *info)
{
if (!info)
return -pdFREERTOS_ERRNO_EINVAL;
return xAmlMemcpyWithDSC(info->dest, info->src, info->size);
}