diff --git a/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig b/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig index 35a5b75ec..8a0330893 100644 --- a/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig +++ b/build/boards/cv180x/cv1800b_milkv_duo_sd/linux/cvitek_cv1800b_milkv_duo_sd_defconfig @@ -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 diff --git a/freertos/cvitek/driver/rtos_cmdqu/include/rtos_cmdqu.h b/freertos/cvitek/driver/rtos_cmdqu/include/rtos_cmdqu.h index 92db0c87d..5d329e11d 100644 --- a/freertos/cvitek/driver/rtos_cmdqu/include/rtos_cmdqu.h +++ b/freertos/cvitek/driver/rtos_cmdqu/include/rtos_cmdqu.h @@ -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, }; diff --git a/freertos/cvitek/task/comm/src/riscv64/comm_main.c b/freertos/cvitek/task/comm/src/riscv64/comm_main.c index a3dfd862f..c90889ae3 100644 --- a/freertos/cvitek/task/comm/src/riscv64/comm_main.c +++ b/freertos/cvitek/task/comm/src/riscv64/comm_main.c @@ -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) + + 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); + } + } + } +} diff --git a/freertos/cvitek/task/main/src/main.c b/freertos/cvitek/task/main/src/main.c index ac6dd9d6d..4c1d191eb 100644 --- a/freertos/cvitek/task/main/src/main.c +++ b/freertos/cvitek/task/main/src/main.c @@ -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 diff --git a/linux_5.10/drivers/soc/cvitek/Kconfig b/linux_5.10/drivers/soc/cvitek/Kconfig index b9c128724..d18c83d38 100644 --- a/linux_5.10/drivers/soc/cvitek/Kconfig +++ b/linux_5.10/drivers/soc/cvitek/Kconfig @@ -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 diff --git a/linux_5.10/drivers/soc/cvitek/Makefile b/linux_5.10/drivers/soc/cvitek/Makefile index 0f7fd8c47..357dd22d4 100644 --- a/linux_5.10/drivers/soc/cvitek/Makefile +++ b/linux_5.10/drivers/soc/cvitek/Makefile @@ -1,3 +1,4 @@ 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/ diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Kconfig b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Kconfig new file mode 100644 index 000000000..047ea3ad6 --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Kconfig @@ -0,0 +1,4 @@ +config CVI_MAILBOX + tristate "cv180x/cv181x mailbox dirver" + help + "cv180x/cv181x mailbox driver" diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Makefile b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Makefile new file mode 100644 index 000000000..c87f9994e --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_CVI_MAILBOX) := cvi_mbox.o +cvi_mbox-y := rtos_cmdqu.o \ + cvi_spinlock.o + +ccflags-y += -I$(srctree)/$(src)/ diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_mailbox.h b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_mailbox.h new file mode 100644 index 000000000..0560e4b2b --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_mailbox.h @@ -0,0 +1,77 @@ +#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__ + diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.c b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.c new file mode 100644 index 000000000..efa41288a --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Cvitek Co., Ltd. 2019-2022. All rights reserved. + * + * File Name: cvi_spinlock.c + * Description: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#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(®_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(®_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(®_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); + } +} diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.h b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.h new file mode 100644 index 000000000..c6a35e532 --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.h @@ -0,0 +1,43 @@ +/* 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__ diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.c b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.c new file mode 100644 index 000000000..a3a85294d --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.c @@ -0,0 +1,530 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtos_cmdqu.h" +#include "cvi_mailbox.h" +#include "cvi_spinlock.h" + +struct cvi_rtos_cmdqu_device { + struct device *dev; + struct miscdevice miscdev; +}; + +spinlock_t mailbox_queue_lock; +spinlock_t send_queue_lock; +static __u64 reg_base; +static int mailbox_irq; + +static int cvi_rtos_cmdqu_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int cvi_rtos_cmdqu_release(struct inode *inode, struct file *file) +{ + return 0; +} + +struct rtos_cmdqu_wait_list_t { + struct list_head list; + cmdqu_t cmdq; + wait_queue_head_t wq; + int condition; +}; + +static struct rtos_cmdqu_wait_list_t rtos_cmdqu_wait_head; + +/* used for callback test*/ +static void callback_rtos_irq_handler(int cmd_id, unsigned int ptr, void *dev_id) +{ + pr_info("callback_rtos_hander cmd_id = %x ptr=%x dev_id=%p\n", cmd_id, ptr, dev_id); +} + +DEFINE_CVI_SPINLOCK(mailbox_lock, SPIN_MBOX); + +irqreturn_t rtos_irq_handler(int irq, void *dev_id) +{ + char set_val, done_val; + int i; + int flags; + cmdqu_t *cmdq; + + struct rtos_cmdqu_wait_list_t *wait_list; + struct list_head *pos; + + drv_spin_lock_irqsave(&mailbox_lock, flags); + if (flags == MAILBOX_LOCK_FAILED) { + pr_err("drv_spin_lock_irqsave failed!\n"); + //must clear irq? + return IRQ_HANDLED; + } + pr_info("rtos_irq_handler irq=%d\n", irq); + set_val = mbox_reg->cpu_mbox_set[RECEIVE_CPU].cpu_mbox_int_int.mbox_int; + done_val = mbox_done_reg->cpu_mbox_done[RECEIVE_CPU].cpu_mbox_int_int.mbox_int; + pr_debug("set_val=%x\n", set_val); + pr_debug("done_val=%x\n", done_val); + + for (i = 0; i < MAILBOX_MAX_NUM && set_val > 0; i++) { + /* valid_val uses unsigned char because of mailbox register table + * ~valid_val will be 0xFF + */ + unsigned char valid_val = set_val & (1 << i); + + pr_debug("MAILBOX_MAX_NUM = %d\n", MAILBOX_MAX_NUM); + pr_debug("valid_val = %d set_val=%d i = %d\n", valid_val, set_val, i); + if (valid_val) { + cmdqu_t linux_cmdq; + + cmdq = (cmdqu_t *)(mailbox_context) + i; + /* mailbox buffer context is send from rtos, 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 long *) &linux_cmdq) = *((unsigned long long *)cmdq); + /* need to clear mailbox interrupt before clear mailbox buffer ??*/ + *((unsigned long long *) cmdq) = 0; + + /* mailbox buffer context is send from rtos */ + pr_debug("cmdq=%p\n", cmdq); + pr_debug("cmdq->ip_id =%d\n", linux_cmdq.ip_id); + pr_debug("cmdq->cmd_id =%d\n", linux_cmdq.cmd_id); + pr_debug("cmdq->param_ptr =%x\n", linux_cmdq.param_ptr); + pr_debug("cmdq->block =%d\n", linux_cmdq.block); + pr_debug("cmdq->linux_valid =%d\n", linux_cmdq.resv.valid.linux_valid); + pr_debug("cmdq->rtos_valid =%x", linux_cmdq.resv.valid.rtos_valid); + if (linux_cmdq.resv.valid.rtos_valid == 1 && + linux_cmdq.block == 1) { + // dewait + list_for_each(pos, &rtos_cmdqu_wait_head.list) { + wait_list = list_entry(pos, struct rtos_cmdqu_wait_list_t, list); + pr_debug("s wait_list->cmdq.ip_id=%d\n", wait_list->cmdq.ip_id); + pr_debug("s wait_list->cmdq.cmd_id=%d\n", wait_list->cmdq.cmd_id); + if (wait_list->cmdq.ip_id == linux_cmdq.ip_id && + wait_list->cmdq.cmd_id == linux_cmdq.cmd_id) { + /* copy data to wait_list and return to user space */ + *((unsigned long long *) &wait_list->cmdq) = + *((unsigned long long *) &linux_cmdq); + pr_debug("wait_list->cmdq.ip_id=%d\n", + wait_list->cmdq.ip_id); + pr_debug("wait_list->cmdq.cmd_id=%d\n", + wait_list->cmdq.cmd_id); + pr_debug("wait_list->cmdq.param_ptr=%x\n", + wait_list->cmdq.param_ptr); + + wait_list->condition = 1; + wake_up_interruptible(&wait_list->wq); + break; + } + } + } else + pr_err("error ip=%d , cmd=%d\n", linux_cmdq.ip_id, linux_cmdq.cmd_id); + } + } + drv_spin_unlock_irqrestore(&mailbox_lock, flags); + return IRQ_HANDLED; +} + +long rtos_cmdqu_init(void) +{ + long ret = 0; + int i; + + pr_debug("RTOS_CMDQU_INIT\n"); + spin_lock_init(&mailbox_queue_lock); + spin_lock_init(&send_queue_lock); + mbox_reg = (struct mailbox_set_register *) reg_base; + mbox_done_reg = (struct mailbox_done_register *) (reg_base + MAILBOX_DONE_OFFSET); + mailbox_context = (unsigned long *) (reg_base + MAILBOX_CONTEXT_OFFSET);//MAILBOX_CONTEXT; + + pr_debug("mbox_reg=%p\n", mbox_reg); + pr_debug("mbox_done_reg=%p\n", mbox_done_reg); + pr_debug("mailbox_context=%p\n", mailbox_context); + + // init mailbox_context + for ( i=0;i < MAILBOX_MAX_NUM;i++) + mailbox_context[i] = 0; + /* init sqirq parameters*/ + return ret; +} + +long rtos_cmdqu_deinit(void) +{ + long ret = 0; + pr_debug("RTOS_CMDQU_DEINIT\n"); + //mailbox deinit + return ret; +} + +int rtos_cmdqu_send(cmdqu_t *cmdq) +{ + int ret = 0; + int valid; + unsigned long flags; + int mb_flags; + cmdqu_t *linux_cmdqu_t; + + pr_debug("RTOS_CMDQU_SEND\n"); + pr_debug("ip_id=%d cmd_id=%d param_ptr=%x\n", cmdq->ip_id, cmdq->cmd_id, (unsigned int)cmdq->param_ptr); + + spin_lock_irqsave(&mailbox_queue_lock, flags); + // when linux and rtos send command at the same time, it might cause a problem. + // might need to spinlock with rtos, do it later + drv_spin_lock_irqsave(&mailbox_lock, mb_flags); + if (mb_flags == MAILBOX_LOCK_FAILED) { + pr_err("ip_id=%d cmd_id=%d param_ptr=%x\n", cmdq->ip_id, cmdq->cmd_id, (unsigned int)cmdq->param_ptr); + spin_unlock_irqrestore(&mailbox_queue_lock, flags); + return -ENOBUFS; + } + linux_cmdqu_t = (cmdqu_t *) mailbox_context; + pr_debug("mailbox_context = %p\n", mailbox_context); + pr_debug("linux_cmdqu_t = %p\n", linux_cmdqu_t); + pr_debug("cmdq->ip_id = %d\n", cmdq->ip_id); + pr_debug("cmdq->cmd_id = %d\n", cmdq->cmd_id); + pr_debug("cmdq->block = %d\n", cmdq->block); + pr_debug("cmdq->para_ptr = %d\n", cmdq->param_ptr); + + for (valid = 0; valid < MAILBOX_MAX_NUM; valid++) { + if (linux_cmdqu_t->resv.valid.linux_valid == 0 && linux_cmdqu_t->resv.valid.rtos_valid == 0) { + // mailbox buffer context is int (4 bytes) access + int *ptr = (int *)linux_cmdqu_t; + + linux_cmdqu_t->resv.valid.linux_valid = 1; + *ptr = ((cmdq->ip_id << 0) | (cmdq->cmd_id << 8) | (cmdq->block << 15) | + (linux_cmdqu_t->resv.valid.linux_valid << 16) | + (linux_cmdqu_t->resv.valid.rtos_valid << 24)); + linux_cmdqu_t->param_ptr = cmdq->param_ptr; + pr_debug("linux_valid = %d\n", linux_cmdqu_t->resv.valid.linux_valid); + pr_debug("rtos_valid = %d\n", linux_cmdqu_t->resv.valid.rtos_valid); + pr_debug("ip_id = %d\n", linux_cmdqu_t->ip_id); + pr_debug("cmd_id = %d\n", linux_cmdqu_t->cmd_id); + pr_debug("block = %d\n", linux_cmdqu_t->block); + pr_debug("param_ptr = %x\n", linux_cmdqu_t->param_ptr); + pr_debug("*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; + } + linux_cmdqu_t++; + } + + if (valid >= MAILBOX_MAX_NUM) { + pr_err("No valid mailbox is available\n"); + drv_spin_unlock_irqrestore(&mailbox_lock, mb_flags); + spin_unlock_irqrestore(&mailbox_queue_lock, flags); + return -ENOBUFS; + } + drv_spin_unlock_irqrestore(&mailbox_lock, mb_flags); + spin_unlock_irqrestore(&mailbox_queue_lock, flags); + return ret; +} +EXPORT_SYMBOL(rtos_cmdqu_send); + +int rtos_cmdqu_send_wait(cmdqu_t *cmdq, int wait_cmd_id) +{ + unsigned long flags; + struct rtos_cmdqu_wait_list_t *wait_list; + struct list_head *pos; + int delaytime; + int ret = 0; + + pr_debug("%s %d\n", __func__, __LINE__); + + spin_lock_irqsave(&send_queue_lock, flags); + /* check list with same commands? if yes, ignore it */ + list_for_each(pos, &rtos_cmdqu_wait_head.list) { + wait_list = list_entry(pos, struct rtos_cmdqu_wait_list_t, list); + pr_debug("list->cmdq.ip_id=%d\n", wait_list->cmdq.ip_id); + pr_debug("list->cmdq.cmd_id=%d\n", wait_list->cmdq.cmd_id); + if (cmdq->ip_id == wait_list->cmdq.ip_id && + wait_cmd_id == wait_list->cmdq.cmd_id) { + + pr_debug("exist : wait_list->cmdq.ip_id=%d\n", wait_list->cmdq.ip_id); + pr_debug("exist : wait_list->cmdq.cmd_id=%d\n", wait_list->cmdq.cmd_id); + pr_debug("exist : wait_list->cmdq.param_ptr=%d\n", wait_list->cmdq.param_ptr); + spin_unlock_irqrestore(&send_queue_lock, flags); + return -EEXIST; + + } + } + cmdq->block = 1; + + wait_list = kzalloc(sizeof(struct rtos_cmdqu_wait_list_t), GFP_KERNEL); + + if (!wait_list) { + spin_unlock_irqrestore(&send_queue_lock, flags); + return -ENOMEM; + } + + *((unsigned long long *) &wait_list->cmdq) = *((unsigned long long *) cmdq); + wait_list->cmdq.cmd_id = wait_cmd_id; + + init_waitqueue_head(&wait_list->wq); + list_add_tail(&wait_list->list, &rtos_cmdqu_wait_head.list); + + spin_unlock_irqrestore(&send_queue_lock, flags); + /* check the delay ms + * if mstime is 65535 (-1), it will be blocked infinite (MAX_JIFFY_OFFSET) + */ + + delaytime = wait_list->cmdq.resv.mstime; + if (delaytime == 0xFFFF) + delaytime = -1; + + ret = rtos_cmdqu_send(cmdq); + + ret = wait_event_interruptible_timeout(wait_list->wq, + wait_list->condition != 0, msecs_to_jiffies(delaytime)); + spin_lock_irqsave(&send_queue_lock, flags); + list_del_init(&wait_list->list); + spin_unlock_irqrestore(&send_queue_lock, flags); + if (!ret) { + ret = -ETIME; + kfree(wait_list); + pr_err("RTOS_CMDQU_SEND_WAIT timeout\n"); + return ret; + } + pr_debug("RTOS_CMDQU_SEND_WAIT done\n"); + pr_debug("list wait_list->cmdq.ip_id=%d wait_list->cmdq.cmd_id=%d wait_list->cmdq.param_ptr=%x\n", + wait_list->cmdq.ip_id, wait_list->cmdq.cmd_id, wait_list->cmdq.param_ptr); + + /* get context from interrupt and return to userspace */ + *((unsigned long long *) cmdq) = *((unsigned long long *) &wait_list->cmdq); + kfree(wait_list); + return 0; +} +EXPORT_SYMBOL(rtos_cmdqu_send_wait); + +static long cvi_rtos_cmdqu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct cvi_rtos_cmdqu_device *dev = filp->private_data; + struct rtos_cmdqu_wait_list_t *wait_list; + struct list_head *pos; + long ret = 0; + unsigned long flags; + cmdqu_t cmdq; + + pr_debug("%s dev=%p\n", __func__, dev); + switch (cmd) { + case RTOS_CMDQU_SEND: + pr_debug("RTOS_CMDQU_SEND\n"); + copy_from_user(&cmdq, + (struct cmdqu_t __user *)arg, + sizeof(struct cmdqu_t)); + ret = rtos_cmdqu_send(&cmdq); + break; + case RTOS_CMDQU_SEND_WAKEUP: + pr_debug("RTOS_CMDQU_SEND_WAKEUP\n"); + copy_from_user(&cmdq, + (struct cmdqu_t __user *)arg, + sizeof(struct cmdqu_t)); + pr_debug("cmdq.ip_id=%d cmdq.cmd_id=%d\n", cmdq.ip_id, cmdq.cmd_id); + + spin_lock_irqsave(&send_queue_lock, flags); + list_for_each(pos, &rtos_cmdqu_wait_head.list) { + wait_list = list_entry(pos, struct rtos_cmdqu_wait_list_t, list); + pr_debug("list->cmdq.ip_id=%d\n", wait_list->cmdq.ip_id); + pr_debug("list->cmdq.cmd_id=%d\n", wait_list->cmdq.cmd_id); + if (cmdq.ip_id == wait_list->cmdq.ip_id && + cmdq.cmd_id == wait_list->cmdq.cmd_id && + wait_list->cmdq.block == 1) { + /* copy data to wait_list and return to user space */ + *((unsigned long long *) &wait_list->cmdq) = *((unsigned long long *) &cmdq); + pr_debug("wait_list->cmdq.ip_id=%d\n", wait_list->cmdq.ip_id); + pr_debug("wait_list->cmdq.cmd_id=%d\n", wait_list->cmdq.cmd_id); + pr_debug("wait_list->cmdq.param_ptr=%d\n", wait_list->cmdq.param_ptr); + + wait_list->condition = 1; + wake_up_interruptible(&wait_list->wq); + break; + } + } + spin_unlock_irqrestore(&send_queue_lock, flags); + pr_debug("RTOS_CMDQU_SEND_WAKEUP done\n"); + break; + + case RTOS_CMDQU_SEND_WAIT: + pr_debug("RTOS_CMDQU_SEND_WAIT\n"); + ret = copy_from_user(&cmdq, + (struct cmdqu_t __user *)arg, + sizeof(struct cmdqu_t)); + if (ret) { + return -EFAULT; + } + rtos_cmdqu_send_wait(&cmdq, cmdq.cmd_id); + ret = copy_to_user((struct cmdqu_t __user *)arg, + &cmdq, + sizeof(struct cmdqu_t)); + break; + default: + ret = -EFAULT; + break; + } + return ret; +} + +static const struct file_operations rtos_cmdqu_fops = { + .owner = THIS_MODULE, + .open = cvi_rtos_cmdqu_open, + .release = cvi_rtos_cmdqu_release, + .unlocked_ioctl = cvi_rtos_cmdqu_ioctl, +}; + +static int _register_dev(struct cvi_rtos_cmdqu_device *ndev) +{ + int rc; + + ndev->miscdev.minor = MISC_DYNAMIC_MINOR; + ndev->miscdev.name = RTOS_CMDQU_DEV_NAME; + ndev->miscdev.fops = &rtos_cmdqu_fops; + + rc = misc_register(&ndev->miscdev); + if (rc) { + dev_err(ndev->dev, "cvi_rtos_cmdqu: failed to register misc device.\n"); + return rc; + } + + return 0; +} + +static int cvi_rtos_cmdqu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cvi_rtos_cmdqu_device *ndev; + struct resource *res; + int ret = 0; + int err = -1; + + pr_info("%s start ---\n", __func__); + pr_info("name=%s\n", pdev->name); + ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL); + if (!ndev) + return -ENOMEM; + + ndev->dev = dev; + + ret = _register_dev(ndev); + if (ret < 0) { + pr_err("regsiter cvi_rtos_cmdqu chrdev error\n"); + return ret; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + +// void __iomem *regs; +// regs = devm_ioremap_resource(dev, res); +// if (IS_ERR(regs)) { +// ret = PTR_ERR(regs); +// goto ERROR_PROVE_DEVICE; +// } +// printk("regs=%x\n", regs); + + reg_base = (__u64)devm_ioremap(&pdev->dev, res->start, + res->end - res->start); + + pr_info("res-reg: start: 0x%llx, end: 0x%llx, virt-addr(%llx).\n", + res->start, res->end, le64_to_cpu(reg_base)); + // spinlock ip offset address (0xc0) + spinlock_base(reg_base + 0xc0); + mailbox_irq = platform_get_irq_byname(pdev, "mailbox"); + + INIT_LIST_HEAD(&rtos_cmdqu_wait_head.list); + /* init cmdqu*/ + rtos_cmdqu_init(); + platform_set_drvdata(pdev, ndev); + + err = request_irq(mailbox_irq, rtos_irq_handler, 0, "mailbox", + (void *)ndev); + + if (err) { + pr_err("fail to register interrupt handler\n"); + return -1; + } + + pr_info("%s DONE\n", __func__); + return 0; + +//ERROR_PROVE_DEVICE: +// return err; +} + +static int cvi_rtos_cmdqu_remove(struct platform_device *pdev) +{ + struct cvi_rtos_cmdqu_device *ndev = platform_get_drvdata(pdev); + + misc_deregister(&ndev->miscdev); + platform_set_drvdata(pdev, NULL); + /* remove irq handler*/ + free_irq(mailbox_irq, ndev); + rtos_cmdqu_deinit(); + pr_debug("%s DONE\n", __func__); + + return 0; +} + +static const struct of_device_id cvi_rtos_cmdqu_match[] = { + { .compatible = "cvitek,rtos_cmdqu" }, + {}, +}; + +static struct platform_driver cvi_rtos_cmdqu_driver = { + .probe = cvi_rtos_cmdqu_probe, + .remove = cvi_rtos_cmdqu_remove, + .driver = { + .owner = THIS_MODULE, + .name = RTOS_CMDQU_DEV_NAME, + .of_match_table = cvi_rtos_cmdqu_match, + }, +}; + +struct class *pbase_class; +static void cvi_rtos_cmdqu_exit(void) +{ + platform_driver_unregister(&cvi_rtos_cmdqu_driver); + class_destroy(pbase_class); + cvi_spinlock_uninit(); + pr_debug("%s DONE\n", __func__); +} + +static int cvi_rtos_cmdqu_init(void) +{ + int rc; + pr_info("cvi_rtos_cmdqu_init\n"); + pbase_class = class_create(THIS_MODULE, RTOS_CMDQU_DEV_NAME); + if (IS_ERR(pbase_class)) { + pr_err("create class failed\n"); + rc = PTR_ERR(pbase_class); + goto cleanup; + } + + platform_driver_register(&cvi_rtos_cmdqu_driver); + pr_debug("%s done\n", __func__); + cvi_spinlock_init(); + return 0; +cleanup: + cvi_rtos_cmdqu_exit(); + return rc; +} + +MODULE_DESCRIPTION("RTOS_CMD_QUEUE"); +MODULE_LICENSE("GPL"); +module_init(cvi_rtos_cmdqu_init); +module_exit(cvi_rtos_cmdqu_exit); diff --git a/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.h b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.h new file mode 100644 index 000000000..6281da79a --- /dev/null +++ b/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.h @@ -0,0 +1,51 @@ +#ifndef __RTOS_COMMAND_QUEUE__ +#define __RTOS_COMMAND_QUEUE__ + +#include + +#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__