Commit 1bca5068 authored by carbon's avatar carbon

Add mailbox based inter-processor communication

parent 56595260
......@@ -270,6 +270,7 @@ CONFIG_ION_CARVEOUT_HEAP=y
CONFIG_ION_CMA_HEAP=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_CV1835_SYSDMA_REMAP=y
CONFIG_CVI_MAILBOX=y
CONFIG_PWM=y
CONFIG_SIFIVE_PLIC=y
CONFIG_ANDROID=y
......
......@@ -11,22 +11,9 @@
enum SYS_CMD_ID {
SYS_CMD_INFO_TRANS = 0x50,
SYS_CMD_INFO_LINUX_INIT_DONE,
SYS_CMD_INFO_RTOS_INIT_DONE,
SYS_CMD_INFO_STOP_ISR,
SYS_CMD_INFO_STOP_ISR_DONE,
SYS_CMD_INFO_LINUX,
SYS_CMD_INFO_RTOS,
SYS_CMD_SYNC_TIME,
SYS_CMD_INFO_DUMP_MSG,
SYS_CMD_INFO_DUMP_EN,
SYS_CMD_INFO_DUMP_DIS,
SYS_CMD_INFO_DUMP_JPG,
SYS_CMD_INFO_TRACE_SNAPSHOT_START,
SYS_CMD_INFO_TRACE_SNAPSHOT_STOP,
SYS_CMD_INFO_TRACE_STREAM_START,
SYS_CMD_INFO_TRACE_STREAM_STOP,
CMD_TEST_A = 0x10,
CMD_TEST_B,
CMD_TEST_C,
SYS_CMD_INFO_LIMIT,
};
......
......@@ -19,49 +19,80 @@
#include "cvi_spinlock.h"
//#define __DEBUG__
// #define __DEBUG__
#ifdef __DEBUG__
#define debug_printf printf
#else
#define debug_printf(...)
#endif
typedef struct _TASK_CTX_S {
char name[32];
u16 stack_size;
UBaseType_t priority;
void (*runTask)(void *pvParameters);
u8 queLength;
QueueHandle_t queHandle;
} TASK_CTX_S;
/****************************************************************************
* Function prototypes
****************************************************************************/
void prvQueueISR(void);
void prvCmdQuRunTask(void *pvParameters);
/****************************************************************************
* Global parameters
****************************************************************************/
TASK_CTX_S gTaskCtx[1] = {
{
.name = "CMDQU",
.stack_size = configMINIMAL_STACK_SIZE,
.priority = tskIDLE_PRIORITY + 5,
.runTask = prvCmdQuRunTask,
.queLength = 30,
.queHandle = NULL,
},
};
/* mailbox parameters */
volatile struct mailbox_set_register *mbox_reg;
volatile struct mailbox_done_register *mbox_done_reg;
volatile unsigned long *mailbox_context; // mailbox buffer context is 64 Bytess
/****************************************************************************
* Function definitions
****************************************************************************/
DEFINE_CVI_SPINLOCK(mailbox_lock, SPIN_MBOX);
void main_create_tasks(void)
{
u8 i = 0;
#define TASK_INIT(_idx) \
do { \
gTaskCtx[_idx].queHandle = xQueueCreate(gTaskCtx[_idx].queLength, sizeof(cmdqu_t)); \
if (gTaskCtx[_idx].queHandle != NULL && gTaskCtx[_idx].runTask != NULL) { \
xTaskCreate(gTaskCtx[_idx].runTask, gTaskCtx[_idx].name, gTaskCtx[_idx].stack_size, \
NULL, gTaskCtx[_idx].priority, NULL); \
} \
} while(0)
DEFINE_CVI_SPINLOCK(mailbox_lock, SPIN_MBOX);
for (; i < ARRAY_SIZE(gTaskCtx); i++) {
TASK_INIT(i);
}
}
void main_cvirtos(void)
{
printf("create cvi task\n");
/* Start the tasks and timer running. */
request_irq(MBOX_INT_C906_2ND, prvQueueISR, 0, "mailbox", (void *)0);
main_create_tasks();
/* Start the tasks and timer running. */
vTaskStartScheduler();
/* If all is well, the scheduler will now be running, and the following
......@@ -77,3 +108,160 @@ void main_cvirtos(void)
for (;;)
;
}
void prvCmdQuRunTask(void *pvParameters)
{
/* Remove compiler warning about unused parameter. */
(void)pvParameters;
cmdqu_t rtos_cmdq;
cmdqu_t *cmdq;
cmdqu_t *rtos_cmdqu_t;
static int stop_ip = 0;
int ret = 0;
int flags;
int valid;
int send_to_cpu = SEND_TO_CPU1;
unsigned int reg_base = MAILBOX_REG_BASE;
/* to compatible code with linux side */
cmdq = &rtos_cmdq;
mbox_reg = (struct mailbox_set_register *) reg_base;
mbox_done_reg = (struct mailbox_done_register *) (reg_base + 2);
mailbox_context = (unsigned long *) (MAILBOX_REG_BUFF);
cvi_spinlock_init();
printf("prvCmdQuRunTask run\n");
for (;;) {
xQueueReceive(gTaskCtx[0].queHandle, &rtos_cmdq, portMAX_DELAY);
switch (rtos_cmdq.cmd_id) {
case CMD_TEST_A:
//do something
//send to C906B
rtos_cmdq.cmd_id = CMD_TEST_A;
rtos_cmdq.param_ptr = 0x12345678;
rtos_cmdq.resv.valid.rtos_valid = 1;
rtos_cmdq.resv.valid.linux_valid = 0;
printf("recv cmd(%d) from C906B...send [0x%x] to C906B\n", rtos_cmdq.cmd_id, rtos_cmdq.param_ptr);
goto send_label;
case CMD_TEST_B:
//nothing to do
printf("nothing to do...\n");
break;
case CMD_TEST_C:
rtos_cmdq.cmd_id = CMD_TEST_C;
rtos_cmdq.param_ptr = 0x55aa;
rtos_cmdq.resv.valid.rtos_valid = 1;
rtos_cmdq.resv.valid.linux_valid = 0;
printf("recv cmd(%d) from C906B...send [0x%x] to C906B\n", rtos_cmdq.cmd_id, rtos_cmdq.param_ptr);
goto send_label;
default:
send_label:
/* used to send command to linux*/
rtos_cmdqu_t = (cmdqu_t *) mailbox_context;
debug_printf("RTOS_CMDQU_SEND %d\n", send_to_cpu);
debug_printf("ip_id=%d cmd_id=%d param_ptr=%x\n", cmdq->ip_id, cmdq->cmd_id, (unsigned int)cmdq->param_ptr);
debug_printf("mailbox_context = %x\n", mailbox_context);
debug_printf("linux_cmdqu_t = %x\n", rtos_cmdqu_t);
debug_printf("cmdq->ip_id = %d\n", cmdq->ip_id);
debug_printf("cmdq->cmd_id = %d\n", cmdq->cmd_id);
debug_printf("cmdq->block = %d\n", cmdq->block);
debug_printf("cmdq->para_ptr = %x\n", cmdq->param_ptr);
drv_spin_lock_irqsave(&mailbox_lock, flags);
if (flags == MAILBOX_LOCK_FAILED) {
printf("[%s][%d] drv_spin_lock_irqsave failed! ip_id = %d , cmd_id = %d\n" , cmdq->ip_id , cmdq->cmd_id);
break;
}
for (valid = 0; valid < MAILBOX_MAX_NUM; valid++) {
if (rtos_cmdqu_t->resv.valid.linux_valid == 0 && rtos_cmdqu_t->resv.valid.rtos_valid == 0) {
// mailbox buffer context is 4 bytes write access
int *ptr = (int *)rtos_cmdqu_t;
cmdq->resv.valid.rtos_valid = 1;
*ptr = ((cmdq->ip_id << 0) | (cmdq->cmd_id << 8) | (cmdq->block << 15) |
(cmdq->resv.valid.linux_valid << 16) |
(cmdq->resv.valid.rtos_valid << 24));
rtos_cmdqu_t->param_ptr = cmdq->param_ptr;
debug_printf("rtos_cmdqu_t->linux_valid = %d\n", rtos_cmdqu_t->resv.valid.linux_valid);
debug_printf("rtos_cmdqu_t->rtos_valid = %d\n", rtos_cmdqu_t->resv.valid.rtos_valid);
debug_printf("rtos_cmdqu_t->ip_id =%x %d\n", &rtos_cmdqu_t->ip_id, rtos_cmdqu_t->ip_id);
debug_printf("rtos_cmdqu_t->cmd_id = %d\n", rtos_cmdqu_t->cmd_id);
debug_printf("rtos_cmdqu_t->block = %d\n", rtos_cmdqu_t->block);
debug_printf("rtos_cmdqu_t->param_ptr addr=%x %x\n", &rtos_cmdqu_t->param_ptr, rtos_cmdqu_t->param_ptr);
debug_printf("*ptr = %x\n", *ptr);
// clear mailbox
mbox_reg->cpu_mbox_set[send_to_cpu].cpu_mbox_int_clr.mbox_int_clr = (1 << valid);
// trigger mailbox valid to rtos
mbox_reg->cpu_mbox_en[send_to_cpu].mbox_info |= (1 << valid);
mbox_reg->mbox_set.mbox_set = (1 << valid);
break;
}
rtos_cmdqu_t++;
}
drv_spin_unlock_irqrestore(&mailbox_lock, flags);
if (valid >= MAILBOX_MAX_NUM) {
printf("No valid mailbox is available\n");
return -1;
}
break;
}
}
}
void prvQueueISR(void)
{
printf("prvQueueISR\n");
unsigned char set_val;
unsigned char valid_val;
int i;
cmdqu_t *cmdq;
BaseType_t YieldRequired = pdFALSE;
set_val = mbox_reg->cpu_mbox_set[RECEIVE_CPU].cpu_mbox_int_int.mbox_int;
if (set_val) {
for(i = 0; i < MAILBOX_MAX_NUM; i++) {
valid_val = set_val & (1 << i);
if (valid_val) {
cmdqu_t rtos_cmdq;
cmdq = (cmdqu_t *)(mailbox_context) + i;
debug_printf("mailbox_context =%x\n", mailbox_context);
debug_printf("sizeof mailbox_context =%x\n", sizeof(cmdqu_t));
/* mailbox buffer context is send from linux, clear mailbox interrupt */
mbox_reg->cpu_mbox_set[RECEIVE_CPU].cpu_mbox_int_clr.mbox_int_clr = valid_val;
// need to disable enable bit
mbox_reg->cpu_mbox_en[RECEIVE_CPU].mbox_info &= ~valid_val;
// copy cmdq context (8 bytes) to buffer ASAP
*((unsigned long *) &rtos_cmdq) = *((unsigned long *)cmdq);
/* need to clear mailbox interrupt before clear mailbox buffer */
*((unsigned long*) cmdq) = 0;
/* mailbox buffer context is send from linux*/
if (rtos_cmdq.resv.valid.linux_valid == 1) {
debug_printf("cmdq=%x\n", cmdq);
debug_printf("cmdq->ip_id =%d\n", rtos_cmdq.ip_id);
debug_printf("cmdq->cmd_id =%d\n", rtos_cmdq.cmd_id);
debug_printf("cmdq->param_ptr =%x\n", rtos_cmdq.param_ptr);
debug_printf("cmdq->block =%x\n", rtos_cmdq.block);
debug_printf("cmdq->linux_valid =%d\n", rtos_cmdq.resv.valid.linux_valid);
debug_printf("cmdq->rtos_valid =%x\n", rtos_cmdq.resv.valid.rtos_valid);
xQueueSendFromISR(gTaskCtx[0].queHandle, &rtos_cmdq, &YieldRequired);
portYIELD_FROM_ISR(YieldRequired);
} else
printf("rtos cmdq is not valid %d, ip=%d , cmd=%d\n",
rtos_cmdq.resv.valid.rtos_valid, rtos_cmdq.ip_id, rtos_cmdq.cmd_id);
}
}
}
}
......@@ -103,6 +103,7 @@ within this file. */
void vApplicationMallocFailedHook(void);
void vApplicationIdleHook(void);
void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName);
void vApplicationTickHook(void);
/* configAPPLICATION_ALLOCATED_HEAP is set to 1 in FreeRTOSConfig.h so the
application can define the array used as the FreeRTOS heap. This is done so the
......@@ -220,6 +221,17 @@ void vApplicationIdleHook(void)
}
/*-----------------------------------------------------------*/
void vApplicationTickHook(void)
{
#ifdef FULL_DEMO
{
/* Only the comprehensive demo actually uses the tick hook. */
extern void vFullDemoTickHook(void);
vFullDemoTickHook();
}
#endif
}
/*-----------------------------------------------------------*/
/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
......
......@@ -30,4 +30,5 @@ config CVI_BT_PIN
GPIO number to do certain action, ex. power on
or wakeup pin.
source "drivers/soc/cvitek/rtos_cmdqu/Kconfig"
endmenu
obj-$(CONFIG_CV1835_SYSDMA_REMAP) += sysdma/cv1835_dma_remap.o
obj-$(CONFIG_CVI_WIFI_PIN) += wifi_pin/cvi_wifi_pin.o
obj-$(CONFIG_CVI_BT_PIN) += bt_pin/cvi_bt_pin.o
\ No newline at end of file
obj-$(CONFIG_CVI_BT_PIN) += bt_pin/cvi_bt_pin.o
obj-$(CONFIG_CVI_MAILBOX) += rtos_cmdqu/
config CVI_MAILBOX
tristate "cv180x/cv181x mailbox dirver"
help
"cv180x/cv181x mailbox driver"
obj-$(CONFIG_CVI_MAILBOX) := cvi_mbox.o
cvi_mbox-y := rtos_cmdqu.o \
cvi_spinlock.o
ccflags-y += -I$(srctree)/$(src)/
#ifndef __CVI_MAILBOX_H__
#define __CVI_MAILBOX_H__
union cpu_mailbox_info_offset{
char mbox_info;
int reserved;
};
union cpu_mailbox_int_clr_offset{
char mbox_int_clr;
int reserved;
};
union cpu_mailbox_int_mask_offset{
char mbox_int_mask;
int reserved;
};
union cpu_mailbox_int_offset{
char mbox_int;
int reserved;
};
union cpu_mailbox_int_raw_offset{
char mbox_int_raw;
int reserved;
};
union mailbox_set{
char mbox_set;
int reserved;
};
union mailbox_status{
char mbox_status;
int reserved;
};
union cpu_mailbox_status{
char mbox_status;
int reserved;
};
/* register mapping refers to mailbox user guide*/
struct cpu_mbox_int{
union cpu_mailbox_int_clr_offset cpu_mbox_int_clr;
union cpu_mailbox_int_mask_offset cpu_mbox_int_mask;
union cpu_mailbox_int_offset cpu_mbox_int_int;
union cpu_mailbox_int_raw_offset cpu_mbox_int_raw;
};
struct mailbox_set_register{
union cpu_mailbox_info_offset cpu_mbox_en[4]; //0x00, 0x04, 0x08, 0x0c
struct cpu_mbox_int cpu_mbox_set[4]; //0x10~0x1C, 0x20~0x2C, 0x30~0x3C, 0x40~0x4C
int reserved[4]; //0x50~0x5C
union mailbox_set mbox_set; //0x60
union mailbox_status mbox_status; //0x64
int reserved2[2]; //0x68~0x6C
union cpu_mailbox_status cpu_mbox_status[4]; //0x70
};
struct mailbox_done_register{
union cpu_mailbox_info_offset cpu_mbox_done_en[4];
struct cpu_mbox_int cpu_mbox_done[4];
};
volatile struct mailbox_set_register *mbox_reg;
volatile struct mailbox_done_register *mbox_done_reg;
volatile unsigned long *mailbox_context; // mailbox buffer context is 64 Bytess
#define MAILBOX_MAX_NUM 0x0008
#define MAILBOX_DONE_OFFSET 0x0002
#define MAILBOX_CONTEXT_OFFSET 0x0400
// C906B
#define RECEIVE_CPU 1
// C906L
#define SEND_TO_CPU 2
#endif // end of__CVI_MAILBOX_H__
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) Cvitek Co., Ltd. 2019-2022. All rights reserved.
*
* File Name: cvi_spinlock.c
* Description:
*/
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_reserved_mem.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include "cvi_spinlock.h"
static unsigned long reg_base;
spinlock_t reg_write_lock;
static unsigned char lockCount[SPIN_MAX+1] = {0};
static void *__iomem c906l_pc_reg;
void cvi_spinlock_init(void)
{
spin_lock_init(&reg_write_lock);
c906l_pc_reg = ioremap(0x1901070, 4);
if (c906l_pc_reg == NULL) {
pr_err("c906l_pc_reg ioremap failed!\n");
}
pr_info("[%s] success\n", __func__);
}
void cvi_spinlock_uninit(void)
{
iounmap(c906l_pc_reg);
}
void spinlock_base(unsigned long mb_base)
{
reg_base = mb_base;
}
static inline int hw_spin_trylock(hw_raw_spinlock_t *lock)
{
writew(lock->locks, (void *)(reg_base + sizeof(int) * lock->hw_field));
if (readw((void *)(reg_base + sizeof(int) * lock->hw_field)) == lock->locks)
return MAILBOX_LOCK_SUCCESS;
return MAILBOX_LOCK_FAILED;
}
int hw_spin_lock(hw_raw_spinlock_t *lock)
{
u64 i;
u64 loops = 1000000;
hw_raw_spinlock_t _lock = {.hw_field = lock->hw_field, .locks=lock->locks};
if (lock->hw_field >= SPIN_LINUX_RTOS) {
unsigned long flags;
spin_lock_irqsave(&reg_write_lock, flags);
if (lockCount[lock->hw_field] == 0) {
lockCount[lock->hw_field]++;
}
_lock.locks = lockCount[lock->hw_field];
lockCount[lock->hw_field]++;
spin_unlock_irqrestore(&reg_write_lock, flags);
}
else {
//....
}
for (i = 0; i < loops; i++) {
if (hw_spin_trylock(&_lock) == MAILBOX_LOCK_SUCCESS)
{
lock->locks = _lock.locks;
return MAILBOX_LOCK_SUCCESS;
}
udelay(1);
}
pr_err("__spin_lock_debug fail! loops = %lld\n", loops);
return MAILBOX_LOCK_FAILED;
}
int _hw_raw_spin_lock_irqsave(hw_raw_spinlock_t *lock)
{
int flag = MAILBOX_LOCK_SUCCESS;
// lock
if (hw_spin_lock(lock) == MAILBOX_LOCK_FAILED) {
pr_err("spin lock fail! C906L pc = 0x%x,reg_val=0x%x, lock->locks=0x%x\n",
ioread32(c906l_pc_reg), readw((void *)(reg_base + sizeof(int) * lock->hw_field)), lock->locks);
return MAILBOX_LOCK_FAILED;
}
return flag;
}
void _hw_raw_spin_unlock_irqrestore(hw_raw_spinlock_t *lock, int flag)
{
// unlock
if (readw((void *)(reg_base + sizeof(int) * lock->hw_field)) == lock->locks) {
writew(lock->locks, (void *)(reg_base + sizeof(int) * lock->hw_field));
} else {
pr_err("spin unlock fail! C906L pc=0x%x,reg_val=0x%x, lock->locks=0x%x\n",
ioread32(c906l_pc_reg), readw((void *)(reg_base + sizeof(int) * lock->hw_field)), lock->locks);
}
}
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DRV_SPINLOCK_H__
#define __DRV_SPINLOCK_H__
enum SPINLOCK_FIELD {
SPIN_UART,
SPIN_LINUX_RTOS = 4, // this spinlock field is used for linux & rtos
SPIN_MBOX = SPIN_LINUX_RTOS,
SPIN_MAX = 7,
};
typedef struct hw_raw_spinlock {
unsigned short locks;
unsigned short hw_field;
} hw_raw_spinlock_t;
#define MAILBOX_LOCK_SUCCESS 1
#define MAILBOX_LOCK_FAILED (-1)
#define __CVI_ARCH_SPIN_LOCK_UNLOCKED \
(0)
#define __CVI_RAW_SPIN_LOCK_INITIALIZER(spinlock_hw_field) \
{ .locks = __CVI_ARCH_SPIN_LOCK_UNLOCKED, .hw_field = spinlock_hw_field, }
#define DEFINE_CVI_SPINLOCK(x, y) \
hw_raw_spinlock_t x = __CVI_RAW_SPIN_LOCK_INITIALIZER(y)
int _hw_raw_spin_lock_irqsave(hw_raw_spinlock_t *lock);
void _hw_raw_spin_unlock_irqrestore(hw_raw_spinlock_t *lock, int flag);
#define drv_spin_lock_irqsave(lock, flags) \
{ flags = _hw_raw_spin_lock_irqsave(lock); }
#define drv_spin_unlock_irqrestore(lock, flags) \
_hw_raw_spin_unlock_irqrestore(lock, flags)
void spinlock_base(unsigned long mb_base);
void cvi_spinlock_init(void);
void cvi_spinlock_uninit(void);
#endif // end of __DRV_SPINLOCK_H__
This diff is collapsed.
#ifndef __RTOS_COMMAND_QUEUE__
#define __RTOS_COMMAND_QUEUE__
#include <linux/kernel.h>
#define NR_SYSTEM_CMD 20
struct valid_t {
unsigned char linux_valid;
unsigned char rtos_valid;
} __attribute__((packed));
typedef union resv_t {
struct valid_t valid;
unsigned short mstime; // 0 : noblock, -1 : block infinite
} resv_t;
typedef struct cmdqu_t cmdqu_t;
/* cmdqu size should be 8 bytes because of mailbox buffer size */
struct cmdqu_t {
unsigned char ip_id;
unsigned char cmd_id : 7;
unsigned char block : 1;
union resv_t resv;
unsigned int param_ptr;
} __attribute__((packed)) __attribute__((aligned(0x8)));
/* keep those commands for ioctl system used */
enum SYSTEM_CMD_TYPE {
CMDQU_SEND = 1,
CMDQU_SEND_WAIT,
CMDQU_SEND_WAKEUP,
CMDQU_SYSTEM_LIMIT = NR_SYSTEM_CMD,
};
enum SYS_CMD_ID {
CMD_TEST_A = 0x10,
CMD_TEST_B,
CMD_TEST_C,
SYS_CMD_INFO_LIMIT,
};
#define RTOS_CMDQU_DEV_NAME "cvi-rtos-cmdqu"
#define RTOS_CMDQU_SEND _IOW('r', CMDQU_SEND, unsigned long)
#define RTOS_CMDQU_SEND_WAIT _IOW('r', CMDQU_SEND_WAIT, unsigned long)
#define RTOS_CMDQU_SEND_WAKEUP _IOW('r', CMDQU_SEND_WAKEUP, unsigned long)
int rtos_cmdqu_send(cmdqu_t *cmdq);
int rtos_cmdqu_send_wait(cmdqu_t *cmdq, int wait_cmd_id);
#endif // end of __RTOS_COMMAND_QUEUE__
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment