diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 8370cd1f73..d7329bfb62 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -499,6 +499,8 @@ struct dsi_split_link_config { * cmd it points to the line after TE. * @dma_sched_window: Determines the width of the window during the * DSI command will be sent by the HW. + * @vpadding: panel stacking height. + * @line_insertion_enable: line insertion support enable. */ struct dsi_host_common_cfg { enum dsi_pixel_format dst_format; @@ -526,6 +528,8 @@ struct dsi_host_common_cfg { u32 byte_intf_clk_div; u32 dma_sched_line; u32 dma_sched_window; + u32 vpadding; + bool line_insertion_enable; }; /** diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 7a8ca00bb2..68b702a09d 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -641,6 +641,12 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps; mode_info->wd_jitter = dsi_mode->priv_info->wd_jitter; + if (dsi_display->panel) + mode_info->vpadding = dsi_display->panel->host_config.vpadding; + if (mode_info->vpadding < drm_mode->vdisplay) { + mode_info->vpadding = 0; + dsi_display->panel->host_config.line_insertion_enable = 0; + } memcpy(&mode_info->topology, &dsi_mode->priv_info->topology, sizeof(struct msm_display_topology)); diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 39eb8ee5d3..d2b9a0a6ff 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1179,7 +1179,8 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, host->dma_sched_window = 0; else host->dma_sched_window = window; - + rc = utils->read_u32(utils->data, "qcom,vert-padding-value", &host->vpadding); + host->line_insertion_enable = (rc || host->vpadding <= 0) ? false : true; DSI_DEBUG("[%s] DMA scheduling parameters Line: %d Window: %d\n", name, host->dma_sched_line, host->dma_sched_window); return 0; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index a5d1d17a33..68b0187b31 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -800,6 +800,7 @@ struct msm_display_wd_jitter_config { * @dyn_clk_list: List of dynamic clock rates for RFI. * @qsync_min_fps: qsync min fps rate * @wd_jitter: Info for WD jitter. + * @vpadding: panel stacking height */ struct msm_mode_info { uint32_t frame_rate; @@ -822,6 +823,7 @@ struct msm_mode_info { struct msm_dyn_clk_list dyn_clk_list; u32 qsync_min_fps; struct msm_display_wd_jitter_config wd_jitter; + u32 vpadding; }; /** diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 3feaece6d9..991353e549 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -3461,3 +3461,20 @@ int sde_connector_event_notify(struct drm_connector *connector, uint32_t type, return ret; } + +bool sde_connector_is_line_insertion_supported(struct sde_connector *sde_conn) +{ + struct dsi_display *display = NULL; + + if (!sde_conn) + return false; + + if (sde_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return false; + + display = (struct dsi_display *)sde_conn->display; + if (!display || !display->panel) + return false; + + return display->panel->host_config.line_insertion_enable; +} diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 42b29dd3bc..7628fa3f72 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -1275,4 +1275,12 @@ int sde_connector_esd_status(struct drm_connector *connector); const char *sde_conn_get_topology_name(struct drm_connector *conn, struct msm_display_topology topology); +/* + * sde_connector_is_line_insertion_supported - get line insertion + * feature bit value from panel + * @sde_conn: Pointer to sde connector structure + * @Return: line insertion support status + */ +bool sde_connector_is_line_insertion_supported(struct sde_connector *sde_conn); + #endif /* _SDE_CONNECTOR_H_ */ diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 7cce35d703..f0c8913bad 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -795,6 +795,22 @@ static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer, format->alpha_enable, fg_alpha, bg_alpha, blend_op); } +static void _sde_crtc_calc_split_dim_layer_yh_param(struct drm_crtc *crtc, u16 *y, u16 *h) +{ + u32 padding_y = 0, padding_start = 0, padding_height = 0; + struct sde_crtc_state *cstate; + + cstate = to_sde_crtc_state(crtc->state); + if (!cstate->line_insertion.panel_line_insertion_enable) + return; + + sde_crtc_calc_vpadding_param(crtc->state, *y, *h, &padding_y, + &padding_start, &padding_height); + + *y = padding_y; + *h = padding_height; +} + static void _sde_crtc_setup_dim_layer_cfg(struct drm_crtc *crtc, struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer, struct sde_hw_dim_layer *dim_layer) @@ -853,6 +869,11 @@ static void _sde_crtc_setup_dim_layer_cfg(struct drm_crtc *crtc, cstate->lm_roi[i].y; } + /* update dim layer rect for panel stacking crtc */ + if (cstate->line_insertion.padding_height) + _sde_crtc_calc_split_dim_layer_yh_param(crtc, &split_dim_layer.rect.y, + &split_dim_layer.rect.h); + SDE_EVT32(DRMID(crtc), dim_layer->stage, cstate->lm_roi[i].x, cstate->lm_roi[i].y, @@ -1394,6 +1415,100 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, return 0; } +static u32 _sde_crtc_calc_gcd(u32 a, u32 b) +{ + if (b == 0) + return a; + + return _sde_crtc_calc_gcd(b, a % b); +} + +static int _sde_crtc_check_panel_stacking(struct drm_crtc *crtc, struct drm_crtc_state *state) +{ + struct sde_kms *kms; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_crtc_state; + struct drm_connector *conn; + struct msm_mode_info mode_info; + struct drm_display_mode *adj_mode = &state->adjusted_mode; + struct msm_sub_mode sub_mode; + u32 gcd = 0, num_of_active_lines = 0, num_of_dummy_lines = 0; + int rc; + struct drm_encoder *encoder; + const u32 max_encoder_cnt = 1; + u32 encoder_cnt = 0; + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + sde_crtc_state = to_sde_crtc_state(state); + /* panel stacking only support single connector */ + drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) + encoder_cnt++; + + if (!kms->catalog->has_line_insertion || !state->mode_changed || + encoder_cnt > max_encoder_cnt) { + SDE_DEBUG("no line insertion support mode change %d enc cnt %d\n", + state->mode_changed, encoder_cnt); + sde_crtc_state->line_insertion.padding_height = 0; + return 0; + } + + conn = sde_crtc_state->connectors[0]; + rc = sde_connector_get_mode_info(conn, adj_mode, &sub_mode, &mode_info); + if (rc) { + SDE_ERROR("failed to get mode info %d\n", rc); + return -EINVAL; + } + + if (!mode_info.vpadding) { + sde_crtc_state->line_insertion.padding_height = 0; + return 0; + } + + if (mode_info.vpadding < state->mode.vdisplay) { + SDE_ERROR("padding height %d is less than vdisplay %d\n", + mode_info.vpadding, state->mode.vdisplay); + return -EINVAL; + } else if (mode_info.vpadding == state->mode.vdisplay) { + SDE_DEBUG("padding height %d is equal to the vdisplay %d\n", + mode_info.vpadding, state->mode.vdisplay); + sde_crtc_state->line_insertion.padding_height = 0; + return 0; + } else if (mode_info.vpadding == sde_crtc_state->line_insertion.padding_height) { + return 0; /* skip calculation if already cached */ + } + + gcd = _sde_crtc_calc_gcd(mode_info.vpadding, state->mode.vdisplay); + if (!gcd) { + SDE_ERROR("zero gcd found for padding height %d %d\n", + mode_info.vpadding, state->mode.vdisplay); + return -EINVAL; + } + num_of_active_lines = state->mode.vdisplay; + do_div(num_of_active_lines, gcd); + num_of_dummy_lines = mode_info.vpadding; + do_div(num_of_dummy_lines, gcd); + num_of_dummy_lines = num_of_dummy_lines - num_of_active_lines; + + if (num_of_active_lines > MAX_VPADDING_RATIO_M || + num_of_dummy_lines > MAX_VPADDING_RATIO_N) { + SDE_ERROR("unsupported panel stacking pattern %d:%d", num_of_active_lines, + num_of_dummy_lines); + return -EINVAL; + } + + sde_crtc_state->line_insertion.padding_active = num_of_active_lines; + sde_crtc_state->line_insertion.padding_dummy = num_of_dummy_lines; + sde_crtc_state->line_insertion.padding_height = mode_info.vpadding; + + return 0; +} + static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc; @@ -3587,6 +3702,26 @@ static void _sde_crtc_setup_mixer_for_encoder( } } +bool sde_crtc_is_line_insertion_supported(struct drm_crtc *crtc) +{ + struct drm_encoder *enc = NULL; + struct sde_kms *kms; + + if (!crtc) + return false; + + kms = _sde_crtc_get_kms(crtc); + if (!kms->catalog->has_line_insertion) + return false; + + list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { + if (enc->crtc == crtc) + return sde_encoder_is_line_insertion_supported(enc); + } + + return false; +} + static void _sde_crtc_setup_mixers(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); @@ -4821,6 +4956,8 @@ static void sde_crtc_enable(struct drm_crtc *crtc, SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc)); sde_crtc = to_sde_crtc(crtc); + cstate->line_insertion.panel_line_insertion_enable = + sde_crtc_is_line_insertion_supported(crtc); /* * Avoid drm_crtc_vblank_on during seamless DMS case @@ -5639,6 +5776,13 @@ static int _sde_crtc_atomic_check(struct drm_crtc *crtc, crtc->base.id, rc); goto end; } + + rc = _sde_crtc_check_panel_stacking(crtc, state); + if (rc) { + SDE_ERROR("crtc%d failed panel stacking check %d\n", + crtc->base.id, rc); + goto end; + } end: kfree(pstates); kfree(multirect_plane); @@ -7876,3 +8020,46 @@ void _sde_crtc_vm_release_notify(struct drm_crtc *crtc) sde_crtc_event_notify(crtc, DRM_EVENT_VM_RELEASE, &val, sizeof(uint32_t)); } + +void sde_crtc_calc_vpadding_param(struct drm_crtc_state *state, u32 crtc_y, uint32_t crtc_h, + u32 *padding_y, u32 *padding_start, u32 *padding_height) +{ + struct sde_kms *kms; + struct sde_crtc_state *cstate = to_sde_crtc_state(state); + u32 y_remain, y_start, y_end; + u32 m, n; + + kms = _sde_crtc_get_kms(state->crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms or catalog\n"); + return; + } + + if (!kms->catalog->has_line_insertion) + return; + + if (!cstate->line_insertion.padding_active) { + SDE_ERROR("zero padding active value\n"); + return; + } + + /* + * Computation logic to add number of dummy and active line at + * precise position on display + */ + m = cstate->line_insertion.padding_active; + n = m + cstate->line_insertion.padding_dummy; + if (m == 0) + return; + + y_remain = crtc_y % m; + y_start = y_remain + crtc_y / m * n; + y_end = (((crtc_y + crtc_h - 1) / m) * n) + ((crtc_y + crtc_h - 1) % m); + *padding_y = y_start; + *padding_start = m - y_remain; + *padding_height = y_end - y_start + 1; + SDE_EVT32(DRMID(cstate->base.crtc), y_remain, y_start, y_end, *padding_y, *padding_start, + *padding_height); + SDE_DEBUG("crtc:%d padding_y:%d padding_start:%d padding_height:%d\n", + DRMID(cstate->base.crtc), *padding_y, *padding_start, *padding_height); +} diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 97042b44e6..e32219d274 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -432,6 +432,20 @@ enum sde_crtc_dirty_flags { #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) +/** + * struct sde_line_insertion_param - sde line insertion parameters + * @panel_line_insertion_enable: line insertion support status + * @padding_height: panel height after line padding + * @padding_active: active lines in panel stacking pattern + * @padding_dummy: dummy lines in panel stacking pattern + */ +struct sde_line_insertion_param { + bool panel_line_insertion_enable; + u32 padding_height; + u32 padding_active; + u32 padding_dummy; +}; + /** * struct sde_crtc_state - sde container for atomic crtc state * @base: Base drm crtc state structure @@ -467,6 +481,7 @@ enum sde_crtc_dirty_flags { * @cp_dirty_list: array tracking features that are dirty * @cp_range_payload: array storing state user_data passed via range props * @cont_splash_populated: State was populated as part of cont. splash + * @param: sde line insertion parameters */ struct sde_crtc_state { struct drm_crtc_state base; @@ -506,6 +521,7 @@ struct sde_crtc_state { struct sde_cp_crtc_range_prop_payload cp_range_payload[SDE_CP_CRTC_MAX_FEATURES]; bool cont_splash_populated; + struct sde_line_insertion_param line_insertion; }; enum sde_crtc_irq_state { @@ -1073,4 +1089,24 @@ struct drm_encoder *sde_crtc_get_src_encoder_of_clone(struct drm_crtc *crtc); */ void _sde_crtc_vm_release_notify(struct drm_crtc *crtc); +/* + * sde_crtc_is_line_insertion_supported - get lineinsertion + * feature bit value from panel + * @drm_crtc: Pointer to drm crtc structure + * @Return: line insertion support status + */ +bool sde_crtc_is_line_insertion_supported(struct drm_crtc *crtc); + +/** + * sde_crtc_calc_vpadding_param - calculate vpadding parameters + * @state: Pointer to DRM crtc state object + * @crtc_y: Plane's CRTC_Y offset + * @crtc_h: Plane's CRTC_H size + * @padding_y: Padding Y offset + * @padding_start: Padding start offset + * @padding_height: Padding height in total + */ +void sde_crtc_calc_vpadding_param(struct drm_crtc_state *state, u32 crtc_y, u32 crtc_h, + u32 *padding_y, u32 *padding_start, u32 *padding_height); + #endif /* _SDE_CRTC_H_ */ diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 6fce847734..e348bd95a0 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1069,6 +1069,32 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc, return ret; } +bool sde_encoder_is_line_insertion_supported(struct drm_encoder *drm_enc) +{ + struct sde_connector *sde_conn = NULL; + struct sde_kms *sde_kms = NULL; + struct drm_connector *conn = NULL; + + if (!drm_enc) { + SDE_ERROR("invalid drm encoder\n"); + return false; + } + + sde_kms = sde_encoder_get_kms(drm_enc); + if (!sde_kms) + return false; + + conn = sde_encoder_get_connector(sde_kms->dev, drm_enc); + if (!conn || !conn->state) + return false; + + sde_conn = to_sde_connector(conn); + if (!sde_conn) + return false; + + return sde_connector_is_line_insertion_supported(sde_conn); +} + static void _sde_encoder_get_qsync_fps_callback(struct drm_encoder *drm_enc, u32 *qsync_fps, struct drm_connector_state *conn_state) { diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index c4a7ac27f8..d56a21e96c 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -683,5 +683,13 @@ static inline bool sde_encoder_is_widebus_enabled(struct drm_encoder *drm_enc) return sde_enc->mode_info.wide_bus_en; } +/* + * sde_encoder_is_line_insertion_supported - get line insertion + * feature bit value from panel + * @drm_enc: Pointer to drm encoder structure + * @Return: line insertion support status + */ +bool sde_encoder_is_line_insertion_supported(struct drm_encoder *drm_enc); + void sde_encoder_add_data_to_minidump_va(struct drm_encoder *drm_enc); #endif /* __SDE_ENCODER_H__ */ diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index b98296e1a0..b087449681 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -1820,6 +1820,8 @@ static void sde_sspp_set_features(struct sde_mdss_cfg *sde_cfg, sblk->maxlinewidth = sde_cfg->max_sspp_linewidth; + if (sde_cfg->has_line_insertion) + set_bit(SDE_SSPP_LINE_INSERTION, &sspp->features); sblk->smart_dma_priority = PROP_VALUE_ACCESS(props->values, SSPP_SMART_DMA, i); if (sblk->smart_dma_priority && sde_cfg->smart_dma_rev) @@ -5161,6 +5163,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->demura_supported[SSPP_DMA1][1] = 1; sde_cfg->demura_supported[SSPP_DMA3][0] = 0; sde_cfg->demura_supported[SSPP_DMA3][1] = 1; + sde_cfg->has_line_insertion = true; } else { SDE_ERROR("unsupported chipset id:%X\n", hw_rev); sde_cfg->perf.min_prefill_lines = 0xffff; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 61b61d82a2..7d2f616b8b 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -199,6 +199,10 @@ enum { #define SYS_CACHE_OP_TYPE BIT(3) #define SYS_CACHE_NO_ALLOC BIT(4) +/* default line padding ratio limitation */ +#define MAX_VPADDING_RATIO_M 93 +#define MAX_VPADDING_RATIO_N 45 + /** * sde_sys_cache_type: Types of system cache supported * SDE_SYS_CACHE_DISP: Static img system cache @@ -305,6 +309,7 @@ enum { * @SDE_SSPP_FP16_UNMULT FP16 alpha unmult color processing block support * @SDE_SSPP_UBWC_STATS: Support for ubwc stats * @SDE_SSPP_SCALER_DE_LPF_BLEND: Support for detail enhancer + * @SDE_SSPP_LINE_INSERTION Line insertion support * @SDE_SSPP_MAX maximum value */ enum { @@ -341,6 +346,7 @@ enum { SDE_SSPP_FP16_UNMULT, SDE_SSPP_UBWC_STATS, SDE_SSPP_SCALER_DE_LPF_BLEND, + SDE_SSPP_LINE_INSERTION, SDE_SSPP_MAX }; @@ -1826,6 +1832,7 @@ struct sde_perf_cfg { * @perf performance control settings * @uidle_cfg settings for uidle feature * @irq_offset_list list of sde_intr_irq_offsets to initialize irq table + * @has_line_insertion line insertion support status * @features bitmap of supported SDE_FEATUREs * @dma_formats supported formats for dma pipe * @vig_formats supported formats for vig pipe @@ -1940,6 +1947,7 @@ struct sde_mdss_cfg { struct sde_uidle_cfg uidle_cfg; struct list_head irq_offset_list; DECLARE_BITMAP(features, SDE_FEATURE_MAX); + bool has_line_insertion; /* Supported Pixel Format Lists */ struct sde_format_extended *dma_formats; diff --git a/msm/sde/sde_hw_sspp.c b/msm/sde/sde_hw_sspp.c index b5f0c457fc..2aafb8ea5e 100644 --- a/msm/sde/sde_hw_sspp.c +++ b/msm/sde/sde_hw_sspp.c @@ -44,6 +44,8 @@ #define SSPP_SRC_CONSTANT_COLOR_REC1 0x180 #define SSPP_EXCL_REC_SIZE_REC1 0x184 #define SSPP_EXCL_REC_XY_REC1 0x188 +#define SSPP_LINE_INSERTION_CTRL_REC1 0x1E4 +#define SSPP_LINE_INSERTION_OUT_SIZE_REC1 0x1EC #define SSPP_UIDLE_CTRL_VALUE 0x1f0 #define SSPP_UIDLE_CTRL_VALUE_REC1 0x1f4 @@ -116,6 +118,8 @@ #define SSPP_TRAFFIC_SHAPER_BPC_MAX 0xFF #define SSPP_CLK_CTRL 0x330 #define SSPP_CLK_STATUS 0x334 +#define SSPP_LINE_INSERTION_CTRL 0x1E0 +#define SSPP_LINE_INSERTION_OUT_SIZE 0x1E8 /* SSPP_QOS_CTRL */ #define SSPP_QOS_CTRL_VBLANK_EN BIT(16) @@ -1442,6 +1446,37 @@ static int sde_hw_sspp_get_clk_ctrl_status(struct sde_hw_blk_reg_map *hw, return 0; } +static void sde_hw_sspp_setup_line_insertion(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index rect_index, + struct sde_hw_pipe_line_insertion_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 ctl_off = 0, size_off = 0, ctl_val = 0; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !cfg) + return; + + c = &ctx->hw; + + if (rect_index == SDE_SSPP_RECT_SOLO || rect_index == SDE_SSPP_RECT_0) { + ctl_off = SSPP_LINE_INSERTION_CTRL; + size_off = SSPP_LINE_INSERTION_OUT_SIZE; + } else { + ctl_off = SSPP_LINE_INSERTION_CTRL_REC1; + size_off = SSPP_LINE_INSERTION_OUT_SIZE_REC1; + } + + if (cfg->enable) + ctl_val = BIT(31) | + (cfg->dummy_lines << 16) | + (cfg->first_active_lines << 8) | + (cfg->active_lines); + + SDE_REG_WRITE(c, ctl_off, ctl_val); + SDE_REG_WRITE(c, size_off, cfg->dst_h << 16); +} + static void _setup_layer_ops(struct sde_hw_pipe *c, unsigned long features, unsigned long perf_features, bool is_virtual_pipe) @@ -1536,6 +1571,8 @@ static void _setup_layer_ops(struct sde_hw_pipe *c, c->ops.set_ubwc_stats_roi = sde_hw_sspp_ubwc_stats_set_roi; c->ops.get_ubwc_stats_data = sde_hw_sspp_ubwc_stats_get_data; } + if (test_bit(SDE_SSPP_LINE_INSERTION, &features)) + c->ops.setup_line_insertion = sde_hw_sspp_setup_line_insertion; } static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp, diff --git a/msm/sde/sde_hw_sspp.h b/msm/sde/sde_hw_sspp.h index 65557e6bdf..2aead05d45 100644 --- a/msm/sde/sde_hw_sspp.h +++ b/msm/sde/sde_hw_sspp.h @@ -291,6 +291,22 @@ struct sde_hw_pipe_ts_cfg { */ #define SDE_PIPE_SBUF_PLANE_NUM 2 +/** + * struct sde_hw_pipe_line_insertion_cfg - line insertion config + * @enable: line insertion is enabled + * @dummy_lines: dummy lines before active lines + * @first_active_lines: number of active lines before first dummy lines + * @active_lines: active lines + * @dst_h: total active lines plus dummy lines + */ +struct sde_hw_pipe_line_insertion_cfg { + bool enable; + u32 dummy_lines; + u32 first_active_lines; + u32 active_lines; + u32 dst_h; +}; + /** * struct sde_hw_sspp_ops - interface to the SSPP Hw driver functions * Caller must call the init function to get the pipe context for each pipe @@ -688,6 +704,15 @@ struct sde_hw_sspp_ops { */ void (*setup_fp16_unmult)(struct sde_hw_pipe *ctx, enum sde_sspp_multirect_index index, void *data); + + /** + * setup_line_insertion - setup line insertion + * @ctx: Pointer to pipe context + * @cfg: Pointer to line insertion configuration + */ + void (*setup_line_insertion)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, + struct sde_hw_pipe_line_insertion_cfg *cfg); }; /** diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index f6e0acba03..c250b0a0ce 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -188,6 +188,45 @@ static struct sde_hw_ctl *_sde_plane_get_hw_ctl(const struct drm_plane *plane) return ctl; } +static void _sde_plane_setup_panel_stacking(struct sde_plane *psde, + struct sde_plane_state *pstate) +{ + struct sde_hw_pipe_line_insertion_cfg *cfg; + struct sde_crtc_state *cstate; + u32 h_start = 0, h_total = 0, y_start = 0; + struct drm_plane_state *dpstate = NULL; + struct drm_crtc *drm_crtc = NULL; + + if (!psde || !psde->base.state || !psde->base.state->crtc) { + SDE_ERROR("Invalid plane psde %p or drm plane state or drm crtc\n", psde); + return; + } + + dpstate = psde->base.state; + drm_crtc = dpstate->crtc; + cstate = to_sde_crtc_state(drm_crtc->state); + pstate->lineinsertion_feature = cstate->line_insertion.panel_line_insertion_enable; + + if ((!test_bit(SDE_SSPP_LINE_INSERTION, (unsigned long *)&psde->features)) || + !cstate->line_insertion.panel_line_insertion_enable) + return; + + cfg = &pstate->line_insertion_cfg; + memset(cfg, 0, sizeof(*cfg)); + if (!cstate->line_insertion.padding_height) + return; + + sde_crtc_calc_vpadding_param(psde->base.state->crtc->state, + pstate->base.crtc_y, pstate->base.crtc_h, + &y_start, &h_start, &h_total); + cfg->enable = true; + cfg->dummy_lines = cstate->line_insertion.padding_dummy; + cfg->active_lines = cstate->line_insertion.padding_active; + cfg->first_active_lines = h_start; + cfg->dst_h = h_total; + psde->pipe_cfg.dst_rect.y += y_start - pstate->base.crtc_y; +} + static bool sde_plane_enabled(const struct drm_plane_state *state) { return state && state->fb && state->crtc; @@ -3094,6 +3133,8 @@ static void _sde_plane_update_roi_config(struct drm_plane *plane, _sde_plane_setup_scaler(psde, pstate, fmt, false); + _sde_plane_setup_panel_stacking(psde, pstate); + /* check for color fill */ psde->color_fill = (uint32_t)sde_plane_get_property(pstate, PLANE_PROP_COLOR_FILL); @@ -3137,6 +3178,11 @@ static void _sde_plane_update_roi_config(struct drm_plane *plane, true, pstate->multirect_index, pstate->multirect_mode); + /* update line insertion */ + if (pstate->lineinsertion_feature && psde->pipe_hw->ops.setup_line_insertion) + psde->pipe_hw->ops.setup_line_insertion(psde->pipe_hw, + pstate->multirect_index, + &pstate->line_insertion_cfg); } static void _sde_plane_update_format_and_rects(struct sde_plane *psde, diff --git a/msm/sde/sde_plane.h b/msm/sde/sde_plane.h index af3669ae2d..9056fa7843 100644 --- a/msm/sde/sde_plane.h +++ b/msm/sde/sde_plane.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -112,6 +113,8 @@ enum sde_plane_sclcheck_state { * @cdp_cfg: CDP configuration * @cont_splash_populated: State was populated as part of cont. splash * @ubwc_stats_roi: cached roi for ubwc stats + * @line_insertion_cfg: line insertion configuration + * @lineinsertion_feature: panel line insertion feature */ struct sde_plane_state { struct drm_plane_state base; @@ -147,6 +150,8 @@ struct sde_plane_state { bool cont_splash_populated; struct sde_drm_ubwc_stats_roi ubwc_stats_roi; + struct sde_hw_pipe_line_insertion_cfg line_insertion_cfg; + bool lineinsertion_feature; }; /**