/* * 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-irq.h" #include "mailbox.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 void *g_tbl_ao; void *pvClientIdTab; struct xClientMboxChan *pxReeMboxChan; struct xClientMboxChan *pxTeeMboxChan; #ifdef DSPA2AO_CHANNEL struct xClientMboxChan *pxDspaMboxChan; #endif TaskHandle_t ReeMboxHandler; TaskHandle_t TeeMboxHandler; #ifdef DSPA2AO_CHANNEL TaskHandle_t DspMboxHandler; #endif static uint32_t ulReeSyncTaskWake; static uint32_t ulTeeSyncTaskWake; #ifdef DSPA2AO_CHANNEL static uint32_t ulDspSyncTaskWake; #endif struct mboxPackInfo syncReeMboxInfo; struct mboxPackInfo syncTeeMboxInfo; #ifdef DSPA2AO_CHANNEL struct mboxPackInfo syncDspMboxInfo; #endif static void vGetPayload(uint32_t addr, void *data, size_t size) { VALID_BUFFER_SIZE(size); PRINT_DBG("get payload: addr:0x%x\n", (unsigned int)addr); if (data != NULL) vMboxRead(data, 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) vMboxWrite(addr, data, size); } static void vMboxHandleIsr(void) { uint64_t val = 0; uint64_t ulIrqMask = IRQ_MASK; int i = 0; uint64_t ulIrqBitHandled = 0; val = xGetMbIrqStats(); PRINT_DBG("[%s]: mb isr: 0x%llx\n", MBTAG, val); val &= ulIrqMask; while (val) { for (i = 0; i < IRQ_MAX; i++) { if (val & (1ULL << i)) { if (xMbHandlerTable[i].vHandler != NULL) xMbHandlerTable[i].vHandler(xMbHandlerTable[i].vArg); } } ulIrqBitHandled |= val; val = xGetMbIrqStats(); val &= ulIrqMask; val = val ^ (ulIrqBitHandled & val); PRINT_DBG("[%s]: mb isr: 0x%llx\n", MBTAG, val); } } //DECLARE_IRQ(IRQ_NUM_MB_4, vMboxHandleIsr) /* Remote to AOCPU mailbox handler */ static void vAoRevMboxHandler(void *vArg) { BaseType_t xYieldRequired = pdFALSE; uint8_t mbox = (uintptr_t)vArg; struct mboxPackInfo mbInfo = {0}; union MbStat_in st_in; uint32_t ulMbCmd, ulSize, ulSync; uint32_t ulRdAddr = 0; uint32_t ulClrAddr = 0; vDisableMbInterrupt(IRQ_REV_BIT(mbox)); st_in.reg = 0; switch (mbox) { case REE2AO_CHANNEL: st_in.reg = REG32(pxReeMboxChan->pxMboxChan->ulStatAddr); ulRdAddr = pxReeMboxChan->pxMboxChan->ulRdAddr; ulClrAddr = pxReeMboxChan->pxMboxChan->ulClrAddr; break; case TEE2AO_CHANNEL: st_in.reg = REG32(pxTeeMboxChan->pxMboxChan->ulStatAddr); ulRdAddr = pxTeeMboxChan->pxMboxChan->ulRdAddr; ulClrAddr = pxTeeMboxChan->pxMboxChan->ulClrAddr; break; #ifdef DSPA2AO_CHANNEL case DSPA2AO_CHANNEL: st_in.reg = REG32(pxDspaMboxChan->pxMboxChan->ulStatAddr); ulRdAddr = pxDspaMboxChan->pxMboxChan->ulRdAddr; ulClrAddr = pxDspaMboxChan->pxMboxChan->ulClrAddr; break; #endif default: break; } if (st_in.reg == 0 || ulRdAddr == 0) { PRINT_ERR("[%s] invalid mbox status or address!\n", MBTAG); vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(mbox)); vEnableMbInterrupt(IRQ_REV_BIT(mbox)); return; } ulMbCmd = st_in.st.cmd; ulSize = st_in.st.size; ulSync = st_in.st.sync; PRINT_DBG("[%s]:Rev Handler 0x%x, 0x%x, 0x%x\n", MBTAG, ulMbCmd, ulSize, ulSync); if (ulMbCmd == 0) { PRINT_ERR("[%s]:Err: mbox cmd is 0\n", MBTAG); vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(mbox)); vEnableMbInterrupt(IRQ_REV_BIT(mbox)); 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 && (REE2AO_CHANNEL == mbox)) { PRINT_ERR("ulReeSyncTaskWake Busy\n"); break; } if (ulTeeSyncTaskWake && (TEE2AO_CHANNEL == mbox)) { PRINT_ERR("ulTeeSyncTaskWake Busy\n"); break; } #ifdef DSPA2AO_CHANNEL if (ulDspSyncTaskWake && (DSPA2AO_CHANNEL == mbox)) { PRINT_ERR("ulDspSyncTaskWake Busy\n"); break; } #endif PRINT_DBG("[%s]: SYNC\n", MBTAG); mbInfo.ulCmd = ulMbCmd; mbInfo.ulSize = ulSize; if (REE2AO_CHANNEL == mbox) { syncReeMboxInfo = mbInfo; ulReeSyncTaskWake = 1; vTaskNotifyGiveFromISR(ReeMboxHandler, &xYieldRequired); } if (TEE2AO_CHANNEL == mbox) { syncTeeMboxInfo = mbInfo; ulTeeSyncTaskWake = 1; vTaskNotifyGiveFromISR(TeeMboxHandler, &xYieldRequired); } #ifdef DSPA2AO_CHANNEL if (DSPA2AO_CHANNEL == mbox) { syncDspMboxInfo = mbInfo; ulDspSyncTaskWake = 1; vTaskNotifyGiveFromISR(DspMboxHandler, &xYieldRequired); } #endif portYIELD_FROM_ISR(xYieldRequired); break; case MB_ASYNC: #ifdef AO_MBOX_ONLY_SYNC PRINT_DBG("[%s]: ASYNC no support\n", MBTAG); vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(mbox)); vEnableMbInterrupt(IRQ_REV_BIT(mbox)); #endif break; default: PRINT_ERR("[%s]: Not SYNC or ASYNC, Fail\n", MBTAG); vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(mbox)); vEnableMbInterrupt(IRQ_REV_BIT(mbox)); break; } } #ifdef CONFIG_MAILBOX_SEND /* AOCPU to remote mailbox ACK handler */ static void vAoAckMboxHandler(void *vArg) { uint32_t mbox = (uintptr_t)vArg; uint32_t addr = ulRevAddrMbox(mbox); struct mbHeadInfo mbHead; BaseType_t xYieldRequired = pdFALSE; vDisableMbInterrupt(IRQ_SENDACK_BIT(mbox)); 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); vClrMbInterrupt(IRQ_SENDACK_BIT(mbox)); vEnableMbInterrupt(IRQ_SENDACK_BIT(mbox)); portYIELD_FROM_ISR(xYieldRequired); } #endif /* REE to AOCPU mailbox handle task on sync mode */ static void vReeSyncTask(void *pvParameters) { uint32_t ulWrAddr; uint32_t ulClrAddr; uint8_t ucMboxChId; int index = 0; (void)pvParameters; ulWrAddr = pxReeMboxChan->pxMboxChan->ulWrAddr; ulClrAddr = pxReeMboxChan->pxMboxChan->ulClrAddr; ucMboxChId = pxReeMboxChan->pxMboxChan->ucMboxChId; 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, ucMboxChId); if (index != 0) { if (index == MAX_ENTRY_NUM) { memset(&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, ucMboxChId); ulReeSyncTaskWake = 0; vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(ucMboxChId)); vEnableMbInterrupt(IRQ_REV_BIT(ucMboxChId)); vExitCritical(); } } /* TEE to AOCPU mailbox handle task on sync mode */ static void vTeeSyncTask(void *pvParameters) { uint32_t ulWrAddr; uint32_t ulClrAddr; uint8_t ucMboxChId; int index = 0; (void)pvParameters; ulWrAddr = pxTeeMboxChan->pxMboxChan->ulWrAddr; ulClrAddr = pxTeeMboxChan->pxMboxChan->ulClrAddr; ucMboxChId = pxTeeMboxChan->pxMboxChan->ucMboxChId; 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, 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, ucMboxChId); ulTeeSyncTaskWake = 0; vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(ucMboxChId)); vEnableMbInterrupt(IRQ_REV_BIT(ucMboxChId)); vExitCritical(); } } #ifdef DSPA2AO_CHANNEL /* DSP to AOCPU mailbox handle task on sync mode */ static void vDspSyncTask(void *pvParameters) { uint32_t ulWrAddr; uint32_t ulClrAddr; uint8_t ucMboxChId; int index = 0; (void)pvParameters; ulWrAddr = pxDspaMboxChan->pxMboxChan->ulWrAddr; ulClrAddr = pxDspaMboxChan->pxMboxChan->ulClrAddr; ucMboxChId = pxDspaMboxChan->pxMboxChan->ucMboxChId; while (1) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); PRINT_DBG("[%s]:DspSyncTask\n", MBTAG); index = mailbox_htbl_invokeCmd(g_tbl_ao, syncDspMboxInfo.ulCmd, syncDspMboxInfo.mbdata.data); PRINT_DBG("[%s]:mbox:%d\n", MBTAG, ucMboxChId); if (index != 0) { if (index == MAX_ENTRY_NUM) { memset(&syncDspMboxInfo.mbdata.data, 0, sizeof(syncDspMboxInfo.mbdata.data)); syncDspMboxInfo.mbdata.status = ACK_FAIL; if (ulWrAddr) prvBuildPayload(ulWrAddr, &syncDspMboxInfo.mbdata, sizeof(syncDspMboxInfo.mbdata)); PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG); } else { PRINT_DBG("[%s]:DspSync re len:%d\n", MBTAG, sizeof(syncDspMboxInfo.mbdata)); syncDspMboxInfo.mbdata.status = ACK_OK; if (ulWrAddr) prvBuildPayload(ulWrAddr, &syncDspMboxInfo.mbdata, sizeof(syncDspMboxInfo.mbdata)); } } vEnterCritical(); PRINT_DBG("[%s]:DspSync clear mbox:%d\n", MBTAG, ucMboxChId); ulDspSyncTaskWake = 0; vClrMboxStats(ulClrAddr); vClrMbInterrupt(IRQ_REV_BIT(ucMboxChId)); vEnableMbInterrupt(IRQ_REV_BIT(ucMboxChId)); vExitCritical(); } } #endif int iMboxInit(void) { int ret; PRINT("[%s]: mbox 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); #ifdef DSPA2AO_CHANNEL pxDspaMboxChan = xMboxRequestChan(DSPA2AO_DRV); #endif /* Set MBOX IRQ Handler and Priority */ vSetMbIrqHandler(IRQ_REV_NUM(REE2AO_CHANNEL), vAoRevMboxHandler, (void *)REE2AO_CHANNEL, 10); vSetMbIrqHandler(IRQ_REV_NUM(TEE2AO_CHANNEL), vAoRevMboxHandler, (void *)TEE2AO_CHANNEL, 10); #ifdef CONFIG_MAILBOX_SEND vSetMbIrqHandler(IRQ_SENDACK_NUM(AO2REE_CHANNEL), vAoAckMboxHandler, (void *)AO2REE_CHANNEL, 10); #endif #ifdef DSPA2AO_CHANNEL vSetMbIrqHandler(IRQ_REV_NUM(DSPA2AO_CHANNEL), vAoRevMboxHandler, (void *)DSPA2AO_CHANNEL, 10); #ifdef CONFIG_MAILBOX_SEND vSetMbIrqHandler(IRQ_SENDACK_NUM(AO2DSPA_CHANNEL), vAoAckMboxHandler, (void *)AO2DSPA_CHANNEL, 10); #endif #endif /* Register and enable mailbox IRQ */ RegisterIrq(MAILBOX_AOCPU_IRQ, 6, vMboxHandleIsr); EnableIrq(MAILBOX_AOCPU_IRQ); xTaskCreate(vReeSyncTask, "AOReeSyncTask", configMINIMAL_STACK_SIZE, 0, TASK_PRIORITY, (TaskHandle_t *)&ReeMboxHandler); xTaskCreate(vTeeSyncTask, "AOTeeSyncTask", configMINIMAL_STACK_SIZE, 0, TASK_PRIORITY, (TaskHandle_t *)&TeeMboxHandler); #ifdef DSPA2AO_CHANNEL xTaskCreate(vDspSyncTask, "AODspSyncTask", configMINIMAL_STACK_SIZE, 0, TASK_PRIORITY, (TaskHandle_t *)&DspMboxHandler); #endif #ifdef CONFIG_MAILBOX_SEND vInitMboxChLock(); #endif ret = vRpcUserCmdInit(); PRINT("[%s]: mbox 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 = %d\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; memcpy((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]:Err: mbox XEFR msg TMO!\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