|
@@ -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);
|
|
|
+}
|