mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 22:02:28 +00:00
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:
parent
3f07432025
commit
5befcdcaf0
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user