diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 12c3d7fb436d..7a27d76da09e 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -604,59 +604,102 @@ static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) + struct drm_connector_state *conn_state) { + struct drm_framebuffer *fb; struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); + const struct drm_display_mode *mode = &crtc_state->mode; struct sde_rect wb_roi = {0,}; struct sde_rect pu_roi = {0,}; + int out_width = 0, out_height = 0; + int ds_srcw = 0, ds_srch = 0, ds_outw = 0, ds_outh = 0; int data_pt; - int ds_outw = 0; - int ds_outh = 0; int ds_in_use = false; int i = 0; int ret = 0; - if (!phys_enc->in_clone_mode) { - SDE_DEBUG("not in CWB mode. early return\n"); - goto exit; + fb = sde_wb_connector_state_get_output_fb(conn_state); + if (!fb) { + SDE_DEBUG("no output framebuffer\n"); + return 0; } ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); if (ret) { SDE_ERROR("failed to get roi %d\n", ret); - goto exit; + return ret; + } + + if (!wb_roi.w || !wb_roi.h) { + SDE_ERROR("cwb roi is not set wxh:%dx%d\n", wb_roi.w, wb_roi.h); + return -EINVAL; } data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT); /* compute cumulative ds output dimensions if in use */ - for (i = 0; i < cstate->num_ds; i++) + for (i = 0; i < cstate->num_ds; i++) { if (cstate->ds_cfg[i].scl3_cfg.enable) { ds_in_use = true; ds_outw += cstate->ds_cfg[i].scl3_cfg.dst_width; ds_outh = cstate->ds_cfg[i].scl3_cfg.dst_height; + ds_srcw += cstate->ds_cfg[i].lm_width; + ds_srch = cstate->ds_cfg[i].lm_height; } - - /* if ds in use check wb roi against ds output dimensions */ - if ((data_pt == CAPTURE_DSPP_OUT) && ds_in_use && - ((wb_roi.w != ds_outw) || (wb_roi.h != ds_outh))) { - SDE_ERROR("invalid wb roi with dest scalar [%dx%d vs %dx%d]\n", - wb_roi.w, wb_roi.h, ds_outw, ds_outh); - ret = -EINVAL; - goto exit; } - /* validate conn roi against pu rect */ + if ((ds_in_use && (!ds_outw || !ds_outh || !ds_srcw || !ds_srch))) { + SDE_ERROR("invalid ds cfg src:%dx%d dst:%dx%d\n", + ds_srcw, ds_srch, ds_outw, ds_outh); + return -EINVAL; + } + + /* 1) No DS case: same restrictions for LM & DSSPP tap point + * a) wb-roi should be inside FB + * b) mode resolution & wb-roi should be same + * 2) With DS case: restrictions would change based on tap point + * 2.1) LM Tap Point: + * a) wb-roi should be inside FB + * b) wb-roi should be same as crtc-LM bounds + * 2.2) DSPP Tap point: same as No DS case + * a) wb-roi should be inside FB + * b) mode resolution & wb-roi should be same + */ + if (ds_in_use && data_pt == CAPTURE_DSPP_OUT) { + out_width = ds_outw; + out_height = ds_outh; + } else if (ds_in_use) { /* LM tap point */ + out_width = ds_srcw; + out_height = ds_srch; + } else { + out_width = mode->hdisplay; + out_height = mode->vdisplay; + } + + if ((wb_roi.w != out_width) || (wb_roi.h != out_height)) { + SDE_ERROR("invalid wb roi[%dx%d] with ds_use:%d out[%dx%d]\n", + wb_roi.w, wb_roi.h, out_width, out_height); + return -EINVAL; + } + + if (((wb_roi.x + wb_roi.w) > fb->width) || + ((wb_roi.y + wb_roi.h) > fb->height)) { + SDE_ERROR("invalid wb roi[%d,%d,%d,%d] fb[%dx%d]\n", + wb_roi.x, wb_roi.y, wb_roi.w, wb_roi.h, + fb->width, fb->height); + return -EINVAL; + } + + /* validate wb roi against pu rect */ if (cstate->user_roi_list.num_rects) { sde_kms_rect_merge_rectangles(&cstate->user_roi_list, &pu_roi); if (wb_roi.w != pu_roi.w || wb_roi.h != pu_roi.h) { SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n", wb_roi.w, wb_roi.h, pu_roi.w, pu_roi.h); - ret = -EINVAL; - goto exit; + return -EINVAL; } } -exit: + return ret; } @@ -742,6 +785,16 @@ static int sde_encoder_phys_wb_atomic_check( if (SDE_FORMAT_IS_YUV(fmt) != !!phys_enc->hw_cdm) crtc_state->mode_changed = true; + /* if in clone mode, return after cwb validation */ + if (phys_enc->in_clone_mode) { + rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, + conn_state); + if (rc) + SDE_ERROR("failed in cwb validation %d\n", rc); + + return rc; + } + if (wb_roi.w && wb_roi.h) { if (wb_roi.w != mode->hdisplay) { SDE_ERROR("invalid roi w=%d, mode w=%d\n", wb_roi.w, @@ -786,12 +839,6 @@ static int sde_encoder_phys_wb_atomic_check( } } - rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, conn_state); - if (rc) { - SDE_ERROR("failed in cwb validation %d\n", rc); - return rc; - } - return rc; }