forked from Minki/linux
drm/imx: handle pending updates better, add plane zpos property support
- Add a mechanism to only send commit done events once all pending updates have been applied. This closes a small race window where already armed events could fire even though the double buffered hardware update just missed the update window. - Add plane zpos property support to allow placing the overlay plane behind the primary plane. - Allow building imx-drm on all platforms under COMPILE_TEST. -----BEGIN PGP SIGNATURE----- iI4EABYIADYWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCXG/bAhgccGhpbGlwcC56 YWJlbEBnbWFpbC5jb20ACgkQ1YWnJRg3YsAz6wEA4ThGF7nvouYeI2jLEuLmkIpr wXdyGA5XScfoSQUgFisBAPGl+g578KjIq7PrazKAEoKeencLytlf8mWCl99YZukB =Veu5 -----END PGP SIGNATURE----- Merge tag 'imx-drm-next-2019-02-22' of git://git.pengutronix.de/pza/linux into drm-next drm/imx: handle pending updates better, add plane zpos property support - Add a mechanism to only send commit done events once all pending updates have been applied. This closes a small race window where already armed events could fire even though the double buffered hardware update just missed the update window. - Add plane zpos property support to allow placing the overlay plane behind the primary plane. - Allow building imx-drm on all platforms under COMPILE_TEST. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Philipp Zabel <pza@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/20190222112350.m3ucezilqx6cyest@pengutronix.de
This commit is contained in:
commit
7fbd5d784f
@ -4,7 +4,7 @@ config DRM_IMX
|
||||
select VIDEOMODE_HELPERS
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
|
||||
depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
|
||||
depends on IMX_IPUV3_CORE
|
||||
help
|
||||
enable i.MX graphics support
|
||||
@ -18,6 +18,7 @@ config DRM_IMX_PARALLEL_DISPLAY
|
||||
config DRM_IMX_TVE
|
||||
tristate "Support for TV and VGA displays"
|
||||
depends on DRM_IMX
|
||||
depends on COMMON_CLK
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Choose this to enable the internal Television Encoder (TVe)
|
||||
|
@ -49,11 +49,7 @@ static int imx_drm_atomic_check(struct drm_device *dev,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
ret = drm_atomic_helper_check(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -229,6 +225,7 @@ static int imx_drm_bind(struct device *dev)
|
||||
drm->mode_config.funcs = &imx_drm_mode_config_funcs;
|
||||
drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
|
||||
drm->mode_config.allow_fb_modifiers = true;
|
||||
drm->mode_config.normalize_zpos = true;
|
||||
|
||||
drm_mode_config_init(drm);
|
||||
|
||||
|
@ -34,6 +34,7 @@ struct ipu_crtc {
|
||||
struct ipu_dc *dc;
|
||||
struct ipu_di *di;
|
||||
int irq;
|
||||
struct drm_pending_vblank_event *event;
|
||||
};
|
||||
|
||||
static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc)
|
||||
@ -173,8 +174,31 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = {
|
||||
static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct ipu_crtc *ipu_crtc = dev_id;
|
||||
struct drm_crtc *crtc = &ipu_crtc->base;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
drm_crtc_handle_vblank(&ipu_crtc->base);
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
|
||||
if (ipu_crtc->event) {
|
||||
for (i = 0; i < ARRAY_SIZE(ipu_crtc->plane); i++) {
|
||||
struct ipu_plane *plane = ipu_crtc->plane[i];
|
||||
|
||||
if (!plane)
|
||||
continue;
|
||||
|
||||
if (ipu_plane_atomic_update_pending(&plane->base))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(ipu_crtc->plane)) {
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
drm_crtc_send_vblank_event(crtc, ipu_crtc->event);
|
||||
ipu_crtc->event = NULL;
|
||||
drm_crtc_vblank_put(crtc);
|
||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -223,8 +247,10 @@ static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
{
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
if (crtc->state->event) {
|
||||
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
|
||||
|
||||
WARN_ON(drm_crtc_vblank_get(crtc));
|
||||
drm_crtc_arm_vblank_event(crtc, crtc->state->event);
|
||||
ipu_crtc->event = crtc->state->event;
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
|
@ -273,6 +273,7 @@ static void ipu_plane_destroy(struct drm_plane *plane)
|
||||
|
||||
static void ipu_plane_state_reset(struct drm_plane *plane)
|
||||
{
|
||||
unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
|
||||
struct ipu_plane_state *ipu_state;
|
||||
|
||||
if (plane->state) {
|
||||
@ -284,8 +285,11 @@ static void ipu_plane_state_reset(struct drm_plane *plane)
|
||||
|
||||
ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
|
||||
|
||||
if (ipu_state)
|
||||
if (ipu_state) {
|
||||
__drm_atomic_helper_plane_reset(plane, &ipu_state->base);
|
||||
ipu_state->base.zpos = zpos;
|
||||
ipu_state->base.normalized_zpos = zpos;
|
||||
}
|
||||
}
|
||||
|
||||
static struct drm_plane_state *
|
||||
@ -560,6 +564,25 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
|
||||
if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
|
||||
ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
|
||||
|
||||
switch (ipu_plane->dp_flow) {
|
||||
case IPU_DP_FLOW_SYNC_BG:
|
||||
if (state->normalized_zpos == 1) {
|
||||
ipu_dp_set_global_alpha(ipu_plane->dp,
|
||||
!fb->format->has_alpha, 0xff,
|
||||
true);
|
||||
} else {
|
||||
ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
|
||||
}
|
||||
break;
|
||||
case IPU_DP_FLOW_SYNC_FG:
|
||||
if (state->normalized_zpos == 1) {
|
||||
ipu_dp_set_global_alpha(ipu_plane->dp,
|
||||
!fb->format->has_alpha, 0xff,
|
||||
false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
eba = drm_plane_state_to_eba(state, 0);
|
||||
|
||||
/*
|
||||
@ -582,6 +605,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
|
||||
active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
|
||||
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
|
||||
ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
|
||||
ipu_plane->next_buf = !active;
|
||||
if (ipu_plane_separate_alpha(ipu_plane)) {
|
||||
active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
|
||||
ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
|
||||
@ -595,34 +619,11 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
|
||||
switch (ipu_plane->dp_flow) {
|
||||
case IPU_DP_FLOW_SYNC_BG:
|
||||
ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB);
|
||||
ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
|
||||
break;
|
||||
case IPU_DP_FLOW_SYNC_FG:
|
||||
ipu_dp_setup_channel(ipu_plane->dp, ics,
|
||||
IPUV3_COLORSPACE_UNKNOWN);
|
||||
/* Enable local alpha on partial plane */
|
||||
switch (fb->format->format) {
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
case DRM_FORMAT_ABGR1555:
|
||||
case DRM_FORMAT_RGBA5551:
|
||||
case DRM_FORMAT_BGRA5551:
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
case DRM_FORMAT_RGB565_A8:
|
||||
case DRM_FORMAT_BGR565_A8:
|
||||
case DRM_FORMAT_RGB888_A8:
|
||||
case DRM_FORMAT_BGR888_A8:
|
||||
case DRM_FORMAT_RGBX8888_A8:
|
||||
case DRM_FORMAT_BGRX8888_A8:
|
||||
ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
|
||||
break;
|
||||
default:
|
||||
ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
|
||||
@ -709,6 +710,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
|
||||
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
|
||||
ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts);
|
||||
ipu_plane_enable(ipu_plane);
|
||||
ipu_plane->next_buf = -1;
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
|
||||
@ -718,6 +720,24 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
|
||||
.atomic_update = ipu_plane_atomic_update,
|
||||
};
|
||||
|
||||
bool ipu_plane_atomic_update_pending(struct drm_plane *plane)
|
||||
{
|
||||
struct ipu_plane *ipu_plane = to_ipu_plane(plane);
|
||||
struct drm_plane_state *state = plane->state;
|
||||
struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
|
||||
|
||||
/* disabled crtcs must not block the update */
|
||||
if (!state->crtc)
|
||||
return false;
|
||||
|
||||
if (ipu_state->use_pre)
|
||||
return ipu_prg_channel_configure_pending(ipu_plane->ipu_ch);
|
||||
else if (ipu_plane->next_buf >= 0)
|
||||
return ipu_idmac_get_current_buffer(ipu_plane->ipu_ch) !=
|
||||
ipu_plane->next_buf;
|
||||
|
||||
return false;
|
||||
}
|
||||
int ipu_planes_assign_pre(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
@ -806,6 +826,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
|
||||
{
|
||||
struct ipu_plane *ipu_plane;
|
||||
const uint64_t *modifiers = ipu_format_modifiers;
|
||||
unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
|
||||
@ -836,5 +857,10 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
|
||||
|
||||
drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
|
||||
|
||||
if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG)
|
||||
drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, 1);
|
||||
else
|
||||
drm_plane_create_zpos_immutable_property(&ipu_plane->base, 0);
|
||||
|
||||
return ipu_plane;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ struct ipu_plane {
|
||||
int dp_flow;
|
||||
|
||||
bool disabling;
|
||||
int next_buf;
|
||||
};
|
||||
|
||||
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
|
||||
@ -48,5 +49,6 @@ int ipu_plane_irq(struct ipu_plane *plane);
|
||||
|
||||
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
|
||||
void ipu_plane_disable_deferred(struct drm_plane *plane);
|
||||
bool ipu_plane_atomic_update_pending(struct drm_plane *plane);
|
||||
|
||||
#endif
|
||||
|
@ -265,6 +265,12 @@ void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
|
||||
writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
|
||||
}
|
||||
|
||||
bool ipu_pre_update_pending(struct ipu_pre *pre)
|
||||
{
|
||||
return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
|
||||
IPU_PRE_CTRL_SDW_UPDATE);
|
||||
}
|
||||
|
||||
u32 ipu_pre_get_baddr(struct ipu_pre *pre)
|
||||
{
|
||||
return (u32)pre->buffer_paddr;
|
||||
|
@ -347,6 +347,22 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
|
||||
|
||||
bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
|
||||
{
|
||||
int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
|
||||
struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
|
||||
struct ipu_prg_channel *chan;
|
||||
|
||||
if (prg_chan < 0)
|
||||
return false;
|
||||
|
||||
chan = &prg->chan[prg_chan];
|
||||
WARN_ON(!chan->enabled);
|
||||
|
||||
return ipu_pre_update_pending(prg->pres[chan->used_pre]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
|
||||
|
||||
static int ipu_prg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -272,6 +272,7 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
|
||||
unsigned int height, unsigned int stride, u32 format,
|
||||
uint64_t modifier, unsigned int bufaddr);
|
||||
void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
|
||||
bool ipu_pre_update_pending(struct ipu_pre *pre);
|
||||
|
||||
struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
|
||||
int ipu_id);
|
||||
|
@ -348,6 +348,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
|
||||
unsigned int axi_id, unsigned int width,
|
||||
unsigned int height, unsigned int stride,
|
||||
u32 format, uint64_t modifier, unsigned long *eba);
|
||||
bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan);
|
||||
|
||||
/*
|
||||
* IPU CMOS Sensor Interface (csi) functions
|
||||
|
Loading…
Reference in New Issue
Block a user