media: rockchip: vpss: offline mode support auto unite output

Change-Id: I234f7c5af53e855e0faebf791d3db74d94e33022
Signed-off-by: Wei Dun <willam.wei@rock-chips.com>
This commit is contained in:
Wei Dun
2025-06-24 11:12:25 +08:00
committed by Tao Huang
parent e8cba62d56
commit 2cd7ed573f
2 changed files with 154 additions and 30 deletions

View File

@@ -296,8 +296,17 @@
/* SCALE_CTRL */
#define RKVPSS2X_SW_SCL_HY_EN BIT(0)
#define RKVPSS2X_SW_SCL_HC_EN BIT(1)
#define RKVPSS2X_SW_SCL_VY_EN BIT(2)
#define RKVPSS2X_SW_SCL_VC_EN BIT(3)
#define RKVPSS2X_SW_AVG_SCALE_H_EN BIT(8)
#define RKVPSS2X_SW_AVG_SCALE_V_EN BIT(9)
#define RKVPSS2X_SW_SCL_HPHASE_EN BIT(12)
#define RKVPSS2X_SW_SCL_CLIP_EN BIT(13)
#define RKVPSS2X_SW_SCL_IN_CLIP_EN BIT(14)
#define RKVPSS2X_SW_SCL_422TO420_EN BIT(30)
#define RKVPSS2X_SW_SCL_YUV420_REAL_EN BIT(31)
/* MI_FORCE_UPDATE */
#define RKVPSS2X_MI_CHN4_FORCE_UPD BIT(8)

View File

