@@ -265,6 +265,19 @@ static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc,
return true;
}
+bool dpu_crtc_needs_dirtyfb(struct drm_crtc *crtc)
+{
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder_mask (encoder, crtc->dev, crtc->state->encoder_mask) {
+ if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer,
struct dpu_plane_state *pstate, struct dpu_format *format)
{
@@ -261,6 +261,15 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc);
*/
void dpu_crtc_complete_commit(struct drm_crtc *crtc);
+/**
+ * dpu_crtc_needs_dirtyfb - do fb updates need to be flushed
+ * @crtc: Pointer to drm crtc object
+ *
+ * Return whether front-buffer updates need to be flushed, ie. is it
+ * a command-mode style of display
+ */
+bool dpu_crtc_needs_dirtyfb(struct drm_crtc *crtc);
+
/**
* dpu_crtc_init - create a new crtc object
* @dev: dpu device
@@ -949,6 +949,7 @@ static const struct msm_kms_funcs kms_funcs = {
.check_modified_format = dpu_format_check_modified_format,
.get_format = dpu_get_msm_format,
.round_pixclk = dpu_kms_round_pixclk,
+ .needs_dirtyfb = dpu_crtc_needs_dirtyfb,
.destroy = dpu_kms_destroy,
.snapshot = dpu_kms_mdp_snapshot,
#ifdef CONFIG_DEBUG_FS
@@ -19,6 +19,7 @@ struct mdp4_crtc {
int id;
int ovlp;
enum mdp4_dma dma;
+ enum mdp4_intf intf;
bool enabled;
/* which mixer/encoder we route output to: */
@@ -594,6 +595,7 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD;
}
+ mdp4_crtc->intf = intf;
mdp4_crtc->mixer = mixer;
blend_setup(crtc);
@@ -612,6 +614,13 @@ void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc)
mdp4_crtc_wait_for_flush_done(crtc);
}
+bool mdp4_crtc_needs_dirtyfb(struct drm_crtc *crtc)
+{
+ struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+ return mdp4_crtc->intf == INTF_DSI_CMD;
+}
+
static const char *dma_names[] = {
"DMA_P", "DMA_S", "DMA_E",
};
@@ -163,6 +163,7 @@ static const struct mdp_kms_funcs kms_funcs = {
.complete_commit = mdp4_complete_commit,
.get_format = mdp_get_format,
.round_pixclk = mdp4_round_pixclk,
+ .needs_dirtyfb = mdp4_crtc_needs_dirtyfb,
.destroy = mdp4_destroy,
},
.set_irqmask = mdp4_set_irqmask,
@@ -190,6 +190,7 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc);
+bool mdp4_crtc_needs_dirtyfb(struct drm_crtc *crtc);
struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
struct drm_plane *plane, int id, int ovlp_id,
enum mdp4_dma dma_id);
@@ -1300,6 +1300,14 @@ void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
mdp5_crtc_wait_for_flush_done(crtc);
}
+bool mdp5_crtc_needs_dirtyfb(struct drm_crtc *crtc)
+{
+ struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+ struct mdp5_interface *intf = mdp5_cstate->pipeline.intf;
+
+ return intf->mode == MDP5_INTF_DSI_MODE_COMMAND;
+}
+
/* initialize crtc */
struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
struct drm_plane *plane,
@@ -280,6 +280,7 @@ static const struct mdp_kms_funcs kms_funcs = {
.get_format = mdp_get_format,
.round_pixclk = mdp5_round_pixclk,
.set_split_display = mdp5_set_split_display,
+ .needs_dirtyfb = mdp5_crtc_needs_dirtyfb,
.destroy = mdp5_kms_destroy,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = mdp5_kms_debugfs_init,
@@ -280,6 +280,7 @@ struct mdp5_hw_mixer *mdp5_crtc_get_mixer(struct drm_crtc *crtc);
struct mdp5_pipeline *mdp5_crtc_get_pipeline(struct drm_crtc *crtc);
void mdp5_crtc_set_pipeline(struct drm_crtc *crtc);
void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc);
+bool mdp5_crtc_needs_dirtyfb(struct drm_crtc *crtc);
struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
struct drm_plane *plane,
struct drm_plane *cursor_plane, int id);
@@ -24,10 +24,72 @@ struct msm_framebuffer {
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
+static int msm_framebuffer_dirtyfb(struct drm_framebuffer *fb,
+ struct drm_file *file_priv, unsigned int flags,
+ unsigned int color, struct drm_clip_rect *clips,
+ unsigned int num_clips)
+{
+ struct msm_drm_private *priv = fb->dev->dev_private;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_plane *plane;
+ bool needs_flush = false;
+ int ret = 0;
+
+ /*
+ * When called from ioctl, we are interruptible, but not when called
+ * internally (ie. defio worker)
+ */
+ drm_modeset_acquire_init(&ctx,
+ file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
+
+retry:
+ drm_for_each_plane(plane, fb->dev) {
+ struct drm_plane_state *plane_state;
+ struct drm_crtc *crtc;
+
+ ret = drm_modeset_lock(&plane->mutex, &ctx);
+ if (ret)
+ goto out;
+
+ if (plane->state->fb != fb) {
+ drm_modeset_unlock(&plane->mutex);
+ continue;
+ }
+
+ crtc = plane->state->crtc;
+
+ ret = drm_modeset_lock(&crtc->mutex, &ctx);
+ if (ret)
+ goto out;
+
+ if (priv->kms->funcs->needs_dirtyfb(crtc)) {
+ needs_flush = true;
+ break;
+ }
+ }
+
+out:
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ if (needs_flush) {
+ ret = drm_atomic_helper_dirtyfb(fb, file_priv, flags,
+ color, clips, num_clips);
+ }
+
+ return ret;
+}
+
static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
.create_handle = drm_gem_fb_create_handle,
.destroy = drm_gem_fb_destroy,
- .dirty = drm_atomic_helper_dirtyfb,
+ .dirty = msm_framebuffer_dirtyfb,
};
#ifdef CONFIG_DEBUG_FS
@@ -117,6 +117,8 @@ struct msm_kms_funcs {
struct drm_encoder *encoder,
struct drm_encoder *slave_encoder,
bool is_cmd_mode);
+ bool (*needs_dirtyfb)(struct drm_crtc *crtc);
+
/* cleanup: */
void (*destroy)(struct msm_kms *kms);