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

282 lines
5.9 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
/*
* this is only for , adopt to other must change the m and n.
*/
#include "../platform-msgbox.h"
#include "hal_msgbox.h"
#include "hal_interrupt.h"
#ifdef CONFIG_ARCH_SUN20IW2
#ifdef CONFIG_ARCH_XTENXA /* only for dsp */
#include "aw_io.h"
#endif
#endif
#include "hal_clk.h"
#include "hal_reset.h"
#include "hal_mutex.h"
#include "hal_log.h"
#ifdef CONFIG_STANDBY
#include <standby/standby.h>
#endif
static struct msg_endpoint *it_edp = NULL;
static hal_mutex_t it_edp_mutex;
#define MSGBOX_MAX_QUEUE 8
static inline int calculte_n(int local, int remote)
{
#if defined(CONFIG_ARCH_SUN8IW20)|| defined(CONFIG_SOC_SUN20IW1) \
|| defined(CONFIG_SOC_SUN20IW3)
/*
* | remote core (send) |
* | ARM:0 | DSP:1 | RV:2 |
* local | ARM:0 | / | 0 | 1 |
* core | DSP:1 | 0 | / | 1 |
* (recv) | RV :2 | 0 | 1 | / |
*/
if (remote < local)
return remote;
else
return remote - 1;
#elif defined(CONFIG_ARCH_SUN20IW2)
/*
* | remote core (send) |
* | ARM:0 | DSP:1 | RV:2 |
* local | ARM:0 | / | 1 | 0 |
* core | DSP:1 | 0 | / | 1 |
* (recv) | RV :2 | 0 | 1 | / |
*/
if (remote < 2)
return remote;
else
return local;
#endif
}
static void irq_msgbox_channel_handler(struct msg_endpoint *medp)
{
void *msg_sts, *msg_reg, *msg_irq_s;
u32 data;
msg_sts = (void *)MSGBOX_MSG_STA_REG(
medp->local_amp, calculte_n(medp->local_amp, medp->remote_amp),
medp->read_ch);
msg_reg = (void *)MSGBOX_MSG_REG(
medp->local_amp, calculte_n(medp->local_amp, medp->remote_amp),
medp->read_ch);
msg_irq_s = (void *)MSGBOX_RD_IRQ_STA_REG(
medp->local_amp, calculte_n(medp->local_amp, medp->remote_amp));
while (readl(msg_sts)) {
data = readl(msg_reg);
if (medp->rec)
medp->rec(data, medp->private);
}
writel(1 << (medp->read_ch * 2), msg_irq_s);
}
static hal_irqreturn_t irq_msgbox_handler(void *p)
{
struct msg_endpoint *t;
/* shouled not use mutex in interrupt contex */
for (t = it_edp; t != NULL; t = t->next) {
irq_msgbox_channel_handler(t);
}
return HAL_IRQ_OK;
}
#ifdef CONFIG_STANDBY
static void msgbox_enable_rec_int(struct msg_endpoint *medp);
static int msgbox_suspend(void *data)
{
hal_log_debug("msgbox suspend\r\n");
return 0;
}
static int msgbox_resume(void *data)
{
struct reset_control *rst;
hal_clk_t clk;
hal_log_debug("msgbox resume\r\n");
rst = hal_reset_control_get(HAL_SUNXI_RESET, RST_MSGBOX);
hal_reset_control_deassert(rst);
hal_reset_control_put(rst);
clk = hal_clock_get(HAL_SUNXI_CCU, CLK_MSGBOX);
hal_clock_enable(clk);
hal_clock_put(clk);
hal_mutex_lock(it_edp_mutex);
/* add to global list */
if (it_edp != NULL) {
struct msg_endpoint *t = it_edp;
while (t) {
msgbox_enable_rec_int(t);
t = t->next;
}
}
hal_mutex_unlock(it_edp_mutex);
return 0;
}
#endif
uint32_t hal_msgbox_init(void)
{
struct reset_control *rst;
hal_clk_t clk;
it_edp_mutex = hal_mutex_create();
// TODO: maybe not always NULL when failed in different OS?
if (it_edp_mutex == NULL) {
hal_log_err("%s(%d): Failed to create it_edp_mutex\n", __func__, __LINE__);
return -1;
}
rst = hal_reset_control_get(HAL_SUNXI_RESET, RST_MSGBOX);
hal_reset_control_assert(rst);
hal_reset_control_deassert(rst);
hal_reset_control_put(rst);
clk = hal_clock_get(HAL_SUNXI_CCU, CLK_MSGBOX);
#ifdef CONFIG_DRIVERS_SUNXI_CLK
hal_clock_disable(clk);
#endif
hal_clock_enable(clk);
hal_clock_put(clk);
hal_request_irq(IRQ_MSGBOX, irq_msgbox_handler, "msgbox", it_edp);
hal_enable_irq(IRQ_MSGBOX);
#ifdef CONFIG_STANDBY
register_pm_dev_notify(msgbox_suspend, msgbox_resume, NULL);
#endif
return 0;
}
static void msgbox_enable_rec_int(struct msg_endpoint *medp)
{
void *msg_irq_e;
msg_irq_e = (void *)MSGBOX_RD_IRQ_EN_REG(
medp->local_amp, calculte_n(medp->local_amp, medp->remote_amp));
writel(readl(msg_irq_e) | (1 << (medp->read_ch * 2)), msg_irq_e);
}
static void msgbox_disable_rec_int(struct msg_endpoint *medp)
{
void *msg_irq_e;
msg_irq_e = (void *)MSGBOX_RD_IRQ_EN_REG(
medp->local_amp, calculte_n(medp->local_amp, medp->remote_amp));
writel(readl(msg_irq_e) & ~(1 << (medp->read_ch * 2)), msg_irq_e);
}
uint32_t hal_msgbox_alloc_channel(struct msg_endpoint *edp, int32_t remote,
int32_t read, int32_t write)
{
edp->local_amp = THIS_MSGBOX_USE;
edp->remote_amp = remote;
edp->read_ch = read;
edp->write_ch = write;
hal_mutex_lock(it_edp_mutex);
/* add to global list */
if (it_edp == NULL) {
it_edp = edp;
} else {
struct msg_endpoint *t = it_edp;
while (t) {
if (t->next == NULL) {
t->next = edp;
break;
}
t = t->next;
}
}
edp->next = NULL;
hal_mutex_unlock(it_edp_mutex);
if (read >= 0)
msgbox_enable_rec_int(edp);
return 0;
}
void hal_msgbox_free_channel(struct msg_endpoint *edp)
{
struct msg_endpoint *t = it_edp;
if (t == edp) {
it_edp = t->next;
} else {
while (t) {
if (t->next == edp) {
t->next = t->next->next;
break;
}
t = t->next;
}
}
edp->next = NULL;
int rev_int = 0;
t = it_edp;
while (t) {
if (t->read_ch >= 0) {
rev_int = 1;
break;
}
}
if (rev_int == 0)
msgbox_disable_rec_int(edp);
return ;
}
static void msgbox_channel_send_data(struct msg_endpoint *medp, u32 data)
{
void *msg_sts, *msg_reg;
msg_sts = (void *)MSGBOX_MSG_STA_REG(
medp->remote_amp, calculte_n(medp->remote_amp, medp->local_amp),
medp->write_ch);
msg_reg = (void *)MSGBOX_MSG_REG(
medp->remote_amp, calculte_n(medp->remote_amp, medp->local_amp),
medp->write_ch);
while (readl(msg_sts) == MSGBOX_MAX_QUEUE);
writel(data, msg_reg);
}
u32 hal_msgbox_channel_send(struct msg_endpoint *medp, uint8_t *bf,
uint32_t len)
{
u32 data, i;
data = 0;
for (i = 0; i < len; i++) {
if (!(i % 4))
data = 0;
data |= *bf++ << ((i % 4) << 3);
if ((i % 4) == 3 || i == len - 1) {
msgbox_channel_send_data(medp, data);
}
}
return 0;
}