1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-07-14 08:44:45 +00:00
Files
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

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);