kernel-brax3-ubuntu-touch/drivers/misc/mediatek/ccu/src/isp6s/ccu_ipc.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

243 lines
7.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/io.h>
#include "ccu_ipc.h"
#include "ccu_cmn.h"
#include "ccu_reg.h"
#include "ccu_platform_def.h"
static DEFINE_MUTEX(ccu_ipc_mutex);
#define CCU_IPC_NO_ACK 0x66669999
#define CCU_IPC_CMD_TIMEOUT_SPEC 3000 //3000us = 3ms
struct CCU_IPC_DATA {
MBOOL m_initialized;
uint32_t *m_ccuIntTriggerPtr;
struct ap2ccu_ipc_t *m_ccuIpcPtr;
void *m_ipcInDataPtr;
void *m_ipcOutDataPtr;
uint32_t m_ipcInDataAddrCcu;
uint32_t m_ipcOutDataAddrCcu;
uint64_t ccu_base;
};
static struct CCU_IPC_DATA ccu_ipc;
void ccu_ipc_init(unsigned int *ccuDmBase, unsigned int *ccuCtrlBase)
{
struct shared_buf_map *sb_map_ptr =
(struct shared_buf_map *)(ccuDmBase + OFFSET_CCU_SHARED_BUF_MAP_BASE);
ccu_ipc.m_ccuIntTriggerPtr =
(uint32_t *)ccuCtrlBase + OFFSET_CCU_INT_TRG;
ccu_ipc.m_ccuIpcPtr =
(struct ap2ccu_ipc_t *)(((uint8_t *)ccuDmBase) +
sb_map_ptr->ipc_base_offset);
ccu_ipc.m_ipcInDataPtr =
(void *)(((uint8_t *)ccuDmBase) + sb_map_ptr->ipc_in_data_base_offset);
ccu_ipc.m_ipcOutDataPtr =
(void *)(((uint8_t *)ccuDmBase) + sb_map_ptr->ipc_out_data_base_offset);
ccu_ipc.m_ipcInDataAddrCcu = sb_map_ptr->ipc_in_data_addr_ccu;
ccu_ipc.m_ipcOutDataAddrCcu = sb_map_ptr->ipc_out_data_addr_ccu;
ccu_ipc.m_initialized = MTRUE;
ccu_ipc.ccu_base = (unsigned long)ccuCtrlBase;
LOG_DBG("ccuDmBase: %p", ccuDmBase);
LOG_DBG("ccuCtrlBase: %p", ccuCtrlBase);
LOG_DBG("m_ccuIntTriggerPtr: %p", ccu_ipc.m_ccuIntTriggerPtr);
LOG_DBG("m_ccuIpcPtr: %p", ccu_ipc.m_ccuIpcPtr);
LOG_DBG("m_ipcInDataPtr: %p", ccu_ipc.m_ipcInDataPtr);
LOG_DBG("m_ipcOutDataPtr: %p", ccu_ipc.m_ipcOutDataPtr);
}
bool ccu_ipc_getIObuffer(void **ipcInDataPtr, void **ipcOutDataPtr,
uint32_t *ipcInDataAddrCcu, uint32_t *ipcOutDataAddrCcu)
{
LOG_DBG("+");
if (ccu_ipc.m_initialized == MFALSE) {
LOG_ERR("not initialized, invalid operation.");
return MFALSE;
}
*ipcInDataPtr = ccu_ipc.m_ipcInDataPtr;
*ipcOutDataPtr = ccu_ipc.m_ipcOutDataPtr;
*ipcInDataAddrCcu = ccu_ipc.m_ipcInDataAddrCcu;
*ipcOutDataAddrCcu = ccu_ipc.m_ipcOutDataAddrCcu;
LOG_DBG("*ipcInDataPtr: %p", *ipcInDataPtr);
LOG_DBG("*ipcOutDataPtr: %p", *ipcOutDataPtr);
LOG_DBG("*ipcInDataAddrCcu: %p", *ipcInDataAddrCcu);
LOG_DBG("*ipcOutDataAddrCcu: %p", *ipcOutDataAddrCcu);
LOG_DBG("-");
return MTRUE;
}
int ccu_ipc_send(struct ccu_msg *msg)
{
uint32_t loopCount = 0;
bool ackValue = 0;
bool timeout = false;
uint32_t write_cnt = 0;
uint32_t read_cnt = 0;
LOG_DBG("+, ftype(%d), msg_id(%d)", msg->feature_type, msg->msg_id);
if (ccu_ipc.m_initialized == MFALSE) {
LOG_ERR("not initialized, invalid operation.");
return -1;
}
LOG_DBG("+, read_cnt1,%x", &ccu_ipc.m_ccuIpcPtr);
//since ipc is synchronized, check no previous ipc
write_cnt = readl(&(ccu_ipc.m_ccuIpcPtr->write_cnt));
read_cnt = readl(&(ccu_ipc.m_ccuIpcPtr->read_cnt));
if (read_cnt != write_cnt) {
LOG_ERR("CCU IPC synchronization violation, rcnt:%d, wcnt:%d",
read_cnt, write_cnt);
return -1;
}
LOG_DBG("+, read_cnt2");
writel(CCU_IPC_NO_ACK, &ccu_ipc.m_ccuIpcPtr->ack);
write_cnt = readl(&ccu_ipc.m_ccuIpcPtr->write_cnt);
writel(write_cnt + 1, &ccu_ipc.m_ccuIpcPtr->write_cnt);
LOG_DBG("+set msg");
writel(msg->feature_type, &ccu_ipc.m_ccuIpcPtr->msg.feature_type);
writel(msg->msg_id, &ccu_ipc.m_ccuIpcPtr->msg.msg_id);
writel(msg->in_data_ptr, &ccu_ipc.m_ccuIpcPtr->msg.in_data_ptr);
writel(msg->out_data_ptr, &ccu_ipc.m_ccuIpcPtr->msg.out_data_ptr);
writel(msg->tg_info, &ccu_ipc.m_ccuIpcPtr->msg.tg_info);
writel(msg->sensor_idx, &ccu_ipc.m_ccuIpcPtr->msg.sensor_idx);
LOG_DBG("+, CCU IPC TRIG");
ccu_write_reg_bit(ccu_ipc.ccu_base, EXT2CCU_INT_CCU,
EXT2CCU_INT_CCU, 1);
while (readl(&ccu_ipc.m_ccuIpcPtr->ack) == CCU_IPC_NO_ACK) {
loopCount++;
udelay(100);
if (loopCount > CCU_IPC_CMD_TIMEOUT_SPEC) {
ackValue = readl(&ccu_ipc.m_ccuIpcPtr->ack);
if (ackValue == CCU_IPC_NO_ACK)
timeout = true;
else
LOG_DBG_MUST("CCU cmd timeout false alarm");
break;
}
}
if (timeout) {
LOG_ERR("CCU cmd timeout");
LOG_ERR("ftype(%d), msg_id(%d), ackValue(%d), loopCount(%d)",
msg->feature_type, msg->msg_id, ackValue, loopCount);
return -1;
}
LOG_DBG("-, ftype(%d), msg_id(%d), loopCount(%d)",
msg->feature_type, msg->msg_id, loopCount);
return 0;
}
bool _copyCmdInData(struct CcuIOBufInfo *inDataBufInfo,
void *inDataPtr, uint32_t inDataSize)
{
uint32_t i;
LOG_DBG("+:%s\n", __func__);
if (inDataBufInfo->bufType == CCU_SRAM_IO) {
// copy to sram
uint32_t *realIoBuf = (uint32_t *)inDataBufInfo->addr_ap;
//copy from _interIBuf to real IO buffer in unit of 4bytes,
//to avoid APB bus constraint of non-4byte-aligned data access
for (i = 0; i < (inDataSize/4); i++) {
// realIoBuf[i] = ((uint32_t *)inDataPtr)[i];
writel(((uint32_t *)inDataPtr)[i], &realIoBuf[i]);
}
}
LOG_DBG("-:%s\n", __func__);
return true;
}
bool _copyCmdOutData(struct CcuIOBufInfo *outDataBufInfo,
void *outDataPtr, uint32_t outDataSize)
{
uint32_t i;
LOG_DBG("+:%s\n", __func__);
if (outDataBufInfo->bufType == CCU_SRAM_IO) {
uint32_t *realIoBuf = (uint32_t *)outDataBufInfo->addr_ap;
//copy from _interIBuf to real IO buffer in unit of 4bytes,
//to avoid APB bus constraint of non-4byte-aligned data access
for (i = 0; i < (outDataSize/4); i++) {
// ((uint32_t *)outDataPtr)[i] = realIoBuf[i];
writel(realIoBuf[i], &((uint32_t *)outDataPtr)[i]);
}
}
LOG_DBG("-:%s\n", __func__);
return MTRUE;
}
bool _resolveCmdIOBuf(struct CcuIOBufInfo *inDataBufInfo,
struct CcuIOBufInfo *outDataBufInfo,
uint32_t inDataSize, uint32_t outDataSize)
{
if (!ccu_ipc_getIObuffer((void **)&inDataBufInfo->addr_ap,
(void **)&outDataBufInfo->addr_ap,
&inDataBufInfo->addr_ccu, &outDataBufInfo->addr_ccu)) {
return false;
}
LOG_DBG("inDataSize(%d), sramInBufCapacity(%d)",
inDataSize, CCU_IPC_IBUF_CAPACITY);
LOG_DBG("outDataSize(%d), sramOutBufCapacity(%d)",
outDataSize, CCU_IPC_OBUF_CAPACITY);
// Resolve Input buffer
if (inDataSize <= CCU_IPC_IBUF_CAPACITY) {
LOG_DBG("using Sram input buffer");
inDataBufInfo->bufType = CCU_SRAM_IO;
} else {
LOG_ERR("inDataSize excceed buffer capacity., sramBufCap(%d)",
CCU_IPC_IBUF_CAPACITY);
return false;
}
LOG_DBG("inDataBufInfo.addr_ap: %p, addr_ccu: %p",
inDataBufInfo->addr_ap, inDataBufInfo->addr_ccu);
// Resolve Output buffer
if (outDataSize <= CCU_IPC_OBUF_CAPACITY) {
LOG_DBG("using Sram output buffer");
outDataBufInfo->bufType = CCU_SRAM_IO;
} else {
LOG_ERR("outDataSize excceed buffer capacity.");
return false;
}
LOG_DBG("outDataBufInfo.addr_ap: %p, addr_ccu: %p",
outDataBufInfo->addr_ap, outDataBufInfo->addr_ccu);
return true;
}
bool ccuControl(
enum ccu_feature_type featureType,
enum IMGSENSOR_SENSOR_IDX sensorIdx,
uint32_t msgId, void *inDataPtr,
uint32_t inDataSize, void *outDataPtr, uint32_t outDataSize)
{
struct CcuIOBufInfo inDataBufInfo;
struct CcuIOBufInfo outDataBufInfo;
struct ccu_msg msg = {featureType, msgId, inDataBufInfo.addr_ccu,
outDataBufInfo.addr_ccu, CCU_CAM_TG_NONE, sensorIdx};
uint32_t ret;
mutex_lock(&ccu_ipc_mutex);
LOG_DBG("[%s]+: ft(%d), sIdx(%d), msgId(%d)\n",
__func__, featureType, sensorIdx, msgId);
//resolve IO buf
ret = _resolveCmdIOBuf(&inDataBufInfo,
&outDataBufInfo, inDataSize, outDataSize);
if (ret == MFALSE) {
LOG_ERR("resolveCmdIOBuf failed, cmd abort.");
mutex_unlock(&ccu_ipc_mutex);
return false;
}
//Check if need input data
if (inDataSize != 0) {
//copy input data to IPC buffer & command data buffer
_copyCmdInData(&inDataBufInfo, inDataPtr, inDataSize);
}
msg.in_data_ptr = inDataBufInfo.addr_ccu;
msg.out_data_ptr = outDataBufInfo.addr_ccu;
ret = ccu_ipc_send(&msg);
if (ret != 0) {
LOG_ERR("sendCcuCommnadIpc failed, msgId(%d)", msgId);
mutex_unlock(&ccu_ipc_mutex);
return false;
}
//check if need to copy output data
if (outDataSize != 0)
_copyCmdOutData(&outDataBufInfo, outDataPtr, outDataSize);
LOG_DBG("-:\n", __func__);
mutex_unlock(&ccu_ipc_mutex);
return true;
}