OSDN Git Service

drm: lcdif: Determine bus format and flags in ->atomic_check()
authorLiu Ying <victor.liu@nxp.com>
Wed, 10 May 2023 09:24:47 +0000 (17:24 +0800)
committerMarek Vasut <marex@denx.de>
Fri, 26 May 2023 17:07:30 +0000 (19:07 +0200)
Instead of determining LCDIF output bus format and bus flags in
->atomic_enable(), do that in ->atomic_check().  This is a
preparation for the upcoming patch to check consistent bus format
and bus flags across all first downstream bridges in ->atomic_check().
New lcdif_crtc_state structure is introduced to cache bus format
and bus flags states in ->atomic_check() so that they can be read
in ->atomic_enable().

Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Reviewed-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
Signed-off-by: Marek Vasut <marex@denx.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20230510092450.4024730-4-victor.liu@nxp.com
drivers/gpu/drm/mxsfb/lcdif_kms.c

index ba00a15..fab2253 100644 (file)
 #include "lcdif_drv.h"
 #include "lcdif_regs.h"
 
+struct lcdif_crtc_state {
+       struct drm_crtc_state   base;   /* always be the first member */
+       u32                     bus_format;
+       u32                     bus_flags;
+};
+
+static inline struct lcdif_crtc_state *
+to_lcdif_crtc_state(struct drm_crtc_state *s)
+{
+       return container_of(s, struct lcdif_crtc_state, base);
+}
+
 /* -----------------------------------------------------------------------------
  * CRTC
  */
@@ -385,48 +397,75 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif)
        readl(lcdif->base + LCDC_V8_CTRL);
 }
 
-static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif,
-                                    struct drm_plane_state *plane_state,
-                                    struct drm_bridge_state *bridge_state,
-                                    const u32 bus_format)
+static void lcdif_crtc_mode_set_nofb(struct drm_crtc_state *crtc_state,
+                                    struct drm_plane_state *plane_state)
 {
-       struct drm_device *drm = lcdif->crtc.dev;
-       struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
-       u32 bus_flags = 0;
-
-       if (lcdif->bridge->timings)
-               bus_flags = lcdif->bridge->timings->input_bus_flags;
-       else if (bridge_state)
-               bus_flags = bridge_state->input_bus_cfg.flags;
+       struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state);
+       struct drm_device *drm = crtc_state->crtc->dev;
+       struct lcdif_drm_private *lcdif = to_lcdif_drm_private(drm);
+       struct drm_display_mode *m = &crtc_state->adjusted_mode;
 
        DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
                             m->crtc_clock,
                             (int)(clk_get_rate(lcdif->clk) / 1000));
        DRM_DEV_DEBUG_DRIVER(drm->dev, "Bridge bus_flags: 0x%08X\n",
-                            bus_flags);
+                            lcdif_crtc_state->bus_flags);
        DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
 
        /* Mandatory eLCDIF reset as per the Reference Manual */
        lcdif_reset_block(lcdif);
 
-       lcdif_set_formats(lcdif, plane_state, bus_format);
+       lcdif_set_formats(lcdif, plane_state, lcdif_crtc_state->bus_format);
 
-       lcdif_set_mode(lcdif, bus_flags);
+       lcdif_set_mode(lcdif, lcdif_crtc_state->bus_flags);
 }
 
 static int lcdif_crtc_atomic_check(struct drm_crtc *crtc,
                                   struct drm_atomic_state *state)
 {
+       struct drm_device *drm = crtc->dev;
+       struct lcdif_drm_private *lcdif = to_lcdif_drm_private(drm);
        struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
                                                                          crtc);
+       struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state);
        bool has_primary = crtc_state->plane_mask &
                           drm_plane_mask(crtc->primary);
+       struct drm_bridge_state *bridge_state;
+       struct drm_bridge *bridge = lcdif->bridge;
+       int ret;
 
        /* The primary plane has to be enabled when the CRTC is active. */
        if (crtc_state->active && !has_primary)
                return -EINVAL;
 
