Files
kernel_amazon_mt8127-common/drivers/misc/mediatek/cmdq/cmdq_test.c
T
2018-03-13 20:30:12 +01:00

2558 lines
66 KiB
C

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <mach/mt_clkmgr.h>
#include <mach/memory.h>
#include "cmdq_record.h"
#include "cmdq_reg.h"
#include "cmdq_core.h"
#include "cmdq_device.h"
#include "cmdq_platform.h"
#include "cmdq_mdp.h"
#define CMDQ_TEST
#ifdef CMDQ_TEST
/* test configuration */
static DEFINE_MUTEX(gCmdqTestProcLock);
static int32_t gCmdqTestConfig[2] = { 0, 0 }; /* {test case, type(normal, secure)} */
static bool gCmdqTestSecure = false;
extern unsigned long msleep_interruptible(unsigned int msecs);
#ifdef _CMDQ_TEST_PROC_
static struct proc_dir_entry *gCmdqTestProcEntry;
#endif
extern int32_t cmdq_core_suspend_HW_thread(int32_t thread);
extern int32_t cmdq_append_command(cmdqRecHandle handle, CMDQ_CODE_ENUM code, uint32_t argA,
uint32_t argB);
extern int32_t cmdq_rec_finalize_command(cmdqRecHandle handle, bool loop);
extern int32_t cmdq_rec_setup_sec_data_of_command_desc_by_rec_handle(
cmdqCommandStruct *pDesc, cmdqRecHandle handle);
extern int32_t cmdq_rec_setup_profile_marker_data(cmdqCommandStruct *pDesc, cmdqRecHandle handle);
static int32_t _test_submit_async(cmdqRecHandle handle, TaskStruct **ppTask)
{
cmdqCommandStruct desc = {
.scenario = handle->scenario,
.priority = handle->priority,
.engineFlag = handle->engineFlag,
.pVABase = (cmdqU32Ptr_t)(unsigned long)handle->pBuffer,
.blockSize = handle->blockSize,
};
/* secure path */
cmdq_rec_setup_sec_data_of_command_desc_by_rec_handle(&desc, handle);
/* profile marker */
cmdq_rec_setup_profile_marker_data(&desc, handle);
return cmdqCoreSubmitTaskAsync(&desc, NULL, 0, ppTask);
}
static void testcase_scenario(void)
{
cmdqRecHandle hRec;
int32_t ret;
int i = 0;
CMDQ_MSG("%s\n", __func__);
/* make sure each scenario runs properly with empty commands */
for (i = 0; i < CMDQ_MAX_SCENARIO_COUNT; ++i) {
if (cmdq_core_is_request_from_user_space(i)) {
continue;
}
CMDQ_MSG("testcase_scenario id:%d\n", i);
cmdqRecCreate((CMDQ_SCENARIO_ENUM) i, &hRec);
cmdqRecReset(hRec);
cmdqRecSetSecure(hRec, false);
ret = cmdqRecFlush(hRec);
cmdqRecDestroy(hRec);
}
CMDQ_MSG("%s END\n", __func__);
return;
}
static struct timer_list timer;
static void _testcase_sync_token_timer_func(unsigned long data)
{
CMDQ_MSG("%s\n", __func__);
/* trigger sync event */
CMDQ_MSG("trigger event=0x%08lx\n", (1L << 16) | data);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | data);
}
static void _testcase_sync_token_timer_loop_func(unsigned long data)
{
CMDQ_MSG("%s\n", __func__);
/* trigger sync event */
CMDQ_MSG("trigger event=0x%08lx\n", (1L << 16) | data);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | data);
/* repeate timeout until user delete it */
mod_timer(&timer, jiffies + msecs_to_jiffies(10));
}
static void testcase_sync_token(void)
{
cmdqRecHandle hRec;
int32_t ret = 0;
CMDQ_MSG("%s\n", __func__);
do {
cmdqRecCreate(CMDQ_SCENARIO_SUB_DISP, &hRec);
cmdqRecReset(hRec);
cmdqRecSetSecure(hRec, gCmdqTestSecure);
/* setup timer to trigger sync token */
setup_timer(&timer, &_testcase_sync_token_timer_func, CMDQ_SYNC_TOKEN_USER_0);
mod_timer(&timer, jiffies + msecs_to_jiffies(1000));
/* wait for sync token */
cmdqRecWait(hRec, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("start waiting\n");
ret = cmdqRecFlush(hRec);
cmdqRecDestroy(hRec);
CMDQ_MSG("waiting done\n");
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
del_timer(&timer);
} while (0);
CMDQ_MSG("%s, timeout case\n", __func__);
/* */
/* test for timeout */
/* */
do {
cmdqRecCreate(CMDQ_SCENARIO_SUB_DISP, &hRec);
cmdqRecReset(hRec);
cmdqRecSetSecure(hRec, gCmdqTestSecure);
/* wait for sync token */
cmdqRecWait(hRec, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("start waiting\n");
ret = cmdqRecFlush(hRec);
cmdqRecDestroy(hRec);
CMDQ_MSG("waiting done\n");
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
BUG_ON(ret >= 0);
} while (0);
CMDQ_MSG("%s END\n", __func__);
}
static struct timer_list timer_reqA;
static struct timer_list timer_reqB;
static void testcase_async_suspend_resume(void)
{
cmdqRecHandle hReqA;
TaskStruct *pTaskA;
int32_t ret = 0;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
/* setup_timer(&timer_reqA, &_testcase_sync_token_timer_func, CMDQ_SYNC_TOKEN_USER_0); */
/* mod_timer(&timer_reqA, jiffies + msecs_to_jiffies(300)); */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
do {
/* let this thread wait for user token, then finish */
cmdqRecCreate(CMDQ_SCENARIO_PRIMARY_ALL, &hReqA);
cmdqRecReset(hReqA);
cmdqRecSetSecure(hReqA, gCmdqTestSecure);
cmdqRecWait(hReqA, CMDQ_SYNC_TOKEN_USER_0);
cmdq_append_command(hReqA, CMDQ_CODE_EOC, 0, 1);
cmdq_append_command(hReqA, CMDQ_CODE_JUMP, 0, 8);
ret = _test_submit_async(hReqA, &pTaskA);
CMDQ_MSG("%s pTask %p, engine:0x%llx, scenario:%d\n",
__func__, pTaskA, pTaskA->engineFlag, pTaskA->scenario);
CMDQ_MSG("%s start suspend+resume thread 0========\n", __func__);
cmdq_core_suspend_HW_thread(0);
CMDQ_REG_SET32(CMDQ_THR_SUSPEND_TASK(0), 0x00); /* resume */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(500);
CMDQ_MSG("%s start wait A========\n", __func__);
ret = cmdqCoreWaitAndReleaseTask(pTaskA, 500);
} while (0);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdqRecDestroy(hReqA);
/* del_timer(&timer_reqA); */
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_errors(void)
{
cmdqRecHandle hReq;
cmdqRecHandle hLoop;
TaskStruct *pTask;
int32_t ret;
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
const uint32_t UNKNOWN_OP = 0x50;
uint32_t *pCommand;
ret = 0;
do {
/* SW timeout */
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
cmdqRecCreate(CMDQ_SCENARIO_TRIGGER_LOOP, &hLoop);
cmdqRecReset(hLoop);
cmdqRecSetSecure(hLoop, false);
cmdqRecPoll(hLoop, CMDQ_TEST_MMSYS_DUMMY_PA, 1, 0xFFFFFFFF);
cmdqRecStartLoop(hLoop);
CMDQ_MSG("=============== INIFINITE Wait ===================\n");
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_EVENT_MDP_RSZ0_EOF);
cmdqRecCreate(CMDQ_SCENARIO_PRIMARY_DISP, &hReq);
/* turn on ALL engine flag to test dump */
for (ret = 0; ret < CMDQ_MAX_ENGINE_COUNT; ++ret) {
hReq->engineFlag |= 1LL << ret;
}
cmdqRecReset(hReq);
cmdqRecSetSecure(hReq, gCmdqTestSecure);
cmdqRecWait(hReq, CMDQ_EVENT_MDP_RSZ0_EOF);
cmdqRecFlush(hReq);
CMDQ_MSG("=============== INIFINITE JUMP ===================\n");
/* HW timeout */
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_EVENT_MDP_RSZ0_EOF);
cmdqRecReset(hReq);
cmdqRecSetSecure(hReq, gCmdqTestSecure);
cmdqRecWait(hReq, CMDQ_EVENT_MDP_RSZ0_EOF);
cmdq_append_command(hReq, CMDQ_CODE_JUMP, 0, 8); /* JUMP to connect tasks */
ret = _test_submit_async(hReq, &pTask);
msleep_interruptible(500);
ret = cmdqCoreWaitAndReleaseTask(pTask, 8000);
CMDQ_MSG("================ POLL INIFINITE ====================\n");
CMDQ_MSG("testReg: %lx\n", MMSYS_DUMMY_REG);
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0x0);
cmdqRecReset(hReq);
cmdqRecSetSecure(hReq, gCmdqTestSecure);
cmdqRecPoll(hReq, CMDQ_TEST_MMSYS_DUMMY_PA, 1, 0xFFFFFFFF);
cmdqRecFlush(hReq);
CMDQ_MSG("================= INVALID INSTR =================\n");
/* invalid instruction */
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
cmdqRecReset(hReq);
cmdqRecSetSecure(hReq, gCmdqTestSecure);
cmdq_append_command(hReq, CMDQ_CODE_JUMP, -1, 0);
cmdqRecFlush(hReq);
CMDQ_MSG("================= INVALID INSTR: UNKNOWN OP(0x%x) =================\n",
UNKNOWN_OP);
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
/* invalid instruction is asserted when unkown OP */
cmdqRecReset(hReq);
cmdqRecSetSecure(hReq, gCmdqTestSecure);
{
pCommand = (uint32_t *) ((uint8_t *) hReq->pBuffer + hReq->blockSize);
*pCommand++ = 0x0;
*pCommand++ = (UNKNOWN_OP << 24);
hReq->blockSize += 8;
}
cmdqRecFlush(hReq);
} while (0);
cmdqRecDestroy(hReq);
cmdqRecDestroy(hLoop);
CMDQ_MSG("%s END\n", __func__);
return;
}
static int32_t finishCallback(unsigned long data)
{
CMDQ_LOG("callback() with data=0x%08lx\n", data);
return 0;
}
static void testcase_fire_and_forget(void)
{
cmdqRecHandle hReqA, hReqB;
CMDQ_MSG("%s\n", __func__);
do {
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &hReqA);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &hReqB);
cmdqRecReset(hReqA);
cmdqRecReset(hReqB);
cmdqRecSetSecure(hReqA, gCmdqTestSecure);
cmdqRecSetSecure(hReqB, gCmdqTestSecure);
CMDQ_MSG("%s %d\n", __func__, __LINE__);
cmdqRecFlushAsync(hReqA);
CMDQ_MSG("%s %d\n", __func__, __LINE__);
cmdqRecFlushAsyncCallback(hReqB, finishCallback, 443);
CMDQ_MSG("%s %d\n", __func__, __LINE__);
} while (0);
cmdqRecDestroy(hReqA);
cmdqRecDestroy(hReqB);
CMDQ_MSG("%s END\n", __func__);
}
static struct timer_list timer_reqA;
static struct timer_list timer_reqB;
static void testcase_async_request(void)
{
cmdqRecHandle hReqA, hReqB;
TaskStruct *pTaskA, *pTaskB;
int32_t ret = 0;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
setup_timer(&timer_reqA, &_testcase_sync_token_timer_func, CMDQ_SYNC_TOKEN_USER_0);
mod_timer(&timer_reqA, jiffies + msecs_to_jiffies(1000));
setup_timer(&timer_reqB, &_testcase_sync_token_timer_func, CMDQ_SYNC_TOKEN_USER_1);
/* mod_timer(&timer_reqB, jiffies + msecs_to_jiffies(1300)); */
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_1);
do {
cmdqRecCreate(CMDQ_SCENARIO_SUB_DISP, &hReqA);
cmdqRecReset(hReqA);
cmdqRecSetSecure(hReqA, gCmdqTestSecure);
cmdqRecWait(hReqA, CMDQ_SYNC_TOKEN_USER_0);
cmdq_append_command(hReqA, CMDQ_CODE_EOC, 0, 1);
cmdq_append_command(hReqA, CMDQ_CODE_JUMP, 0, 8);
cmdqRecCreate(CMDQ_SCENARIO_SUB_DISP, &hReqB);
cmdqRecReset(hReqB);
cmdqRecSetSecure(hReqB, gCmdqTestSecure);
cmdqRecWait(hReqB, CMDQ_SYNC_TOKEN_USER_1);
cmdq_append_command(hReqB, CMDQ_CODE_EOC, 0, 1);
cmdq_append_command(hReqB, CMDQ_CODE_JUMP, 0, 8);
ret = _test_submit_async(hReqA, &pTaskA);
ret = _test_submit_async(hReqB, &pTaskB);
CMDQ_MSG("%s start wait sleep========\n", __func__);
msleep_interruptible(500);
CMDQ_MSG("%s start wait A========\n", __func__);
ret = cmdqCoreWaitAndReleaseTask(pTaskA, 500);
CMDQ_MSG("%s start wait B, this should timeout========\n", __func__);
ret = cmdqCoreWaitAndReleaseTask(pTaskB, 600);
CMDQ_MSG("%s wait B get %d ========\n", __func__, ret);
} while (0);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_1);
cmdqRecDestroy(hReqA);
cmdqRecDestroy(hReqB);
del_timer(&timer_reqA);
del_timer(&timer_reqB);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_multiple_async_request(void)
{
#define TEST_REQ_COUNT 30
cmdqRecHandle hReq[TEST_REQ_COUNT]= { 0 };
TaskStruct *pTask[TEST_REQ_COUNT] = { 0 };
int32_t ret = 0;
int i;
CMDQ_MSG("%s\n", __func__);
setup_timer(&timer, &_testcase_sync_token_timer_loop_func, CMDQ_SYNC_TOKEN_USER_0);
mod_timer(&timer, jiffies + msecs_to_jiffies(10));
/* Queue multiple async request */
/* to test dynamic task allocation */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
for (i = 0; i < TEST_REQ_COUNT; ++i) {
ret = cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &hReq[i]);
if (0 > ret) {
CMDQ_ERR("%s cmdqRecCreate failed:%d, i:%d\n ", __func__, ret, i);
continue;
}
cmdqRecReset(hReq[i]);
/* specify engine flag in order to dispatch all tasks to the same HW thread*/
hReq[i]->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
cmdqRecSetSecure(hReq[i], gCmdqTestSecure);
cmdqRecWait(hReq[i], CMDQ_SYNC_TOKEN_USER_0);
cmdq_rec_finalize_command(hReq[i], false);
/* higher priority for later tasks */
hReq[i]->priority = i;
ret = _test_submit_async(hReq[i], &pTask[i]);
CMDQ_MSG("======== create task[%2d]=0x%p done ========\n", i, pTask[i]);
}
/* release token and wait them */
for (i = 0; i < TEST_REQ_COUNT; ++i) {
if (NULL == pTask[i]) {
CMDQ_ERR("%s pTask[%d] is NULL\n ", __func__, i);
continue;
}
msleep_interruptible(100);
CMDQ_LOG("======== wait task[%2d]=0x%p ========\n", i, pTask[i]);
ret = cmdqCoreWaitAndReleaseTask(pTask[i], 1000);
cmdqRecDestroy(hReq[i]);
}
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
del_timer(&timer);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_async_request_partial_engine(void)
{
int32_t ret = 0;
int i;
CMDQ_SCENARIO_ENUM scn[] = { CMDQ_SCENARIO_PRIMARY_DISP,
CMDQ_SCENARIO_JPEG_DEC,
CMDQ_SCENARIO_PRIMARY_MEMOUT,
CMDQ_SCENARIO_SUB_DISP,
CMDQ_SCENARIO_DEBUG,
};
struct timer_list timers[sizeof(scn) / sizeof(scn[0])];
cmdqRecHandle hReq[(sizeof(scn) / sizeof(scn[0]))] = { 0 };
TaskStruct *pTasks[(sizeof(scn) / sizeof(scn[0]))] = { 0 };
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
for (i = 0; i < (sizeof(scn) / sizeof(scn[0])); ++i) {
setup_timer(&timers[i], &_testcase_sync_token_timer_func,
CMDQ_SYNC_TOKEN_USER_0 + i);
mod_timer(&timers[i], jiffies + msecs_to_jiffies(400 * (1 + i)));
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0 + i);
cmdqRecCreate(scn[i], &hReq[i]);
cmdqRecReset(hReq[i]);
cmdqRecSetSecure(hReq[i], false);
cmdqRecWait(hReq[i], CMDQ_SYNC_TOKEN_USER_0 + i);
cmdq_rec_finalize_command(hReq[i], false);
CMDQ_MSG("TEST: SUBMIT scneario %d\n", scn[i]);
ret = _test_submit_async(hReq[i], &pTasks[i]);
}
/* wait for task completion */
for (i = 0; i < (sizeof(scn) / sizeof(scn[0])); ++i) {
ret = cmdqCoreWaitAndReleaseTask(pTasks[i], msecs_to_jiffies(3000));
}
/* clear token */
for (i = 0; i < (sizeof(scn) / sizeof(scn[0])); ++i) {
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0 + i);
cmdqRecDestroy(hReq[i]);
del_timer(&timers[i]);
}
CMDQ_MSG("%s END\n", __func__);
}
static void _testcase_unlock_all_event_timer_func(unsigned long data)
{
uint32_t token = 0;
CMDQ_MSG("%s\n", __func__);
/* trigger sync event */
CMDQ_MSG("trigger events\n");
for (token = 0; token < CMDQ_SYNC_TOKEN_MAX; ++token) {
/* 3 threads waiting, so update 3 times */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | token);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | token);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | token);
}
}
static void testcase_sync_token_threaded(void)
{
CMDQ_SCENARIO_ENUM scn[] = { CMDQ_SCENARIO_PRIMARY_DISP, /* high prio */
CMDQ_SCENARIO_JPEG_DEC, /* normal prio */
CMDQ_SCENARIO_TRIGGER_LOOP /* normal prio */
};
int32_t ret = 0;
int i = 0;
uint32_t token = 0;
struct timer_list eventTimer;
cmdqRecHandle hReq[(sizeof(scn) / sizeof(scn[0]))] = { 0 };
TaskStruct *pTasks[(sizeof(scn) / sizeof(scn[0]))] = { 0 };
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
for (i = 0; i < (sizeof(scn) / sizeof(scn[0])); ++i) {
setup_timer(&eventTimer, &_testcase_unlock_all_event_timer_func, 0);
mod_timer(&eventTimer, jiffies + msecs_to_jiffies(500));
/* */
/* 3 threads, all wait & clear 511 events */
/* */
cmdqRecCreate(scn[i], &hReq[i]);
cmdqRecReset(hReq[i]);
cmdqRecSetSecure(hReq[i], false);
for (token = 0; token < CMDQ_SYNC_TOKEN_MAX; ++token) {
cmdqRecWait(hReq[i], (CMDQ_EVENT_ENUM) token);
}
cmdq_rec_finalize_command(hReq[i], false);
CMDQ_MSG("TEST: SUBMIT scneario %d\n", scn[i]);
ret = _test_submit_async(hReq[i], &pTasks[i]);
}
/* wait for task completion */
msleep_interruptible(1000);
for (i = 0; i < (sizeof(scn) / sizeof(scn[0])); ++i) {
ret = cmdqCoreWaitAndReleaseTask(pTasks[i], msecs_to_jiffies(5000));
}
/* clear token */
for (i = 0; i < (sizeof(scn) / sizeof(scn[0])); ++i) {
cmdqRecDestroy(hReq[i]);
}
del_timer(&eventTimer);
CMDQ_MSG("%s END\n", __func__);
}
static struct timer_list g_loopTimer;
static int g_loopIter;
static cmdqRecHandle hLoopReq;
static void _testcase_loop_timer_func(unsigned long data)
{
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | data);
mod_timer(&g_loopTimer, jiffies + msecs_to_jiffies(300));
g_loopIter++;
}
static void testcase_loop(void)
{
int status = 0;
CMDQ_MSG("%s\n", __func__);
cmdqRecCreate(CMDQ_SCENARIO_TRIGGER_LOOP, &hLoopReq);
cmdqRecReset(hLoopReq);
cmdqRecSetSecure(hLoopReq, false);
cmdqRecWait(hLoopReq, CMDQ_SYNC_TOKEN_USER_0);
setup_timer(&g_loopTimer, &_testcase_loop_timer_func, CMDQ_SYNC_TOKEN_USER_0);
mod_timer(&g_loopTimer, jiffies + msecs_to_jiffies(300));
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
g_loopIter = 0;
/* should success */
status = cmdqRecStartLoop(hLoopReq);
BUG_ON(status != 0);
/* should fail because already started */
CMDQ_MSG("============testcase_loop start loop\n");
status = cmdqRecStartLoop(hLoopReq);
BUG_ON(status >= 0);
cmdqRecDumpCommand(hLoopReq);
/* WAIT */
while (g_loopIter < 20) {
msleep_interruptible(2000);
}
msleep_interruptible(2000);
CMDQ_MSG("============testcase_loop stop timer\n");
cmdqRecDestroy(hLoopReq);
del_timer(&g_loopTimer);
CMDQ_MSG("%s\n", __func__);
}
static unsigned long gLoopCount = 0L;
static void _testcase_trigger_func(unsigned long data)
{
/* trigger sync event */
CMDQ_MSG("_testcase_trigger_func");
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_SYNC_TOKEN_USER_1);
/* start again */
mod_timer(&timer, jiffies + msecs_to_jiffies(1000));
gLoopCount++;
}
/*
static void leave_loop_func(struct work_struct *w)
{
CMDQ_MSG("leave_loop_func: cancel loop");
cmdqRecStopLoop(hLoopConfig);
hLoopConfig = NULL;
return;
}
DECLARE_WORK(leave_loop, leave_loop_func);
int32_t my_irq_callback(unsigned long data)
{
CMDQ_MSG("%s data=%d\n", __FUNCTION__, data);
++gLoopCount;
switch(data)
{
case 1:
if(gLoopCount < 20)
{
return 0;
}
else
{
return -1;
}
break;
case 2:
if(gLoopCount > 40)
{
// insert stopping cal
schedule_work(&leave_loop);
}
break;
}
return 0;
}
*/
static void testcase_trigger_thread(void)
{
cmdqRecHandle hTrigger, hConfig;
int32_t ret = 0;
int index = 0;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token for every 1 sec */
setup_timer(&timer, &_testcase_trigger_func, 0);
mod_timer(&timer, jiffies + msecs_to_jiffies(1000));
do {
/* THREAD 1, trigger loop */
cmdqRecCreate(CMDQ_SCENARIO_TRIGGER_LOOP, &hTrigger);
cmdqRecReset(hTrigger);
/* * WAIT and CLEAR config dirty */
/* cmdqRecWait(hTrigger, CMDQ_SYNC_TOKEN_CONFIG_DIRTY); */
/* * WAIT and CLEAR TE */
/* cmdqRecWait(hTrigger, CMDQ_EVENT_MDP_DSI0_TE_SOF); */
/* * WAIT and CLEAR stream done */
/* cmdqRecWait(hTrigger, CMDQ_EVENT_MUTEX0_STREAM_EOF); */
/* * WRITE mutex enable */
/* cmdqRecWait(hTrigger, MM_MUTEX_BASE + 0x20); */
cmdqRecWait(hTrigger, CMDQ_SYNC_TOKEN_USER_0);
/* * RUN forever but each IRQ trigger is bypass to my_irq_callback */
ret = cmdqRecStartLoop(hTrigger);
/* THREAD 2, config thread */
cmdqRecCreate(CMDQ_SCENARIO_JPEG_DEC, &hConfig);
hConfig->priority = CMDQ_THR_PRIO_NORMAL;
cmdqRecReset(hConfig);
/* insert tons of instructions */
for (index = 0; index < 10; ++index) {
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0, 0x1);
}
ret = cmdqRecFlush(hConfig);
CMDQ_MSG("flush 0\n");
hConfig->priority = CMDQ_THR_PRIO_DISPLAY_CONFIG;
cmdqRecReset(hConfig);
/* insert tons of instructions */
for (index = 0; index < 10; ++index) {
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0, 0x1);
}
ret = cmdqRecFlush(hConfig);
CMDQ_MSG("flush 1\n");
cmdqRecReset(hConfig);
/* insert tons of instructions */
for (index = 0; index < 500; ++index) {
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0, 0x1);
}
ret = cmdqRecFlush(hConfig);
CMDQ_MSG("flush 2\n");
/* WAIT */
while (gLoopCount < 20) {
msleep_interruptible(2000);
}
} while (0);
del_timer(&timer);
cmdqRecDestroy(hTrigger);
cmdqRecDestroy(hConfig);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_prefetch_scenarios(void)
{
/* make sure both prefetch and non-prefetch cases */
/* handle 248+ instructions properly */
cmdqRecHandle hConfig;
int32_t ret = 0;
int index = 0, scn = 0;
const int INSTRUCTION_COUNT = 500;
CMDQ_MSG("%s\n", __func__);
/* make sure each scenario runs properly with 248+ commands */
for (scn = 0; scn < CMDQ_MAX_SCENARIO_COUNT; ++scn) {
if (cmdq_core_is_request_from_user_space(scn)) {
continue;
}
CMDQ_MSG("testcase_prefetch_scenarios scenario:%d\n", scn);
cmdqRecCreate((CMDQ_SCENARIO_ENUM) scn, &hConfig);
cmdqRecReset(hConfig);
/* insert tons of instructions */
for (index = 0; index < INSTRUCTION_COUNT; ++index) {
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0, 0x1);
}
ret = cmdqRecFlush(hConfig);
BUG_ON(ret < 0);
cmdqRecDestroy(hConfig);
}
CMDQ_MSG("%s END\n", __func__);
}
extern void cmdq_core_reset_hw_events(void);
void testcase_clkmgr_impl(enum cg_clk_id gateId,
char *name,
const unsigned long testWriteReg,
const uint32_t testWriteValue,
const unsigned long testReadReg,
const bool verifyWriteResult)
{
/* clkmgr is not available on FPGA */
#ifndef CONFIG_MTK_FPGA
uint32_t value = 0;
CMDQ_MSG("====== %s:%s ====== \n", __func__, name);
CMDQ_VERBOSE("clk:%d, name:%s\n", gateId, name);
CMDQ_VERBOSE("write reg(0x%lx) to 0x%08x, read reg(0x%lx), verify write result:%d\n",
testWriteReg, testWriteValue, testReadReg, verifyWriteResult);
/* turn on CLK, function should work */
CMDQ_MSG("enable_clock\n");
enable_clock(gateId, name);
CMDQ_REG_SET32(testWriteReg, testWriteValue);
value = CMDQ_REG_GET32(testReadReg);
if ((true == verifyWriteResult) &&
(testWriteValue != value)) {
CMDQ_ERR("when enable clock reg(0x%lx) = 0x%08x\n", testReadReg, value);
/* BUG(); */
}
/* turn off CLK, function should not work and access register should not cause hang */
CMDQ_MSG("disable_clock\n");
disable_clock(gateId, name);
CMDQ_REG_SET32(testWriteReg, testWriteValue);
value = CMDQ_REG_GET32(testReadReg);
if (0 != value) {
CMDQ_ERR("when disable clock reg(0x%lx) = 0x%08x\n", testReadReg, value);
/* BUG(); */
}
#endif
}
static void testcase_clkmgr(void)
{
CMDQ_MSG("%s\n", __func__);
testcase_clkmgr_impl(MT_CG_INFRA_GCE,
"CMDQ_TEST",
CMDQ_GPR_R32(CMDQ_DATA_REG_DEBUG),
0xFFFFDEAD,
CMDQ_GPR_R32(CMDQ_DATA_REG_DEBUG),
true);
testcase_clkmgr_mdp();
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_dram_access(void)
{
#ifdef CMDQ_GPR_SUPPORT
cmdqRecHandle handle;
uint32_t *regResults;
dma_addr_t regResultsMVA;
dma_addr_t dstMVA;
uint32_t argA;
uint32_t subsysCode;
uint32_t *pCmdEnd = NULL;
unsigned long long data64;
CMDQ_MSG("%s\n", __func__);
regResults = cmdq_core_alloc_hw_buffer(cmdq_dev_get(),
sizeof(uint32_t) * 2, &regResultsMVA, GFP_KERNEL);
/* set up intput */
regResults[0] = 0xdeaddead; /* this is read-from */
regResults[1] = 0xffffffff; /* this is write-to */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
/* */
/* READ from DRAME: register to read from */
/* */
/* note that we force convert to physical reg address. */
/* if it is already physical address, it won't be affected (at least on this platform) */
argA = CMDQ_TEST_MMSYS_DUMMY_PA;
subsysCode = cmdq_subsys_from_phys_addr(argA);
pCmdEnd = (uint32_t *) (((char *)handle->pBuffer) + handle->blockSize);
CMDQ_MSG("pCmdEnd initial=0x%p, reg MVA=%pa, size=%d\n",
pCmdEnd, &regResultsMVA, handle->blockSize);
/* Move &(regResults[0]) to CMDQ_DATA_REG_DEBUG_DST */
*pCmdEnd = (uint32_t) CMDQ_PHYS_TO_AREG(regResultsMVA);
pCmdEnd += 1;
*pCmdEnd = (CMDQ_CODE_MOVE << 24) |
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
((regResultsMVA >> 32) & 0xffff) |
#endif
((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) | (4 << 21);
pCmdEnd += 1;
/* */
/* WRITE to DRAME: */
/* from src_addr(CMDQ_DATA_REG_DEBUG_DST) to external RAM (regResults[1]) */
/* */
/* Read data from *CMDQ_DATA_REG_DEBUG_DST to CMDQ_DATA_REG_DEBUG */
*pCmdEnd = CMDQ_DATA_REG_DEBUG;
pCmdEnd += 1;
*pCmdEnd =
(CMDQ_CODE_READ << 24) | (0 & 0xffff) | ((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) | (6 <<
21);
pCmdEnd += 1;
/* Load dst_addr to GPR: Move &(regResults[1]) to CMDQ_DATA_REG_DEBUG_DST */
dstMVA = regResultsMVA + 4; /* note regResults is a uint32_t array */
*pCmdEnd = ((uint32_t) dstMVA);
pCmdEnd += 1;
*pCmdEnd = (CMDQ_CODE_MOVE << 24) |
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
((dstMVA >> 32) & 0xffff) |
#endif
((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) | (4 << 21);
pCmdEnd += 1;
/* Write from CMDQ_DATA_REG_DEBUG to *CMDQ_DATA_REG_DEBUG_DST */
*pCmdEnd = CMDQ_DATA_REG_DEBUG;
pCmdEnd += 1;
*pCmdEnd = (CMDQ_CODE_WRITE << 24) |
(0 & 0xffff) | ((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) | (6 << 21);
pCmdEnd += 1;
handle->blockSize += 4 * 8; /* 4 * 64-bit instructions */
cmdqRecDumpCommand(handle);
cmdqRecFlush(handle);
cmdqRecDumpCommand(handle);
cmdqRecDestroy(handle);
data64 = 0LL;
data64 = CMDQ_REG_GET64_GPR_PX(CMDQ_DATA_REG_DEBUG_DST);
CMDQ_MSG("regResults=[0x%08x, 0x%08x]\n", regResults[0], regResults[1]);
CMDQ_MSG("CMDQ_DATA_REG_DEBUG=0x%08x, CMDQ_DATA_REG_DEBUG_DST=0x%llx\n",
CMDQ_REG_GET32(CMDQ_GPR_R32(CMDQ_DATA_REG_DEBUG)), data64);
if (regResults[1] != regResults[0]) {
CMDQ_ERR("ERROR!!!!!!\n");
} else {
CMDQ_MSG("OK!!!!!!\n");
}
cmdq_core_free_hw_buffer(cmdq_dev_get(), 2 * sizeof(uint32_t), regResults, regResultsMVA);
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
#endif
}
static void testcase_long_command(void)
{
int i;
cmdqRecHandle handle;
uint32_t data;
uint32_t pattern = 0x0;
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
/* build a 64KB instruction buffer */
for (i = 0; i < 64 * 1024 / 8; ++i) {
pattern = i;
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, pattern, ~0);
}
cmdqRecFlush(handle);
cmdqRecDestroy(handle);
/* verify data */
do {
if(true == gCmdqTestSecure) {
CMDQ_LOG("%s, timeout case in secure path\n", __func__);
break;
}
data = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (pattern != data) {
CMDQ_ERR("TEST FAIL: reg value is 0x%08x, not pattern 0x%08x\n", data, pattern);
}
} while (0);
CMDQ_MSG("%s END\n", __func__);
return;
}
static void testcase_perisys_apb(void)
{
#ifdef CMDQ_GPR_SUPPORT
/* write value to PERISYS register */
/* we use MSDC debug to test: */
/* write SEL, read OUT. */
const uint32_t MSDC_SW_DBG_SEL_PA = 0x11230000 + 0xA0;
const uint32_t MSDC_SW_DBG_OUT_PA = 0x11230000 + 0xA4;
const uint32_t AUDIO_TOP_CONF0_PA = 0x11220000;
#ifdef CMDQ_OF_SUPPORT
const unsigned long MSDC_VA_BASE = cmdq_dev_alloc_module_base_VA_by_name("mediatek,MSDC0");
const unsigned long AUDIO_VA_BASE = cmdq_dev_alloc_module_base_VA_by_name("mediatek,AUDIO");
const unsigned long MSDC_SW_DBG_OUT = MSDC_VA_BASE + 0xA4;
const unsigned long AUDIO_TOP_CONF0 = AUDIO_VA_BASE;
/* CMDQ_LOG("MSDC_VA_BASE: VA:%lx, PA: 0x%08x\n", MSDC_VA_BASE, 0x11230000); */
/* CMDQ_LOG("AUDIO_VA_BASE: VA:%lx, PA: 0x%08x\n", AUDIO_TOP_CONF0_PA, 0x11220000); */
#else
const uint32_t MSDC_SW_DBG_OUT = 0xF1230000 + 0xA4;
const uint32_t AUDIO_TOP_CONF0 = 0xF1220000;
#endif
const uint32_t AUDIO_TOP_MASK = ~0 & ~(1 << 28 |
1 << 21 |
1 << 17 |
1 << 16 |
1 << 15 |
1 << 11 |
1 << 10 |
1 << 7 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 1 | 1 << 0);
cmdqRecHandle handle = NULL;
uint32_t data = 0;
uint32_t dataRead = 0;
CMDQ_MSG("%s\n", __func__);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, false);
cmdqRecWrite(handle, MSDC_SW_DBG_SEL_PA, 1, ~0);
cmdqRecFlush(handle);
/* verify data */
data = CMDQ_REG_GET32(MSDC_SW_DBG_OUT);
CMDQ_MSG("MSDC_SW_DBG_OUT = 0x%08x=====\n", data);
/* test read from AP_DMA_GLOBAL_SLOW_DOWN to CMDQ GPR */
cmdqRecReset(handle);
cmdqRecSetSecure(handle, false);
cmdqRecReadToDataRegister(handle, MSDC_SW_DBG_OUT_PA, CMDQ_DATA_REG_PQ_COLOR);
cmdqRecFlush(handle);
/* verify data */
dataRead = CMDQ_REG_GET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR));
if (data != dataRead) {
CMDQ_ERR("TEST FAIL: CMDQ_DATA_REG_PQ_COLOR is 0x%08x, different=====\n", dataRead);
}
CMDQ_REG_SET32(AUDIO_TOP_CONF0, ~0);
data = CMDQ_REG_GET32(AUDIO_TOP_CONF0);
CMDQ_MSG("write 0xFFFFFFFF to AUDIO_TOP_CONF0 = 0x%08x=====\n", data);
CMDQ_REG_SET32(AUDIO_TOP_CONF0, 0);
data = CMDQ_REG_GET32(AUDIO_TOP_CONF0);
CMDQ_MSG("Before AUDIO_TOP_CONF0 = 0x%08x=====\n", data);
cmdqRecReset(handle);
cmdqRecWrite(handle, AUDIO_TOP_CONF0_PA, ~0, AUDIO_TOP_MASK);
cmdqRecFlush(handle);
/* verify data */
data = CMDQ_REG_GET32(AUDIO_TOP_CONF0);
CMDQ_MSG("after AUDIO_TOP_CONF0 = 0x%08x=====\n", data);
if (data != AUDIO_TOP_MASK) {
CMDQ_ERR("TEST FAIL: AUDIO_TOP_CONF0 is 0x%08x=====\n", data);
}
cmdqRecDestroy(handle);
#ifdef CMDQ_OF_SUPPORT
/* release registers map */
cmdq_dev_free_module_base_VA(MSDC_VA_BASE);
cmdq_dev_free_module_base_VA(AUDIO_VA_BASE);
#endif
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
#endif /* CMDQ_GPR_SUPPORT */
}
static void testcase_write_address(void)
{
dma_addr_t pa = 0;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
cmdqCoreAllocWriteAddress(3, &pa);
CMDQ_LOG("ALLOC: 0x%pa\n", &pa);
value = cmdqCoreReadWriteAddress(pa);
CMDQ_LOG("value 0: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 1);
CMDQ_LOG("value 1: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 2);
CMDQ_LOG("value 2: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 3);
CMDQ_LOG("value 3: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 4);
CMDQ_LOG("value 4: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + (4 * 20));
CMDQ_LOG("value 80: 0x%08x\n", value);
/* free invalid start address fist to verify error handle */
CMDQ_LOG("cmdqCoreFreeWriteAddress, pa:0, it's a error case\n");
cmdqCoreFreeWriteAddress(0);
/* ok case */
CMDQ_LOG("cmdqCoreFreeWriteAddress, pa:%pa, it's a ok case\n", &pa);
cmdqCoreFreeWriteAddress(pa);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_write_from_data_reg(void)
{
#ifdef CMDQ_GPR_SUPPORT
cmdqRecHandle handle;
uint32_t value;
const uint32_t PATTERN = 0xFFFFDEAD;
const uint32_t srcGprId = CMDQ_DATA_REG_DEBUG;
const uint32_t dstRegPA = CMDQ_TEST_MMSYS_DUMMY_PA;
const unsigned long dstRegVA = CMDQ_TEST_MMSYS_DUMMY_VA;
CMDQ_MSG("%s\n", __func__);
/* clean dst register value*/
CMDQ_REG_SET32(dstRegVA, 0x0);
/* init GPR as value 0xFFFFDEAD */
CMDQ_REG_SET32(CMDQ_GPR_R32(srcGprId), PATTERN);
value = CMDQ_REG_GET32(CMDQ_GPR_R32(srcGprId));
if (PATTERN != value) {
CMDQ_ERR("init CMDQ_DATA_REG_DEBUG to 0x%08x failed, value: 0x%08x\n", PATTERN, value);
}
/* write GPR data reg to hw register*/
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
cmdqRecWriteFromDataRegister(handle, srcGprId, dstRegPA);
cmdqRecFlush(handle);
cmdqRecDumpCommand(handle);
cmdqRecDestroy(handle);
/* verify */
value = CMDQ_REG_GET32(dstRegVA);
if (PATTERN != value) {
CMDQ_ERR("%s failed, dstReg value is not 0x%08x, value: 0x%08x\n", __func__, PATTERN, value);
}
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
#endif
}
static void testcase_read_to_data_reg(void)
{
#ifdef CMDQ_GPR_SUPPORT
cmdqRecHandle handle;
uint32_t data;
unsigned long long data64;
unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
CMDQ_MSG("%s\n", __func__);
/* init GPR 64*/
CMDQ_REG_SET64_GPR_PX(CMDQ_DATA_REG_PQ_COLOR_DST, 0x1234567890ABCDEFULL);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR), 0xbeefbeef); /* R4 */
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_2D_SHARPNESS_0), 0x0); /* R5 */
cmdq_core_gpr_dump();
/* [read 64 bit test] move data from GPR to GPR_Px: COLOR to COLOR_DST (64 bit) */
#if 1
cmdqRecReadToDataRegister(handle, CMDQ_GPR_R32_PA(CMDQ_DATA_REG_PQ_COLOR),
CMDQ_DATA_REG_PQ_COLOR_DST);
#else
/* 64 bit behavior of Read OP depends APB bus implementation */
/* (CMDQ uses APB to access HW register, use AXI to access DRAM) */
/* from DE's suggestion, */
/* 1. for read HW register case, it's better to separate 1 x 64 bit length read to 2 x 32 bit length read*/
/* 2. for GPRx each assignment case, it's better performance to use MOVE op to read GPR_x1 to GPR_x2*/
/* when Read 64 length failed, try to use move to clear up if APB issue */
const uint32_t srcDataReg = CMDQ_DATA_REG_PQ_COLOR;
const uint32_t dstDataReg = CMDQ_DATA_REG_PQ_COLOR_DST;
/* argA, 22 bit 1: argB is GPR*/
/* argA, 23 bit 1: argA is GPR*/
cmdq_append_command(
handle,
CMDQ_CODE_RAW,
(CMDQ_CODE_MOVE << 24) | (dstDataReg << 16) | (4 << 21) | (2 << 21),
srcDataReg);
#endif
/* [read 32 bit test] move data from register value to GPR_Rx: MM_DUMMY_REG to COLOR(32 bit) */
cmdqRecReadToDataRegister(handle, CMDQ_TEST_MMSYS_DUMMY_PA, CMDQ_DATA_REG_PQ_COLOR);
cmdqRecFlush(handle);
cmdqRecDumpCommand(handle);
cmdqRecDestroy(handle);
cmdq_core_gpr_dump();
/* verify data */
data = CMDQ_REG_GET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR));
if (data != 0xdeaddead) {
CMDQ_ERR("[Read 32 bit from GPR_Rx]TEST FAIL: PQ reg value is 0x%08x\n", data);
}
data64 = 0LL;
data64 = CMDQ_REG_GET64_GPR_PX(CMDQ_DATA_REG_PQ_COLOR_DST);
if (0xbeefbeef != data64) {
CMDQ_ERR("[Read 64 bit from GPR_Px]TEST FAIL: PQ_DST reg value is 0x%llx\n", data64);
}
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
return;
#endif
}
static void testcase_write_reg_from_slot(void)
{
#ifdef CMDQ_GPR_SUPPORT
const uint32_t PATTEN = 0xBCBCBCBC;
cmdqRecHandle handle;
cmdqBackupSlotHandle hSlot = 0;
uint32_t value = 0;
long long value64 = 0LL;
const CMDQ_DATA_REGISTER_ENUM dstRegId = CMDQ_DATA_REG_DEBUG;
const CMDQ_DATA_REGISTER_ENUM srcRegId = CMDQ_DATA_REG_DEBUG_DST;
CMDQ_MSG("%s\n", __func__);
/* init */
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, 0xdeaddead);
CMDQ_REG_SET32(CMDQ_GPR_R32(dstRegId), 0xdeaddead);
CMDQ_REG_SET64_GPR_PX(srcRegId, 0xdeaddeaddeaddead);
cmdqBackupAllocateSlot(&hSlot, 1);
cmdqBackupWriteSlot(hSlot, 0, PATTEN);
cmdqBackupReadSlot(hSlot, 0, &value);
if (PATTEN != value) {
CMDQ_ERR("%s, slot init failed\n", __func__);
}
/* Create cmdqRec */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
/* Reset command buffer */
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
/* Insert commands to write register with slot's value */
cmdqRecBackupWriteRegisterFromSlot(handle, hSlot, 0, CMDQ_TEST_MMSYS_DUMMY_PA);
/* Execute commands */
cmdqRecFlush(handle);
/* debug dump command instructions */
cmdqRecDumpCommand(handle);
/* we can destroy cmdqRec handle after flush. */
cmdqRecDestroy(handle);
/* verify */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (PATTEN != value) {
CMDQ_ERR("%s failed, value:0x%x\n", __func__, value);
}
value = CMDQ_REG_GET32(CMDQ_GPR_R32(dstRegId));
value64 = CMDQ_REG_GET64_GPR_PX(srcRegId);
CMDQ_LOG("srcGPR(%x):0x%llx\n", srcRegId, value64);
CMDQ_LOG("dstGPR(%x):0x%08x\n", dstRegId, value);
/* release result free slot */
cmdqBackupFreeSlot(hSlot);
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
return;
#endif
}
static void testcase_backup_reg_to_slot(void)
{
#ifdef CMDQ_GPR_SUPPORT
cmdqRecHandle handle;
unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
cmdqBackupSlotHandle hSlot = 0;
int i;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
/* Create cmdqRec */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
/* Create Slot */
cmdqBackupAllocateSlot(&hSlot, 5);
for (i = 0; i < 5; ++i) {
cmdqBackupWriteSlot(hSlot, i, i);
}
for (i = 0; i < 5; ++i) {
cmdqBackupReadSlot(hSlot, i, &value);
if (value != i) {
CMDQ_ERR("testcase_cmdqBackupWriteSlot FAILED!!!!!\n");
}
CMDQ_LOG("testcase_cmdqBackupWriteSlot OK!!!!!\n");
}
/* Reset command buffer */
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
/* Insert commands to backup registers */
for (i = 0; i < 5; ++i) {
cmdqRecBackupRegisterToSlot(handle, hSlot, i, CMDQ_TEST_MMSYS_DUMMY_PA);
}
/* Execute commands */
cmdqRecFlush(handle);
/* debug dump command instructions */
cmdqRecDumpCommand(handle);
/* we can destroy cmdqRec handle after flush. */
cmdqRecDestroy(handle);
/* verify data by reading it back from slot */
for (i = 0; i < 5; ++i) {
cmdqBackupReadSlot(hSlot, i, &value);
CMDQ_LOG("backup slot %d = 0x%08x\n", i, value);
if (value != 0xdeaddead) {
CMDQ_ERR("content error!!!!!!!!!!!!!!!!!!!!\n");
}
}
/* release result free slot */
cmdqBackupFreeSlot(hSlot);
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
return;
#endif
}
static void testcase_update_value_to_slot(void)
{
int32_t i;
uint32_t value;
cmdqRecHandle handle;
cmdqBackupSlotHandle hSlot = 0;
const uint32_t PATTERNS[] = {
0xDEAD0000, 0xDEAD0001, 0xDEAD0002, 0xDEAD0003, 0xDEAD0004 };
CMDQ_MSG("%s\n", __func__);
/* Create Slot*/
cmdqBackupAllocateSlot(&hSlot, 5);
/*use CMDQ to update slot value*/
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
for (i = 0; i < 5; ++i) {
cmdqRecBackupUpdateSlot(handle, hSlot, i, PATTERNS[i]);
}
cmdqRecFlush(handle);
cmdqRecDumpCommand(handle);
cmdqRecDestroy(handle);
/* CPU verify value by reading it back from slot */
for (i = 0; i < 5; ++i) {
cmdqBackupReadSlot(hSlot, i, &value);
if (PATTERNS[i] != value) {
CMDQ_ERR("slot[%d] = 0x%08x...content error! It should be 0x%08x\n",
i, value, PATTERNS[i]);
} else {
CMDQ_LOG("slot[%d] = 0x%08x\n", i, value);
}
}
/* release result free slot */
cmdqBackupFreeSlot(hSlot);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_poll(void)
{
cmdqRecHandle handle;
uint32_t value = 0;
uint32_t pollingVal = 0x00003001;
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, ~0);
/* it's too slow that set value after enable CMDQ */
/* sw timeout will be hanppened before CPU schedule to set value..., so we set value here */
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, pollingVal);
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
CMDQ_MSG("target value is 0x%08x\n", value);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
cmdqRecPoll(handle, CMDQ_TEST_MMSYS_DUMMY_PA, pollingVal, ~0);
cmdqRecFlush(handle);
cmdqRecDestroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (pollingVal != value) {
CMDQ_ERR("polling target value is 0x%08x\n", value);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_write_with_mask(void)
{
cmdqRecHandle handle;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
const uint32_t MASK = (1 << 16);
const uint32_t EXPECT_RESULT = PATTERN & MASK;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
/* set to 0x0 */
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, 0x0);
/* use CMDQ to set to PATTERN */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, MASK);
cmdqRecFlush(handle);
cmdqRecDestroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (EXPECT_RESULT != value ) {
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n", value, EXPECT_RESULT);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_write(void)
{
cmdqRecHandle handle;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, ~0);
/* use CMDQ to set to PATTERN */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, ~0);
cmdqRecFlush(handle);
cmdqRecDestroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (value != PATTERN) {
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n", value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_prefetch(void)
{
cmdqRecHandle handle;
int i;
uint32_t value = 0;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16); /* 0xDEADDEAD; */
const uint32_t testRegPA = CMDQ_TEST_MMSYS_DUMMY_PA;
const unsigned long testRegVA = CMDQ_TEST_MMSYS_DUMMY_VA;
const uint32_t REP_COUNT = 500;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(testRegVA, ~0);
/* No prefetch. */
/* use CMDQ to set to PATTERN */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, false);
for (i = 0; i < REP_COUNT; ++i) {
cmdqRecWrite(handle, testRegPA, PATTERN, ~0);
}
cmdqRecFlushAsync(handle);
cmdqRecFlushAsync(handle);
cmdqRecFlushAsync(handle);
msleep_interruptible(1000);
cmdqRecDestroy(handle);
/* use prefetch */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG_PREFETCH, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, false);
for (i = 0; i < REP_COUNT; ++i) {
cmdqRecWrite(handle, testRegPA, PATTERN, ~0);
}
cmdqRecFlushAsync(handle);
cmdqRecFlushAsync(handle);
cmdqRecFlushAsync(handle);
msleep_interruptible(1000);
cmdqRecDestroy(handle);
/* value check */
value = CMDQ_REG_GET32(testRegVA);
if (value != PATTERN) {
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n", value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_backup_register(void)
{
#ifdef CMDQ_GPR_SUPPORT
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
cmdqRecHandle handle;
int ret = 0;
uint32_t regAddr[3] = { CMDQ_TEST_MMSYS_DUMMY_PA,
CMDQ_GPR_R32_PA(CMDQ_DATA_REG_PQ_COLOR),
CMDQ_GPR_R32_PA(CMDQ_DATA_REG_2D_SHARPNESS_0)
};
uint32_t regValue[3] = { 0 };
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xAAAAAAAA);
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR), 0xBBBBBBBB);
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_2D_SHARPNESS_0), 0xCCCCCCCC);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
ret = cmdqRecFlushAndReadRegister(handle, 3, regAddr, regValue);
cmdqRecDestroy(handle);
if (regValue[0] != 0xAAAAAAAA) {
CMDQ_ERR("regValue[0] is 0x%08x, wrong!\n", regValue[0]);
}
if (regValue[1] != 0xBBBBBBBB) {
CMDQ_ERR("regValue[1] is 0x%08x, wrong!\n", regValue[1]);
}
if (regValue[2] != 0xCCCCCCCC) {
CMDQ_ERR("regValue[2] is 0x%08x, wrong!\n", regValue[2]);
}
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
#endif
}
static void testcase_get_result(void)
{
#ifdef CMDQ_GPR_SUPPORT
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
int i;
cmdqRecHandle handle;
int ret = 0;
cmdqCommandStruct desc = {0};
int registers[1] = { CMDQ_TEST_MMSYS_DUMMY_PA };
int result[1] = { 0 };
CMDQ_MSG("%s\n", __func__);
/* make sure each scenario runs properly with empty commands */
/* use CMDQ_SCENARIO_PRIMARY_ALL to test */
/* because it has COLOR0 HW flag */
cmdqRecCreate(CMDQ_SCENARIO_PRIMARY_ALL, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
/* insert dummy commands */
cmdq_rec_finalize_command(handle, false);
/* init desc attributes after finalize command to ensure correct size and buffer addr */
desc.scenario = handle->scenario;
desc.priority = handle->priority;
desc.engineFlag = handle->engineFlag;
desc.pVABase = (cmdqU32Ptr_t)(unsigned long)handle->pBuffer;
desc.blockSize = handle->blockSize;
desc.regRequest.count = 1;
desc.regRequest.regAddresses = (cmdqU32Ptr_t)(unsigned long)registers;
desc.regValue.count = 1;
desc.regValue.regValues = (cmdqU32Ptr_t)(unsigned long)result;
desc.secData.isSecure = handle->secData.isSecure;
desc.secData.addrMetadataCount = 0;
desc.secData.addrMetadataMaxCount = 0;
desc.secData.waitCookie = 0;
desc.secData.resetExecCnt = false;
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
/* manually raise the dirty flag */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_EVENT_MUTEX0_STREAM_EOF);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_EVENT_MUTEX1_STREAM_EOF);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_EVENT_MUTEX2_STREAM_EOF);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | CMDQ_EVENT_MUTEX3_STREAM_EOF);
for (i = 0; i < 1; ++i) {
ret = cmdqCoreSubmitTask(&desc);
if (CMDQ_U32_PTR(desc.regValue.regValues)[0] != 0xdeaddead) {
CMDQ_ERR("TEST FAIL: reg value is 0x%08x\n", CMDQ_U32_PTR(desc.regValue.regValues)[0]);
}
}
cmdqRecDestroy(handle);
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__);
#endif
}
static void testcase_emergency_buffer(void)
{
/* ensure to define CMDQ_TEST_EMERGENCY_BUFFER in cmdq_core.c*/
const uint32_t longCommandSize = 160 * 1024;
const uint32_t submitTaskCount = 4;
cmdqRecHandle handle;
int32_t i;
CMDQ_MSG("%s\n", __func__);
/* force to use emergency buffer */
if (0 > cmdq_core_enable_emergency_buffer_test(true) ) {
return;
}
/* prepare long command */
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, false);
for(i = 0; i < (longCommandSize / CMDQ_INST_SIZE); i++)
{
cmdqRecReadToDataRegister(handle, CMDQ_TEST_MMSYS_DUMMY_PA, CMDQ_DATA_REG_PQ_COLOR);
}
/* submit */
for (i = 0; i < submitTaskCount; i++)
{
CMDQ_LOG("async submit large command(size: %d), count:%d\n", longCommandSize, i);
cmdqRecFlushAsync(handle);
}
msleep_interruptible(1000);
/* reset to apply normal memory allocation flow */
cmdq_core_enable_emergency_buffer_test(false);
cmdqRecDestroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static int _testcase_simplest_command_loop_submit(const uint32_t loop,
CMDQ_SCENARIO_ENUM scenario,
const long long engineFlag, /* force specify engineFlag */
const bool isSecureTask)
{
cmdqRecHandle handle;
int32_t i;
CMDQ_MSG("%s\n", __func__);
cmdqRecCreate(scenario, &handle);
for(i = 0; i < loop; i++)
{
CMDQ_MSG("pid: %d, flush:%4d, engineFlag:0x%llx, isSecureTask:%d\n",
current->pid, i, engineFlag, isSecureTask);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, isSecureTask);
handle->engineFlag = engineFlag;
cmdqRecFlush(handle);
}
cmdqRecDestroy(handle);
CMDQ_MSG("%s END\n", __func__);
return 0;
}
/* threadfn: int (*threadfn)(void *data) */
static int _testcase_thread_dispatch(void *data)
{
long long engineFlag;
engineFlag = *((long long*)data);
_testcase_simplest_command_loop_submit(1000, CMDQ_SCENARIO_DEBUG, engineFlag, false);
return 0;
}
static void testcase_thread_dispatch(void)
{
char threadName[20];
struct task_struct *pKThread1;
struct task_struct *pKThread2;
const long long engineFlag1 = (0x1 << CMDQ_ENG_ISP_IMGI) | (0x1 << CMDQ_ENG_ISP_IMGO);
const long long engineFlag2 = (0x1 << CMDQ_ENG_MDP_RDMA0) | (0x1 << CMDQ_ENG_MDP_WDMA);
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("=============== 2 THREAD with different engines ===============\n");
sprintf(threadName, "cmdqKTHR_%llx", engineFlag1);
pKThread1 = kthread_run(_testcase_thread_dispatch, (void *)(&engineFlag1), threadName);
if (IS_ERR(pKThread1)) {
CMDQ_ERR("create thread failed, thread:%s\n", threadName);
return;
}
sprintf(threadName, "cmdqKTHR_%llx", engineFlag2);
pKThread2 = kthread_run(_testcase_thread_dispatch, (void *)(&engineFlag2), threadName);
if (IS_ERR(pKThread2)) {
CMDQ_ERR("create thread failed, thread:%s\n", threadName);
return;
}
msleep_interruptible(5 * 1000);
/* ensure both thread execute all command */
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG, engineFlag1, false);
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG, engineFlag2, false);
CMDQ_MSG("%s END\n", __func__);
return;
}
static int _testcase_full_thread_array(void *data)
{
/* this testcase will be passed only when cmdqSecDr support async config mode because */
/* never execute event setting till IWC back to NWd */
cmdqRecHandle handle;
int32_t i;
/* clearn event first */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
/* specify engine flag in order to dispatch all tasks to the same HW thread*/
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
cmdqRecWaitNoClear(handle, CMDQ_SYNC_TOKEN_USER_0);
for (i = 0; i < 50; i++) {
CMDQ_LOG("pid: %d, flush:%6d\n", current->pid, i);
if (40 == i) {
CMDQ_LOG("set token: %d to 1\n", CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
}
cmdqRecFlushAsync(handle);
}
cmdqRecDestroy(handle);
return 0;
}
static void testcase_full_thread_array(void)
{
char threadName[20];
struct task_struct *pKThread;
CMDQ_MSG("%s\n", __func__);
sprintf(threadName, "cmdqKTHR");
pKThread = kthread_run(_testcase_full_thread_array, NULL, threadName);
if (IS_ERR(pKThread)) {
CMDQ_ERR("create thread failed, thread:%s\n", threadName);
}
msleep_interruptible(5 * 1000);
CMDQ_MSG("%s END\n", __func__);
return;
}
static void testcase_module_full_dump(void)
{
cmdqRecHandle handle;
const bool alreadyEnableLog = cmdq_core_should_print_msg();
CMDQ_MSG("%s\n", __func__);
/* enable full dump*/
if (false == alreadyEnableLog) {
cmdq_core_set_log_level(1);
}
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
/* clean SW token to invoke SW timeout latter*/
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/* turn on ALL except DISP engine flag to test dump */
handle->engineFlag = ~(CMDQ_ENG_DISP_GROUP_BITS);
CMDQ_LOG("%s, engine: 0x%llx, it's a timeout case\n",
__func__, handle->engineFlag);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, false);
cmdqRecWaitNoClear(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdqRecFlush(handle);
/* disable full dump*/
if (false == alreadyEnableLog) {
cmdq_core_set_log_level(0);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_profile_marker(void)
{
cmdqRecHandle handle;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("%s: write op without profile marker\n", __func__);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, 0xBCBCBCBC, ~0);
cmdqRecFlush(handle);
CMDQ_MSG("%s: write op with profile marker\n", __func__);
cmdqRecReset(handle);
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, 0x11111111, ~0);
cmdqRecProfileMarker(handle, "WRI_BEGIN");
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, 0x22222222, ~0);
cmdqRecProfileMarker(handle, "WRI_END");
cmdqRecDumpCommand(handle);
cmdqRecFlush(handle);
cmdqRecDestroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
#ifdef CMDQ_SECURE_PATH_SUPPORT
#include "cmdq_sec.h"
#include "cmdq_sec_iwc_common.h"
#include "cmdqSecTl_Api.h"
int32_t cmdq_sec_submit_to_secure_world_async_unlocked(uint32_t iwcCommand,
TaskStruct *pTask, int32_t thread, CmdqSecFillIwcCB iwcFillCB, void *data);
#endif
void testcase_secure_basic(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
int32_t status = 0;
CMDQ_MSG("%s\n", __func__);
do {
CMDQ_MSG("=========== Hello cmdqSecTl ===========\n ");
status = cmdq_sec_submit_to_secure_world_async_unlocked(
CMD_CMDQ_TL_TEST_HELLO_TL, NULL, CMDQ_INVALID_THREAD , NULL, NULL);
if(0 > status) {
CMDQ_ERR("entry cmdqSecTL failed, status:%d\n", status);
}
CMDQ_MSG("=========== Hello cmdqSecDr ===========\n ");
status = cmdq_sec_submit_to_secure_world_async_unlocked(
CMD_CMDQ_TL_TEST_DUMMY, NULL, CMDQ_INVALID_THREAD , NULL, NULL);
if(0 > status) {
CMDQ_ERR("entry cmdqSecDr failed, status:%d\n", status);
}
} while(0);
CMDQ_MSG("%s END\n", __func__);
#endif
}
void testcase_secure_disp_scenario(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
/* note: this case used to verify command compose in secure world. */
/* It must test when DISP driver has switched primary DISP to secure path, */
/* otherwise we should disable "enable GCE" in SWd in order to prevent phone hang */
cmdqRecHandle hDISP;
cmdqRecHandle hDisableDISP;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
CMDQ_MSG("%s\n", __func__);
CMDQ_LOG("=========== secure primary path ===========\n");
cmdqRecCreate(CMDQ_SCENARIO_PRIMARY_DISP, &hDISP);
cmdqRecReset(hDISP);
cmdqRecSetSecure(hDISP, true);
cmdqRecWrite(hDISP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, ~0);
cmdqRecFlush(hDISP);
cmdqRecDestroy(hDISP);
CMDQ_LOG("=========== disp secure primary path ===========\n");
cmdqRecCreate(CMDQ_SCENARIO_DISP_PRIMARY_DISABLE_SECURE_PATH, &hDisableDISP);
cmdqRecReset(hDisableDISP);
cmdqRecSetSecure(hDisableDISP, true);
cmdqRecWrite(hDisableDISP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, ~0);
cmdqRecFlush(hDisableDISP);
cmdqRecDestroy(hDisableDISP);
CMDQ_MSG("%s END\n", __func__);
#endif
}
void testcase_secure_meta_data(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
cmdqRecHandle hReqMDP;
cmdqRecHandle hReqDISP;
const uint32_t PATTERN_MDP = (1 << 0) | (1 << 2) | (1 << 16);
const uint32_t PATTERN_DISP = 0xBCBCBCBC;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, ~0);
CMDQ_MSG("=========== MDP case ===========\n");
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &hReqMDP);
cmdqRecReset(hReqMDP);
cmdqRecSetSecure(hReqMDP, true);
/* specify use MDP engine */
hReqMDP->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0) | (1LL << CMDQ_ENG_MDP_WDMA) | (1LL << CMDQ_ENG_MDP_WROT0);
/* enable secure test */
cmdqRecSecureEnableDAPC(hReqMDP,
(1LL << CMDQ_ENG_MDP_RDMA0) | (1LL << CMDQ_ENG_MDP_WDMA) | (1LL << CMDQ_ENG_MDP_WROT0));
cmdqRecSecureEnablePortSecurity(hReqMDP,
(1LL << CMDQ_ENG_MDP_RDMA0) | (1LL << CMDQ_ENG_MDP_WDMA) | (1LL << CMDQ_ENG_MDP_WROT0));
/* record command */
cmdqRecWrite(hReqMDP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN_MDP, ~0);
cmdqRecFlush(hReqMDP);
cmdqRecDestroy(hReqMDP);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (value != PATTERN_MDP) {
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n", value, PATTERN_MDP);
}
CMDQ_MSG("=========== DISP case ===========\n");
cmdqRecCreate(CMDQ_SCENARIO_SUB_DISP, &hReqDISP);
cmdqRecReset(hReqDISP);
cmdqRecSetSecure(hReqDISP, true);
/* enable secure test */
cmdqRecSecureEnableDAPC(hReqDISP, (1LL << CMDQ_ENG_DISP_WDMA1));
cmdqRecSecureEnablePortSecurity(hReqDISP, (1LL << CMDQ_ENG_DISP_WDMA1));
/* record command */
cmdqRecWrite(hReqDISP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN_DISP, ~0);
cmdqRecFlush(hReqDISP);
cmdqRecDestroy(hReqDISP);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (value != PATTERN_DISP) {
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n", value, PATTERN_DISP);
}
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("%s failed since not support secure path\n", __func__);
#endif
}
void testcase_submit_after_error_happened(void)
{
cmdqRecHandle handle;
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
const uint32_t pollingVal = 0x00003001;
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("=========== timeout case ===========\n");
/* let poll INIFINITE */
/* CMDQ_REG_SET32(MMSYS_DUMMY_REG, pollingVal); */
CMDQ_REG_SET32(MMSYS_DUMMY_REG, ~0);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
cmdqRecPoll(handle, CMDQ_TEST_MMSYS_DUMMY_PA, pollingVal, ~0);
cmdqRecFlush(handle);
CMDQ_MSG("=========== okay case ===========\n");
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG, 0, gCmdqTestSecure);
/* clear up */
cmdqRecDestroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_write_stress_test(void)
{
int32_t loop;
CMDQ_MSG("%s\n", __func__);
loop = 1;
CMDQ_MSG("=============== loop x %d ===============\n", loop);
_testcase_simplest_command_loop_submit(loop, CMDQ_SCENARIO_DEBUG, 0, gCmdqTestSecure);
loop = 100;
CMDQ_MSG("=============== loop x %d ===============\n", loop);
_testcase_simplest_command_loop_submit(loop, CMDQ_SCENARIO_DEBUG, 0, gCmdqTestSecure);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_prefetch_multiple_command(void)
{
/* define #define CMDQ_TEST_PREFETCH_FOR_MULTIPLE_COMMAND in cmdq_core.c for debug */
#define LOOP 2
int32_t i;
int32_t ret;
cmdqRecHandle handle[LOOP] = {0};
TaskStruct *pTask[LOOP] = { 0 };
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("%s\n", __func__);
for(i = 0; i < LOOP; i++)
{
CMDQ_MSG("=============== flush:%d/%d ===============\n", i, LOOP);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG_PREFETCH, &(handle[i]));
cmdqRecReset(handle[i]);
cmdqRecSetSecure(handle[i], false);
/* record instructions which needs prefetch */
cmdqRecEnablePrefetch(handle[i]);
cmdqRecWait(handle[i], CMDQ_SYNC_TOKEN_USER_0);
cmdqRecDisablePrefetch(handle[i]);
/* record instructions which does not need prefetch */
cmdqRecWrite(handle[i], CMDQ_TEST_MMSYS_DUMMY_PA, 0x3000, ~0);
cmdq_rec_finalize_command(handle[i], false);
cmdqRecDumpCommand(handle[i]);
ret = _test_submit_async(handle[i], &pTask[i]);
}
for (i = 0; i < LOOP; ++i) {
if (NULL == pTask[i]) {
CMDQ_ERR("%s pTask[%d] is NULL\n ", __func__, i);
continue;
}
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(100);
CMDQ_MSG("wait 0x%p, i:%2d========\n", pTask[i], i);
ret = cmdqCoreWaitAndReleaseTask(pTask[i], 500);
cmdqRecDestroy(handle[i]);
}
CMDQ_MSG("%s END\n", __func__);
}
static int _testcase_concurrency(void *data)
{
uint32_t securePath;
securePath = *((uint32_t*)data);
CMDQ_MSG("start secure(%d) path\n", securePath);
_testcase_simplest_command_loop_submit(
1000, CMDQ_SCENARIO_DEBUG, (0x1 << CMDQ_ENG_MDP_RSZ0), securePath);
return 0;
}
static void testcase_concurrency_for_normal_path_and_secure_path(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
struct task_struct *pKThread1;
struct task_struct *pKThread2;
const uint32_t securePath[2] = {0, 1};
CMDQ_MSG("%s\n", __func__);
pKThread1 = kthread_run(_testcase_concurrency, (void *)(&securePath[0]), "cmdqNormal");
if (IS_ERR(pKThread1)) {
CMDQ_ERR("create cmdqNormal failed\n");
return;
}
pKThread2 = kthread_run(_testcase_concurrency, (void *)(&securePath[1]), "cmdqSecure");
if (IS_ERR(pKThread2)) {
CMDQ_ERR("create cmdqSecure failed\n");
return;
}
msleep_interruptible(5 * 1000);
/* ensure both thread execute all command */
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG, 0x0, false);
CMDQ_MSG("%s END\n", __func__);
return;
#endif
}
void testcase_async_write_stress_test(void)
{
#if 0
#define LOOP 100
int32_t i;
int32_t ret;
cmdqRecHandle handle[LOOP] = {0};
TaskStruct *pTask[LOOP] = { 0 };
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("%s\n", __func__);
for(i = 0; i < LOOP; i++)
{
CMDQ_MSG("=============== flush:%d/%d ===============\n", i, LOOP);
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &(handle[i]));
cmdqRecReset(handle[i]);
cmdqRecSetSecure(handle[i], gCmdqTestSecure);
cmdqRecWait(handle[i], CMDQ_SYNC_TOKEN_USER_0);
cmdq_rec_finalize_command(handle[i], false);
ret = _test_submit_async(handle[i], &pTask[i]);
}
/* release token and wait them */
for (i = 0; i < LOOP; ++i) {
if (NULL == pTask[i]) {
CMDQ_ERR("%s pTask[%d] is NULL\n ", __func__, i);
continue;
}
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(100);
CMDQ_MSG("wait 0x%p, i:%2d========\n", pTask[i], i);
ret = cmdqCoreWaitAndReleaseTask(pTask[i], 500);
cmdqRecDestroy(handle[i]);
}
CMDQ_MSG("%s END\n", __func__);
#endif
}
typedef enum CMDQ_TESTCASE_ENUM {
CMDQ_TESTCASE_ALL = 0,
CMDQ_TESTCASE_BASIC = 1,
CMDQ_TESTCASE_ERROR = 2,
CMDQ_TESTCASE_READ_REG_REQUEST, /* user request get some registers' value when task execution */
CMDQ_TESTCASE_GPR,
CMDQ_TESTCASE_SW_TIMEOUT_HANDLE,
CMDQ_TESTCASE_END, /* always at the end */
} CMDQ_TESTCASE_ENUM;
ssize_t cmdq_test_proc(struct file *fp, char __user *u, size_t s, loff_t *l)
{
uint32_t testId;
bool isSecureTest;
mutex_lock(&gCmdqTestProcLock);
smp_mb();
CMDQ_LOG("[TESTCASE]CONFIG: test case: %d, secure test: %d, gCmdqTestSecure:%d\n",
gCmdqTestConfig[0], gCmdqTestConfig[1], gCmdqTestSecure);
testId = gCmdqTestConfig[0];
isSecureTest = (0 < gCmdqTestConfig[1]) ? (true) : (false);
mutex_unlock(&gCmdqTestProcLock);
/* trigger test case here */
CMDQ_MSG("//\n//\n//\ncmdq_test_proc\n");
cmdq_test_setup();
switch (gCmdqTestConfig[0]) {
case 108:
testcase_profile_marker();
break;
case 107:
testcase_prefetch_multiple_command();
break;
case 106:
testcase_concurrency_for_normal_path_and_secure_path();
break;
case 105:
testcase_async_write_stress_test();
break;
case 104:
testcase_submit_after_error_happened();
break;
case 103:
testcase_secure_meta_data();
break;
case 102:
testcase_secure_disp_scenario();
break;
case 101:
testcase_write_stress_test();
break;
case 100:
testcase_secure_basic();
break;
case 99:
testcase_write();
testcase_write_with_mask();
break;
case 98:
testcase_errors();
break;
case 97:
testcase_scenario();
break;
case 96:
testcase_sync_token();
break;
case 95:
testcase_write_address();
break;
case 94:
testcase_async_request();
break;
case 93:
testcase_async_suspend_resume();
break;
case 92:
testcase_async_request_partial_engine();
break;
case 91:
testcase_prefetch_scenarios();
break;
case 90:
testcase_loop();
break;
case 89:
testcase_trigger_thread();
break;
case 88:
testcase_multiple_async_request();
break;
case 87:
testcase_get_result();
break;
case 86:
testcase_read_to_data_reg();
break;
case 85:
testcase_dram_access();
break;
case 84:
testcase_backup_register();
break;
case 83:
testcase_fire_and_forget();
break;
case 82:
testcase_sync_token_threaded();
break;
case 81:
testcase_long_command();
break;
case 80:
testcase_clkmgr();
break;
case 79:
testcase_perisys_apb();
break;
case 78:
testcase_backup_reg_to_slot();
break;
case 77:
testcase_thread_dispatch();
break;
case 76:
testcase_emergency_buffer();
break;
case 75:
testcase_full_thread_array();
break;
case 74:
testcase_module_full_dump();
break;
case 73:
testcase_write_from_data_reg();
break;
case 72:
testcase_update_value_to_slot();
break;
case 71:
testcase_poll();
break;
case 70:
testcase_write_reg_from_slot();
break;
case CMDQ_TESTCASE_ERROR:
testcase_errors();
break;
case CMDQ_TESTCASE_BASIC:
testcase_write();
testcase_poll();
testcase_scenario();
break;
case CMDQ_TESTCASE_READ_REG_REQUEST:
testcase_get_result();
break;
case CMDQ_TESTCASE_GPR:
testcase_read_to_data_reg(); /* must verify! */
testcase_dram_access();
break;
case CMDQ_TESTCASE_ALL:
default:
testcase_multiple_async_request();
testcase_read_to_data_reg();
testcase_get_result();
testcase_errors();
testcase_scenario();
testcase_sync_token();
testcase_write();
testcase_poll();
testcase_write_address();
testcase_async_request();
testcase_async_suspend_resume();
testcase_async_request_partial_engine();
testcase_prefetch_scenarios();
testcase_loop();
testcase_trigger_thread();
testcase_prefetch();
/* testcase_sync_token_threaded(); */
testcase_long_command();
/* testcase_clkmgr(); */
testcase_dram_access();
testcase_perisys_apb();
testcase_backup_register();
testcase_fire_and_forget();
testcase_backup_reg_to_slot();
testcase_emergency_buffer();
testcase_thread_dispatch();
testcase_full_thread_array();
testcase_module_full_dump();
break;
}
cmdq_test_cleanup();
CMDQ_MSG("cmdq_test_proc ended\n");
return 0;
}
static ssize_t cmdq_write_test_proc_config(struct file *file,
const char __user *userBuf, size_t count, loff_t *data)
{
char desc[10];
int testType = -1;
int newTestSuit = -1;
int32_t len = 0;
/* copy user input */
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
if (copy_from_user(desc, userBuf, count)) {
CMDQ_ERR("TEST_CONFIG: data fail\n");
return 0;
}
desc[len] = '\0';
/* process and update config */
if (0 >= sscanf(desc, "%d %d", &testType, &newTestSuit)) {
/* sscanf returns the number of items in argument list successfully filled. */
CMDQ_ERR("TEST_CONFIG: sscanf failed\n");
return 0;
}
if ((0 > testType) || (2 <= testType) || (-1 == newTestSuit)) {
CMDQ_ERR("TEST_CONFIG: testType:%d, newTestSuit:%d\n", testType, newTestSuit);
return 0;
}
mutex_lock(&gCmdqTestProcLock);
smp_mb();
gCmdqTestConfig[0] = newTestSuit;
gCmdqTestConfig[1] = testType;
gCmdqTestSecure = (testType == 1) ? (true) : (false);
mutex_unlock(&gCmdqTestProcLock);
return count;
}
static int cmdq_test_open(struct inode *pInode, struct file *pFile)
{
return 0;
}
static struct file_operations cmdq_fops = {
.owner = THIS_MODULE,
.open = cmdq_test_open,
.read = cmdq_test_proc,
.write = cmdq_write_test_proc_config,
};
static int __init cmdq_test_init(void)
{
#ifdef _CMDQ_TEST_PROC_
CMDQ_MSG("cmdq_test_init\n");
/* Mout proc entry for debug */
gCmdqTestProcEntry = proc_mkdir("cmdq_test", NULL);
if (NULL != gCmdqTestProcEntry) {
if (NULL == proc_create("test", 0660, gCmdqTestProcEntry, &cmdq_fops)) {
CMDQ_MSG("cmdq_test_init failed\n");
}
}
#endif
return 0;
}
static void __exit cmdq_test_exit(void)
{
#ifdef _CMDQ_TEST_PROC_
CMDQ_MSG("cmdq_test_exit\n");
if (NULL != gCmdqTestProcEntry) {
proc_remove(gCmdqTestProcEntry);
gCmdqTestProcEntry = NULL;
}
#endif
}
module_init(cmdq_test_init);
module_exit(cmdq_test_exit);
MODULE_LICENSE("GPL");
#else
void testcase_clkmgr_impl(enum cg_clk_id gateId,
char *name,
const unsigned long testWriteReg,
const uint32_t testWriteValue,
const unsigned long testReadReg,
const bool verifyWriteResult)
{
}
#endif /* CMDQ_TEST */