kernel_samsung_a34x-permissive/drivers/misc/mediatek/vow/ver02/vow_scp.c
2024-04-28 15:51:13 +02:00

213 lines
5.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* vow_scp.c -- VoW SCP
*
* Copyright (c) 2020 MediaTek Inc.
* Author: Michael HSiao <michael.hsiao@mediatek.com>
*/
/*****************************************************************************
* Header Files
*****************************************************************************/
#include <linux/delay.h>
#include "vow_scp.h"
#include "vow.h"
#include "vow_assert.h"
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
#include "scp.h"
#endif
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
static int vow_ipi_recv_handler(unsigned int id,
void *prdata,
void *data,
unsigned int len);
static int vow_ipi_ack_handler(unsigned int id,
void *prdata,
void *data,
unsigned int len);
#endif
unsigned int ipi_ack_return;
unsigned int ipi_ack_id;
unsigned int ipi_ack_data;
struct vow_ipi_receive_info vow_ipi_receive;
struct vow_ipi_ack_info vow_ipi_send_ack;
void (*ipi_rx_handle)(unsigned int a, void *b);
bool (*ipi_tx_ack_handle)(unsigned int a, unsigned int b);
/*****************************************************************************
* Function
****************************************************************************/
unsigned int vow_check_scp_status(void)
{
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
return is_scp_ready(SCP_A_ID);
#else
return 0;
#endif
}
void vow_ipi_register(void (*ipi_rx_call)(unsigned int, void *),
bool (*ipi_tx_ack_call)(unsigned int, unsigned int))
{
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
mtk_ipi_register(&scp_ipidev, IPI_IN_AUDIO_VOW_1,
(void *)vow_ipi_recv_handler, NULL,
&vow_ipi_receive);
mtk_ipi_register(&scp_ipidev, IPI_IN_AUDIO_VOW_ACK_1,
(void *)vow_ipi_ack_handler, NULL,
&vow_ipi_send_ack);
#endif
ipi_rx_handle = ipi_rx_call;
ipi_tx_ack_handle = ipi_tx_ack_call;
}
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
static int vow_ipi_recv_handler(unsigned int id,
void *prdata,
void *data,
unsigned int len)
{
struct vow_ipi_receive_info *ipi_info =
(struct vow_ipi_receive_info *)data;
ipi_rx_handle(ipi_info->msg_id, (void *)ipi_info->msg_data);
return 0;
}
static int vow_ipi_ack_handler(unsigned int id,
void *prdata,
void *data,
unsigned int len)
{
struct vow_ipi_ack_info *ipi_info =
(struct vow_ipi_ack_info *)data;
ipi_tx_ack_handle(ipi_info->msg_id, ipi_info->msg_data);
ipi_ack_return = ipi_info->msg_need_ack;
ipi_ack_id = ipi_info->msg_id;
ipi_ack_data = ipi_info->msg_data;
return 0;
}
#endif
bool vow_ipi_send(unsigned int msg_id,
unsigned int payload_len,
unsigned int *payload,
unsigned int need_ack)
{
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
bool ret = false;
int ipi_result = -1;
unsigned int retry_time = VOW_IPI_SEND_CNT_TIMEOUT;
unsigned int retry_cnt = 0;
unsigned int ack_time = VOW_IPI_WAIT_ACK_TIMEOUT;
unsigned int ack_cnt = 0;
unsigned int msg_need_ack = 0;
unsigned int resend_cnt = 0;
struct vow_ipi_send_info ipi_data;
if (!vow_check_scp_status()) {
VOWDRV_DEBUG("SCP is off, bypass send ipi id(%d)\n", msg_id);
return false;
}
if (vow_service_GetScpRecoverStatus() == true) {
VOWDRV_DEBUG("scp is recovering, then break\n");
return false;
}
/* clear send buffer */
memset(&ipi_data.payload[0], 0,
sizeof(unsigned int) * VOW_IPI_SEND_BUFFER_LENGTH);
resend_cnt = 0;
msg_need_ack = need_ack;
ipi_data.msg_id = msg_id;
ipi_data.msg_need_ack = msg_need_ack;
ipi_data.param1 = 0;
ipi_data.param2 = 0;
ipi_data.msg_length = payload_len;
if (payload > 0) {
/* have payload */
memcpy(&ipi_data.payload[0], payload,
sizeof(unsigned int) * payload_len);
}
RESEND_IPI:
if (resend_cnt == VOW_IPI_RESEND_TIMES) {
VOWDRV_DEBUG("%s(), resend over time, drop id:%d\n",
__func__, msg_id);
return false;
}
/* ipi ack reset */
ipi_ack_return = 0;
ipi_ack_id = 0xFF;
ipi_ack_data = 0;
for (retry_cnt = 0; retry_cnt <= retry_time; retry_cnt++) {
ipi_result = mtk_ipi_send(&scp_ipidev,
IPI_OUT_AUDIO_VOW_1,
0,
&ipi_data,
PIN_OUT_SIZE_AUDIO_VOW_1,
0);
if (ipi_result == IPI_ACTION_DONE) {
if (retry_cnt != 0) {
VOWDRV_DEBUG("%s(), ipi_id(%d) succeed after retry cnt =%d\n",
__func__,
msg_id,
retry_cnt);
}
break;
} else {
if (retry_cnt == retry_time) { // already retry max times
VOWDRV_DEBUG("%s() ERROR, ipi_id(%d) Fail after retry cnt =%d\n",
__func__,
msg_id,
ipi_result,
retry_cnt);
}
}
if (vow_service_GetScpRecoverStatus() == true) {
VOWDRV_DEBUG("scp is recovering, then break\n");
break;
}
msleep(VOW_WAITCHECK_INTERVAL_MS);
}
if (ipi_result == IPI_ACTION_DONE) {
if (need_ack == VOW_IPI_NEED_ACK) {
for (ack_cnt = 0; ack_cnt <= ack_time; ack_cnt++) {
if ((ipi_ack_return == VOW_IPI_ACK_BACK) &&
(ipi_ack_id == msg_id)) {
/* ack back */
break;
}
if (ack_cnt >= ack_time) {
/* no ack */
VOWDRV_DEBUG("%s(), no ack\n",
__func__);
resend_cnt++;
goto RESEND_IPI;
}
msleep(VOW_WAITCHECK_INTERVAL_MS);
}
}
VOWDRV_DEBUG("%s(), ipi_id(%d) pass\n", __func__, msg_id);
ret = true;
}
return ret;
#else
(void) msg_id;
(void) payload_len;
(void) payload;
(void) need_ack;
VOWDRV_DEBUG("vow:SCP no support\n\r");
return false;
#endif
}