Add mailbox based inter-processor communication
This commit is contained in:
@ -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,
|
||||
};
|
||||
|
||||
|
||||
@ -20,48 +20,79 @@
|
||||
|
||||
|
||||
// #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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
obj-$(CONFIG_CVI_MAILBOX) += rtos_cmdqu/
|
||||
|
||||
4
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Kconfig
Normal file
4
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Kconfig
Normal file
@ -0,0 +1,4 @@
|
||||
config CVI_MAILBOX
|
||||
tristate "cv180x/cv181x mailbox dirver"
|
||||
help
|
||||
"cv180x/cv181x mailbox driver"
|
||||
5
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Makefile
Normal file
5
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/Makefile
Normal file
@ -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)/
|
||||
77
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_mailbox.h
Normal file
77
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_mailbox.h
Normal file
@ -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__
|
||||
|
||||
108
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.c
Normal file
108
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.c
Normal file
@ -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 <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(®_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);
|
||||
}
|
||||
}
|
||||
43
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.h
Normal file
43
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/cvi_spinlock.h
Normal file
@ -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__
|
||||
530
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.c
Normal file
530
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.c
Normal file
@ -0,0 +1,530 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#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);
|
||||
51
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.h
Normal file
51
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.h
Normal file
@ -0,0 +1,51 @@
|
||||
#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__
|
||||
Reference in New Issue
Block a user