/* * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. * * SPDX-License-Identifier: MIT */ #include #include #include #include #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" #include #include "n200_eclic.h" #include "n200_func.h" #include "uart.h" #include "common.h" #include "riscv_encoding.h" #include "mailbox-common.h" #include "mailbox_soc.h" #include "mailbox-pl.h" #include "mailbox-htbl.h" #include "mailbox-api.h" #include "mailbox-rpc-test.h" #define MBTAG "AOCPU" #define PRINT_DBG(...) //printf(__VA_ARGS__) #define PRINT_ERR(...) printf(__VA_ARGS__) #define PRINT(...) printf(__VA_ARGS__) #define AO_MBOX_ONLY_SYNC 1 #define MHU_MB_TASK_PRIORITIES (configMAX_PRIORITIES - 1) void *g_tbl_ao; void *pvClientIdTab; struct xClientMboxChan *pxReeMboxChan; struct xClientMboxChan *pxTeeMboxChan; TaskHandle_t ReeMboxHandler; TaskHandle_t TeeMboxHandler; static uint32_t ulReeSyncTaskWake; static uint32_t ulTeeSyncTaskWake; struct mboxPackInfo syncReeMboxInfo; struct mboxPackInfo syncTeeMboxInfo; static void vGetPayload(uint32_t addr, void *data, size_t size) { VALID_BUFFER_SIZE(size); PRINT_DBG("%s: addr:0x%x, 0x%x\n", __func__, (unsigned int)addr, size); if (data != NULL) pvMboxMemCpy((void *)(uintptr_t)data, (void *)(uintptr_t)addr, size); } static void prvBuildPayload(uint32_t addr, void *data, size_t size) { VALID_BUFFER_SIZE(size); PRINT_DBG("%s: addr:0x%x\n", __func__, (unsigned int)addr); if (data != NULL) { pvMboxMemSet((void *)(uintptr_t)addr, 0, MAILBOX_BUFFER_SIZE); pvMboxMemCpy((void *)(uintptr_t)addr, (void *)(uintptr_t)data, size); } } /* ARMTEE to AOCPU mailbox handler */ static void vAoRevTeeMboxHandler(uint32_t mbox) { (void)mbox; BaseType_t xYieldRequired = pdFALSE; struct mboxPackInfo mbInfo; union MbStat_in st_in; uint32_t ulMbCmd, ulSize, ulSync; uint32_t ulRdAddr = 0; uint32_t ulClrAddr = 0; DisableIrq(MAILBOX_AOCPU_TEE_IRQ); PRINT_DBG("[%s]: TeeMbox 0x%x\n", MBTAG, (unsigned int)mbox); st_in.reg = REG32(pxTeeMboxChan->pxMboxChan->ulStatAddr); ulRdAddr = pxTeeMboxChan->pxMboxChan->ulRdAddr; ulClrAddr = pxTeeMboxChan->pxMboxChan->ulClrAddr; if (st_in.reg == 0 || ulRdAddr == 0) { PRINT_ERR("[%s] invalid mbox status or address!\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ); EnableIrq(MAILBOX_AOCPU_TEE_IRQ); return; } ulMbCmd = st_in.st.cmd; ulSize = st_in.st.size; ulSync = st_in.st.sync; PRINT_DBG("[%s]: 0x%x, 0x%x, 0x%x, 0x%x\n", MBTAG, (unsigned int)mbox, (unsigned int)ulMbCmd, (unsigned int)ulSize, (unsigned int)ulSync); if (ulMbCmd == 0) { PRINT_ERR("[%s]: Err: mbox cmd is 0\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ); EnableIrq(MAILBOX_AOCPU_TEE_IRQ); return; } if (ulSize != 0) vGetPayload(ulRdAddr, &mbInfo.mbdata, ulSize); PRINT_DBG("%s taskid: 0x%llx\n", MBTAG, mbInfo.mbdata.taskid); PRINT_DBG("%s complete: 0x%llx\n", MBTAG, mbInfo.mbdata.complete); PRINT_DBG("%s ullclt: 0x%llx\n", MBTAG, mbInfo.mbdata.ullclt); switch (ulSync) { case MB_SYNC: if (ulTeeSyncTaskWake) { PRINT_ERR("TeeSyncTaskWake Busy\n"); break; } PRINT_DBG("[%s]: SYNC\n", MBTAG); mbInfo.ulCmd = ulMbCmd; mbInfo.ulSize = ulSize; pvMboxMemCpy(&syncTeeMboxInfo, &mbInfo, sizeof(syncTeeMboxInfo)); ; vTaskNotifyGiveFromISR(TeeMboxHandler, &xYieldRequired); portYIELD_FROM_ISR(xYieldRequired); break; case MB_ASYNC: #ifdef AO_MBOX_ONLY_SYNC PRINT_DBG("[%s]: ASYNC no support\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_TEE_IRQ); #endif break; default: PRINT_ERR("[%s]: Not SYNC or ASYNC, Fail\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ); EnableIrq(MAILBOX_AOCPU_TEE_IRQ); break; } } /* TEE to AOCPU mailbox handle task on sync mode */ static void vTeeSyncTask(void *pvParameters) { uint32_t ulWrAddr; uint32_t ulClrAddr; int index = 0; (void)pvParameters; ulWrAddr = pxTeeMboxChan->pxMboxChan->ulWrAddr; ulClrAddr = pxTeeMboxChan->pxMboxChan->ulClrAddr; while (1) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); PRINT_DBG("[%s]:TeeSyncTask\n", MBTAG); index = mailbox_htbl_invokeCmd(g_tbl_ao, syncTeeMboxInfo.ulCmd, syncTeeMboxInfo.mbdata.data); PRINT_DBG("[%s]:mbox:%d\n", MBTAG, pxTeeMboxChan->pxMboxChan->ucMboxChId); if (index != 0) { if (index == MAX_ENTRY_NUM) { pvMboxMemSet(&syncTeeMboxInfo.mbdata.data, 0, sizeof(syncTeeMboxInfo.mbdata.data)); syncTeeMboxInfo.mbdata.status = ACK_FAIL; if (ulWrAddr) prvBuildPayload(ulWrAddr, &syncTeeMboxInfo.mbdata, sizeof(syncTeeMboxInfo.mbdata)); PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG); } else { PRINT_DBG("[%s]:TeeSync re len:%d\n", MBTAG, sizeof(syncTeeMboxInfo.mbdata)); syncTeeMboxInfo.mbdata.status = ACK_OK; if (ulWrAddr) prvBuildPayload(ulWrAddr, &syncTeeMboxInfo.mbdata, sizeof(syncTeeMboxInfo.mbdata)); } } vEnterCritical(); PRINT_DBG("[%s]:TeeSync clear mbox:%d\n", MBTAG, pxTeeMboxChan->pxMboxChan->ucMboxChId); ulTeeSyncTaskWake = 0; vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ); EnableIrq(MAILBOX_AOCPU_TEE_IRQ); vExitCritical(); } } /* ARMREE to AOCPU mailbox handler */ static void vAoRevReeMboxHandler(uint32_t mbox) { (void)mbox; BaseType_t xYieldRequired = pdFALSE; struct mboxPackInfo mbInfo; union MbStat_in st_in; uint32_t ulMbCmd, ulSize, ulSync; uint32_t ulRdAddr = 0; uint32_t ulClrAddr = 0; DisableIrq(MAILBOX_AOCPU_REE_IRQ); PRINT_DBG("[%s]: Reembox %d\n", MBTAG, mbox); st_in.reg = REG32(pxReeMboxChan->pxMboxChan->ulStatAddr); ulRdAddr = pxReeMboxChan->pxMboxChan->ulRdAddr; ulClrAddr = pxReeMboxChan->pxMboxChan->ulClrAddr; if (st_in.reg == 0 || ulRdAddr == 0) { PRINT_ERR("[%s] invalid mbox status or address!\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_REE_IRQ); return; } ulMbCmd = st_in.st.cmd; ulSize = st_in.st.size; ulSync = st_in.st.sync; PRINT_DBG("[%s]: 0x%x, 0x%x, 0x%x, 0x%x\n", MBTAG, (unsigned int)mbox, (unsigned int)ulMbCmd, (unsigned int)ulSize, (unsigned int)ulSync); if (ulMbCmd == 0) { PRINT_DBG("[%s]:Err: mbox cmd is 0\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_REE_IRQ); return; } if (ulSize != 0) vGetPayload(ulRdAddr, &mbInfo.mbdata, ulSize); PRINT_DBG("%s taskid: 0x%llx\n", MBTAG, mbInfo.mbdata.taskid); PRINT_DBG("%s complete: 0x%llx\n", MBTAG, mbInfo.mbdata.complete); PRINT_DBG("%s ullclt: 0x%llx\n", MBTAG, mbInfo.mbdata.ullclt); switch (ulSync) { case MB_SYNC: if (ulReeSyncTaskWake) { PRINT("ulReeSyncTaskWake Busy\n"); break; } PRINT_DBG("[%s]: SYNC\n", MBTAG); ulReeSyncTaskWake = 1; mbInfo.ulCmd = ulMbCmd; mbInfo.ulSize = ulSize; pvMboxMemCpy(&syncReeMboxInfo, &mbInfo, sizeof(syncReeMboxInfo)); vTaskNotifyGiveFromISR(ReeMboxHandler, &xYieldRequired); portYIELD_FROM_ISR(xYieldRequired); break; case MB_ASYNC: #ifdef AO_MBOX_ONLY_SYNC PRINT_ERR("[%s]: ASYNC no support\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_REE_IRQ); #endif break; default: PRINT_ERR("[%s]: Not SYNC or ASYNC, Fail\n", MBTAG); vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_REE_IRQ); break; } } #ifdef CONFIG_MAILBOX_SEND /* AOCPU to remote mailbox ACK handler */ static void vAoAckMboxHandler(uint32_t mbox) { uint32_t addr = ulRevAddrMbox(mbox); struct mbHeadInfo mbHead; BaseType_t xYieldRequired = pdFALSE; DisableIrq(MAILBOX_AOCPU_REEACK_IRQ); PRINT_DBG("[%s]: AO ACK handler, mboxid = %d\n", MBTAG, (unsigned int)mbox); xGetPayloadHead(addr, &mbHead); if (mbHead.taskid) vTaskNotifyGiveFromISR((TaskHandle_t)((uint32_t)mbHead.taskid), &xYieldRequired); ClearPendingIrq(MAILBOX_AOCPU_REEACK_IRQ); EnableIrq(MAILBOX_AOCPU_REEACK_IRQ); portYIELD_FROM_ISR(xYieldRequired); } #endif static void vReeSyncTask(void *pvParameters) { uint32_t ulWrAddr; uint32_t ulClrAddr; int index = 0; (void)pvParameters; ulWrAddr = pxReeMboxChan->pxMboxChan->ulWrAddr; ulClrAddr = pxReeMboxChan->pxMboxChan->ulClrAddr; while (1) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); PRINT_DBG("[%s]:ReeSyncTask\n", MBTAG); index = mailbox_htbl_invokeCmd(g_tbl_ao, syncReeMboxInfo.ulCmd, syncReeMboxInfo.mbdata.data); PRINT_DBG("[%s]:mbox:%d\n", MBTAG, pxReeMboxChan->pxMboxChan->ucMboxChId); if (index != 0) { if (index == MAX_ENTRY_NUM) { pvMboxMemSet(&syncReeMboxInfo.mbdata.data, 0, sizeof(syncReeMboxInfo.mbdata.data)); syncReeMboxInfo.mbdata.status = ACK_FAIL; if (ulWrAddr) prvBuildPayload(ulWrAddr, &syncReeMboxInfo.mbdata, sizeof(syncReeMboxInfo.mbdata)); PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG); } else { PRINT_DBG("[%s]:ReeSync re len:%d\n", MBTAG, sizeof(syncReeMboxInfo.mbdata)); syncReeMboxInfo.mbdata.status = ACK_OK; if (ulWrAddr) prvBuildPayload(ulWrAddr, &syncReeMboxInfo.mbdata, sizeof(syncReeMboxInfo.mbdata)); } } vEnterCritical(); PRINT_DBG("[%s]:ReeSync clear mbox:%d\n", MBTAG, pxReeMboxChan->pxMboxChan->ucMboxChId); ulReeSyncTaskWake = 0; vClrMboxStats(ulClrAddr); ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_REE_IRQ); vExitCritical(); } } static void vMboxHandleReeIsr(void) { vAoRevReeMboxHandler(REE2AO_CHANNEL); } #ifdef CONFIG_MAILBOX_SEND static void vMboxHandleReeAckIsr(void) { vAoAckMboxHandler(AO2REE_CHANNEL); } #endif static void vMboxHandleTeeIsr(void) { vAoRevTeeMboxHandler(TEE2AO_CHANNEL); } int iMboxInit(void) { int ret; PRINT("[%s]: mbox pl init\n", MBTAG); mailbox_htbl_init(&g_tbl_ao); iMboxClientIdTabInit(&pvClientIdTab); /* Request mailbox channel for remote core to AOCPU */ pxReeMboxChan = xMboxRequestChan(REE2AO_DRV); pxTeeMboxChan = xMboxRequestChan(TEE2AO_DRV); /* Register and enable mailbox IRQ */ RegisterIrq(MAILBOX_AOCPU_REE_IRQ, 6, vMboxHandleReeIsr); RegisterIrq(MAILBOX_AOCPU_TEE_IRQ, 6, vMboxHandleTeeIsr); #ifdef CONFIG_MAILBOX_SEND RegisterIrq(MAILBOX_AOCPU_REEACK_IRQ, 6, vMboxHandleReeAckIsr); EnableIrq(MAILBOX_AOCPU_REEACK_IRQ); #endif EnableIrq(MAILBOX_AOCPU_REE_IRQ); EnableIrq(MAILBOX_AOCPU_TEE_IRQ); xTaskCreate(vTeeSyncTask, "AoTeeSyncTask", configMINIMAL_STACK_SIZE, 0, MHU_MB_TASK_PRIORITIES, (TaskHandle_t *)&TeeMboxHandler); xTaskCreate(vReeSyncTask, "AoReeSyncTask", configMINIMAL_STACK_SIZE, 0, MHU_MB_TASK_PRIORITIES, (TaskHandle_t *)&ReeMboxHandler); #ifdef CONFIG_MAILBOX_SEND vInitMboxChLock(); #endif ret = vRpcUserCmdInit(); PRINT("[%s]: mbox pl init end\n", MBTAG); return ret; } #ifdef CONFIG_MAILBOX_SEND int iMboxTransData(struct xClientMboxChan *pxChan, struct xMboxData *pxData) { struct mboxData xMboxData; uint32_t ulSize; union MbStat_in xMboxStatIn; struct MbStat *pxMboxStat; uint32_t ulVal = 0; uint8_t ucChId; uint8_t ucClientId; int iRet = 0; ucClientId = pxChan->ucClientChId; ucChId = pxChan->pxMboxChan->ucMboxChId; SEND_VALID_CHANNEL(ucChId); PRINT_DBG("[%s]: mboxid = %ld\n", MBTAG, ucChId); PRINT_DBG("[%s]: cmd = 0x%x\n", MBTAG, (unsigned int)pxData->ulCmd); PRINT_DBG("[%s]: set_addr = 0x%x\n", MBTAG, (unsigned int)pxChan->pxMboxChan->ulSetAddr); xMuteLock(pxChan->pxMboxChan->xLock); ulSize = pxData->ucTxSize + sizeof(struct mbHeadInfo); pxMboxStat = &xMboxStatIn.st; pxMboxStat->cmd = pxData->ulCmd; pxMboxStat->size = ulSize; pxMboxStat->sync = MB_ASYNC; strncpy((char *)xMboxData.data, pxData->pvTxbuf, pxData->ucTxSize); xMboxData.taskid = (uint32_t)(void *)xTaskGetCurrentTaskHandle(); xMboxData.status = ucClientId; xMboxData.complete = 0; prvBuildPayload(pxChan->pxMboxChan->ulWrAddr, &xMboxData, ulSize); PRINT_DBG("[%s]: set command 0x%x\n", MBTAG, pxMboxStat->cmd); vSetMboxStats(pxChan->pxMboxChan->ulSetAddr, xMboxStatIn.st); ulVal = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(3000)); if (ulVal == 0) { PRINT_ERR("[%s]: mailbox transfer message time out!\n", MBTAG); xMboxData.taskid = 0; xMboxData.status = 0; prvBuildPayload(pxChan->pxMboxChan->ulWrAddr, &xMboxData, ulSize); xMboxStatIn.reg = 0; vSetMboxStats(pxChan->pxMboxChan->ulSetAddr, xMboxStatIn.st); iRet = ERR_MBOX(ETIME); } else { PRINT_DBG("[%s]: task wait ACK done\n", MBTAG); iRet = pdTRUE; } xMuteUnlock(pxChan->pxMboxChan->xLock); return iRet; } #endif