Because of stability issues, we may want to limit the maximum bandwidth
required by the MXSFB (eLCDIF) driver.

Signed-off-by: Robert Chiras <robert.chi...@nxp.com>
Tested-by: Guido Günther <a...@sigxcpu.org>
---
 drivers/gpu/drm/mxsfb/mxsfb_drv.c | 48 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/mxsfb/mxsfb_drv.h |  2 ++
 2 files changed, 50 insertions(+)

diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c 
b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index f95ba63..d8686c7 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -158,6 +158,49 @@ static const struct drm_mode_config_helper_funcs 
mxsfb_mode_config_helpers = {
        .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 };
 
+enum drm_mode_status mxsfb_pipe_mode_valid(struct drm_crtc *crtc,
+                                          const struct drm_display_mode *mode)
+{
+       struct drm_simple_display_pipe *pipe =
+               container_of(crtc, struct drm_simple_display_pipe, crtc);
+       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+       u32 bpp;
+       u64 bw;
+
+       if (!pipe->plane.state->fb)
+               bpp = 32;
+       else
+               bpp = pipe->plane.state->fb->format->depth;
+
+       bw = mode->crtc_clock * 1000;
+       bw = bw * mode->hdisplay * mode->vdisplay * (bpp / 8);
+       bw = div_u64(bw, mode->htotal * mode->vtotal);
+
+       if (mxsfb->max_bw && (bw > mxsfb->max_bw))
+               return MODE_BAD;
+
+       return MODE_OK;
+}
+
+static int mxsfb_pipe_check(struct drm_simple_display_pipe *pipe,
+                           struct drm_plane_state *plane_state,
+                           struct drm_crtc_state *crtc_state)
+{
+       struct drm_framebuffer *fb = plane_state->fb;
+       struct drm_framebuffer *old_fb = pipe->plane.state->fb;
+
+       /* force 'mode_changed' when fb pitches changed, since
+        * the pitch related registers configuration of LCDIF
+        * can not be done when LCDIF is running.
+        */
+       if (old_fb && likely(!crtc_state->mode_changed)) {
+               if (old_fb->pitches[0] != fb->pitches[0])
+                       crtc_state->mode_changed = true;
+       }
+
+       return 0;
+}
+
 static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
                              struct drm_crtc_state *crtc_state,
                              struct drm_plane_state *plane_state)
@@ -244,6 +287,8 @@ static void mxsfb_pipe_disable_vblank(struct 
drm_simple_display_pipe *pipe)
 }
 
 static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
+       .mode_valid     = mxsfb_pipe_mode_valid,
+       .check          = mxsfb_pipe_check,
        .enable         = mxsfb_pipe_enable,
        .disable        = mxsfb_pipe_disable,
        .update         = mxsfb_pipe_update,
@@ -283,6 +328,9 @@ static int mxsfb_load(struct drm_device *drm, unsigned long 
flags)
        if (IS_ERR(mxsfb->clk_disp_axi))
                mxsfb->clk_disp_axi = NULL;
 
+       of_property_read_u32(drm->dev->of_node, "max-memory-bandwidth",
+                            &mxsfb->max_bw);
+
        ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h 
b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
index 8fb65d3..a178173 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
@@ -32,6 +32,8 @@ struct mxsfb_drm_private {
        struct drm_connector            *connector;
        struct drm_panel                *panel;
        struct drm_bridge               *bridge;
+
+       u32                             max_bw;
 };
 
 int mxsfb_setup_crtc(struct drm_device *dev);
-- 
2.7.4

Reply via email to