From fa4c12dab89021e2f206c8173beb7c1e7f454200 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Sat, 15 Jun 2024 13:59:01 +0800 Subject: [PATCH 01/10] media: i2c: rk628: fix YUV format color range detect Signed-off-by: Jianwei Fan Change-Id: Ifac5d10823b7b5a0da875032cb4ff8c8492762c0 --- drivers/media/i2c/rk628/rk628.c | 2 +- drivers/media/i2c/rk628/rk628_hdmirx.c | 19 +++++++++++++++++-- drivers/media/i2c/rk628/rk628_hdmirx.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628.c b/drivers/media/i2c/rk628/rk628.c index adb2d128450a..95c97944adc1 100644 --- a/drivers/media/i2c/rk628/rk628.c +++ b/drivers/media/i2c/rk628/rk628.c @@ -76,8 +76,8 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = { regmap_reg_range(HDMI_RX_PDEC_STS, HDMI_RX_PDEC_STS), regmap_reg_range(HDMI_RX_PDEC_GCP_AVMUTE, HDMI_RX_PDEC_GCP_AVMUTE), regmap_reg_range(HDMI_RX_PDEC_ACR_CTS, HDMI_RX_PDEC_ACR_N), + regmap_reg_range(HDMI_RX_PDEC_AVI_HB, HDMI_RX_PDEC_AVI_PB), regmap_reg_range(HDMI_RX_PDEC_AIF_CTRL, HDMI_RX_PDEC_AIF_PB0), - regmap_reg_range(HDMI_RX_PDEC_AVI_PB, HDMI_RX_PDEC_AVI_PB), regmap_reg_range(HDMI_RX_HDMI20_CONTROL, HDMI_RX_CHLOCK_CONFIG), regmap_reg_range(HDMI_RX_SCDC_REGS0, HDMI_RX_SCDC_REGS2), regmap_reg_range(HDMI_RX_SCDC_WRDATA0, HDMI_RX_SCDC_WRDATA0), diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 5af2cc8223bb..ab5ea36adde5 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -71,6 +71,11 @@ enum hdmirx_pix_fmt { HDMIRX_YUV420 = 3, }; +enum hdmirx_ycc_range { + HDMIRX_YCC_LIMIT, + HDMIRX_YCC_FULL, +}; + static const char * const bus_format_str[] = { "RGB", "YUV422", @@ -1759,13 +1764,23 @@ EXPORT_SYMBOL(rk628_hdmirx_get_timings); u8 rk628_hdmirx_get_range(struct rk628 *rk628) { - u8 color_range; - u32 val, vic, fmt; + u8 color_range, yuv_range; + u32 val, vic, fmt, avi_hb; rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val); + rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_HB, &avi_hb); color_range = (val & RGB_COLORRANGE_MASK) >> 18; + yuv_range = (avi_hb & YUV_COLORRANGE_MASK) >> 30; vic = (val & VID_IDENT_CODE_MASK) >> 24; fmt = (val & VIDEO_FORMAT_MASK) >> 5; + if (fmt != HDMIRX_RGB888) { + if (yuv_range == HDMIRX_YCC_LIMIT) + color_range = HDMIRX_LIMIT_RANGE; + else if (yuv_range == HDMIRX_YCC_FULL) + color_range = HDMIRX_FULL_RANGE; + else + color_range = HDMIRX_DEFAULT_RANGE; + } if (fmt == HDMIRX_RGB888 && color_range == HDMIRX_DEFAULT_RANGE) { (vic) ? (color_range = HDMIRX_LIMIT_RANGE) : diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index ed5c4c05ac01..015c3df0aa38 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -267,6 +267,7 @@ #define VIDEO_FORMAT_MASK GENMASK(6, 5) #define VIDEO_FORMAT(x) UPDATE(x, 6, 5) #define RGB_COLORRANGE_MASK GENMASK(19, 18) +#define YUV_COLORRANGE_MASK GENMASK(31, 30) #define RGB_COLORRANGE(x) UPDATE(x, 19, 18) #define ACT_INFO_PRESENT_MASK BIT(4) #define HDMI_RX_PDEC_ACR_CTS (HDMI_RX_BASE + 0x0390) From b8e6944e4f2ceff68a2382f26304b67d0808881d Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Fri, 21 Jun 2024 09:27:23 +0800 Subject: [PATCH 02/10] drm/rockchip: vop: Fix mixing irqsave and irq in vop_crtc_atomic_flush() Signed-off-by: Tao Huang Change-Id: I4be4ad6728cf77f9f49d6824eed10f7b91d04815 --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 922bdaa03d82..ad8cf09685e9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -4351,7 +4351,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, */ vop_wait_for_irq_handler(vop); - spin_lock_irq(&crtc->dev->event_lock); + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc) != 0); WARN_ON(vop->event); @@ -4359,7 +4359,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, vop->event = crtc->state->event; crtc->state->event = NULL; } - spin_unlock_irq(&crtc->dev->event_lock); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); for_each_old_plane_in_state(old_state, plane, old_plane_state, i) { if (!old_plane_state->fb) From 21dad904b51aacb48310e77e45bffd071f2101e8 Mon Sep 17 00:00:00 2001 From: Weixin Zhou Date: Mon, 17 Jun 2024 17:15:31 +0800 Subject: [PATCH 03/10] input: touchscreen: ft5726: Fix abnormal sleep power Signed-off-by: Weixin Zhou Change-Id: If52037a97e141b1f777a93fbab8f0af5f6a09724 --- .../input/touchscreen/focaltech_touch_ft5726/focaltech_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_config.h b/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_config.h index 04e3b744c364..a356bc2edc65 100644 --- a/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_config.h +++ b/drivers/input/touchscreen/focaltech_touch_ft5726/focaltech_config.h @@ -208,7 +208,7 @@ * enable it when customer need control TP power * default: disable */ -#define FTS_POWER_SOURCE_CUST_EN 1 +#define FTS_POWER_SOURCE_CUST_EN 0 /****************************************************/ From 3305069c0a928672511c0e970d8a76716fab9abb Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Fri, 21 Jun 2024 09:14:40 +0800 Subject: [PATCH 04/10] pinctrl: rockchip: Fix iterator 'j' not incremented in rk_iomux_set() Signed-off-by: Tao Huang Change-Id: I7f659bdcc491ac3bdde5163231b789cf00c0162a --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 943f5afb9793..39e464decde4 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -5416,8 +5416,8 @@ int rk_iomux_set(int bank, int pin, int mux) mutex_lock(&iomux_lock); for (i = 0; i < info->ngroups; i++) { grp = &info->groups[i]; - for (j = 0; j < grp->npins; i++) { - if (grp->pins[i] == (gpio->pin_base + pin)) { + for (j = 0; j < grp->npins; j++) { + if (grp->pins[j] == (gpio->pin_base + pin)) { cfg = grp->data; break; } From f019bedaa1089fdb5077c7c90e264c87b553eb56 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Fri, 21 Jun 2024 15:28:08 +0800 Subject: [PATCH 05/10] video: rockchip: rga3: modify workaround for RK3576 issue reset core_clk on every frame Signed-off-by: Yu Qiaowei Change-Id: I9158fe1fc550fc3a96b8268e4102fccb674fbb43 --- drivers/video/rockchip/rga3/rga2_reg_info.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/video/rockchip/rga3/rga2_reg_info.c b/drivers/video/rockchip/rga3/rga2_reg_info.c index c9423729640a..d5302e91c756 100644 --- a/drivers/video/rockchip/rga3/rga2_reg_info.c +++ b/drivers/video/rockchip/rga3/rga2_reg_info.c @@ -2889,7 +2889,6 @@ static void rga2_set_reg_full_csc(struct rga_job *job, struct rga_scheduler_t *s static int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) { int i; - int cur_num; bool master_mode_en; uint32_t sys_ctrl; uint32_t *cmd; @@ -2930,10 +2929,8 @@ static int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) * when RGA is running continuously, disabling auto_rst * requires resetting core_clk. */ - cur_num = (rga_read(RGA2_STATUS1, scheduler) & m_RGA2_STATUS1_SW_CMD_CUR_NUM) >> 8; - if (cur_num > 0) - rga_write(m_RGA2_SYS_CTRL_AUTO_CKG | m_RGA2_SYS_CTRL_CCLK_SRESET_P, - RGA2_SYS_CTRL, scheduler); + rga_write(m_RGA2_SYS_CTRL_AUTO_CKG | m_RGA2_SYS_CTRL_CCLK_SRESET_P, + RGA2_SYS_CTRL, scheduler); } else { sys_ctrl |= m_RGA2_SYS_CTRL_AUTO_RST; } @@ -2966,8 +2963,6 @@ static int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) for (i = 0; i <= 32; i++) rga_write(cmd[i], 0x100 + i * 4, scheduler); - rga_write(rga_read(RGA2_CMD_CTRL, scheduler) | m_RGA2_CMD_CTRL_CMD_LINE_ST_P, - RGA2_CMD_CTRL, scheduler); rga_write(sys_ctrl, RGA2_SYS_CTRL, scheduler); } From a7620fa846c2e767aa9de2efeb3a26a73b819c97 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Fri, 19 Apr 2024 11:46:23 +0800 Subject: [PATCH 06/10] drm/rockchip: analogix_dp: add support for color format yuv444/yuv422 The detailed changes as follows: 1.Add flag max_bpc and format_yuv to check whether the platform support 10 bit per component and YUV444/YUV422. 2.Add exact bpp related to output format in bandwidth calculation, which is fixed to 24 before the patch. 3.Add .atomic_get_input_bus_fmts() and .atomic_get_output_bus_fmts() to get the supported input and output bus formats. Change-Id: I78ef43d19b3a2970a961b0f668a75ef857951dfe Signed-off-by: Damon Ding --- .../drm/bridge/analogix/analogix_dp_core.c | 130 ++++++++++++++++-- .../drm/bridge/analogix/analogix_dp_core.h | 2 + .../gpu/drm/rockchip/analogix_dp-rockchip.c | 58 ++++++-- include/drm/bridge/analogix_dp.h | 9 ++ 4 files changed, 170 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 9e39d5090b1c..5831088e2cdd 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -54,23 +54,52 @@ struct bridge_init { struct device_node *node; }; +static const struct analogix_dp_output_format possible_output_fmts[] = { + { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, 10 }, + { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, 8 }, + { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, 6 }, + { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCBCR444, 10 }, + { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCBCR444, 8}, + { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCBCR422, 10 }, + { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCBCR422, 8 }, +}; + +static u8 analogix_dp_get_output_bpp(const struct analogix_dp_output_format *fmt) +{ + switch (fmt->color_format) { + case DRM_COLOR_FORMAT_YCBCR422: + return fmt->bpc * 2; + case DRM_COLOR_FORMAT_RGB444: + case DRM_COLOR_FORMAT_YCBCR444: + default: + return fmt->bpc * 3; + } +} + +const struct analogix_dp_output_format *analogix_dp_get_output_format(u32 bus_format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) + if (possible_output_fmts[i].bus_format == bus_format) + return &possible_output_fmts[i]; + + return &possible_output_fmts[1]; +} +EXPORT_SYMBOL_GPL(analogix_dp_get_output_format); + static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *adj_mode); static bool analogix_dp_bandwidth_ok(struct analogix_dp_device *dp, - const struct drm_display_mode *mode, + const struct drm_display_mode *mode, u32 bpp, unsigned int rate, unsigned int lanes) { - const struct drm_display_info *info; - u32 max_bw, req_bw, bpp = 24; + u32 max_bw, req_bw; if (dp->plat_data->skip_connector) return true; - info = &dp->connector.display_info; - if (info->bpc) - bpp = 3 * info->bpc; - req_bw = mode->crtc_clock * bpp / 8; max_bw = lanes * rate; if (req_bw > max_bw) @@ -691,8 +720,9 @@ static u8 analogix_dp_select_link_rate_from_table(struct analogix_dp_device *dp) for (i = 0; i < dp->nr_link_rate_table; i++) { bw_code = drm_dp_link_rate_to_bw_code(dp->link_rate_table[i]); - if (!analogix_dp_bandwidth_ok(dp, &dp->video_info.mode, dp->link_rate_table[i], - dp->link_train.lane_count)) + if (!analogix_dp_bandwidth_ok(dp, &dp->video_info.mode, + analogix_dp_get_output_bpp(dp->output_fmt), + dp->link_rate_table[i], dp->link_train.lane_count)) continue; if (dp->link_rate_table[i] <= max_link_rate && @@ -832,7 +862,7 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp, return -EINVAL; } - if (!analogix_dp_bandwidth_ok(dp, &video->mode, + if (!analogix_dp_bandwidth_ok(dp, &video->mode, analogix_dp_get_output_bpp(dp->output_fmt), drm_dp_bw_code_to_link_rate(dp->link_train.link_rate), dp->link_train.lane_count)) { dev_err(dp->dev, "bandwidth overflow\n"); @@ -1746,6 +1776,12 @@ analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; + struct drm_bridge_state *new_bridge_state; + + new_bridge_state = drm_atomic_get_new_bridge_state(old_state, bridge); + if (WARN_ON(!new_bridge_state)) + return; + dp->output_fmt = analogix_dp_get_output_format(new_bridge_state->output_bus_cfg.format); crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) @@ -1967,7 +2003,6 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *adj_mode) { struct analogix_dp_device *dp = bridge->driver_private; - struct drm_display_info *display_info = &dp->connector.display_info; struct video_info *video = &dp->video_info; struct drm_display_mode *mode = &video->mode; struct device_node *dp_node = dp->dev->of_node; @@ -1998,7 +2033,7 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, video->dynamic_range = VESA; /* Input vide bpc and color_formats */ - switch (display_info->bpc) { + switch (dp->output_fmt->bpc) { case 12: video->color_depth = COLOR_12; break; @@ -2015,10 +2050,10 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, video->color_depth = COLOR_8; break; } - if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444) { + if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_YCBCR444) { video->color_space = COLOR_YCBCR444; video->ycbcr_coeff = COLOR_YCBCR709; - } else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422) { + } else if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_YCBCR422) { video->color_space = COLOR_YCBCR422; video->ycbcr_coeff = COLOR_YCBCR709; } else { @@ -2057,18 +2092,26 @@ analogix_dp_bridge_mode_valid(struct drm_bridge *bridge, struct analogix_dp_device *dp = bridge->driver_private; struct drm_display_mode m; u32 max_link_rate, max_lane_count; + u32 min_bpp; drm_mode_copy(&m, mode); if (dp->plat_data->split_mode || dp->plat_data->dual_connector_split) dp->plat_data->convert_to_origin_mode(&m); + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) + min_bpp = 16; + else if (info->color_formats & DRM_COLOR_FORMAT_RGB444) + min_bpp = 18; + else + min_bpp = 24; + max_link_rate = min_t(u32, dp->video_info.max_link_rate, dp->link_train.link_rate); max_lane_count = min_t(u32, dp->video_info.max_lane_count, dp->link_train.lane_count); if (analogix_dp_link_config_validate(max_link_rate, max_lane_count) && - !analogix_dp_bandwidth_ok(dp, &m, + !analogix_dp_bandwidth_ok(dp, &m, min_bpp, drm_dp_bw_code_to_link_rate(max_link_rate), max_lane_count)) return MODE_BAD; @@ -2076,10 +2119,67 @@ analogix_dp_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } +static u32 *analogix_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts) +{ + struct analogix_dp_device *dp = bridge->driver_private; + struct drm_display_info *di = &dp->connector.display_info; + u32 *output_fmts; + unsigned int i, j = 0; + + if (dp->plat_data->panel) { + *num_output_fmts = 1; + + output_fmts = kzalloc(sizeof(*output_fmts), GFP_KERNEL); + if (!output_fmts) + return NULL; + + if (di->num_bus_formats && di->bus_formats) + output_fmts[0] = di->bus_formats[0]; + else + output_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + + return output_fmts; + } + + *num_output_fmts = 0; + + output_fmts = kcalloc(ARRAY_SIZE(possible_output_fmts), sizeof(*output_fmts), GFP_KERNEL); + if (!output_fmts) + return NULL; + + for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { + const struct analogix_dp_output_format *fmt = &possible_output_fmts[i]; + + if (fmt->bpc > conn_state->max_bpc || fmt->bpc > dp->plat_data->max_bpc) + continue; + + if (!(di->color_formats & fmt->color_format)) + continue; + + if (!analogix_dp_bandwidth_ok(dp, &crtc_state->mode, + analogix_dp_get_output_bpp(fmt), + drm_dp_bw_code_to_link_rate(dp->link_train.link_rate), + dp->link_train.lane_count)) + continue; + + output_fmts[j++] = fmt->bus_format; + } + + *num_output_fmts = j; + + return output_fmts; +} + static const struct drm_bridge_funcs analogix_dp_bridge_funcs = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt, + .atomic_get_output_bus_fmts = analogix_dp_bridge_atomic_get_output_bus_fmts, .atomic_pre_enable = analogix_dp_bridge_atomic_pre_enable, .atomic_enable = analogix_dp_bridge_atomic_enable, .atomic_disable = analogix_dp_bridge_atomic_disable, diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 09f8319edf36..2b2883029c5b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -206,6 +206,8 @@ struct analogix_dp_device { struct analogix_dp_compliance compliance; u32 split_area; + + const struct analogix_dp_output_format *output_fmt; }; /* analogix_dp_reg.c */ diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 861c407b2ab4..a48a3b5d2460 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -70,6 +70,8 @@ struct rockchip_dp_chip_data { bool ssc; bool audio; bool split_mode; + bool format_yuv; + u8 max_bpc; }; struct rockchip_dp_device { @@ -230,15 +232,16 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, struct drm_connector *connector) { + struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); struct drm_display_info *di = &connector->display_info; - /* VOP couldn't output YUV video format for eDP rightly */ u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422; - if ((di->color_formats & mask)) { - DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); - di->color_formats &= ~mask; - di->color_formats |= DRM_COLOR_FORMAT_RGB444; - di->bpc = 8; + if (!dp->data->format_yuv) { + if ((di->color_formats & mask)) { + DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); + di->color_formats &= ~mask; + di->color_formats |= DRM_COLOR_FORMAT_RGB444; + } } return 0; @@ -463,12 +466,19 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, struct rockchip_dp_device *dp = encoder_to_dp(encoder); struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); struct drm_display_info *di = &conn_state->connector->display_info; + struct drm_bridge_state *new_bridge_state; + struct drm_bridge *bridge; + const struct analogix_dp_output_format *output_fmt; int refresh_rate; - if (di->num_bus_formats) - s->bus_format = di->bus_formats[0]; - else - s->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + bridge = drm_bridge_chain_get_first_bridge(encoder); + new_bridge_state = drm_atomic_get_new_bridge_state(conn_state->state, bridge); + if (!new_bridge_state) + return 0; + + dev_dbg(dp->dev, "input format 0x%04x, output format 0x%04x\n", + new_bridge_state->input_bus_cfg.format, + new_bridge_state->output_bus_cfg.format); /* * The hardware IC designed that VOP must output the RGB10 video @@ -477,8 +487,17 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, * controller, that's why we need to hardcode the VOP output mode * to RGA10 here. */ - - s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + output_fmt = analogix_dp_get_output_format(new_bridge_state->output_bus_cfg.format); + switch (output_fmt->color_format) { + case DRM_COLOR_FORMAT_YCBCR422: + s->output_mode = ROCKCHIP_OUT_MODE_YUV422; + break; + case DRM_COLOR_FORMAT_RGB444: + case DRM_COLOR_FORMAT_YCBCR444: + default: + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + break; + } s->output_type = DRM_MODE_CONNECTOR_eDP; if (dp->plat_data.split_mode) { s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; @@ -495,12 +514,16 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, s->output_if |= dp->id ? VOP_OUTPUT_IF_eDP1 : VOP_OUTPUT_IF_eDP0; } - s->output_bpc = di->bpc; + s->bus_format = output_fmt->bus_format; + s->output_bpc = output_fmt->bpc; s->bus_flags = di->bus_flags; s->tv_state = &conn_state->tv; s->eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; s->color_encoding = DRM_COLOR_YCBCR_BT709; - s->color_range = DRM_COLOR_YCBCR_FULL_RANGE; + if (output_fmt->color_format == DRM_COLOR_FORMAT_RGB444) + s->color_range = DRM_COLOR_YCBCR_FULL_RANGE; + else + s->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; /** * It's priority to user rate range define in dtsi. */ @@ -707,6 +730,7 @@ static int rockchip_dp_probe(struct platform_device *pdev) dp->adp = ERR_PTR(-ENODEV); dp->data = &dp_data[id]; dp->plat_data.ssc = dp->data->ssc; + dp->plat_data.max_bpc = dp->data->max_bpc ? dp->data->max_bpc : 8; dp->plat_data.panel = panel; dp->plat_data.dev_type = dp->data->chip_type; dp->plat_data.power_on_start = rockchip_dp_poweron_start; @@ -863,6 +887,8 @@ static const struct rockchip_dp_chip_data rk3576_edp[] = { .ssc = true, .audio = true, .split_mode = true, + .format_yuv = true, + .max_bpc = 10, }, { /* sentinel */ } }; @@ -876,6 +902,8 @@ static const struct rockchip_dp_chip_data rk3588_edp[] = { .ssc = true, .audio = true, .split_mode = true, + .format_yuv = true, + .max_bpc = 10, }, { .chip_type = RK3588_EDP, @@ -885,6 +913,8 @@ static const struct rockchip_dp_chip_data rk3588_edp[] = { .ssc = true, .audio = true, .split_mode = true, + .format_yuv = true, + .max_bpc = 10, }, { /* sentinel */ } }; diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 3773a093b856..4abaf81c2238 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -51,6 +51,8 @@ struct analogix_dp_plat_data { bool dual_connector_split; bool left_display; + u8 max_bpc; + struct analogix_dp_device *left; struct analogix_dp_device *right; @@ -66,6 +68,12 @@ struct analogix_dp_plat_data { void (*convert_to_origin_mode)(struct drm_display_mode *); }; +struct analogix_dp_output_format { + u32 bus_format; + u32 color_format; + u8 bpc; +}; + int analogix_dp_resume(struct analogix_dp_device *dp); int analogix_dp_suspend(struct analogix_dp_device *dp); int analogix_dp_runtime_resume(struct analogix_dp_device *dp); @@ -89,5 +97,6 @@ int analogix_dp_audio_get_eld(struct analogix_dp_device *dp, u8 *buf, size_t len); int analogix_dp_loader_protect(struct analogix_dp_device *dp); void analogix_dp_disable(struct analogix_dp_device *dp); +const struct analogix_dp_output_format *analogix_dp_get_output_format(u32 bus_format); #endif /* _ANALOGIX_DP_H_ */ From a9cd753a9e0005a332763e708a4936f0023fdb81 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Tue, 4 Jun 2024 15:03:05 +0800 Subject: [PATCH 07/10] drm/rockchip: vop2: add support dynamic adjust vop aclk auto cs div Signed-off-by: Sandy Huang Change-Id: Ia8cfc3748f7f3914f1a8c387ef50d3af02a620af --- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 6 +- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 166 +++++++++++-------- 3 files changed, 103 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 58a52dbcc43e..1e32e72769cf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -506,7 +506,7 @@ struct rockchip_crtc_funcs { void (*crtc_output_post_enable)(struct drm_crtc *crtc, int intf); void (*crtc_output_pre_disable)(struct drm_crtc *crtc, int intf); int (*crtc_set_color_bar)(struct drm_crtc *crtc, enum rockchip_color_bar_mode mode); - int (*set_aclk)(struct drm_crtc *crtc, enum rockchip_drm_vop_aclk_mode aclk_mode); + int (*set_aclk)(struct drm_crtc *crtc, enum rockchip_drm_vop_aclk_mode aclk_mode, struct dmcfreq_vop_info *vop_bw_info); int (*get_crc)(struct drm_crtc *crtc); }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 97e756101440..08e1f4020963 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -202,14 +202,14 @@ static int rockchip_drm_aclk_adjust(struct drm_device *dev, if (vop_bw_info->plane_num_4k || crtc_num > 1 || crtc->state->adjusted_mode.crtc_hdisplay > 2560 || crtc->state->adjusted_mode.crtc_vdisplay > 2560) { - funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_ADVANCED_MODE); + funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_ADVANCED_MODE, vop_bw_info); priv->aclk_adjust_frame_num = 2; } else { if (priv->aclk_adjust_frame_num >= 1) { - funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_ADVANCED_MODE); + funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_ADVANCED_MODE, vop_bw_info); priv->aclk_adjust_frame_num--; } else { - funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_NORMAL_MODE); + funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_NORMAL_MODE, vop_bw_info); } } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 0e1d6563ff4b..615e217dbdee 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -968,6 +968,8 @@ struct vop2 { u32 aclk_mode_rate[ROCKCHIP_VOP_ACLK_MAX_MODE]; #endif + /* aclk auto cs div */ + u32 csu_div; /* must put at the end of the struct */ struct vop2_win win[]; }; @@ -1016,7 +1018,6 @@ static const struct drm_bus_format_enum_list drm_bus_format_enum_list[] = { }; static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list) -static int vop2_devfreq_set_aclk(struct drm_crtc *crtc, enum rockchip_drm_vop_aclk_mode aclk_mode); static inline struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc) { @@ -1306,6 +1307,99 @@ static struct drm_crtc *vop2_find_crtc_by_plane_mask(struct vop2 *vop2, uint8_t return NULL; } +static u32 rk3562_vop2_get_csu_div(struct drm_crtc *crtc) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + unsigned long aclk_rate = 0, dclk_rate = 0; + u32 csu_div; + + aclk_rate = clk_get_rate(vp->vop2->aclk); + dclk_rate = clk_get_rate(vp->dclk); + if (!dclk_rate) + return 0; + + /* aclk > 1/2 * dclk */ + csu_div = (aclk_rate - 1) * 2 / dclk_rate; + + return csu_div; +} + +static u32 rk3576_vop2_get_csu_div(struct drm_crtc *crtc, struct dmcfreq_vop_info *vop_bw_info) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + u32 csu_div; + + if (vp->vop2->aclk_mode == ROCKCHIP_VOP_ACLK_NORMAL_MODE) { + if (adjusted_mode->crtc_clock < 250000) { + if (vop_bw_info->plane_num == 1) + csu_div = 3; + else if (vop_bw_info->plane_num == 2) + csu_div = 2; + else + csu_div = 1; + } else { + csu_div = 1; + } + } else { + csu_div = 1; + } + + return csu_div; +} + +static int vop2_set_aclk_rate(struct drm_crtc *crtc, + enum rockchip_drm_vop_aclk_mode aclk_mode, + struct dmcfreq_vop_info *vop_bw_info) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + struct drm_crtc *first_active_crtc = NULL; + int i = 0, ret = 0; + u32 csu_div = 0; + + /* all vp/crtc share one vop aclk, so only need to set once */ + for (i = 0; i < vop2->data->nr_vps; i++) { + if (vop2->vps[i].rockchip_crtc.crtc.state && + vop2->vps[i].rockchip_crtc.crtc.state->active) { + first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc; + break; + } + } + if (first_active_crtc != crtc) + return 0; + + vop2->aclk_target_freq = vop2->aclk_mode_rate[aclk_mode]; + +#ifdef CONFIG_PM_DEVFREQ + if (vop2->devfreq) { + mutex_lock(&vop2->devfreq->lock); + ret = update_devfreq(vop2->devfreq); + mutex_unlock(&vop2->devfreq->lock); + if (ret) + dev_err(vop2->dev, "failed to set rate %lu\n", vop2->aclk_target_freq); + } +#endif + vop2->aclk_mode = aclk_mode; + + if (vop2->csu_aclk && vop_bw_info) { + if (vop2->version == VOP_VERSION_RK3562) + csu_div = rk3562_vop2_get_csu_div(crtc); + else + csu_div = rk3576_vop2_get_csu_div(crtc, vop_bw_info); + if (csu_div != vop2->csu_div) { + rockchip_csu_set_div(vop2->csu_aclk, csu_div); + rockchip_drm_dbg(vop2->dev, VOP_DEBUG_CLK, + "Set aclk auto cs div from %d to %d, aclk rate:%ld, aclk mode:%d\n", + vop2->csu_div, csu_div, clk_get_rate(vop2->aclk), + vop2->aclk_mode); + } + vop2->csu_div = csu_div; + } + + return 0; +} + static int vop2_clk_reset(struct reset_control *rstc) { int ret; @@ -4453,7 +4547,7 @@ static void vop2_disable(struct drm_crtc *crtc) VOP_CTRL_SET(vop2, dma_stop, 1); if (vop2->aclk_mode_rate[ROCKCHIP_VOP_ACLK_RESET_MODE] && clk_get_rate(vop2->aclk) > vop2->aclk_mode_rate[ROCKCHIP_VOP_ACLK_RESET_MODE]) - vop2_devfreq_set_aclk(crtc, ROCKCHIP_VOP_ACLK_RESET_MODE); + vop2_set_aclk_rate(crtc, ROCKCHIP_VOP_ACLK_RESET_MODE, NULL); rockchip_drm_dma_detach_device(vop2->drm_dev, vop2->dev); vop2->is_iommu_enabled = false; } @@ -6949,27 +7043,6 @@ static int vop2_crtc_get_inital_acm_info(struct drm_crtc *crtc) return 0; } -static void vop2_crtc_csu_set_rate(struct drm_crtc *crtc) -{ - struct vop2_video_port *vp = to_vop2_video_port(crtc); - struct vop2 *vop2 = vp->vop2; - unsigned long aclk_rate = 0, dclk_rate = 0; - u32 csu_div = 0; - - if (!vop2->csu_aclk) - return; - - aclk_rate = clk_get_rate(vop2->aclk); - dclk_rate = clk_get_rate(vp->dclk); - if (!dclk_rate || !aclk_rate) - return; - - /* aclk > 1/2 * dclk */ - csu_div = (aclk_rate - 1) * 2 / dclk_rate; - - rockchip_csu_set_div(vop2->csu_aclk, csu_div); -} - static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on, void *data) { struct vop2_video_port *vp = to_vop2_video_port(crtc); @@ -7049,8 +7122,6 @@ static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on, void *data) cubic_lut_mst = cubic_lut->offset + private->cubic_lut_dma_addr; VOP_MODULE_SET(vop2, vp, cubic_lut_mst, cubic_lut_mst); } - - vop2_crtc_csu_set_rate(crtc); } else { vop2_crtc_atomic_disable(crtc, NULL); } @@ -7847,7 +7918,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = { .crtc_output_post_enable = vop2_crtc_output_post_enable, .crtc_output_pre_disable = vop2_crtc_output_pre_disable, .crtc_set_color_bar = vop2_crtc_set_color_bar, - .set_aclk = vop2_devfreq_set_aclk, + .set_aclk = vop2_set_aclk_rate, .get_crc = vop2_crtc_get_crc, }; @@ -9482,7 +9553,6 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta if (is_vop3(vop2)) vop3_setup_pipe_dly(vp, NULL); - vop2_crtc_csu_set_rate(crtc); vop2_crtc_setup_output_mode(crtc); vop2_cfg_done(crtc); @@ -11719,12 +11789,12 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_stat VOP_CTRL_SET(vop2, dma_stop, 1); if (vop2->aclk_mode_rate[ROCKCHIP_VOP_ACLK_RESET_MODE] && clk_get_rate(vop2->aclk) > vop2->aclk_mode_rate[ROCKCHIP_VOP_ACLK_RESET_MODE]) { - vop2_devfreq_set_aclk(crtc, ROCKCHIP_VOP_ACLK_RESET_MODE); + vop2_set_aclk_rate(crtc, ROCKCHIP_VOP_ACLK_RESET_MODE, NULL); enter_vop_aclk_reset_mode = true; } ret = rockchip_drm_dma_attach_device(vop2->drm_dev, vop2->dev); if (enter_vop_aclk_reset_mode) - vop2_devfreq_set_aclk(crtc, aclk_mode); + vop2_set_aclk_rate(crtc, aclk_mode, NULL); if (ret) { vop2->is_iommu_enabled = false; vop2_disable_all_planes_for_crtc(crtc); @@ -13892,39 +13962,6 @@ static struct devfreq_governor devfreq_vop2_ondemand = { .event_handler = devfreq_vop2_ondemand_handler, }; -static int vop2_devfreq_set_aclk(struct drm_crtc *crtc, enum rockchip_drm_vop_aclk_mode aclk_mode) -{ - struct vop2_video_port *vp = to_vop2_video_port(crtc); - struct vop2 *vop2 = vp->vop2; - struct drm_crtc *first_active_crtc = NULL; - int i = 0, ret = 0; - - if (!vop2->devfreq) - return 0; - - /* all vp/crtc share one vop aclk, so only need to set once */ - for (i = 0; i < vop2->data->nr_vps; i++) { - if (vop2->vps[i].rockchip_crtc.crtc.state && - vop2->vps[i].rockchip_crtc.crtc.state->active) { - first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc; - break; - } - } - if (first_active_crtc != crtc) - return 0; - - vop2->aclk_target_freq = vop2->aclk_mode_rate[aclk_mode]; - - mutex_lock(&vop2->devfreq->lock); - ret = update_devfreq(vop2->devfreq); - mutex_unlock(&vop2->devfreq->lock); - if (ret) - dev_err(vop2->dev, "failed to set rate %lu\n", vop2->aclk_target_freq); - vop2->aclk_mode = aclk_mode; - - return 0; -} - static int vop2_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { @@ -14074,11 +14111,6 @@ static void rockchip_vop2_devfreq_uninit(struct vop2 *vop2) rockchip_uninit_opp_table(vop2->dev, &vop2->opp_info); } #else -static inline int vop2_devfreq_set_aclk(struct drm_crtc *crtc, enum rockchip_drm_vop_aclk_mode aclk_mode) -{ - return 0; -} - static inline int rockchip_vop2_devfreq_init(struct vop2 *vop2) { return 0; From df37f6e8e00beebf6a5bc8cce13d4c198684fbd9 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Tue, 4 Jun 2024 14:26:44 +0800 Subject: [PATCH 08/10] arm64: dts: rockchip: rk3576: enable VOP aclk auto cs Signed-off-by: Sandy Huang Change-Id: Ied57a55b5094962a6c7373723a547ab31f4c12f4 --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index 6647bb8a9479..b06c7e80e4bf 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -2777,6 +2777,8 @@ rockchip,aclk-reset-mode-rates = <594000000>; rockchip,aclk-advanced-mode-rates = <702000000>; operating-points-v2 = <&vop_opp_table>; + rockchip,csu = <&csu CSU_VOP_ACLK>; + rockchip,csu-names = "aclk"; iommus = <&vop_mmu>; power-domains = <&power RK3576_PD_VOP>; rockchip,grf = <&sys_grf>; From 233f1cf947f35a3d98aa736d2135e5a715d7f412 Mon Sep 17 00:00:00 2001 From: Mingwei Yan Date: Thu, 9 May 2024 15:12:03 +0800 Subject: [PATCH 09/10] media: rockchip: vpss: online support 8k Signed-off-by: Mingwei Yan Change-Id: I363cc1d0dfc5296ec88db0e283ae1cd067ee36e3 --- drivers/media/platform/rockchip/isp/capture.c | 3 - .../media/platform/rockchip/isp/isp_sditf.c | 11 + .../media/platform/rockchip/isp/isp_vpss.h | 7 +- drivers/media/platform/rockchip/isp/rkisp.c | 10 + drivers/media/platform/rockchip/vpss/common.c | 78 +- drivers/media/platform/rockchip/vpss/common.h | 12 +- drivers/media/platform/rockchip/vpss/dev.c | 13 +- drivers/media/platform/rockchip/vpss/dev.h | 12 + drivers/media/platform/rockchip/vpss/hw.c | 5 +- drivers/media/platform/rockchip/vpss/stream.c | 896 ++++++++++++++---- drivers/media/platform/rockchip/vpss/stream.h | 15 + drivers/media/platform/rockchip/vpss/vpss.c | 92 +- drivers/media/platform/rockchip/vpss/vpss.h | 6 + 13 files changed, 942 insertions(+), 218 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/capture.c b/drivers/media/platform/rockchip/isp/capture.c index cfad3e69b948..82a798b599c0 100644 --- a/drivers/media/platform/rockchip/isp/capture.c +++ b/drivers/media/platform/rockchip/isp/capture.c @@ -435,9 +435,6 @@ int rkisp_stream_frame_start(struct rkisp_device *dev, u32 isp_mis) rkisp_dvbm_event(dev, CIF_ISP_V_START); rkisp_bridge_update_mi(dev, isp_mis); - if (dev->isp_ver == ISP_V39) - rkisp_sditf_sof(dev, isp_mis); - for (i = 0; i < RKISP_MAX_STREAM; i++) { if (i == RKISP_STREAM_VIR || i == RKISP_STREAM_LUMA) continue; diff --git a/drivers/media/platform/rockchip/isp/isp_sditf.c b/drivers/media/platform/rockchip/isp/isp_sditf.c index 91ed3ee3670a..77266494eab8 100644 --- a/drivers/media/platform/rockchip/isp/isp_sditf.c +++ b/drivers/media/platform/rockchip/isp/isp_sditf.c @@ -96,6 +96,7 @@ void rkisp_sditf_sof(struct rkisp_device *dev, u32 irq) return; info.irq = irq; rkisp_dmarx_get_frame(dev, &info.seq, NULL, &info.timestamp, true); + info.unite_index = dev->unite_index; v4l2_subdev_call(sditf->remote_sd, core, ioctl, RKISP_VPSS_CMD_SOF, &info); } @@ -106,8 +107,18 @@ static long rkisp_sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *ar switch (cmd) { case RKISP_VPSS_CMD_EOF: + if (*(int *)arg) { + sditf->is_on = false; + sditf->isp->irq_ends_mask &= ~ISP_FRAME_VPSS; + } rkisp_check_idle(sditf->isp, ISP_FRAME_VPSS); break; + case RKISP_VPSS_GET_UNITE_MODE: + if (sditf->isp->unite_div == ISP_UNITE_DIV2) + *(unsigned int *)arg = sditf->isp->unite_div; + else + *(unsigned int *)arg = 0; + break; default: ret = -ENOIOCTLCMD; } diff --git a/drivers/media/platform/rockchip/isp/isp_vpss.h b/drivers/media/platform/rockchip/isp/isp_vpss.h index 5a7f194d9c5f..332447487c4f 100644 --- a/drivers/media/platform/rockchip/isp/isp_vpss.h +++ b/drivers/media/platform/rockchip/isp/isp_vpss.h @@ -8,12 +8,17 @@ _IOW('V', BASE_VIDIOC_PRIVATE + 0, struct rkisp_vpss_sof) #define RKISP_VPSS_CMD_EOF \ - _IO('V', BASE_VIDIOC_PRIVATE + 1) + _IOW('V', BASE_VIDIOC_PRIVATE + 1, int) + +#define RKISP_VPSS_GET_UNITE_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 2, unsigned int) struct rkisp_vpss_sof { u32 irq; u32 seq; u64 timestamp; + u32 unite_index; + u32 reserved; }; #endif diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index e81ffc788b53..4449524a42cc 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -660,6 +660,9 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo rkisp_stream_frame_start(dev, 0); } + if (dev->isp_ver == ISP_V39) + rkisp_sditf_sof(dev, 0); + if (!hw->is_single) { /* multi sensor need to reset isp resize mode if scale up */ val = 0; @@ -1148,6 +1151,9 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq) u32 state = dev->isp_state; struct rkisp_stream *s; + if (dev->sditf_dev && !dev->sditf_dev->is_on) + dev->isp_state = ISP_STOP; + for (val = 0; val < RKISP_STREAM_VIR; val++) { s = &dev->cap_dev.stream[val]; dev->isp_state = ISP_STOP; @@ -4453,6 +4459,8 @@ void rkisp_isp_isr(unsigned int isp_mis, dev->isp_sdev.frm_timestamp = rkisp_time_get_ns(dev); rkisp_isp_queue_event_sof(&dev->isp_sdev); rkisp_stream_frame_start(dev, isp_mis); + if (dev->isp_ver == ISP_V39) + rkisp_sditf_sof(dev, isp_mis); rkisp_rockit_frame_start(dev); } vs_skip: @@ -4617,6 +4625,8 @@ vs_skip: rkisp_isp_queue_event_sof(&dev->isp_sdev); rkisp_stream_frame_start(dev, isp_mis); rkisp_rockit_frame_start(dev); + if (dev->isp_ver == ISP_V39) + rkisp_sditf_sof(dev, isp_mis); } if (isp_mis & ISP3X_OUT_FRM_QUARTER) { diff --git a/drivers/media/platform/rockchip/vpss/common.c b/drivers/media/platform/rockchip/vpss/common.c index e76cd2f5f561..b73b71ee5d1d 100644 --- a/drivers/media/platform/rockchip/vpss/common.c +++ b/drivers/media/platform/rockchip/vpss/common.c @@ -9,49 +9,70 @@ #include "dev.h" #include "regs.h" -void rkvpss_write(struct rkvpss_device *dev, u32 reg, u32 val) -{ - u32 *mem = dev->sw_base_addr + reg; - u32 *flag = dev->sw_base_addr + reg + RKVPSS_SW_REG_SIZE; +void rkvpss_idx_write(struct rkvpss_device *dev, u32 reg, u32 val, int idx) +{ + u32 *mem, *flag, offset = idx * RKVPSS_SW_REG_SIZE_MAX; + + if (!dev->unite_mode) + offset = 0; + + mem = dev->sw_base_addr + reg + offset; + flag = dev->sw_base_addr + reg + RKVPSS_SW_REG_SIZE + offset; *mem = val; *flag = RKVPSS_REG_CACHE; - if (dev->hw_dev->is_single) + + if (dev->hw_dev->is_single && !dev->unite_mode) rkvpss_hw_write(dev->hw_dev, reg, val); } -u32 rkvpss_read(struct rkvpss_device *dev, u32 reg) +void rkvpss_unite_write(struct rkvpss_device *dev, u32 reg, u32 val) { - u32 val; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_LEFT); + if (dev->unite_mode) + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); +} - if (dev->hw_dev->is_single) +u32 rkvpss_idx_read(struct rkvpss_device *dev, u32 reg, int idx) +{ + u32 val, offset = idx * RKVPSS_SW_REG_SIZE_MAX; + + if (!dev->unite_mode) + offset = 0; + + if (dev->hw_dev->is_single && !dev->unite_mode) val = rkvpss_hw_read(dev->hw_dev, reg); else - val = *(u32 *)(dev->sw_base_addr + reg); + val = *(u32 *)(dev->sw_base_addr + reg + offset); return val; } -void rkvpss_set_bits(struct rkvpss_device *dev, u32 reg, u32 mask, u32 val) +void rkvpss_idx_set_bits(struct rkvpss_device *dev, u32 reg, u32 mask, u32 val, int idx) { - u32 *mem = dev->sw_base_addr + reg; - u32 *flag = dev->sw_base_addr + reg + RKVPSS_SW_REG_SIZE; + u32 tmp = rkvpss_idx_read(dev, reg, idx) & ~mask; - *mem &= ~mask; - *mem |= val; - *flag = RKVPSS_REG_CACHE; - if (dev->hw_dev->is_single) - rkvpss_hw_set_bits(dev->hw_dev, reg, mask, val); + rkvpss_idx_write(dev, reg, val | tmp, idx); } -void rkvpss_clear_bits(struct rkvpss_device *dev, u32 reg, u32 mask) +void rkvpss_unite_set_bits(struct rkvpss_device *dev, u32 reg, u32 mask, u32 val) { - u32 *mem = dev->sw_base_addr + reg; - u32 *flag = dev->sw_base_addr + reg + RKVPSS_SW_REG_SIZE; + rkvpss_idx_set_bits(dev, reg, mask, val, VPSS_UNITE_LEFT); + if (dev->unite_mode) + rkvpss_idx_set_bits(dev, reg, mask, val, VPSS_UNITE_RIGHT); +} - *mem &= ~mask; - *flag = RKVPSS_REG_CACHE; - if (dev->hw_dev->is_single) - rkvpss_hw_clear_bits(dev->hw_dev, reg, mask); +void rkvpss_idx_clear_bits(struct rkvpss_device *dev, u32 reg, u32 mask, int idx) +{ + u32 tmp = rkvpss_idx_read(dev, reg, idx); + + rkvpss_idx_write(dev, reg, tmp & ~mask, idx); +} + +void rkvpss_unite_clear_bits(struct rkvpss_device *dev, u32 reg, u32 mask) +{ + rkvpss_idx_clear_bits(dev, reg, mask, VPSS_UNITE_LEFT); + if (dev->unite_mode) + rkvpss_idx_clear_bits(dev, reg, mask, VPSS_UNITE_RIGHT); } void rkvpss_update_regs(struct rkvpss_device *dev, u32 start, u32 end) @@ -69,6 +90,13 @@ void rkvpss_update_regs(struct rkvpss_device *dev, u32 start, u32 end) u32 *val = dev->sw_base_addr + i; u32 *flag = dev->sw_base_addr + i + RKVPSS_SW_REG_SIZE; + if (dev->unite_mode && + ((!dev->mir_en && dev->unite_index == VPSS_UNITE_RIGHT) || + (dev->mir_en && dev->unite_index == VPSS_UNITE_LEFT))) { + val += (RKVPSS_SW_REG_SIZE_MAX / 4); + flag += (RKVPSS_SW_REG_SIZE_MAX / 4); + } + if (*flag != RKVPSS_REG_CACHE) continue; @@ -86,6 +114,8 @@ void rkvpss_update_regs(struct rkvpss_device *dev, u32 start, u32 end) } } writel(*val, base + i); + if (i == RKVPSS_MI_WR_INIT) + writel(*val, base + i); if (IS_SYNC_REG(i)) spin_unlock_irqrestore(&hw->reg_lock, lock_flags); } diff --git a/drivers/media/platform/rockchip/vpss/common.h b/drivers/media/platform/rockchip/vpss/common.h index ef595721658a..6e4d71b8c1c7 100644 --- a/drivers/media/platform/rockchip/vpss/common.h +++ b/drivers/media/platform/rockchip/vpss/common.h @@ -14,6 +14,7 @@ #include #include "../isp/isp_vpss.h" +#include #define RKVPSS_PLANE_Y 0 #define RKVPSS_PLANE_UV 1 @@ -90,10 +91,13 @@ static inline struct vb2_queue *to_vb2_queue(struct file *file) extern int rkvpss_debug; extern struct platform_driver rkvpss_plat_drv; -void rkvpss_write(struct rkvpss_device *dev, u32 reg, u32 val); -void rkvpss_set_bits(struct rkvpss_device *dev, u32 reg, u32 mask, u32 val); -u32 rkvpss_read(struct rkvpss_device *dev, u32 reg); -void rkvpss_clear_bits(struct rkvpss_device *dev, u32 reg, u32 mask); +void rkvpss_idx_write(struct rkvpss_device *dev, u32 reg, u32 val, int idx); +void rkvpss_unite_write(struct rkvpss_device *dev, u32 reg, u32 val); +void rkvpss_idx_set_bits(struct rkvpss_device *dev, u32 reg, u32 mask, u32 val, int idx); +void rkvpss_unite_set_bits(struct rkvpss_device *dev, u32 reg, u32 mask, u32 val); +u32 rkvpss_idx_read(struct rkvpss_device *dev, u32 reg, int idx); +void rkvpss_idx_clear_bits(struct rkvpss_device *dev, u32 reg, u32 mask, int idx); +void rkvpss_unite_clear_bits(struct rkvpss_device *dev, u32 reg, u32 mask); void rkvpss_update_regs(struct rkvpss_device *dev, u32 start, u32 end); int rkvpss_attach_hw(struct rkvpss_device *vpss); diff --git a/drivers/media/platform/rockchip/vpss/dev.c b/drivers/media/platform/rockchip/vpss/dev.c index 5f60c24696a1..971d4e209691 100644 --- a/drivers/media/platform/rockchip/vpss/dev.c +++ b/drivers/media/platform/rockchip/vpss/dev.c @@ -75,6 +75,9 @@ int rkvpss_pipeline_stream(struct rkvpss_device *dev, bool on) (!on && atomic_dec_return(&dev->pipe_stream_cnt) > 0)) return 0; + v4l2_dbg(1, rkvpss_debug, &dev->v4l2_dev, + "%s on:%d\n", __func__, on); + if (on) { ret = v4l2_subdev_call(&dev->vpss_sdev.sd, video, s_stream, true); if (ret < 0) @@ -84,7 +87,12 @@ int rkvpss_pipeline_stream(struct rkvpss_device *dev, bool on) v4l2_subdev_call(&dev->vpss_sdev.sd, video, s_stream, false); goto err; } + dev->stopping = false; } else { + dev->stopping = true; + ret = wait_event_timeout(dev->stop_done, !dev->stopping, msecs_to_jiffies(300)); + if (!ret) + v4l2_warn(&dev->v4l2_dev, "%s timeout\n", __func__); v4l2_subdev_call(dev->remote_sd, video, s_stream, false); v4l2_subdev_call(&dev->vpss_sdev.sd, video, s_stream, false); } @@ -256,7 +264,7 @@ static int rkvpss_plat_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct v4l2_device *v4l2_dev; struct rkvpss_device *vpss_dev; - int ret; + int ret, mult = 2; sprintf(rkvpss_version, "v%02x.%02x.%02x", RKVPSS_DRIVER_VERSION >> 16, @@ -268,7 +276,7 @@ static int rkvpss_plat_probe(struct platform_device *pdev) vpss_dev = devm_kzalloc(dev, sizeof(*vpss_dev), GFP_KERNEL); if (!vpss_dev) return -ENOMEM; - vpss_dev->sw_base_addr = devm_kzalloc(dev, RKVPSS_SW_REG_SIZE_MAX, GFP_KERNEL); + vpss_dev->sw_base_addr = devm_kzalloc(dev, RKVPSS_SW_REG_SIZE_MAX * mult, GFP_KERNEL); if (!vpss_dev->sw_base_addr) return -ENOMEM; @@ -314,6 +322,7 @@ static int rkvpss_plat_probe(struct platform_device *pdev) rkvpss_proc_init(vpss_dev); pm_runtime_enable(&pdev->dev); vpss_dev->is_probe_end = true; + init_waitqueue_head(&vpss_dev->stop_done); return 0; err_unreg_media_dev: diff --git a/drivers/media/platform/rockchip/vpss/dev.h b/drivers/media/platform/rockchip/vpss/dev.h index 6c6309a8d626..be9830241462 100644 --- a/drivers/media/platform/rockchip/vpss/dev.h +++ b/drivers/media/platform/rockchip/vpss/dev.h @@ -29,6 +29,12 @@ enum { T_CMD_END, }; +enum { + VPSS_UNITE_LEFT = 0, + VPSS_UNITE_RIGHT, + VPSS_UNITE_MAX, +}; + struct rkvpss_rdbk_info { u64 timestamp; u64 seq; @@ -65,6 +71,12 @@ struct rkvpss_device { bool mir_en; bool cmsc_upd; + u32 unite_mode; + u8 unite_index; + bool stopping; + wait_queue_head_t stop_done; + unsigned int irq_ends; + unsigned int irq_ends_mask; bool is_probe_end; }; diff --git a/drivers/media/platform/rockchip/vpss/hw.c b/drivers/media/platform/rockchip/vpss/hw.c index acd56f95aef5..6be54c704596 100644 --- a/drivers/media/platform/rockchip/vpss/hw.c +++ b/drivers/media/platform/rockchip/vpss/hw.c @@ -665,8 +665,11 @@ static irqreturn_t mi_irq_hdl(int irq, void *ctx) mis_val = rkvpss_hw_read(hw_dev, RKVPSS_MI_MIS); if (mis_val) { + if (mis_val & RKVPSS_MI_BUS_ERR) + dev_err(dev, "axi bus error\n"); rkvpss_hw_write(hw_dev, RKVPSS_MI_ICR, mis_val); - rkvpss_mi_isr(vpss, mis_val); + if (vpss) + rkvpss_mi_isr(vpss, mis_val); } return IRQ_HANDLED; } diff --git a/drivers/media/platform/rockchip/vpss/stream.c b/drivers/media/platform/rockchip/vpss/stream.c index a93052cbbc54..5b650357399c 100644 --- a/drivers/media/platform/rockchip/vpss/stream.c +++ b/drivers/media/platform/rockchip/vpss/stream.c @@ -458,6 +458,80 @@ static struct stream_config scl3_config = { }, }; +static void calc_unite_scl_params(struct rkvpss_stream *stream) +{ + struct rkvpss_online_unite_params *params = &stream->unite_params; + u32 right_scl_need_size_y, right_scl_need_size_c; + u32 left_in_used_size_y, left_in_used_size_c; + u32 right_fst_position_y, right_fst_position_c; + u32 right_y_crop_total; + u32 right_c_crop_total; + + params->y_w_fac = (stream->crop.width - 1) * 4096 / + (stream->out_fmt.width - 1); + params->c_w_fac = (stream->crop.width / 2 - 1) * 4096 / + (stream->out_fmt.width / 2 - 1); + params->y_h_fac = (stream->crop.height - 1) * 4096 / + (stream->out_fmt.height - 1); + params->c_h_fac = (stream->crop.height - 1) * 4096 / + (stream->out_fmt.height - 1); + + right_fst_position_y = stream->out_fmt.width / 2 * + params->y_w_fac; + right_fst_position_c = stream->out_fmt.width / 2 / 2 * + params->c_w_fac; + + left_in_used_size_y = right_fst_position_y >> 12; + left_in_used_size_c = (right_fst_position_c >> 12) * 2; + + params->y_w_phase = right_fst_position_y & 0xfff; + params->c_w_phase = right_fst_position_c & 0xfff; + + right_scl_need_size_y = stream->crop.width - + left_in_used_size_y; + params->right_scl_need_size_y = right_scl_need_size_y; + right_scl_need_size_c = stream->crop.width - + left_in_used_size_c; + params->right_scl_need_size_c = right_scl_need_size_c; + + if (stream->id == 0 && stream->crop.width != stream->out_fmt.width) { + right_y_crop_total = stream->crop.width / 2 + + RKMOUDLE_UNITE_EXTEND_PIXEL - + right_scl_need_size_y - 3; + right_c_crop_total = stream->crop.width / 2 + + RKMOUDLE_UNITE_EXTEND_PIXEL - + right_scl_need_size_c - 6; + } else { + right_y_crop_total = stream->crop.width / 2 + + RKMOUDLE_UNITE_EXTEND_PIXEL - + right_scl_need_size_y; + right_c_crop_total = stream->crop.width / 2 + + RKMOUDLE_UNITE_EXTEND_PIXEL - + right_scl_need_size_c; + } + + params->quad_crop_w = ALIGN_DOWN(min(right_y_crop_total, right_c_crop_total), 2); + + params->scl_in_crop_w_y = right_y_crop_total - params->quad_crop_w; + params->scl_in_crop_w_c = right_c_crop_total - params->quad_crop_w; + + if (rkvpss_debug >= 2) { + v4l2_info(&stream->dev->v4l2_dev, + "%s ch:%d y_w_fac:%u c_w_fac:%u y_h_fac:%u c_h_fac:%u\n", + __func__, stream->id, params->y_w_fac, + params->c_w_fac, params->y_h_fac, params->c_h_fac); + v4l2_info(&stream->dev->v4l2_dev, + "\t%s y_w_phase:%u c_w_phase:%u quad_crop_w:%u scl_in_crop_w_y:%u scl_in_crop_w_c:%u\n", + __func__, params->y_w_phase, params->c_w_phase, + params->quad_crop_w, + params->scl_in_crop_w_y, params->scl_in_crop_w_c); + v4l2_info(&stream->dev->v4l2_dev, + "\t%s right_scl_need_size_y:%u right_scl_need_size_c:%u\n", + __func__, params->right_scl_need_size_y, + params->right_scl_need_size_c); + } +} + int rkvpss_stream_buf_cnt(struct rkvpss_stream *stream) { unsigned long lock_flags = 0; @@ -477,7 +551,11 @@ int rkvpss_stream_buf_cnt(struct rkvpss_stream *stream) static void stream_frame_start(struct rkvpss_stream *stream, u32 irq) { + struct rkvpss_device *dev = stream->dev; + if (stream->is_crop_upd) { + if (dev->unite_mode) + calc_unite_scl_params(stream); rkvpss_stream_scale(stream, true, !irq); rkvpss_stream_crop(stream, true, !irq); } @@ -507,8 +585,8 @@ static void scl_force_update(struct rkvpss_stream *stream) return; } /* need update two for online2 mode */ - rkvpss_write(stream->dev, RKVPSS_MI_WR_INIT, val); - rkvpss_write(stream->dev, RKVPSS_MI_WR_INIT, val); + rkvpss_unite_write(stream->dev, RKVPSS_MI_WR_INIT, val); + rkvpss_unite_write(stream->dev, RKVPSS_MI_WR_INIT, val); } static void scl_update_mi(struct rkvpss_stream *stream) @@ -516,7 +594,7 @@ static void scl_update_mi(struct rkvpss_stream *stream) struct rkvpss_device *dev = stream->dev; struct rkvpss_buffer *buf = NULL; unsigned long lock_flags = 0; - u32 val; + u32 y_base, uv_base; spin_lock_irqsave(&stream->vbq_lock, lock_flags); if (!list_empty(&stream->buf_queue) && !stream->curr_buf) { @@ -527,10 +605,17 @@ static void scl_update_mi(struct rkvpss_stream *stream) spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); if (buf) { - val = buf->dma[0]; - rkvpss_write(dev, stream->config->mi.y_base, val); - val = buf->dma[1]; - rkvpss_write(dev, stream->config->mi.uv_base, val); + y_base = buf->dma[0]; + uv_base = buf->dma[1]; + rkvpss_idx_write(dev, stream->config->mi.y_base, y_base, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, stream->config->mi.uv_base, uv_base, VPSS_UNITE_LEFT); + if (dev->unite_mode) { + y_base = buf->dma[0] + stream->out_fmt.width / 2; + uv_base = buf->dma[1] + stream->out_fmt.width / 2; + rkvpss_idx_write(dev, stream->config->mi.y_base, y_base, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, stream->config->mi.uv_base, uv_base, VPSS_UNITE_RIGHT); + } + scl_force_update(stream); if (stream->is_pause) { stream->is_pause = false; @@ -540,11 +625,12 @@ static void scl_update_mi(struct rkvpss_stream *stream) stream->is_pause = true; stream->ops->disable_mi(stream); } + v4l2_dbg(2, rkvpss_debug, &dev->v4l2_dev, - "%s id:%d Y:0x%x UV:0x%x | Y_SHD:0x%x\n", - __func__, stream->id, - rkvpss_read(dev, stream->config->mi.y_base), - rkvpss_read(dev, stream->config->mi.uv_base), + "%s id:%d unite_index:%d Y:0x%x UV:0x%x | Y_SHD:0x%x\n", + __func__, stream->id, dev->unite_index, + rkvpss_idx_read(dev, stream->config->mi.y_base, dev->unite_index), + rkvpss_idx_read(dev, stream->config->mi.uv_base, dev->unite_index), rkvpss_hw_read(dev->hw_dev, stream->config->mi.y_shd)); } @@ -557,7 +643,8 @@ static void scl_config_mi(struct rkvpss_stream *stream) val = out_fmt->plane_fmt[0].bytesperline; reg = stream->config->mi.stride; - rkvpss_write(dev, reg, val); + rkvpss_unite_write(dev, reg, val); + rkvpss_unite_write(dev, reg, val); switch (fmt->fourcc) { case V4L2_PIX_FMT_RGB565: @@ -575,25 +662,25 @@ static void scl_config_mi(struct rkvpss_stream *stream) val = val * out_fmt->height; reg = stream->config->mi.y_pic_size; - rkvpss_write(dev, reg, val); + rkvpss_unite_write(dev, reg, val); val = out_fmt->plane_fmt[0].bytesperline * out_fmt->height; reg = stream->config->mi.y_size; - rkvpss_write(dev, reg, val); + rkvpss_unite_write(dev, reg, val); val = out_fmt->plane_fmt[1].sizeimage; reg = stream->config->mi.uv_size; - rkvpss_write(dev, reg, val); + rkvpss_unite_write(dev, reg, val); reg = stream->config->mi.y_offs_cnt; - rkvpss_write(dev, reg, 0); + rkvpss_unite_write(dev, reg, 0); reg = stream->config->mi.uv_offs_cnt; - rkvpss_write(dev, reg, 0); + rkvpss_unite_write(dev, reg, 0); val = fmt->wr_fmt | fmt->output_fmt | fmt->swap | RKVPSS_MI_CHN_WR_EN | RKVPSS_MI_CHN_WR_AUTO_UPD; reg = stream->config->mi.ctrl; - rkvpss_write(dev, reg, val); + rkvpss_unite_write(dev, reg, val); switch (fmt->fourcc) { case V4L2_PIX_FMT_NV21: @@ -636,9 +723,9 @@ static void scl_enable_mi(struct rkvpss_stream *stream) val |= RKVPSS_ISP2VPSS_ONLINE2; if (!dev->hw_dev->is_ofl_cmsc) val |= RKVPSS_ISP2VPSS_ONLINE2_CMSC_EN; - rkvpss_set_bits(dev, RKVPSS_VPSS_ONLINE, mask, val); + rkvpss_unite_set_bits(dev, RKVPSS_VPSS_ONLINE, mask, val); val = RKVPSS_ONLINE2_CHN_FORCE_UPD | RKVPSS_CFG_GEN_UPD; - rkvpss_write(dev, RKVPSS_VPSS_UPDATE, val); + rkvpss_unite_write(dev, RKVPSS_VPSS_UPDATE, val); } static void scl_disable_mi(struct rkvpss_stream *stream) @@ -663,9 +750,9 @@ static void scl_disable_mi(struct rkvpss_stream *stream) return; } - rkvpss_clear_bits(dev, RKVPSS_VPSS_ONLINE, val); + rkvpss_unite_clear_bits(dev, RKVPSS_VPSS_ONLINE, val); val = RKVPSS_ONLINE2_CHN_FORCE_UPD | RKVPSS_CFG_GEN_UPD; - rkvpss_write(dev, RKVPSS_VPSS_UPDATE, val); + rkvpss_unite_write(dev, RKVPSS_VPSS_UPDATE, val); } static struct streams_ops scl_stream_ops = { @@ -863,19 +950,78 @@ static int rkvpss_stream_crop(struct rkvpss_stream *stream, bool on, bool sync) u32 val; val = RKVPSS_CROP_CHN_EN(stream->id); - if (on) { - rkvpss_set_bits(dev, reg_ctrl, 0, val); - rkvpss_write(dev, reg_h_offs, crop->left); - rkvpss_write(dev, reg_v_offs, crop->top); - rkvpss_write(dev, reg_h_size, crop->width); - rkvpss_write(dev, reg_v_size, crop->height); + if (!dev->unite_mode) { + if (on) { + rkvpss_unite_set_bits(dev, reg_ctrl, 0, val); + rkvpss_unite_write(dev, reg_h_offs, crop->left); + rkvpss_unite_write(dev, reg_v_offs, crop->top); + rkvpss_unite_write(dev, reg_h_size, crop->width); + rkvpss_unite_write(dev, reg_v_size, crop->height); + + v4l2_dbg(4, rkvpss_debug, &dev->v4l2_dev, + "crop left:%d top:%d w:%d h:%d\n", + crop->left, crop->top, crop->width, crop->height); + } else { + rkvpss_unite_clear_bits(dev, reg_ctrl, val); + } + if (sync) { + val = RKVPSS_CROP_CHN_FORCE_UPD(stream->id); + val |= RKVPSS_CROP_GEN_UPD; + rkvpss_unite_write(dev, reg_upd, val); + rkvpss_unite_write(dev, reg_upd, val); + } } else { - rkvpss_clear_bits(dev, reg_ctrl, val); - } - if (sync) { - val = RKVPSS_CROP_CHN_FORCE_UPD(stream->id); - val |= RKVPSS_CROP_GEN_UPD; - rkvpss_write(dev, reg_upd, val); + if (on) { + if (crop->left + crop->width / 2 != dev->vpss_sdev.in_fmt.width / 2) { + v4l2_err(&dev->v4l2_dev, + "unite need centered crop left:%d top:%d w:%d h:%d\n", + crop->left, crop->top, crop->width, crop->height); + return -EINVAL; + } + /* unite left */ + rkvpss_idx_set_bits(dev, reg_ctrl, 0, val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, reg_h_offs, crop->left, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, reg_v_offs, crop->top, VPSS_UNITE_LEFT); + /* if no scale left don't enlarge */ + if (crop->width == stream->out_fmt.width) + rkvpss_idx_write(dev, reg_h_size, crop->width / 2, + VPSS_UNITE_LEFT); + else + rkvpss_idx_write(dev, reg_h_size, crop->width / 2 + + RKMOUDLE_UNITE_EXTEND_PIXEL, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, reg_v_size, crop->height, VPSS_UNITE_LEFT); + v4l2_dbg(4, rkvpss_debug, &dev->v4l2_dev, + "right crop left:%d top:%d w:%d h:%d\n", + rkvpss_idx_read(dev, reg_h_offs, VPSS_UNITE_LEFT), + rkvpss_idx_read(dev, reg_v_offs, VPSS_UNITE_LEFT), + rkvpss_idx_read(dev, reg_h_size, VPSS_UNITE_LEFT), + rkvpss_idx_read(dev, reg_v_size, VPSS_UNITE_LEFT)); + + /* unite right */ + rkvpss_idx_set_bits(dev, reg_ctrl, 0, val, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, reg_h_offs, stream->unite_params.quad_crop_w, + VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, reg_v_offs, crop->top, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, reg_h_size, crop->width / 2 + + RKMOUDLE_UNITE_EXTEND_PIXEL - + stream->unite_params.quad_crop_w, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, reg_v_size, crop->height, VPSS_UNITE_RIGHT); + v4l2_dbg(4, rkvpss_debug, &dev->v4l2_dev, + "right crop left:%d top:%d w:%d h:%d\n", + rkvpss_idx_read(dev, reg_h_offs, VPSS_UNITE_RIGHT), + rkvpss_idx_read(dev, reg_v_offs, VPSS_UNITE_RIGHT), + rkvpss_idx_read(dev, reg_h_size, VPSS_UNITE_RIGHT), + rkvpss_idx_read(dev, reg_v_size, VPSS_UNITE_RIGHT)); + } else { + rkvpss_idx_clear_bits(dev, reg_ctrl, val, VPSS_UNITE_LEFT); + rkvpss_idx_clear_bits(dev, reg_ctrl, val, VPSS_UNITE_RIGHT); + } + if (sync) { + val = RKVPSS_CROP_CHN_FORCE_UPD(stream->id); + val |= RKVPSS_CROP_GEN_UPD; + rkvpss_idx_write(dev, reg_upd, val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, reg_upd, val, VPSS_UNITE_RIGHT); + } } stream->is_crop_upd = false; return 0; @@ -893,8 +1039,14 @@ static void poly_phase_scale(struct rkvpss_stream *stream, bool on, bool sync) bool dering_en = false, yuv420_in = false, yuv422_to_420 = false; if (!on) { - rkvpss_write(dev, RKVPSS_ZME_Y_SCL_CTRL, 0); - rkvpss_write(dev, RKVPSS_ZME_UV_SCL_CTRL, 0); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_SCL_CTRL, 0); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_SCL_CTRL, 0); + if (dev->unite_mode) { + rkvpss_idx_write(dev, RKVPSS_ZME_Y_SCL_CTRL, 0, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_SCL_CTRL, 0, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_SCL_CTRL, 0, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_SCL_CTRL, 0, VPSS_UNITE_RIGHT); + } return; } @@ -910,19 +1062,52 @@ static void poly_phase_scale(struct rkvpss_stream *stream, bool on, bool sync) out_div = 1; } - val = (in_w - 1) | ((in_h - 1) << 16); - rkvpss_write(dev, RKVPSS_ZME_Y_SRC_SIZE, val); - rkvpss_write(dev, RKVPSS_ZME_UV_SRC_SIZE, val); - val = (out_w - 1) | ((out_h - 1) << 16); - rkvpss_write(dev, RKVPSS_ZME_Y_DST_SIZE, val); - rkvpss_write(dev, RKVPSS_ZME_UV_DST_SIZE, val); + if (dev->unite_mode) { + /* unite left */ + if (in_w == out_w) + val = (in_w / 2 - 1) | ((in_h - 1) << 16); + else + val = (in_w / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL - 1) | + ((in_h - 1) << 16); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_SRC_SIZE, val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_SRC_SIZE, val, VPSS_UNITE_LEFT); + + /* unite right */ + val = (ALIGN(stream->unite_params.right_scl_need_size_y + 3, 2) - 1) | + ((in_h - 1) << 16); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_SRC_SIZE, val, VPSS_UNITE_RIGHT); + val = (ALIGN(stream->unite_params.right_scl_need_size_c + 6, 2) - 1) | + ((in_h - 1) << 16); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_SRC_SIZE, val, VPSS_UNITE_RIGHT); + + val = (out_w / 2 - 1) | ((out_h - 1) << 16); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_DST_SIZE, val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_DST_SIZE, val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_DST_SIZE, val, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_DST_SIZE, val, VPSS_UNITE_RIGHT); + } else { + val = (in_w - 1) | ((in_h - 1) << 16); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_SRC_SIZE, val); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_SRC_SIZE, val); + val = (out_w - 1) | ((out_h - 1) << 16); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_DST_SIZE, val); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_DST_SIZE, val); + } ctrl = RKVPSS_ZME_XSCL_MODE | RKVPSS_ZME_YSCL_MODE; if (dering_en) { ctrl |= RKVPSS_ZME_DERING_EN; - rkvpss_write(dev, RKVPSS_ZME_Y_DERING_PARA, 0xd10410); - rkvpss_write(dev, RKVPSS_ZME_UV_DERING_PARA, 0xd10410); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_DERING_PARA, 0xd10410); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_DERING_PARA, 0xd10410); + + if (dev->unite_mode) { + rkvpss_idx_write(dev, RKVPSS_ZME_Y_DERING_PARA, 0xd10410, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_DERING_PARA, 0xd10410, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_DERING_PARA, 0xd10410, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_DERING_PARA, 0xd10410, VPSS_UNITE_RIGHT); + } } + if (in_w != out_w) { if (in_w > out_w) { factor = 4096; @@ -940,16 +1125,45 @@ static void poly_phase_scale(struct rkvpss_stream *stream, bool on, bool sync) for (j = 0; j < 8; j += 2) { val = RKVPSS_ZME_TAP_COE(rkvpss_zme_tap8_coe[idx][i][j], rkvpss_zme_tap8_coe[idx][i][j + 1]); - rkvpss_write(dev, RKVPSS_ZME_Y_HOR_COE0_10 + i * 16 + j * 2, val); - rkvpss_write(dev, RKVPSS_ZME_UV_HOR_COE0_10 + i * 16 + j * 2, val); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_HOR_COE0_10 + i * 16 + j * 2, val); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_HOR_COE0_10 + i * 16 + j * 2, val); + + if (dev->unite_mode) { + rkvpss_idx_write(dev, + RKVPSS_ZME_Y_HOR_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, + RKVPSS_ZME_UV_HOR_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, + RKVPSS_ZME_Y_HOR_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, + RKVPSS_ZME_UV_HOR_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_RIGHT); + } } } } else { y_xscl_fac = 0; uv_xscl_fac = 0; } - rkvpss_write(dev, RKVPSS_ZME_Y_XSCL_FACTOR, y_xscl_fac); - rkvpss_write(dev, RKVPSS_ZME_UV_XSCL_FACTOR, uv_xscl_fac); + + if (dev->unite_mode) { + /* unite left */ + rkvpss_idx_write(dev, RKVPSS_ZME_Y_XSCL_FACTOR, y_xscl_fac, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_XSCL_FACTOR, uv_xscl_fac, VPSS_UNITE_LEFT); + + /* unite right */ + val = y_xscl_fac | (stream->unite_params.y_w_phase << 16); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_XSCL_FACTOR, val, VPSS_UNITE_RIGHT); + val = uv_xscl_fac | (stream->unite_params.c_w_phase << 16); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_XSCL_FACTOR, val, VPSS_UNITE_RIGHT); + } else { + rkvpss_unite_write(dev, RKVPSS_ZME_Y_XSCL_FACTOR, y_xscl_fac); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_XSCL_FACTOR, uv_xscl_fac); + } + if (in_h != out_h) { if (in_h > out_h) { factor = 4096; @@ -967,31 +1181,90 @@ static void poly_phase_scale(struct rkvpss_stream *stream, bool on, bool sync) for (j = 0; j < 8; j += 2) { val = RKVPSS_ZME_TAP_COE(rkvpss_zme_tap6_coe[idx][i][j], rkvpss_zme_tap6_coe[idx][i][j + 1]); - rkvpss_write(dev, RKVPSS_ZME_Y_VER_COE0_10 + i * 16 + j * 2, val); - rkvpss_write(dev, RKVPSS_ZME_UV_VER_COE0_10 + i * 16 + j * 2, val); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_VER_COE0_10 + i * 16 + j * 2, val); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_VER_COE0_10 + i * 16 + j * 2, val); + + if (dev->unite_mode) { + rkvpss_idx_write(dev, + RKVPSS_ZME_Y_VER_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, + RKVPSS_ZME_UV_VER_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, + RKVPSS_ZME_Y_VER_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, + RKVPSS_ZME_UV_VER_COE0_10 + i * 16 + j * 2, + val, VPSS_UNITE_RIGHT); + } } } } else { y_yscl_fac = 0; uv_yscl_fac = 0; } - rkvpss_write(dev, RKVPSS_ZME_Y_YSCL_FACTOR, y_yscl_fac); - rkvpss_write(dev, RKVPSS_ZME_UV_YSCL_FACTOR, uv_yscl_fac); - rkvpss_write(dev, RKVPSS_ZME_Y_SCL_CTRL, ctrl); - rkvpss_write(dev, RKVPSS_ZME_UV_SCL_CTRL, ctrl); + if (dev->unite_mode) { + /* unite left */ + rkvpss_idx_write(dev, RKVPSS_ZME_Y_YSCL_FACTOR, y_yscl_fac, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_YSCL_FACTOR, uv_yscl_fac, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_SCL_CTRL, ctrl, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_SCL_CTRL, ctrl, VPSS_UNITE_LEFT); + + /* unite right */ + rkvpss_idx_write(dev, RKVPSS_ZME_Y_YSCL_FACTOR, y_yscl_fac, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_YSCL_FACTOR, uv_yscl_fac, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_Y_SCL_CTRL, ctrl, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_UV_SCL_CTRL, ctrl, VPSS_UNITE_RIGHT); + } else { + rkvpss_unite_write(dev, RKVPSS_ZME_Y_YSCL_FACTOR, y_yscl_fac); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_YSCL_FACTOR, uv_yscl_fac); + rkvpss_unite_write(dev, RKVPSS_ZME_Y_SCL_CTRL, ctrl); + rkvpss_unite_write(dev, RKVPSS_ZME_UV_SCL_CTRL, ctrl); + } + + if (dev->unite_mode) { + /* unite left */ + val = out_w / 2; + rkvpss_idx_write(dev, RKVPSS_ZME_H_SIZE, (val << 16) | val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_H_OFFS, 0, VPSS_UNITE_LEFT); + + /* unite right */ + rkvpss_idx_write(dev, RKVPSS_ZME_H_SIZE, (val << 16) | val, VPSS_UNITE_RIGHT); + rkvpss_idx_write(dev, RKVPSS_ZME_H_OFFS, 0, VPSS_UNITE_RIGHT); + val = out_w / 2 - ALIGN_DOWN(out_w / 2, 16); + rkvpss_idx_write(dev, RKVPSS_ZME_H_OFFS, (3 << 20) | (3 << 16) | + (stream->unite_params.scl_in_crop_w_y << 8) | + (stream->unite_params.scl_in_crop_w_c << 12) | + (val << 4) | val, VPSS_UNITE_RIGHT); + } ctrl = RKVPSS_ZME_GATING_EN; if (yuv420_in) ctrl |= RKVPSS_ZME_SCL_YUV420_REAL_EN; if (yuv422_to_420) ctrl |= RKVPSS_ZME_422TO420_EN; - rkvpss_write(dev, RKVPSS_ZME_CTRL, ctrl); + if (dev->unite_mode) { + /* unite left */ + ctrl |= RKVPSS_ZME_CLIP_EN | RKVPSS_ZME_8K_EN; + rkvpss_idx_write(dev, RKVPSS_ZME_CTRL, ctrl, VPSS_UNITE_LEFT); + + /* unite left */ + ctrl |= RKVPSS_ZME_IN_CLIP_EN; + rkvpss_idx_write(dev, RKVPSS_ZME_CTRL, ctrl, VPSS_UNITE_RIGHT); + } else { + rkvpss_unite_write(dev, RKVPSS_ZME_CTRL, ctrl); + } val = RKVPSS_ZME_GEN_UPD; if (sync) val |= RKVPSS_ZME_FORCE_UPD; - rkvpss_write(dev, RKVPSS_ZME_UPDATE, val); + rkvpss_unite_write(dev, RKVPSS_ZME_UPDATE, val); + if (dev->unite_mode) { + rkvpss_idx_write(dev, RKVPSS_ZME_UPDATE, val, VPSS_UNITE_LEFT); + rkvpss_idx_write(dev, RKVPSS_ZME_UPDATE, val, VPSS_UNITE_RIGHT); + } } static void bilinear_scale(struct rkvpss_stream *stream, bool on, bool sync) @@ -1007,68 +1280,184 @@ static void bilinear_scale(struct rkvpss_stream *stream, bool on, bool sync) if (!on) { reg = stream->config->scale.ctrl; - rkvpss_write(dev, reg, 0); + rkvpss_unite_write(dev, reg, 0); return; } - /* TODO diff for input and output format */ - if (yuv420_in) { - in_div = 2; - out_div = 2; - } else if (yuv422_to_420) { - in_div = 1; - out_div = 2; + if (!dev->unite_mode) { + /* TODO diff for input and output format */ + if (yuv420_in) { + in_div = 2; + out_div = 2; + } else if (yuv422_to_420) { + in_div = 1; + out_div = 2; + } else { + in_div = 1; + out_div = 1; + } + + reg = stream->config->scale.hy_offs; + rkvpss_unite_write(dev, reg, 0); + reg = stream->config->scale.hc_offs; + rkvpss_unite_write(dev, reg, 0); + reg = stream->config->scale.vy_offs; + rkvpss_unite_write(dev, reg, 0); + reg = stream->config->scale.vc_offs; + rkvpss_unite_write(dev, reg, 0); + + val = in_w | (in_h << 16); + reg = stream->config->scale.src_size; + rkvpss_unite_write(dev, reg, val); + val = out_w | (out_h << 16); + reg = stream->config->scale.dst_size; + rkvpss_unite_write(dev, reg, val); + + if (in_w != out_w) { + val = (in_w - 1) * 4096 / (out_w - 1); + reg = stream->config->scale.hy_fac; + rkvpss_unite_write(dev, reg, val); + + val = (in_w / 2 - 1) * 4096 / (out_w / 2 - 1); + reg = stream->config->scale.hc_fac; + rkvpss_unite_write(dev, reg, val); + + ctrl |= RKVPSS_SCL_HY_EN | RKVPSS_SCL_HC_EN; + } + if (in_h != out_h) { + val = (in_h - 1) * 4096 / (out_h - 1); + reg = stream->config->scale.vy_fac; + rkvpss_unite_write(dev, reg, val); + + val = (in_h / in_div - 1) * 4096 / (out_h / out_div - 1); + reg = stream->config->scale.vc_fac; + rkvpss_unite_write(dev, reg, val); + + ctrl |= RKVPSS_SCL_VY_EN | RKVPSS_SCL_VC_EN; + } + + reg = stream->config->scale.ctrl; + rkvpss_unite_write(dev, reg, ctrl); + + val = RKVPSS_SCL_GEN_UPD; + if (sync) + val |= RKVPSS_SCL_FORCE_UPD; + reg = stream->config->scale.update; + rkvpss_unite_write(dev, reg, val); } else { - in_div = 1; - out_div = 1; + /* unite left */ + reg = stream->config->scale.in_crop_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + + reg = stream->config->scale.hy_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + reg = stream->config->scale.hc_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + reg = stream->config->scale.vy_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + reg = stream->config->scale.vc_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + + reg = stream->config->scale.hy_offs_mi; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + reg = stream->config->scale.hc_offs_mi; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_LEFT); + + if (in_w == out_w) + val = (in_w / 2) | (in_h << 16); + else + val = (in_w / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL) | (in_h << 16); + reg = stream->config->scale.src_size; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_LEFT); + val = (out_w / 2) | (out_h << 16); + reg = stream->config->scale.dst_size; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_LEFT); + + ctrl |= RKVPSS_SCL_CLIP_EN; + + if (in_w != out_w) { + reg = stream->config->scale.hy_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.y_w_fac, VPSS_UNITE_LEFT); + reg = stream->config->scale.hc_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.c_w_fac, VPSS_UNITE_LEFT); + ctrl |= RKVPSS_SCL_HY_EN | RKVPSS_SCL_HC_EN; + } + + if (in_h != out_h) { + reg = stream->config->scale.vy_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.y_h_fac, VPSS_UNITE_LEFT); + reg = stream->config->scale.vc_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.c_h_fac, VPSS_UNITE_LEFT); + ctrl |= RKVPSS_SCL_VY_EN | RKVPSS_SCL_VC_EN; + } + + reg = stream->config->scale.ctrl; + rkvpss_idx_write(dev, reg, ctrl, VPSS_UNITE_LEFT); + + val = RKVPSS_SCL_GEN_UPD; + if (sync) + val |= RKVPSS_SCL_FORCE_UPD; + reg = stream->config->scale.update; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_LEFT); + + /* unite right */ + ctrl = 0; + val = stream->unite_params.scl_in_crop_w_y | + (stream->unite_params.scl_in_crop_w_c << 4); + reg = stream->config->scale.in_crop_offs; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + + val = stream->unite_params.y_w_phase; + reg = stream->config->scale.hy_offs; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + val = stream->unite_params.c_w_phase; + reg = stream->config->scale.hc_offs; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + reg = stream->config->scale.vy_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_RIGHT); + reg = stream->config->scale.vc_offs; + rkvpss_idx_write(dev, reg, 0, VPSS_UNITE_RIGHT); + + val = out_w / 2 - ALIGN_DOWN(out_w / 2, 16); + reg = stream->config->scale.hy_offs_mi; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + reg = stream->config->scale.hc_offs_mi; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + + val = (in_w / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL) | (in_h << 16); + reg = stream->config->scale.src_size; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + val = (out_w / 2) | (out_h << 16); + reg = stream->config->scale.dst_size; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); + + ctrl |= RKVPSS_SCL_CLIP_EN | RKVPSS_SCL_IN_CLIP_EN; + + if (in_w != out_w) { + reg = stream->config->scale.hy_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.y_w_fac, VPSS_UNITE_RIGHT); + reg = stream->config->scale.hc_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.c_w_fac, VPSS_UNITE_RIGHT); + ctrl |= RKVPSS_SCL_HY_EN | RKVPSS_SCL_HC_EN; + } + + if (in_h != out_h) { + reg = stream->config->scale.vy_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.y_h_fac, VPSS_UNITE_RIGHT); + reg = stream->config->scale.vc_fac; + rkvpss_idx_write(dev, reg, stream->unite_params.c_h_fac, VPSS_UNITE_RIGHT); + ctrl |= RKVPSS_SCL_VY_EN | RKVPSS_SCL_VC_EN; + } + + reg = stream->config->scale.ctrl; + rkvpss_idx_write(dev, reg, ctrl, VPSS_UNITE_RIGHT); + + val = RKVPSS_SCL_GEN_UPD; + if (sync) + val |= RKVPSS_SCL_FORCE_UPD; + reg = stream->config->scale.update; + rkvpss_idx_write(dev, reg, val, VPSS_UNITE_RIGHT); } - - reg = stream->config->scale.hy_offs; - rkvpss_write(dev, reg, 0); - reg = stream->config->scale.hc_offs; - rkvpss_write(dev, reg, 0); - reg = stream->config->scale.vy_offs; - rkvpss_write(dev, reg, 0); - reg = stream->config->scale.vc_offs; - rkvpss_write(dev, reg, 0); - - val = in_w | (in_h << 16); - reg = stream->config->scale.src_size; - rkvpss_write(dev, reg, val); - val = out_w | (out_h << 16); - reg = stream->config->scale.dst_size; - rkvpss_write(dev, reg, val); - - if (in_w != out_w) { - val = (in_w - 1) * 4096 / (out_w - 1); - reg = stream->config->scale.hy_fac; - rkvpss_write(dev, reg, val); - - val = (in_w / 2 - 1) * 4096 / (out_w / 2 - 1); - reg = stream->config->scale.hc_fac; - rkvpss_write(dev, reg, val); - - ctrl |= RKVPSS_SCL_HY_EN | RKVPSS_SCL_HC_EN; - } - if (in_h != out_h) { - val = (in_h - 1) * 4096 / (out_h - 1); - reg = stream->config->scale.vy_fac; - rkvpss_write(dev, reg, val); - - val = (in_h / in_div - 1) * 4096 / (out_h / out_div - 1); - reg = stream->config->scale.vc_fac; - rkvpss_write(dev, reg, val); - - ctrl |= RKVPSS_SCL_VY_EN | RKVPSS_SCL_VC_EN; - } - reg = stream->config->scale.ctrl; - rkvpss_write(dev, reg, ctrl); - - val = RKVPSS_SCL_GEN_UPD; - if (sync) - val |= RKVPSS_SCL_FORCE_UPD; - reg = stream->config->scale.update; - rkvpss_write(dev, reg, val); } static int rkvpss_stream_scale(struct rkvpss_stream *stream, bool on, bool sync) @@ -1086,10 +1475,12 @@ static void rkvpss_stream_stop(struct rkvpss_stream *stream) int ret; stream->stopping = true; - ret = wait_event_timeout(stream->done, !stream->streaming, - msecs_to_jiffies(300)); - if (!ret) - v4l2_warn(&dev->v4l2_dev, "%s id:%d timeout\n", __func__, stream->id); + if (atomic_read(&dev->pipe_stream_cnt) > 0) { + ret = wait_event_timeout(stream->done, !stream->streaming, + msecs_to_jiffies(300)); + if (!ret) + v4l2_warn(&dev->v4l2_dev, "%s id:%d timeout\n", __func__, stream->id); + } stream->stopping = false; stream->streaming = false; if (stream->ops->disable_mi) @@ -1112,8 +1503,14 @@ static void rkvpss_stop_streaming(struct vb2_queue *queue) v4l2_dbg(1, rkvpss_debug, &dev->v4l2_dev, "%s %s id:%d enter\n", __func__, node->vdev.name, stream->id); - rkvpss_stream_stop(stream); - rkvpss_pipeline_stream(dev, false); + + if (atomic_read(&dev->pipe_stream_cnt) == 1) { + rkvpss_pipeline_stream(dev, false); + rkvpss_stream_stop(stream); + } else { + rkvpss_stream_stop(stream); + rkvpss_pipeline_stream(dev, false); + } destroy_buf_queue(stream, VB2_BUF_STATE_ERROR); rkvpss_pipeline_close(dev); tasklet_disable(&stream->buf_done_tasklet); @@ -1161,10 +1558,15 @@ static int check_wr_uvswap(struct rkvpss_stream *stream) return ret; } + static int rkvpss_stream_start(struct rkvpss_stream *stream) { + struct rkvpss_device *dev = stream->dev; int ret = 0; + if (dev->unite_mode) + calc_unite_scl_params(stream); + stream->is_crop_upd = true; ret = rkvpss_stream_scale(stream, true, true); if (ret < 0) @@ -1523,6 +1925,7 @@ static int rkvpss_s_selection(struct file *file, void *prv, sel->r.left, sel->r.top, sel->r.width, sel->r.height, max_w, max_h); return -EINVAL; } + *crop = sel->r; stream->is_crop_upd = true; v4l2_dbg(1, rkvpss_debug, &dev->v4l2_dev, @@ -1560,11 +1963,11 @@ static void rkvpss_stream_mf(struct rkvpss_stream *stream) if (!dev->hw_dev->is_ofl_cmsc) { mask = RKVPSS_MIR_EN; val = dev->mir_en ? RKVPSS_MIR_EN : 0; - rkvpss_set_bits(dev, RKVPSS_VPSS_CTRL, mask, val); + rkvpss_unite_set_bits(dev, RKVPSS_VPSS_CTRL, mask, val); } mask = RKVPSS_MI_CHN_V_FLIP(stream->id); val = stream->flip_en ? mask : 0; - rkvpss_set_bits(dev, RKVPSS_MI_WR_VFLIP_CTRL, mask, val); + rkvpss_unite_set_bits(dev, RKVPSS_MI_WR_VFLIP_CTRL, mask, val); } static int rkvpss_get_mirror_flip(struct rkvpss_stream *stream, @@ -1593,12 +1996,76 @@ static int rkvpss_set_mirror_flip(struct rkvpss_stream *stream, return 0; } +static void cmsc_config_hw(struct rkvpss_device *dev, struct rkvpss_cmsc_cfg *cfg, bool sync, + int unite_index) +{ + int i, j, k, slope, hor; + u32 win_en, mode, val, ctrl = 0; + + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + win_en = cfg->win[i].win_en; + v4l2_dbg(4, rkvpss_debug, &dev->v4l2_dev, + "%s unite:%d, unite_index:%d ch:%d win_en:0x%x\n", __func__, + dev->unite_mode, unite_index, i, win_en); + if (win_en) + ctrl |= RKVPSS_CMSC_CHN_EN(i); + rkvpss_idx_write(dev, RKVPSS_CMSC_CHN0_WIN + i * 4, win_en, unite_index); + + mode = cfg->win[i].mode; + rkvpss_idx_write(dev, RKVPSS_CMSC_CHN0_MODE + i * 4, mode, unite_index); + + for (j = 0; j < RKVPSS_CMSC_WIN_MAX && win_en; j++) { + if (!(win_en & BIT(j))) + continue; + for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { + val = RKVPSS_CMSC_WIN_VTX(cfg->win[j].point[k].x, + cfg->win[j].point[k].y); + rkvpss_idx_write(dev, RKVPSS_CMSC_WIN0_L0_VTX + k * 8 + j * 32, val, + unite_index); + + rkvpss_cmsc_slop(&cfg->win[j].point[k], + (k + 1 == RKVPSS_CMSC_POINT_MAX) ? + &cfg->win[j].point[0] : &cfg->win[j].point[k + 1], + &slope, &hor); + val = RKVPSS_CMSC_WIN_SLP(slope, hor); + rkvpss_idx_write(dev, RKVPSS_CMSC_WIN0_L0_SLP + k * 8 + j * 32, val, + unite_index); + v4l2_dbg(4, rkvpss_debug, &dev->v4l2_dev, + "%s unite:%d unite_index:%d ch:%d win:%d point:%d x:%u y:%u", + __func__, dev->unite_mode, unite_index, i, j, k, + cfg->win[j].point[k].x, + cfg->win[j].point[k].y); + } + + if ((mode & BIT(j))) + continue; + val = RKVPSS_CMSK_WIN_YUV(cfg->win[j].cover_color_y, + cfg->win[j].cover_color_u, + cfg->win[j].cover_color_v); + val |= RKVPSS_CMSC_WIN_ALPHA(cfg->win[j].cover_color_a); + rkvpss_idx_write(dev, RKVPSS_CMSC_WIN0_PARA + j * 4, val, unite_index); + } + } + + if (ctrl) { + ctrl |= RKVPSS_CMSC_EN; + ctrl |= RKVPSS_CMSC_BLK_SZIE(cfg->mosaic_block); + } + rkvpss_idx_write(dev, RKVPSS_CMSC_CTRL, ctrl, unite_index); + val = RKVPSS_CMSC_GEN_UPD; + if (sync) + val |= RKVPSS_CMSC_FORCE_UPD; + rkvpss_idx_write(dev, RKVPSS_CMSC_UPDATE, val, unite_index); +} + void rkvpss_cmsc_config(struct rkvpss_device *dev, bool sync) { unsigned long lock_flags = 0; - struct rkvpss_cmsc_cfg cfg; - int i, j, k, slope, hor; - u32 win_en, mode, val, ctrl = 0; + struct rkvpss_cmsc_cfg left_cfg = {0}, right_cfg = {0}; + struct rkvpss_cmsc_win *win; + struct rkvpss_cmsc_point *point; + int i, j, k; + u32 mask; spin_lock_irqsave(&dev->cmsc_lock, lock_flags); if (dev->hw_dev->is_ofl_cmsc || !dev->cmsc_upd) { @@ -1606,53 +2073,123 @@ void rkvpss_cmsc_config(struct rkvpss_device *dev, bool sync) return; } dev->cmsc_upd = false; - cfg = dev->cmsc_cfg; spin_unlock_irqrestore(&dev->cmsc_lock, lock_flags); - for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { - win_en = cfg.win[i].win_en; - if (win_en) - ctrl |= RKVPSS_CMSC_CHN_EN(i); - rkvpss_write(dev, RKVPSS_CMSC_CHN0_WIN + i * 4, win_en); - - mode = cfg.win[i].mode; - rkvpss_write(dev, RKVPSS_CMSC_CHN0_MODE + i * 4, mode); - - for (j = 0; j < RKVPSS_CMSC_WIN_MAX && win_en; j++) { - if (!(win_en & BIT(j))) - continue; - for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { - val = RKVPSS_CMSC_WIN_VTX(cfg.win[j].point[k].x, - cfg.win[j].point[k].y); - rkvpss_write(dev, RKVPSS_CMSC_WIN0_L0_VTX + k * 8 + j * 32, val); - - rkvpss_cmsc_slop(&cfg.win[j].point[k], - (k + 1 == RKVPSS_CMSC_POINT_MAX) ? - &cfg.win[j].point[0] : &cfg.win[j].point[k + 1], - &slope, &hor); - val = RKVPSS_CMSC_WIN_SLP(slope, hor); - rkvpss_write(dev, RKVPSS_CMSC_WIN0_L0_SLP + k * 8 + j * 32, val); - } - - if ((mode & BIT(j))) - continue; - val = RKVPSS_CMSK_WIN_YUV(cfg.win[j].cover_color_y, - cfg.win[j].cover_color_u, - cfg.win[j].cover_color_v); - val |= RKVPSS_CMSC_WIN_ALPHA(cfg.win[j].cover_color_a); - rkvpss_write(dev, RKVPSS_CMSC_WIN0_PARA + j * 4, val); + if (dev->unite_mode) { + /* unite left */ + for (i = 0; i < RKVPSS_CMSC_WIN_MAX; i++) { + left_cfg.win[i].cover_color_y = dev->cmsc_cfg.win[i].cover_color_y; + left_cfg.win[i].cover_color_u = dev->cmsc_cfg.win[i].cover_color_u; + left_cfg.win[i].cover_color_v = dev->cmsc_cfg.win[i].cover_color_v; + left_cfg.win[i].cover_color_a = dev->cmsc_cfg.win[i].cover_color_a; + for (j = 0; j < RKVPSS_CMSC_POINT_MAX; j++) + left_cfg.win[i].point[j] = dev->cmsc_cfg.win[i].point[j]; + } + left_cfg.mosaic_block = dev->cmsc_cfg.mosaic_block; + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + left_cfg.win[i].win_en = dev->cmsc_cfg.win[i].win_en; + left_cfg.win[i].mode = dev->cmsc_cfg.win[i].mode; } - } - if (ctrl) { - ctrl |= RKVPSS_CMSC_EN; - ctrl |= RKVPSS_CMSC_BLK_SZIE(cfg.mosaic_block); + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + for (j = 0; j < RKVPSS_CMSC_WIN_MAX; j++) { + win = &left_cfg.win[j]; + if (!(left_cfg.win[i].win_en & BIT(j))) + continue; + mask = 0; + for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { + point = &win->point[k]; + if (point->x >= dev->vpss_sdev.in_fmt.width / 2) + mask |= BIT(k); + else + mask &= ~BIT(k); + } + if (mask == 0xf) { + /** all right **/ + left_cfg.win[i].win_en &= ~BIT(j); + } else if (mask != 0) { + /** middle need avoid pentagon **/ + if (win->point[0].x != win->point[3].x || + win->point[1].x != win->point[2].x) { + left_cfg.win[i].win_en &= ~BIT(j); + } else { + win->point[1].x = dev->vpss_sdev.in_fmt.width / 2; + win->point[2].x = dev->vpss_sdev.in_fmt.width / 2; + } + } + } + } + + /* unite right */ + for (i = 0; i < RKVPSS_CMSC_WIN_MAX; i++) { + right_cfg.win[i].cover_color_y = dev->cmsc_cfg.win[i].cover_color_y; + right_cfg.win[i].cover_color_u = dev->cmsc_cfg.win[i].cover_color_u; + right_cfg.win[i].cover_color_v = dev->cmsc_cfg.win[i].cover_color_v; + right_cfg.win[i].cover_color_a = dev->cmsc_cfg.win[i].cover_color_a; + + for (j = 0; j < RKVPSS_CMSC_POINT_MAX; j++) + right_cfg.win[i].point[j] = dev->cmsc_cfg.win[i].point[j]; + } + right_cfg.mosaic_block = dev->cmsc_cfg.mosaic_block; + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + right_cfg.win[i].win_en = dev->cmsc_cfg.win[i].win_en; + right_cfg.win[i].mode = dev->cmsc_cfg.win[i].mode; + } + + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + for (j = 0; j < RKVPSS_CMSC_WIN_MAX; j++) { + win = &right_cfg.win[j]; + if (!(right_cfg.win[i].win_en & BIT(j))) + continue; + mask = 0; + for (k = 0; k < RKVPSS_CMSC_POINT_MAX; k++) { + point = &win->point[k]; + if (point->x <= dev->vpss_sdev.in_fmt.width / 2) + mask |= BIT(k); + else + mask &= ~BIT(k); + } + if (mask == 0xf) { + /** all left **/ + right_cfg.win[i].win_en &= ~BIT(j); + } else if (mask != 0) { + /** middle need avoid pentagon **/ + if (win->point[0].x != win->point[3].x || + win->point[1].x != win->point[2].x) { + right_cfg.win[i].win_en &= ~BIT(j); + } else { + win->point[0].x = RKMOUDLE_UNITE_EXTEND_PIXEL; + win->point[3].x = RKMOUDLE_UNITE_EXTEND_PIXEL; + win->point[1].x = win->point[1].x - + (dev->vpss_sdev.in_fmt.width / 2) + + RKMOUDLE_UNITE_EXTEND_PIXEL; + win->point[2].x = win->point[2].x - + (dev->vpss_sdev.in_fmt.width / 2) + + RKMOUDLE_UNITE_EXTEND_PIXEL; + } + } else { + /** all right **/ + win->point[0].x = win->point[0].x - + (dev->vpss_sdev.in_fmt.width / 2) + + RKMOUDLE_UNITE_EXTEND_PIXEL; + win->point[1].x = win->point[1].x - + (dev->vpss_sdev.in_fmt.width / 2) + + RKMOUDLE_UNITE_EXTEND_PIXEL; + win->point[2].x = win->point[2].x - + (dev->vpss_sdev.in_fmt.width / 2) + + RKMOUDLE_UNITE_EXTEND_PIXEL; + win->point[3].x = win->point[3].x - + (dev->vpss_sdev.in_fmt.width / 2) + + RKMOUDLE_UNITE_EXTEND_PIXEL; + } + } + } + + cmsc_config_hw(dev, &left_cfg, sync, VPSS_UNITE_LEFT); + cmsc_config_hw(dev, &right_cfg, sync, VPSS_UNITE_RIGHT); + } else { + cmsc_config_hw(dev, &dev->cmsc_cfg, sync, VPSS_UNITE_LEFT); } - rkvpss_write(dev, RKVPSS_CMSC_CTRL, ctrl); - val = RKVPSS_CMSC_GEN_UPD; - if (sync) - val |= RKVPSS_CMSC_FORCE_UPD; - rkvpss_write(dev, RKVPSS_CMSC_UPDATE, val); } static int rkvpss_get_cmsc(struct rkvpss_stream *stream, struct rkvpss_cmsc_cfg *cfg) @@ -1722,6 +2259,11 @@ static int rkvpss_set_cmsc(struct rkvpss_stream *stream, struct rkvpss_cmsc_cfg dev->cmsc_cfg.win[stream->id].mode = mode; dev->cmsc_cfg.mosaic_block = cfg->mosaic_block; dev->cmsc_upd = true; + v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, + "%s ch:%d win_en:0x%x", + __func__, stream->id, + dev->cmsc_cfg.win[stream->id].win_en); + unlock: spin_unlock_irqrestore(&dev->cmsc_lock, lock_flags); return ret; @@ -1931,7 +2473,7 @@ void rkvpss_isr(struct rkvpss_device *dev, u32 mis_val) "isr:0x%x\n", mis_val); dev->isr_cnt++; if (mis_val & RKVPSS_ISP_ALL_FRM_END && dev->remote_sd) - v4l2_subdev_call(dev->remote_sd, core, ioctl, RKISP_VPSS_CMD_EOF, NULL); + rkvpss_check_idle(dev, VPSS_FRAME_END); } void rkvpss_mi_isr(struct rkvpss_device *dev, u32 mis_val) @@ -1941,8 +2483,6 @@ void rkvpss_mi_isr(struct rkvpss_device *dev, u32 mis_val) v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, "mi isr:0x%x, ris:0x%x\n", mis_val, ris); - if (mis_val & RKVPSS_MI_BUS_ERR) - v4l2_warn(&dev->v4l2_dev, "axi bus error\n"); for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { stream = &dev->stream_vdev.stream[i]; @@ -1951,13 +2491,17 @@ void rkvpss_mi_isr(struct rkvpss_device *dev, u32 mis_val) !(ris & stream->config->frame_end_id)) continue; writel(stream->config->frame_end_id, dev->hw_dev->base_addr + RKVPSS_MI_ICR); - if (stream->stopping) { - stream->stopping = false; - stream->streaming = false; - stream->ops->disable_mi(stream); - wake_up(&stream->done); - } else { - rkvpss_frame_end(stream); + + if (!dev->unite_mode || dev->unite_index == VPSS_UNITE_RIGHT) { + if (stream->stopping) { + stream->stopping = false; + stream->streaming = false; + stream->ops->disable_mi(stream); + wake_up(&stream->done); + } else { + rkvpss_frame_end(stream); + } } } + rkvpss_check_idle(dev, (ris & 0xf) << 3); } diff --git a/drivers/media/platform/rockchip/vpss/stream.h b/drivers/media/platform/rockchip/vpss/stream.h index 23b1e75a786e..531a6cc6b7dd 100644 --- a/drivers/media/platform/rockchip/vpss/stream.h +++ b/drivers/media/platform/rockchip/vpss/stream.h @@ -120,6 +120,20 @@ struct frame_debug_info { u32 frameloss; }; +struct rkvpss_online_unite_params { + u32 y_w_fac; + u32 c_w_fac; + u32 y_h_fac; + u32 c_h_fac; + u32 y_w_phase; + u32 c_w_phase; + u32 quad_crop_w; + u32 scl_in_crop_w_y; + u32 scl_in_crop_w_c; + u32 right_scl_need_size_y; + u32 right_scl_need_size_c; +}; + /* struct rkvpss_stream - VPSS stream video device * id: stream video identify * buf_queue: queued buffer list @@ -154,6 +168,7 @@ struct rkvpss_stream { struct v4l2_rect crop; struct v4l2_pix_format_mplane out_fmt; struct frame_debug_info dbg; + struct rkvpss_online_unite_params unite_params; int id; bool streaming; diff --git a/drivers/media/platform/rockchip/vpss/vpss.c b/drivers/media/platform/rockchip/vpss/vpss.c index e6561115fec7..3dd809ea1448 100644 --- a/drivers/media/platform/rockchip/vpss/vpss.c +++ b/drivers/media/platform/rockchip/vpss/vpss.c @@ -148,8 +148,8 @@ static int rkvpss_sd_s_stream(struct v4l2_subdev *sd, int on) "s_stream on:%d %dx%d\n", on, w, h); if (!on) { - rkvpss_clear_bits(dev, RKVPSS_VPSS_ONLINE, RKVPSS_ONLINE_MODE_MASK); - rkvpss_clear_bits(dev, RKVPSS_VPSS_IMSC, RKVPSS_ISP_ALL_FRM_END); + rkvpss_unite_clear_bits(dev, RKVPSS_VPSS_ONLINE, RKVPSS_ONLINE_MODE_MASK); + rkvpss_unite_clear_bits(dev, RKVPSS_VPSS_IMSC, RKVPSS_ISP_ALL_FRM_END); sdev->state = VPSS_STOP; atomic_dec(&dev->hw_dev->refcnt); return 0; @@ -158,18 +158,23 @@ static int rkvpss_sd_s_stream(struct v4l2_subdev *sd, int on) sdev->frame_seq = -1; sdev->frame_timestamp = 0; dev->isr_cnt = 0; + dev->irq_ends = 0; atomic_inc(&dev->hw_dev->refcnt); dev->cmsc_upd = true; rkvpss_cmsc_config(dev, true); - rkvpss_write(dev, RKVPSS_VPSS_ONLINE2_SIZE, h << 16 | w); + + if (dev->unite_mode) + w = w / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL; + + rkvpss_unite_write(dev, RKVPSS_VPSS_ONLINE2_SIZE, h << 16 | w); val = RKVPSS_CFG_FORCE_UPD | RKVPSS_CFG_GEN_UPD | RKVPSS_MIR_GEN_UPD; if (!dev->hw_dev->is_ofl_cmsc) val |= RKVPSS_MIR_FORCE_UPD; - rkvpss_write(dev, RKVPSS_VPSS_UPDATE, val); + rkvpss_unite_write(dev, RKVPSS_VPSS_UPDATE, val); - rkvpss_set_bits(dev, RKVPSS_VPSS_IMSC, 0, RKVPSS_ISP_ALL_FRM_END); + rkvpss_unite_set_bits(dev, RKVPSS_VPSS_IMSC, 0, RKVPSS_ISP_ALL_FRM_END); sdev->state |= VPSS_START; return 0; } @@ -209,6 +214,8 @@ static int rkvpss_sd_s_power(struct v4l2_subdev *sd, int on) return ret; } } + v4l2_subdev_call(dev->remote_sd, core, ioctl, RKISP_VPSS_GET_UNITE_MODE, + &dev->unite_mode); ret = pm_runtime_get_sync(dev->dev); if (ret < 0) { v4l2_err(&dev->v4l2_dev, @@ -232,11 +239,17 @@ static int rkvpss_sof(struct rkvpss_subdev *sdev, struct rkisp_vpss_sof *info) struct rkvpss_hw_dev *hw = dev->hw_dev; struct rkvpss_stream *stream; int i; + u32 vpss_online, val = 0; if (!info) return -EINVAL; sdev->frame_seq = info->seq; sdev->frame_timestamp = info->timestamp; + dev->unite_index = info->unite_index; + + v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, + "%s unite_mode:%u, unite_indev:%u\n", __func__, + dev->unite_mode, dev->unite_index); rkvpss_cmsc_config(dev, !info->irq); for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { @@ -247,7 +260,7 @@ static int rkvpss_sof(struct rkvpss_subdev *sdev, struct rkisp_vpss_sof *info) stream->ops->frame_start(stream, info->irq); } - if (!info->irq && !hw->is_single) { + if (!info->irq && (!hw->is_single || dev->unite_mode)) { hw->cur_dev_id = dev->dev_id; rkvpss_update_regs(dev, RKVPSS_VPSS_CTRL, RKVPSS_VPSS_ONLINE2_SIZE); rkvpss_update_regs(dev, RKVPSS_VPSS_IRQ_CFG, RKVPSS_VPSS_IMSC); @@ -262,7 +275,7 @@ static int rkvpss_sof(struct rkvpss_subdev *sdev, struct rkisp_vpss_sof *info) rkvpss_update_regs(dev, RKVPSS_MI_WR_WRAP_CTRL, RKVPSS_MI_IMSC); rkvpss_update_regs(dev, RKVPSS_MI_CHN0_WR_CTRL, RKVPSS_MI_CHN3_WR_LINE_CNT); - rkvpss_update_regs(dev, RKVPSS_MI_WR_CTRL, RKVPSS_MI_WR_INIT); + rkvpss_update_regs(dev, RKVPSS_MI_WR_CTRL, RKVPSS_MI_WR_CTRL); rkvpss_update_regs(dev, RKVPSS_SCALE3_CTRL, RKVPSS_SCALE3_UPDATE); rkvpss_update_regs(dev, RKVPSS_SCALE2_CTRL, RKVPSS_SCALE2_UPDATE); rkvpss_update_regs(dev, RKVPSS_SCALE1_CTRL, RKVPSS_SCALE1_UPDATE); @@ -270,6 +283,23 @@ static int rkvpss_sof(struct rkvpss_subdev *sdev, struct rkisp_vpss_sof *info) rkvpss_update_regs(dev, RKVPSS_CROP1_CTRL, RKVPSS_CROP1_UPDATE); rkvpss_update_regs(dev, RKVPSS_CMSC_CTRL, RKVPSS_CMSC_UPDATE); rkvpss_update_regs(dev, RKVPSS_VPSS_UPDATE, RKVPSS_VPSS_UPDATE); + + /* force update mi write */ + vpss_online = rkvpss_hw_read(hw, RKVPSS_VPSS_ONLINE); + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + if (((vpss_online >> (2 * i)) & 0x3) == 0x2) + val |= BIT(i); + } + rkvpss_unite_write(dev, RKVPSS_MI_WR_INIT, val << 4); + rkvpss_update_regs(dev, RKVPSS_MI_WR_INIT, RKVPSS_MI_WR_INIT); + } + + dev->irq_ends_mask = VPSS_FRAME_END; + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + if (hw->is_ofl_ch[i]) + continue; + if (rkvpss_hw_read(dev->hw_dev, RKVPSS_MI_CHN0_WR_CTRL_SHD + i * 0x100) & 0x1) + dev->irq_ends_mask |= BIT(i+3); } return 0; } @@ -342,6 +372,54 @@ static void rkvpss_subdev_default_fmt(struct rkvpss_subdev *sdev) out_fmt->height = RKVPSS_DEFAULT_HEIGHT; } +static void rkvpss_end_notify_isp(struct rkvpss_device *dev) +{ + int stopping; + + v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, + "%s stopping:%d unite_index:%d\n", __func__, dev->stopping, dev->unite_index); + + if (dev->stopping) { + if (dev->unite_mode) { + if (dev->unite_index == VPSS_UNITE_LEFT) { + stopping = 0; + v4l2_subdev_call(dev->remote_sd, core, ioctl, RKISP_VPSS_CMD_EOF, + &stopping); + } else { + dev->stopping = false; + wake_up(&dev->stop_done); + stopping = 1; + v4l2_subdev_call(dev->remote_sd, core, ioctl, RKISP_VPSS_CMD_EOF, + &stopping); + } + } else { + dev->stopping = false; + wake_up(&dev->stop_done); + stopping = 1; + v4l2_subdev_call(dev->remote_sd, core, ioctl, RKISP_VPSS_CMD_EOF, + &stopping); + } + } else { + stopping = 0; + v4l2_subdev_call(dev->remote_sd, core, ioctl, RKISP_VPSS_CMD_EOF, &stopping); + } +} + +void rkvpss_check_idle(struct rkvpss_device *dev, u32 irq) +{ + dev->irq_ends |= (irq & dev->irq_ends_mask); + + v4l2_dbg(3, rkvpss_debug, &dev->v4l2_dev, + "%s irq:0x%x ends:0x%x mask:0x%x\n", + __func__, irq, dev->irq_ends, dev->irq_ends_mask); + + if ((dev->irq_ends & dev->irq_ends_mask) != dev->irq_ends_mask) + return; + + dev->irq_ends = 0; + rkvpss_end_notify_isp(dev); +} + int rkvpss_register_subdev(struct rkvpss_device *dev, struct v4l2_device *v4l2_dev) { diff --git a/drivers/media/platform/rockchip/vpss/vpss.h b/drivers/media/platform/rockchip/vpss/vpss.h index 06ef58628e13..f4f7eadf5d0e 100644 --- a/drivers/media/platform/rockchip/vpss/vpss.h +++ b/drivers/media/platform/rockchip/vpss/vpss.h @@ -18,6 +18,11 @@ enum rkvpss_state { VPSS_STOP = 0, VPSS_FS = BIT(0), VPSS_FE = BIT(1), + VPSS_FRAME_END = BIT(2), + VPSS_FRAME_SCL0 = BIT(3), + VPSS_FRAME_SCL1 = BIT(4), + VPSS_FRAME_SCL2 = BIT(5), + VPSS_FRAME_SCL3 = BIT(6), VPSS_START = BIT(8), VPSS_RX_START = BIT(9), @@ -46,4 +51,5 @@ struct rkvpss_subdev { int rkvpss_register_subdev(struct rkvpss_device *dev, struct v4l2_device *v4l2_dev); void rkvpss_unregister_subdev(struct rkvpss_device *dev); +void rkvpss_check_idle(struct rkvpss_device *dev, u32 irq); #endif From 34c17d0724d5e26a4efda23502cfbbb612bcb994 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Fri, 21 Jun 2024 15:09:50 +0800 Subject: [PATCH 10/10] drm/rockchip: vop2: Support invalid phy id for vop2_plane_id_to_string ROCKCHIP_VOP2_PHY_ID_INVALID has a value of -1 that is out of range for vop2_layer_name_list. Convert it to "INVALID". Signed-off-by: Chaoyi Chen Change-Id: I0aaa36c5a51ef0227847567ca1b495d16470ee1b --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 615e217dbdee..d7f6f40a7c19 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -13828,6 +13828,9 @@ static char *vop2_plane_mask_to_string(unsigned long mask) static inline const char *vop2_plane_id_to_string(unsigned long phy) { + if (phy == ROCKCHIP_VOP2_PHY_ID_INVALID) + return "INVALID"; + if (WARN_ON(phy >= ARRAY_SIZE(vop2_layer_name_list))) return NULL;