kernel_samsung_a34x-permissive/drivers/misc/mediatek/adsp/mt6853/adsp_mbox.c

265 lines
6.2 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#include <linux/soc/mediatek/mtk-mbox.h>
#include <linux/vmalloc.h> /* needed by vmalloc */
#include "adsp_core.h"
#include "adsp_platform.h"
#include "adsp_mbox.h"
#include "audio_ipi_platform.h"
#include "adsp_ipi_queue.h"
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);
struct mtk_mbox_info adsp_mbox_table[ADSP_IPI_CH_CNT] = {
{ .opt = MBOX_OPT_QUEUE_DIR, .is64d = true},
{ .opt = MBOX_OPT_QUEUE_DIR, .is64d = true},
{ .opt = MBOX_OPT_QUEUE_DIR, .is64d = true},
{ .opt = MBOX_OPT_QUEUE_DIR, .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,
.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,
.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,
/*.post_cb = adsp_post_cb, */
};
int adsp_mbox_send(struct mtk_mbox_pin_send *pin_send, void *msg,
unsigned int wait)
{
int result;
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)) {
mutex_unlock(&pin_send->mutex_send);
return MBOX_PIN_BUSY;
}
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);
return result;
}
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);
return result;
}
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;
}
}
}
mutex_unlock(&pin_send->mutex_send);
return MBOX_DONE;
}
static int adsp_mbox_pin_cb(unsigned int id, void *prdata, void *buf,
unsigned int len)
{
u32 opendsp_id = *(u32 *)prdata ?
AUDIO_OPENDSP_USE_HIFI3_B : AUDIO_OPENDSP_USE_HIFI3_A;
adsp_mt_clr_spm(*(u32 *)prdata);
if (id >= ADSP_NR_IPI) {
pr_err("%s() invalid ipi_id %d\n", __func__, id);
return ADSP_IPI_ERROR;
}
if (!adsp_ipi_descs[id].handler) {
pr_err("%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 (is_scp_ipi_queue_init(opendsp_id))
scp_dispatch_ipi_hanlder_to_queue(
opendsp_id, id, buf, len, adsp_ipi_descs[id].handler);
else {
pr_info("ipi queue not ready!! core: %u, ipi_id: %u, buf: %p, len: %u, ipi_handler: %p",
opendsp_id, id, buf, len, adsp_ipi_descs[id].handler);
WARN_ON(1);
}
return ADSP_IPI_DONE;
}
int adsp_mbox_probe(struct platform_device *pdev)
{
int ret;
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;
}
for (idx = 0; idx < mbdev->send_count; idx++)
mutex_init(&mbdev->pin_send_table[idx].mutex_send);
return ret;
}
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);
}
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);
}
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);