1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-09-26 19:04:54 +00:00
Files
a155-U-u1/kernel-5.10/drivers/misc/mediatek/vcp/rv/vcp_wrapper_ipi.c
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

220 lines
5.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#include "vcp_ipi.h"
#include "vcp_ipi_table.h"
#include "vcp.h"
#define IPI_NO_USE 0xFF
struct vcp_ipi_desc mpool[VCP_NR_IPI - IPI_MPOOL - 1];
struct vcp_ipi_wrapper vcp_ipi_legacy_id[1];
struct vcp_ipi_legacy_pkt {
unsigned int id;
unsigned int len;
void *data;
};
/*
* API let apps unregister an ipi handler
* @param id: IPI ID
*/
enum vcp_ipi_status vcp_ipi_unregistration(enum vcp_ipi_id id)
{
int ret;
if (id >= VCP_NR_IPI || id == IPI_MPOOL)
return VCP_IPI_ERROR;
if (id > IPI_MPOOL) {
/* if ipi id belongs to mbox pool, remove handler only */
mpool[id - IPI_MPOOL - 1].handler = NULL;
return VCP_IPI_DONE;
}
if (vcp_ipi_legacy_id[id].in_id_0 != IPI_NO_USE) {
ret = mtk_ipi_unregister(&vcp_ipidev,
vcp_ipi_legacy_id[id].in_id_0);
if (ret != IPI_ACTION_DONE)
return VCP_IPI_ERROR;
}
if (vcp_ipi_legacy_id[id].in_id_1 != IPI_NO_USE) {
ret = mtk_ipi_unregister(&vcp_ipidev,
vcp_ipi_legacy_id[id].in_id_1);
if (ret != IPI_ACTION_DONE)
return VCP_IPI_ERROR;
}
return VCP_IPI_DONE;
}
EXPORT_SYMBOL_GPL(vcp_ipi_unregistration);
/*
* API for apps to send an IPI to vcp
* @param id: IPI ID
* @param buf: the pointer of data
* @param len: data length
* @param wait: If true, wait (atomically) until data have been gotten by Host
* @param len: data length
*/
enum vcp_ipi_status vcp_ipi_send(enum vcp_ipi_id id, void *buf,
unsigned int len, unsigned int wait, enum vcp_core_id vcp_id)
{
/* declare pkt with a mbox maximum size for re-structing data */
char pkt[256];
int ret = VCP_IPI_ERROR, tmp_id;
void *ptr;
if (id >= VCP_NR_IPI || id == IPI_MPOOL)
return VCP_IPI_ERROR;
if (id > IPI_MPOOL)
tmp_id = IPI_MPOOL;
else
tmp_id = id;
if (is_vcp_ready(vcp_id) == 0) {
pr_notice("[VCP] %s: %s not ready\n", __func__, core_ids[vcp_id]);
return VCP_IPI_NOT_READY;
}
if (len > (vcp_ipi_legacy_id[tmp_id].out_size - 2) * MBOX_SLOT_SIZE) {
pr_notice("%s: len overflow\n", __func__);
return VCP_IPI_ERROR;
}
/* variation length will only support chre and sensor for reducing slot
* and cpu time cost by memcpy.
*/
memcpy((void *)pkt, (void *)&id, sizeof(uint32_t));
memcpy((void *)(pkt + 4), (void *)&len, sizeof(uint32_t));
memcpy((void *)(pkt + 8), buf, len);
ptr = pkt;
if (vcp_ipi_legacy_id[tmp_id].out_id_0 != IPI_NO_USE
&& vcp_id == (enum vcp_core_id)VCP_CORE0_ID) {
ret =
mtk_ipi_send(&vcp_ipidev, vcp_ipi_legacy_id[tmp_id].out_id_0,
0, ptr, vcp_ipi_legacy_id[tmp_id].out_size,
wait * VCP_IPI_LEGACY_WAIT);
if (ret == IPI_ACTION_DONE)
return VCP_IPI_DONE;
if (ret == IPI_PIN_BUSY)
return VCP_IPI_BUSY;
}
if (vcp_ipi_legacy_id[tmp_id].out_id_1 != IPI_NO_USE
&& vcp_id == (enum vcp_core_id)VCP_CORE1_ID) {
ret =
mtk_ipi_send(&vcp_ipidev, vcp_ipi_legacy_id[tmp_id].out_id_1,
0, ptr, vcp_ipi_legacy_id[tmp_id].out_size,
wait * VCP_IPI_LEGACY_WAIT);
if (ret == IPI_ACTION_DONE)
return VCP_IPI_DONE;
if (ret == IPI_PIN_BUSY)
return VCP_IPI_BUSY;
}
return VCP_IPI_ERROR;
}
EXPORT_SYMBOL_GPL(vcp_ipi_send);
void mbox_setup_pin_table(unsigned int mbox)
{
int i, last_ofs = 0, last_idx = 0, last_slot = 0, last_sz = 0;
for (i = 0; i < vcp_mboxdev.send_count; i++) {
if (mbox == vcp_mbox_pin_send[i].mbox) {
vcp_mbox_pin_send[i].offset = last_ofs + last_slot;
vcp_mbox_pin_send[i].pin_index = last_idx + last_sz;
last_idx = vcp_mbox_pin_send[i].pin_index;
if (vcp_mbox_info[mbox].is64d == 1) {
last_sz = DIV_ROUND_UP(
vcp_mbox_pin_send[i].msg_size, 2);
last_ofs = last_sz * 2;
last_slot = last_idx * 2;
} else {
last_sz = vcp_mbox_pin_send[i].msg_size;
last_ofs = last_sz;
last_slot = last_idx;
}
} else if (mbox < vcp_mbox_pin_send[i].mbox)
break; /* no need to search the rest ipi */
}
for (i = 0; i < vcp_mboxdev.recv_count; i++) {
if (mbox == vcp_mbox_pin_recv[i].mbox) {
vcp_mbox_pin_recv[i].offset = last_ofs + last_slot;
vcp_mbox_pin_recv[i].pin_index = last_idx + last_sz;
last_idx = vcp_mbox_pin_recv[i].pin_index;
if (vcp_mbox_info[mbox].is64d == 1) {
last_sz = DIV_ROUND_UP(
vcp_mbox_pin_recv[i].msg_size, 2);
last_ofs = last_sz * 2;
last_slot = last_idx * 2;
} else {
last_sz = vcp_mbox_pin_recv[i].msg_size;
last_ofs = last_sz;
last_slot = last_idx;
}
} else if (mbox < vcp_mbox_pin_recv[i].mbox)
break; /* no need to search the rest ipi */
}
if (last_idx > 32 ||
(last_ofs + last_slot) > (vcp_mbox_info[mbox].is64d + 1) * 32) {
pr_notice("mbox%d ofs(%d)/slot(%d) exceed the maximum\n",
mbox, last_idx, last_ofs + last_slot);
WARN_ON(1);
}
}
/*
* API to dump wakeup reason for sensor ipi in detailed
*/
void mt_print_vcp_ipi_id(unsigned int mbox)
{
unsigned int irq_status, i;
struct vcp_ipi_info {
unsigned int id;
unsigned int len;
uint8_t info[4];
} buf;
irq_status = mtk_mbox_read_recv_irq(&vcp_mboxdev, mbox);
for (i = 0; i < vcp_mboxdev.recv_count; i++) {
if (vcp_mbox_pin_recv[i].mbox == mbox) {
if (irq_status & 1 << vcp_mbox_pin_recv[i].pin_index) {
if (vcp_mbox_pin_recv[i].chan_id
== IPI_IN_VCP_MPOOL_0) {
/* only read 1st, 2nd, 3rd slot for
* sensor id, len, and header info
*/
mtk_mbox_read(&vcp_mboxdev, mbox,
vcp_mbox_pin_recv[i].offset,
&buf, MBOX_SLOT_SIZE * 3);
pr_info("[VCP] ipi id/type/action/event/reserve = %u/%u/%u/%u/%u\n",
buf.id, buf.info[0],
buf.info[1], buf.info[2],
buf.info[3]);
} else {
pr_info("[VCP] mbox%u, ipi id %u\n",
mbox,
vcp_mbox_pin_recv[i].chan_id);
}
}
}
}
}