Files
linux/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
Liviu Dudau eaa225b6b5 drm/komeda: Fix handling of atomic commits in the atomic_commit_tail hook
Komeda driver relies on the generic DRM atomic helper functions to handle
commits. It only implements an atomic_commit_tail hook for the
mode_config_helper_funcs and even that one is pretty close to the generic
implementation with the exception of additional dma_fence signalling.

What the generic helper framework doesn't do is waiting for the actual
hardware to signal that the commit parameters have been written into the
appropriate registers. As we signal CRTC events only on the irq handlers,
we need to flush the configuration and wait for the hardware to respond.

Add the Komeda specific implementation for atomic_commit_hw_done() that
flushes and waits for flip done before calling drm_atomic_helper_commit_hw_done().

The fix was prompted by a patch from Carsten Haitzler where he was trying to
solve the same issue but in a different way that I think can lead to wrong
event signaling to userspace.

Reported-by: Carsten Haitzler <carsten.haitzler@arm.com>
Tested-by: Carsten Haitzler <carsten.haitzler@arm.com>
Reviewed-by: Carsten Haitzler <carsten.haitzler@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220722122139.288486-1-liviu.dudau@arm.com
2022-07-22 14:12:08 +01:00

193 lines
5.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
* Author: James.Qian.Wang <james.qian.wang@arm.com>
*
*/
#ifndef _KOMEDA_KMS_H_
#define _KOMEDA_KMS_H_
#include <linux/list.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_writeback.h>
#include <drm/drm_print.h>
/**
* struct komeda_plane - komeda instance of drm_plane
*/
struct komeda_plane {
/** @base: &drm_plane */
struct drm_plane base;
/**
* @layer:
*
* represents available layer input pipelines for this plane.
*
* NOTE:
* the layer is not for a specific Layer, but indicate a group of
* Layers with same capabilities.
*/
struct komeda_layer *layer;
};
/**
* struct komeda_plane_state
*
* The plane_state can be split into two data flow (left/right) and handled
* by two layers &komeda_plane.layer and &komeda_plane.layer.right
*/
struct komeda_plane_state {
/** @base: &drm_plane_state */
struct drm_plane_state base;
/** @zlist_node: zorder list node */
struct list_head zlist_node;
/** @layer_split: on/off layer_split */
u8 layer_split : 1;
};
/**
* struct komeda_wb_connector
*/
struct komeda_wb_connector {
/** @base: &drm_writeback_connector */
struct drm_writeback_connector base;
/** @wb_layer: represents associated writeback pipeline of komeda */
struct komeda_layer *wb_layer;
};
/**
* struct komeda_crtc
*/
struct komeda_crtc {
/** @base: &drm_crtc */
struct drm_crtc base;
/** @master: only master has display output */
struct komeda_pipeline *master;
/**
* @slave: optional
*
* Doesn't have its own display output, the handled data flow will
* merge into the master.
*/
struct komeda_pipeline *slave;
/** @slave_planes: komeda slave planes mask */
u32 slave_planes;
/** @wb_conn: komeda write back connector */
struct komeda_wb_connector *wb_conn;
/** @disable_done: this flip_done is for tracing the disable */
struct completion *disable_done;
};
/**
* struct komeda_crtc_state
*/
struct komeda_crtc_state {
/** @base: &drm_crtc_state */
struct drm_crtc_state base;
/* private properties */
/* computed state which are used by validate/check */
/**
* @affected_pipes:
* the affected pipelines in once display instance
*/
u32 affected_pipes;
/**
* @active_pipes:
* the active pipelines in once display instance
*/
u32 active_pipes;
/** @clock_ratio: ratio of (aclk << 32)/pxlclk */
u64 clock_ratio;
/** @max_slave_zorder: the maximum of slave zorder */
u32 max_slave_zorder;
};
/** struct komeda_kms_dev - for gather KMS related things */
struct komeda_kms_dev {
/** @base: &drm_device */
struct drm_device base;
/** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
int n_crtcs;
/** @crtcs: crtcs list */
struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
};
#define to_kplane(p) container_of(p, struct komeda_plane, base)
#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
#define to_wb_conn(x) container_of(x, struct drm_writeback_connector, base)
static inline bool is_writeback_only(struct drm_crtc_state *st)
{
struct komeda_wb_connector *wb_conn = to_kcrtc(st->crtc)->wb_conn;
struct drm_connector *conn = wb_conn ? &wb_conn->base.base : NULL;
return conn && (st->connector_mask == BIT(drm_connector_index(conn)));
}
static inline bool
is_only_changed_connector(struct drm_crtc_state *st, struct drm_connector *conn)
{
struct drm_crtc_state *old_st;
u32 changed_connectors;
old_st = drm_atomic_get_old_crtc_state(st->state, st->crtc);
changed_connectors = st->connector_mask ^ old_st->connector_mask;
return BIT(drm_connector_index(conn)) == changed_connectors;
}
static inline bool has_flip_h(u32 rot)
{
u32 rotation = drm_rotation_simplify(rot,
DRM_MODE_ROTATE_0 |
DRM_MODE_ROTATE_90 |
DRM_MODE_REFLECT_MASK);
if (rotation & DRM_MODE_ROTATE_90)
return !!(rotation & DRM_MODE_REFLECT_Y);
else
return !!(rotation & DRM_MODE_REFLECT_X);
}
void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st,
u32 *color_depths, u32 *color_formats);
unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st);
int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
struct komeda_dev *mdev);
int komeda_kms_add_wb_connectors(struct komeda_kms_dev *kms,
struct komeda_dev *mdev);
void komeda_kms_cleanup_private_objs(struct komeda_kms_dev *kms);
void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,
struct komeda_events *evts);
void komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc,
struct completion *input_flip_done);
struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
void komeda_kms_detach(struct komeda_kms_dev *kms);
#endif /*_KOMEDA_KMS_H_*/