mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2025-09-05 12:50:27 +00:00
2033 lines
67 KiB
C
2033 lines
67 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2018 MediaTek Inc.
|
|
*
|
|
* Author: Daniel Huang <daniel.huang@mediatek.com>
|
|
*
|
|
*/
|
|
|
|
#include <linux/platform_device.h>
|
|
#include <linux/soc/mediatek/mtk-cmdq-ext.h>
|
|
#include <linux/pm_opp.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include "mtk_imgsys-engine.h"
|
|
#include "mtk_imgsys-cmdq.h"
|
|
#include "mtk_imgsys-cmdq-ext.h"
|
|
#include "mtk_imgsys-cmdq-plat.h"
|
|
#include "mtk_imgsys-trace.h"
|
|
#include "mtk-interconnect.h"
|
|
#if IMGSYS_SECURE_ENABLE
|
|
#include "cmdq-sec.h"
|
|
#include "cmdq-sec-iwc-common.h"
|
|
#endif
|
|
|
|
#define WPE_BWLOG_HW_COMB (IMGSYS_ENG_WPE_TNR | IMGSYS_ENG_DIP)
|
|
#define WPE_BWLOG_HW_COMB_ninA (IMGSYS_ENG_WPE_EIS | IMGSYS_ENG_PQDIP_A)
|
|
#define WPE_BWLOG_HW_COMB_ninB (IMGSYS_ENG_WPE_EIS | IMGSYS_ENG_PQDIP_B)
|
|
|
|
int imgsys_cmdq_ts_en;
|
|
module_param(imgsys_cmdq_ts_en, int, 0644);
|
|
|
|
int imgsys_wpe_bwlog_en;
|
|
module_param(imgsys_wpe_bwlog_en, int, 0644);
|
|
|
|
int imgsys_cmdq_ts_dbg_en;
|
|
module_param(imgsys_cmdq_ts_dbg_en, int, 0644);
|
|
|
|
int imgsys_dvfs_dbg_en;
|
|
module_param(imgsys_dvfs_dbg_en, int, 0644);
|
|
|
|
int imgsys_qos_update_freq;
|
|
module_param(imgsys_qos_update_freq, int, 0644);
|
|
|
|
int imgsys_qos_blank_int;
|
|
module_param(imgsys_qos_blank_int, int, 0644);
|
|
|
|
int imgsys_qos_factor;
|
|
module_param(imgsys_qos_factor, int, 0644);
|
|
|
|
int imgsys_quick_onoff_en;
|
|
module_param(imgsys_quick_onoff_en, int, 0644);
|
|
|
|
struct workqueue_struct *imgsys_cmdq_wq;
|
|
static u32 is_stream_off;
|
|
#if IMGSYS_SECURE_ENABLE
|
|
static u32 is_sec_task_create;
|
|
#endif
|
|
static struct imgsys_event_history event_hist[IMGSYS_CMDQ_SYNC_POOL_NUM];
|
|
|
|
void imgsys_cmdq_init(struct mtk_imgsys_dev *imgsys_dev, const int nr_imgsys_dev)
|
|
{
|
|
struct device *dev = imgsys_dev->dev;
|
|
u32 idx = 0;
|
|
|
|
pr_info("%s: +, dev(0x%x), num(%d)\n", __func__, dev, nr_imgsys_dev);
|
|
|
|
/* Only first user has to do init work queue */
|
|
if (nr_imgsys_dev == 1) {
|
|
imgsys_cmdq_wq = alloc_ordered_workqueue("%s",
|
|
__WQ_LEGACY | WQ_MEM_RECLAIM |
|
|
WQ_FREEZABLE,
|
|
"imgsys_cmdq_cb_wq");
|
|
if (!imgsys_cmdq_wq)
|
|
pr_info("%s: Create workquque IMGSYS-CMDQ fail!\n",
|
|
__func__);
|
|
}
|
|
|
|
switch (nr_imgsys_dev) {
|
|
case 1: /* DIP */
|
|
/* request thread by index (in dts) 0 */
|
|
for (idx = 0; idx < IMGSYS_ENG_MAX; idx++) {
|
|
imgsys_clt[idx] = cmdq_mbox_create(dev, idx);
|
|
pr_info("%s: cmdq_mbox_create(%d, 0x%x)\n", __func__, idx, imgsys_clt[idx]);
|
|
}
|
|
#if IMGSYS_SECURE_ENABLE
|
|
/* request for imgsys secure gce thread */
|
|
for (idx = IMGSYS_ENG_MAX; idx < (IMGSYS_ENG_MAX + IMGSYS_SEC_THD); idx++) {
|
|
imgsys_sec_clt[idx-IMGSYS_ENG_MAX] = cmdq_mbox_create(dev, idx);
|
|
pr_info(
|
|
"%s: cmdq_mbox_create sec_thd(%d, 0x%x)\n",
|
|
__func__, idx, imgsys_sec_clt[idx-IMGSYS_ENG_MAX]);
|
|
}
|
|
#endif
|
|
/* parse hardware event */
|
|
for (idx = 0; idx < IMGSYS_CMDQ_EVENT_MAX; idx++) {
|
|
of_property_read_u16(dev->of_node,
|
|
imgsys_event[idx].dts_name,
|
|
&imgsys_event[idx].event);
|
|
pr_info("%s: event idx %d is (%s, %d)\n", __func__,
|
|
idx, imgsys_event[idx].dts_name,
|
|
imgsys_event[idx].event);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
mutex_init(&imgsys_dev->dvfs_qos_lock);
|
|
mutex_init(&imgsys_dev->power_ctrl_lock);
|
|
|
|
}
|
|
|
|
void imgsys_cmdq_release(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
u32 idx = 0;
|
|
pr_info("%s: +\n", __func__);
|
|
|
|
/* Destroy cmdq client */
|
|
for (idx = 0; idx < IMGSYS_ENG_MAX; idx++) {
|
|
cmdq_mbox_destroy(imgsys_clt[idx]);
|
|
imgsys_clt[idx] = NULL;
|
|
}
|
|
#if IMGSYS_SECURE_ENABLE
|
|
for (idx = 0; idx < IMGSYS_SEC_THD; idx++) {
|
|
cmdq_mbox_destroy(imgsys_sec_clt[idx]);
|
|
imgsys_sec_clt[idx] = NULL;
|
|
}
|
|
#endif
|
|
|
|
/* Release work_quque */
|
|
flush_workqueue(imgsys_cmdq_wq);
|
|
destroy_workqueue(imgsys_cmdq_wq);
|
|
imgsys_cmdq_wq = NULL;
|
|
mutex_destroy(&imgsys_dev->dvfs_qos_lock);
|
|
mutex_destroy(&imgsys_dev->power_ctrl_lock);
|
|
}
|
|
|
|
void imgsys_cmdq_streamon(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
u32 idx = 0;
|
|
|
|
dev_info(imgsys_dev->dev,
|
|
"%s: cmdq stream on (%d) quick_pwr(%d)\n",
|
|
__func__, is_stream_off, imgsys_quick_onoff_enable());
|
|
is_stream_off = 0;
|
|
|
|
cmdq_mbox_enable(imgsys_clt[0]->chan);
|
|
|
|
for (idx = IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_START;
|
|
idx <= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_END; idx++)
|
|
cmdq_clear_event(imgsys_clt[0]->chan, imgsys_event[idx].event);
|
|
|
|
memset((void *)event_hist, 0x0,
|
|
sizeof(struct imgsys_event_history)*IMGSYS_CMDQ_SYNC_POOL_NUM);
|
|
#if DVFS_QOS_READY
|
|
mtk_imgsys_mmqos_reset(imgsys_dev);
|
|
#endif
|
|
}
|
|
|
|
void imgsys_cmdq_streamoff(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
u32 idx = 0;
|
|
|
|
dev_info(imgsys_dev->dev,
|
|
"%s: cmdq stream off (%d) idx(%d) quick_pwr(%d)\n",
|
|
__func__, is_stream_off, idx, imgsys_quick_onoff_enable());
|
|
is_stream_off = 1;
|
|
|
|
#if CMDQ_STOP_FUNC
|
|
for (idx = 0; idx < IMGSYS_ENG_MAX; idx++) {
|
|
cmdq_mbox_stop(imgsys_clt[idx]);
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: calling cmdq_mbox_stop(%d, 0x%x)\n",
|
|
__func__, idx, imgsys_clt[idx]);
|
|
}
|
|
#endif
|
|
#if IMGSYS_SECURE_ENABLE
|
|
if (is_sec_task_create) {
|
|
cmdq_sec_mbox_stop(imgsys_sec_clt[0]);
|
|
/* cmdq_pkt_destroy(pkt_sec); */
|
|
/* pkt_sec = NULL; */
|
|
is_sec_task_create = 0;
|
|
}
|
|
#endif
|
|
|
|
cmdq_mbox_disable(imgsys_clt[0]->chan);
|
|
|
|
#if DVFS_QOS_READY
|
|
mtk_imgsys_mmqos_reset(imgsys_dev);
|
|
#endif
|
|
}
|
|
|
|
static void imgsys_cmdq_cmd_dump(struct swfrm_info_t *frm_info, u32 frm_idx)
|
|
{
|
|
struct GCERecoder *cmd_buf = NULL;
|
|
struct Command *cmd = NULL;
|
|
u32 cmd_num = 0;
|
|
u32 cmd_idx = 0;
|
|
u32 cmd_ofst = 0;
|
|
|
|
cmd_buf = (struct GCERecoder *)frm_info->user_info[frm_idx].g_swbuf;
|
|
cmd_num = cmd_buf->curr_length / sizeof(struct Command);
|
|
cmd_ofst = sizeof(struct GCERecoder);
|
|
|
|
pr_info(
|
|
"%s: +, req fd/no(%d/%d) frame no(%d) frm(%d/%d), cmd_oft(0x%x/0x%x), cmd_len(%d), num(%d), sz_per_cmd(%d), frm_blk(%d), hw_comb(0x%x)\n",
|
|
__func__, frm_info->request_fd, frm_info->request_no, frm_info->frame_no,
|
|
frm_idx, frm_info->total_frmnum, cmd_buf->cmd_offset, cmd_ofst,
|
|
cmd_buf->curr_length, cmd_num, sizeof(struct Command), cmd_buf->frame_block,
|
|
frm_info->user_info[frm_idx].hw_comb);
|
|
|
|
if (cmd_ofst != cmd_buf->cmd_offset) {
|
|
pr_info("%s: [ERROR]cmd offset is not match (0x%x/0x%x)!\n",
|
|
__func__, cmd_buf->cmd_offset, cmd_ofst);
|
|
return;
|
|
}
|
|
|
|
cmd = (struct Command *)((unsigned long)(frm_info->user_info[frm_idx].g_swbuf) +
|
|
(unsigned long)(cmd_buf->cmd_offset));
|
|
|
|
for (cmd_idx = 0; cmd_idx < cmd_num; cmd_idx++) {
|
|
switch (cmd[cmd_idx].opcode) {
|
|
case IMGSYS_CMD_READ:
|
|
pr_info(
|
|
"%s: READ with source(0x%08lx) target(0x%08lx) mask(0x%08x)\n", __func__,
|
|
cmd[cmd_idx].u.source, cmd[cmd_idx].u.target, cmd[cmd_idx].u.mask);
|
|
break;
|
|
case IMGSYS_CMD_WRITE:
|
|
pr_debug(
|
|
"%s: WRITE with addr(0x%08lx) value(0x%08x) mask(0x%08x)\n", __func__,
|
|
cmd[cmd_idx].u.address, cmd[cmd_idx].u.value, cmd[cmd_idx].u.mask);
|
|
break;
|
|
case IMGSYS_CMD_POLL:
|
|
pr_info(
|
|
"%s: POLL with addr(0x%08lx) value(0x%08x) mask(0x%08x)\n", __func__,
|
|
cmd[cmd_idx].u.address, cmd[cmd_idx].u.value, cmd[cmd_idx].u.mask);
|
|
break;
|
|
case IMGSYS_CMD_WAIT:
|
|
pr_info(
|
|
"%s: WAIT event(%d/%d) action(%d)\n", __func__,
|
|
cmd[cmd_idx].u.event, imgsys_event[cmd[cmd_idx].u.event].event,
|
|
cmd[cmd_idx].u.action);
|
|
break;
|
|
case IMGSYS_CMD_UPDATE:
|
|
pr_info(
|
|
"%s: UPDATE event(%d/%d) action(%d)\n", __func__,
|
|
cmd[cmd_idx].u.event, imgsys_event[cmd[cmd_idx].u.event].event,
|
|
cmd[cmd_idx].u.action);
|
|
break;
|
|
case IMGSYS_CMD_ACQUIRE:
|
|
pr_info(
|
|
"%s: ACQUIRE event(%d/%d) action(%d)\n", __func__,
|
|
cmd[cmd_idx].u.event, imgsys_event[cmd[cmd_idx].u.event].event,
|
|
cmd[cmd_idx].u.action);
|
|
break;
|
|
case IMGSYS_CMD_TIME:
|
|
pr_info("%s: Get cmdq TIME stamp\n", __func__);
|
|
break;
|
|
case IMGSYS_CMD_STOP:
|
|
pr_info("%s: End Of Cmd!\n", __func__);
|
|
break;
|
|
default:
|
|
pr_info("%s: [ERROR]Not Support Cmd(%d)!\n", __func__, cmd[cmd_idx].opcode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void imgsys_cmdq_cb_work(struct work_struct *work)
|
|
{
|
|
struct mtk_imgsys_cb_param *cb_param = NULL;
|
|
struct mtk_imgsys_dev *imgsys_dev = NULL;
|
|
u32 hw_comb = 0;
|
|
u32 cb_frm_cnt = 0;
|
|
u64 tsDvfsQosStart = 0, tsDvfsQosEnd = 0;
|
|
int req_fd = 0, req_no = 0, frm_no = 0;
|
|
u32 tsSwEvent = 0, tsHwEvent = 0, tsHw = 0, tsTaskPending = 0;
|
|
u32 tsHwStr = 0, tsHwEnd = 0;
|
|
bool isLastTaskInReq = 0;
|
|
char *wpestr = NULL;
|
|
u32 wpebw_en = imgsys_wpe_bwlog_enable();
|
|
char logBuf_temp[MTK_IMGSYS_LOG_LENGTH];
|
|
u32 idx = 0;
|
|
u32 real_frm_idx = 0;
|
|
|
|
pr_debug("%s: +\n", __func__);
|
|
|
|
cb_param = container_of(work, struct mtk_imgsys_cb_param, cmdq_cb_work);
|
|
cb_param->cmdqTs.tsCmdqCbWorkStart = ktime_get_boottime_ns()/1000;
|
|
imgsys_dev = cb_param->imgsys_dev;
|
|
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: cb(%p) gid(%d) in block(%d/%d) for frm(%d/%d) lst(%d/%d/%d) task(%d/%d/%d) ofst(%x/%x/%x/%x/%x)\n",
|
|
__func__, cb_param, cb_param->group_id,
|
|
cb_param->blk_idx, cb_param->blk_num,
|
|
cb_param->frm_idx, cb_param->frm_num,
|
|
cb_param->isBlkLast, cb_param->isFrmLast, cb_param->isTaskLast,
|
|
cb_param->task_id, cb_param->task_num, cb_param->task_cnt,
|
|
cb_param->pkt_ofst[0], cb_param->pkt_ofst[1], cb_param->pkt_ofst[2],
|
|
cb_param->pkt_ofst[3], cb_param->pkt_ofst[4]);
|
|
|
|
mtk_imgsys_power_ctrl(imgsys_dev, false);
|
|
|
|
if (imgsys_cmdq_ts_enable()) {
|
|
for (idx = 0; idx < cb_param->task_cnt; idx++) {
|
|
/* Calculating task timestamp */
|
|
tsSwEvent = cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+1]
|
|
- cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+0];
|
|
tsHwEvent = cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+2]
|
|
- cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+1];
|
|
tsHwStr = cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+2];
|
|
tsHwEnd = cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+3];
|
|
tsHw = cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+3]
|
|
- cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+2];
|
|
tsTaskPending =
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+cb_param->taskTs.num-1]
|
|
- cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+0];
|
|
CMDQ_TICK_TO_US(tsSwEvent);
|
|
CMDQ_TICK_TO_US(tsHwEvent);
|
|
CMDQ_TICK_TO_US(tsHw);
|
|
CMDQ_TICK_TO_US(tsHwStr);
|
|
CMDQ_TICK_TO_US(tsHwEnd);
|
|
CMDQ_TICK_TO_US(tsTaskPending);
|
|
tsTaskPending =
|
|
(cb_param->cmdqTs.tsCmdqCbStart-cb_param->cmdqTs.tsFlushStart)
|
|
- tsTaskPending;
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: TSus cb(%p) err(%d) frm(%d/%d/%d) hw_comb(0x%x) ts_num(%d) sw_event(%d) hw_event(%d) hw_real(%d) (%d/%d/%d/%d)\n",
|
|
__func__, cb_param, cb_param->err, cb_param->frm_idx,
|
|
cb_param->frm_num, cb_frm_cnt, hw_comb,
|
|
cb_param->taskTs.num, tsSwEvent, tsHwEvent, tsHw,
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+0],
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+1],
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+2],
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+4*idx+3]
|
|
);
|
|
if (imgsys_cmdq_ts_dbg_enable()) {
|
|
real_frm_idx = cb_param->frm_idx - (cb_param->task_cnt - 1) + idx;
|
|
hw_comb = cb_param->frm_info->user_info[real_frm_idx].hw_comb;
|
|
memset((char *)logBuf_temp, 0x0, MTK_IMGSYS_LOG_LENGTH);
|
|
logBuf_temp[strlen(logBuf_temp)] = '\0';
|
|
snprintf(logBuf_temp, MTK_IMGSYS_LOG_LENGTH,
|
|
"/[%d/%d/%d/%d]hw_comb(0x%x)ts(%d-%d-%d-%d)hw(%d-%d)",
|
|
real_frm_idx, cb_param->frm_num,
|
|
cb_param->blk_idx, cb_param->blk_num,
|
|
hw_comb, tsTaskPending, tsSwEvent, tsHwEvent,
|
|
tsHw, tsHwStr, tsHwEnd);
|
|
strncat(cb_param->frm_info->hw_ts_log, logBuf_temp,
|
|
strlen(logBuf_temp));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cb_param->err != 0)
|
|
pr_info(
|
|
"%s: [ERROR] cb(%p) req fd/no(%d/%d) frame no(%d) error(%d) gid(%d) clt(0x%x) hw_comb(0x%x) for frm(%d/%d) blk(%d/%d) lst(%d/%d) earlycb(%d) ofst(0x%x) task(%d/%d/%d) ofst(%x/%x/%x/%x/%x)",
|
|
__func__, cb_param, cb_param->req_fd,
|
|
cb_param->req_no, cb_param->frm_no,
|
|
cb_param->err, cb_param->group_id,
|
|
cb_param->clt, cb_param->hw_comb,
|
|
cb_param->frm_idx, cb_param->frm_num,
|
|
cb_param->blk_idx, cb_param->blk_num,
|
|
cb_param->isBlkLast, cb_param->isFrmLast,
|
|
cb_param->is_earlycb, cb_param->pkt->err_data.offset,
|
|
cb_param->task_id, cb_param->task_num, cb_param->task_cnt,
|
|
cb_param->pkt_ofst[0], cb_param->pkt_ofst[1], cb_param->pkt_ofst[2],
|
|
cb_param->pkt_ofst[3], cb_param->pkt_ofst[4]);
|
|
if (is_stream_off == 1)
|
|
pr_info("%s: [ERROR] cb(%p) pipe already streamoff(%d)!\n",
|
|
__func__, cb_param, is_stream_off);
|
|
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: req fd/no(%d/%d) frame no(%d) cb(%p)frm_info(%p) isBlkLast(%d) isFrmLast(%d) isECB(%d) isGPLast(%d) isGPECB(%d) for frm(%d/%d)\n",
|
|
__func__, cb_param->frm_info->request_fd,
|
|
cb_param->frm_info->request_no, cb_param->frm_info->frame_no,
|
|
cb_param, cb_param->frm_info, cb_param->isBlkLast,
|
|
cb_param->isFrmLast, cb_param->is_earlycb,
|
|
cb_param->frm_info->user_info[cb_param->frm_idx].is_lastingroup,
|
|
cb_param->frm_info->user_info[cb_param->frm_idx].is_earlycb,
|
|
cb_param->frm_idx, cb_param->frm_num);
|
|
|
|
hw_comb = cb_param->frm_info->user_info[cb_param->frm_idx].hw_comb;
|
|
req_fd = cb_param->frm_info->request_fd;
|
|
req_no = cb_param->frm_info->request_no;
|
|
frm_no = cb_param->frm_info->frame_no;
|
|
|
|
cb_param->frm_info->cb_frmcnt++;
|
|
cb_frm_cnt = cb_param->frm_info->cb_frmcnt;
|
|
|
|
if (wpebw_en > 0) {
|
|
switch (wpebw_en) {
|
|
case 1:
|
|
if ((hw_comb & WPE_BWLOG_HW_COMB) == WPE_BWLOG_HW_COMB)
|
|
wpestr = "tnr";
|
|
break;
|
|
case 2:
|
|
if (((hw_comb & WPE_BWLOG_HW_COMB_ninA) == WPE_BWLOG_HW_COMB_ninA)
|
|
|| ((hw_comb & WPE_BWLOG_HW_COMB_ninB) == WPE_BWLOG_HW_COMB_ninB))
|
|
wpestr = "eis";
|
|
break;
|
|
case 3:
|
|
if (hw_comb == IMGSYS_ENG_WPE_LITE)
|
|
wpestr = "lite";
|
|
break;
|
|
}
|
|
if (wpestr) {
|
|
dev_info(imgsys_dev->dev,
|
|
"%s: wpe_bwlog req fd/no(%d/%d)frameNo(%d)cb(%p)err(%d)frm(%d/%d/%d)hw_comb(0x%x)read_num(%d)-%s(%d/%d/%d/%d)\n",
|
|
__func__, cb_param->frm_info->request_fd,
|
|
cb_param->frm_info->request_no,
|
|
cb_param->frm_info->frame_no,
|
|
cb_param, cb_param->err, cb_param->frm_idx,
|
|
cb_param->frm_num, cb_frm_cnt, hw_comb,
|
|
cb_param->taskTs.num,
|
|
wpestr,
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+0],
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+1],
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+2],
|
|
cb_param->taskTs.dma_va[cb_param->taskTs.ofst+3]
|
|
);
|
|
}
|
|
}
|
|
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: req fd/no(%d/%d) frame no(%d) cb(%p)frm_info(%p) isBlkLast(%d) cb_param->frm_num(%d) cb_frm_cnt(%d)\n",
|
|
__func__, cb_param->frm_info->request_fd,
|
|
cb_param->frm_info->request_no, cb_param->frm_info->frame_no,
|
|
cb_param, cb_param->frm_info, cb_param->isBlkLast, cb_param->frm_num,
|
|
cb_frm_cnt);
|
|
|
|
if (cb_param->isBlkLast && cb_param->user_cmdq_cb &&
|
|
((cb_param->frm_info->total_taskcnt == cb_frm_cnt) || cb_param->is_earlycb)) {
|
|
struct cmdq_cb_data user_cb_data;
|
|
|
|
/* PMQOS API */
|
|
tsDvfsQosStart = ktime_get_boottime_ns()/1000;
|
|
IMGSYS_SYSTRACE_BEGIN(
|
|
"%s_%s|Imgsys MWFrame:#%d MWReq:#%d ReqFd:%d Own:%llx\n",
|
|
__func__, "dvfs_qos", cb_param->frm_info->frame_no,
|
|
cb_param->frm_info->request_no, cb_param->frm_info->request_fd,
|
|
cb_param->frm_info->frm_owner);
|
|
/* Calling PMQOS API if last frame */
|
|
if (cb_param->frm_info->total_taskcnt == cb_frm_cnt) {
|
|
mutex_lock(&(imgsys_dev->dvfs_qos_lock));
|
|
#if DVFS_QOS_READY
|
|
mtk_imgsys_mmdvfs_mmqos_cal(imgsys_dev, cb_param->frm_info, 0);
|
|
mtk_imgsys_mmdvfs_set(imgsys_dev, cb_param->frm_info, 0);
|
|
#if IMGSYS_QOS_SET_REAL
|
|
mtk_imgsys_mmqos_ts_cal(imgsys_dev, cb_param, hw_comb);
|
|
mtk_imgsys_mmqos_set(imgsys_dev, cb_param->frm_info, 0);
|
|
#elif IMGSYS_QOS_SET_BY_SCEN
|
|
mtk_imgsys_mmqos_set_by_scen(imgsys_dev, cb_param->frm_info, 0);
|
|
#endif
|
|
#endif
|
|
mutex_unlock(&(imgsys_dev->dvfs_qos_lock));
|
|
if (imgsys_cmdq_ts_enable() || imgsys_wpe_bwlog_enable()) {
|
|
cmdq_mbox_buf_free(cb_param->clt,
|
|
cb_param->taskTs.dma_va, cb_param->taskTs.dma_pa);
|
|
if (imgsys_cmdq_ts_dbg_enable()) {
|
|
dev_info(imgsys_dev->dev, "%s: %s",
|
|
__func__, cb_param->frm_info->hw_ts_log);
|
|
vfree(cb_param->frm_info->hw_ts_log);
|
|
}
|
|
}
|
|
isLastTaskInReq = 1;
|
|
} else
|
|
isLastTaskInReq = 0;
|
|
IMGSYS_SYSTRACE_END();
|
|
tsDvfsQosEnd = ktime_get_boottime_ns()/1000;
|
|
|
|
user_cb_data.err = cb_param->err;
|
|
user_cb_data.data = (void *)cb_param->frm_info;
|
|
cb_param->cmdqTs.tsUserCbStart = ktime_get_boottime_ns()/1000;
|
|
IMGSYS_SYSTRACE_BEGIN(
|
|
"%s_%s|Imgsys MWFrame:#%d MWReq:#%d ReqFd:%d Own:%llx\n",
|
|
__func__, "user_cb", cb_param->frm_info->frame_no,
|
|
cb_param->frm_info->request_no, cb_param->frm_info->request_fd,
|
|
cb_param->frm_info->frm_owner);
|
|
cb_param->user_cmdq_cb(user_cb_data, cb_param->frm_idx, isLastTaskInReq);
|
|
IMGSYS_SYSTRACE_END();
|
|
cb_param->cmdqTs.tsUserCbEnd = ktime_get_boottime_ns()/1000;
|
|
}
|
|
|
|
IMGSYS_SYSTRACE_BEGIN(
|
|
"%s_%s|Imgsys MWFrame:#%d MWReq:#%d ReqFd:%d fidx:%d hw_comb:0x%x Own:%llx cb:%p thd:%d frm(%d/%d/%d) DvfsSt(%lld) SetCmd(%lld) HW(%lld/%d-%d-%d-%d) Cmdqcb(%lld) WK(%lld) UserCb(%lld) DvfsEnd(%lld)\n",
|
|
__func__, "wait_pkt", cb_param->frm_info->frame_no,
|
|
cb_param->frm_info->request_no, cb_param->frm_info->request_fd,
|
|
cb_param->frm_info->user_info[cb_param->frm_idx].subfrm_idx, hw_comb,
|
|
cb_param->frm_info->frm_owner, cb_param, cb_param->thd_idx,
|
|
cb_param->frm_idx, cb_param->frm_num, cb_frm_cnt,
|
|
(cb_param->cmdqTs.tsDvfsQosEnd-cb_param->cmdqTs.tsDvfsQosStart),
|
|
(cb_param->cmdqTs.tsFlushStart-cb_param->cmdqTs.tsReqStart),
|
|
(cb_param->cmdqTs.tsCmdqCbStart-cb_param->cmdqTs.tsFlushStart),
|
|
tsTaskPending, tsSwEvent, tsHwEvent, tsHw,
|
|
(cb_param->cmdqTs.tsCmdqCbEnd-cb_param->cmdqTs.tsCmdqCbStart),
|
|
(cb_param->cmdqTs.tsCmdqCbWorkStart-cb_param->cmdqTs.tsCmdqCbEnd),
|
|
(cb_param->cmdqTs.tsUserCbEnd-cb_param->cmdqTs.tsUserCbStart),
|
|
(tsDvfsQosEnd-tsDvfsQosStart));
|
|
|
|
cmdq_pkt_wait_complete(cb_param->pkt);
|
|
cmdq_pkt_destroy(cb_param->pkt);
|
|
cb_param->cmdqTs.tsReqEnd = ktime_get_boottime_ns()/1000;
|
|
IMGSYS_SYSTRACE_END();
|
|
|
|
if (imgsys_cmdq_ts_dbg_enable())
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: TSus req fd/no(%d/%d) frame no(%d) thd(%d) cb(%p) err(%d) frm(%d/%d/%d) hw_comb(0x%x) DvfsSt(%lld) Req(%lld) SetCmd(%lld) HW(%lld/%d-%d-%d-%d) Cmdqcb(%lld) WK(%lld) CmdqCbWk(%lld) UserCb(%lld) DvfsEnd(%lld)\n",
|
|
__func__, req_fd, req_no, frm_no, cb_param->thd_idx,
|
|
cb_param, cb_param->err, cb_param->frm_idx,
|
|
cb_param->frm_num, cb_frm_cnt, hw_comb,
|
|
(cb_param->cmdqTs.tsDvfsQosEnd-cb_param->cmdqTs.tsDvfsQosStart),
|
|
(cb_param->cmdqTs.tsReqEnd-cb_param->cmdqTs.tsReqStart),
|
|
(cb_param->cmdqTs.tsFlushStart-cb_param->cmdqTs.tsReqStart),
|
|
(cb_param->cmdqTs.tsCmdqCbStart-cb_param->cmdqTs.tsFlushStart),
|
|
tsTaskPending, tsSwEvent, tsHwEvent, tsHw,
|
|
(cb_param->cmdqTs.tsCmdqCbEnd-cb_param->cmdqTs.tsCmdqCbStart),
|
|
(cb_param->cmdqTs.tsCmdqCbWorkStart-cb_param->cmdqTs.tsCmdqCbEnd),
|
|
(cb_param->cmdqTs.tsReqEnd-cb_param->cmdqTs.tsCmdqCbWorkStart),
|
|
(cb_param->cmdqTs.tsUserCbEnd-cb_param->cmdqTs.tsUserCbStart),
|
|
(tsDvfsQosEnd-tsDvfsQosStart)
|
|
);
|
|
vfree(cb_param);
|
|
}
|
|
|
|
void imgsys_cmdq_task_cb(struct cmdq_cb_data data)
|
|
{
|
|
struct mtk_imgsys_cb_param *cb_param;
|
|
struct mtk_imgsys_pipe *pipe;
|
|
size_t err_ofst;
|
|
u32 idx = 0, err_idx = 0, real_frm_idx = 0;
|
|
u16 event = 0, event_sft = 0;
|
|
u64 event_diff = 0;
|
|
bool isHWhang = 0;
|
|
|
|
pr_debug("%s: +\n", __func__);
|
|
|
|
if (!data.data) {
|
|
pr_info("%s: [ERROR]no callback data\n", __func__);
|
|
return;
|
|
}
|
|
|
|
cb_param = (struct mtk_imgsys_cb_param *)data.data;
|
|
cb_param->err = data.err;
|
|
cb_param->cmdqTs.tsCmdqCbStart = ktime_get_boottime_ns()/1000;
|
|
|
|
pr_debug(
|
|
"%s: Receive cb(%p) with err(%d) for frm(%d/%d)\n",
|
|
__func__, cb_param, data.err, cb_param->frm_idx, cb_param->frm_num);
|
|
|
|
if (cb_param->err != 0) {
|
|
err_ofst = cb_param->pkt->err_data.offset;
|
|
err_idx = 0;
|
|
for (idx = 0; idx < cb_param->task_cnt; idx++)
|
|
if (err_ofst > cb_param->pkt_ofst[idx])
|
|
err_idx++;
|
|
else
|
|
break;
|
|
if (err_idx >= cb_param->task_cnt) {
|
|
pr_info(
|
|
"%s: [ERROR] can't find task in task list! cb(%p) error(%d) for frm(%d/%d) blk(%d/%d) ofst(0x%x) erridx(%d/%d) task(%d/%d/%d) ofst(%x/%x/%x/%x/%x)",
|
|
__func__, cb_param, cb_param->err, cb_param->group_id,
|
|
cb_param->frm_idx, cb_param->frm_num,
|
|
cb_param->blk_idx, cb_param->blk_num,
|
|
cb_param->pkt->err_data.offset,
|
|
err_idx, real_frm_idx,
|
|
cb_param->task_id, cb_param->task_num, cb_param->task_cnt,
|
|
cb_param->pkt_ofst[0], cb_param->pkt_ofst[1], cb_param->pkt_ofst[2],
|
|
cb_param->pkt_ofst[3], cb_param->pkt_ofst[4]);
|
|
err_idx = cb_param->task_cnt - 1;
|
|
}
|
|
real_frm_idx = cb_param->frm_idx - (cb_param->task_cnt - 1) + err_idx;
|
|
pr_info(
|
|
"%s: [ERROR] cb(%p) req fd/no(%d/%d) frame no(%d) error(%d) gid(%d) clt(0x%x) hw_comb(0x%x) for frm(%d/%d) blk(%d/%d) lst(%d/%d/%d) earlycb(%d) ofst(0x%x) erridx(%d/%d) task(%d/%d/%d) ofst(%x/%x/%x/%x/%x)",
|
|
__func__, cb_param, cb_param->req_fd,
|
|
cb_param->req_no, cb_param->frm_no,
|
|
cb_param->err, cb_param->group_id,
|
|
cb_param->clt, cb_param->hw_comb,
|
|
cb_param->frm_idx, cb_param->frm_num,
|
|
cb_param->blk_idx, cb_param->blk_num,
|
|
cb_param->isBlkLast, cb_param->isFrmLast, cb_param->isTaskLast,
|
|
cb_param->is_earlycb, cb_param->pkt->err_data.offset,
|
|
err_idx, real_frm_idx,
|
|
cb_param->task_id, cb_param->task_num, cb_param->task_cnt,
|
|
cb_param->pkt_ofst[0], cb_param->pkt_ofst[1], cb_param->pkt_ofst[2],
|
|
cb_param->pkt_ofst[3], cb_param->pkt_ofst[4]);
|
|
if (is_stream_off == 1)
|
|
pr_info("%s: [ERROR] cb(%p) pipe had been turned off(%d)!\n",
|
|
__func__, cb_param, is_stream_off);
|
|
pipe = (struct mtk_imgsys_pipe *)cb_param->frm_info->pipe;
|
|
if (!pipe->streaming) {
|
|
/* is_stream_off = 1; */
|
|
pr_info("%s: [ERROR] cb(%p) pipe already streamoff(%d)\n",
|
|
__func__, cb_param, is_stream_off);
|
|
}
|
|
|
|
event = cb_param->pkt->err_data.event;
|
|
if ((event >= IMGSYS_CMDQ_HW_EVENT_BEGIN) &&
|
|
(event <= IMGSYS_CMDQ_HW_EVENT_END)) {
|
|
isHWhang = 1;
|
|
pr_info(
|
|
"%s: [ERROR] HW event timeout! wfe(%d) event(%d) isHW(%d)",
|
|
__func__,
|
|
cb_param->pkt->err_data.wfe_timeout,
|
|
cb_param->pkt->err_data.event, isHWhang);
|
|
} else if ((event >= IMGSYS_CMDQ_SW_EVENT_BEGIN) &&
|
|
(event <= IMGSYS_CMDQ_SW_EVENT_END)) {
|
|
event_sft = event - IMGSYS_CMDQ_SW_EVENT_BEGIN;
|
|
event_diff = event_hist[event_sft].set.ts >
|
|
event_hist[event_sft].wait.ts ?
|
|
(event_hist[event_sft].set.ts -
|
|
event_hist[event_sft].wait.ts) :
|
|
(event_hist[event_sft].wait.ts -
|
|
event_hist[event_sft].set.ts);
|
|
pr_info(
|
|
"%s: [ERROR] SW event timeout! wfe(%d) event(%d) isHW(%d); event st(%d)_ts(%lld)_set(%d/%d/%d/%lld)_wait(%d/%d/%d/%lld)",
|
|
__func__,
|
|
cb_param->pkt->err_data.wfe_timeout,
|
|
cb_param->pkt->err_data.event, isHWhang,
|
|
event_hist[event_sft].st, event_diff,
|
|
event_hist[event_sft].set.req_fd,
|
|
event_hist[event_sft].set.req_no,
|
|
event_hist[event_sft].set.frm_no,
|
|
event_hist[event_sft].set.ts,
|
|
event_hist[event_sft].wait.req_fd,
|
|
event_hist[event_sft].wait.req_no,
|
|
event_hist[event_sft].wait.frm_no,
|
|
event_hist[event_sft].wait.ts);
|
|
} else if ((event >= IMGSYS_CMDQ_SW_EVENT2_BEGIN) &&
|
|
(event <= IMGSYS_CMDQ_SW_EVENT2_END)) {
|
|
event_sft = event - IMGSYS_CMDQ_SW_EVENT2_BEGIN +
|
|
(IMGSYS_CMDQ_SW_EVENT_END - IMGSYS_CMDQ_SW_EVENT_BEGIN);
|
|
event_diff = event_hist[event_sft].set.ts >
|
|
event_hist[event_sft].wait.ts ?
|
|
(event_hist[event_sft].set.ts -
|
|
event_hist[event_sft].wait.ts) :
|
|
(event_hist[event_sft].wait.ts -
|
|
event_hist[event_sft].set.ts);
|
|
pr_info(
|
|
"%s: [ERROR] SW event2 timeout! wfe(%d) event(%d) isHW(%d); event st(%d)_ts(%lld)_set(%d/%d/%d/%lld)_wait(%d/%d/%d/%lld)",
|
|
__func__,
|
|
cb_param->pkt->err_data.wfe_timeout,
|
|
cb_param->pkt->err_data.event, isHWhang,
|
|
event_hist[event_sft].st, event_diff,
|
|
event_hist[event_sft].set.req_fd,
|
|
event_hist[event_sft].set.req_no,
|
|
event_hist[event_sft].set.frm_no,
|
|
event_hist[event_sft].set.ts,
|
|
event_hist[event_sft].wait.req_fd,
|
|
event_hist[event_sft].wait.req_no,
|
|
event_hist[event_sft].wait.frm_no,
|
|
event_hist[event_sft].wait.ts);
|
|
} else if ((event >= IMGSYS_CMDQ_GPR_EVENT_BEGIN) &&
|
|
(event <= IMGSYS_CMDQ_GPR_EVENT_END)) {
|
|
isHWhang = 1;
|
|
pr_info(
|
|
"%s: [ERROR] GPR event timeout! wfe(%d) event(%d) isHW(%d)",
|
|
__func__,
|
|
cb_param->pkt->err_data.wfe_timeout,
|
|
cb_param->pkt->err_data.event, isHWhang);
|
|
} else
|
|
pr_info(
|
|
"%s: [ERROR] Other event timeout! wfe(%d) event(%d) isHW(%d)",
|
|
__func__,
|
|
cb_param->pkt->err_data.wfe_timeout,
|
|
cb_param->pkt->err_data.event, isHWhang);
|
|
|
|
imgsys_cmdq_cmd_dump(cb_param->frm_info, real_frm_idx);
|
|
|
|
if (cb_param->user_cmdq_err_cb) {
|
|
struct cmdq_cb_data user_cb_data;
|
|
|
|
user_cb_data.err = cb_param->err;
|
|
user_cb_data.data = (void *)cb_param->frm_info;
|
|
cb_param->user_cmdq_err_cb(
|
|
user_cb_data, real_frm_idx, isHWhang);
|
|
}
|
|
}
|
|
|
|
cb_param->cmdqTs.tsCmdqCbEnd = ktime_get_boottime_ns()/1000;
|
|
|
|
INIT_WORK(&cb_param->cmdq_cb_work, imgsys_cmdq_cb_work);
|
|
queue_work(imgsys_cmdq_wq, &cb_param->cmdq_cb_work);
|
|
}
|
|
|
|
int imgsys_cmdq_sendtask(struct mtk_imgsys_dev *imgsys_dev,
|
|
struct swfrm_info_t *frm_info,
|
|
void (*cmdq_cb)(struct cmdq_cb_data data,
|
|
uint32_t subfidx, bool isLastTaskInReq),
|
|
void (*cmdq_err_cb)(struct cmdq_cb_data data,
|
|
uint32_t fail_subfidx, bool isHWhang))
|
|
{
|
|
struct cmdq_client *clt = NULL;
|
|
struct cmdq_pkt *pkt = NULL;
|
|
struct GCERecoder *cmd_buf = NULL;
|
|
struct Command *cmd = NULL;
|
|
struct mtk_imgsys_cb_param *cb_param = NULL;
|
|
dma_addr_t pkt_ts_pa;
|
|
u32 *pkt_ts_va = NULL;
|
|
u32 pkt_ts_num = 0;
|
|
u32 pkt_ts_ofst = 0;
|
|
u32 cmd_max_sz = 0;
|
|
u32 cmd_num = 0;
|
|
u32 cmd_idx = 0;
|
|
u32 blk_idx = 0; /* For Vss block cnt */
|
|
u32 blk_num = 0;
|
|
u32 thd_idx = 0;
|
|
u32 hw_comb = 0;
|
|
int ret = 0, ret_flush = 0;
|
|
u64 tsReqStart = 0;
|
|
u64 tsDvfsQosStart = 0, tsDvfsQosEnd = 0;
|
|
u32 frm_num = 0, frm_idx = 0;
|
|
u32 cmd_ofst = 0;
|
|
bool isPack = 0;
|
|
u32 task_idx = 0;
|
|
u32 task_id = 0;
|
|
u32 task_num = 0;
|
|
u32 task_cnt = 0;
|
|
size_t pkt_ofst[MAX_FRAME_IN_TASK] = {0};
|
|
char logBuf_temp[MTK_IMGSYS_LOG_LENGTH];
|
|
|
|
/* PMQOS API */
|
|
tsDvfsQosStart = ktime_get_boottime_ns()/1000;
|
|
IMGSYS_SYSTRACE_BEGIN("%s_%s|Imgsys MWFrame:#%d MWReq:#%d ReqFd:%d Own:%llx\n",
|
|
__func__, "dvfs_qos", frm_info->frame_no, frm_info->request_no,
|
|
frm_info->request_fd, frm_info->frm_owner);
|
|
mutex_lock(&(imgsys_dev->dvfs_qos_lock));
|
|
#if DVFS_QOS_READY
|
|
mtk_imgsys_mmdvfs_mmqos_cal(imgsys_dev, frm_info, 1);
|
|
mtk_imgsys_mmdvfs_set(imgsys_dev, frm_info, 1);
|
|
#if IMGSYS_QOS_SET_REAL
|
|
mtk_imgsys_mmqos_set(imgsys_dev, frm_info, 1);
|
|
#elif IMGSYS_QOS_SET_BY_SCEN
|
|
mtk_imgsys_mmqos_set_by_scen(imgsys_dev, frm_info, 1);
|
|
#endif
|
|
#endif
|
|
mutex_unlock(&(imgsys_dev->dvfs_qos_lock));
|
|
IMGSYS_SYSTRACE_END();
|
|
tsDvfsQosEnd = ktime_get_boottime_ns()/1000;
|
|
|
|
/* is_stream_off = 0; */
|
|
frm_num = frm_info->total_frmnum;
|
|
frm_info->cb_frmcnt = 0;
|
|
frm_info->total_taskcnt = 0;
|
|
cmd_ofst = sizeof(struct GCERecoder);
|
|
|
|
#if IMGSYS_SECURE_ENABLE
|
|
if (frm_info->is_secReq && (is_sec_task_create == 0)) {
|
|
imgsys_cmdq_sec_sendtask(imgsys_dev);
|
|
is_sec_task_create = 1;
|
|
pr_info(
|
|
"%s: create imgsys secure task is_secReq(%d)\n",
|
|
__func__, frm_info->is_secReq);
|
|
}
|
|
#endif
|
|
|
|
/* Allocate cmdq buffer for task timestamp */
|
|
if (imgsys_cmdq_ts_enable() || imgsys_wpe_bwlog_enable()) {
|
|
pkt_ts_va = cmdq_mbox_buf_alloc(imgsys_clt[0], &pkt_ts_pa);
|
|
if (imgsys_cmdq_ts_dbg_enable()) {
|
|
frm_info->hw_ts_log = vzalloc(sizeof(char)*MTK_IMGSYS_LOG_LENGTH);
|
|
memset((char *)frm_info->hw_ts_log, 0x0, MTK_IMGSYS_LOG_LENGTH);
|
|
frm_info->hw_ts_log[strlen(frm_info->hw_ts_log)] = '\0';
|
|
memset((char *)logBuf_temp, 0x0, MTK_IMGSYS_LOG_LENGTH);
|
|
logBuf_temp[strlen(logBuf_temp)] = '\0';
|
|
snprintf(logBuf_temp, MTK_IMGSYS_LOG_LENGTH,
|
|
"own(%llx/%s)req fd/no(%d/%d) frame no(%d) gid(%d)",
|
|
frm_info->frm_owner, (char *)(&(frm_info->frm_owner)),
|
|
frm_info->request_fd, frm_info->request_no, frm_info->frame_no,
|
|
frm_info->group_id);
|
|
strncat(frm_info->hw_ts_log, logBuf_temp, strlen(logBuf_temp));
|
|
}
|
|
}
|
|
|
|
for (frm_idx = 0; frm_idx < frm_num; frm_idx++) {
|
|
cmd_buf = (struct GCERecoder *)frm_info->user_info[frm_idx].g_swbuf;
|
|
|
|
if ((cmd_buf->header_code != 0x5A5A5A5A) ||
|
|
(cmd_buf->check_pre != 0x55AA55AA) ||
|
|
(cmd_buf->check_post != 0xAA55AA55) ||
|
|
(cmd_buf->footer_code != 0xA5A5A5A5)) {
|
|
pr_info("%s: Incorrect guard word: %08x/%08x/%08x/%08x", __func__,
|
|
cmd_buf->header_code, cmd_buf->check_pre, cmd_buf->check_post,
|
|
cmd_buf->footer_code);
|
|
return -1;
|
|
}
|
|
|
|
if (frm_info->user_info[frm_idx].is_time_shared)
|
|
cmd_max_sz = IMGSYS_CMD_MAX_SZ_V;
|
|
else
|
|
cmd_max_sz = IMGSYS_CMD_MAX_SZ_N;
|
|
if (cmd_buf->cmd_offset > cmd_max_sz) {
|
|
pr_info("%s: [ERROR] cmd offset(0x%x) is over maximum(0x%x)",
|
|
__func__, cmd_buf->cmd_offset, cmd_max_sz);
|
|
return -1;
|
|
}
|
|
|
|
cmd_num = cmd_buf->curr_length / sizeof(struct Command);
|
|
cmd = (struct Command *)((unsigned long)(frm_info->user_info[frm_idx].g_swbuf) +
|
|
(unsigned long)(cmd_buf->cmd_offset));
|
|
blk_num = cmd_buf->frame_block;
|
|
hw_comb = frm_info->user_info[frm_idx].hw_comb;
|
|
|
|
if (isPack == 0) {
|
|
if (frm_info->group_id == -1) {
|
|
/* Choose cmdq_client base on hw scenario */
|
|
for (thd_idx = 0; thd_idx < IMGSYS_ENG_MAX; thd_idx++) {
|
|
if (hw_comb & 0x1) {
|
|
clt = imgsys_clt[thd_idx];
|
|
pr_debug(
|
|
"%s: chosen mbox thread (%d, 0x%x) for frm(%d/%d)\n",
|
|
__func__, thd_idx, clt, frm_idx, frm_num);
|
|
break;
|
|
}
|
|
hw_comb = hw_comb>>1;
|
|
}
|
|
/* This segment can be removed since user had set dependency */
|
|
if (frm_info->user_info[frm_idx].hw_comb & IMGSYS_ENG_DIP) {
|
|
thd_idx = 4;
|
|
clt = imgsys_clt[thd_idx];
|
|
}
|
|
} else {
|
|
if ((frm_info->group_id >= 0) &&
|
|
(frm_info->group_id < IMGSYS_ENG_MAX)) {
|
|
thd_idx = frm_info->group_id;
|
|
clt = imgsys_clt[thd_idx];
|
|
} else {
|
|
pr_info(
|
|
"%s: [ERROR] group_id(%d) is not in range(%d) for hw_comb(0x%x) frm(%d/%d)!\n",
|
|
__func__, frm_info->group_id, IMGSYS_ENG_MAX,
|
|
frm_info->user_info[frm_idx].hw_comb,
|
|
frm_idx, frm_num);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* This is work around for low latency flow. */
|
|
/* If we change to request base, */
|
|
/* we don't have to take this condition into account. */
|
|
if (frm_info->sync_id != -1) {
|
|
thd_idx = 0;
|
|
clt = imgsys_clt[thd_idx];
|
|
}
|
|
|
|
if (clt == NULL) {
|
|
pr_info("%s: [ERROR] No HW Found (0x%x) for frm(%d/%d)!\n",
|
|
__func__, frm_info->user_info[frm_idx].hw_comb,
|
|
frm_idx, frm_num);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: req fd/no(%d/%d) frame no(%d) frm(%d/%d) cmd_oft(0x%x/0x%x), cmd_len(%d), num(%d), sz_per_cmd(%d), frm_blk(%d), hw_comb(0x%x), sync_id(%d), gce_thd(%d), gce_clt(0x%x)\n",
|
|
__func__, frm_info->request_fd, frm_info->request_no, frm_info->frame_no,
|
|
frm_idx, frm_num, cmd_buf->cmd_offset, cmd_ofst, cmd_buf->curr_length,
|
|
cmd_num, sizeof(struct Command), cmd_buf->frame_block,
|
|
frm_info->user_info[frm_idx].hw_comb, frm_info->sync_id, thd_idx, clt);
|
|
|
|
cmd_idx = 0;
|
|
for (blk_idx = 0; blk_idx < blk_num; blk_idx++) {
|
|
tsReqStart = ktime_get_boottime_ns()/1000;
|
|
if (isPack == 0) {
|
|
/* create pkt and hook clt as pkt's private data */
|
|
pkt = cmdq_pkt_create(clt);
|
|
if (pkt == NULL) {
|
|
pr_info(
|
|
"%s: [ERROR] cmdq_pkt_create fail in block(%d)!\n",
|
|
__func__, blk_idx);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: cmdq_pkt_create success(0x%x) in block(%d) for frm(%d/%d)\n",
|
|
__func__, pkt, blk_idx, frm_idx, frm_num);
|
|
/* Reset pkt timestamp num */
|
|
pkt_ts_num = 0;
|
|
|
|
/* Assign task priority according to is_time_shared */
|
|
if (frm_info->user_info[frm_idx].is_time_shared)
|
|
pkt->priority = IMGSYS_PRI_LOW;
|
|
else
|
|
pkt->priority = IMGSYS_PRI_HIGH;
|
|
}
|
|
|
|
IMGSYS_SYSTRACE_BEGIN(
|
|
"%s_%s|Imgsys MWFrame:#%d MWReq:#%d ReqFd:%d fidx:%d hw_comb:0x%x Own:%llx frm(%d/%d) blk(%d)\n",
|
|
__func__, "cmd_parser", frm_info->frame_no, frm_info->request_no,
|
|
frm_info->request_fd, frm_info->user_info[frm_idx].subfrm_idx,
|
|
frm_info->user_info[frm_idx].hw_comb, frm_info->frm_owner,
|
|
frm_idx, frm_num, blk_idx);
|
|
// Add secure token begin
|
|
#if IMGSYS_SECURE_ENABLE
|
|
if (frm_info->user_info[frm_idx].is_secFrm)
|
|
imgsys_cmdq_sec_cmd(pkt);
|
|
#endif
|
|
|
|
ret = imgsys_cmdq_parser(frm_info, pkt, &cmd[cmd_idx], hw_comb, cmd_num,
|
|
(pkt_ts_pa + 4 * pkt_ts_ofst), &pkt_ts_num, thd_idx);
|
|
if (ret < 0) {
|
|
pr_info(
|
|
"%s: [ERROR] parsing idx(%d) with cmd(%d) in block(%d) for frm(%d/%d) fail\n",
|
|
__func__, cmd_idx, cmd[cmd_idx].opcode,
|
|
blk_idx, frm_idx, frm_num);
|
|
cmdq_pkt_destroy(pkt);
|
|
goto sendtask_done;
|
|
}
|
|
cmd_idx += ret;
|
|
|
|
// Add secure token end
|
|
#if IMGSYS_SECURE_ENABLE
|
|
if (frm_info->user_info[frm_idx].is_secFrm)
|
|
imgsys_cmdq_sec_cmd(pkt);
|
|
#endif
|
|
|
|
IMGSYS_SYSTRACE_END();
|
|
|
|
/* Check for packing gce task */
|
|
pkt_ofst[task_cnt] = pkt->cmd_buf_size - CMDQ_INST_SIZE;
|
|
task_cnt++;
|
|
if ((frm_info->user_info[frm_idx].is_time_shared)
|
|
|| (frm_info->user_info[frm_idx].is_secFrm)
|
|
|| (frm_info->user_info[frm_idx].is_earlycb)
|
|
|| ((frm_idx + 1) == frm_num)) {
|
|
mtk_imgsys_power_ctrl(imgsys_dev, true);
|
|
|
|
/* Prepare cb param */
|
|
cb_param =
|
|
vzalloc(sizeof(struct mtk_imgsys_cb_param));
|
|
if (cb_param == NULL) {
|
|
cmdq_pkt_destroy(pkt);
|
|
return -1;
|
|
}
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: cb_param kzalloc success cb(%p) in block(%d) for frm(%d/%d)!\n",
|
|
__func__, cb_param, blk_idx, frm_idx, frm_num);
|
|
|
|
task_num++;
|
|
cb_param->pkt = pkt;
|
|
cb_param->frm_info = frm_info;
|
|
cb_param->req_fd = frm_info->request_fd;
|
|
cb_param->req_no = frm_info->request_no;
|
|
cb_param->frm_no = frm_info->frame_no;
|
|
cb_param->hw_comb = hw_comb;
|
|
cb_param->frm_idx = frm_idx;
|
|
cb_param->frm_num = frm_num;
|
|
cb_param->user_cmdq_cb = cmdq_cb;
|
|
cb_param->user_cmdq_err_cb = cmdq_err_cb;
|
|
if ((blk_idx + 1) == blk_num)
|
|
cb_param->isBlkLast = 1;
|
|
else
|
|
cb_param->isBlkLast = 0;
|
|
if ((frm_idx + 1) == frm_num)
|
|
cb_param->isFrmLast = 1;
|
|
else
|
|
cb_param->isFrmLast = 0;
|
|
cb_param->blk_idx = blk_idx;
|
|
cb_param->blk_num = blk_num;
|
|
cb_param->is_earlycb = frm_info->user_info[frm_idx].is_earlycb;
|
|
cb_param->group_id = frm_info->group_id;
|
|
cb_param->cmdqTs.tsReqStart = tsReqStart;
|
|
cb_param->cmdqTs.tsDvfsQosStart = tsDvfsQosStart;
|
|
cb_param->cmdqTs.tsDvfsQosEnd = tsDvfsQosEnd;
|
|
cb_param->imgsys_dev = imgsys_dev;
|
|
cb_param->thd_idx = thd_idx;
|
|
cb_param->clt = clt;
|
|
cb_param->task_cnt = task_cnt;
|
|
for (task_idx = 0; task_idx < task_cnt; task_idx++)
|
|
cb_param->pkt_ofst[task_idx] = pkt_ofst[task_idx];
|
|
task_cnt = 0;
|
|
cb_param->task_id = task_id;
|
|
task_id++;
|
|
if ((cb_param->isBlkLast) && (cb_param->isFrmLast)) {
|
|
cb_param->isTaskLast = 1;
|
|
cb_param->task_num = task_num;
|
|
frm_info->total_taskcnt = task_num;
|
|
} else {
|
|
cb_param->isTaskLast = 0;
|
|
cb_param->task_num = 0;
|
|
}
|
|
|
|
dev_dbg(imgsys_dev->dev,
|
|
"%s: cb(%p) gid(%d) in block(%d/%d) for frm(%d/%d) lst(%d/%d/%d) task(%d/%d/%d) ofst(%x/%x/%x/%x/%x)\n",
|
|
__func__, cb_param, cb_param->group_id,
|
|
cb_param->blk_idx, cb_param->blk_num,
|
|
cb_param->frm_idx, cb_param->frm_num,
|
|
cb_param->isBlkLast, cb_param->isFrmLast,
|
|
cb_param->isTaskLast, cb_param->task_id,
|
|
cb_param->task_num, cb_param->task_cnt,
|
|
cb_param->pkt_ofst[0], cb_param->pkt_ofst[1],
|
|
cb_param->pkt_ofst[2], cb_param->pkt_ofst[3],
|
|
cb_param->pkt_ofst[4]);
|
|
|
|
if (imgsys_cmdq_ts_enable() || imgsys_wpe_bwlog_enable()) {
|
|
cb_param->taskTs.dma_pa = pkt_ts_pa;
|
|
cb_param->taskTs.dma_va = pkt_ts_va;
|
|
cb_param->taskTs.num = pkt_ts_num;
|
|
cb_param->taskTs.ofst = pkt_ts_ofst;
|
|
pkt_ts_ofst += pkt_ts_num;
|
|
}
|
|
|
|
/* flush synchronized, block API */
|
|
cb_param->cmdqTs.tsFlushStart = ktime_get_boottime_ns()/1000;
|
|
IMGSYS_SYSTRACE_BEGIN(
|
|
"%s_%s|Imgsys MWFrame:#%d MWReq:#%d ReqFd:%d fidx:%d hw_comb:0x%x Own:%llx cb(%p) frm(%d/%d) blk(%d/%d)\n",
|
|
__func__, "pkt_flush", frm_info->frame_no,
|
|
frm_info->request_no, frm_info->request_fd,
|
|
frm_info->user_info[frm_idx].subfrm_idx,
|
|
frm_info->user_info[frm_idx].hw_comb,
|
|
frm_info->frm_owner, cb_param, frm_idx, frm_num,
|
|
blk_idx, blk_num);
|
|
|
|
ret_flush = cmdq_pkt_flush_async(pkt, imgsys_cmdq_task_cb,
|
|
(void *)cb_param);
|
|
IMGSYS_SYSTRACE_END();
|
|
if (ret_flush < 0)
|
|
pr_info(
|
|
"%s: [ERROR] cmdq_pkt_flush_async fail(%d) for frm(%d/%d)!\n",
|
|
__func__, ret_flush, frm_idx, frm_num);
|
|
else
|
|
pr_debug(
|
|
"%s: cmdq_pkt_flush_async success(%d), blk(%d), frm(%d/%d)!\n",
|
|
__func__, ret_flush, blk_idx, frm_idx, frm_num);
|
|
isPack = 0;
|
|
} else {
|
|
isPack = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
sendtask_done:
|
|
return ret;
|
|
}
|
|
|
|
int imgsys_cmdq_parser(struct swfrm_info_t *frm_info, struct cmdq_pkt *pkt,
|
|
struct Command *cmd, u32 hw_comb, u32 cmd_num,
|
|
dma_addr_t dma_pa, uint32_t *num, u32 thd_idx)
|
|
{
|
|
bool stop = 0;
|
|
int count = 0;
|
|
int req_fd = 0, req_no = 0, frm_no = 0;
|
|
u32 event = 0;
|
|
|
|
req_fd = frm_info->request_fd;
|
|
req_no = frm_info->request_no;
|
|
frm_no = frm_info->frame_no;
|
|
|
|
pr_debug("%s: +, cmd(%d)\n", __func__, cmd->opcode);
|
|
|
|
do {
|
|
switch (cmd->opcode) {
|
|
case IMGSYS_CMD_READ:
|
|
if ((cmd->u.address < IMGSYS_REG_START) ||
|
|
(cmd->u.address > IMGSYS_REG_END)) {
|
|
pr_info(
|
|
"%s: [ERROR] READ with source(0x%08lx) target(0x%08lx) mask(0x%08x)\n",
|
|
__func__, cmd->u.source, cmd->u.target, cmd->u.mask);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: READ with source(0x%08lx) target(0x%08lx) mask(0x%08x)\n",
|
|
__func__, cmd->u.source, cmd->u.target, cmd->u.mask);
|
|
if (imgsys_wpe_bwlog_enable()) {
|
|
cmdq_pkt_mem_move(pkt, NULL, (dma_addr_t)cmd->u.source,
|
|
dma_pa + (4*(*num)), CMDQ_THR_SPR_IDX3);
|
|
(*num)++;
|
|
} else
|
|
pr_info(
|
|
"%s: [ERROR]Not enable imgsys read cmd!!\n",
|
|
__func__);
|
|
break;
|
|
case IMGSYS_CMD_WRITE:
|
|
if ((cmd->u.address < IMGSYS_REG_START) ||
|
|
(cmd->u.address > IMGSYS_REG_END)) {
|
|
pr_info(
|
|
"%s: [ERROR] WRITE with addr(0x%08lx) value(0x%08x) mask(0x%08x)\n",
|
|
__func__, cmd->u.address, cmd->u.value, cmd->u.mask);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: WRITE with addr(0x%08lx) value(0x%08x) mask(0x%08x)\n",
|
|
__func__, cmd->u.address, cmd->u.value, cmd->u.mask);
|
|
cmdq_pkt_write(pkt, NULL, (dma_addr_t)cmd->u.address,
|
|
cmd->u.value, cmd->u.mask);
|
|
break;
|
|
case IMGSYS_CMD_POLL:
|
|
if ((cmd->u.address < IMGSYS_REG_START) ||
|
|
(cmd->u.address > IMGSYS_REG_END)) {
|
|
pr_info(
|
|
"%s: [ERROR] POLL with addr(0x%08lx) value(0x%08x) mask(0x%08x) thd(%d)\n",
|
|
__func__, cmd->u.address, cmd->u.value, cmd->u.mask,
|
|
thd_idx);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: POLL with addr(0x%08lx) value(0x%08x) mask(0x%08x) thd(%d)\n",
|
|
__func__, cmd->u.address, cmd->u.value, cmd->u.mask, thd_idx);
|
|
/* cmdq_pkt_poll(pkt, NULL, cmd->u.value, cmd->u.address, */
|
|
/* cmd->u.mask, CMDQ_GPR_R15); */
|
|
cmdq_pkt_poll_timeout(pkt, cmd->u.value, SUBSYS_NO_SUPPORT,
|
|
cmd->u.address, cmd->u.mask, 0xFFFF, CMDQ_GPR_R03+thd_idx);
|
|
break;
|
|
case IMGSYS_CMD_WAIT:
|
|
if (cmd->u.event >= IMGSYS_CMDQ_EVENT_MAX) {
|
|
pr_info(
|
|
"%s: [ERROR] WAIT event(%d) index is over maximum(%d) with action(%d)!\n",
|
|
__func__, cmd->u.event, IMGSYS_CMDQ_EVENT_MAX,
|
|
cmd->u.action);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: WAIT event(%d/%d) action(%d)\n",
|
|
__func__, cmd->u.event, imgsys_event[cmd->u.event].event,
|
|
cmd->u.action);
|
|
if (cmd->u.action == 1) {
|
|
cmdq_pkt_wfe(pkt, imgsys_event[cmd->u.event].event);
|
|
if ((cmd->u.event >= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_POOL_START) &&
|
|
(cmd->u.event <= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_END)) {
|
|
event = cmd->u.event -
|
|
IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_POOL_START;
|
|
event_hist[event].st++;
|
|
event_hist[event].wait.req_fd = req_fd;
|
|
event_hist[event].wait.req_no = req_no;
|
|
event_hist[event].wait.frm_no = frm_no;
|
|
event_hist[event].wait.ts = ktime_get_boottime_ns()/1000;
|
|
event_hist[event].wait.frm_info = frm_info;
|
|
event_hist[event].wait.pkt = pkt;
|
|
}
|
|
} else if (cmd->u.action == 0)
|
|
cmdq_pkt_wait_no_clear(pkt, imgsys_event[cmd->u.event].event);
|
|
else
|
|
pr_info("%s: [ERROR]Not Support wait action(%d)!\n",
|
|
__func__, cmd->u.action);
|
|
break;
|
|
case IMGSYS_CMD_UPDATE:
|
|
if (cmd->u.event >= IMGSYS_CMDQ_EVENT_MAX) {
|
|
pr_info(
|
|
"%s: [ERROR] UPDATE event(%d) index is over maximum(%d) with action(%d)!\n",
|
|
__func__, cmd->u.event, IMGSYS_CMDQ_EVENT_MAX,
|
|
cmd->u.action);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: UPDATE event(%d/%d) action(%d)\n",
|
|
__func__, cmd->u.event, imgsys_event[cmd->u.event].event,
|
|
cmd->u.action);
|
|
if (cmd->u.action == 1) {
|
|
cmdq_pkt_set_event(pkt, imgsys_event[cmd->u.event].event);
|
|
if ((cmd->u.event >= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_POOL_START) &&
|
|
(cmd->u.event <= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_END)) {
|
|
event = cmd->u.event -
|
|
IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_POOL_START;
|
|
event_hist[event].st--;
|
|
event_hist[event].set.req_fd = req_fd;
|
|
event_hist[event].set.req_no = req_no;
|
|
event_hist[event].set.frm_no = frm_no;
|
|
event_hist[event].set.ts = ktime_get_boottime_ns()/1000;
|
|
event_hist[event].set.frm_info = frm_info;
|
|
event_hist[event].set.pkt = pkt;
|
|
}
|
|
} else if (cmd->u.action == 0)
|
|
cmdq_pkt_clear_event(pkt, imgsys_event[cmd->u.event].event);
|
|
else
|
|
pr_info("%s: [ERROR]Not Support update action(%d)!\n",
|
|
__func__, cmd->u.action);
|
|
break;
|
|
case IMGSYS_CMD_ACQUIRE:
|
|
if (cmd->u.event >= IMGSYS_CMDQ_EVENT_MAX) {
|
|
pr_info(
|
|
"%s: [ERROR] ACQUIRE event(%d) index is over maximum(%d) with action(%d)!\n",
|
|
__func__, cmd->u.event, IMGSYS_CMDQ_EVENT_MAX,
|
|
cmd->u.action);
|
|
return -1;
|
|
}
|
|
pr_debug(
|
|
"%s: ACQUIRE event(%d/%d) action(%d)\n", __func__,
|
|
cmd->u.event, imgsys_event[cmd->u.event].event, cmd->u.action);
|
|
cmdq_pkt_acquire_event(pkt, imgsys_event[cmd->u.event].event);
|
|
break;
|
|
case IMGSYS_CMD_TIME:
|
|
pr_debug(
|
|
"%s: TIME with addr(0x%08lx) num(0x%08x)\n",
|
|
__func__, dma_pa, *num);
|
|
if (imgsys_cmdq_ts_enable()) {
|
|
cmdq_pkt_write_indriect(pkt, NULL, dma_pa + (4*(*num)),
|
|
CMDQ_TPR_ID, ~0);
|
|
(*num)++;
|
|
} else
|
|
pr_info(
|
|
"%s: [ERROR]Not enable imgsys cmdq ts function!!\n",
|
|
__func__);
|
|
break;
|
|
case IMGSYS_CMD_STOP:
|
|
pr_debug("%s: End Of Cmd!\n", __func__);
|
|
stop = 1;
|
|
break;
|
|
default:
|
|
pr_info("%s: [ERROR]Not Support Cmd(%d)!\n", __func__, cmd->opcode);
|
|
return -1;
|
|
}
|
|
cmd++;
|
|
count++;
|
|
} while ((stop == 0) && (count < cmd_num));
|
|
|
|
return count;
|
|
}
|
|
|
|
void imgsys_cmdq_sec_task_cb(struct cmdq_cb_data data)
|
|
{
|
|
struct cmdq_pkt *pkt_sec = (struct cmdq_pkt *)data.data;
|
|
|
|
cmdq_pkt_destroy(pkt_sec);
|
|
}
|
|
|
|
int imgsys_cmdq_sec_sendtask(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
struct cmdq_client *clt_sec = NULL;
|
|
struct cmdq_pkt *pkt_sec = NULL;
|
|
int ret = 0;
|
|
|
|
clt_sec = imgsys_sec_clt[0];
|
|
#if IMGSYS_SECURE_ENABLE
|
|
pkt_sec = cmdq_pkt_create(clt_sec);
|
|
cmdq_sec_pkt_set_data(pkt_sec, 0, 0, CMDQ_SEC_DEBUG, CMDQ_METAEX_TZMP);
|
|
cmdq_sec_pkt_set_mtee(pkt_sec, true);
|
|
cmdq_pkt_finalize_loop(pkt_sec);
|
|
cmdq_pkt_flush_threaded(pkt_sec, imgsys_cmdq_sec_task_cb, (void *)pkt_sec);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
void imgsys_cmdq_sec_cmd(struct cmdq_pkt *pkt)
|
|
{
|
|
cmdq_pkt_set_event(pkt, imgsys_event[IMGSYS_CMDQ_SYNC_TOKEN_TZMP_ISP_WAIT].event);
|
|
cmdq_pkt_wfe(pkt, imgsys_event[IMGSYS_CMDQ_SYNC_TOKEN_TZMP_ISP_SET].event);
|
|
}
|
|
|
|
void imgsys_cmdq_setevent(u64 u_id)
|
|
{
|
|
u32 event_id = 0L, event_val = 0L;
|
|
|
|
event_id = IMGSYS_CMDQ_SYNC_TOKEN_CAMSYS_POOL_1 + (u_id % 10);
|
|
event_val = cmdq_get_event(imgsys_clt[0]->chan, imgsys_event[event_id].event);
|
|
|
|
if (event_val == 0) {
|
|
cmdq_set_event(imgsys_clt[0]->chan, imgsys_event[event_id].event);
|
|
pr_debug("%s: SetEvent success with (u_id/event_id/event_val)=(%d/%d/%d)!\n",
|
|
__func__, u_id, event_id, event_val);
|
|
} else {
|
|
pr_info("%s: [ERROR]SetEvent fail with (u_id/event_id/event_val)=(%d/%d/%d)!\n",
|
|
__func__, u_id, event_id, event_val);
|
|
}
|
|
}
|
|
|
|
void imgsys_cmdq_clearevent(int event_id)
|
|
{
|
|
if ((event_id >= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_POOL_START) &&
|
|
(event_id <= IMGSYS_CMDQ_SYNC_TOKEN_IMGSYS_END)) {
|
|
cmdq_mbox_enable(imgsys_clt[0]->chan);
|
|
cmdq_clear_event(imgsys_clt[0]->chan, imgsys_event[event_id].event);
|
|
pr_debug("%s: cmdq_clear_event with (%d/%d)!\n",
|
|
__func__, event_id, imgsys_event[event_id].event);
|
|
cmdq_mbox_disable(imgsys_clt[0]->chan);
|
|
} else {
|
|
pr_info("%s: [ERROR]unexpected event_id=(%d)!\n",
|
|
__func__, event_id);
|
|
}
|
|
}
|
|
|
|
#if DVFS_QOS_READY
|
|
void mtk_imgsys_mmdvfs_init(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
struct mtk_imgsys_dvfs *dvfs_info = &imgsys_dev->dvfs_info;
|
|
u64 freq = 0;
|
|
int ret = 0, opp_num = 0, opp_idx = 0, idx = 0, volt;
|
|
struct device_node *np, *child_np = NULL;
|
|
struct of_phandle_iterator it;
|
|
|
|
memset((void *)dvfs_info, 0x0, sizeof(struct mtk_imgsys_dvfs));
|
|
dvfs_info->dev = imgsys_dev->dev;
|
|
dvfs_info->reg = NULL;
|
|
ret = dev_pm_opp_of_add_table(dvfs_info->dev);
|
|
if (ret < 0) {
|
|
dev_info(dvfs_info->dev,
|
|
"%s: [ERROR] fail to init opp table: %d\n", __func__, ret);
|
|
return;
|
|
}
|
|
dvfs_info->reg = devm_regulator_get(dvfs_info->dev, "dvfsrc-vmm");
|
|
if (IS_ERR_OR_NULL(dvfs_info->reg)) {
|
|
dev_info(dvfs_info->dev, "%s: [ERROR] can't get dvfsrc-vmm\n", __func__);
|
|
return;
|
|
}
|
|
|
|
opp_num = regulator_count_voltages(dvfs_info->reg);
|
|
of_for_each_phandle(
|
|
&it, ret, dvfs_info->dev->of_node, "operating-points-v2", NULL, 0) {
|
|
np = of_node_get(it.node);
|
|
if (!np) {
|
|
dev_info(dvfs_info->dev, "%s: [ERROR] of_node_get fail\n", __func__);
|
|
return;
|
|
}
|
|
|
|
do {
|
|
child_np = of_get_next_available_child(np, child_np);
|
|
if (child_np) {
|
|
of_property_read_u64(child_np, "opp-hz", &freq);
|
|
dvfs_info->clklv[opp_idx][idx] = freq;
|
|
of_property_read_u32(child_np, "opp-microvolt", &volt);
|
|
dvfs_info->voltlv[opp_idx][idx] = volt;
|
|
idx++;
|
|
}
|
|
} while (child_np);
|
|
dvfs_info->clklv_num[opp_idx] = idx;
|
|
dvfs_info->clklv_target[opp_idx] = dvfs_info->clklv[opp_idx][0];
|
|
dvfs_info->clklv_idx[opp_idx] = 0;
|
|
idx = 0;
|
|
opp_idx++;
|
|
of_node_put(np);
|
|
}
|
|
|
|
opp_num = opp_idx;
|
|
for (opp_idx = 0; opp_idx < opp_num; opp_idx++) {
|
|
for (idx = 0; idx < dvfs_info->clklv_num[opp_idx]; idx++) {
|
|
dev_info(dvfs_info->dev, "[%s] opp=%d, idx=%d, clk=%d volt=%d\n",
|
|
__func__, opp_idx, idx, dvfs_info->clklv[opp_idx][idx],
|
|
dvfs_info->voltlv[opp_idx][idx]);
|
|
}
|
|
}
|
|
dvfs_info->cur_volt = 0;
|
|
dvfs_info->vss_task_cnt = 0;
|
|
dvfs_info->smvr_task_cnt = 0;
|
|
|
|
}
|
|
|
|
void mtk_imgsys_mmdvfs_uninit(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
struct mtk_imgsys_dvfs *dvfs_info = &imgsys_dev->dvfs_info;
|
|
int volt = 0, ret = 0;
|
|
|
|
dev_info(dvfs_info->dev, "[%s]\n", __func__);
|
|
|
|
dvfs_info->cur_volt = volt;
|
|
|
|
if (IS_ERR_OR_NULL(dvfs_info->reg))
|
|
dev_info(dvfs_info->dev, "%s: [ERROR] reg is err or null\n", __func__);
|
|
else
|
|
ret = regulator_set_voltage(dvfs_info->reg, volt, INT_MAX);
|
|
|
|
}
|
|
|
|
void mtk_imgsys_mmdvfs_set(struct mtk_imgsys_dev *imgsys_dev,
|
|
struct swfrm_info_t *frm_info,
|
|
bool isSet)
|
|
{
|
|
struct mtk_imgsys_dvfs *dvfs_info = &imgsys_dev->dvfs_info;
|
|
int volt = 0, ret = 0, idx = 0, opp_idx = 0;
|
|
unsigned long freq = 0;
|
|
/* u32 hw_comb = frm_info->user_info[0].hw_comb; */
|
|
|
|
freq = dvfs_info->freq;
|
|
|
|
if (IS_ERR_OR_NULL(dvfs_info->reg))
|
|
dev_dbg(dvfs_info->dev, "%s: [ERROR] reg is err or null\n", __func__);
|
|
else {
|
|
/* Choose for IPESYS */
|
|
/* if (hw_comb & IMGSYS_ENG_ME) */
|
|
/* opp_idx = 1; */
|
|
|
|
for (idx = 0; idx < dvfs_info->clklv_num[opp_idx]; idx++) {
|
|
if (freq <= dvfs_info->clklv[opp_idx][idx])
|
|
break;
|
|
}
|
|
if (idx == dvfs_info->clklv_num[opp_idx])
|
|
idx--;
|
|
volt = dvfs_info->voltlv[opp_idx][idx];
|
|
|
|
if (dvfs_info->cur_volt != volt) {
|
|
if (imgsys_dvfs_dbg_enable())
|
|
dev_info(dvfs_info->dev, "[%s] volt change opp=%d, idx=%d, clk=%d volt=%d\n",
|
|
__func__, opp_idx, idx, dvfs_info->clklv[opp_idx][idx],
|
|
dvfs_info->voltlv[opp_idx][idx]);
|
|
ret = regulator_set_voltage(dvfs_info->reg, volt, INT_MAX);
|
|
dvfs_info->cur_volt = volt;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_init(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
struct mtk_imgsys_qos *qos_info = &imgsys_dev->qos_info;
|
|
//struct icc_path *path;
|
|
int idx = 0;
|
|
|
|
memset((void *)qos_info, 0x0, sizeof(struct mtk_imgsys_qos));
|
|
qos_info->dev = imgsys_dev->dev;
|
|
qos_info->qos_path = imgsys_qos_path;
|
|
|
|
for (idx = 0; idx < IMGSYS_M4U_PORT_MAX; idx++) {
|
|
qos_info->qos_path[idx].path =
|
|
of_mtk_icc_get(qos_info->dev, qos_info->qos_path[idx].dts_name);
|
|
qos_info->qos_path[idx].bw = 0;
|
|
dev_info(qos_info->dev, "[%s] idx=%d, path=%p, name=%s, bw=%d\n",
|
|
__func__, idx,
|
|
qos_info->qos_path[idx].path,
|
|
qos_info->qos_path[idx].dts_name,
|
|
qos_info->qos_path[idx].bw);
|
|
}
|
|
mtk_imgsys_mmqos_reset(imgsys_dev);
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_uninit(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
struct mtk_imgsys_qos *qos_info = &imgsys_dev->qos_info;
|
|
int idx = 0;
|
|
|
|
for (idx = 0; idx < IMGSYS_M4U_PORT_MAX; idx++) {
|
|
if (IS_ERR_OR_NULL(qos_info->qos_path[idx].path)) {
|
|
dev_dbg(qos_info->dev, "[%s] path of idx(%d) is NULL\n", __func__, idx);
|
|
continue;
|
|
}
|
|
dev_dbg(qos_info->dev, "[%s] idx=%d, path=%p, bw=%d\n",
|
|
__func__, idx,
|
|
qos_info->qos_path[idx].path,
|
|
qos_info->qos_path[idx].bw);
|
|
qos_info->qos_path[idx].bw = 0;
|
|
mtk_icc_set_bw(qos_info->qos_path[idx].path, 0, 0);
|
|
}
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_set(struct mtk_imgsys_dev *imgsys_dev,
|
|
struct swfrm_info_t *frm_info,
|
|
bool isSet)
|
|
{
|
|
struct mtk_imgsys_qos *qos_info = &imgsys_dev->qos_info;
|
|
u32 hw_comb = 0;
|
|
//u32 port_st = 0, port_num = 0, port_idx = 0;
|
|
u32 frm_num = 0, frm_idx = 0;
|
|
u32 bw;
|
|
u32 dvfs_idx = 0, qos_idx = 0;
|
|
u64 bw_cal[MTK_IMGSYS_DVFS_GROUP][MTK_IMGSYS_QOS_GROUP] = {0};
|
|
u64 bw_final[MTK_IMGSYS_QOS_GROUP] = {0};
|
|
|
|
bw = 0;
|
|
frm_num = frm_info->total_frmnum;
|
|
for (frm_idx = 0; frm_idx < frm_num; frm_idx++)
|
|
hw_comb |= frm_info->user_info[frm_idx].hw_comb;
|
|
|
|
#if IMGSYS_QOS_ENABLE
|
|
if (is_stream_off == 0) {
|
|
if (isSet == 0) {
|
|
qos_info->req_cnt++;
|
|
if (qos_info->req_cnt < imgsys_qos_update_freq)
|
|
/* Do nothing */
|
|
bw = 0;
|
|
else if (qos_info->req_cnt == imgsys_qos_update_freq) {
|
|
for (qos_idx = 0; qos_idx < MTK_IMGSYS_QOS_GROUP; qos_idx++) {
|
|
for (dvfs_idx = 0; dvfs_idx < MTK_IMGSYS_DVFS_GROUP;
|
|
dvfs_idx++) {
|
|
bw_cal[dvfs_idx][qos_idx] =
|
|
qos_info->bw_total[dvfs_idx][qos_idx] /
|
|
qos_info->ts_total[dvfs_idx];
|
|
bw_final[qos_idx] += bw_cal[dvfs_idx][qos_idx];
|
|
}
|
|
bw_final[qos_idx] =
|
|
(bw_final[qos_idx] * imgsys_qos_factor) / 10;
|
|
}
|
|
dev_info(qos_info->dev,
|
|
"%s: bw_final(%lld/%lld) bw_cal_a(%lld/%lld) bw_cal_b(%lld/%lld) bw_a(%lld/%lld) bw_b(%lld/%lld) ts(%d/%lld) para(%d/%d/%d)\n",
|
|
__func__, bw_final[0], bw_final[1],
|
|
bw_cal[0][0], bw_cal[0][1], bw_cal[1][0], bw_cal[1][1],
|
|
qos_info->bw_total[0][0], qos_info->bw_total[0][1],
|
|
qos_info->bw_total[1][0], qos_info->bw_total[1][1],
|
|
qos_info->ts_total[0], qos_info->ts_total[1],
|
|
imgsys_qos_update_freq, imgsys_qos_blank_int,
|
|
imgsys_qos_factor);
|
|
/* Add update bw api */
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
MBps_to_icc(bw_final[0]),
|
|
0);
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
MBps_to_icc(bw_final[1]),
|
|
0);
|
|
} else if ((qos_info->req_cnt > imgsys_qos_update_freq) &&
|
|
(qos_info->req_cnt <=
|
|
(imgsys_qos_update_freq + imgsys_qos_blank_int))) {
|
|
qos_info->isIdle = 1;
|
|
} else {
|
|
for (dvfs_idx = 0; dvfs_idx < MTK_IMGSYS_DVFS_GROUP; dvfs_idx++) {
|
|
for (qos_idx = 0; qos_idx < MTK_IMGSYS_QOS_GROUP; qos_idx++)
|
|
qos_info->bw_total[dvfs_idx][qos_idx] = 0;
|
|
qos_info->ts_total[dvfs_idx] = 0;
|
|
}
|
|
qos_info->req_cnt = 0;
|
|
qos_info->isIdle = 0;
|
|
}
|
|
}
|
|
} else {
|
|
/* Set bw to zero */
|
|
mtk_icc_set_bw(qos_info->qos_path[IMGSYS_L9_COMMON_0].path, 0, 0);
|
|
mtk_icc_set_bw(qos_info->qos_path[IMGSYS_L12_COMMON_1].path, 0, 0);
|
|
}
|
|
#else
|
|
bw = 10240;
|
|
port_st = 0;
|
|
port_num = IMGSYS_M4U_PORT_MAX;
|
|
for (port_idx = port_st; port_idx < (port_num + port_st); port_idx++) {
|
|
if (IS_ERR_OR_NULL(qos_info->qos_path[port_idx].path)) {
|
|
dev_dbg(qos_info->dev, "[ERROR] [%s] path of idx(%d) is NULL\n",
|
|
__func__, port_idx);
|
|
continue;
|
|
}
|
|
if (qos_info->qos_path[port_idx].bw != bw) {
|
|
dev_dbg(qos_info->dev, "[%s] idx=%d, path=%p, bw=%d/%d,\n",
|
|
__func__, port_idx,
|
|
qos_info->qos_path[port_idx].path,
|
|
qos_info->qos_path[port_idx].bw, bw);
|
|
qos_info->qos_path[port_idx].bw = bw;
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[port_idx].path,
|
|
MBps_to_icc(qos_info->qos_path[port_idx].bw),
|
|
MBps_to_icc(qos_info->qos_path[port_idx].bw));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_set_by_scen(struct mtk_imgsys_dev *imgsys_dev,
|
|
struct swfrm_info_t *frm_info,
|
|
bool isSet)
|
|
{
|
|
struct mtk_imgsys_qos *qos_info = &imgsys_dev->qos_info;
|
|
struct mtk_imgsys_dvfs *dvfs_info = &imgsys_dev->dvfs_info;
|
|
u32 hw_comb = 0;
|
|
u64 pixel_sz = 0;
|
|
u32 fps = 0;
|
|
u32 frm_num = 0;
|
|
u64 bw_final[MTK_IMGSYS_QOS_GROUP] = {0};
|
|
|
|
frm_num = frm_info->total_frmnum;
|
|
hw_comb = frm_info->user_info[frm_num-1].hw_comb;
|
|
pixel_sz = frm_info->user_info[frm_num-1].pixel_bw;
|
|
fps = frm_info->fps;
|
|
|
|
if (is_stream_off == 0) {
|
|
if (isSet == 1) {
|
|
if (dvfs_info->vss_task_cnt != 0) {
|
|
bw_final[0] = IMGSYS_QOS_VSS_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_VSS_BW_1;
|
|
if (qos_info->bw_total[0][0] != bw_final[0]) {
|
|
dev_dbg(qos_info->dev,
|
|
"[%s] L9_0 idx=%d, path=%p, bw=%d/%d; L12_1 idx=%d, path=%p, bw=%d/%d,\n",
|
|
__func__,
|
|
IMGSYS_L9_COMMON_0,
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].bw,
|
|
bw_final[0],
|
|
IMGSYS_L12_COMMON_1,
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].bw,
|
|
bw_final[1]);
|
|
// Save for capture bw
|
|
qos_info->bw_total[0][0] = bw_final[0];
|
|
qos_info->bw_total[0][1] = bw_final[1];
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
MBps_to_icc(qos_info->qos_path[IMGSYS_L9_COMMON_0].bw),
|
|
MBps_to_icc(qos_info->bw_total[0][0]));
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
MBps_to_icc(qos_info->qos_path[IMGSYS_L12_COMMON_1].bw),
|
|
MBps_to_icc(qos_info->bw_total[0][1]));
|
|
}
|
|
} else if ((hw_comb & (IMGSYS_ENG_WPE_TNR | IMGSYS_ENG_DIP)) ==
|
|
(IMGSYS_ENG_WPE_TNR | IMGSYS_ENG_DIP)) {
|
|
if (fps == 30) {
|
|
if (pixel_sz > IMGSYS_QOS_4K_SIZE) {
|
|
bw_final[0] = IMGSYS_QOS_4K_30_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_4K_30_BW_1;
|
|
} else if (pixel_sz > IMGSYS_QOS_FHD_SIZE) {
|
|
bw_final[0] = IMGSYS_QOS_FHD_30_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_FHD_30_BW_1;
|
|
} else {
|
|
bw_final[0] = IMGSYS_QOS_FHD_30_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_FHD_30_BW_1;
|
|
}
|
|
} else if (fps == 60) {
|
|
if (pixel_sz > IMGSYS_QOS_4K_SIZE) {
|
|
bw_final[0] = IMGSYS_QOS_4K_60_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_4K_60_BW_1;
|
|
} else if (pixel_sz > IMGSYS_QOS_FHD_SIZE) {
|
|
bw_final[0] = IMGSYS_QOS_FHD_60_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_FHD_60_BW_1;
|
|
} else {
|
|
bw_final[0] = IMGSYS_QOS_FHD_60_BW_0;
|
|
bw_final[1] = IMGSYS_QOS_FHD_60_BW_1;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
bw_final[0] = (bw_final[0] * imgsys_qos_factor)/10;
|
|
bw_final[1] = (bw_final[1] * imgsys_qos_factor)/10;
|
|
if (qos_info->qos_path[IMGSYS_L9_COMMON_0].bw != bw_final[0]) {
|
|
dev_info(qos_info->dev,
|
|
"[%s] L9_0 idx=%d, path=%p, bw=%d/%d; L12_1 idx=%d, path=%p, bw=%d/%d,\n",
|
|
__func__,
|
|
IMGSYS_L9_COMMON_0,
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].bw,
|
|
bw_final[0],
|
|
IMGSYS_L12_COMMON_1,
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].bw,
|
|
bw_final[1]);
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].bw = bw_final[0];
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].bw = bw_final[1];
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
MBps_to_icc(qos_info->qos_path[IMGSYS_L9_COMMON_0].bw),
|
|
0);
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
MBps_to_icc(qos_info->qos_path[IMGSYS_L12_COMMON_1].bw),
|
|
0);
|
|
}
|
|
}
|
|
} else if (isSet == 0) {
|
|
if (dvfs_info->vss_task_cnt == 0) {
|
|
if (qos_info->bw_total[0][0] != 0) {
|
|
dev_dbg(qos_info->dev,
|
|
"[%s] L9_0 idx=%d, path=%p, bw=%d/%d; L12_1 idx=%d, path=%p, bw=%d/%d,\n",
|
|
__func__,
|
|
IMGSYS_L9_COMMON_0,
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].bw,
|
|
bw_final[0],
|
|
IMGSYS_L12_COMMON_1,
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].bw,
|
|
bw_final[1]);
|
|
// Clear for capture bw
|
|
qos_info->bw_total[0][0] = 0;
|
|
qos_info->bw_total[0][1] = 0;
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].path,
|
|
MBps_to_icc(qos_info->qos_path[IMGSYS_L9_COMMON_0].bw),
|
|
0);
|
|
mtk_icc_set_bw(
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].path,
|
|
MBps_to_icc(qos_info->qos_path[IMGSYS_L12_COMMON_1].bw),
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_reset(struct mtk_imgsys_dev *imgsys_dev)
|
|
{
|
|
u32 dvfs_idx = 0, qos_idx = 0;
|
|
struct mtk_imgsys_qos *qos_info = NULL;
|
|
|
|
qos_info = &imgsys_dev->qos_info;
|
|
|
|
qos_info->qos_path[IMGSYS_L9_COMMON_0].bw = 0;
|
|
qos_info->qos_path[IMGSYS_L12_COMMON_1].bw = 0;
|
|
mtk_icc_set_bw(qos_info->qos_path[IMGSYS_L9_COMMON_0].path, 0, 0);
|
|
mtk_icc_set_bw(qos_info->qos_path[IMGSYS_L12_COMMON_1].path, 0, 0);
|
|
|
|
for (dvfs_idx = 0; dvfs_idx < MTK_IMGSYS_DVFS_GROUP; dvfs_idx++) {
|
|
for (qos_idx = 0; qos_idx < MTK_IMGSYS_QOS_GROUP; qos_idx++)
|
|
qos_info->bw_total[dvfs_idx][qos_idx] = 0;
|
|
qos_info->ts_total[dvfs_idx] = 0;
|
|
}
|
|
qos_info->req_cnt = 0;
|
|
qos_info->isIdle = 0;
|
|
|
|
if (imgsys_qos_update_freq == 0)
|
|
imgsys_qos_update_freq = IMGSYS_QOS_UPDATE_FREQ;
|
|
if (imgsys_qos_blank_int == 0)
|
|
imgsys_qos_blank_int = IMGSYS_QOS_BLANK_INT;
|
|
if (imgsys_qos_factor == 0)
|
|
imgsys_qos_factor = IMGSYS_QOS_FACTOR;
|
|
|
|
}
|
|
|
|
void mtk_imgsys_mmdvfs_mmqos_cal(struct mtk_imgsys_dev *imgsys_dev,
|
|
struct swfrm_info_t *frm_info,
|
|
bool isSet)
|
|
{
|
|
struct mtk_imgsys_dvfs *dvfs_info = NULL;
|
|
struct mtk_imgsys_qos *qos_info = NULL;
|
|
unsigned long pixel_size[MTK_IMGSYS_DVFS_GROUP] = {0};
|
|
int frm_num = 0, frm_idx = 0, g_idx;
|
|
u32 hw_comb = 0;
|
|
u32 batch_num = 0;
|
|
u32 fps = 0;
|
|
u32 bw_exe = 0;
|
|
unsigned long freq = 0;
|
|
#if IMGSYS_DVFS_ENABLE
|
|
unsigned long pixel_max = 0, pixel_total_max = 0;
|
|
/* struct timeval curr_time; */
|
|
u64 ts_fps = 0;
|
|
#endif
|
|
#if IMGSYS_QOS_ENABLE
|
|
struct frame_bw_t *bw_buf = NULL;
|
|
void *smi_port = NULL;
|
|
u32 port_st = 0, port_num = 0, port_idx = 0;
|
|
#endif
|
|
|
|
dvfs_info = &imgsys_dev->dvfs_info;
|
|
qos_info = &imgsys_dev->qos_info;
|
|
frm_num = frm_info->total_frmnum;
|
|
batch_num = frm_info->batchnum;
|
|
fps = frm_info->fps;
|
|
/* fps = (batch_num)?(frm_info->fps*batch_num):frm_info->fps; */
|
|
bw_exe = fps;
|
|
hw_comb = frm_info->user_info[0].hw_comb;
|
|
|
|
/* Calculate DVFS*/
|
|
if (fps != 0) {
|
|
for (frm_idx = 0; frm_idx < frm_num; frm_idx++) {
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++) {
|
|
if (frm_info->user_info[frm_idx].hw_comb & dvfs_group[g_idx].g_hw)
|
|
pixel_size[g_idx] += frm_info->user_info[frm_idx].pixel_bw;
|
|
}
|
|
}
|
|
}
|
|
#if IMGSYS_DVFS_ENABLE
|
|
/* Check current time */
|
|
/* do_gettimeofday(&curr_time); */
|
|
/* ts_curr = curr_time.tv_sec * 1000000 + curr_time.tv_usec; */
|
|
/* ts_eq = frm_info->eqtime.tv_sec * 1000000 + frm_info->eqtime.tv_usec; */
|
|
/* ts_sw = ts_curr - ts_eq; */
|
|
if (fps != 0)
|
|
ts_fps = 1000000 / fps;
|
|
else
|
|
ts_fps = 0;
|
|
|
|
if (isSet == 1) {
|
|
if (fps != 0) {
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++) {
|
|
dvfs_info->pixel_size[g_idx] += (pixel_size[g_idx]*fps);
|
|
if (pixel_size[g_idx] > pixel_max)
|
|
pixel_max = pixel_size[g_idx];
|
|
if (dvfs_info->pixel_size[g_idx] > pixel_total_max)
|
|
pixel_total_max = dvfs_info->pixel_size[g_idx];
|
|
}
|
|
|
|
if (batch_num > 1) {
|
|
dvfs_info->smvr_task_cnt++;
|
|
if (pixel_total_max < IMGSYS_SMVR_FREQ_FLOOR)
|
|
freq = IMGSYS_SMVR_FREQ_FLOOR;
|
|
else
|
|
freq = pixel_total_max;
|
|
} else if (dvfs_info->smvr_task_cnt == 0)
|
|
freq = pixel_total_max;
|
|
|
|
if (dvfs_info->vss_task_cnt == 0)
|
|
dvfs_info->freq = freq;
|
|
} else {
|
|
dvfs_info->vss_task_cnt++;
|
|
freq = IMGSYS_VSS_FREQ_FLOOR; /* Forcing highest frequency if fps is 0 */
|
|
if (freq > dvfs_info->freq)
|
|
dvfs_info->freq = freq;
|
|
}
|
|
} else if (isSet == 0) {
|
|
if (fps != 0) {
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++) {
|
|
dvfs_info->pixel_size[g_idx] -= (pixel_size[g_idx]*fps);
|
|
if (pixel_size[g_idx] > pixel_max)
|
|
pixel_max = pixel_size[g_idx];
|
|
if (dvfs_info->pixel_size[g_idx] > pixel_total_max)
|
|
pixel_total_max = dvfs_info->pixel_size[g_idx];
|
|
}
|
|
|
|
if (batch_num > 1) {
|
|
dvfs_info->smvr_task_cnt--;
|
|
if (pixel_total_max < IMGSYS_SMVR_FREQ_FLOOR)
|
|
freq = IMGSYS_SMVR_FREQ_FLOOR;
|
|
else
|
|
freq = pixel_total_max;
|
|
} else if (dvfs_info->smvr_task_cnt == 0)
|
|
freq = pixel_total_max;
|
|
|
|
if (dvfs_info->vss_task_cnt == 0)
|
|
dvfs_info->freq = freq;
|
|
|
|
//if (pixel_total_max == 0) {
|
|
// freq = 0;
|
|
// dvfs_info->freq = freq;
|
|
//}
|
|
} else {
|
|
dvfs_info->vss_task_cnt--;
|
|
if (dvfs_info->vss_task_cnt == 0) {
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++)
|
|
if (dvfs_info->pixel_size[g_idx] > pixel_total_max)
|
|
pixel_total_max = dvfs_info->pixel_size[g_idx];
|
|
freq = pixel_total_max;
|
|
dvfs_info->freq = freq;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (imgsys_dvfs_dbg_enable())
|
|
dev_info(qos_info->dev,
|
|
"[%s] isSet(%d) fps(%d/%d) batchNum(%d) bw_exe(%d) vss(%d) smvr(%d) freq(%lld/%lld) local_pix_sz(%lld/%lld/%lld/%lld) global_pix_sz(%lld/%lld/%lld/%lld)\n",
|
|
__func__, isSet, fps, frm_info->fps, batch_num, bw_exe,
|
|
dvfs_info->vss_task_cnt, dvfs_info->smvr_task_cnt, freq, dvfs_info->freq,
|
|
pixel_size[0], pixel_size[1], pixel_size[2], pixel_max,
|
|
dvfs_info->pixel_size[0], dvfs_info->pixel_size[1],
|
|
dvfs_info->pixel_size[2], pixel_total_max
|
|
);
|
|
#else
|
|
if (isSet == 1) {
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++)
|
|
dvfs_info->pixel_size[0] += pixel_size[g_idx];
|
|
freq = 650000000;
|
|
dvfs_info->freq = freq;
|
|
} else if (isSet == 0) {
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++)
|
|
dvfs_info->pixel_size[0] -= pixel_size[g_idx];
|
|
if (dvfs_info->pixel_size[0] == 0) {
|
|
freq = 0;
|
|
dvfs_info->freq = freq;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Calculate QOS*/
|
|
#if IMGSYS_QOS_ENABLE
|
|
if ((isSet == 0) && (qos_info->isIdle == 0) && (is_stream_off == 0)) {
|
|
for (frm_idx = 0; frm_idx < frm_num; frm_idx++) {
|
|
hw_comb = frm_info->user_info[frm_idx].hw_comb;
|
|
bw_buf = (struct frame_bw_t *)frm_info->user_info[frm_idx].bw_swbuf;
|
|
//pixel_size += frm_info->user_info[frm_idx].pixel_bw;
|
|
if (hw_comb & IMGSYS_ENG_WPE_EIS) {
|
|
port_st = IMGSYS_M4U_PORT_WPE_EIS_START;
|
|
port_num = WPE_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->wpe_eis.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_WPE_TNR) {
|
|
port_st = IMGSYS_M4U_PORT_WPE_TNR_START;
|
|
port_num = WPE_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->wpe_tnr.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 1);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_WPE_LITE) {
|
|
port_st = IMGSYS_M4U_PORT_WPE_LITE_START;
|
|
port_num = WPE_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->wpe_lite.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_TRAW) {
|
|
port_st = IMGSYS_M4U_PORT_TRAW_START;
|
|
port_num = TRAW_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->traw.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_LTR) {
|
|
port_st = IMGSYS_M4U_PORT_LTRAW_START;
|
|
port_num = LTRAW_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->ltraw.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_XTR) {
|
|
port_st = IMGSYS_M4U_PORT_XTRAW_START;
|
|
port_num = XTRAW_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->xtraw.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_DIP) {
|
|
port_st = IMGSYS_M4U_PORT_DIP0_START;
|
|
port_num = DIP0_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->dip.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
port_st = IMGSYS_M4U_PORT_DIP1_START;
|
|
port_num = DIP1_SMI_PORT_NUM;
|
|
port_idx = IMGSYS_M4U_PORT_DIP1_START -
|
|
IMGSYS_M4U_PORT_DIP0_START;
|
|
smi_port =
|
|
(void *)(bw_buf->dip.smiport+port_idx);
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 1);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_PQDIP_A) {
|
|
port_st = IMGSYS_M4U_PORT_PQDIP_A_START;
|
|
port_num = PQ_DIP_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->pqdip_a.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 0);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_PQDIP_B) {
|
|
port_st = IMGSYS_M4U_PORT_PQDIP_B_START;
|
|
port_num = PQ_DIP_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->pqdip_b.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 1);
|
|
}
|
|
if (hw_comb & IMGSYS_ENG_ME) {
|
|
port_st = IMGSYS_M4U_PORT_ME_START;
|
|
port_num = ME_SMI_PORT_NUM;
|
|
smi_port = (void *)bw_buf->me.smiport;
|
|
mtk_imgsys_mmqos_bw_cal(imgsys_dev, smi_port, hw_comb,
|
|
port_st, port_num, 1);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_bw_cal(struct mtk_imgsys_dev *imgsys_dev,
|
|
void *smi_port, uint32_t hw_comb,
|
|
uint32_t port_st, uint32_t port_num, uint32_t port_id)
|
|
{
|
|
struct mtk_imgsys_qos *qos_info = NULL;
|
|
struct smi_port_t *smi = NULL;
|
|
uint32_t port_idx = 0, g_idx = 0;
|
|
|
|
qos_info = &imgsys_dev->qos_info;
|
|
smi = (struct smi_port_t *)smi_port;
|
|
for (port_idx = port_st; port_idx < (port_num + port_st); port_idx++)
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++)
|
|
if (hw_comb & dvfs_group[g_idx].g_hw)
|
|
qos_info->bw_total[g_idx][port_id] += smi[port_idx-port_st].portbw;
|
|
}
|
|
|
|
void mtk_imgsys_mmqos_ts_cal(struct mtk_imgsys_dev *imgsys_dev,
|
|
struct mtk_imgsys_cb_param *cb_param, uint32_t hw_comb)
|
|
{
|
|
struct mtk_imgsys_qos *qos_info = NULL;
|
|
uint32_t g_idx = 0;
|
|
u64 ts_hw = 0;
|
|
|
|
if (is_stream_off == 0) {
|
|
qos_info = &imgsys_dev->qos_info;
|
|
ts_hw = cb_param->cmdqTs.tsCmdqCbStart-cb_param->cmdqTs.tsFlushStart;
|
|
for (g_idx = 0; g_idx < MTK_IMGSYS_DVFS_GROUP; g_idx++)
|
|
if (hw_comb & dvfs_group[g_idx].g_hw)
|
|
qos_info->ts_total[g_idx] += ts_hw;
|
|
}
|
|
}
|
|
|
|
void mtk_imgsys_power_ctrl(struct mtk_imgsys_dev *imgsys_dev, bool isPowerOn)
|
|
{
|
|
struct mtk_imgsys_dvfs *dvfs_info = &imgsys_dev->dvfs_info;
|
|
u32 user_cnt = 0;
|
|
int i;
|
|
|
|
if (isPowerOn) {
|
|
user_cnt = atomic_inc_return(&imgsys_dev->imgsys_user_cnt);
|
|
if (user_cnt == 1) {
|
|
if (!imgsys_quick_onoff_enable())
|
|
dev_info(dvfs_info->dev,
|
|
"[%s] isPowerOn(%d) user(%d)\n",
|
|
__func__, isPowerOn, user_cnt);
|
|
|
|
mutex_lock(&(imgsys_dev->power_ctrl_lock));
|
|
|
|
pm_runtime_get_sync(imgsys_dev->dev);
|
|
|
|
/*set default value for hw module*/
|
|
mtk_imgsys_mod_get(imgsys_dev);
|
|
for (i = 0; i < (imgsys_dev->num_mods); i++)
|
|
if (imgsys_dev->modules[i].set)
|
|
imgsys_dev->modules[i].set(imgsys_dev);
|
|
mutex_unlock(&(imgsys_dev->power_ctrl_lock));
|
|
}
|
|
} else {
|
|
user_cnt = atomic_dec_return(&imgsys_dev->imgsys_user_cnt);
|
|
if (user_cnt == 0) {
|
|
if (!imgsys_quick_onoff_enable())
|
|
dev_info(dvfs_info->dev,
|
|
"[%s] isPowerOn(%d) user(%d)\n",
|
|
__func__, isPowerOn, user_cnt);
|
|
|
|
mutex_lock(&(imgsys_dev->power_ctrl_lock));
|
|
|
|
mtk_imgsys_mod_put(imgsys_dev);
|
|
pm_runtime_put_sync(imgsys_dev->dev);
|
|
//pm_runtime_mark_last_busy(imgsys_dev->dev);
|
|
//pm_runtime_put_autosuspend(imgsys_dev->dev);
|
|
|
|
mutex_unlock(&(imgsys_dev->power_ctrl_lock));
|
|
}
|
|
}
|
|
}
|
|
|
|
void mtk_imgsys_pwr(struct platform_device *pdev, bool on)
|
|
{
|
|
struct mtk_imgsys_dev *imgsys_dev;
|
|
|
|
imgsys_dev = platform_get_drvdata(pdev);
|
|
mtk_imgsys_power_ctrl(imgsys_dev, on);
|
|
}
|
|
EXPORT_SYMBOL(mtk_imgsys_pwr);
|
|
|
|
#endif
|
|
|
|
bool imgsys_cmdq_ts_enable(void)
|
|
{
|
|
return imgsys_cmdq_ts_en;
|
|
}
|
|
|
|
u32 imgsys_wpe_bwlog_enable(void)
|
|
{
|
|
return imgsys_wpe_bwlog_en;
|
|
}
|
|
|
|
bool imgsys_cmdq_ts_dbg_enable(void)
|
|
{
|
|
return imgsys_cmdq_ts_dbg_en;
|
|
}
|
|
|
|
bool imgsys_dvfs_dbg_enable(void)
|
|
{
|
|
return imgsys_dvfs_dbg_en;
|
|
}
|
|
|
|
bool imgsys_quick_onoff_enable(void)
|
|
{
|
|
return imgsys_quick_onoff_en;
|
|
}
|
|
|