474 lines
13 KiB
C
474 lines
13 KiB
C
#include "vg_lite_os.h"
|
|
|
|
#include "rtthread.h"
|
|
#include "vg_lite_hw.h"
|
|
#include "vg_lite_hal.h"
|
|
|
|
/* If bit31 is activated this indicates a bus error */
|
|
#define IS_AXI_BUS_ERR(x) ((x)&(1U << 31))
|
|
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
#define ISR_WAIT_TIME 0x1FFFF
|
|
#define MAX_MUTEX_TIME 100
|
|
#define THREAD_WAIT_TIME 20
|
|
|
|
/* command queue task parameter */
|
|
#define QUEUE_THREAD_NAME "queue_thread"
|
|
#ifndef QUEUE_THREAD_PRIO
|
|
// #define QUEUE_THREAD_PRIO (configMAX_PRIORITIES - 1)
|
|
#define QUEUE_THREAD_PRIO 0
|
|
#endif /* QUEUE_THREAD_PRIO */
|
|
#define QUEUE_THREAD_SIZE 1024
|
|
#define QUEUE_LENGTH 8
|
|
#define MAX_QUEUE_WAIT_NUM 10
|
|
/* The array stores one or more tlss, which is pointed by user_data of current thread. Set it to 1 when only vglite is used, otherwise set it to 2 if elementary is applied. */
|
|
#define TLS_ARRAY_LENGTH 2
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
#ifndef TURE
|
|
#define TURE 1
|
|
#endif
|
|
|
|
typedef struct vg_lite_queue{
|
|
uint32_t cmd_physical;
|
|
uint32_t cmd_offset;
|
|
uint32_t cmd_size;
|
|
vg_lite_os_async_event_t *event;
|
|
}
|
|
vg_lite_queue_t;
|
|
|
|
rt_uint32_t tls_array[TLS_ARRAY_LENGTH] = {NULL};
|
|
typedef struct vg_lite_os{
|
|
rt_thread_t task_hanlde;
|
|
rt_mq_t queue_handle;
|
|
}
|
|
vg_lite_os_t;
|
|
|
|
static rt_mutex_t mutex;
|
|
static vg_lite_os_t os_obj = {0};
|
|
|
|
rt_sem_t semaphore[THREAD_LENGTH] = {NULL};
|
|
rt_sem_t command_semaphore = NULL;
|
|
uint32_t curContext;
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|
|
rt_sem_t int_queue;
|
|
volatile uint32_t int_flags;
|
|
|
|
void __attribute__((weak)) vg_lite_bus_error_handler()
|
|
{
|
|
/*
|
|
* Default implementation of the bus error handler does nothing. Application
|
|
* should override this handler if it requires to be notified when a bus
|
|
* error event occurs.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
/* command queue function */
|
|
void command_queue(void * parameters)
|
|
{
|
|
vg_lite_queue_t* peek_queue;
|
|
uint32_t even_got;
|
|
uint32_t len;
|
|
|
|
os_obj.queue_handle = rt_mq_create("queue_vglite", sizeof(vg_lite_queue_t * ), QUEUE_LENGTH, RT_IPC_FLAG_PRIO);
|
|
if(os_obj.queue_handle == RT_NULL)
|
|
{
|
|
/*command queue create fail, delete queue task */
|
|
rt_thread_delete(rt_thread_self());
|
|
}
|
|
|
|
command_semaphore = rt_sem_create("cs", 0, RT_IPC_FLAG_PRIO);
|
|
while(1)
|
|
{
|
|
even_got = 0;
|
|
if (rt_sem_take((rt_sem_t)command_semaphore, RT_WAITING_FOREVER) == RT_EOK) {
|
|
if(os_obj.queue_handle->entry)
|
|
{
|
|
len = rt_mq_recv(os_obj.queue_handle, (void*) &peek_queue, os_obj.queue_handle->msg_size, (rt_int32_t) ((rt_int64_t)THREAD_WAIT_TIME * RT_TICK_PER_SECOND / 1000));
|
|
if(len != 0)
|
|
{
|
|
#if defined(PRINT_COMMAND_BUFFER)
|
|
int i = 0;
|
|
for(i=0;i < (peek_queue->cmd_size + 3) / 4; i++)
|
|
{
|
|
if(i % 4 == 0)
|
|
printf("\r\n");
|
|
printf("0x%08x ",((uint32_t*)(peek_queue->cmd_physical + peek_queue->cmd_offset))[i]);
|
|
}
|
|
#endif
|
|
vg_lite_hal_poke(VG_LITE_HW_CMDBUF_ADDRESS, peek_queue->cmd_physical + peek_queue->cmd_offset);
|
|
vg_lite_hal_poke(VG_LITE_HW_CMDBUF_SIZE, (peek_queue->cmd_size +7)/8 );
|
|
|
|
if(vg_lite_hal_wait_interrupt(ISR_WAIT_TIME, (uint32_t)~0, &even_got))
|
|
peek_queue->event->signal = VG_LITE_HW_FINISHED;
|
|
else
|
|
#if defined(PRINT_DEBUG_REGISTER)
|
|
{
|
|
unsigned int debug;
|
|
unsigned int iter;
|
|
for(iter =0; iter < 16 ; iter ++)
|
|
{
|
|
vg_lite_hal_poke(0x470, iter);
|
|
debug = vg_lite_hal_peek(0x450);
|
|
printf("0x450[%d] = 0x%x\n", iter,debug);
|
|
}
|
|
for(iter =0; iter < 16 ; iter ++)
|
|
{
|
|
vg_lite_hal_poke(0x470, iter <<16);
|
|
debug = vg_lite_hal_peek(0x454);
|
|
printf("0x454[%d] = 0x%x\n", iter,debug);
|
|
}
|
|
for(iter =0; iter < 16 ; iter ++)
|
|
{
|
|
vg_lite_hal_poke(0x478, iter);
|
|
debug = vg_lite_hal_peek(0x468);
|
|
printf("0x468[%d] = 0x%x\n", iter,debug);
|
|
}
|
|
for(iter =0; iter < 16 ; iter ++)
|
|
{
|
|
vg_lite_hal_poke(0x478, iter);
|
|
debug = vg_lite_hal_peek(0x46C);
|
|
printf("0x46C[%d] = 0x%x\n", iter,debug);
|
|
}
|
|
#endif
|
|
/* wait timeout */
|
|
peek_queue->event->signal = VG_LITE_IDLE;
|
|
#if defined(PRINT_DEBUG_REGISTER)
|
|
}
|
|
#endif
|
|
if(semaphore[peek_queue->event->semaphore_id]){
|
|
rt_sem_release(semaphore[peek_queue->event->semaphore_id]);
|
|
}
|
|
|
|
vg_lite_os_free((void *) peek_queue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32_t vg_lite_os_init_tls_array(void)
|
|
{
|
|
rt_thread_t rt_TCB;
|
|
|
|
rt_TCB = rt_thread_self();
|
|
RT_ASSERT( rt_TCB != NULL );
|
|
|
|
rt_TCB->user_data = (rt_uint32_t) tls_array;
|
|
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
void vg_lite_os_deinit_tls_array(void)
|
|
{
|
|
rt_thread_t rt_TCB;
|
|
|
|
rt_TCB = rt_thread_self();
|
|
RT_ASSERT( rt_TCB != NULL );
|
|
rt_TCB->user_data = NULL;
|
|
}
|
|
|
|
int32_t vg_lite_os_set_tls(void* tls)
|
|
{
|
|
if(tls == NULL)
|
|
return VG_LITE_INVALID_ARGUMENT;
|
|
|
|
rt_thread_t rt_TCB;
|
|
|
|
rt_TCB = rt_thread_self();
|
|
RT_ASSERT( rt_TCB != NULL );
|
|
|
|
rt_uint32_t * tls_ptr = (rt_uint32_t *) rt_TCB->user_data;
|
|
*tls_ptr = (rt_uint32_t) tls;
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
void * vg_lite_os_get_tls( )
|
|
{
|
|
rt_thread_t rt_TCB;
|
|
|
|
void * pvReturn = NULL;
|
|
|
|
rt_TCB = rt_thread_self();
|
|
|
|
rt_uint32_t * tls_ptr = (rt_uint32_t *) rt_TCB->user_data;
|
|
pvReturn = (void *) (*tls_ptr);
|
|
|
|
return pvReturn;
|
|
}
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|
|
|
|
void * vg_lite_os_malloc(uint32_t size)
|
|
{
|
|
return rt_malloc((rt_size_t)size);
|
|
}
|
|
|
|
void vg_lite_os_free(void * memory)
|
|
{
|
|
rt_free(memory);
|
|
}
|
|
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
void vg_lite_os_reset_tls()
|
|
{
|
|
rt_thread_t rt_TCB;
|
|
|
|
rt_TCB = rt_thread_self();
|
|
RT_ASSERT( rt_TCB != NULL );
|
|
|
|
rt_uint32_t * tls_ptr = (rt_uint32_t *) rt_TCB->user_data;
|
|
*tls_ptr = NULL;
|
|
}
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|
|
|
|
void vg_lite_os_sleep(uint32_t msec)
|
|
{
|
|
rt_thread_mdelay(msec);
|
|
}
|
|
|
|
int32_t vg_lite_os_initialize(void)
|
|
{
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
static int task_number = 0;
|
|
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|
|
|
|
int_queue = rt_sem_create("iq", 0, RT_IPC_FLAG_PRIO);
|
|
int_flags = 0;
|
|
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
if(mutex == NULL)
|
|
{
|
|
mutex = rt_mutex_create("mut", RT_IPC_FLAG_PRIO);
|
|
if(mutex == NULL)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
}
|
|
|
|
if(task_number == 0)
|
|
{
|
|
if(rt_mutex_take(mutex, (rt_int32_t) ((rt_int64_t)THREAD_WAIT_TIME * RT_TICK_PER_SECOND / 1000)) == RT_EOK)
|
|
{
|
|
if(os_obj.task_hanlde == NULL)
|
|
{
|
|
os_obj.task_hanlde = rt_thread_create(QUEUE_THREAD_NAME, command_queue, NULL, QUEUE_THREAD_SIZE, QUEUE_THREAD_PRIO, 1);
|
|
if(os_obj.task_hanlde == RT_NULL)
|
|
{
|
|
/* command queue task create fail */
|
|
rt_mutex_release(mutex);
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
}
|
|
else
|
|
rt_thread_startup(os_obj.task_hanlde);
|
|
}
|
|
task_number++;
|
|
rt_mutex_release(mutex);
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
}
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
void vg_lite_os_deinitialize(void)
|
|
{
|
|
/* TODO: Remove clock. */
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
rt_mutex_delete(mutex);
|
|
mutex = 0;
|
|
#endif /* VG_DRIVER_SINGLE_THREAD */
|
|
rt_sem_delete(int_queue);
|
|
/* TODO: Remove power. */
|
|
}
|
|
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
int32_t vg_lite_os_lock()
|
|
{
|
|
if(mutex == NULL)
|
|
return VG_LITE_NOT_SUPPORT;
|
|
|
|
if(rt_mutex_take(mutex, (rt_int32_t) ((rt_int64_t)MAX_MUTEX_TIME * RT_TICK_PER_SECOND / 1000)) != RT_EOK)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
int32_t vg_lite_os_unlock()
|
|
{
|
|
if(rt_mutex_release(mutex) != RT_EOK)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
int32_t vg_lite_os_submit(uint32_t context, uint32_t physical, uint32_t offset, uint32_t size, vg_lite_os_async_event_t *event)
|
|
{
|
|
vg_lite_queue_t* queue_node;
|
|
|
|
if(os_obj.queue_handle == RT_NULL)
|
|
return VG_LITE_NOT_SUPPORT;
|
|
|
|
queue_node = (vg_lite_queue_t*) vg_lite_os_malloc(sizeof(vg_lite_queue_t));
|
|
if(queue_node == NULL)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
|
|
queue_node->cmd_physical = physical;
|
|
queue_node->cmd_offset = offset;
|
|
queue_node->cmd_size = size;
|
|
queue_node->event = event;
|
|
|
|
/* Current command buffer has been sent to the command queue. */
|
|
event->signal = VG_LITE_IN_QUEUE;
|
|
|
|
if(rt_mq_send_wait(os_obj.queue_handle, (void *) &queue_node, os_obj.queue_handle->msg_size, (rt_int32_t) ((rt_int64_t)ISR_WAIT_TIME * RT_TICK_PER_SECOND / 1000)) != RT_EOK)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
curContext = context;
|
|
|
|
if (vg_lite_os_wait_event(event) == VG_LITE_SUCCESS) {
|
|
if(rt_sem_release(command_semaphore) != RT_EOK)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
}
|
|
|
|
int32_t vg_lite_os_wait(uint32_t timeout, vg_lite_os_async_event_t *event)
|
|
{
|
|
if (semaphore[event->semaphore_id]) {
|
|
if (rt_sem_take(semaphore[event->semaphore_id], RT_WAITING_FOREVER) == RT_EOK) {
|
|
if(event->signal == VG_LITE_HW_FINISHED){
|
|
rt_sem_release(semaphore[event->semaphore_id]);
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
else{
|
|
rt_sem_release(semaphore[event->semaphore_id]);
|
|
return VG_LITE_TIMEOUT;
|
|
}
|
|
}
|
|
}
|
|
return VG_LITE_TIMEOUT;
|
|
}
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|
|
|
|
void vg_lite_os_IRQHandler(void)
|
|
{
|
|
uint32_t flags = vg_lite_hal_peek(VG_LITE_INTR_STATUS);
|
|
|
|
if (flags) {
|
|
/* Combine with current interrupt flags. */
|
|
int_flags |= flags;
|
|
|
|
/* Wake up any waiters. */
|
|
if(int_queue){
|
|
rt_sem_release(int_queue);
|
|
}
|
|
}
|
|
}
|
|
|
|
int32_t vg_lite_os_wait_interrupt(uint32_t timeout, uint32_t mask, uint32_t * value)
|
|
{
|
|
#if _BAREMETAL
|
|
uint32_t int_status=0;
|
|
int_status = vg_lite_hal_peek(VG_LITE_INTR_STATUS);
|
|
(void)value;
|
|
|
|
while (int_status==0){
|
|
int_status = vg_lite_hal_peek(VG_LITE_INTR_STATUS);
|
|
usleep(1);
|
|
}
|
|
|
|
if (IS_AXI_BUS_ERR(*value))
|
|
{
|
|
vg_lite_bus_error_handler();
|
|
}
|
|
return 1;
|
|
#else /*for rt500*/
|
|
if(int_queue) {
|
|
if (rt_sem_take(int_queue, (rt_int32_t) ((rt_int64_t)timeout * RT_TICK_PER_SECOND / 1000)) == RT_EOK) {
|
|
if (value != NULL) {
|
|
*value = int_flags & mask;
|
|
if (IS_AXI_BUS_ERR(*value))
|
|
{
|
|
vg_lite_bus_error_handler();
|
|
}
|
|
}
|
|
int_flags = 0;
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#if !defined(VG_DRIVER_SINGLE_THREAD)
|
|
int32_t vg_lite_os_init_event(vg_lite_os_async_event_t *event,
|
|
uint32_t semaphore_id,
|
|
int32_t state)
|
|
{
|
|
if (event->semaphore_id >= THREAD_LENGTH)
|
|
return VG_LITE_INVALID_ARGUMENT;
|
|
|
|
if (semaphore[semaphore_id])
|
|
return VG_LITE_ALREADY_EXISTS;
|
|
|
|
char name[RT_NAME_MAX] = {0};
|
|
rt_snprintf(name, RT_NAME_MAX, "s%d", semaphore_id);
|
|
semaphore[semaphore_id] = rt_sem_create(name, 0, RT_IPC_FLAG_PRIO);
|
|
if (!semaphore[semaphore_id])
|
|
return VG_LITE_OUT_OF_MEMORY;
|
|
|
|
rt_sem_release(semaphore[semaphore_id]);
|
|
|
|
event->semaphore_id = semaphore_id;
|
|
event->signal = state;
|
|
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
int32_t vg_lite_os_delete_event(vg_lite_os_async_event_t *event)
|
|
{
|
|
if (event->semaphore_id >= THREAD_LENGTH)
|
|
return VG_LITE_INVALID_ARGUMENT;
|
|
|
|
if (semaphore[event->semaphore_id]){
|
|
rt_sem_delete(semaphore[event->semaphore_id]);
|
|
semaphore[event->semaphore_id] = NULL;
|
|
}
|
|
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
int32_t vg_lite_os_wait_event(vg_lite_os_async_event_t *event)
|
|
{
|
|
if (event->semaphore_id >= THREAD_LENGTH)
|
|
return VG_LITE_INVALID_ARGUMENT;
|
|
|
|
if (rt_sem_take(semaphore[event->semaphore_id], RT_WAITING_FOREVER) != RT_EOK)
|
|
return VG_LITE_MULTI_THREAD_FAIL;
|
|
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
int32_t vg_lite_os_signal_event(vg_lite_os_async_event_t *event)
|
|
{
|
|
if (event->semaphore_id >= THREAD_LENGTH)
|
|
return VG_LITE_INVALID_ARGUMENT;
|
|
|
|
rt_sem_release(semaphore[event->semaphore_id]);
|
|
return VG_LITE_SUCCESS;
|
|
}
|
|
|
|
int8_t vg_lite_os_query_context_switch(uint32_t context)
|
|
{
|
|
if(!curContext || curContext == context)
|
|
return FALSE;
|
|
return TURE;
|
|
}
|
|
#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
|