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

447 lines
12 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-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