1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-10-18 01:15:33 +00:00
Files
a155-U-u1/kernel-5.10/drivers/misc/mediatek/scp/rv/scp_wrapper_ipi.c
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

343 lines
8.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#include "scp_ipi.h"
#include "scp_ipi_table.h"
#include "scp.h"
#define IPI_NO_USE 0xFF
struct scp_ipi_desc mpool[SCP_NR_IPI - IPI_MPOOL - 1];
struct scp_ipi_wrapper scp_ipi_legacy_id[1];
struct scp_ipi_legacy_pkt {
unsigned int id;
unsigned int len;
void *data;
};
/*
* This is a handler for handling legacy ipi callback function
*/
static int scp_legacy_handler(unsigned int id, void *prdata, void *data,
unsigned int len)
{
void (*handler)(int id, void *data, unsigned int len);
struct scp_ipi_legacy_pkt pkt;
/* variation length will only support chre, chrex and sensor for
* reducing slot and cpu time cost by memcpy.
*/
pkt.id = *(unsigned int *)data;
pkt.len = *(unsigned int *)(data + 4);
pkt.data = (void *)(data + 8);
if (pkt.id > IPI_MPOOL)
handler = mpool[pkt.id - IPI_MPOOL - 1].handler;
else
handler = prdata;
if (handler)
handler(pkt.id, pkt.data, pkt.len);
return 0;
}
/*
* API let apps can register an ipi handler to receive IPI
* @param id: IPI ID
* @param handler: IPI handler
* @param name: IPI name
*/
enum scp_ipi_status scp_ipi_registration(enum ipi_id id,
void (*ipi_handler)(int id, void *data, unsigned int len),
const char *name)
{
int ret = SCP_IPI_ERROR;
if (id >= SCP_NR_IPI || id == IPI_MPOOL)
return SCP_IPI_ERROR;
if (ipi_handler == NULL)
return SCP_IPI_ERROR;
if (id > IPI_MPOOL) {
mpool[id - IPI_MPOOL - 1].handler = ipi_handler;
return SCP_IPI_DONE;
}
if (scp_ipi_legacy_id[id].in_id_0 != IPI_NO_USE) {
ret =
mtk_ipi_register(&scp_ipidev, scp_ipi_legacy_id[id].in_id_0,
(void *)scp_legacy_handler, ipi_handler,
scp_ipi_legacy_id[id].msg_0);
if (ret != IPI_ACTION_DONE)
return SCP_IPI_ERROR;
}
if (scp_ipi_legacy_id[id].in_id_1 != IPI_NO_USE) {
ret =
mtk_ipi_register(&scp_ipidev, scp_ipi_legacy_id[id].in_id_1,
(void *)scp_legacy_handler, ipi_handler,
scp_ipi_legacy_id[id].msg_1);
if (ret != IPI_ACTION_DONE)
return SCP_IPI_ERROR;
}
return SCP_IPI_DONE;
}
EXPORT_SYMBOL_GPL(scp_ipi_registration);
/*
* API let apps unregister an ipi handler
* @param id: IPI ID
*/
enum scp_ipi_status scp_ipi_unregistration(enum ipi_id id)
{
int ret;
if (id >= SCP_NR_IPI || id == IPI_MPOOL)
return SCP_IPI_ERROR;
if (id > IPI_MPOOL) {
/* if ipi id belongs to mbox pool, remove handler only */
mpool[id - IPI_MPOOL - 1].handler = NULL;
return SCP_IPI_DONE;
}
if (scp_ipi_legacy_id[id].in_id_0 != IPI_NO_USE) {
ret = mtk_ipi_unregister(&scp_ipidev,
scp_ipi_legacy_id[id].in_id_0);
if (ret != IPI_ACTION_DONE)
return SCP_IPI_ERROR;
}
if (scp_ipi_legacy_id[id].in_id_1 != IPI_NO_USE) {
ret = mtk_ipi_unregister(&scp_ipidev,
scp_ipi_legacy_id[id].in_id_1);
if (ret != IPI_ACTION_DONE)
return SCP_IPI_ERROR;
}
return SCP_IPI_DONE;
}
EXPORT_SYMBOL_GPL(scp_ipi_unregistration);
/*
* API for apps to send an IPI to scp
* @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 scp_ipi_status scp_ipi_send(enum ipi_id id, void *buf,
unsigned int len, unsigned int wait, enum scp_core_id scp_id)
{
/* declare pkt with a mbox maximum size for re-structing data */
char pkt[256];
int ret = SCP_IPI_ERROR, tmp_id;
void *ptr;
if (id >= SCP_NR_IPI || id == IPI_MPOOL)
return SCP_IPI_ERROR;
if (id > IPI_MPOOL)
tmp_id = IPI_MPOOL;
else
tmp_id = id;
if (is_scp_ready(scp_id) == 0) {
pr_notice("[SCP] %s: %s not ready\n", __func__, core_ids[scp_id]);
return SCP_IPI_NOT_READY;
}
if (len > (scp_ipi_legacy_id[tmp_id].out_size - 2) * MBOX_SLOT_SIZE) {
pr_notice("%s: len overflow\n", __func__);
return SCP_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 (scp_ipi_legacy_id[tmp_id].out_id_0 != IPI_NO_USE
&& scp_id == (enum scp_core_id)SCP_CORE0_ID) {
ret =
mtk_ipi_send(&scp_ipidev, scp_ipi_legacy_id[tmp_id].out_id_0,
0, ptr, scp_ipi_legacy_id[tmp_id].out_size,
wait * SCP_IPI_LEGACY_WAIT);
if (ret == IPI_ACTION_DONE)
return SCP_IPI_DONE;
if (ret == IPI_PIN_BUSY)
return SCP_IPI_BUSY;
}
if (scp_ipi_legacy_id[tmp_id].out_id_1 != IPI_NO_USE
&& scp_id == (enum scp_core_id)SCP_CORE1_ID) {
ret =
mtk_ipi_send(&scp_ipidev, scp_ipi_legacy_id[tmp_id].out_id_1,
0, ptr, scp_ipi_legacy_id[tmp_id].out_size,
wait * SCP_IPI_LEGACY_WAIT);
if (ret == IPI_ACTION_DONE)
return SCP_IPI_DONE;
if (ret == IPI_PIN_BUSY)
return SCP_IPI_BUSY;
}
return SCP_IPI_ERROR;
}
EXPORT_SYMBOL_GPL(scp_ipi_send);
enum scp_ipi_status scp_legacy_ipi_init(void)
{
int ret = 0;
ret = mtk_ipi_register(&scp_ipidev, IPI_IN_SCP_MPOOL_0,
(void *)scp_legacy_handler, 0,
scp_ipi_legacy_id[0].msg_0);
if (ret != IPI_ACTION_DONE)
return SCP_IPI_ERROR;
ret = mtk_ipi_register(&scp_ipidev, IPI_IN_SCP_MPOOL_1,
(void *)scp_legacy_handler, 0,
scp_ipi_legacy_id[0].msg_1);
if (ret != IPI_ACTION_DONE)
return SCP_IPI_ERROR;
return SCP_IPI_DONE;
}
bool mbox_check_send_table(unsigned int id)
{
unsigned int i = 0;
for (i = 0; i < scp_mboxdev.send_count; i++)
if (scp_mbox_pin_send[i].chan_id == id)
return true;
return false;
}
bool mbox_check_recv_table(unsigned int id)
{
unsigned int i = 0;
for (i = 0; i < scp_mboxdev.recv_count; i++)
if (scp_mbox_pin_recv[i].chan_id == id)
return true;
return false;
}
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 < scp_mboxdev.send_count; i++) {
if (mbox == scp_mbox_pin_send[i].mbox) {
scp_mbox_pin_send[i].offset = last_ofs + last_slot;
scp_mbox_pin_send[i].pin_index = last_idx + last_sz;
last_idx = scp_mbox_pin_send[i].pin_index;
if (scp_mbox_info[mbox].is64d == 1) {
last_sz = DIV_ROUND_UP(
scp_mbox_pin_send[i].msg_size, 2);
last_ofs = last_sz * 2;
last_slot = last_idx * 2;
} else {
last_sz = scp_mbox_pin_send[i].msg_size;
last_ofs = last_sz;
last_slot = last_idx;
}
} else if (mbox < scp_mbox_pin_send[i].mbox)
break; /* no need to search the rest ipi */
}
for (i = 0; i < scp_mboxdev.recv_count; i++) {
if (mbox == scp_mbox_pin_recv[i].mbox) {
scp_mbox_pin_recv[i].offset = last_ofs + last_slot;
scp_mbox_pin_recv[i].pin_index = last_idx + last_sz;
last_idx = scp_mbox_pin_recv[i].pin_index;
if (scp_mbox_info[mbox].is64d == 1) {
last_sz = DIV_ROUND_UP(
scp_mbox_pin_recv[i].msg_size, 2);
last_ofs = last_sz * 2;
last_slot = last_idx * 2;
} else {
last_sz = scp_mbox_pin_recv[i].msg_size;
last_ofs = last_sz;
last_slot = last_idx;
}
} else if (mbox < scp_mbox_pin_recv[i].mbox)
break; /* no need to search the rest ipi */
}
if (last_idx > 32 ||
(last_ofs + last_slot) > (scp_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_scp_ipi_id(unsigned int mbox)
{
unsigned int irq_status, i;
struct scp_ipi_info {
unsigned int id;
unsigned int len;
uint8_t info[4];
} buf;
irq_status = mtk_mbox_read_recv_irq(&scp_mboxdev, mbox);
for (i = 0; i < scp_mboxdev.recv_count; i++) {
if (scp_mbox_pin_recv[i].mbox == mbox) {
if (irq_status & 1 << scp_mbox_pin_recv[i].pin_index) {
if (scp_mbox_pin_recv[i].chan_id
== IPI_IN_SCP_MPOOL_0) {
/* only read 1st, 2nd, 3rd slot for
* sensor id, len, and header info
*/
mtk_mbox_read(&scp_mboxdev, mbox,
scp_mbox_pin_recv[i].offset,
&buf, MBOX_SLOT_SIZE * 3);
pr_info("[SCP] 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 if (scp_mbox_pin_recv[i].chan_id
== IPI_IN_SENSOR_NOTIFY){
mtk_mbox_read(&scp_mboxdev, mbox,
scp_mbox_pin_recv[i].offset,
&buf.info, sizeof(buf.info));
pr_info("[SCP] sensor notify seq %u type %u cmd %u len %u\n",
buf.info[0], buf.info[1], buf.info[2], buf.info[3]);
} else {
pr_info("[SCP] mbox%u, ipi id %u\n",
mbox,
scp_mbox_pin_recv[i].chan_id);
}
}
}
}
}