/* * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. * * SPDX-License-Identifier: MIT */ #include #include #include #include #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); }