@@ -324,32 +324,124 @@ static void average_scale_down(struct rkvpss_frame_cfg *frame_cfg,
rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CLK_GATE, clk_mask, clk_mask);
if (!unite) {
if (in_w == out_w && in_h == out_w)
if (in_w == out_w && in_h == out_h)
goto end;
val = in_w | (in_h << 16);
rkvpss_hw_write(hw, reg_base + 0x8, val);
rkvpss_hw_write(hw, reg_base + 0x8, val); /* input size */
val = out_w | (out_h << 16);
rkvpss_hw_write(hw, reg_base + 0xc, val);
rkvpss_hw_write(hw, reg_base + 0xc, val); /* output size */
if (in_w != out_w) {
val = (out_w - 1) * 65536 / (in_w - 1) + 1;
rkvpss_hw_write(hw, reg_base + 0x10, val);
val = (out_w / 2 - 1) * 65536 / (in_w / 2 - 1) + 1;
rkvpss_hw_write(hw, reg_base + 0x14, val);
ctrl |= RKVPSS_SCL_HY_EN | RKVPSS_SCL_HC_EN | RKVPSS2X_SW_AVG_SCALE_H_EN;
rkvpss_hw_write(hw, reg_base + 0x10, val); /* y_w_fac */
rkvpss_hw_write(hw, reg_base + 0x14, val); /* c_w_fac */
ctrl |= RKVPSS2X_SW_SCL_HY_EN | RKVPSS2X_SW_SCL_HC_EN |
RKVPSS2X_SW_AVG_SCALE_H_EN;
}
if (in_h != out_h) {
val = (out_h - 1) * 65536 / (in_h - 1) + 1;
rkvpss_hw_write(hw, reg_base + 0x18, val);
val = (out_h - 1) * 65536 / (in_h - 1) + 1;
rkvpss_hw_write(hw, reg_base + 0x1c, val);
rkvpss_hw_write(hw, reg_base + 0x18, val); /* y_h_fac */
rkvpss_hw_write(hw, reg_base + 0x1c, val); /* c_h_fac */
ctrl |= RKVPSS2X_SW_SCL_VY_EN | RKVPSS2X_SW_SCL_VC_EN |
RKVPSS2X_SW_AVG_SCALE_V_EN;
}
} else {
u32 in_width = cfg->crop_width / 2;
u32 out_width = cfg->scl_width / 2;
u32 overlap = UNITE_ENLARGE;
ctrl |= RKVPSS_SCL_VY_EN | RKVPSS_SCL_VC_EN | RKVPSS2X_SW_AVG_SCALE_V_EN;
if (left) {
/* Left side processing */
rkvpss_hw_write(hw, reg_base + 0x50, 0); /* in_crop_offs */
rkvpss_hw_write(hw, reg_base + 0x20, 0); /* hy_offs */
rkvpss_hw_write(hw, reg_base + 0x24, 0); /* hc_offs */
rkvpss_hw_write(hw, reg_base + 0x28, 0); /* vy_offs */
rkvpss_hw_write(hw, reg_base + 0x2c, 0); /* vc_offs */
rkvpss_hw_write(hw, reg_base + 0x48, 0); /* hy_offs_mi */
rkvpss_hw_write(hw, reg_base + 0x4c, 0); /* hc_offs_mi */
u32 in_w_for_hw = (in_width == out_width) ? in_width : (in_width + overlap);
u32 aligned_width = ALIGN(in_w_for_hw, 16);
val = aligned_width | (cfg->crop_height << 16);
rkvpss_hw_write(hw, reg_base + 0x8, val); /* input size */
aligned_width = ALIGN(out_width, 16);
val = aligned_width | (cfg->scl_height << 16);
rkvpss_hw_write(hw, reg_base + 0xc, val); /* output size */
ctrl |= RKVPSS2X_SW_SCL_CLIP_EN;
} else {
/* Right side processing */
val = ofl->unite_params[idx].scl_in_crop_w_y |
(ofl->unite_params[idx].scl_in_crop_w_c << 4);
rkvpss_hw_write(hw, reg_base + 0x50, val); /* in_crop_offs */
ctrl |= RKVPSS2X_SW_SCL_HPHASE_EN;
u32 y_phase = ofl->unite_params[idx].y_w_phase;
u32 c_phase = ofl->unite_params[idx].c_w_phase;
rkvpss_hw_write(hw, reg_base + 0x20, y_phase); /* hy_offs */
rkvpss_hw_write(hw, reg_base + 0x24, c_phase); /* hc_offs */
rkvpss_hw_write(hw, reg_base + 0x28, 0); /* vy_offs */
rkvpss_hw_write(hw, reg_base + 0x2c, 0); /* vc_offs */
val = 16 - (cfg->scl_width / 2 & 0xf);
if (val == 16)
val = 0;
rkvpss_hw_write(hw, reg_base + 0x48, val); /* hy_offs_mi */
rkvpss_hw_write(hw, reg_base + 0x4c, val); /* hc_offs_mi */
u32 in_w_for_hw = (in_width == out_width) ? in_width : (in_width + overlap);
u32 aligned_width = ALIGN(in_w_for_hw, 16);
val = aligned_width | (cfg->crop_height << 16);
rkvpss_hw_write(hw, reg_base + 0x8, val); /* input size */
aligned_width = ALIGN(out_width, 16);
val = aligned_width | (cfg->scl_height << 16);
rkvpss_hw_write(hw, reg_base + 0xc, val); /* output size */
v4l2_dbg(1, rkvpss_debug, &ofl->v4l2_dev,
"Right side: in_w=%d out_w=%d y_phase=0x%x c_phase=0x%x mi_offset=0x%x\n",
aligned_width, out_width, y_phase, c_phase, val);
if (in_width != out_width) {
ctrl |= RKVPSS2X_SW_SCL_HY_EN | RKVPSS2X_SW_SCL_HC_EN |
RKVPSS2X_SW_AVG_SCALE_H_EN;
}
if (cfg->crop_height != cfg->scl_height) {
ctrl |= RKVPSS2X_SW_SCL_VY_EN | RKVPSS2X_SW_SCL_VC_EN |
RKVPSS2X_SW_AVG_SCALE_V_EN;
}
if (overlap > 0) {
ctrl |= RKVPSS2X_SW_SCL_CLIP_EN;
if (aligned_width > out_width)
ctrl |= RKVPSS2X_SW_SCL_IN_CLIP_EN;
}
}
if (cfg->scl_width != frame_cfg->input.width) {
val = ofl->unite_params[idx].y_w_fac;
rkvpss_hw_write(hw, reg_base + 0x10, val); /* y_w_fac */
val = ofl->unite_params[idx].c_w_fac;
rkvpss_hw_write(hw, reg_base + 0x14, val); /* c_w_fac */
ctrl |= RKVPSS2X_SW_SCL_HY_EN | RKVPSS2X_SW_SCL_HC_EN |
RKVPSS2X_SW_AVG_SCALE_H_EN;
}
if (cfg->scl_height != frame_cfg->input.height) {
val = ofl->unite_params[idx].y_h_fac;
rkvpss_hw_write(hw, reg_base + 0x18, val); /* y_h_fac */
val = ofl->unite_params[idx].c_h_fac;
rkvpss_hw_write(hw, reg_base + 0x1c, val); /* c_h_fac */
ctrl |= RKVPSS2X_SW_SCL_VY_EN | RKVPSS2X_SW_SCL_VC_EN |
RKVPSS2X_SW_AVG_SCALE_V_EN;
}
}
//unite todo
end:
rkvpss_hw_write(hw, reg_base, ctrl);
@@ -410,7 +502,7 @@ static void bilinear_scale(struct rkvpss_frame_cfg *frame_cfg,
rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CLK_GATE, clk_mask, clk_mask);
if (!unite) {
if (in_w == out_w && in_h == out_w)
if (in_w == out_w && in_h == out_h)
goto end;
/* TODO diff for input and output format */
@@ -507,14 +599,42 @@ static void scale_config(struct rkvpss_offline_dev *ofl,
struct rkvpss_frame_cfg *cfg, bool unite, bool left)
{
int i;
bool is_downscale_w;
bool is_downscale_h;
bool use_average;
for (i = 0; i < RKVPSS_OUT_V20_MAX; i++) {
if (!cfg->output[i].enable)
continue;
if ((i == 0 || i == 2) && cfg->output[i].avg_scl_down)
average_scale_down(cfg, ofl, &cfg->output[i], i, unite, left);
else
bilinear_scale(cfg, ofl, &cfg->output[i], i, unite, left);
is_downscale_w = cfg->output[i].scl_width <= cfg->output[i].crop_width;
is_downscale_h = cfg->output[i].scl_height <= cfg->output[i].crop_height;
use_average = is_downscale_w && is_downscale_h;
/* channel 0 and 2 use average_scale_down when downscale */
if (use_average && (i == RKVPSS_OUTPUT_CH0 || i == RKVPSS_OUTPUT_CH2)) {
if (unite) {
v4l2_dbg(2, rkvpss_debug, &ofl->v4l2_dev,
"Unite mode: average_scale_down for channel %d\n", i);
average_scale_down(cfg, ofl, &cfg->output[i], i, true, true);
average_scale_down(cfg, ofl, &cfg->output[i], i, true, false);
} else {
v4l2_dbg(2, rkvpss_debug, &ofl->v4l2_dev,
"Normal mode: average_scale_down for channel %d\n", i);
average_scale_down(cfg, ofl, &cfg->output[i], i, false, false);
}
} else {
/* use bilinear_scale for other channels */
if (unite) {
v4l2_dbg(2, rkvpss_debug, &ofl->v4l2_dev,
"Unite mode: bilinear_scale for channel %d\n", i);
bilinear_scale(cfg, ofl, &cfg->output[i], i, true, true);
bilinear_scale(cfg, ofl, &cfg->output[i], i, true, false);
} else {
v4l2_dbg(2, rkvpss_debug, &ofl->v4l2_dev,
"Normal mode: bilinear_scale for channel %d\n", i);
bilinear_scale(cfg, ofl, &cfg->output[i], i, false, false);
}
}
}
}
@@ -1912,12 +2032,6 @@ int rkvpss_check_params(struct rkvpss_offline_dev *ofl,
goto end;
}
/* set unite mode */
if (cfg->input.width > RKVPSS_MAX_WIDTH_V20)
*unite = true;
else
*unite = false;
/* check input format */
switch (cfg->input.format) {
case V4L2_PIX_FMT_NV16:
@@ -2044,6 +2158,12 @@ int rkvpss_check_params(struct rkvpss_offline_dev *ofl,
goto end;
}
/* set unite mode */
if (out_width > RKVPSS_MAX_WIDTH_V20)
*unite = true;
else
*unite = false;
/* check crop */
cfg->output[i].crop_h_offs = ALIGN(cfg->output[i].crop_h_offs, 2);
cfg->output[i].crop_v_offs = ALIGN(cfg->output[i].crop_v_offs, 2);
@@ -2233,12 +2353,7 @@ int rkvpss_check_params(struct rkvpss_offline_dev *ofl,
ret = -EINVAL;
goto end;
}
if (cfg->output[i].scl_width > cfg->input.width) {
v4l2_err(&ofl->v4l2_dev, "dev_id:%d unite horizontal no support scale up\n",
cfg->dev_id);
ret = -EINVAL;
goto end;
}
if (cfg->output[i].aspt.enable) {
v4l2_err(&ofl->v4l2_dev, "dev_id:%d unite no support aspt\n",
cfg->dev_id);