-       return drm_atomic_add_affected_planes(state, crtc);
+       ret = drm_atomic_add_affected_planes(state, crtc);
+       if (ret)
+               return ret;
+
+       bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+       if (!bridge_state)
+               lcdif_crtc_state->bus_format = MEDIA_BUS_FMT_FIXED;
+       else
+               lcdif_crtc_state->bus_format = bridge_state->input_bus_cfg.format;
+
+       if (lcdif_crtc_state->bus_format == MEDIA_BUS_FMT_FIXED) {
+               dev_warn_once(drm->dev,
+                             "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
+                             "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
+               lcdif_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+       } else if (!lcdif_crtc_state->bus_format) {
+               /* If all else fails, default to RGB888_1X24 */
+               lcdif_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+       }
+
+       if (bridge->timings)
+               lcdif_crtc_state->bus_flags = bridge->timings->input_bus_flags;
+       else if (bridge_state)
+               lcdif_crtc_state->bus_flags = bridge_state->input_bus_cfg.flags;
+       else
+               lcdif_crtc_state->bus_flags = 0;
+
+       return 0;
 }
 
 static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc,
@@ -458,35 +497,18 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc,
                                     struct drm_atomic_state *state)
 {
        struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
+       struct drm_crtc_state *new_cstate = drm_atomic_get_new_crtc_state(state, crtc);
        struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
                                                                            crtc->primary);
        struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
-       struct drm_bridge_state *bridge_state = NULL;
        struct drm_device *drm = lcdif->drm;
-       u32 bus_format;
        dma_addr_t paddr;
 
-       bridge_state = drm_atomic_get_new_bridge_state(state, lcdif->bridge);
-       if (!bridge_state)
-               bus_format = MEDIA_BUS_FMT_FIXED;
-       else
-               bus_format = bridge_state->input_bus_cfg.format;
-
-       if (bus_format == MEDIA_BUS_FMT_FIXED) {
-               dev_warn_once(drm->dev,
-                             "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
-                             "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
-               bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-       } else if (!bus_format) {
-               /* If all else fails, default to RGB888_1X24 */
-               bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-       }
-
        clk_set_rate(lcdif->clk, m->crtc_clock * 1000);
 
        pm_runtime_get_sync(drm->dev);
 
-       lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format);
+       lcdif_crtc_mode_set_nofb(new_cstate, new_pstate);
 
        /* Write cur_buf as well to avoid an initial corrupt frame */
        paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0);
@@ -523,6 +545,48 @@ static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc,
        pm_runtime_put_sync(drm->dev);
 }
 
+static void lcdif_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state)
+{
+       __drm_atomic_helper_crtc_destroy_state(state);
+       kfree(to_lcdif_crtc_state(state));
+}
+
+static void lcdif_crtc_reset(struct drm_crtc *crtc)
+{
+       struct lcdif_crtc_state *state;
+
+       if (crtc->state)
+               lcdif_crtc_atomic_destroy_state(crtc, crtc->state);
+
+       crtc->state = NULL;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_crtc_reset(crtc, &state->base);
+}
+
+static struct drm_crtc_state *
+lcdif_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+       struct lcdif_crtc_state *old = to_lcdif_crtc_state(crtc->state);
+       struct lcdif_crtc_state *new;
+
+       if (WARN_ON(!crtc->state))
+               return NULL;
+
+       new = kzalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
+               return NULL;
+
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &new->base);
+
+       new->bus_format = old->bus_format;
+       new->bus_flags = old->bus_flags;
+
+       return &new->base;
+}
+
 static int lcdif_crtc_enable_vblank(struct drm_crtc *crtc)
 {
        struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
@@ -551,12 +615,12 @@ static const struct drm_crtc_helper_funcs lcdif_crtc_helper_funcs = {
 };
 
 static const struct drm_crtc_funcs lcdif_crtc_funcs = {
-       .reset = drm_atomic_helper_crtc_reset,
+       .reset = lcdif_crtc_reset,
        .destroy = drm_crtc_cleanup,
        .set_config = drm_atomic_helper_set_config,
        .page_flip = drm_atomic_helper_page_flip,
-       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
-       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+       .atomic_duplicate_state = lcdif_crtc_atomic_duplicate_state,
+       .atomic_destroy_state = lcdif_crtc_atomic_destroy_state,
        .enable_vblank = lcdif_crtc_enable_vblank,
        .disable_vblank = lcdif_crtc_disable_vblank,
 };