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

502 lines
14 KiB
C

/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include <unistd.h>
#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