sdk-hwV1.3/lichee/rtos-hal/hal/source/msgbox/msgbox_sx/msgbox_sx.c

243 lines
5.5 KiB
C

#include "hal_msgbox.h"
#include "bitops.h"
#include "msgbox_sx.h"
#include "compiler_attributes.h"
#define MSGBOX_CTRL_REG_OFFSET 0x00
#define MSGBOX_VER_REG_OFFSET 0x10
#define MSGBOX_IRQ_EN_REG_OFFSET 0x40
#define MSGBOX_IRQ_STATUS_OFFSET 0x50
#define MSGBOX_FIFO_STATUS_OFFSET 0x100
#define MSGBOX_FIFO_STATUS_MASK BIT(0)
#define MSGBOX_MSG_STATUS_OFFSET 0x140
#define MSGBOX_MSG_STATUS_MASK 0x0f
#define MSGBOX_MSG_QUEUE_OFFSET 0x180
static int msg_queue_t_set(struct messagebox *mb, int queue)
{
int user = mb->this_user;
int offset_reg = (queue / 4 ) * 4 + MSGBOX_CTRL_REG_OFFSET;
int offset_bit_t = 4 + ((queue % 4) * 8 );
int offset_bit_r = ((queue % 4) * 8 );
unsigned long *reg = (unsigned long *)(mb->base + offset_reg);
unsigned long data;
if (queue >= MSGBOX_MAX_QUEUE || user >= MSGBOX_MAX_USER)
return -EINVAL;
data = *reg;
data &= ~(BIT(offset_bit_r) | BIT(offset_bit_t));
if (user)
*reg = data | BIT(offset_bit_t);
else
*reg = data | BIT(offset_bit_r);
return 0;
}
static int msg_queue_r_set(struct messagebox *mb, int queue)
{
int user = mb->this_user;
int offset_reg = (queue / 4 ) * 4 + MSGBOX_CTRL_REG_OFFSET;
int offset_bit_t = 4 + ((queue % 4) * 8 );
int offset_bit_r = ((queue % 4) * 8 );
unsigned long *reg = (unsigned long *)(mb->base + offset_reg);
unsigned long data;
if (queue >= MSGBOX_MAX_QUEUE || user >= MSGBOX_MAX_USER)
return -EINVAL;
data = *reg;
data &= ~(BIT(offset_bit_r) | BIT(offset_bit_t));
if (user)
*reg = data | BIT(offset_bit_r);
else
*reg = data | BIT(offset_bit_t);
return 0;
}
static int msg_queue_irq_t(struct messagebox *mb, int queue, int en)
{
int user = mb->this_user;
long *reg = (long *)(mb->base + MSGBOX_IRQ_EN_REG_OFFSET + user * 0x20);
int offset_bit = 1 + (queue << 1);
if (queue >= MSGBOX_MAX_QUEUE || user >= MSGBOX_MAX_USER)
return -EINVAL;
if (en)
*reg = SET_BIT(*reg, offset_bit);
else
*reg = CLR_BIT(*reg, offset_bit);
return 0;
}
static int msg_queue_irq_r(struct messagebox *mb, int queue, int en)
{
int user = mb->this_user;
long *reg = (long *)(mb->base + MSGBOX_IRQ_EN_REG_OFFSET + user * 0x20);
int offset_bit = (queue << 1);
if (queue >= MSGBOX_MAX_QUEUE || user >= MSGBOX_MAX_USER)
return -EINVAL;
if (en)
*reg = SET_BIT(*reg, offset_bit);
else
*reg = CLR_BIT(*reg, offset_bit);
return 0;
}
/*
* static int msg_queue_status_pending(struct messagebox *mb, int queue)
* {
* int user = mb->this_user;
*
* if (queue >= MSGBOX_MAX_QUEUE || user >= MSGBOX_MAX_USER)
* return -EINVAL;
*
* return 0;
* }
*/
static __maybe_unused int msg_queue_is_full(struct messagebox *mb, int queue)
{
long *reg = (long *)(mb->base + MSGBOX_FIFO_STATUS_OFFSET + queue * 4);
if (queue >= MSGBOX_MAX_QUEUE)
return -EINVAL;
if (*reg & MSGBOX_FIFO_STATUS_MASK)
return 1;
return 0;
}
static int msg_queue_msg_cnt_sx(struct messagebox *mb, int queue)
{
long *reg = (long *)(mb->base + MSGBOX_MSG_STATUS_OFFSET + 4 * queue);
if (queue >= MSGBOX_MAX_QUEUE)
return -EINVAL;
return *reg & MSGBOX_MSG_STATUS_MASK;
}
static int msg_queue_read_sx(struct messagebox *mb, int queue, unsigned long *read)
{
long *reg = (long *)(mb->base + MSGBOX_MSG_QUEUE_OFFSET + 4 * queue);
*read = *reg;
return 0;
}
static int msg_queue_write_sx(struct messagebox *mb, int queue,
unsigned long write)
{
long *reg = (long *)(mb->base + MSGBOX_MSG_QUEUE_OFFSET + 4 * queue);
*reg = write;
return 0;
}
static inline unsigned long msg_irq_enable_get(struct messagebox *mb)
{
int user = mb->this_user;
long *reg = (long *)(mb->base + MSGBOX_IRQ_EN_REG_OFFSET + user * 0x20);
return *reg;
}
static inline unsigned long msg_irq_status(struct messagebox *mb)
{
int user = mb->this_user;
long *reg = (long *)(mb->base + MSGBOX_IRQ_STATUS_OFFSET + 0x20 * user);
if (user >= MSGBOX_MAX_USER)
return -EINVAL;
return *reg;
}
static inline int msg_irq_clear(struct messagebox *mb, unsigned long clr)
{
int user = mb->this_user;
long *reg = (long *)(mb->base + MSGBOX_IRQ_STATUS_OFFSET + 0x20 * user);
if (user >= MSGBOX_MAX_USER)
return -EINVAL;
*reg = clr;
return 0;
}
hal_irqreturn_t msg_irq_handler_sx(void *d)
{
int channel;
struct messagebox *mb = d;
unsigned long status = msg_irq_status(mb);
unsigned long enable = msg_irq_enable_get(mb);
for (channel = 0; channel < MSGBOX_MAX_QUEUE; channel++) {
unsigned long tbit = channel << 1;
struct msg_channel *h = &mb->msg_handler[channel];
tbit = (1 << tbit) | (1 << (tbit + 1));
if ((tbit & status & enable) && h->cb_of_msg_queue) {
h->cb_of_msg_queue(channel, h);
}
}
msg_irq_clear(mb, status & enable);
return HAL_IRQ_OK;
}
static inline int
msg_channel_set_direction_sx(struct messagebox *mb, int channel,
enum msgbox_channel_direction dir)
{
if (dir == MSGBOX_CHANNEL_SEND)
return msg_queue_t_set(mb, channel);
else
return msg_queue_r_set(mb, channel);
}
static inline int msg_channel_irq_set_sx(struct messagebox *mb, int channel,
int enable)
{
struct msg_channel *ch;
if (channel >= MSGBOX_MAX_QUEUE)
return -EINVAL;
ch = &mb->msg_handler[channel];
if (ch->dir == MSGBOX_CHANNEL_SEND)
return msg_queue_irq_t(mb, channel, enable);
else
return msg_queue_irq_r(mb, channel, enable);
}
int msg_ops_init_sx(struct messagebox *mb)
{
mb->channel_set_direction = msg_channel_set_direction_sx;
mb->channel_irq_set = msg_channel_irq_set_sx;
mb->channel_fifo_len = msg_queue_msg_cnt_sx;
mb->channel_read = msg_queue_read_sx;
mb->channel_write = msg_queue_write_sx;
return 0;
}