drm: lcdif: Determine bus format and flags in ->atomic_check()

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
This commit is contained in:
Liu Ying 2023-05-10 17:24:47 +08:00 committed by Marek Vasut
parent 3f07432025
commit 5befcdcaf0

View file

@ -30,6 +30,18 @@
#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,
};