mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2025-07-14 08:44:45 +00:00
343 lines
8.3 KiB
C
343 lines
8.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/vmalloc.h> /* needed by vmalloc */
|
|
#include <linux/interrupt.h>
|
|
#include <linux/sched/clock.h>
|
|
#include "adsp_core.h"
|
|
#include "adsp_platform.h"
|
|
#include "adsp_mbox.h"
|
|
|
|
static int (*ipi_queue_recv_msg_hanlder)(
|
|
uint32_t core_id, /* enum adsp_core_id */
|
|
uint32_t ipi_id, /* enum adsp_ipi_id */
|
|
void *buf,
|
|
uint32_t len,
|
|
void (*ipi_handler)(int ipi_id, void *buf, unsigned int len));
|
|
|
|
struct adsp_ipi_desc {
|
|
void (*handler)(int id, void *data, unsigned int len);
|
|
const char *name;
|
|
} adsp_ipi_descs[ADSP_NR_IPI];
|
|
|
|
static int adsp_mbox_pin_cb(unsigned int id, void *prdata, void *buf,
|
|
unsigned int len);
|
|
|
|
static void adsp_ipi_cb(struct mtk_mbox_pin_recv *pin, void *priv);
|
|
|
|
struct mtk_mbox_info adsp_mbox_table[ADSP_IPI_CH_CNT] = {
|
|
{ .opt = MBOX_OPT_QUEUE_DIR, .is64d = true},
|
|
{ .opt = MBOX_OPT_DIRECT, .is64d = true},
|
|
{ .opt = MBOX_OPT_QUEUE_DIR, .is64d = true},
|
|
{ .opt = MBOX_OPT_DIRECT, .is64d = true},
|
|
};
|
|
|
|
struct mtk_mbox_pin_send adsp_mbox_pin_send[ADSP_TOTAL_SEND_PIN] = {
|
|
{
|
|
.mbox = ADSP_MBOX0_CH_ID,
|
|
.offset = ADSP_MBOX_SEND_SLOT_OFFSET,
|
|
.msg_size = ADSP_MBOX_SLOT_COUNT,
|
|
.pin_index = 0,
|
|
},
|
|
{
|
|
.mbox = ADSP_MBOX2_CH_ID,
|
|
.offset = ADSP_MBOX_SEND_SLOT_OFFSET,
|
|
.msg_size = ADSP_MBOX_SLOT_COUNT,
|
|
.pin_index = 0,
|
|
}
|
|
};
|
|
|
|
struct mtk_mbox_pin_recv adsp_mbox_pin_recv[ADSP_TOTAL_RECV_PIN] = {
|
|
{
|
|
.mbox = ADSP_MBOX1_CH_ID,
|
|
.offset = ADSP_MBOX_RECV_SLOT_OFFSET,
|
|
.cb_ctx_opt = MBOX_CB_IN_PROCESS,
|
|
.msg_size = ADSP_MBOX_SLOT_COUNT,
|
|
.pin_index = 0,
|
|
.mbox_pin_cb = adsp_mbox_pin_cb,
|
|
},
|
|
{
|
|
.mbox = ADSP_MBOX3_CH_ID,
|
|
.offset = ADSP_MBOX_RECV_SLOT_OFFSET,
|
|
.cb_ctx_opt = MBOX_CB_IN_PROCESS,
|
|
.msg_size = ADSP_MBOX_SLOT_COUNT,
|
|
.pin_index = 0,
|
|
.mbox_pin_cb = adsp_mbox_pin_cb,
|
|
}
|
|
};
|
|
|
|
struct mtk_mbox_device adsp_mboxdev = {
|
|
.name = "adsp_mailbox",
|
|
.pin_recv_table = adsp_mbox_pin_recv,
|
|
.pin_send_table = adsp_mbox_pin_send,
|
|
.info_table = adsp_mbox_table,
|
|
.count = ADSP_IPI_CH_CNT,
|
|
.recv_count = ADSP_TOTAL_RECV_PIN,
|
|
.send_count = ADSP_TOTAL_SEND_PIN,
|
|
.ipi_cb = adsp_ipi_cb,
|
|
/*.post_cb = adsp_post_cb, */
|
|
};
|
|
|
|
void hook_ipi_queue_recv_msg_hanlder(
|
|
int (*recv_msg_hanlder)(
|
|
uint32_t core_id, /* enum adsp_core_id */
|
|
uint32_t ipi_id, /* enum adsp_ipi_id */
|
|
void *buf,
|
|
uint32_t len,
|
|
void (*ipi_handler)(int ipi_id, void *buf, unsigned int len)))
|
|
{
|
|
ipi_queue_recv_msg_hanlder = recv_msg_hanlder;
|
|
}
|
|
EXPORT_SYMBOL(hook_ipi_queue_recv_msg_hanlder);
|
|
|
|
void unhook_ipi_queue_recv_msg_hanlder(void)
|
|
{
|
|
ipi_queue_recv_msg_hanlder = NULL;
|
|
}
|
|
EXPORT_SYMBOL(unhook_ipi_queue_recv_msg_hanlder);
|
|
|
|
void adsp_mbox_dump(void)
|
|
{
|
|
#if IS_ENABLED(CONFIG_MTK_IRQ_DBG)
|
|
mt_irq_dump_status(adsp_mbox_table[ADSP_MBOX1_CH_ID].irq_num);
|
|
mt_irq_dump_status(adsp_mbox_table[ADSP_MBOX3_CH_ID].irq_num);
|
|
#endif
|
|
mtk_mbox_dump_recv_pin(&adsp_mboxdev, &adsp_mbox_pin_recv[0]);
|
|
mtk_mbox_dump_recv_pin(&adsp_mboxdev, &adsp_mbox_pin_recv[1]);
|
|
}
|
|
|
|
int adsp_mbox_send(struct mtk_mbox_pin_send *pin_send, void *msg,
|
|
unsigned int wait)
|
|
{
|
|
int result = MBOX_DONE;
|
|
struct mtk_mbox_device *mbdev = &adsp_mboxdev;
|
|
ktime_t start_time;
|
|
s64 time_ipc_us;
|
|
|
|
if (mutex_trylock(&pin_send->mutex_send) == 0) {
|
|
pr_info("%s, mbox %d mutex_trylock busy",
|
|
__func__, pin_send->mbox);
|
|
return MBOX_PIN_BUSY;
|
|
}
|
|
|
|
if (mtk_mbox_check_send_irq(mbdev, pin_send->mbox,
|
|
pin_send->pin_index)) {
|
|
result = MBOX_PIN_BUSY;
|
|
goto EXIT;
|
|
}
|
|
|
|
result = mtk_mbox_write_hd(mbdev, pin_send->mbox,
|
|
pin_send->offset, msg);
|
|
|
|
if (result != MBOX_DONE) {
|
|
pr_err("%s() error mbox%d write, result %d\n",
|
|
__func__, pin_send->mbox, result);
|
|
goto EXIT;
|
|
}
|
|
|
|
dsb(SY);
|
|
|
|
result = mtk_mbox_trigger_irq(mbdev, pin_send->mbox,
|
|
0x1 << pin_send->pin_index);
|
|
|
|
if (result != MBOX_DONE) {
|
|
pr_err("%s() error mbox%d trigger, result %d\n",
|
|
__func__, pin_send->mbox, result);
|
|
goto EXIT;
|
|
}
|
|
|
|
if (wait) {
|
|
start_time = ktime_get();
|
|
while (mtk_mbox_check_send_irq(mbdev, pin_send->mbox,
|
|
pin_send->pin_index)) {
|
|
time_ipc_us = ktime_us_delta(ktime_get(), start_time);
|
|
if (time_ipc_us > 1000) {/* 1 ms */
|
|
pr_warn("%s, time_ipc_us > 1000", __func__);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
EXIT:
|
|
mutex_unlock(&pin_send->mutex_send);
|
|
return result;
|
|
}
|
|
|
|
static int adsp_mbox_pin_cb(unsigned int id, void *prdata, void *buf,
|
|
unsigned int len)
|
|
{
|
|
u32 core_id = *(u32 *)prdata;
|
|
int ret = -1;
|
|
|
|
if (core_id >= get_adsp_core_total()) {
|
|
pr_notice("%s() invalid core_id %u\n", __func__, core_id);
|
|
return ADSP_IPI_ERROR;
|
|
}
|
|
adsp_mt_clr_spm(core_id);
|
|
|
|
if (id >= ADSP_NR_IPI) {
|
|
pr_notice("%s() invalid ipi_id %d\n", __func__, id);
|
|
return ADSP_IPI_ERROR;
|
|
}
|
|
|
|
if (!adsp_ipi_descs[id].handler) {
|
|
pr_notice("%s() invalid ipi handler %d\n", __func__, id);
|
|
return ADSP_IPI_ERROR;
|
|
}
|
|
|
|
if (id == ADSP_IPI_ADSP_A_READY ||
|
|
id == ADSP_IPI_DVFS_SUSPEND ||
|
|
id == ADSP_IPI_LOGGER_INIT)
|
|
adsp_ipi_descs[id].handler(id, buf, len);
|
|
else {
|
|
if (ipi_queue_recv_msg_hanlder != NULL) {
|
|
ret = ipi_queue_recv_msg_hanlder(
|
|
core_id, id, buf, len, adsp_ipi_descs[id].handler);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
pr_info("ipi queue not ready!! core: %u, ipi_id: %u, buf: %p, len: %u, ipi_handler: %p",
|
|
core_id, id, buf, len, adsp_ipi_descs[id].handler);
|
|
adsp_ipi_descs[id].handler(id, buf, len);
|
|
}
|
|
}
|
|
|
|
return ADSP_IPI_DONE;
|
|
}
|
|
|
|
static void adsp_ipi_cb(struct mtk_mbox_pin_recv *pin, void *priv)
|
|
{
|
|
struct mtk_ipi_msg *ipimsg;
|
|
void *buf;
|
|
|
|
if (pin->cb_ctx_opt == MBOX_CB_IN_PROCESS) {
|
|
ipimsg = (struct mtk_ipi_msg *)pin->pin_buf;
|
|
buf = pin->pin_buf + sizeof(struct mtk_ipi_msg_hd);
|
|
|
|
pin->recv_record.pre_timestamp = cpu_clock(0);
|
|
pin->mbox_pin_cb(ipimsg->ipihd.id,
|
|
pin->prdata, buf,
|
|
(unsigned int)ipimsg->ipihd.len);
|
|
pin->recv_record.post_timestamp = cpu_clock(0);
|
|
pin->recv_record.cb_count++;
|
|
}
|
|
}
|
|
|
|
int adsp_mbox_probe(struct platform_device *pdev)
|
|
{
|
|
int ret, size;
|
|
int idx = 0;
|
|
struct mtk_mbox_device *mbdev = &adsp_mboxdev;
|
|
|
|
for (idx = 0; idx < ADSP_IPI_CH_CNT; idx++) {
|
|
ret = mtk_mbox_probe(pdev, mbdev, idx);
|
|
if (ret)
|
|
break;
|
|
|
|
ret = enable_irq_wake(mbdev->info_table[idx].irq_num);
|
|
if (ret < 0)
|
|
break;
|
|
}
|
|
|
|
for (idx = 0; idx < mbdev->send_count; idx++)
|
|
mutex_init(&mbdev->pin_send_table[idx].mutex_send);
|
|
|
|
for (idx = 0; idx < mbdev->recv_count; idx++) {
|
|
size = mbdev->pin_recv_table[idx].msg_size * MBOX_SLOT_SIZE;
|
|
mbdev->pin_recv_table[idx].pin_buf = vmalloc(size);
|
|
if (!mbdev->pin_recv_table[idx].pin_buf)
|
|
return -ENOMEM;
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(adsp_mbox_probe);
|
|
|
|
struct mtk_mbox_pin_send *get_adsp_mbox_pin_send(int index)
|
|
{
|
|
int i;
|
|
struct mtk_mbox_info *mbox;
|
|
struct mtk_mbox_pin_send *pin_send;
|
|
|
|
if (index >= ADSP_IPI_CH_CNT)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
mbox = adsp_mboxdev.info_table + index;
|
|
|
|
if (!mbox->enable) {
|
|
pr_info("the channel %d not enable", index);
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
|
|
for (i = 0; i < ADSP_TOTAL_SEND_PIN; i++) {
|
|
pin_send = &adsp_mbox_pin_send[i];
|
|
if (pin_send->mbox == index)
|
|
return pin_send;
|
|
}
|
|
|
|
pr_info("the channel %d is not send pin", index);
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
EXPORT_SYMBOL(get_adsp_mbox_pin_send);
|
|
|
|
struct mtk_mbox_pin_recv *get_adsp_mbox_pin_recv(int index)
|
|
{
|
|
int i;
|
|
struct mtk_mbox_info *mbox;
|
|
struct mtk_mbox_pin_recv *pin_recv;
|
|
|
|
if (index >= ADSP_IPI_CH_CNT)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
mbox = adsp_mboxdev.info_table + index;
|
|
|
|
if (!mbox->enable) {
|
|
pr_info("the channel %d not enable", index);
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
|
|
for (i = 0; i < ADSP_TOTAL_RECV_PIN; i++) {
|
|
pin_recv = &adsp_mbox_pin_recv[i];
|
|
if (pin_recv->mbox == index)
|
|
return pin_recv;
|
|
}
|
|
|
|
pr_info("the channel %d is not recv pin", index);
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
EXPORT_SYMBOL(get_adsp_mbox_pin_recv);
|
|
|
|
enum adsp_ipi_status adsp_ipi_registration(
|
|
enum adsp_ipi_id id,
|
|
void (*ipi_handler)(int id, void *data, unsigned int len),
|
|
const char *name)
|
|
{
|
|
if (id < ADSP_NR_IPI && id >= 0) {
|
|
adsp_ipi_descs[id].name = name;
|
|
|
|
if (ipi_handler == NULL)
|
|
return ADSP_IPI_ERROR;
|
|
|
|
adsp_ipi_descs[id].handler = ipi_handler;
|
|
return ADSP_IPI_DONE;
|
|
} else
|
|
return ADSP_IPI_ERROR;
|
|
}
|
|
EXPORT_SYMBOL_GPL(adsp_ipi_registration);
|
|
|
|
/*
|
|
* API let apps unregister an ipi handler
|
|
* @param id: IPI ID
|
|
*/
|
|
enum adsp_ipi_status adsp_ipi_unregistration(enum adsp_ipi_id id)
|
|
{
|
|
if (id < ADSP_NR_IPI && id >= 0) {
|
|
adsp_ipi_descs[id].name = "";
|
|
adsp_ipi_descs[id].handler = NULL;
|
|
return ADSP_IPI_DONE;
|
|
} else
|
|
return ADSP_IPI_ERROR;
|
|
}
|
|
EXPORT_SYMBOL_GPL(adsp_ipi_unregistration);
|
|
|