mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2025-09-26 19:04:54 +00:00
2388 lines
68 KiB
C
2388 lines
68 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2021 MediaTek Inc.
|
|
* Author: Dennis YC Hsieh <dennis-yc.hsieh@mediatek.com>
|
|
*/
|
|
|
|
#include <linux/component.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/math64.h>
|
|
#include <soc/mediatek/smi.h>
|
|
|
|
#include "mtk-mml-buf.h"
|
|
#include "mtk-mml-color.h"
|
|
#include "mtk-mml-core.h"
|
|
#include "mtk-mml-driver.h"
|
|
#include "mtk-mml-dle-adaptor.h"
|
|
|
|
#include "tile_driver.h"
|
|
#include "mtk-mml-tile.h"
|
|
#include "tile_mdp_func.h"
|
|
#include "mtk-mml-sys.h"
|
|
#include "mtk-mml-mmp.h"
|
|
|
|
#ifdef CONFIG_MTK_SMI_EXT
|
|
#include "smi_public.h"
|
|
#endif
|
|
|
|
/* WROT register offset */
|
|
#define VIDO_CTRL 0x000
|
|
#define VIDO_DMA_PERF 0x004
|
|
#define VIDO_MAIN_BUF_SIZE 0x008
|
|
#define VIDO_SOFT_RST 0x010
|
|
#define VIDO_SOFT_RST_STAT 0x014
|
|
#define VIDO_INT_EN 0x018
|
|
#define VIDO_INT 0x01c
|
|
#define VIDO_CROP_OFST 0x020
|
|
#define VIDO_TAR_SIZE 0x024
|
|
#define VIDO_FRAME_SIZE 0x028
|
|
#define VIDO_OFST_ADDR 0x02c
|
|
#define VIDO_STRIDE 0x030
|
|
#define VIDO_BKGD 0x034
|
|
#define VIDO_OFST_ADDR_C 0x038
|
|
#define VIDO_STRIDE_C 0x03c
|
|
#define VIDO_ISSUE_REQ_TH 0x040
|
|
#define VIDO_GROUP_REQ_TH 0x044
|
|
#define VIDO_CTRL_2 0x048
|
|
#define VIDO_IN_LINE_ROT 0x050
|
|
#define VIDO_DITHER 0x054
|
|
#define VIDO_DITHER_CON 0x058
|
|
#define VIDO_OFST_ADDR_V 0x068
|
|
#define VIDO_STRIDE_V 0x06c
|
|
#define VIDO_EOL_SEL 0x070
|
|
#define VIDO_DMA_PREULTRA 0x074
|
|
#define VIDO_IN_SIZE 0x078
|
|
#define VIDO_ROT_EN 0x07c
|
|
#define VIDO_FIFO_TEST 0x080
|
|
#define VIDO_MAT_CTRL 0x084
|
|
#define VIDO_CG_NEW_CTRL 0x088
|
|
#define VIDO_SHADOW_CTRL 0x08c
|
|
#define VIDO_DEBUG 0x0d0
|
|
#define VIDO_ARB_SW_CTL 0x0d4
|
|
#define VIDO_PVRIC 0x0d8
|
|
#define VIDO_SCAN_10BIT 0x0dc
|
|
#define VIDO_PENDING_ZERO 0x0e0
|
|
#define VIDO_PVRIC_SETTING 0x0e4
|
|
#define VIDO_CRC_CTRL 0x0e8
|
|
#define VIDO_CRC_VALUE 0x0ec
|
|
#define VIDO_COMPRESSION_VALUE 0x0f0
|
|
#define VIDO_BASE_ADDR 0xf00
|
|
#define VIDO_BASE_ADDR_C 0xf04
|
|
#define VIDO_BASE_ADDR_V 0xf08
|
|
#define VIDO_PVRIC_FMT 0xf0c
|
|
#define VIDO_FBC_FBDC_CR_CH0123_VAL0 0xf10
|
|
#define VIDO_FBC_FBDC_CR_CH0123_VAL1 0xf14
|
|
#define VIDO_FBC_FBDC_CR_Y_VAL0 0xf18
|
|
#define VIDO_FBC_FBDC_CR_UV_VAL0 0xf1c
|
|
#define VIDO_FBC_FBDC_CR_Y_VAL1 0xf20
|
|
#define VIDO_FBC_FBDC_CR_UV_VAL1 0xf24
|
|
#define VIDO_AFBC_VERSION 0xf28
|
|
#define VIDO_AFBC_YUVTRANS 0xf2c
|
|
#define VIDO_BUS_CTRL 0xf30
|
|
#define VIDO_BASE_ADDR_HIGH 0xf34
|
|
#define VIDO_BASE_ADDR_HIGH_C 0xf38
|
|
#define VIDO_BASE_ADDR_HIGH_V 0xf3c
|
|
#define VIDO_OFST_ADDR_HIGH 0xf40
|
|
#define VIDO_OFST_ADDR_HIGH_C 0xf44
|
|
#define VIDO_OFST_ADDR_HIGH_V 0xf48
|
|
|
|
#define WROT_MIN_BUF_LINE_NUM 16
|
|
|
|
/* register mask */
|
|
#define VIDO_INT_MASK 0x00000007
|
|
|
|
/* Inline rot offsets */
|
|
#define DISPSYS_SHADOW_CTRL 0x010
|
|
#define INLINEROT_OVLSEL 0x030
|
|
#define INLINEROT_HEIGHT0 0x034
|
|
#define INLINEROT_HEIGHT1 0x038
|
|
#define INLINEROT_WDONE 0x03C
|
|
|
|
/* SMI offset */
|
|
#define SMI_LARB_NON_SEC_CON 0x380
|
|
|
|
#define MML_WROT_RACING_MIN 64
|
|
|
|
/* debug option to change sram write height */
|
|
int mml_racing_h = MML_WROT_RACING_MIN;
|
|
module_param(mml_racing_h, int, 0644);
|
|
|
|
int mml_racing_rdone;
|
|
module_param(mml_racing_rdone, int, 0644);
|
|
|
|
/* ceil_m and floor_m helper function */
|
|
static u32 ceil_m(u64 n, u64 d)
|
|
{
|
|
u32 reminder = do_div((n),(d));
|
|
|
|
return n + (reminder != 0);
|
|
}
|
|
|
|
static u32 floor_m(u64 n, u64 d)
|
|
{
|
|
do_div(n, d);
|
|
return n;
|
|
}
|
|
|
|
enum wrot_label {
|
|
WROT_LABEL_ADDR = 0,
|
|
WROT_LABEL_ADDR_HIGH,
|
|
WROT_LABEL_ADDR_C,
|
|
WROT_LABEL_ADDR_HIGH_C,
|
|
WROT_LABEL_ADDR_V,
|
|
WROT_LABEL_ADDR_HIGH_V,
|
|
WROT_LABEL_TOTAL
|
|
};
|
|
|
|
static s32 wrot_write_ofst(struct cmdq_pkt *pkt,
|
|
dma_addr_t addr, dma_addr_t addr_high, u64 value)
|
|
{
|
|
s32 ret;
|
|
|
|
ret = cmdq_pkt_write(pkt, NULL, addr, value & GENMASK_ULL(31, 0), U32_MAX);
|
|
if (ret)
|
|
return ret;
|
|
ret = cmdq_pkt_write(pkt, NULL, addr_high, value >> 32, U32_MAX);
|
|
return ret;
|
|
}
|
|
|
|
static s32 wrot_write_addr(struct cmdq_pkt *pkt,
|
|
dma_addr_t addr, dma_addr_t addr_high, u64 value,
|
|
struct mml_task_reuse *reuse,
|
|
struct mml_pipe_cache *cache,
|
|
u16 *label_idx)
|
|
{
|
|
s32 ret;
|
|
|
|
ret = mml_write(pkt, addr, value & GENMASK_ULL(31, 0), U32_MAX,
|
|
reuse, cache, label_idx);
|
|
if (ret)
|
|
return ret;
|
|
ret = mml_write(pkt, addr_high, value >> 32, U32_MAX,
|
|
reuse, cache, label_idx + 1);
|
|
return ret;
|
|
}
|
|
|
|
static void wrot_update_addr(struct mml_task_reuse *reuse,
|
|
u16 label, u16 label_high, u64 value)
|
|
{
|
|
mml_update(reuse, label, value & GENMASK_ULL(31, 0));
|
|
mml_update(reuse, label_high, value >> 32);
|
|
}
|
|
|
|
struct wrot_data {
|
|
u32 fifo;
|
|
u32 tile_width;
|
|
u32 sram_size;
|
|
u8 rb_swap; /* version for rb channel swap behavior */
|
|
};
|
|
|
|
static const struct wrot_data mml_wrot_data = {
|
|
.fifo = 256,
|
|
.tile_width = 512,
|
|
.sram_size = 512 * 1024,
|
|
.rb_swap = 1,
|
|
};
|
|
|
|
struct mml_comp_wrot {
|
|
struct mtk_ddp_comp ddp_comp;
|
|
struct mml_comp comp;
|
|
const struct wrot_data *data;
|
|
bool ddp_bound;
|
|
|
|
u16 event_eof; /* wrot frame done */
|
|
u16 event_bufa; /* notify pipe0 that pipe1 ready buf a */
|
|
u16 event_bufb; /* notify pipe0 that pipe1 ready buf b */
|
|
u16 event_buf_next; /* notify pipe1 that pipe0 ready new round */
|
|
int idx;
|
|
|
|
struct device *dev; /* for dmabuf to iova */
|
|
/* smi register to config sram/dram mode */
|
|
phys_addr_t smi_larb_con;
|
|
/* inline rotate base addr */
|
|
phys_addr_t irot_base[MML_PIPE_CNT];
|
|
void __iomem *irot_va[MML_PIPE_CNT];
|
|
|
|
u32 sram_size;
|
|
u32 sram_cnt;
|
|
u64 sram_pa;
|
|
struct mutex sram_mutex;
|
|
};
|
|
|
|
/* meta data for each different frame config */
|
|
struct wrot_frame_data {
|
|
/* 0 or 1 for 1st or 2nd out port */
|
|
u8 out_idx;
|
|
|
|
/* width and height before rotate */
|
|
u32 out_w;
|
|
u32 out_h;
|
|
struct mml_rect compose;
|
|
u32 y_stride;
|
|
u32 uv_stride;
|
|
u64 iova[MML_MAX_PLANES];
|
|
u32 plane_offset[MML_MAX_PLANES];
|
|
|
|
/* calculate in prepare and use as tile input */
|
|
bool en_x_crop;
|
|
bool en_y_crop;
|
|
struct mml_rect out_crop;
|
|
|
|
/* following data calculate in init and use in tile command */
|
|
u8 mat_en;
|
|
u8 mat_sel;
|
|
u32 dither_con;
|
|
/* bits per pixel y */
|
|
u32 bbp_y;
|
|
/* bits per pixel uv */
|
|
u32 bbp_uv;
|
|
/* hor right shift uv */
|
|
u32 hor_sh_uv;
|
|
/* vert right shift uv */
|
|
u32 ver_sh_uv;
|
|
/* VIDO_FILT_TYPE_V Chroma down sample filter type */
|
|
u32 filt_v;
|
|
|
|
/* calculate in frame, use in each tile calc */
|
|
u32 fifo_max_sz;
|
|
u32 max_line_cnt;
|
|
|
|
u32 pixel_acc; /* pixel accumulation */
|
|
u32 datasize; /* qos data size in bytes */
|
|
|
|
struct {
|
|
bool eol:1; /* tile is end of current line */
|
|
u8 sram:1; /* sram ping pong idx of this tile */
|
|
} wdone[256];
|
|
u8 sram_side; /* write to left/right ovl */
|
|
|
|
/* array of indices to one of entry in cache entry list,
|
|
* use in reuse command
|
|
*/
|
|
u16 labels[WROT_LABEL_TOTAL];
|
|
|
|
u32 wdone_cnt;
|
|
};
|
|
|
|
static inline struct wrot_frame_data *wrot_frm_data(struct mml_comp_config *ccfg)
|
|
{
|
|
return ccfg->data;
|
|
}
|
|
|
|
static inline struct mml_comp_wrot *comp_to_wrot(struct mml_comp *comp)
|
|
{
|
|
return container_of(comp, struct mml_comp_wrot, comp);
|
|
}
|
|
|
|
struct wrot_ofst_addr {
|
|
u64 y; /* wrot_y_ofst_adr for VIDO_OFST_ADDR */
|
|
u64 c; /* wrot_c_ofst_adr for VIDO_OFST_ADDR_C */
|
|
u64 v; /* wrot_v_ofst_adr for VIDO_OFST_ADDR_V */
|
|
};
|
|
|
|
/* different wrot setting between each tile */
|
|
struct wrot_setting {
|
|
/* parameters for calculation */
|
|
u32 tar_xsize;
|
|
/* result settings */
|
|
u32 main_blk_width;
|
|
u32 main_buf_line_num;
|
|
};
|
|
|
|
struct check_buf_param {
|
|
u32 y_buf_size;
|
|
u32 uv_buf_size;
|
|
u32 y_buf_check;
|
|
u32 uv_buf_check;
|
|
u32 y_buf_width;
|
|
u32 y_buf_usage;
|
|
u32 uv_blk_width;
|
|
u32 uv_blk_line;
|
|
u32 uv_buf_width;
|
|
u32 uv_buf_usage;
|
|
};
|
|
|
|
/* filt_h, filt_v, uv_xsel, uv_ysel */
|
|
static const u32 uv_table[2][4][2][4] = {
|
|
{ /* YUV422 */
|
|
{ /* 0 */
|
|
{ 1 /* [1 2 1] */, 0 /* drop */, 0, 2 },
|
|
{ 2 /* [1 2 1] */, 0 /* drop */, 1, 2 }, /* flip */
|
|
}, { /* 90 */
|
|
{ 0 /* drop */, 4 /* [1 1] */, 2, 1 },
|
|
{ 0 /* drop */, 3 /* [1 1] */, 2, 0 }, /* flip */
|
|
}, { /* 180 */
|
|
{ 2 /* [1 2 1] */, 0 /* drop */, 1, 2 },
|
|
{ 1 /* [1 2 1] */, 0 /* drop */, 0, 2 }, /* flip */
|
|
}, { /* 270 */
|
|
{ 0 /* drop */, 3 /* [1 1] */, 2, 0 },
|
|
{ 0 /* drop */, 4 /* [1 1] */, 2, 1 }, /* flip */
|
|
},
|
|
}, { /* YUV420 */
|
|
{ /* 0 */
|
|
{ 1 /* [1 2 1] */, 3 /* [1 1] */, 0, 0 },
|
|
{ 2 /* [1 2 1] */, 3 /* [1 1] */, 1, 0 }, /* flip */
|
|
}, { /* 90 */
|
|
{ 1 /* [1 2 1] */, 4 /* [1 1] */, 0, 1 },
|
|
{ 1 /* [1 2 1] */, 3 /* [1 1] */, 0, 0 }, /* flip */
|
|
}, { /* 180 */
|
|
{ 2 /* [1 2 1] */, 4 /* [1 1] */, 1, 1 },
|
|
{ 1 /* [1 2 1] */, 4 /* [1 1] */, 0, 1 }, /* flip */
|
|
}, { /* 270 */
|
|
{ 2 /* [1 2 1] */, 3 /* [1 1] */, 1, 0 },
|
|
{ 2 /* [1 2 1] */, 4 /* [1 1] */, 1, 1 }, /* flip */
|
|
},
|
|
}
|
|
};
|
|
|
|
static bool is_change_wx(u16 r, bool f)
|
|
{
|
|
return ((r == MML_ROT_0 && f) ||
|
|
(r == MML_ROT_180 && !f) ||
|
|
r == MML_ROT_270);
|
|
}
|
|
|
|
static void wrot_config_left(struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
wrot_frm->en_x_crop = true;
|
|
wrot_frm->out_crop.left = 0;
|
|
wrot_frm->out_crop.width = wrot_frm->out_w >> 1;
|
|
|
|
if (MML_FMT_10BIT_PACKED(dest->data.format) &&
|
|
wrot_frm->out_crop.width & 3) {
|
|
wrot_frm->out_crop.width = (wrot_frm->out_crop.width & ~3) + 4;
|
|
if (is_change_wx(dest->rotate, dest->flip))
|
|
wrot_frm->out_crop.width = wrot_frm->out_w -
|
|
wrot_frm->out_crop.width;
|
|
} else if (wrot_frm->out_crop.width & 1) {
|
|
wrot_frm->out_crop.width++;
|
|
}
|
|
}
|
|
|
|
static void wrot_config_right(struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
wrot_frm->en_x_crop = true;
|
|
wrot_frm->out_crop.left = wrot_frm->out_w >> 1;
|
|
|
|
if (MML_FMT_10BIT_PACKED(dest->data.format) &&
|
|
wrot_frm->out_crop.left & 3) {
|
|
wrot_frm->out_crop.left = (wrot_frm->out_crop.left & ~3) + 4;
|
|
if (is_change_wx(dest->rotate, dest->flip))
|
|
wrot_frm->out_crop.left = wrot_frm->out_w -
|
|
wrot_frm->out_crop.left;
|
|
} else if (wrot_frm->out_crop.left & 1) {
|
|
wrot_frm->out_crop.left++;
|
|
}
|
|
|
|
wrot_frm->out_crop.width = wrot_frm->out_w - wrot_frm->out_crop.left;
|
|
}
|
|
|
|
static void wrot_config_top(struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
wrot_frm->en_y_crop = true;
|
|
wrot_frm->out_crop.top = 0;
|
|
wrot_frm->out_crop.height = wrot_frm->out_h >> 1;
|
|
if (wrot_frm->out_crop.height & 0x1)
|
|
wrot_frm->out_crop.height++;
|
|
}
|
|
|
|
static void wrot_config_bottom(struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
wrot_frm->en_y_crop = true;
|
|
wrot_frm->out_crop.top = wrot_frm->out_h >> 1;
|
|
if (wrot_frm->out_crop.top & 0x1)
|
|
wrot_frm->out_crop.top++;
|
|
wrot_frm->out_crop.height = wrot_frm->out_h - wrot_frm->out_crop.top;
|
|
}
|
|
|
|
static void wrot_config_pipe0(struct mml_frame_config *cfg,
|
|
struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
if (cfg->info.mode == MML_MODE_RACING) {
|
|
if ((dest->rotate == MML_ROT_90 && !dest->flip) ||
|
|
(dest->rotate == MML_ROT_270 && dest->flip))
|
|
wrot_config_bottom(dest, wrot_frm);
|
|
else if ((dest->rotate == MML_ROT_90 && dest->flip) ||
|
|
(dest->rotate == MML_ROT_270 && !dest->flip))
|
|
wrot_config_top(dest, wrot_frm);
|
|
else if ((dest->rotate == MML_ROT_0 && !dest->flip) ||
|
|
(dest->rotate == MML_ROT_180 && dest->flip))
|
|
wrot_config_left(dest, wrot_frm);
|
|
else if ((dest->rotate == MML_ROT_0 && dest->flip) ||
|
|
(dest->rotate == MML_ROT_180 && !dest->flip))
|
|
wrot_config_right(dest, wrot_frm);
|
|
} else {
|
|
wrot_config_left(dest, wrot_frm);
|
|
}
|
|
}
|
|
|
|
static void wrot_config_pipe1(struct mml_frame_config *cfg,
|
|
struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
if (cfg->info.mode == MML_MODE_RACING) {
|
|
if ((dest->rotate == MML_ROT_90 && !dest->flip) ||
|
|
(dest->rotate == MML_ROT_270 && dest->flip))
|
|
wrot_config_top(dest, wrot_frm);
|
|
else if ((dest->rotate == MML_ROT_90 && dest->flip) ||
|
|
(dest->rotate == MML_ROT_270 && !dest->flip))
|
|
wrot_config_bottom(dest, wrot_frm);
|
|
else if ((dest->rotate == MML_ROT_0 && !dest->flip) ||
|
|
(dest->rotate == MML_ROT_180 && dest->flip))
|
|
wrot_config_right(dest, wrot_frm);
|
|
else if ((dest->rotate == MML_ROT_0 && dest->flip) ||
|
|
(dest->rotate == MML_ROT_180 && !dest->flip))
|
|
wrot_config_left(dest, wrot_frm);
|
|
} else {
|
|
wrot_config_right(dest, wrot_frm);
|
|
}
|
|
}
|
|
|
|
static s32 wrot_prepare(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct wrot_frame_data *wrot_frm;
|
|
struct mml_frame_dest *dest;
|
|
u8 i;
|
|
|
|
/* initialize component frame data for current frame config */
|
|
wrot_frm = kzalloc(sizeof(*wrot_frm), GFP_KERNEL);
|
|
ccfg->data = wrot_frm;
|
|
|
|
/* cache out index for easy use */
|
|
wrot_frm->out_idx = ccfg->node->out_idx;
|
|
|
|
/* select output port struct */
|
|
dest = &cfg->info.dest[wrot_frm->out_idx];
|
|
|
|
wrot_frm->compose = dest->compose;
|
|
wrot_frm->y_stride = dest->data.y_stride;
|
|
wrot_frm->uv_stride = dest->data.uv_stride;
|
|
if (dest->rotate == MML_ROT_0 || dest->rotate == MML_ROT_180) {
|
|
wrot_frm->out_w = dest->data.width;
|
|
wrot_frm->out_h = dest->data.height;
|
|
} else {
|
|
wrot_frm->out_w = dest->data.height;
|
|
wrot_frm->out_h = dest->data.width;
|
|
swap(wrot_frm->compose.width, wrot_frm->compose.height);
|
|
}
|
|
|
|
/* make sure uv stride data */
|
|
if (MML_FMT_PLANE(dest->data.format) > 1 && !wrot_frm->uv_stride)
|
|
wrot_frm->uv_stride = mml_color_get_min_uv_stride(
|
|
dest->data.format, dest->data.width);
|
|
|
|
/* plane offset for later use */
|
|
for (i = 0; i < task->buf.dest[wrot_frm->out_idx].cnt; i++)
|
|
wrot_frm->plane_offset[i] = dest->data.plane_offset[i];
|
|
|
|
if (cfg->dual) {
|
|
if (ccfg->pipe == 0)
|
|
wrot_config_pipe0(cfg, dest, wrot_frm);
|
|
else
|
|
wrot_config_pipe1(cfg, dest, wrot_frm);
|
|
|
|
if (cfg->info.mode == MML_MODE_RACING) {
|
|
if (dest->rotate == MML_ROT_0)
|
|
wrot_frm->sram_side = ccfg->pipe;
|
|
else if (dest->rotate == MML_ROT_90)
|
|
wrot_frm->sram_side = !ccfg->pipe;
|
|
else if (dest->rotate == MML_ROT_180)
|
|
wrot_frm->sram_side = !ccfg->pipe;
|
|
else
|
|
wrot_frm->sram_side = ccfg->pipe;
|
|
|
|
if (dest->flip)
|
|
wrot_frm->sram_side = !wrot_frm->sram_side;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 wrot_buf_map(struct mml_comp *comp, struct mml_task *task,
|
|
const struct mml_path_node *node)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
struct mml_file_buf *dest_buf = &task->buf.dest[node->out_idx];
|
|
s32 ret = 0;
|
|
|
|
mml_trace_ex_begin("%s", __func__);
|
|
|
|
if (task->config->info.mode == MML_MODE_RACING) {
|
|
} else {
|
|
/* get iova */
|
|
ret = mml_buf_iova_get(wrot->dev, dest_buf);
|
|
if (ret < 0)
|
|
mml_err("%s iova fail %d", __func__, ret);
|
|
|
|
mml_mmp(buf_map, MMPROFILE_FLAG_PULSE,
|
|
((u64)task->job.jobid << 16) | comp->id,
|
|
(unsigned long)dest_buf->dma[0].iova);
|
|
}
|
|
|
|
mml_trace_ex_end();
|
|
|
|
mml_msg("%s comp %u iova %#11llx (%u) %#11llx (%u) %#11llx (%u)",
|
|
__func__, comp->id,
|
|
dest_buf->dma[0].iova,
|
|
dest_buf->size[0],
|
|
dest_buf->dma[1].iova,
|
|
dest_buf->size[1],
|
|
dest_buf->dma[2].iova,
|
|
dest_buf->size[2]);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static s32 wrot_buf_prepare(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct mml_file_buf *dest_buf = &task->buf.dest[wrot_frm->out_idx];
|
|
u32 i;
|
|
|
|
if (task->config->info.mode == MML_MODE_RACING) {
|
|
/* assign sram pa directly */
|
|
mutex_lock(&wrot->sram_mutex);
|
|
if (!wrot->sram_cnt)
|
|
wrot->sram_pa = (u64)mml_sram_get(task->config->mml);
|
|
wrot->sram_cnt++;
|
|
mutex_unlock(&wrot->sram_mutex);
|
|
wrot_frm->iova[0] = wrot->sram_pa;
|
|
} else {
|
|
for (i = 0; i < dest_buf->cnt; i++)
|
|
wrot_frm->iova[i] = dest_buf->dma[i].iova;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void wrot_buf_unprepare(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
|
|
if (task->config->info.mode == MML_MODE_RACING) {
|
|
mutex_lock(&wrot->sram_mutex);
|
|
wrot->sram_cnt--;
|
|
if (wrot->sram_cnt == 0)
|
|
mml_sram_put(task->config->mml);
|
|
mutex_unlock(&wrot->sram_mutex);
|
|
}
|
|
}
|
|
|
|
static s32 wrot_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 wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct mml_frame_dest *dest = &cfg->info.dest[wrot_frm->out_idx];
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
|
|
data->wrot.dest_fmt = dest->data.format;
|
|
data->wrot.rotate = dest->rotate;
|
|
data->wrot.flip = dest->flip;
|
|
data->wrot.alpharot = cfg->alpharot;
|
|
data->wrot.racing = cfg->info.mode == MML_MODE_RACING;
|
|
data->wrot.racing_h = max(mml_racing_h, MML_WROT_RACING_MIN);
|
|
|
|
/* reuse wrot_frm data which processed with rotate and dual */
|
|
data->wrot.enable_x_crop = wrot_frm->en_x_crop;
|
|
data->wrot.enable_y_crop = wrot_frm->en_y_crop;
|
|
data->wrot.crop = wrot_frm->out_crop;
|
|
func->full_size_x_in = wrot_frm->out_w;
|
|
func->full_size_y_in = wrot_frm->out_h;
|
|
func->full_size_x_out = wrot_frm->out_w;
|
|
func->full_size_y_out = wrot_frm->out_h;
|
|
|
|
data->wrot.max_width = wrot->data->tile_width;
|
|
/* WROT support crop capability */
|
|
func->type = TILE_TYPE_WDMA | TILE_TYPE_CROP_EN;
|
|
func->init_func = tile_wrot_init;
|
|
func->for_func = tile_wrot_for;
|
|
func->back_func = tile_wrot_back;
|
|
func->data = data;
|
|
func->enable_flag = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct mml_comp_tile_ops wrot_tile_ops = {
|
|
.prepare = wrot_tile_prepare,
|
|
};
|
|
|
|
static u32 wrot_get_label_count(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
return WROT_LABEL_TOTAL;
|
|
}
|
|
|
|
static void wrot_color_fmt(struct mml_frame_config *cfg,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
u32 fmt = cfg->info.dest[wrot_frm->out_idx].data.format;
|
|
u16 profile_in = cfg->info.src.profile;
|
|
u16 profile_out = cfg->info.dest[wrot_frm->out_idx].data.profile;
|
|
|
|
wrot_frm->mat_en = 0;
|
|
wrot_frm->mat_sel = 15;
|
|
wrot_frm->bbp_y = MML_FMT_BITS_PER_PIXEL(fmt);
|
|
|
|
switch (fmt) {
|
|
case MML_FMT_GREY:
|
|
/* Y only */
|
|
wrot_frm->bbp_uv = 0;
|
|
wrot_frm->hor_sh_uv = 0;
|
|
wrot_frm->ver_sh_uv = 0;
|
|
break;
|
|
case MML_FMT_RGB565:
|
|
case MML_FMT_BGR565:
|
|
case MML_FMT_RGB888:
|
|
case MML_FMT_BGR888:
|
|
case MML_FMT_RGBA8888:
|
|
case MML_FMT_BGRA8888:
|
|
case MML_FMT_ARGB8888:
|
|
case MML_FMT_ABGR8888:
|
|
/* HW_SUPPORT_10BIT_PATH */
|
|
case MML_FMT_RGBA1010102:
|
|
case MML_FMT_BGRA1010102:
|
|
case MML_FMT_ARGB1010102:
|
|
case MML_FMT_ABGR1010102:
|
|
/* DMA_SUPPORT_AFBC */
|
|
case MML_FMT_RGBA8888_AFBC:
|
|
case MML_FMT_BGRA8888_AFBC:
|
|
case MML_FMT_RGBA1010102_AFBC:
|
|
case MML_FMT_BGRA1010102_AFBC:
|
|
wrot_frm->bbp_uv = 0;
|
|
wrot_frm->hor_sh_uv = 0;
|
|
wrot_frm->ver_sh_uv = 0;
|
|
wrot_frm->mat_en = 1;
|
|
break;
|
|
case MML_FMT_UYVY:
|
|
case MML_FMT_VYUY:
|
|
case MML_FMT_YUYV:
|
|
case MML_FMT_YVYU:
|
|
/* YUV422, 1 plane */
|
|
wrot_frm->bbp_uv = 0;
|
|
wrot_frm->hor_sh_uv = 0;
|
|
wrot_frm->ver_sh_uv = 0;
|
|
break;
|
|
case MML_FMT_I420:
|
|
case MML_FMT_YV12:
|
|
/* YUV420, 3 plane */
|
|
wrot_frm->bbp_uv = 8;
|
|
wrot_frm->hor_sh_uv = 1;
|
|
wrot_frm->ver_sh_uv = 1;
|
|
break;
|
|
case MML_FMT_I422:
|
|
case MML_FMT_YV16:
|
|
/* YUV422, 3 plane */
|
|
wrot_frm->bbp_uv = 8;
|
|
wrot_frm->hor_sh_uv = 1;
|
|
wrot_frm->ver_sh_uv = 0;
|
|
break;
|
|
case MML_FMT_I444:
|
|
case MML_FMT_YV24:
|
|
/* YUV444, 3 plane */
|
|
wrot_frm->bbp_uv = 8;
|
|
wrot_frm->hor_sh_uv = 0;
|
|
wrot_frm->ver_sh_uv = 0;
|
|
break;
|
|
case MML_FMT_NV12:
|
|
case MML_FMT_NV21:
|
|
/* YUV420, 2 plane */
|
|
wrot_frm->bbp_uv = 16;
|
|
wrot_frm->hor_sh_uv = 1;
|
|
wrot_frm->ver_sh_uv = 1;
|
|
break;
|
|
case MML_FMT_NV16:
|
|
case MML_FMT_NV61:
|
|
/* YUV422, 2 plane */
|
|
wrot_frm->bbp_uv = 16;
|
|
wrot_frm->hor_sh_uv = 1;
|
|
wrot_frm->ver_sh_uv = 0;
|
|
break;
|
|
/* HW_SUPPORT_10BIT_PATH */
|
|
case MML_FMT_NV12_10L:
|
|
case MML_FMT_NV21_10L:
|
|
/* P010 YUV420, 2 plane 10bit */
|
|
wrot_frm->bbp_uv = 32;
|
|
wrot_frm->hor_sh_uv = 1;
|
|
wrot_frm->ver_sh_uv = 1;
|
|
break;
|
|
case MML_FMT_NV12_10P:
|
|
case MML_FMT_NV21_10P:
|
|
/* MTK packet YUV420, 2 plane 10bit */
|
|
wrot_frm->bbp_uv = 20;
|
|
wrot_frm->hor_sh_uv = 1;
|
|
wrot_frm->ver_sh_uv = 1;
|
|
break;
|
|
default:
|
|
mml_err("[wrot] not support format %x", fmt);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* 4'b0000: RGB to JPEG
|
|
* 4'b0010: RGB to BT601
|
|
* 4'b0011: RGB to BT709
|
|
* 4'b0100: JPEG to RGB
|
|
* 4'b0110: BT601 to RGB
|
|
* 4'b0111: BT709 to RGB
|
|
* 4'b1000: JPEG to BT601
|
|
* 4'b1001: JPEG to BT709
|
|
* 4'b1010: BT601 to JPEG
|
|
* 4'b1011: BT709 to JPEG
|
|
* 4'b1100: BT709 to BT601
|
|
* 4'b1101: BT601 to BT709
|
|
*/
|
|
if (profile_in == MML_YCBCR_PROFILE_BT2020 ||
|
|
profile_in == MML_YCBCR_PROFILE_FULL_BT709 ||
|
|
profile_in == MML_YCBCR_PROFILE_FULL_BT2020)
|
|
profile_in = MML_YCBCR_PROFILE_BT709;
|
|
|
|
if (wrot_frm->mat_en == 1) {
|
|
if (profile_in == MML_YCBCR_PROFILE_BT601)
|
|
wrot_frm->mat_sel = 6;
|
|
else if (profile_in == MML_YCBCR_PROFILE_BT709)
|
|
wrot_frm->mat_sel = 7;
|
|
else if (profile_in == MML_YCBCR_PROFILE_JPEG)
|
|
wrot_frm->mat_sel = 4;
|
|
else
|
|
mml_err("[wrot] unknown profile conversion %x",
|
|
profile_in);
|
|
} else {
|
|
if (profile_in == MML_YCBCR_PROFILE_JPEG &&
|
|
profile_out == MML_YCBCR_PROFILE_BT601) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->mat_sel = 8;
|
|
} else if (profile_in == MML_YCBCR_PROFILE_JPEG &&
|
|
profile_out == MML_YCBCR_PROFILE_BT709) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->mat_sel = 9;
|
|
} else if (profile_in == MML_YCBCR_PROFILE_BT601 &&
|
|
profile_out == MML_YCBCR_PROFILE_JPEG) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->mat_sel = 10;
|
|
} else if (profile_in == MML_YCBCR_PROFILE_BT709 &&
|
|
profile_out == MML_YCBCR_PROFILE_JPEG) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->mat_sel = 11;
|
|
} else if (profile_in == MML_YCBCR_PROFILE_BT709 &&
|
|
profile_out == MML_YCBCR_PROFILE_BT601) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->mat_sel = 12;
|
|
} else if (profile_in == MML_YCBCR_PROFILE_BT601 &&
|
|
profile_out == MML_YCBCR_PROFILE_BT709) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->mat_sel = 13;
|
|
}
|
|
}
|
|
|
|
/* Enable dither */
|
|
if (MML_FMT_10BIT(cfg->info.src.format) && !MML_FMT_10BIT(fmt)) {
|
|
wrot_frm->mat_en = 1;
|
|
wrot_frm->dither_con = (0x1 << 10) +
|
|
(0x0 << 8) +
|
|
(0x0 << 4) +
|
|
(0x1 << 2) +
|
|
(0x1 << 1) +
|
|
(0x1 << 0);
|
|
}
|
|
}
|
|
|
|
static void calc_plane_offset(u32 left, u32 top,
|
|
u32 y_stride, u32 uv_stride,
|
|
u32 bbp_y, u32 bbp_uv,
|
|
u32 hor_sh_uv, u32 ver_sh_uv,
|
|
u32 *offset)
|
|
{
|
|
if (!left && !top)
|
|
return;
|
|
|
|
offset[0] += (left * bbp_y >> 3) + (y_stride * top);
|
|
|
|
offset[1] += (left >> hor_sh_uv) * (bbp_uv >> 3) +
|
|
(top >> ver_sh_uv) * uv_stride;
|
|
|
|
offset[2] += (left >> hor_sh_uv) * (bbp_uv >> 3) +
|
|
(top >> hor_sh_uv) * uv_stride;
|
|
}
|
|
|
|
static void calc_afbc_block(u32 bits_per_pixel, u32 y_stride, u32 vert_stride,
|
|
u64 *iova, u32 *offset,
|
|
u32 *block_x, u64 *addr_c, u64 *addr_v, u64 *addr)
|
|
{
|
|
u32 block_y;
|
|
u64 header_sz;
|
|
|
|
*block_x = ((y_stride << 3) / bits_per_pixel + 31) >> 5;
|
|
block_y = (vert_stride + 7) >> 3;
|
|
header_sz = ((((*block_x * block_y) << 4) + 1023) >> 10) << 10;
|
|
|
|
*addr_c = iova[0] + offset[0];
|
|
*addr_v = iova[2] + offset[2];
|
|
*addr = *addr_c + header_sz;
|
|
}
|
|
|
|
static void wrot_calc_hw_buf_setting(const struct mml_comp_wrot *wrot,
|
|
const struct mml_frame_config *cfg,
|
|
const struct mml_frame_dest *dest,
|
|
struct wrot_frame_data *wrot_frm)
|
|
{
|
|
const u32 dest_fmt = dest->data.format;
|
|
|
|
if (MML_FMT_YUV422(dest_fmt)) {
|
|
if (MML_FMT_PLANE(dest_fmt) == 1) {
|
|
wrot_frm->fifo_max_sz = wrot->data->tile_width * 32;
|
|
wrot_frm->max_line_cnt = 32;
|
|
} else {
|
|
wrot_frm->fifo_max_sz = wrot->data->tile_width * 48;
|
|
wrot_frm->max_line_cnt = 48;
|
|
}
|
|
} else if (MML_FMT_YUV420(dest_fmt)) {
|
|
wrot_frm->fifo_max_sz = wrot->data->tile_width * 64;
|
|
wrot_frm->max_line_cnt = 64;
|
|
} else if (dest_fmt == MML_FMT_GREY) {
|
|
wrot_frm->fifo_max_sz = wrot->data->tile_width * 64;
|
|
wrot_frm->max_line_cnt = 64;
|
|
} else if (MML_FMT_IS_RGB(dest_fmt)) {
|
|
if (cfg->alpharot) {
|
|
wrot_frm->fifo_max_sz = wrot->data->tile_width * 16;
|
|
wrot_frm->max_line_cnt = 16;
|
|
} else {
|
|
wrot_frm->fifo_max_sz = wrot->data->tile_width * 32;
|
|
wrot_frm->max_line_cnt = 32;
|
|
}
|
|
} else {
|
|
mml_err("%s fail set fifo max size, max line count for %#x",
|
|
__func__, dest_fmt);
|
|
}
|
|
}
|
|
|
|
static void wrot_config_addr(const struct mml_frame_dest *dest,
|
|
const u32 dest_fmt,
|
|
const phys_addr_t base_pa,
|
|
struct wrot_frame_data *wrot_frm,
|
|
struct cmdq_pkt *pkt,
|
|
struct mml_task_reuse *reuse,
|
|
struct mml_pipe_cache *cache)
|
|
{
|
|
u64 addr_c, addr_v, addr;
|
|
|
|
if (MML_FMT_COMPRESS(dest_fmt)) {
|
|
/* wrot afbc output case */
|
|
u32 block_x;
|
|
u32 frame_size;
|
|
|
|
/* Write frame base address */
|
|
calc_afbc_block(wrot_frm->bbp_y,
|
|
wrot_frm->y_stride, dest->data.vert_stride,
|
|
wrot_frm->iova, wrot_frm->plane_offset,
|
|
&block_x, &addr_c, &addr_v, &addr);
|
|
|
|
if (dest->rotate == MML_ROT_0 || dest->rotate == MML_ROT_180)
|
|
frame_size = ((((wrot_frm->out_h + 31) >>
|
|
5) << 5) << 16) +
|
|
((block_x << 5) << 0);
|
|
else
|
|
frame_size = ((((wrot_frm->out_w + 31) >>
|
|
5) << 5) << 16) +
|
|
((block_x << 5) << 0);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_FRAME_SIZE,
|
|
frame_size, U32_MAX);
|
|
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_AFBC_YUVTRANS,
|
|
MML_FMT_IS_ARGB(dest_fmt), 0x1);
|
|
} else {
|
|
addr = wrot_frm->iova[0] + wrot_frm->plane_offset[0];
|
|
addr_c = wrot_frm->iova[1] + wrot_frm->plane_offset[1];
|
|
addr_v = wrot_frm->iova[2] + wrot_frm->plane_offset[2];
|
|
|
|
mml_msg("%s base %#llx+%u %#llx+%u %#llx+%u",
|
|
__func__,
|
|
addr, wrot_frm->plane_offset[0],
|
|
addr_c, wrot_frm->plane_offset[1],
|
|
addr_v, wrot_frm->plane_offset[2]);
|
|
}
|
|
|
|
if (!mml_slt) {
|
|
/* Write frame base address */
|
|
wrot_write_addr(pkt,
|
|
base_pa + VIDO_BASE_ADDR,
|
|
base_pa + VIDO_BASE_ADDR_HIGH, addr,
|
|
reuse, cache, &wrot_frm->labels[WROT_LABEL_ADDR]);
|
|
wrot_write_addr(pkt,
|
|
base_pa + VIDO_BASE_ADDR_C,
|
|
base_pa + VIDO_BASE_ADDR_HIGH_C, addr_c,
|
|
reuse, cache, &wrot_frm->labels[WROT_LABEL_ADDR_C]);
|
|
wrot_write_addr(pkt,
|
|
base_pa + VIDO_BASE_ADDR_V,
|
|
base_pa + VIDO_BASE_ADDR_HIGH_V, addr_v,
|
|
reuse, cache, &wrot_frm->labels[WROT_LABEL_ADDR_V]);
|
|
}
|
|
}
|
|
|
|
static void wrot_config_ready(struct mml_comp_wrot *wrot,
|
|
struct mml_frame_config *cfg,
|
|
struct wrot_frame_data *wrot_frm, u32 pipe, struct cmdq_pkt *pkt,
|
|
bool enable)
|
|
{
|
|
const struct mml_topology_path *path = cfg->path[pipe];
|
|
phys_addr_t sel = path->mmlsys->base_pa +
|
|
mml_sys_get_reg_ready_sel(path->mmlsys);
|
|
u32 shift, mask;
|
|
|
|
if (wrot->idx == 0)
|
|
shift = 0;
|
|
else if (wrot->idx == 1)
|
|
shift = 3;
|
|
else
|
|
return;
|
|
mask = cfg->dual ? (0x7 << shift) | GENMASK(31, 6) : U32_MAX;
|
|
|
|
if (mml_racing_rdone) {
|
|
/* debug mode, make rdone to wrot tie 1 */
|
|
cmdq_pkt_write(pkt, NULL, sel, 0x24, U32_MAX);
|
|
return;
|
|
}
|
|
|
|
if (!enable) {
|
|
cmdq_pkt_write(pkt, NULL, sel, 0, mask);
|
|
} else if (cfg->disp_dual) {
|
|
/* 1:2 or 2:2 monitor both disp0 and disp1, mdpsys merge ready */
|
|
cmdq_pkt_write(pkt, NULL, sel, 2 << shift, mask);
|
|
} else {
|
|
/* 1:1 or 2:1 monitor only disp0 */
|
|
cmdq_pkt_write(pkt, NULL, sel, 0, mask);
|
|
}
|
|
}
|
|
|
|
static s32 wrot_config_frame(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct mml_frame_dest *dest = &cfg->info.dest[wrot_frm->out_idx];
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
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;
|
|
const u32 src_fmt = cfg->info.src.format;
|
|
const u32 dest_fmt = dest->data.format;
|
|
const u16 rotate = dest->rotate;
|
|
const u8 flip = dest->flip ? 1 : 0;
|
|
const u32 h_subsample = MML_FMT_H_SUBSAMPLE(dest_fmt);
|
|
const u32 v_subsample = MML_FMT_V_SUBSAMPLE(dest_fmt);
|
|
const u8 plane = MML_FMT_PLANE(dest_fmt);
|
|
const u32 preultra_en = 1; /* always enable wrot pre-ultra */
|
|
const u32 crop_en = 1; /* always enable crop */
|
|
const u32 hw_fmt = MML_FMT_HW_FORMAT(dest_fmt);
|
|
|
|
u32 out_swap = MML_FMT_SWAP(dest_fmt);
|
|
u32 uv_xsel, uv_ysel;
|
|
u32 preultra;
|
|
u32 scan_10bit = 0, bit_num = 0, pending_zero = 0, pvric = 0;
|
|
|
|
wrot_color_fmt(cfg, wrot_frm);
|
|
|
|
/* calculate for later config tile use */
|
|
wrot_calc_hw_buf_setting(wrot, cfg, dest, wrot_frm);
|
|
|
|
if (cfg->alpharot) {
|
|
wrot_frm->mat_en = 0;
|
|
|
|
if (wrot->data->rb_swap == 1) {
|
|
if (!MML_FMT_COMPRESS(src_fmt) && !MML_FMT_10BIT(src_fmt))
|
|
out_swap ^= MML_FMT_SWAP(src_fmt);
|
|
else if (MML_FMT_COMPRESS(src_fmt) && !MML_FMT_10BIT(src_fmt))
|
|
out_swap =
|
|
(MML_FMT_SWAP(src_fmt) == MML_FMT_SWAP(dest_fmt)) ? 1 : 0;
|
|
else if (MML_FMT_COMPRESS(src_fmt) && MML_FMT_10BIT(src_fmt))
|
|
out_swap = out_swap ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
mml_msg("use config %p wrot %p", cfg, wrot);
|
|
|
|
/* Enable engine */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_ROT_EN, 0x01, 0x00000001);
|
|
|
|
/* Enable shadow */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_SHADOW_CTRL, 0x1, U32_MAX);
|
|
|
|
if (h_subsample) { /* YUV422/420 out */
|
|
wrot_frm->filt_v = MML_FMT_V_SUBSAMPLE(src_fmt) ||
|
|
MML_FMT_GROUP(src_fmt) == 2 ?
|
|
0 : uv_table[v_subsample][rotate][flip][1];
|
|
uv_xsel = uv_table[v_subsample][rotate][flip][2];
|
|
uv_ysel = uv_table[v_subsample][rotate][flip][3];
|
|
} else if (dest_fmt == MML_FMT_GREY) {
|
|
uv_xsel = 0;
|
|
uv_ysel = 0;
|
|
} else {
|
|
uv_xsel = 2;
|
|
uv_ysel = 2;
|
|
}
|
|
|
|
/* Note: check odd size roi_w & roi_h for uv_xsel/uv_ysel */
|
|
if ((wrot_frm->compose.width & 0x1) && uv_xsel == 1)
|
|
uv_xsel = 0;
|
|
if ((wrot_frm->compose.height & 0x1) && uv_ysel == 1)
|
|
uv_ysel = 0;
|
|
|
|
/* Note: WROT not support UV swap */
|
|
if (out_swap == 1 && MML_FMT_PLANE(dest_fmt) == 3) {
|
|
swap(wrot_frm->iova[1], wrot_frm->iova[2]);
|
|
swap(wrot_frm->plane_offset[1], wrot_frm->plane_offset[2]);
|
|
}
|
|
|
|
calc_plane_offset(wrot_frm->compose.left, wrot_frm->compose.top,
|
|
wrot_frm->y_stride, wrot_frm->uv_stride,
|
|
wrot_frm->bbp_y, wrot_frm->bbp_uv,
|
|
wrot_frm->hor_sh_uv, wrot_frm->ver_sh_uv,
|
|
wrot_frm->plane_offset);
|
|
|
|
if (dest->data.secure) {
|
|
/* TODO: for secure case setup plane offset and reg */
|
|
}
|
|
|
|
if (task->config->info.mode == MML_MODE_RACING) {
|
|
/* config smi addr to emi (iova) or sram */
|
|
cmdq_pkt_write(pkt, NULL, wrot->smi_larb_con,
|
|
GENMASK(19, 16), GENMASK(19, 16));
|
|
|
|
/* config ready signal from disp0 or disp1 */
|
|
wrot_config_ready(wrot, cfg, wrot_frm, ccfg->pipe, pkt, true);
|
|
|
|
/* inline rotate case always write to sram pa */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_BASE_ADDR,
|
|
wrot->sram_pa, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_BASE_ADDR_HIGH,
|
|
wrot->sram_pa >> 32, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_BASE_ADDR_C,
|
|
wrot->sram_pa, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_BASE_ADDR_HIGH_C,
|
|
wrot->sram_pa >> 32, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_BASE_ADDR_V,
|
|
wrot->sram_pa, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_BASE_ADDR_HIGH_V,
|
|
wrot->sram_pa >> 32, U32_MAX);
|
|
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[0] + DISPSYS_SHADOW_CTRL, 0x2, U32_MAX);
|
|
|
|
if (mml_racing_ut == 2)
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[0] + INLINEROT_OVLSEL, 0x22, U32_MAX);
|
|
else if (mml_racing_ut == 3)
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[0] + INLINEROT_OVLSEL, 0xc, U32_MAX);
|
|
|
|
mml_msg("%s sram pa %#x", __func__, (u32)wrot->sram_pa);
|
|
} else {
|
|
/* normal dram case config wrot iova with reuse */
|
|
wrot_config_addr(dest, dest_fmt, base_pa,
|
|
wrot_frm, pkt, reuse, cache);
|
|
/* always turn off ready to wrot */
|
|
wrot_config_ready(wrot, cfg, wrot_frm, ccfg->pipe, pkt, false);
|
|
|
|
/* and clear inlinerot enable since last frame maybe racing mode */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_IN_LINE_ROT, 0, U32_MAX);
|
|
}
|
|
|
|
/* Write frame related registers */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_CTRL,
|
|
(uv_ysel << 30) +
|
|
(uv_xsel << 28) +
|
|
(flip << 24) +
|
|
(dest->rotate << 20) +
|
|
(cfg->alpharot << 16) + /* alpha rot */
|
|
(preultra_en << 14) + /* pre-ultra */
|
|
(crop_en << 12) +
|
|
(out_swap << 8) +
|
|
(hw_fmt << 0), 0xf131510f);
|
|
|
|
if (MML_FMT_10BIT_LOOSE(dest_fmt)) {
|
|
scan_10bit = 1;
|
|
bit_num = 1;
|
|
} else if (MML_FMT_10BIT_PACKED(dest_fmt)) {
|
|
if (MML_FMT_IS_ARGB(dest_fmt))
|
|
scan_10bit = 1;
|
|
else
|
|
scan_10bit = 3;
|
|
pending_zero = 1;
|
|
bit_num = 1;
|
|
}
|
|
/* DMA_SUPPORT_AFBC */
|
|
if (MML_FMT_COMPRESS(dest_fmt)) {
|
|
scan_10bit = 0;
|
|
pending_zero = 1;
|
|
}
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_SCAN_10BIT, scan_10bit, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_PENDING_ZERO,
|
|
pending_zero << 26, 0x04000000);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_CTRL_2, bit_num,
|
|
0x00000007);
|
|
|
|
if (MML_FMT_COMPRESS(dest_fmt)) {
|
|
pvric |= BIT(0);
|
|
if (MML_FMT_10BIT(dest_fmt))
|
|
pvric |= BIT(1);
|
|
}
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_PVRIC, pvric, U32_MAX);
|
|
|
|
/* set ESL */
|
|
if (plane == 3 || plane == 2 || hw_fmt == 7) {
|
|
/* 3-plane, 2-plane, Y8 */
|
|
preultra = (216 << 12) + (196 << 0);
|
|
} else if(hw_fmt == 0 || hw_fmt == 1) {
|
|
/* RGB */
|
|
preultra = (136 << 12) + (76 << 0);
|
|
} else if (hw_fmt == 2 || hw_fmt == 3) {
|
|
/* ARGB */
|
|
preultra = (96 << 12) + (16 << 0);
|
|
} else if (hw_fmt == 4 || hw_fmt == 5) {
|
|
/* UYVY */
|
|
preultra = (176 << 12) + (136 << 0);
|
|
} else {
|
|
preultra = 0;
|
|
}
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_DMA_PREULTRA, preultra,
|
|
U32_MAX);
|
|
|
|
/* Write frame Y stride */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_STRIDE, wrot_frm->y_stride,
|
|
U32_MAX);
|
|
/* Write frame UV stride */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_STRIDE_C, wrot_frm->uv_stride,
|
|
U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_STRIDE_V, wrot_frm->uv_stride,
|
|
U32_MAX);
|
|
|
|
/* Write matrix control */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_MAT_CTRL,
|
|
(wrot_frm->mat_sel << 4) +
|
|
(wrot_frm->mat_en << 0), U32_MAX);
|
|
|
|
/* Set the fixed ALPHA as 0xff */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_DITHER, 0xff000000, U32_MAX);
|
|
|
|
/* Set VIDO_EOL_SEL */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_EOL_SEL, 0x80000000, 0x80000000);
|
|
|
|
/* Set VIDO_FIFO_TEST */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_FIFO_TEST, wrot->data->fifo, U32_MAX);
|
|
|
|
/* turn off WROT dma dcm */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_ROT_EN,
|
|
(0x1 << 23) + (0x1 << 20), 0x00900000);
|
|
|
|
/* Enable dither */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_DITHER_CON, wrot_frm->dither_con, U32_MAX);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void wrot_tile_calc_comp(const struct mml_frame_dest *dest,
|
|
const struct wrot_frame_data *wrot_frm,
|
|
const struct mml_tile_engine *tile,
|
|
struct wrot_ofst_addr *ofst)
|
|
{
|
|
/* Following data retrieve from tile calc result */
|
|
const u64 out_xs = tile->out.xs;
|
|
const char *msg = "";
|
|
|
|
if (dest->rotate == MML_ROT_0 && !dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = out_xs * 32;
|
|
|
|
/*
|
|
* Target U offset
|
|
* RGBA: 64, YV12 8-bit: 24, 10-bit: 32
|
|
*/
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "No flip and no rotation";
|
|
} else if (dest->rotate == MML_ROT_0 && dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = (wrot_frm->out_w - out_xs - 32) * 32;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Flip without rotation";
|
|
} else if (dest->rotate == MML_ROT_90 && !dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = (((out_xs / 8) + 1) *
|
|
(wrot_frm->y_stride / 128) - 1) * 1024;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Rotate 90 degree only";
|
|
} else if (dest->rotate == MML_ROT_90 && dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = (out_xs / 8) * (wrot_frm->y_stride / 128) * 1024;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Flip and Rotate 90 degree";
|
|
} else if (dest->rotate == MML_ROT_180 && !dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = ((((u64)wrot_frm->out_h / 8) - 1) *
|
|
(wrot_frm->y_stride / 128) +
|
|
((wrot_frm->out_w / 32) - (out_xs / 32) - 1)) *
|
|
1024;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Rotate 180 degree only";
|
|
} else if (dest->rotate == MML_ROT_180 && dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = ((((u64)wrot_frm->out_h / 8) - 1) *
|
|
(wrot_frm->y_stride / 128) +
|
|
(out_xs / 32)) * 1024;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Flip and Rotate 180 degree";
|
|
} else if (dest->rotate == MML_ROT_270 && !dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = ((wrot_frm->out_w / 8) - (out_xs / 8) - 1) *
|
|
(wrot_frm->y_stride / 128) * 1024;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Rotate 270 degree only";
|
|
} else if (dest->rotate == MML_ROT_270 && dest->flip) {
|
|
/* Target Y offset */
|
|
ofst->y = (((wrot_frm->out_w / 8) - (out_xs / 8)) *
|
|
(wrot_frm->y_stride / 128) - 1) * 1024;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ofst->y / 64;
|
|
|
|
msg = "Flip and Rotate 270 degree";
|
|
}
|
|
mml_msg("%s %s: offset Y:%#010llx U:%#010llx V:%#010llx",
|
|
__func__, msg, ofst->y, ofst->c, ofst->v);
|
|
}
|
|
|
|
static void wrot_tile_calc(const struct mml_task *task,
|
|
const struct mml_comp_wrot *wrot,
|
|
const struct mml_frame_dest *dest,
|
|
const struct mml_tile_output *tout,
|
|
const struct mml_tile_engine *tile,
|
|
const u32 idx,
|
|
const enum mml_mode mode,
|
|
struct wrot_frame_data *wrot_frm,
|
|
struct wrot_ofst_addr *ofst)
|
|
{
|
|
/* Following data retrieve from tile calc result */
|
|
u64 out_xs = tile->out.xs;
|
|
u64 out_ys = tile->out.ys;
|
|
u32 out_w = wrot_frm->out_w;
|
|
u32 out_h = wrot_frm->out_h;
|
|
u32 sram_block = 0; /* buffer block number for sram */
|
|
const char *msg = "";
|
|
bool tile_eol = false;
|
|
|
|
if (dest->rotate == MML_ROT_0 && !dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = tout->tiles[idx].v_tile_no & 0x1;
|
|
out_ys = 0;
|
|
tile_eol = tout->h_tile_cnt == (tout->tiles[idx].h_tile_no + 1);
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = out_ys * wrot_frm->y_stride +
|
|
(out_xs * wrot_frm->bbp_y >> 3);
|
|
|
|
/* Target U offset */
|
|
ofst->c = (out_ys >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
((out_xs >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
/* Target V offset */
|
|
ofst->v = (out_ys >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
((out_xs >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
msg = "No flip and no rotation";
|
|
} else if (dest->rotate == MML_ROT_0 && dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = tout->tiles[idx].v_tile_no & 0x1;
|
|
out_ys = 0;
|
|
tile_eol = tout->h_tile_cnt == (tout->tiles[idx].h_tile_no + 1);
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = out_ys * wrot_frm->y_stride +
|
|
((out_w - out_xs) *
|
|
wrot_frm->bbp_y >> 3) - 1;
|
|
|
|
/* Target U offset */
|
|
ofst->c = (out_ys >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
(((out_w - out_xs) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
/* Target V offset */
|
|
ofst->v = (out_ys >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
(((out_w - out_xs) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
msg = "Flip without rotation";
|
|
} else if (dest->rotate == MML_ROT_90 && !dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = tout->tiles[idx].h_tile_no & 0x1;
|
|
out_xs = 0;
|
|
tile_eol = tout->v_tile_cnt == (tout->tiles[idx].v_tile_no + 1);
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = out_xs * wrot_frm->y_stride +
|
|
((out_h - out_ys) *
|
|
wrot_frm->bbp_y >> 3) - 1;
|
|
|
|
/* Target U offset */
|
|
ofst->c = (out_xs >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
(((out_h - out_ys) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
/* Target V offset */
|
|
ofst->v = (out_xs >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
(((out_h - out_ys) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
msg = "Rotate 90 degree only";
|
|
} else if (dest->rotate == MML_ROT_90 && dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = tout->tiles[idx].h_tile_no & 0x1;
|
|
out_xs = 0;
|
|
tile_eol = tout->v_tile_cnt == (tout->tiles[idx].v_tile_no + 1);
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = out_xs * wrot_frm->y_stride +
|
|
(out_ys * wrot_frm->bbp_y >> 3);
|
|
|
|
/* Target U offset */
|
|
ofst->c = (out_xs >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
((out_ys >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
/* Target V offset */
|
|
ofst->v = (out_xs >> wrot_frm->ver_sh_uv) *
|
|
wrot_frm->uv_stride +
|
|
((out_ys >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
msg = "Flip and Rotate 90 degree";
|
|
} else if (dest->rotate == MML_ROT_180 && !dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = (tout->v_tile_cnt - tout->tiles[idx].v_tile_no - 1) & 0x1;
|
|
out_h = tile->out.ye + 1;
|
|
tile_eol = tout->tiles[idx].h_tile_no == 0;
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = (out_h - out_ys - 1) *
|
|
wrot_frm->y_stride +
|
|
((out_w - out_xs) *
|
|
wrot_frm->bbp_y >> 3) - 1;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ((out_h - out_ys - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
(((out_w - out_xs) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
/* Target V offset */
|
|
ofst->v = ((out_h - out_ys - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
(((out_w - out_xs) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
msg = "Rotate 180 degree only";
|
|
} else if (dest->rotate == MML_ROT_180 && dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = (tout->v_tile_cnt - tout->tiles[idx].v_tile_no - 1) & 0x1;
|
|
out_h = tile->out.ye + 1;
|
|
tile_eol = tout->tiles[idx].h_tile_no == 0;
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = (out_h - out_ys - 1) *
|
|
wrot_frm->y_stride +
|
|
(out_xs * wrot_frm->bbp_y >> 3);
|
|
|
|
/* Target U offset */
|
|
ofst->c = ((out_h - out_ys - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
((out_xs >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
/* Target V offset */
|
|
ofst->v = ((out_h - out_ys - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
((out_xs >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
msg = "Flip and Rotate 180 degree";
|
|
} else if (dest->rotate == MML_ROT_270 && !dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = (tout->h_tile_cnt - tout->tiles[idx].h_tile_no - 1) & 0x1;
|
|
out_w = tile->out.xe + 1;
|
|
tile_eol = tout->tiles[idx].v_tile_no == 0;
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = (out_w - out_xs - 1) *
|
|
wrot_frm->y_stride +
|
|
(out_ys * wrot_frm->bbp_y >> 3);
|
|
|
|
/* Target U offset */
|
|
ofst->c = ((out_w - out_xs - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
((out_ys >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
/* Target V offset */
|
|
ofst->v = ((out_w - out_xs - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
((out_ys >> wrot_frm->hor_sh_uv) *
|
|
wrot_frm->bbp_uv >> 3);
|
|
|
|
msg = "Rotate 270 degree only";
|
|
} else if (dest->rotate == MML_ROT_270 && dest->flip) {
|
|
if (mode == MML_MODE_RACING) {
|
|
sram_block = (tout->h_tile_cnt - tout->tiles[idx].h_tile_no - 1) & 0x1;
|
|
out_w = tile->out.xe + 1;
|
|
tile_eol = tout->tiles[idx].v_tile_no == 0;
|
|
}
|
|
/* Target Y offset */
|
|
ofst->y = (out_w - out_xs - 1) *
|
|
wrot_frm->y_stride +
|
|
((out_h - out_ys) *
|
|
wrot_frm->bbp_y >> 3) - 1;
|
|
|
|
/* Target U offset */
|
|
ofst->c = ((out_w - out_xs - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
(((out_h - out_ys) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
/* Target V offset */
|
|
ofst->v = ((out_w - out_xs - 1) >>
|
|
wrot_frm->ver_sh_uv) * wrot_frm->uv_stride +
|
|
(((out_h - out_ys) >>
|
|
wrot_frm->hor_sh_uv) * wrot_frm->bbp_uv >> 3) - 1;
|
|
|
|
msg = "Flip and Rotate 270 degree";
|
|
}
|
|
|
|
if (mode == MML_MODE_RACING) {
|
|
ofst->y += wrot->data->sram_size * sram_block;
|
|
ofst->c += wrot->data->sram_size * sram_block;
|
|
ofst->v += wrot->data->sram_size * sram_block;
|
|
wrot_frm->wdone[idx].sram = sram_block;
|
|
wrot_frm->wdone[idx].eol = tile_eol;
|
|
tout->tiles[idx].eol = tile_eol;
|
|
}
|
|
|
|
mml_msg("%s %s: offset Y:%#010llx U:%#010llx V:%#010llx h:%hu/%hu v:%hu/%hu (%u%s)",
|
|
__func__, msg, ofst->y, ofst->c, ofst->v,
|
|
tout->tiles[idx].h_tile_no, tout->h_tile_cnt,
|
|
tout->tiles[idx].v_tile_no, tout->v_tile_cnt, sram_block,
|
|
tile_eol ? " eol" : "");
|
|
}
|
|
|
|
static void wrot_check_buf(const struct mml_frame_dest *dest,
|
|
struct wrot_setting *setting,
|
|
struct check_buf_param *buf)
|
|
{
|
|
/* Checking Y buffer usage
|
|
* y_buf_width is just larger than main_blk_width
|
|
*/
|
|
buf->y_buf_width = ceil_m(setting->main_blk_width,
|
|
setting->main_buf_line_num) *
|
|
setting->main_buf_line_num;
|
|
buf->y_buf_usage = buf->y_buf_width * setting->main_buf_line_num;
|
|
if (buf->y_buf_usage > buf->y_buf_size) {
|
|
setting->main_buf_line_num = setting->main_buf_line_num - 4;
|
|
buf->y_buf_check = 0;
|
|
buf->uv_buf_check = 0;
|
|
return;
|
|
} else {
|
|
buf->y_buf_check = 1;
|
|
}
|
|
|
|
/* Checking UV buffer usage */
|
|
if (!MML_FMT_H_SUBSAMPLE(dest->data.format)) {
|
|
buf->uv_blk_width = setting->main_blk_width;
|
|
buf->uv_blk_line = setting->main_buf_line_num;
|
|
} else {
|
|
if (!MML_FMT_V_SUBSAMPLE(dest->data.format)) {
|
|
/* YUV422 */
|
|
if (dest->rotate == MML_ROT_0 ||
|
|
dest->rotate == MML_ROT_180) {
|
|
buf->uv_blk_width =
|
|
setting->main_blk_width >> 1;
|
|
buf->uv_blk_line = setting->main_buf_line_num;
|
|
} else {
|
|
buf->uv_blk_width = setting->main_blk_width;
|
|
buf->uv_blk_line =
|
|
setting->main_buf_line_num >> 1;
|
|
}
|
|
} else {
|
|
/* YUV420 */
|
|
buf->uv_blk_width = setting->main_blk_width >> 1;
|
|
buf->uv_blk_line = setting->main_buf_line_num >> 1;
|
|
}
|
|
}
|
|
|
|
buf->uv_buf_width = ceil_m(buf->uv_blk_width, buf->uv_blk_line) *
|
|
buf->uv_blk_line;
|
|
buf->uv_buf_usage = buf->uv_buf_width * buf->uv_blk_line;
|
|
if (buf->uv_buf_usage > buf->uv_buf_size) {
|
|
setting->main_buf_line_num = setting->main_buf_line_num - 4;
|
|
buf->y_buf_check = 0;
|
|
buf->uv_buf_check = 0;
|
|
} else {
|
|
buf->uv_buf_check = 1;
|
|
}
|
|
}
|
|
|
|
static void wrot_calc_setting(struct mml_comp_wrot *wrot,
|
|
const struct mml_frame_dest *dest,
|
|
const struct wrot_frame_data *wrot_frm,
|
|
struct wrot_setting *setting)
|
|
{
|
|
u32 hw_fmt = MML_FMT_HW_FORMAT(dest->data.format);
|
|
u32 tile_width = wrot->data->tile_width;
|
|
u32 coeff1, coeff2, temp;
|
|
struct check_buf_param buf = {0};
|
|
|
|
if (hw_fmt == 9 || hw_fmt == 13) {
|
|
buf.y_buf_size = tile_width * 48;
|
|
buf.uv_buf_size = tile_width / 2 * 48;
|
|
} else if (hw_fmt == 8 || hw_fmt == 12) {
|
|
buf.y_buf_size = tile_width * 64;
|
|
buf.uv_buf_size = tile_width / 2 * 32;
|
|
} else {
|
|
buf.y_buf_size = tile_width * 32;
|
|
buf.uv_buf_size = tile_width * 32;
|
|
}
|
|
|
|
/* Default value */
|
|
setting->main_buf_line_num = 0;
|
|
/* Allocate FIFO buffer */
|
|
setting->main_blk_width = setting->tar_xsize;
|
|
|
|
coeff1 = floor_m(wrot_frm->fifo_max_sz, setting->tar_xsize * 2) * 2;
|
|
coeff2 = ceil_m(setting->tar_xsize, coeff1);
|
|
temp = ceil_m(setting->tar_xsize, coeff2 * 4) * 4;
|
|
|
|
if (temp > setting->tar_xsize)
|
|
setting->main_buf_line_num = ceil_m(setting->tar_xsize, 4) * 4;
|
|
else
|
|
setting->main_buf_line_num = temp;
|
|
if (setting->main_buf_line_num > wrot_frm->max_line_cnt)
|
|
setting->main_buf_line_num = wrot_frm->max_line_cnt;
|
|
|
|
/* check for internal buffer size */
|
|
while (!buf.y_buf_check || !buf.uv_buf_check)
|
|
wrot_check_buf(dest, setting, &buf);
|
|
}
|
|
|
|
static s32 wrot_config_tile(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg, u32 idx)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
u32 plane;
|
|
|
|
/* frame data should not change between each tile */
|
|
const struct mml_frame_dest *dest = &cfg->info.dest[wrot_frm->out_idx];
|
|
const phys_addr_t base_pa = comp->base_pa;
|
|
const u32 dest_fmt = dest->data.format;
|
|
|
|
struct mml_tile_engine *tile = config_get_tile(cfg, ccfg, idx);
|
|
const struct mml_tile_output *tout = cfg->tile_output[ccfg->pipe];
|
|
/* Following data retrieve from tile result */
|
|
const u32 in_xs = tile->in.xs;
|
|
const u32 in_xe = tile->in.xe;
|
|
const u32 in_ys = tile->in.ys;
|
|
const u32 in_ye = tile->in.ye;
|
|
const u32 out_xs = tile->out.xs;
|
|
const u32 out_xe = tile->out.xe;
|
|
const u32 out_ys = tile->out.ys;
|
|
const u32 out_ye = tile->out.ye;
|
|
const u32 wrot_crop_ofst_x = tile->luma.x;
|
|
const u32 wrot_crop_ofst_y = tile->luma.y;
|
|
|
|
u32 wrot_in_xsize;
|
|
u32 wrot_in_ysize;
|
|
u32 wrot_tar_xsize;
|
|
u32 wrot_tar_ysize;
|
|
struct wrot_ofst_addr ofst = {0};
|
|
struct wrot_setting setting = {0};
|
|
u32 buf_line_num;
|
|
|
|
/* Fill the the tile settings */
|
|
if (MML_FMT_COMPRESS(dest_fmt))
|
|
wrot_tile_calc_comp(dest, wrot_frm, tile, &ofst);
|
|
else
|
|
wrot_tile_calc(task, wrot, dest, tout, tile, idx, cfg->info.mode,
|
|
wrot_frm, &ofst);
|
|
|
|
if (cfg->info.mode == MML_MODE_RACING) {
|
|
/* enable inline rotate and config buffer 0 or 1 */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_IN_LINE_ROT,
|
|
(wrot_frm->wdone[idx].sram << 1) | 0x1, U32_MAX);
|
|
}
|
|
|
|
/* Write Y pixel offset */
|
|
wrot_write_ofst(pkt,
|
|
base_pa + VIDO_OFST_ADDR,
|
|
base_pa + VIDO_OFST_ADDR_HIGH, ofst.y);
|
|
/* Write U pixel offset */
|
|
wrot_write_ofst(pkt,
|
|
base_pa + VIDO_OFST_ADDR_C,
|
|
base_pa + VIDO_OFST_ADDR_HIGH_C, ofst.c);
|
|
/* Write V pixel offset */
|
|
wrot_write_ofst(pkt,
|
|
base_pa + VIDO_OFST_ADDR_V,
|
|
base_pa + VIDO_OFST_ADDR_HIGH_V, ofst.v);
|
|
|
|
/* Write source size */
|
|
wrot_in_xsize = in_xe - in_xs + 1;
|
|
wrot_in_ysize = in_ye - in_ys + 1;
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_IN_SIZE,
|
|
(wrot_in_ysize << 16) + (wrot_in_xsize << 0),
|
|
U32_MAX);
|
|
|
|
/* Write target size */
|
|
wrot_tar_xsize = out_xe - out_xs + 1;
|
|
wrot_tar_ysize = out_ye - out_ys + 1;
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_TAR_SIZE,
|
|
(wrot_tar_ysize << 16) + (wrot_tar_xsize << 0),
|
|
U32_MAX);
|
|
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_CROP_OFST,
|
|
(wrot_crop_ofst_y << 16) + (wrot_crop_ofst_x << 0),
|
|
U32_MAX);
|
|
|
|
/* set max internal buffer for tile usage,
|
|
* and check for internal buffer size
|
|
*/
|
|
setting.tar_xsize = wrot_tar_xsize;
|
|
wrot_calc_setting(wrot, dest, wrot_frm, &setting);
|
|
if (cfg->info.mode == MML_MODE_RACING) {
|
|
/* line number for inline always set 16,
|
|
* since sram has no latency
|
|
*/
|
|
buf_line_num = WROT_MIN_BUF_LINE_NUM;
|
|
} else {
|
|
/* line number for each tile calculated by format */
|
|
buf_line_num = setting.main_buf_line_num;
|
|
}
|
|
|
|
cmdq_pkt_write(pkt, NULL, base_pa + VIDO_MAIN_BUF_SIZE,
|
|
(setting.main_blk_width << 16) |
|
|
(buf_line_num << 8) |
|
|
(wrot_frm->filt_v << 4), U32_MAX);
|
|
|
|
/* Set wrot interrupt bit for debug,
|
|
* this bit will clear to 0 after wrot done.
|
|
*
|
|
* cmdq_pkt_write(pkt, NULL, base_pa + VIDO_INT, 0x1, U32_MAX);
|
|
*/
|
|
|
|
/* qos accumulate tile pixel */
|
|
wrot_frm->pixel_acc += wrot_tar_xsize * wrot_tar_ysize;
|
|
|
|
/* no bandwidth for racing mode since wrot write to sram */
|
|
if (cfg->info.mode != MML_MODE_RACING) {
|
|
/* calculate qos for later use */
|
|
plane = MML_FMT_PLANE(dest->data.format);
|
|
wrot_frm->datasize += mml_color_get_min_y_size(dest->data.format,
|
|
wrot_tar_xsize, wrot_tar_ysize);
|
|
if (plane > 1)
|
|
wrot_frm->datasize += mml_color_get_min_uv_size(dest->data.format,
|
|
wrot_tar_xsize, wrot_tar_ysize);
|
|
if (plane > 2)
|
|
wrot_frm->datasize += mml_color_get_min_uv_size(dest->data.format,
|
|
wrot_tar_xsize, wrot_tar_ysize);
|
|
}
|
|
|
|
mml_msg("%s min block width: %u min buf line num: %u",
|
|
__func__, setting.main_blk_width, setting.main_buf_line_num);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void mml_ir_done_2to1(struct mml_comp_wrot *wrot, bool disp_dual,
|
|
struct cmdq_pkt *pkt, u32 pipe, u32 sram, u32 irot_h_off, u32 height)
|
|
{
|
|
u32 wdone = 1 << sram;
|
|
|
|
if (pipe == 0) {
|
|
if (sram == 0)
|
|
cmdq_pkt_wfe(pkt, wrot->event_bufa);
|
|
else
|
|
cmdq_pkt_wfe(pkt, wrot->event_bufb);
|
|
/* for pipe 0, wait pipe 1 and trigger wdone */
|
|
cmdq_pkt_write(pkt, NULL, wrot->irot_base[0] + irot_h_off,
|
|
height, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, wrot->irot_base[0] + INLINEROT_WDONE,
|
|
wdone, U32_MAX);
|
|
if (disp_dual) {
|
|
cmdq_pkt_write(pkt, NULL, wrot->irot_base[1] + irot_h_off,
|
|
height, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, wrot->irot_base[1] + INLINEROT_WDONE,
|
|
wdone, U32_MAX);
|
|
}
|
|
if (sram == 1)
|
|
cmdq_pkt_set_event(pkt, wrot->event_buf_next);
|
|
} else {
|
|
if (sram == 0) {
|
|
/* notify pipe0 buf a */
|
|
cmdq_pkt_set_event(pkt, wrot->event_bufa);
|
|
} else {
|
|
/* notify pipe0 buf b and wait for loop,
|
|
* this prevent event set twice or buf race condition
|
|
*/
|
|
cmdq_pkt_set_event(pkt, wrot->event_bufb);
|
|
cmdq_pkt_wfe(pkt, wrot->event_buf_next);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void wrot_config_inlinerot(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg, u32 idx)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct mml_frame_dest *dest = &cfg->info.dest[wrot_frm->out_idx];
|
|
struct mml_tile_engine *tile = config_get_tile(cfg, ccfg, idx);
|
|
u32 height;
|
|
u32 irot_h_off;
|
|
|
|
if (dest->rotate == MML_ROT_0 || dest->rotate == MML_ROT_180)
|
|
height = tile->out.ye - tile->out.ys + 1;
|
|
else
|
|
height = tile->out.xe - tile->out.xs + 1;
|
|
|
|
/* config height for current sram buf
|
|
* INLINEROT_HEIGHT0 for buf a and
|
|
* INLINEROT_HEIGHT1 for buf b
|
|
* so assign reg by sram side
|
|
*/
|
|
irot_h_off = INLINEROT_HEIGHT0 + 4 * wrot_frm->wdone[idx].sram;
|
|
|
|
/* config wdone to trigger inlinerot work */
|
|
if (cfg->dual) {
|
|
/* 2 wrot to 1 disp: wait and trigger 1 wdone
|
|
* 2 wrot to 2 disp: wrot0 and wrot1 sync first
|
|
*/
|
|
mml_ir_done_2to1(wrot, cfg->disp_dual, pkt, ccfg->pipe,
|
|
wrot_frm->wdone[idx].sram, irot_h_off, height);
|
|
} else if (!cfg->dual && cfg->disp_dual) {
|
|
/* 1 wrot to 2 disp: trigger 2 wdone (dual done) */
|
|
cmdq_pkt_write(pkt, NULL, wrot->irot_base[0] + irot_h_off,
|
|
height, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[0] + INLINEROT_WDONE,
|
|
1 << wrot_frm->wdone[idx].sram, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, wrot->irot_base[1] + irot_h_off,
|
|
height, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[1] + INLINEROT_WDONE,
|
|
1 << wrot_frm->wdone[idx].sram, U32_MAX);
|
|
} else {
|
|
/* 1 wrot to 1 disp: trigger 1 wdone (by pipe)
|
|
* both case set disp wdone for current pipe
|
|
*/
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[wrot_frm->sram_side] + irot_h_off,
|
|
height, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL,
|
|
wrot->irot_base[wrot_frm->sram_side] + INLINEROT_WDONE,
|
|
1 << wrot_frm->wdone[idx].sram, U32_MAX);
|
|
}
|
|
|
|
/* debug, make gce send irq to cmdq and mark mmp pulse */
|
|
if (unlikely(mml_racing_wdone_eoc))
|
|
cmdq_pkt_eoc(pkt, false);
|
|
}
|
|
|
|
static s32 wrot_wait(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg, u32 idx)
|
|
{
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
|
|
/* wait wrot frame done */
|
|
cmdq_pkt_wfe(pkt, wrot->event_eof);
|
|
|
|
if (task->config->info.mode == MML_MODE_RACING && wrot_frm->wdone[idx].eol) {
|
|
wrot_config_inlinerot(comp, task, ccfg, idx);
|
|
wrot_frm->wdone_cnt++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 wrot_post(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct mml_pipe_cache *cache = &task->config->cache[ccfg->pipe];
|
|
|
|
/* accmulate data size and use max pixel */
|
|
cache->total_datasize += wrot_frm->datasize;
|
|
cache->max_pixel = max(cache->max_pixel, wrot_frm->pixel_acc);
|
|
|
|
mml_msg("%s task %p pipe %hhu data %u pixel %u eol %u",
|
|
__func__, task, ccfg->pipe, wrot_frm->datasize, wrot_frm->pixel_acc,
|
|
wrot_frm->wdone_cnt);
|
|
|
|
if (task->config->info.mode == MML_MODE_RACING) {
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
|
|
/* clear path sel back to dram */
|
|
cmdq_pkt_write(task->pkts[ccfg->pipe], NULL, wrot->smi_larb_con,
|
|
0, GENMASK(19, 16));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 update_frame_addr(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
struct mml_frame_dest *dest = &cfg->info.dest[wrot_frm->out_idx];
|
|
struct mml_task_reuse *reuse = &task->reuse[ccfg->pipe];
|
|
|
|
const u32 dest_fmt = dest->data.format;
|
|
const u32 out_swap = MML_FMT_SWAP(dest_fmt);
|
|
u64 addr_c, addr_v, addr;
|
|
|
|
if (out_swap == 1 && MML_FMT_PLANE(dest_fmt) == 3)
|
|
swap(wrot_frm->iova[1], wrot_frm->iova[2]);
|
|
|
|
if (dest->data.secure) {
|
|
/* TODO: for secure case setup plane offset and reg */
|
|
}
|
|
|
|
/* DMA_SUPPORT_AFBC */
|
|
if (MML_FMT_COMPRESS(dest_fmt)) {
|
|
u32 block_x;
|
|
|
|
/* Write frame base address */
|
|
calc_afbc_block(wrot_frm->bbp_y,
|
|
wrot_frm->y_stride, dest->data.vert_stride,
|
|
wrot_frm->iova, wrot_frm->plane_offset,
|
|
&block_x, &addr_c, &addr_v, &addr);
|
|
} else {
|
|
addr = wrot_frm->iova[0] + wrot_frm->plane_offset[0];
|
|
addr_c = wrot_frm->iova[1] + wrot_frm->plane_offset[1];
|
|
addr_v = wrot_frm->iova[2] + wrot_frm->plane_offset[2];
|
|
}
|
|
/* update frame base address to list */
|
|
wrot_update_addr(reuse,
|
|
wrot_frm->labels[WROT_LABEL_ADDR],
|
|
wrot_frm->labels[WROT_LABEL_ADDR_HIGH],
|
|
addr);
|
|
wrot_update_addr(reuse,
|
|
wrot_frm->labels[WROT_LABEL_ADDR_C],
|
|
wrot_frm->labels[WROT_LABEL_ADDR_HIGH_C],
|
|
addr_c);
|
|
wrot_update_addr(reuse,
|
|
wrot_frm->labels[WROT_LABEL_ADDR_V],
|
|
wrot_frm->labels[WROT_LABEL_ADDR_HIGH_V],
|
|
addr_v);
|
|
return 0;
|
|
}
|
|
|
|
static s32 wrot_reconfig_frame(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
/* for reconfig case, no need update addr */
|
|
if (task->config->info.mode == MML_MODE_RACING)
|
|
return 0;
|
|
return update_frame_addr(comp, task, ccfg);
|
|
}
|
|
|
|
static const struct mml_comp_config_ops wrot_cfg_ops = {
|
|
.prepare = wrot_prepare,
|
|
.buf_map = wrot_buf_map,
|
|
.buf_prepare = wrot_buf_prepare,
|
|
.buf_unprepare = wrot_buf_unprepare,
|
|
.get_label_count = wrot_get_label_count,
|
|
.frame = wrot_config_frame,
|
|
.tile = wrot_config_tile,
|
|
.wait = wrot_wait,
|
|
.post = wrot_post,
|
|
.reframe = wrot_reconfig_frame,
|
|
};
|
|
|
|
u32 wrot_datasize_get(struct mml_task *task, struct mml_comp_config *ccfg)
|
|
{
|
|
struct wrot_frame_data *wrot_frm = wrot_frm_data(ccfg);
|
|
|
|
return wrot_frm->datasize;
|
|
}
|
|
|
|
u32 wrot_format_get(struct mml_task *task, struct mml_comp_config *ccfg)
|
|
{
|
|
return task->config->info.dest[ccfg->node->out_idx].data.format;
|
|
}
|
|
|
|
static const struct mml_comp_hw_ops wrot_hw_ops = {
|
|
.pw_enable = &mml_comp_pw_enable,
|
|
.pw_disable = &mml_comp_pw_disable,
|
|
.clk_enable = &mml_comp_clk_enable,
|
|
.clk_disable = &mml_comp_clk_disable,
|
|
.qos_datasize_get = &wrot_datasize_get,
|
|
.qos_format_get = &wrot_format_get,
|
|
.qos_set = &mml_comp_qos_set,
|
|
.qos_clear = &mml_comp_qos_clear,
|
|
};
|
|
|
|
static const char *wrot_state(u32 state)
|
|
{
|
|
switch (state) {
|
|
case 0x0:
|
|
return "sof";
|
|
case 0x1:
|
|
return "frame done";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
static void wrot_debug_dump(struct mml_comp *comp)
|
|
{
|
|
void __iomem *base = comp->base;
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
u32 value[33];
|
|
u32 debug[33];
|
|
u32 dbg_id = 0, state, smi_req;
|
|
u32 shadow_ctrl;
|
|
u32 i;
|
|
|
|
mml_err("wrot component %u dump:", comp->id);
|
|
|
|
/* Enable shadow read working */
|
|
shadow_ctrl = readl(base + VIDO_SHADOW_CTRL);
|
|
shadow_ctrl |= 0x4;
|
|
writel(shadow_ctrl, base + VIDO_SHADOW_CTRL);
|
|
|
|
value[0] = readl(base + VIDO_CTRL);
|
|
value[1] = readl(base + VIDO_DMA_PERF);
|
|
value[2] = readl(base + VIDO_MAIN_BUF_SIZE);
|
|
value[3] = readl(base + VIDO_SOFT_RST);
|
|
value[4] = readl(base + VIDO_SOFT_RST_STAT);
|
|
value[5] = readl(base + VIDO_INT);
|
|
value[6] = readl(base + VIDO_IN_SIZE);
|
|
value[7] = readl(base + VIDO_CROP_OFST);
|
|
value[8] = readl(base + VIDO_TAR_SIZE);
|
|
value[9] = readl(base + VIDO_FRAME_SIZE);
|
|
value[10] = readl(base + VIDO_OFST_ADDR_HIGH);
|
|
value[11] = readl(base + VIDO_OFST_ADDR);
|
|
value[12] = readl(base + VIDO_OFST_ADDR_HIGH_C);
|
|
value[13] = readl(base + VIDO_OFST_ADDR_C);
|
|
value[14] = readl(base + VIDO_OFST_ADDR_HIGH_V);
|
|
value[15] = readl(base + VIDO_OFST_ADDR_V);
|
|
value[16] = readl(base + VIDO_STRIDE);
|
|
value[17] = readl(base + VIDO_STRIDE_C);
|
|
value[18] = readl(base + VIDO_STRIDE_V);
|
|
value[19] = readl(base + VIDO_CTRL_2);
|
|
value[20] = readl(base + VIDO_IN_LINE_ROT);
|
|
value[21] = readl(base + VIDO_EOL_SEL);
|
|
value[22] = readl(base + VIDO_ROT_EN);
|
|
value[23] = readl(base + VIDO_SHADOW_CTRL);
|
|
value[24] = readl(base + VIDO_PVRIC);
|
|
value[25] = readl(base + VIDO_SCAN_10BIT);
|
|
value[26] = readl(base + VIDO_PENDING_ZERO);
|
|
value[27] = readl(base + VIDO_BASE_ADDR_HIGH);
|
|
value[28] = readl(base + VIDO_BASE_ADDR);
|
|
value[29] = readl(base + VIDO_BASE_ADDR_HIGH_C);
|
|
value[30] = readl(base + VIDO_BASE_ADDR_C);
|
|
value[31] = readl(base + VIDO_BASE_ADDR_HIGH_V);
|
|
value[32] = readl(base + VIDO_BASE_ADDR_V);
|
|
|
|
/* debug id from 0x0100 ~ 0x2100, count 33 which is debug array size */
|
|
for (i = 0; i < ARRAY_SIZE(debug); i++) {
|
|
dbg_id += 0x100;
|
|
writel(dbg_id, base + VIDO_INT_EN);
|
|
debug[i] = readl(base + VIDO_DEBUG);
|
|
}
|
|
|
|
mml_err("VIDO_CTRL %#010x VIDO_DMA_PERF %#010x VIDO_MAIN_BUF_SIZE %#010x",
|
|
value[0], value[1], value[2]);
|
|
mml_err("VIDO_SOFT_RST %#010x VIDO_SOFT_RST_STAT %#010x VIDO_INT %#010x",
|
|
value[3], value[4], value[5]);
|
|
mml_err("VIDO_IN_SIZE %#010x VIDO_CROP_OFST %#010x VIDO_TAR_SIZE %#010x",
|
|
value[6], value[7], value[8]);
|
|
mml_err("VIDO_FRAME_SIZE %#010x",
|
|
value[9]);
|
|
mml_err("VIDO_OFST ADDR_HIGH %#010x ADDR %#010x",
|
|
value[10], value[11]);
|
|
mml_err("VIDO_OFST ADDR_HIGH_C %#010x ADDR_C %#010x",
|
|
value[12], value[13]);
|
|
mml_err("VIDO_OFST ADDR_HIGH_V %#010x ADDR_V %#010x",
|
|
value[14], value[15]);
|
|
mml_err("VIDO_STRIDE %#010x C %#010x V %#010x",
|
|
value[16], value[17], value[18]);
|
|
mml_err("VIDO_CTRL_2 %#010x VIDO_IN_LINE_ROT %#010x VIDO_EOL_SEL %#010x",
|
|
value[19], value[20], value[21]);
|
|
mml_err("VIDO_ROT_EN %#010x VIDO_SHADOW_CTRL %#010x",
|
|
value[22], value[23]);
|
|
mml_err("VIDO_PVRIC %#010x VIDO_SCAN_10BIT %#010x VIDO_PENDING_ZERO %#010x",
|
|
value[24], value[25], value[26]);
|
|
mml_err("VIDO_BASE ADDR_HIGH %#010x ADDR %#010x",
|
|
value[27], value[28]);
|
|
mml_err("VIDO_BASE ADDR_HIGH_C %#010x ADDR_C %#010x",
|
|
value[29], value[30]);
|
|
mml_err("VIDO_BASE ADDR_HIGH_V %#010x ADDR_V %#010x",
|
|
value[31], value[32]);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(debug) / 3; i++) {
|
|
mml_err("VIDO_DEBUG %02X %#010x VIDO_DEBUG %02X %#010x VIDO_DEBUG %02X %#010x",
|
|
i * 3 + 1, debug[i * 3],
|
|
i * 3 + 2, debug[i * 3 + 1],
|
|
i * 3 + 3, debug[i * 3 + 2]);
|
|
}
|
|
|
|
/* parse state */
|
|
mml_err("WROT crop_busy:%u req:%u valid:%u",
|
|
(debug[2] >> 1) & 0x1, (debug[2] >> 2) & 0x1,
|
|
(debug[2] >> 3) & 0x1);
|
|
state = debug[2] & 0x1;
|
|
smi_req = (debug[24] >> 30) & 0x1;
|
|
mml_err("WROT state: %#x (%s)", state, wrot_state(state));
|
|
mml_err("WROT x_cnt %u y_cnt %u",
|
|
debug[9] & 0xffff, (debug[9] >> 16) & 0xffff);
|
|
mml_err("WROT smi_req:%u => suggest to ask SMI help:%u", smi_req, smi_req);
|
|
|
|
/* inlinerot debug */
|
|
if (wrot->irot_va[0]) {
|
|
value[0] = readl(wrot->irot_va[0] + INLINEROT_OVLSEL);
|
|
mml_err("INLINEROT0 INLINEROT_OVLSEL %#x", value[0]);
|
|
}
|
|
if (wrot->irot_va[1]) {
|
|
value[1] = readl(wrot->irot_va[1] + INLINEROT_OVLSEL);
|
|
mml_err("INLINEROT1 INLINEROT_OVLSEL %#x", value[1]);
|
|
}
|
|
}
|
|
|
|
static void wrot_reset(struct mml_comp *comp, struct mml_frame_config *cfg, u32 pipe)
|
|
{
|
|
const struct mml_topology_path *path = cfg->path[pipe];
|
|
struct mml_comp_wrot *wrot = comp_to_wrot(comp);
|
|
|
|
if (cfg->info.mode == MML_MODE_RACING) {
|
|
cmdq_clear_event(path->clt->chan, wrot->event_bufa);
|
|
cmdq_clear_event(path->clt->chan, wrot->event_bufb);
|
|
cmdq_clear_event(path->clt->chan, wrot->event_buf_next);
|
|
}
|
|
}
|
|
|
|
static const struct mml_comp_debug_ops wrot_debug_ops = {
|
|
.dump = &wrot_debug_dump,
|
|
.reset = &wrot_reset,
|
|
};
|
|
|
|
static int mml_bind(struct device *dev, struct device *master, void *data)
|
|
{
|
|
struct mml_comp_wrot *wrot = dev_get_drvdata(dev);
|
|
struct drm_device *drm_dev = data;
|
|
s32 ret;
|
|
|
|
if (!drm_dev) {
|
|
ret = mml_register_comp(master, &wrot->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, &wrot->ddp_comp);
|
|
if (ret)
|
|
dev_err(dev, "Failed to register ddp component %s: %d\n",
|
|
dev->of_node->full_name, ret);
|
|
else
|
|
wrot->ddp_bound = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void mml_unbind(struct device *dev, struct device *master, void *data)
|
|
{
|
|
struct mml_comp_wrot *wrot = dev_get_drvdata(dev);
|
|
struct drm_device *drm_dev = data;
|
|
|
|
if (!drm_dev) {
|
|
mml_unregister_comp(master, &wrot->comp);
|
|
} else {
|
|
mml_ddp_comp_unregister(drm_dev, &wrot->ddp_comp);
|
|
wrot->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 = {
|
|
};
|
|
|
|
phys_addr_t mml_get_node_base_pa(struct platform_device *pdev, const char *name,
|
|
u32 idx, void __iomem **base)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct device_node *node;
|
|
struct resource res;
|
|
phys_addr_t base_pa = 0;
|
|
|
|
node = of_parse_phandle(dev->of_node, name, idx);
|
|
if (!node)
|
|
goto done;
|
|
|
|
if (of_address_to_resource(node, 0, &res))
|
|
goto done;
|
|
|
|
base_pa = res.start;
|
|
*base = of_iomap(node, 0);
|
|
mml_log("[wrot]%s%u %pa %p", name, idx, &base_pa, *base);
|
|
|
|
done:
|
|
if (node)
|
|
of_node_put(node);
|
|
return base_pa;
|
|
}
|
|
|
|
static struct mml_comp_wrot *dbg_probed_components[4];
|
|
static int dbg_probed_count;
|
|
|
|
static int probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct mml_comp_wrot *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);
|
|
priv->dev = dev;
|
|
|
|
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
|
|
if (ret)
|
|
dev_err(dev, "fail to config wrot dma mask %d\n", ret);
|
|
|
|
ret = mml_comp_init(pdev, &priv->comp);
|
|
if (ret) {
|
|
dev_err(dev, "Failed to init mml component: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* init larb for smi and mtcmos */
|
|
ret = mml_comp_init_larb(&priv->comp, dev);
|
|
if (ret) {
|
|
if (ret == -EPROBE_DEFER)
|
|
return ret;
|
|
dev_err(dev, "fail to init component %u larb ret %d",
|
|
priv->comp.id, ret);
|
|
}
|
|
|
|
/* store smi larb con register for later use */
|
|
priv->smi_larb_con = priv->comp.larb_base +
|
|
SMI_LARB_NON_SEC_CON + priv->comp.larb_port * 4;
|
|
mutex_init(&priv->sram_mutex);
|
|
|
|
of_property_read_u16(dev->of_node, "event_frame_done",
|
|
&priv->event_eof);
|
|
of_property_read_u16(dev->of_node, "event_bufa",
|
|
&priv->event_bufa);
|
|
of_property_read_u16(dev->of_node, "event_bufb",
|
|
&priv->event_bufb);
|
|
of_property_read_u16(dev->of_node, "event_buf_next",
|
|
&priv->event_buf_next);
|
|
|
|
/* get index of wrot by alias */
|
|
priv->idx = of_alias_get_id(dev->of_node, "mml_wrot");
|
|
|
|
/* parse inline rot node for racing mode */
|
|
priv->irot_base[0] = mml_get_node_base_pa(pdev, "inlinerot", 0, &priv->irot_va[0]);
|
|
priv->irot_base[1] = mml_get_node_base_pa(pdev, "inlinerot", 1, &priv->irot_va[1]);
|
|
|
|
/* assign ops */
|
|
priv->comp.tile_ops = &wrot_tile_ops;
|
|
priv->comp.config_ops = &wrot_cfg_ops;
|
|
priv->comp.hw_ops = &wrot_hw_ops;
|
|
priv->comp.debug_ops = &wrot_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);
|
|
|
|
mml_log("wrot%d (%u) smi larb con %#lx event eof %hu sync %hu/%hu/%hu",
|
|
priv->idx, priv->comp.id, priv->smi_larb_con,
|
|
priv->event_eof,
|
|
priv->event_bufa,
|
|
priv->event_bufb,
|
|
priv->event_buf_next);
|
|
|
|
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_wrot_driver_dt_match[] = {
|
|
{
|
|
.compatible = "mediatek,mt6983-mml_wrot",
|
|
.data = &mml_wrot_data,
|
|
},
|
|
{
|
|
.compatible = "mediatek,mt6893-mml_wrot",
|
|
.data = &mml_wrot_data
|
|
},
|
|
{
|
|
.compatible = "mediatek,mt6879-mml_wrot",
|
|
.data = &mml_wrot_data
|
|
},
|
|
{
|
|
.compatible = "mediatek,mt6895-mml_wrot",
|
|
.data = &mml_wrot_data
|
|
},
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mml_wrot_driver_dt_match);
|
|
|
|
struct platform_driver mml_wrot_driver = {
|
|
.probe = probe,
|
|
.remove = remove,
|
|
.driver = {
|
|
.name = "mediatek-mml-wrot",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = mml_wrot_driver_dt_match,
|
|
},
|
|
};
|
|
|
|
//module_platform_driver(mml_wrot_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(wrot_debug, &dbg_param_ops, NULL, 0644);
|
|
MODULE_PARM_DESC(wrot_debug, "mml wrot debug case");
|
|
|
|
MODULE_AUTHOR("Dennis-YC Hsieh <dennis-yc.hsieh@mediatek.com>");
|
|
MODULE_DESCRIPTION("MediaTek SoC display MML WROT driver");
|
|
MODULE_LICENSE("GPL v2");
|