Commit 5befcdca authored by Liu Ying's avatar Liu Ying Committed by Marek Vasut
Browse files

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: default avatarAlexander Stein <alexander.stein@ew.tq-group.com>
Reviewed-by: default avatarAlexander Stein <alexander.stein@ew.tq-group.com>
Reviewed-by: default avatarMarek Vasut <marex@denx.de>
Signed-off-by: default avatarLiu Ying <victor.liu@nxp.com>
Signed-off-by: default avatarMarek Vasut <marex@denx.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20230510092450.4024730-4-victor.liu@nxp.com
parent 3f074320
Loading
Loading
Loading
Loading
+102 −38
Original line number Diff line number Diff line
@@ -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,
};