blob: ded0429300ac2c459557b74d2d55e99b007e8e86 [file]
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/component.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <mtk_drm_ddp_comp.h>
#include "mtk-mml-color.h"
#include "mtk-mml-core.h"
#include "mtk-mml-driver.h"
#include "mtk-mml-dle-adaptor.h"
#include "mtk-mml-pq-core.h"
#include "tile_driver.h"
#include "mtk-mml-tile.h"
#include "tile_mdp_func.h"
#undef pr_fmt
#define pr_fmt(fmt) "[mml_pq_aal]" fmt
#define AAL_WAIT_TIMEOUT_MS (50)
#define AAL_POLL_SLEEP_TIME_US (10)
#define AAL_MAX_POLL_TIME_US (1000)
#define MAX_SRAM_BUF_NUM (2)
#define AAL_SRAM_STATUS_BIT BIT(17)
#define AAL_HIST_MAX_SUM (300)
/* min of label count for aal curve
* (AAL_CURVE_NUM * 7 / CMDQ_NUM_CMD(CMDQ_CMD_BUFFER_SIZE) + 1)
*/
#define AAL_LABEL_CNT 10
enum mml_aal_reg_index {
AAL_EN,
AAL_INTSTA,
AAL_STATUS,
AAL_CFG,
AAL_INPUT_COUNT,
AAL_OUTPUT_COUNT,
AAL_SIZE,
AAL_OUTPUT_SIZE,
AAL_OUTPUT_OFFSET,
AAL_SRAM_STATUS,
AAL_SRAM_RW_IF_0,
AAL_SRAM_RW_IF_1,
AAL_SRAM_RW_IF_2,
AAL_SRAM_RW_IF_3,
AAL_SHADOW_CTRL,
AAL_TILE_02,
AAL_DRE_BLOCK_INFO_07,
AAL_CFG_MAIN,
AAL_WIN_X_MAIN,
AAL_WIN_Y_MAIN,
AAL_DRE_BLOCK_INFO_00,
AAL_TILE_00,
AAL_TILE_01,
AAL_DUAL_PIPE_00,
AAL_DUAL_PIPE_01,
AAL_DUAL_PIPE_02,
AAL_DUAL_PIPE_03,
AAL_DUAL_PIPE_04,
AAL_DUAL_PIPE_05,
AAL_DUAL_PIPE_06,
AAL_DUAL_PIPE_07,
AAL_DRE_ROI_00,
AAL_DRE_ROI_01,
AAL_DUAL_PIPE_08,
AAL_DUAL_PIPE_09,
AAL_DUAL_PIPE_10,
AAL_DUAL_PIPE_11,
AAL_DUAL_PIPE_12,
AAL_DUAL_PIPE_13,
AAL_DUAL_PIPE_14,
AAL_DUAL_PIPE_15,
AAL_REG_MAX_COUNT
};
static const u16 aal_reg_table_mt6983[AAL_REG_MAX_COUNT] = {
[AAL_EN] = 0x000,
[AAL_INTSTA] = 0x00c,
[AAL_STATUS] = 0x010,
[AAL_CFG] = 0x020,
[AAL_INPUT_COUNT] = 0x024,
[AAL_OUTPUT_COUNT] = 0x028,
[AAL_SIZE] = 0x030,
[AAL_OUTPUT_SIZE] = 0x034,
[AAL_OUTPUT_OFFSET] = 0x038,
[AAL_SRAM_STATUS] = 0x0c8,
[AAL_SRAM_RW_IF_0] = 0x0cc,
[AAL_SRAM_RW_IF_1] = 0x0d0,
[AAL_SRAM_RW_IF_2] = 0x0d4,
[AAL_SRAM_RW_IF_3] = 0x0d8,
[AAL_SHADOW_CTRL] = 0x0f0,
[AAL_TILE_02] = 0x0f4,
[AAL_DRE_BLOCK_INFO_07] = 0x0f8,
[AAL_CFG_MAIN] = 0x200,
[AAL_WIN_X_MAIN] = 0x460,
[AAL_WIN_Y_MAIN] = 0x464,
[AAL_DRE_BLOCK_INFO_00] = 0x468,
[AAL_TILE_00] = 0x4ec,
[AAL_TILE_01] = 0x4f0,
[AAL_DUAL_PIPE_00] = 0x500,
[AAL_DUAL_PIPE_01] = 0x504,
[AAL_DUAL_PIPE_02] = 0x508,
[AAL_DUAL_PIPE_03] = 0x50c,
[AAL_DUAL_PIPE_04] = 0x510,
[AAL_DUAL_PIPE_05] = 0x514,
[AAL_DUAL_PIPE_06] = 0x518,
[AAL_DUAL_PIPE_07] = 0x51c,
[AAL_DRE_ROI_00] = 0x520,
[AAL_DRE_ROI_01] = 0x524,
[AAL_DUAL_PIPE_08] = 0x544,
[AAL_DUAL_PIPE_09] = 0x548,
[AAL_DUAL_PIPE_10] = 0x54c,
[AAL_DUAL_PIPE_11] = 0x550,
[AAL_DUAL_PIPE_12] = 0x554,
[AAL_DUAL_PIPE_13] = 0x558,
[AAL_DUAL_PIPE_14] = 0x55c,
[AAL_DUAL_PIPE_15] = 0x560
};
struct aal_data {
u32 min_tile_width;
u32 tile_width;
u32 min_hist_width;
bool vcp_readback;
u16 gpr[MML_PIPE_CNT];
u16 cpr[MML_PIPE_CNT];
const u16 *reg_table;
bool crop;
};
static const struct aal_data mt6893_aal_data = {
.min_tile_width = 50,
.tile_width = 560,
.min_hist_width = 128,
.vcp_readback = false,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = true,
};
static const struct aal_data mt6983_aal_data = {
.min_tile_width = 50,
.tile_width = 1652,
.min_hist_width = 128,
.vcp_readback = false,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = true,
};
static const struct aal_data mt6879_aal_data = {
.min_tile_width = 50,
.tile_width = 1376,
.min_hist_width = 128,
.vcp_readback = false,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = true,
};
static const struct aal_data mt6895_aal0_data = {
.min_tile_width = 50,
.tile_width = 1300,
.min_hist_width = 128,
.vcp_readback = true,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = true,
};
static const struct aal_data mt6895_aal1_data = {
.min_tile_width = 50,
.tile_width = 852,
.min_hist_width = 128,
.vcp_readback = true,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = true,
};
static const struct aal_data mt6985_aal_data = {
.min_tile_width = 50,
.tile_width = 1690,
.min_hist_width = 128,
.vcp_readback = false,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = false,
};
static const struct aal_data mt6886_aal_data = {
.min_tile_width = 50,
.tile_width = 1300,
.min_hist_width = 128,
.vcp_readback = false,
.gpr = {CMDQ_GPR_R08, CMDQ_GPR_R10},
.cpr = {CMDQ_CPR_MML_PQ0_ADDR, CMDQ_CPR_MML_PQ1_ADDR},
.reg_table = aal_reg_table_mt6983,
.crop = true,
};
struct mml_comp_aal {
struct mtk_ddp_comp ddp_comp;
struct mml_comp comp;
const struct aal_data *data;
bool ddp_bound;
u32 sram_curve_start;
u32 sram_hist_start;
};
enum aal_label_index {
AAL_REUSE_LABEL = 0,
AAL_POLLGPR_0 = AAL_LABEL_CNT,
AAL_POLLGPR_1,
AAL_LABEL_TOTAL
};
/* meta data for each different frame config */
struct aal_frame_data {
u32 out_hist_xs;
u32 dre_blk_width;
u32 dre_blk_height;
u32 begin_offset;
u32 condi_offset;
u32 cut_pos_x;
struct cmdq_poll_reuse polling_reuse;
u16 labels[AAL_LABEL_TOTAL];
struct mml_reuse_array reuse_curve;
struct mml_reuse_offset offs_curve[AAL_LABEL_CNT];
bool is_aal_need_readback;
bool config_success;
};
static inline struct aal_frame_data *aal_frm_data(struct mml_comp_config *ccfg)
{
return ccfg->data;
}
static inline struct mml_comp_aal *comp_to_aal(struct mml_comp *comp)
{
return container_of(comp, struct mml_comp_aal, comp);
}
static s32 aal_prepare(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct aal_frame_data *aal_frm;
aal_frm = kzalloc(sizeof(*aal_frm), GFP_KERNEL);
ccfg->data = aal_frm;
aal_frm->reuse_curve.offs = aal_frm->offs_curve;
aal_frm->reuse_curve.offs_size = ARRAY_SIZE(aal_frm->offs_curve);
return 0;
}
static s32 aal_buf_prepare(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct mml_frame_config *cfg = task->config;
struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
s32 ret = 0;
mml_pq_trace_ex_begin("%s", __func__);
mml_pq_msg("%s engine_id[%d] en_dre[%d]", __func__, comp->id,
dest->pq_config.en_dre);
if (dest->pq_config.en_dre)
ret = mml_pq_set_comp_config(task);
mml_pq_trace_ex_end();
return ret;
}
static s32 aal_tile_prepare(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg,
struct tile_func_block *func,
union mml_tile_data *data)
{
struct mml_frame_config *cfg = task->config;
struct mml_frame_data *src = &cfg->info.src;
struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
struct mml_comp_aal *aal = comp_to_aal(comp);
mml_pq_trace_ex_begin("%s", __func__);
func->in_tile_width = aal->data->tile_width;
func->out_tile_width = aal->data->tile_width;
func->for_func = tile_aal_for;
func->in_tile_height = 65535;
func->out_tile_height = 65535;
if (aal->data->crop) {
func->l_tile_loss = 8;
func->r_tile_loss = 8;
} else {
func->l_tile_loss = 0;
func->r_tile_loss = 0;
}
func->enable_flag = dest->pq_config.en_dre;
if ((cfg->info.dest_cnt == 1 ||
!memcmp(&cfg->info.dest[0].crop,
&cfg->info.dest[1].crop,
sizeof(struct mml_crop))) &&
(dest->crop.r.width != src->width ||
dest->crop.r.height != src->height)) {
u32 in_crop_w, in_crop_h;
in_crop_w = dest->crop.r.width;
in_crop_h = dest->crop.r.height;
if (in_crop_w + dest->crop.r.left > src->width)
in_crop_w = src->width - dest->crop.r.left;
if (in_crop_h + dest->crop.r.top > src->height)
in_crop_h = src->height - dest->crop.r.top;
func->full_size_x_in = in_crop_w;
func->full_size_y_in = in_crop_h;
} else {
func->full_size_x_in = src->width;
func->full_size_y_in = src->height;
}
func->full_size_x_out = func->full_size_x_in;
func->full_size_y_out = func->full_size_y_in;
func->in_min_width = max(min(aal->data->min_hist_width,
(u32)func->full_size_x_in),
aal->data->min_tile_width);
mml_pq_msg("%s engine_id[%d]", __func__, comp->id);
mml_pq_trace_ex_end();
return 0;
}
static const struct mml_comp_tile_ops aal_tile_ops = {
.prepare = aal_tile_prepare,
};
static u32 aal_get_label_count(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct mml_frame_config *cfg = task->config;
struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
mml_pq_msg("%s engine_id[%d] en_dre[%d]", __func__, comp->id,
dest->pq_config.en_dre);
if (!dest->pq_config.en_dre)
return 0;
return AAL_LABEL_TOTAL;
}
static void aal_init(struct mml_comp *comp, struct cmdq_pkt *pkt, const phys_addr_t base_pa)
{
struct mml_comp_aal *aal = comp_to_aal(comp);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_EN], 0x1, U32_MAX);
/* Enable shadow */
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_SHADOW_CTRL], 0x2, U32_MAX);
}
static void aal_relay(struct mml_comp *comp, struct cmdq_pkt *pkt, const phys_addr_t base_pa,
u32 relay)
{
struct mml_comp_aal *aal = comp_to_aal(comp);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_CFG], relay, 0x00000001);
}
static s32 aal_config_init(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
aal_init(comp, task->pkts[ccfg->pipe], comp->base_pa);
return 0;
}
static struct mml_pq_comp_config_result *get_aal_comp_config_result(
struct mml_task *task)
{
return task->pq_task->comp_config.result;
}
static s32 aal_config_frame(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct mml_comp_aal *aal = comp_to_aal(comp);
struct mml_frame_config *cfg = task->config;
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
struct mml_frame_data *src = &cfg->info.src;
const struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
const phys_addr_t base_pa = comp->base_pa;
struct mml_pq_comp_config_result *result;
struct mml_pq_reg *regs;
u32 *curve;
struct mml_pq_aal_config_param *tile_config_param;
struct mml_task_reuse *reuse = &task->reuse[ccfg->pipe];
struct mml_pipe_cache *cache = &cfg->cache[ccfg->pipe];
u32 addr = aal->sram_curve_start;
u32 gpr = aal->data->gpr[ccfg->pipe];
u32 cpr = aal->data->cpr[ccfg->pipe];
s32 ret = 0;
u32 i;
mml_pq_trace_ex_begin("%s", __func__);
mml_pq_msg("%s engine_id[%d] en_dre[%d]", __func__, comp->id, dest->pq_config.en_dre);
if (!dest->pq_config.en_dre || dest->crop.r.width < aal->data->min_tile_width) {
/* relay mode */
aal_relay(comp, pkt, base_pa, 0x1);
goto exit;
}
aal_relay(comp, pkt, base_pa, 0x0);
mml_pq_msg("%s sram_start_addr[%d] cmdq_cpr[%d]", __func__, addr, cpr);
if (MML_FMT_10BIT(src->format) || MML_FMT_10BIT(dest->data.format))
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_CFG_MAIN],
0, 0x00000080);
else
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_CFG_MAIN],
1 << 7, 0x00000080);
do {
ret = mml_pq_get_comp_config_result(task, AAL_WAIT_TIMEOUT_MS);
if (ret) {
mml_pq_comp_config_clear(task);
aal_frm->config_success = false;
mml_pq_err("get aal param timeout: %d in %dms",
ret, AAL_WAIT_TIMEOUT_MS);
ret = -ETIMEDOUT;
goto exit;
}
result = get_aal_comp_config_result(task);
if (!result) {
mml_pq_err("%s: not get result from user lib", __func__);
ret = -EBUSY;
goto exit;
}
} while ((mml_pq_debug_mode & MML_PQ_SET_TEST) && result->is_set_test);
regs = result->aal_regs;
curve = result->aal_curve;
/* TODO: use different regs */
mml_pq_msg("%s:config aal regs, count: %d", __func__, result->aal_reg_cnt);
aal_frm->config_success = true;
for (i = 0; i < result->aal_reg_cnt; i++) {
cmdq_pkt_write(pkt, NULL, base_pa + regs[i].offset,
regs[i].value, regs[i].mask);
mml_pq_msg("[aal][config][%x] = %#x mask(%#x)",
regs[i].offset, regs[i].value, regs[i].mask);
}
for (i = 0; i < AAL_CURVE_NUM; i++, addr += 4) {
cmdq_pkt_write(pkt, NULL,
base_pa + aal->data->reg_table[AAL_SRAM_RW_IF_0], addr, U32_MAX);
cmdq_pkt_poll(pkt, NULL, (0x1 << 16),
base_pa + aal->data->reg_table[AAL_SRAM_STATUS], (0x1 << 16), gpr);
mml_write_array(pkt, base_pa + aal->data->reg_table[AAL_SRAM_RW_IF_1], curve[i],
U32_MAX, reuse, cache, &aal_frm->reuse_curve);
}
mml_pq_msg("%s is_aal_need_readback[%d] base_pa[%llx] reuses[%u]",
__func__, result->is_aal_need_readback, base_pa,
aal_frm->reuse_curve.idx);
aal_frm->is_aal_need_readback = result->is_aal_need_readback;
aal_frm->config_success = true;
tile_config_param = &(result->aal_param[ccfg->node->out_idx]);
aal_frm->dre_blk_width = tile_config_param->dre_blk_width;
aal_frm->dre_blk_height = tile_config_param->dre_blk_height;
mml_pq_msg("%s: success dre_blk_width[%d], dre_blk_height[%d]",
__func__, tile_config_param->dre_blk_width,
tile_config_param->dre_blk_height);
exit:
mml_pq_trace_ex_end();
return ret;
}
static s32 aal_config_tile(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg, u32 idx)
{
struct mml_frame_config *cfg = task->config;
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
const phys_addr_t base_pa = comp->base_pa;
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
struct mml_comp_aal *aal = comp_to_aal(comp);
struct mml_tile_engine *tile = config_get_tile(cfg, ccfg, idx);
u32 src_frame_width = cfg->info.src.width;
u32 src_frame_height = cfg->info.src.height;
u16 tile_cnt = cfg->tile_output[ccfg->pipe]->tile_cnt;
u32 aal_input_w;
u32 aal_input_h;
u32 aal_output_w;
u32 aal_output_h;
u32 aal_crop_x_offset;
u32 aal_crop_y_offset;
u32 dre_blk_width = 0;
u32 dre_blk_height = 0;
u32 act_win_x_start = 0, act_win_x_end = 0;
u32 act_win_y_start = 0, act_win_y_end = 0;
u32 win_x_start = 0, win_x_end = 0;
u32 blk_num_x_start = 0, blk_num_x_end = 0;
u32 blk_num_y_start = 0, blk_num_y_end = 0;
u32 blk_cnt_x_start = 0, blk_cnt_x_end = 0;
u32 blk_cnt_y_start = 0, blk_cnt_y_end = 0;
u32 roi_x_start = 0, roi_x_end = 0;
u32 roi_y_start = 0, roi_y_end = 0;
u32 win_y_start = 0, win_y_end = 0;
u32 aal_hist_left_start = 0;
u32 tile_pxl_x_start = 0, tile_pxl_x_end = 0;
u32 tile_pxl_y_start = 0, tile_pxl_y_end = 0;
u32 last_tile_x_flag = 0, last_tile_y_flag = 0;
u32 save_first_blk_col_flag = 0;
u32 save_last_blk_col_flag = 0;
s32 ret = 0;
mml_pq_trace_ex_begin("%s", __func__);
aal_input_w = tile->in.xe - tile->in.xs + 1;
aal_input_h = tile->in.ye - tile->in.ys + 1;
aal_output_w = tile->out.xe - tile->out.xs + 1;
aal_output_h = tile->out.ye - tile->out.ys + 1;
aal_crop_x_offset = tile->out.xs - tile->in.xs;
aal_crop_y_offset = tile->out.ys - tile->in.ys;
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_SIZE],
(aal_input_w << 16) + aal_input_h, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_OUTPUT_OFFSET],
(aal_crop_x_offset << 16) + aal_crop_y_offset, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_OUTPUT_SIZE],
(aal_output_w << 16) + aal_output_h, U32_MAX);
if (!dest->pq_config.en_dre)
goto exit;
if (!idx) {
if (task->config->dual)
aal_frm->cut_pos_x = dest->crop.r.width / 2;
else
aal_frm->cut_pos_x = dest->crop.r.width;
if (ccfg->pipe)
aal_frm->out_hist_xs = aal_frm->cut_pos_x;
}
dre_blk_width = aal_frm->dre_blk_width;
dre_blk_height = aal_frm->dre_blk_height;
aal_hist_left_start =
(tile->out.xs > aal_frm->out_hist_xs) ? tile->out.xs : aal_frm->out_hist_xs;
mml_pq_msg("%s jobid[%d] engine_id[%d] idx[%d] pipe[%d] pkt[%08x]",
__func__, task->job.jobid, comp->id, idx, ccfg->pipe, pkt);
mml_pq_msg("%s %d: %d: %d: [input] [xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, tile->in.xs,
tile->in.xe, tile->in.ys,
tile->in.ye);
mml_pq_msg("%s %d: %d: %d: [output] [xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx,
tile->out.xs, tile->out.xe, tile->out.ys,
tile->out.ye);
mml_pq_msg("%s %d: %d: %d: [aal_crop_offset] [x, y] = [%d, %d], aal_hist_left_start[%d]",
__func__, task->job.jobid, comp->id, idx,
aal_crop_x_offset, aal_crop_y_offset,
aal_hist_left_start);
act_win_x_start = aal_hist_left_start - tile->in.xs;
if (task->config->dual && !ccfg->pipe && (idx + 1 >= tile_cnt))
act_win_x_end = aal_frm->cut_pos_x - tile->in.xs - 1;
else
act_win_x_end = tile->out.xe - tile->in.xs;
tile_pxl_x_start = tile->in.xs;
tile_pxl_x_end = tile->in.xe;
last_tile_x_flag = (tile->in.xe+1 >= src_frame_width) ? 1:0;
mml_pq_msg("%s %d: %d: %d: [tile_pxl] [xs, xe] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, tile_pxl_x_start, tile_pxl_x_end);
act_win_y_start = 0;
act_win_y_end = tile->in.ye - tile->in.ys;
tile_pxl_y_start = 0;
tile_pxl_y_end = tile->in.ye - tile->in.ys;
last_tile_y_flag = (tile_pxl_y_end+1 >= src_frame_height) ? 1:0;
roi_x_start = 0;
roi_x_end = tile->in.xe - tile->in.xs;
roi_y_start = 0;
roi_y_end = tile->in.ye - tile->in.ys;
blk_num_x_start = (tile_pxl_x_start / dre_blk_width);
blk_num_x_end = (tile_pxl_x_end / dre_blk_width);
blk_cnt_x_start = tile_pxl_x_start - (blk_num_x_start * dre_blk_width);
blk_cnt_x_end = tile_pxl_x_end - (blk_num_x_end * dre_blk_width);
blk_num_y_start = (tile_pxl_y_start / dre_blk_height);
blk_num_y_end = (tile_pxl_y_end / dre_blk_height);
blk_cnt_y_start = tile_pxl_y_start - (blk_num_y_start * dre_blk_height);
blk_cnt_y_end = tile_pxl_y_end - (blk_num_y_end * dre_blk_height);
if (!idx) {
if (task->config->dual && ccfg->pipe)
aal_frm->out_hist_xs = tile->in.xs + act_win_x_end + 1;
else
aal_frm->out_hist_xs = tile->out.xe + 1;
save_first_blk_col_flag = (ccfg->pipe) ? 1 : 0;
if (idx + 1 >= tile_cnt)
save_last_blk_col_flag = (ccfg->pipe) ? 0 : 1;
else
save_last_blk_col_flag = 0;
} else if (idx + 1 >= tile_cnt) {
aal_frm->out_hist_xs = 0;
save_first_blk_col_flag = 0;
save_last_blk_col_flag = (ccfg->pipe) ? 0 : 1;
} else {
if (task->config->dual && ccfg->pipe)
aal_frm->out_hist_xs = tile->in.xs + act_win_x_end + 1;
else
aal_frm->out_hist_xs = tile->out.xe + 1;
save_first_blk_col_flag = 0;
save_last_blk_col_flag = 0;
}
win_x_start = 0;
win_x_end = tile_pxl_x_end - tile_pxl_x_start + 1;
win_y_start = 0;
win_y_end = tile_pxl_y_end - tile_pxl_y_start + 1;
mml_pq_msg("%s %d: %d: %d:[act_win][xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, act_win_x_start, act_win_x_end,
act_win_y_start, act_win_y_end);
mml_pq_msg("%s %d: %d: %d:[blk_num][xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, blk_num_x_start, blk_num_x_end,
blk_num_y_start, blk_num_y_end);
mml_pq_msg("%s %d: %d: %d:[blk_cnt][xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, blk_cnt_x_start, blk_cnt_x_end,
blk_cnt_y_start, blk_cnt_y_end);
mml_pq_msg("%s %d: %d: %d:[roi][xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, roi_x_start,
roi_x_end, roi_y_start, roi_y_end);
mml_pq_msg("%s %d: %d: %d:[win][xs, xe] = [%d, %d], [ys, ye] = [%d, %d]",
__func__, task->job.jobid, comp->id, idx, win_x_start,
win_x_end, win_y_start, win_y_end);
mml_pq_msg("%s %d: %d: %d:save_first_blk_col_flag[%d], save_last_blk_col_flag[%d]",
__func__, task->job.jobid, comp->id, idx,
save_first_blk_col_flag,
save_last_blk_col_flag);
mml_pq_msg("%s %d: %d: %d:last_tile_x_flag[%d], last_tile_y_flag[%d]",
__func__, task->job.jobid, comp->id, idx,
last_tile_x_flag, last_tile_y_flag);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_DRE_BLOCK_INFO_00],
(act_win_x_end << 16) | act_win_x_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_DRE_BLOCK_INFO_07],
(act_win_y_end << 16) | act_win_y_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_TILE_00],
(save_first_blk_col_flag << 23) | (save_last_blk_col_flag << 22) |
(last_tile_x_flag << 21) | (last_tile_y_flag << 20) |
(blk_num_x_end << 15) | (blk_num_x_start << 10) |
(blk_num_y_end << 5) | blk_num_y_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_TILE_01],
(blk_cnt_x_end << 16) | blk_cnt_x_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_TILE_02],
(blk_cnt_y_end << 16) | blk_cnt_y_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_DRE_ROI_00],
(roi_x_end << 16) | roi_x_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_DRE_ROI_01],
(roi_y_end << 16) | roi_y_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_WIN_X_MAIN],
(win_x_end << 16) | win_x_start, U32_MAX);
cmdq_pkt_write(pkt, NULL, base_pa + aal->data->reg_table[AAL_WIN_Y_MAIN],
(win_y_end << 16) | win_y_start, U32_MAX);
exit:
mml_pq_trace_ex_end();
return ret;
}
static void aal_readback_cmdq(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct mml_comp_aal *aal = comp_to_aal(comp);
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
struct mml_frame_config *cfg = task->config;
struct mml_task_reuse *reuse = &task->reuse[ccfg->pipe];
struct mml_pipe_cache *cache = &cfg->cache[ccfg->pipe];
const phys_addr_t base_pa = comp->base_pa;
u32 addr = aal->sram_hist_start;
u32 dre30_hist_sram_start = aal->sram_hist_start;
s32 i = 0;
u8 pipe = ccfg->pipe;
dma_addr_t begin_pa = 0;
u32 *condi_inst = NULL;
dma_addr_t pa = 0;
struct cmdq_operand lop, rop;
const u16 idx_addr = CMDQ_THR_SPR_IDX1;
const u16 idx_val = CMDQ_THR_SPR_IDX2;
const u16 poll_gpr = aal->data->gpr[ccfg->pipe];
const u16 idx_out = aal->data->cpr[ccfg->pipe];
const u16 idx_out64 = CMDQ_CPR_TO_CPR64(idx_out);
mml_pq_msg("%s start engine_id[%d] addr[%d]", __func__, comp->id, addr);
mml_pq_get_readback_buffer(task, pipe, &(task->pq_task->aal_hist[pipe]));
if (unlikely(!task->pq_task->aal_hist[pipe])) {
mml_pq_err("%s job_id[%d] aal_hist is null", __func__,
task->job.jobid);
return;
}
pa = task->pq_task->aal_hist[pipe]->pa;
/* init sprs
* spr1 = AAL_SRAM_START
* cpr64 = out_pa
*/
cmdq_pkt_assign_command(pkt, idx_addr, dre30_hist_sram_start);
mml_assign(pkt, idx_out, (u32)pa,
reuse, cache, &aal_frm->labels[AAL_POLLGPR_0]);
mml_assign(pkt, idx_out + 1, (u32)(pa >> 32),
reuse, cache, &aal_frm->labels[AAL_POLLGPR_1]);
/* loop again here */
aal_frm->begin_offset = pkt->cmd_buf_size;
begin_pa = cmdq_pkt_get_pa_by_offset(pkt, aal_frm->begin_offset);
/* config aal sram addr and poll */
cmdq_pkt_write_reg_addr(pkt, base_pa + aal->data->reg_table[AAL_SRAM_RW_IF_2],
idx_addr, U32_MAX);
/* use gpr low as poll gpr */
cmdq_pkt_poll_addr(pkt, AAL_SRAM_STATUS_BIT,
base_pa + aal->data->reg_table[AAL_SRAM_STATUS],
AAL_SRAM_STATUS_BIT, poll_gpr);
/* read to value spr */
cmdq_pkt_read_addr(pkt, base_pa + aal->data->reg_table[AAL_SRAM_RW_IF_3], idx_val);
/* write value spr to dst cpr64 */
cmdq_pkt_write_reg_indriect(pkt, idx_out64, idx_val, U32_MAX);
/* jump forward end if sram is last one, if spr1 >= 4096 + 4 * 767 */
cmdq_pkt_assign_command(pkt, CMDQ_THR_SPR_IDX0, begin_pa);
aal_frm->condi_offset = pkt->cmd_buf_size - CMDQ_INST_SIZE;
/* inc src addr */
lop.reg = true;
lop.idx = idx_addr;
rop.reg = false;
rop.value = 4;
cmdq_pkt_logic_command(pkt, CMDQ_LOGIC_ADD, idx_addr, &lop, &rop);
/* inc outut pa */
lop.reg = true;
lop.idx = idx_out;
rop.reg = false;
rop.value = 4;
cmdq_pkt_logic_command(pkt, CMDQ_LOGIC_ADD, idx_out, &lop, &rop);
lop.reg = true;
lop.idx = idx_addr;
rop.reg = false;
rop.value = dre30_hist_sram_start + 4 * (AAL_HIST_NUM - 1);
cmdq_pkt_cond_jump_abs(pkt, CMDQ_THR_SPR_IDX0, &lop, &rop,
CMDQ_LESS_THAN_AND_EQUAL);
condi_inst = (u32 *)cmdq_pkt_get_va_by_offset(pkt, aal_frm->condi_offset);
if (unlikely(!condi_inst))
mml_pq_err("%s wrong offset %u\n", __func__, aal_frm->condi_offset);
*condi_inst = (u32)CMDQ_REG_SHIFT_ADDR(begin_pa);
for (i = 0; i < 8; i++) {
cmdq_pkt_read_addr(pkt, base_pa + aal->data->reg_table[AAL_DUAL_PIPE_00] + i * 4,
idx_val);
cmdq_pkt_write_reg_indriect(pkt, idx_out64, idx_val, U32_MAX);
lop.reg = true;
lop.idx = idx_out;
rop.reg = false;
rop.value = 4;
cmdq_pkt_logic_command(pkt, CMDQ_LOGIC_ADD, idx_out, &lop, &rop);
}
for (i = 0; i < 8; i++) {
cmdq_pkt_read_addr(pkt, base_pa + aal->data->reg_table[AAL_DUAL_PIPE_08] + i * 4,
idx_val);
cmdq_pkt_write_reg_indriect(pkt, idx_out64, idx_val, U32_MAX);
lop.reg = true;
lop.idx = idx_out;
rop.reg = false;
rop.value = 4;
cmdq_pkt_logic_command(pkt, CMDQ_LOGIC_ADD, idx_out, &lop, &rop);
}
mml_pq_rb_msg("%s end job_id[%d] engine_id[%d] va[%p] pa[%llx] pkt[%p]",
__func__, task->job.jobid, comp->id, task->pq_task->aal_hist[pipe]->va,
task->pq_task->aal_hist[pipe]->pa, pkt);
mml_pq_rb_msg("%s end job_id[%d] condi:offset[%u] inst[%p], begin:offset[%u] pa[%llx]",
__func__, task->job.jobid, aal_frm->condi_offset, condi_inst,
aal_frm->begin_offset, begin_pa);
}
static void aal_readback_vcp(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
struct mml_comp_aal *aal = comp_to_aal(comp);
struct mml_task_reuse *reuse = &task->reuse[ccfg->pipe];
u8 pipe = ccfg->pipe;
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
u32 gpr = aal->data->gpr[ccfg->pipe];
u32 engine = CMDQ_VCP_ENG_MML_AAL0 + pipe;
mml_pq_rb_msg("%s aal_hist[%p] pipe[%d]", __func__,
task->pq_task->aal_hist[pipe], pipe);
if (!(task->pq_task->aal_hist[pipe])) {
task->pq_task->aal_hist[pipe] =
kzalloc(sizeof(struct mml_pq_readback_buffer), GFP_KERNEL);
if (unlikely(!task->pq_task->aal_hist[pipe])) {
mml_pq_err("%s not enough mem for aal_hist", __func__);
return;
}
task->pq_task->aal_hist[pipe]->va =
cmdq_get_vcp_buf(engine, &(task->pq_task->aal_hist[pipe]->pa));
}
mml_pq_get_vcp_buf_offset(task, MML_PQ_AAL0+pipe, task->pq_task->aal_hist[pipe]);
cmdq_vcp_enable(true);
cmdq_pkt_readback(pkt, engine, task->pq_task->aal_hist[pipe]->va_offset,
AAL_HIST_NUM+AAL_DUAL_INFO_NUM, gpr,
&reuse->labels[reuse->label_idx],
&aal_frm->polling_reuse);
add_reuse_label(reuse, &aal_frm->labels[AAL_POLLGPR_0],
task->pq_task->aal_hist[pipe]->va_offset);
mml_pq_rb_msg("%s end job_id[%d] engine_id[%d] va[%p] pa[%llx] pkt[%p] offset[%d]",
__func__, task->job.jobid, comp->id, task->pq_task->aal_hist[pipe]->va,
task->pq_task->aal_hist[pipe]->pa, pkt,
task->pq_task->aal_hist[pipe]->va_offset);
}
static s32 aal_config_post(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct mml_frame_dest *dest = &task->config->info.dest[ccfg->node->out_idx];
struct mml_comp_aal *aal = comp_to_aal(comp);
bool vcp = aal->data->vcp_readback;
mml_pq_msg("%s start engine_id[%d] en_dre[%d]", __func__, comp->id,
dest->pq_config.en_dre);
if (!dest->pq_config.en_dre)
goto exit;
if (vcp)
aal_readback_vcp(comp, task, ccfg);
else
aal_readback_cmdq(comp, task, ccfg);
mml_pq_put_comp_config_result(task);
exit:
return 0;
}
static s32 aal_reconfig_frame(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
struct mml_frame_config *cfg = task->config;
struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
struct mml_task_reuse *reuse = &task->reuse[ccfg->pipe];
struct mml_pq_comp_config_result *result;
u32 *curve, i, j, idx;
s32 ret = 0;
mml_pq_trace_ex_begin("%s", __func__);
mml_pq_msg("%s engine_id[%d] en_dre[%d] config_success[%d]", __func__, comp->id,
dest->pq_config.en_dre, aal_frm->config_success);
if (!dest->pq_config.en_dre)
goto exit;
do {
ret = mml_pq_get_comp_config_result(task, AAL_WAIT_TIMEOUT_MS);
if (ret) {
mml_pq_comp_config_clear(task);
mml_pq_err("get aal param timeout: %d in %dms",
ret, AAL_WAIT_TIMEOUT_MS);
ret = -ETIMEDOUT;
goto exit;
}
result = get_aal_comp_config_result(task);
if (!result || !aal_frm->config_success) {
mml_pq_err("%s: not get result from user lib", __func__);
ret = -EBUSY;
goto exit;
}
} while ((mml_pq_debug_mode & MML_PQ_SET_TEST) && result->is_set_test);
curve = result->aal_curve;
idx = 0;
for (i = 0; i < aal_frm->reuse_curve.idx; i++)
for (j = 0; j < aal_frm->reuse_curve.offs[i].cnt; j++, idx++)
mml_update_array(reuse, &aal_frm->reuse_curve, i, j, curve[idx]);
mml_pq_msg("%s is_aal_need_readback[%d]",
__func__, result->is_aal_need_readback);
aal_frm->is_aal_need_readback = result->is_aal_need_readback;
exit:
mml_pq_trace_ex_end();
return ret;
}
static s32 aal_config_repost(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
struct mml_frame_dest *dest = &task->config->info.dest[ccfg->node->out_idx];
struct mml_task_reuse *reuse = &task->reuse[ccfg->pipe];
u8 pipe = ccfg->pipe;
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
dma_addr_t begin_pa = 0;
u32 *condi_inst = NULL;
struct mml_comp_aal *aal = comp_to_aal(comp);
bool vcp = aal->data->vcp_readback;
u32 engine = CMDQ_VCP_ENG_MML_AAL0 + pipe;
mml_pq_msg("%s engine_id[%d] en_dre[%d]", __func__, comp->id,
dest->pq_config.en_dre);
if (!dest->pq_config.en_dre)
goto exit;
if (vcp) {
if (!(task->pq_task->aal_hist[pipe])) {
task->pq_task->aal_hist[pipe] =
kzalloc(sizeof(struct mml_pq_readback_buffer), GFP_KERNEL);
if (unlikely(!task->pq_task->aal_hist[pipe])) {
mml_pq_err("%s not enough mem for aal_hist", __func__);
goto comp_config_put;
}
mml_pq_rb_msg("%s aal_hist[%p] pipe[%d]", __func__,
task->pq_task->aal_hist[pipe], pipe);
task->pq_task->aal_hist[pipe]->va =
cmdq_get_vcp_buf(engine, &(task->pq_task->aal_hist[pipe]->pa));
}
cmdq_vcp_enable(true);
mml_pq_get_vcp_buf_offset(task, MML_PQ_AAL0+pipe,
task->pq_task->aal_hist[pipe]);
mml_update(reuse, aal_frm->labels[AAL_POLLGPR_0],
cmdq_pkt_vcp_reuse_val(engine,
task->pq_task->aal_hist[pipe]->va_offset,
AAL_HIST_NUM + AAL_DUAL_INFO_NUM));
cmdq_pkt_reuse_poll(pkt, &aal_frm->polling_reuse);
mml_pq_rb_msg("%s end job_id[%d] engine_id[%d] va[%p] pa[%llx] pkt[%p] offset[%d]",
__func__, task->job.jobid, comp->id, task->pq_task->aal_hist[pipe]->va,
task->pq_task->aal_hist[pipe]->pa, pkt,
task->pq_task->aal_hist[pipe]->va_offset);
} else {
mml_pq_get_readback_buffer(task, pipe, &(task->pq_task->aal_hist[pipe]));
if (unlikely(!task->pq_task->aal_hist[pipe])) {
mml_pq_err("%s job_id[%d] aal_hist is null", __func__,
task->job.jobid);
goto comp_config_put;
}
mml_update(reuse, aal_frm->labels[AAL_POLLGPR_0],
(u32)task->pq_task->aal_hist[pipe]->pa);
mml_update(reuse, aal_frm->labels[AAL_POLLGPR_1],
(u32)(task->pq_task->aal_hist[pipe]->pa >> 32));
begin_pa = cmdq_pkt_get_pa_by_offset(pkt, aal_frm->begin_offset);
condi_inst = (u32 *)cmdq_pkt_get_va_by_offset(pkt, aal_frm->condi_offset);
if (unlikely(!condi_inst))
mml_pq_err("%s wrong offset %u\n", __func__, aal_frm->condi_offset);
*condi_inst = (u32)CMDQ_REG_SHIFT_ADDR(begin_pa);
mml_pq_rb_msg("%s end job_id[%d] engine_id[%d] va[%p] pa[%llx] pkt[%p]",
__func__, task->job.jobid, comp->id, task->pq_task->aal_hist[pipe]->va,
task->pq_task->aal_hist[pipe]->pa, pkt);
mml_pq_rb_msg("%s end job_id[%d]condi:offset[%u]inst[%p],begin:offset[%u]pa[%llx]",
__func__, task->job.jobid, aal_frm->condi_offset, condi_inst,
aal_frm->begin_offset, begin_pa);
}
comp_config_put:
mml_pq_put_comp_config_result(task);
exit:
return 0;
}
static const struct mml_comp_config_ops aal_cfg_ops = {
.prepare = aal_prepare,
.buf_prepare = aal_buf_prepare,
.get_label_count = aal_get_label_count,
.init = aal_config_init,
.frame = aal_config_frame,
.tile = aal_config_tile,
.post = aal_config_post,
.reframe = aal_reconfig_frame,
.repost = aal_config_repost,
};
static inline bool aal_reg_poll(struct mml_comp *comp, u32 addr, u32 value, u32 mask)
{
bool return_value = false;
u32 reg_value = 0;
u32 polling_time = 0;
void __iomem *base = comp->base;
do {
reg_value = readl(base + addr);
if ((reg_value & mask) == value) {
return_value = true;
break;
}
udelay(AAL_POLL_SLEEP_TIME_US);
polling_time += AAL_POLL_SLEEP_TIME_US;
} while (polling_time < AAL_MAX_POLL_TIME_US);
return return_value;
}
static bool get_dre_block(u32 *phist, const int block_x, const int block_y,
const int dre_blk_x_num)
{
u32 read_value;
u32 block_offset = 6 * (block_y * dre_blk_x_num + block_x);
u32 sum = 0, i = 0;
u32 aal_hist[AAL_HIST_BIN] = {0};
u32 error_sum = AAL_HIST_MAX_SUM;
if (block_x < 0 || block_y < 0) {
mml_pq_err("Error block num block_y = %d, block_x = %d", block_y, block_x);
return false;
}
do {
if (block_offset >= AAL_HIST_NUM)
break;
read_value = phist[block_offset++];
aal_hist[0] = read_value & 0xff;
aal_hist[1] = (read_value>>8) & 0xff;
aal_hist[2] = (read_value>>16) & 0xff;
aal_hist[3] = (read_value>>24) & 0xff;
if (block_offset >= AAL_HIST_NUM)
break;
read_value = phist[block_offset++];
aal_hist[4] = read_value & 0xff;
aal_hist[5] = (read_value>>8) & 0xff;
aal_hist[6] = (read_value>>16) & 0xff;
aal_hist[7] = (read_value>>24) & 0xff;
if (block_offset >= AAL_HIST_NUM)
break;
read_value = phist[block_offset++];
aal_hist[8] = read_value & 0xff;
aal_hist[9] = (read_value>>8) & 0xff;
aal_hist[10] = (read_value>>16) & 0xff;
aal_hist[11] = (read_value>>24) & 0xff;
if (block_offset >= AAL_HIST_NUM)
break;
read_value = phist[block_offset++];
aal_hist[12] = read_value & 0xff;
aal_hist[13] = (read_value>>8) & 0xff;
aal_hist[14] = (read_value>>16) & 0xff;
aal_hist[15] = (read_value>>24) & 0xff;
if (block_offset >= AAL_HIST_NUM)
break;
read_value = phist[block_offset++];
aal_hist[16] = read_value & 0xff;
} while (0);
for (i = 0; i < AAL_HIST_BIN; i++)
sum += aal_hist[i];
if (sum >= error_sum) {
mml_pq_err("hist[0-8] = (%d %d %d %d %d %d %d %d %d)",
aal_hist[0], aal_hist[1], aal_hist[2], aal_hist[3],
aal_hist[4], aal_hist[5], aal_hist[6], aal_hist[7],
aal_hist[8]);
mml_pq_err("hist[9-16] = (%d %d %d %d %d %d %d %d)",
aal_hist[9], aal_hist[10], aal_hist[11], aal_hist[12],
aal_hist[13], aal_hist[14], aal_hist[15], aal_hist[16]);
return false;
} else
return true;
}
static bool aal_hist_check(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg, u32 *phist)
{
u32 blk_x = 0, blk_y = 0;
u8 pipe = (ccfg) ? ccfg->pipe : 0;
bool dual = (task) ? task->config->dual : false;
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
u32 crop_width = task->config->info.dest[ccfg->node->out_idx].crop.r.width;
u32 crop_height = task->config->info.dest[ccfg->node->out_idx].crop.r.height;
u32 cut_pos_x = aal_frm->cut_pos_x;
u32 dre_blk_width = aal_frm->dre_blk_width;
u32 dre_blk_height = aal_frm->dre_blk_height;
u32 blk_x_start = 0;
u32 dre_blk_y_num = 0, dre_blk_x_num = 0;
if (dual) {
if (pipe == 1)
dre_blk_x_num = (crop_width - cut_pos_x) / dre_blk_width;
if (!pipe)
dre_blk_x_num = cut_pos_x / dre_blk_width;
blk_x_start = cut_pos_x / dre_blk_width + 1;
} else {
dre_blk_x_num = crop_width / dre_blk_width;
blk_x_start = 0;
}
dre_blk_y_num = crop_height / dre_blk_height;
mml_pq_msg("%s pipe[%d] crop_width[%u] crop_height[%u] cut_pos_x[%u]",
__func__, pipe, crop_width, crop_height, cut_pos_x);
mml_pq_msg("%s dre_blk_x_num[%u] dre_blk_y_num[%u] blk_x_start[%u]",
__func__, dre_blk_x_num, dre_blk_y_num, blk_x_start);
for (blk_y = 0; blk_y < dre_blk_y_num; blk_y++)
for (blk_x = blk_x_start; blk_x < dre_blk_x_num; blk_x++)
if (!get_dre_block(phist, blk_x, blk_y, dre_blk_x_num))
return false;
return true;
}
static void aal_task_done_readback(struct mml_comp *comp, struct mml_task *task,
struct mml_comp_config *ccfg)
{
struct mml_frame_config *cfg = task->config;
struct aal_frame_data *aal_frm = aal_frm_data(ccfg);
struct mml_frame_dest *dest = &cfg->info.dest[ccfg->node->out_idx];
struct mml_comp_aal *aal = comp_to_aal(comp);
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
u8 pipe = ccfg->pipe;
bool vcp = aal->data->vcp_readback;
u32 engine = MML_PQ_AAL0 + pipe;
u32 offset = 0;
mml_pq_trace_ex_begin("%s", __func__);
mml_pq_msg("%s is_aal_need_readback[%d] id[%d] en_dre[%d]", __func__,
aal_frm->is_aal_need_readback, comp->id, dest->pq_config.en_dre);
mml_pq_msg("%s job_id[%d] pkt %p size %zu", __func__, task->job.jobid,
pkt, pkt->cmd_buf_size);
if (!dest->pq_config.en_dre || !task->pq_task->aal_hist[pipe])
goto exit;
offset = vcp ? task->pq_task->aal_hist[pipe]->va_offset : 0;
mml_pq_rb_msg("%s job_id[%d] id[%d] pipe[%d] en_dre[%d] va[%p] pa[%llx] offset[%d]",
__func__, task->job.jobid, comp->id, ccfg->pipe,
dest->pq_config.en_dre, task->pq_task->aal_hist[pipe]->va,
task->pq_task->aal_hist[pipe]->pa,
task->pq_task->aal_hist[pipe]->va_offset);
if (!pipe) {
mml_pq_rb_msg("%s job_id[%d] hist[0~4]={%08x, %08x, %08x, %08x, %08x}",
__func__, task->job.jobid,
task->pq_task->aal_hist[pipe]->va[offset/4+0],
task->pq_task->aal_hist[pipe]->va[offset/4+1],
task->pq_task->aal_hist[pipe]->va[offset/4+2],
task->pq_task->aal_hist[pipe]->va[offset/4+3],
task->pq_task->aal_hist[pipe]->va[offset/4+4]);
mml_pq_rb_msg("%s job_id[%d] hist[10~14]={%08x, %08x, %08x, %08x, %08}",
__func__, task->job.jobid,
task->pq_task->aal_hist[pipe]->va[offset/4+10],
task->pq_task->aal_hist[pipe]->va[offset/4+11],
task->pq_task->aal_hist[pipe]->va[offset/4+12],
task->pq_task->aal_hist[pipe]->va[offset/4+13],
task->pq_task->aal_hist[pipe]->va[offset/4+14]);
} else {
mml_pq_rb_msg("%s job_id[%d] hist[600~604]={%08x, %08x, %08x, %08x, %08x",
__func__, task->job.jobid,
task->pq_task->aal_hist[pipe]->va[offset/4+600],
task->pq_task->aal_hist[pipe]->va[offset/4+601],
task->pq_task->aal_hist[pipe]->va[offset/4+602],
task->pq_task->aal_hist[pipe]->va[offset/4+603],
task->pq_task->aal_hist[pipe]->va[offset/4+604]);
mml_pq_rb_msg("%s job_id[%d] hist[610~614]={%08x, %08x, %08x, %08x, %08x",
__func__, task->job.jobid,
task->pq_task->aal_hist[pipe]->va[offset/4+610],
task->pq_task->aal_hist[pipe]->va[offset/4+611],
task->pq_task->aal_hist[pipe]->va[offset/4+612],
task->pq_task->aal_hist[pipe]->va[offset/4+613],
task->pq_task->aal_hist[pipe]->va[offset/4+614]);
}
/*remain code for ping-pong in the feature*/
if (!dest->pq_config.en_dre) {
u32 addr = aal->sram_hist_start;
void __iomem *base = comp->base;
s32 i;
s32 dual_info_start = AAL_HIST_NUM;
u32 poll_intsta_addr = aal->data->reg_table[AAL_INTSTA];
u32 poll_sram_status_addr = aal->data->reg_table[AAL_SRAM_STATUS];
u32 *phist = kmalloc((AAL_HIST_NUM+AAL_DUAL_INFO_NUM)*sizeof(u32),
GFP_KERNEL);
for (i = 0; i < AAL_HIST_NUM; i++) {
if (aal_reg_poll(comp, poll_intsta_addr, (0x1 << 1), (0x1 << 1))) {
do {
writel(addr,
base + aal->data->reg_table[AAL_SRAM_RW_IF_2]);
if (aal_reg_poll(comp, poll_sram_status_addr,
(0x1 << 17), (0x1 << 17)) != true) {
mml_pq_log("%s idx[%d]", __func__, i);
break;
}
phist[i] = readl(base +
aal->data->reg_table[AAL_SRAM_RW_IF_3]);
} while (0);
addr = addr + 4;
}
}
if (task->config->dual) {
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_00]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_01]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_02]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_03]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_04]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_05]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_06]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_07]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_08]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_09]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_10]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_11]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_12]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_13]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_14]);
phist[dual_info_start++] =
readl(base + aal->data->reg_table[AAL_DUAL_PIPE_15]);
}
mml_pq_aal_readback(task, ccfg->pipe, phist);
}
if (aal_frm->is_aal_need_readback) {
mml_pq_aal_readback(task, ccfg->pipe,
&(task->pq_task->aal_hist[pipe]->va[offset/4]));
if (mml_pq_debug_mode & MML_PQ_HIST_CHECK) {
if (!aal_hist_check(comp, task, ccfg,
&(task->pq_task->aal_hist[pipe]->va[offset / 4]))) {
mml_pq_err("%s hist error", __func__);
mml_pq_util_aee("MML_PQ_AAL_Histogram Error",
"AAL Histogram error need to check jobid:%d",
task->job.jobid);
}
}
}
if (vcp) {
mml_pq_put_vcp_buf_offset(task, engine, task->pq_task->aal_hist[pipe]);
cmdq_vcp_enable(false);
} else
mml_pq_put_readback_buffer(task, pipe, task->pq_task->aal_hist[pipe]);
exit:
mml_pq_trace_ex_end();
}
static const struct mml_comp_hw_ops aal_hw_ops = {
.clk_enable = &mml_comp_clk_enable,
.clk_disable = &mml_comp_clk_disable,
.task_done = aal_task_done_readback,
};
static void aal_debug_dump(struct mml_comp *comp)
{
struct mml_comp_aal *aal = comp_to_aal(comp);
void __iomem *base = comp->base;
u32 value[9];
u32 shadow_ctrl;
mml_err("aal component %u dump:", comp->id);
/* Enable shadow read working */
shadow_ctrl = readl(base + aal->data->reg_table[AAL_SHADOW_CTRL]);
shadow_ctrl |= 0x4;
writel(shadow_ctrl, base + aal->data->reg_table[AAL_SHADOW_CTRL]);
value[0] = readl(base + aal->data->reg_table[AAL_INTSTA]);
value[1] = readl(base + aal->data->reg_table[AAL_STATUS]);
value[2] = readl(base + aal->data->reg_table[AAL_INPUT_COUNT]);
value[3] = readl(base + aal->data->reg_table[AAL_OUTPUT_COUNT]);
value[4] = readl(base + aal->data->reg_table[AAL_SIZE]);
value[5] = readl(base + aal->data->reg_table[AAL_OUTPUT_SIZE]);
value[6] = readl(base + aal->data->reg_table[AAL_OUTPUT_OFFSET]);
value[7] = readl(base + aal->data->reg_table[AAL_TILE_00]);
value[8] = readl(base + aal->data->reg_table[AAL_TILE_01]);
mml_err("AAL_INTSTA %#010x AAL_STATUS %#010x AAL_INPUT_COUNT %#010x AAL_OUTPUT_COUNT %#010x",
value[0], value[1], value[2], value[3]);
mml_err("AAL_SIZE %#010x AAL_OUTPUT_SIZE %#010x AAL_OUTPUT_OFFSET %#010x",
value[4], value[5], value[6]);
mml_err("AAL_TILE_00 %#010x AAL_TILE_01 %#010x",
value[7], value[8]);
}
static const struct mml_comp_debug_ops aal_debug_ops = {
.dump = &aal_debug_dump,
};
static int mml_bind(struct device *dev, struct device *master, void *data)
{
struct mml_comp_aal *aal = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
s32 ret;
if (!drm_dev) {
ret = mml_register_comp(master, &aal->comp);
if (ret)
dev_err(dev, "Failed to register mml component %s: %d\n",
dev->of_node->full_name, ret);
} else {
ret = mml_ddp_comp_register(drm_dev, &aal->ddp_comp);
if (ret)
dev_err(dev, "Failed to register ddp component %s: %d\n",
dev->of_node->full_name, ret);
else
aal->ddp_bound = true;
}
return ret;
}
static void mml_unbind(struct device *dev, struct device *master, void *data)
{
struct mml_comp_aal *aal = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
if (!drm_dev) {
mml_unregister_comp(master, &aal->comp);
} else {
mml_ddp_comp_unregister(drm_dev, &aal->ddp_comp);
aal->ddp_bound = false;
}
}
static const struct component_ops mml_comp_ops = {
.bind = mml_bind,
.unbind = mml_unbind,
};
static const struct mtk_ddp_comp_funcs ddp_comp_funcs = {
};
static struct mml_comp_aal *dbg_probed_components[4];
static int dbg_probed_count;
static int probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mml_comp_aal *priv;
s32 ret;
bool add_ddp = true;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->data = of_device_get_match_data(dev);
ret = mml_comp_init(pdev, &priv->comp);
if (ret) {
dev_err(dev, "Failed to init mml component: %d\n", ret);
return ret;
}
if (of_property_read_u32(dev->of_node, "sram-curve-base", &priv->sram_curve_start))
dev_err(dev, "read curve base fail\n");
if (of_property_read_u32(dev->of_node, "sram-his-base", &priv->sram_hist_start))
dev_err(dev, "read his base fail\n");
/* assign ops */
priv->comp.tile_ops = &aal_tile_ops;
priv->comp.config_ops = &aal_cfg_ops;
priv->comp.hw_ops = &aal_hw_ops;
priv->comp.debug_ops = &aal_debug_ops;
ret = mml_ddp_comp_init(dev, &priv->ddp_comp, &priv->comp,
&ddp_comp_funcs);
if (ret) {
mml_log("failed to init ddp component: %d", ret);
add_ddp = false;
}
dbg_probed_components[dbg_probed_count++] = priv;
ret = component_add(dev, &mml_comp_ops);
if (add_ddp)
ret = component_add(dev, &mml_comp_ops);
if (ret)
dev_err(dev, "Failed to add component: %d\n", ret);
return ret;
}
static int remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &mml_comp_ops);
component_del(&pdev->dev, &mml_comp_ops);
return 0;
}
const struct of_device_id mml_aal_driver_dt_match[] = {
{
.compatible = "mediatek,mt6983-mml_aal",
.data = &mt6983_aal_data,
},
{
.compatible = "mediatek,mt6893-mml_aal",
.data = &mt6893_aal_data
},
{
.compatible = "mediatek,mt6879-mml_aal",
.data = &mt6879_aal_data
},
{
.compatible = "mediatek,mt6895-mml_aal0",
.data = &mt6895_aal0_data
},
{
.compatible = "mediatek,mt6895-mml_aal1",
.data = &mt6895_aal1_data
},
{
.compatible = "mediatek,mt6985-mml_aal",
.data = &mt6985_aal_data
},
{
.compatible = "mediatek,mt6886-mml_aal",
.data = &mt6886_aal_data
},
{},
};
MODULE_DEVICE_TABLE(of, mml_aal_driver_dt_match);
struct platform_driver mml_aal_driver = {
.probe = probe,
.remove = remove,
.driver = {
.name = "mediatek-mml-aal",
.owner = THIS_MODULE,
.of_match_table = mml_aal_driver_dt_match,
},
};
//module_platform_driver(mml_aal_driver);
static s32 dbg_case;
static s32 dbg_set(const char *val, const struct kernel_param *kp)
{
s32 result;
result = kstrtos32(val, 0, &dbg_case);
mml_log("%s: debug_case=%d", __func__, dbg_case);
switch (dbg_case) {
case 0:
mml_log("use read to dump component status");
break;
default:
mml_err("invalid debug_case: %d", dbg_case);
break;
}
return result;
}
static s32 dbg_get(char *buf, const struct kernel_param *kp)
{
s32 length = 0;
u32 i;
switch (dbg_case) {
case 0:
length += snprintf(buf + length, PAGE_SIZE - length,
"[%d] probed count: %d\n", dbg_case, dbg_probed_count);
for (i = 0; i < dbg_probed_count; i++) {
struct mml_comp *comp = &dbg_probed_components[i]->comp;
length += snprintf(buf + length, PAGE_SIZE - length,
" - [%d] mml comp_id: %d.%d @%llx name: %s bound: %d\n", i,
comp->id, comp->sub_idx, comp->base_pa,
comp->name ? comp->name : "(null)", comp->bound);
length += snprintf(buf + length, PAGE_SIZE - length,
" - larb_port: %d @%llx pw: %d clk: %d\n",
comp->larb_port, comp->larb_base,
comp->pw_cnt, comp->clk_cnt);
length += snprintf(buf + length, PAGE_SIZE - length,
" - ddp comp_id: %d bound: %d\n",
dbg_probed_components[i]->ddp_comp.id,
dbg_probed_components[i]->ddp_bound);
}
break;
default:
mml_err("not support read for debug_case: %d", dbg_case);
break;
}
buf[length] = '\0';
return length;
}
static const struct kernel_param_ops dbg_param_ops = {
.set = dbg_set,
.get = dbg_get,
};
module_param_cb(aal_debug, &dbg_param_ops, NULL, 0644);
MODULE_PARM_DESC(aal_debug, "mml aal debug case");
MODULE_AUTHOR("Dennis-YC Hsieh <dennis-yc.hsieh@mediatek.com>");
MODULE_DESCRIPTION("MediaTek SoC display MML AAL driver");
MODULE_LICENSE("GPL v2");