diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 50c1276975..9a25008690 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2108,7 +2108,8 @@ static int _sde_connector_lm_preference(struct sde_connector *sde_conn, return -EINVAL; } - sde_hw_mixer_set_preference(sde_kms->catalog, num_lm, disp_type); + sde_conn->lm_mask = sde_hw_mixer_set_preference(sde_kms->catalog, + num_lm, disp_type); return ret; } diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index f18e2584e8..2a6b8ca7c9 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -542,6 +542,7 @@ struct sde_misr_sign { * @hdr_min_luminance: desired min luminance obtained from HDR block * @hdr_supported: does the sink support HDR content * @color_enc_fmt: Colorimetry encoding formats of sink + * @lm_mask: preferred LM mask for connector * @allow_bl_update: Flag to indicate if BL update is allowed currently or not * @dimming_bl_notify_enabled: Flag to indicate if dimming bl notify is enabled or not * @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode @@ -616,6 +617,7 @@ struct sde_connector { bool hdr_supported; u32 color_enc_fmt; + u32 lm_mask; u8 hdr_plus_app_ver; u32 qsync_mode; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 3c246d87e9..eeaeadbaf0 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2045,10 +2045,10 @@ static int sde_ctl_parse_dt(struct device_node *np, return 0; } -void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, +u32 sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, uint32_t disp_type) { - u32 i, cnt = 0, sec_cnt = 0; + u32 i, cnt = 0, sec_cnt = 0, lm_mask = 0; if (disp_type == SDE_CONNECTOR_PRIMARY) { for (i = 0; i < sde_cfg->mixer_count; i++) { @@ -2067,6 +2067,7 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, if (cnt < num_lm) { set_bit(SDE_DISP_PRIMARY_PREF, &sde_cfg->mixer[i].features); + lm_mask |= BIT(sde_cfg->mixer[i].id - 1); cnt++; } @@ -2105,10 +2106,13 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, BIT(SDE_DISP_PRIMARY_PREF))) { set_bit(SDE_DISP_SECONDARY_PREF, &sde_cfg->mixer[i].features); + lm_mask |= BIT(sde_cfg->mixer[i].id - 1); cnt++; } } } + + return lm_mask; } static int sde_mixer_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 623a981b3b..af2cea4477 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1998,13 +1998,15 @@ struct sde_mdss_hw_cfg_handler { #define BLK_RC(s) ((s)->rc) /** - * sde_hw_set_preference: populate the individual hw lm preferences, - * overwrite if exists - * @sde_cfg: pointer to sspp cfg - * @num_lm: num lms to set preference - * @disp_type: is the given display primary/secondary + * sde_hw_mixer_set_preference: populate the individual hw lm preferences, + * overwrite if exists + * @sde_cfg: pointer to sspp cfg + * @num_lm: num lms to set preference + * @disp_type: is the given display primary/secondary + * + * Return: layer mixer mask allocated for the disp_type */ -void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, +u32 sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, uint32_t disp_type); /** diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index 76df522d1b..77ae1e57c8 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -131,11 +131,13 @@ char sde_hw_blk_str[SDE_HW_BLK_MAX][SDE_HW_BLK_NAME_LEN] = { * @top_ctrl: topology control preference from kernel client * @top: selected topology for the display * @hw_res: Hardware resources required as reported by the encoders + * @conn_lm_mask: preferred LM mask of cwb requested display */ struct sde_rm_requirements { uint64_t top_ctrl; const struct sde_rm_topology_def *topology; struct sde_encoder_hw_resources hw_res; + u32 conn_lm_mask; }; /** @@ -1157,7 +1159,8 @@ static bool _sde_rm_check_lm_and_get_connected_blks( struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp, - struct sde_rm_hw_blk *primary_lm) + struct sde_rm_hw_blk *primary_lm, + u32 conn_lm_mask) { const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; const struct sde_pingpong_cfg *pp_cfg; @@ -1212,6 +1215,11 @@ static bool _sde_rm_check_lm_and_get_connected_blks( } else if (!RM_RQ_DCWB(reqs) && dcwb_pref) { SDE_DEBUG("fail: dcwb supported dummy lm incorrectly allocated\n"); return false; + } else if (RM_RQ_DCWB(reqs) && dcwb_pref && + ((ffs(conn_lm_mask) % 2) == ((lm_cfg->id + 1) % 2))) { + SDE_DEBUG("fail: dcwb:%d trying to match lm:%d\n", + lm_cfg->id, ffs(conn_lm_mask)); + return false; } } else if ((!is_conn_primary && lm_primary_pref) || (!is_conn_secondary && lm_secondary_pref)) { @@ -1258,7 +1266,7 @@ static int _sde_rm_reserve_lms( struct sde_rm_hw_blk *ds[MAX_BLOCKS]; struct sde_rm_hw_blk *pp[MAX_BLOCKS]; struct sde_rm_hw_iter iter_i, iter_j; - u32 lm_mask = 0; + u32 lm_mask = 0, conn_lm_mask = 0; int lm_count = 0; int i, rc = 0; @@ -1267,6 +1275,8 @@ static int _sde_rm_reserve_lms( return 0; } + if (RM_RQ_DCWB(reqs)) + conn_lm_mask = reqs->conn_lm_mask; /* Find a primary mixer */ sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_LM); while (lm_count != reqs->topology->num_lm && @@ -1290,7 +1300,7 @@ static int _sde_rm_reserve_lms( if (!_sde_rm_check_lm_and_get_connected_blks( rm, rsvp, reqs, lm[lm_count], &dspp[lm_count], &ds[lm_count], - &pp[lm_count], NULL)) + &pp[lm_count], NULL, conn_lm_mask)) continue; lm_mask |= (1 << iter_i.blk->id); @@ -1300,6 +1310,9 @@ static int _sde_rm_reserve_lms( if (lm_count == reqs->topology->num_lm) break; + if (RM_RQ_DCWB(reqs)) + conn_lm_mask = conn_lm_mask & ~BIT(ffs(conn_lm_mask) - 1); + /* Valid primary mixer found, find matching peers */ sde_rm_init_hw_iter(&iter_j, 0, SDE_HW_BLK_LM); @@ -1315,7 +1328,8 @@ static int _sde_rm_reserve_lms( if (!_sde_rm_check_lm_and_get_connected_blks( rm, rsvp, reqs, iter_j.blk, &dspp[lm_count], &ds[lm_count], - &pp[lm_count], iter_i.blk)) + &pp[lm_count], iter_i.blk, + conn_lm_mask)) continue; SDE_DEBUG("blk id = %d, _lm_ids[%d] = %d\n", @@ -1328,6 +1342,10 @@ static int _sde_rm_reserve_lms( lm_mask |= (1 << iter_j.blk->id); ++lm_count; + + if (RM_RQ_DCWB(reqs)) + conn_lm_mask = conn_lm_mask & ~BIT(ffs(conn_lm_mask) - 1); + break; } @@ -2278,6 +2296,26 @@ int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, return 0; } +static struct drm_connector *_sde_rm_get_connector( + struct drm_encoder *enc) +{ + struct drm_connector *conn = NULL, *conn_search; + struct sde_connector *c_conn = NULL; + struct drm_connector_list_iter conn_iter; + + drm_connector_list_iter_begin(enc->dev, &conn_iter); + drm_for_each_connector_iter(conn_search, &conn_iter) { + c_conn = to_sde_connector(conn_search); + if (c_conn->encoder == enc) { + conn = conn_search; + break; + } + } + drm_connector_list_iter_end(&conn_iter); + + return conn; +} + static int _sde_rm_populate_requirements( struct sde_rm *rm, struct drm_encoder *enc, @@ -2287,6 +2325,8 @@ static int _sde_rm_populate_requirements( struct sde_rm_requirements *reqs) { const struct drm_display_mode *mode = &crtc_state->mode; + struct drm_encoder *encoder_iter; + struct drm_connector *conn; int i, num_lm; reqs->top_ctrl = sde_connector_get_property(conn_state, @@ -2353,6 +2393,19 @@ static int _sde_rm_populate_requirements( reqs->topology->top_name, reqs->topology->num_ctl); } + if (RM_RQ_DCWB(reqs)) { + drm_for_each_encoder_mask(encoder_iter, enc->dev, + crtc_state->encoder_mask) { + if (drm_encoder_mask(encoder_iter) == drm_encoder_mask(enc)) + continue; + + conn = _sde_rm_get_connector(encoder_iter); + if (conn) + reqs->conn_lm_mask = to_sde_connector(conn)->lm_mask; + break; + } + } + SDE_DEBUG("top_ctrl: 0x%llX num_h_tiles: %d\n", reqs->top_ctrl, reqs->hw_res.display_num_of_h_tiles); SDE_DEBUG("num_lm: %d num_ctl: %d topology: %d split_display: %d\n", @@ -2395,26 +2448,6 @@ static struct sde_rm_rsvp *_sde_rm_get_rsvp_cur(struct sde_rm *rm, struct drm_en return _sde_rm_get_rsvp(rm, enc, false); } -static struct drm_connector *_sde_rm_get_connector( - struct drm_encoder *enc) -{ - struct drm_connector *conn = NULL, *conn_search; - struct sde_connector *c_conn = NULL; - struct drm_connector_list_iter conn_iter; - - drm_connector_list_iter_begin(enc->dev, &conn_iter); - drm_for_each_connector_iter(conn_search, &conn_iter) { - c_conn = to_sde_connector(conn_search); - if (c_conn->encoder == enc) { - conn = conn_search; - break; - } - } - drm_connector_list_iter_end(&conn_iter); - - return conn; -} - int sde_rm_update_topology(struct sde_rm *rm, struct drm_connector_state *conn_state, struct msm_display_topology *topology)