drm/kmb: Disable change of plane parameters
authorEdmund Dea <edmund.j.dea@intel.com>
Wed, 6 Oct 2021 23:03:48 +0000 (16:03 -0700)
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Thu, 21 Oct 2021 09:08:08 +0000 (11:08 +0200)
Due to HW limitations, KMB cannot change height, width, or
pixel format after initial plane configuration.

v2: removed memset disp_cfg as it is already zero.

Fixes: 7f7b96a8a0a1 ("drm/kmb: Add support for KeemBay Display")
Signed-off-by: Edmund Dea <edmund.j.dea@intel.com>
Signed-off-by: Anitha Chrisanthus <anitha.chrisanthus@intel.com>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20211013233632.471892-4-anitha.chrisanthus@intel.com
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
drivers/gpu/drm/kmb/kmb_drv.h
drivers/gpu/drm/kmb/kmb_plane.c
drivers/gpu/drm/kmb/kmb_plane.h

index 4f7a986..bf085e9 100644 (file)
@@ -57,6 +57,7 @@ struct kmb_drm_private {
        spinlock_t                      irq_lock;
        int                             irq_lcd;
        int                             sys_clk_mhz;
+       struct disp_cfg                 init_disp_cfg[KMB_MAX_PLANES];
        struct layer_status             plane_status[KMB_MAX_PLANES];
        int                             kmb_under_flow;
        int                             kmb_flush_done;
index 06b0c42..00404ba 100644 (file)
@@ -67,8 +67,21 @@ static const u32 kmb_formats_v[] = {
 
 static unsigned int check_pixel_format(struct drm_plane *plane, u32 format)
 {
+       struct kmb_drm_private *kmb;
+       struct kmb_plane *kmb_plane = to_kmb_plane(plane);
        int i;
+       int plane_id = kmb_plane->id;
+       struct disp_cfg init_disp_cfg;
 
+       kmb = to_kmb(plane->dev);
+       init_disp_cfg = kmb->init_disp_cfg[plane_id];
+       /* Due to HW limitations, changing pixel format after initial
+        * plane configuration is not supported.
+        */
+       if (init_disp_cfg.format && init_disp_cfg.format != format) {
+               drm_dbg(&kmb->drm, "Cannot change format after initial plane configuration");
+               return -EINVAL;
+       }
        for (i = 0; i < plane->format_count; i++) {
                if (plane->format_types[i] == format)
                        return 0;
@@ -81,11 +94,17 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,
 {
        struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
                                                                                 plane);
+       struct kmb_drm_private *kmb;
+       struct kmb_plane *kmb_plane = to_kmb_plane(plane);
+       int plane_id = kmb_plane->id;
+       struct disp_cfg init_disp_cfg;
        struct drm_framebuffer *fb;
        int ret;
        struct drm_crtc_state *crtc_state;
        bool can_position;
 
+       kmb = to_kmb(plane->dev);
+       init_disp_cfg = kmb->init_disp_cfg[plane_id];
        fb = new_plane_state->fb;
        if (!fb || !new_plane_state->crtc)
                return 0;
@@ -99,6 +118,16 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,
            new_plane_state->crtc_w < KMB_FB_MIN_WIDTH ||
            new_plane_state->crtc_h < KMB_FB_MIN_HEIGHT)
                return -EINVAL;
+
+       /* Due to HW limitations, changing plane height or width after
+        * initial plane configuration is not supported.
+        */
+       if ((init_disp_cfg.width && init_disp_cfg.height) &&
+           (init_disp_cfg.width != fb->width ||
+           init_disp_cfg.height != fb->height)) {
+               drm_dbg(&kmb->drm, "Cannot change plane height or width after initial configuration");
+               return -EINVAL;
+       }
        can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
        crtc_state =
                drm_atomic_get_existing_crtc_state(state,
@@ -335,6 +364,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,
        unsigned char plane_id;
        int num_planes;
        static dma_addr_t addr[MAX_SUB_PLANES];
+       struct disp_cfg *init_disp_cfg;
 
        if (!plane || !new_plane_state || !old_plane_state)
                return;
@@ -357,7 +387,8 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,
        }
        spin_unlock_irq(&kmb->irq_lock);
 
-       src_w = (new_plane_state->src_w >> 16);
+       init_disp_cfg = &kmb->init_disp_cfg[plane_id];
+       src_w = new_plane_state->src_w >> 16;
        src_h = new_plane_state->src_h >> 16;
        crtc_x = new_plane_state->crtc_x;
        crtc_y = new_plane_state->crtc_y;
@@ -500,6 +531,16 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,
 
        /* Enable DMA */
        kmb_write_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id), dma_cfg);
+
+       /* Save initial display config */
+       if (!init_disp_cfg->width ||
+           !init_disp_cfg->height ||
+           !init_disp_cfg->format) {
+               init_disp_cfg->width = width;
+               init_disp_cfg->height = height;
+               init_disp_cfg->format = fb->format->format;
+       }
+
        drm_dbg(&kmb->drm, "dma_cfg=0x%x LCD_DMA_CFG=0x%x\n", dma_cfg,
                kmb_read_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id)));
 
index 6e8d22c..b511440 100644 (file)
@@ -63,6 +63,12 @@ struct layer_status {
        u32 ctrl;
 };
 
+struct disp_cfg {
+       unsigned int width;
+       unsigned int height;
+       unsigned int format;
+};
+
 struct kmb_plane *kmb_plane_init(struct drm_device *drm);
 void kmb_plane_destroy(struct drm_plane *plane);
 #endif /* __KMB_PLANE_H__ */