@@ -1231,6 +1231,50 @@ static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state
}
#define MAX_CHANNELS_PER_CRTC 2
+#define MAX_HDISPLAY_SPLIT 1080
+
+static struct msm_display_topology dpu_crtc_get_topology(
+ struct drm_crtc *crtc,
+ struct dpu_kms *dpu_kms,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+ struct msm_display_topology topology = {0};
+ struct drm_encoder *drm_enc;
+
+ drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask)
+ dpu_encoder_update_topology(drm_enc, &topology, crtc_state->state,
+ &crtc_state->adjusted_mode);
+
+ /*
+ * Datapath topology selection
+ *
+ * Dual display
+ * 2 LM, 2 INTF ( Split display using 2 interfaces)
+ *
+ * Single display
+ * 1 LM, 1 INTF
+ * 2 LM, 1 INTF (stream merge to support high resolution interfaces)
+ *
+ * If DSC is enabled, use 2 LMs for 2:2:1 topology
+ *
+ * Add dspps to the reservation requirements if ctm is requested
+ */
+
+ if (topology.num_intf == 2)
+ topology.num_lm = 2;
+ else if (topology.num_dsc == 2)
+ topology.num_lm = 2;
+ else if (dpu_kms->catalog->caps->has_3d_merge)
+ topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
+ else
+ topology.num_lm = 1;
+
+ if (crtc_state->ctm)
+ topology.num_dspp = topology.num_lm;
+
+ return topology;
+}
static int dpu_crtc_assign_resources(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state)
@@ -1243,6 +1287,8 @@ static int dpu_crtc_assign_resources(struct drm_crtc *crtc,
struct dpu_global_state *global_state;
struct dpu_crtc_state *cstate;
struct drm_encoder *drm_enc;
+ struct msm_display_topology topology;
+ int ret;
if (!crtc_state->encoder_mask)
return 0;
@@ -1254,13 +1300,24 @@ static int dpu_crtc_assign_resources(struct drm_crtc *crtc,
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask)
break;
+ /*
+ * Release and Allocate resources on every modeset
+ */
global_state = dpu_kms_get_global_state(crtc_state->state);
if (IS_ERR(global_state))
return PTR_ERR(global_state);
+ dpu_rm_release(global_state, drm_enc);
+
if (!crtc_state->enable)
return 0;
+ topology = dpu_crtc_get_topology(crtc, dpu_kms, crtc_state);
+ ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
+ drm_enc, crtc_state, &topology);
+ if (ret)
+ return ret;
+
cstate = to_dpu_crtc_state(crtc_state);
num_ctl = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
@@ -1290,6 +1347,28 @@ static int dpu_crtc_assign_resources(struct drm_crtc *crtc,
return 0;
}
+/**
+ * dpu_crtc_check_mode_changed: check if full modeset is required
+ * @crtc_state: Corresponding CRTC state to be checked
+ *
+ * Check if the changes in the object properties demand full mode set.
+ */
+int dpu_crtc_check_mode_changed(struct drm_crtc_state *crtc_state)
+{
+ struct drm_encoder *drm_enc;
+ struct drm_crtc *crtc = crtc_state->crtc;
+
+ DRM_DEBUG_ATOMIC("%d\n", crtc->base.id);
+
+ /* there might be cases where encoder needs a modeset too */
+ drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) {
+ if (dpu_encoder_needs_modeset(drm_enc, crtc_state->state))
+ crtc_state->mode_changed = true;
+ }
+
+ return 0;
+}
+
static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
@@ -239,6 +239,8 @@ static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc)
return crtc ? atomic_read(&to_dpu_crtc(crtc)->frame_pending) : -EINVAL;
}
+int dpu_crtc_check_mode_changed(struct drm_crtc_state *crtc_state);
+
int dpu_crtc_vblank(struct drm_crtc *crtc, bool en);
void dpu_crtc_vblank_callback(struct drm_crtc *crtc);
@@ -58,8 +58,6 @@
#define IDLE_SHORT_TIMEOUT 1
-#define MAX_HDISPLAY_SPLIT 1080
-
/* timeout in frames waiting for frame done */
#define DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES 5
@@ -622,7 +620,7 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc)
if (dpu_enc->phys_encs[i])
intf_count++;
- /* See dpu_encoder_get_topology, we only support 2:2:1 topology */
+ /* See dpu_crtc_get_topology, we only support 2:2:1 topology */
if (dpu_enc->dsc)
num_dsc = 2;
@@ -647,153 +645,88 @@ struct drm_dsc_config *dpu_encoder_get_dsc_config(struct drm_encoder *drm_enc)
return NULL;
}
-static struct msm_display_topology dpu_encoder_get_topology(
- struct dpu_encoder_virt *dpu_enc,
- struct drm_display_mode *mode,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
+void dpu_encoder_update_topology(struct drm_encoder *drm_enc,
+ struct msm_display_topology *topology,
+ struct drm_atomic_state *state,
+ const struct drm_display_mode *adj_mode)
{
- struct msm_drm_private *priv = dpu_enc->base.dev->dev_private;
- struct msm_display_info *disp_info = &dpu_enc->disp_info;
- struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms);
- struct drm_dsc_config *dsc = dpu_encoder_get_dsc_config(&dpu_enc->base);
- struct msm_display_topology topology = {0};
- int i, intf_count = 0;
+ struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ struct msm_display_info *disp_info;
+ struct drm_framebuffer *fb;
+ struct msm_drm_private *priv;
+ struct drm_dsc_config *dsc;
+
+ int i;
for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++)
if (dpu_enc->phys_encs[i])
- intf_count++;
-
- /* Datapath topology selection
- *
- * Dual display
- * 2 LM, 2 INTF ( Split display using 2 interfaces)
- *
- * Single display
- * 1 LM, 1 INTF
- * 2 LM, 1 INTF (stream merge to support high resolution interfaces)
- *
- * Add dspps to the reservation requirements if ctm is requested
- */
- if (intf_count == 2)
- topology.num_lm = 2;
- else if (!dpu_kms->catalog->caps->has_3d_merge)
- topology.num_lm = 1;
- else
- topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
-
- if (crtc_state->ctm)
- topology.num_dspp = topology.num_lm;
+ topology->num_intf++;
- topology.num_intf = intf_count;
+ dsc = dpu_encoder_get_dsc_config(drm_enc);
+ /* We only support 2 DSC mode (with 2 LM and 1 INTF) */
if (dsc) {
- /*
- * In case of Display Stream Compression (DSC), we would use
- * 2 DSC encoders, 2 layer mixers and 1 interface
- * this is power optimal and can drive up to (including) 4k
- * screens
- */
- topology.num_dsc = 2;
- topology.num_lm = 2;
- topology.num_intf = 1;
+ topology->num_dsc = 2;
+ topology->num_intf = 1;
}
+ connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc);
+ if (!connector)
+ return;
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ if (!conn_state)
+ return;
+
+ disp_info = &dpu_enc->disp_info;
+
+ priv = drm_enc->dev->dev_private;
+
/*
* Use CDM only for writeback or DP at the moment as other interfaces cannot handle it.
* If writeback itself cannot handle cdm for some reason it will fail in its atomic_check()
* earlier.
*/
if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
- struct drm_framebuffer *fb;
-
fb = conn_state->writeback_job->fb;
if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb)))
- topology.needs_cdm = true;
+ topology->needs_cdm = true;
} else if (disp_info->intf_type == INTF_DP) {
- if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], mode))
- topology.needs_cdm = true;
+ if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
+ topology->needs_cdm = true;
}
-
- return topology;
}
-/**
- * dpu_encoder_virt_check_mode_changed: check if full modeset is required
- * @drm_enc: Pointer to drm encoder structure
- * @crtc_state: Corresponding CRTC state to be checked
- * @conn_state: Corresponding Connector's state to be checked
- *
- * Check if the changes in the object properties demand full mode set.
- */
-int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
+bool dpu_encoder_needs_modeset(struct drm_encoder *drm_enc, struct drm_atomic_state *state)
{
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ struct drm_framebuffer *fb;
struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
- struct msm_display_topology topology;
-
- DPU_DEBUG_ENC(dpu_enc, "\n");
-
- /* Using mode instead of adjusted_mode as it wasn't computed yet */
- topology = dpu_encoder_get_topology(dpu_enc, &crtc_state->mode, crtc_state, conn_state);
-
- if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
- crtc_state->mode_changed = true;
- else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
- crtc_state->mode_changed = true;
-
- return 0;
-}
-
-static int dpu_encoder_virt_atomic_check(
- struct drm_encoder *drm_enc,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- struct dpu_encoder_virt *dpu_enc;
- struct msm_drm_private *priv;
- struct dpu_kms *dpu_kms;
- struct drm_display_mode *adj_mode;
- struct msm_display_topology topology;
- struct dpu_global_state *global_state;
- int ret = 0;
-
- if (!drm_enc || !crtc_state || !conn_state) {
- DPU_ERROR("invalid arg(s), drm_enc %d, crtc/conn state %d/%d\n",
- drm_enc != NULL, crtc_state != NULL, conn_state != NULL);
- return -EINVAL;
- }
-
- dpu_enc = to_dpu_encoder_virt(drm_enc);
- DPU_DEBUG_ENC(dpu_enc, "\n");
-
- priv = drm_enc->dev->dev_private;
- dpu_kms = to_dpu_kms(priv->kms);
- adj_mode = &crtc_state->adjusted_mode;
- global_state = dpu_kms_get_global_state(crtc_state->state);
- if (IS_ERR(global_state))
- return PTR_ERR(global_state);
- trace_dpu_enc_atomic_check(DRMID(drm_enc));
+ if (!drm_enc || !state)
+ return false;
- topology = dpu_encoder_get_topology(dpu_enc, adj_mode, crtc_state, conn_state);
+ connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc);
+ if (!connector)
+ return false;
- /*
- * Release and Allocate resources on every modeset
- */
- if (drm_atomic_crtc_needs_modeset(crtc_state)) {
- dpu_rm_release(global_state, drm_enc);
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
- if (crtc_state->enable)
- ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
- drm_enc, crtc_state, &topology);
+ if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) {
+ fb = conn_state->writeback_job->fb;
+ if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb))) {
+ if (!dpu_enc->cur_master->hw_cdm)
+ return true;
+ } else {
+ if (dpu_enc->cur_master->hw_cdm)
+ return true;
+ }
}
- trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags);
-
- return ret;
+ return false;
}
static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
@@ -2612,7 +2545,6 @@ static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
.atomic_disable = dpu_encoder_virt_atomic_disable,
.atomic_enable = dpu_encoder_virt_atomic_enable,
- .atomic_check = dpu_encoder_virt_atomic_check,
};
static const struct drm_encoder_funcs dpu_encoder_funcs = {
@@ -80,6 +80,13 @@ int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos);
bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc);
+void dpu_encoder_update_topology(struct drm_encoder *drm_enc,
+ struct msm_display_topology *topology,
+ struct drm_atomic_state *state,
+ const struct drm_display_mode *adj_mode);
+
+bool dpu_encoder_needs_modeset(struct drm_encoder *drm_enc, struct drm_atomic_state *state);
+
void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
struct drm_writeback_job *job);
@@ -88,8 +95,4 @@ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc);
-int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state);
-
#endif /* __DPU_ENCODER_H__ */
@@ -449,24 +449,11 @@ static void dpu_kms_disable_commit(struct msm_kms *kms)
static int dpu_kms_check_mode_changed(struct msm_kms *kms, struct drm_atomic_state *state)
{
struct drm_crtc_state *new_crtc_state;
- struct drm_connector *connector;
- struct drm_connector_state *new_conn_state;
+ struct drm_crtc *crtc;
int i;
- for_each_new_connector_in_state(state, connector, new_conn_state, i) {
- struct drm_encoder *encoder;
-
- WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc);
-
- if (!new_conn_state->crtc || !new_conn_state->best_encoder)
- continue;
-
- new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
-
- encoder = new_conn_state->best_encoder;
-
- dpu_encoder_virt_check_mode_changed(encoder, new_crtc_state, new_conn_state);
- }
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
+ dpu_crtc_check_mode_changed(new_crtc_state);
return 0;
}