drm/msm/sde: add support for crtc properties
Move sync_fence_timeout property from plane to crtc, so that
a common wait time can be applied to all planes selected for
each crtc.
Change-Id: I8108de8882667fad00df000073ddfc23202b15e0
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 7c1d630..0f71530 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -83,7 +83,6 @@
PLANE_PROP_ALPHA,
PLANE_PROP_COLOR_FILL,
PLANE_PROP_SYNC_FENCE,
- PLANE_PROP_SYNC_FENCE_TIMEOUT,
/* enum/bitmask properties */
PLANE_PROP_ROTATION,
@@ -94,6 +93,17 @@
PLANE_PROP_COUNT
};
+enum msm_mdp_crtc_property {
+ /* # of blob properties */
+ CRTC_PROP_BLOBCOUNT,
+
+ /* range properties */
+ CRTC_PROP_SYNC_FENCE_TIMEOUT = CRTC_PROP_BLOBCOUNT,
+
+ /* total # of properties */
+ CRTC_PROP_COUNT
+};
+
struct msm_vblank_ctrl {
struct work_struct work;
struct list_head event_list;
@@ -171,6 +181,7 @@
/* Properties */
struct drm_property *plane_property[PLANE_PROP_COUNT];
+ struct drm_property *crtc_property[CRTC_PROP_COUNT];
/* VRAM carveout, used when no IOMMU: */
struct {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index d498e0c..e2d0db2 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -131,7 +131,13 @@
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
DBG("");
+
+ if (!crtc)
+ return;
+
+ msm_property_destroy(&sde_crtc->property_info);
debugfs_remove_recursive(sde_crtc->debugfs_root);
+
drm_crtc_cleanup(crtc);
kfree(sde_crtc);
}
@@ -524,10 +530,103 @@
}
}
-static int sde_crtc_set_property(struct drm_crtc *crtc,
- struct drm_property *property, uint64_t val)
+/**
+ * sde_crtc_destroy_state - state destroy hook
+ * @crtc: drm CRTC
+ * @state: CRTC state object to release
+ */
+static void sde_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
{
- return -EINVAL;
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+
+ if (!crtc || !state) {
+ DRM_ERROR("invalid argument(s)\n");
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(state);
+
+ DBG("");
+
+ __drm_atomic_helper_crtc_destroy_state(crtc, state);
+
+ /* destroy value helper */
+ msm_property_destroy_state(&sde_crtc->property_info, cstate,
+ cstate->property_values, cstate->property_blobs);
+}
+
+/**
+ * sde_crtc_duplicate_state - state duplicate hook
+ * @crtc: Pointer to drm crtc structure
+ * @Returns: Pointer to new drm_crtc_state structure
+ */
+static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate, *old_cstate;
+
+ if (!crtc || !crtc->state) {
+ DRM_ERROR("invalid argument(s)\n");
+ return NULL;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ old_cstate = to_sde_crtc_state(crtc->state);
+ cstate = msm_property_alloc_state(&sde_crtc->property_info);
+ if (!cstate) {
+ DRM_ERROR("failed to allocate state\n");
+ return NULL;
+ }
+
+ /* duplicate value helper */
+ msm_property_duplicate_state(&sde_crtc->property_info,
+ old_cstate, cstate,
+ cstate->property_values, cstate->property_blobs);
+
+ /* duplicate base helper */
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base);
+
+ return &cstate->base;
+}
+
+/**
+ * sde_crtc_reset - reset hook for CRTCs
+ * Resets the atomic state for @crtc by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ * @crtc: Pointer to drm crtc structure
+ */
+static void sde_crtc_reset(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+
+ if (!crtc) {
+ DRM_ERROR("invalid crtc\n");
+ return;
+ }
+
+ /* remove previous state, if present */
+ if (crtc->state) {
+ sde_crtc_destroy_state(crtc, crtc->state);
+ crtc->state = 0;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = msm_property_alloc_state(&sde_crtc->property_info);
+ if (!cstate) {
+ DRM_ERROR("failed to allocate state\n");
+ return;
+ }
+
+ /* reset value helper */
+ msm_property_reset_state(&sde_crtc->property_info, cstate,
+ cstate->property_values, cstate->property_blobs);
+
+ cstate->base.crtc = crtc;
+ crtc->state = &cstate->base;
}
static int sde_crtc_cursor_set(struct drm_crtc *crtc,
@@ -666,28 +765,6 @@
return 0;
}
-static const struct drm_crtc_funcs sde_crtc_funcs = {
- .set_config = drm_atomic_helper_set_config,
- .destroy = sde_crtc_destroy,
- .page_flip = drm_atomic_helper_page_flip,
- .set_property = sde_crtc_set_property,
- .reset = drm_atomic_helper_crtc_reset,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
- .cursor_set = sde_crtc_cursor_set,
- .cursor_move = sde_crtc_cursor_move,
-};
-
-static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = {
- .mode_fixup = sde_crtc_mode_fixup,
- .mode_set_nofb = sde_crtc_mode_set_nofb,
- .disable = sde_crtc_disable,
- .enable = sde_crtc_enable,
- .atomic_check = sde_crtc_atomic_check,
- .atomic_begin = sde_crtc_atomic_begin,
- .atomic_flush = sde_crtc_atomic_flush,
-};
-
int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
{
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
@@ -716,9 +793,104 @@
{
}
-static void sde_crtc_install_properties(struct drm_crtc *crtc,
- struct drm_mode_object *obj)
+/**
+ * sde_crtc_install_properties - install all drm properties for crtc
+ * @crtc: Pointer to drm crtc structure
+ */
+static void sde_crtc_install_properties(struct drm_crtc *crtc)
{
+ struct sde_crtc *sde_crtc;
+ struct drm_device *dev;
+
+ DBG("");
+
+ if (!crtc) {
+ DRM_ERROR("invalid crtc\n");
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ dev = crtc->dev;
+
+ /* range properties */
+ msm_property_install_range(&sde_crtc->property_info,
+ "sync_fence_timeout", 0, ~0, 10000,
+ CRTC_PROP_SYNC_FENCE_TIMEOUT);
+}
+
+/**
+ * sde_crtc_atomic_set_property - atomically set a crtc drm property
+ * @crtc: Pointer to drm crtc structure
+ * @state: Pointer to drm crtc state structure
+ * @property: Pointer to targeted drm property
+ * @val: Updated property value
+ * @Returns: Zero on success
+ */
+static int sde_crtc_atomic_set_property(struct drm_crtc *crtc,
+ struct drm_crtc_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ int ret = -EINVAL;
+
+ if (!crtc || !state || !property) {
+ DRM_ERROR("invalid argument(s)\n");
+ } else {
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(state);
+ ret = msm_property_atomic_set(&sde_crtc->property_info,
+ cstate->property_values, cstate->property_blobs,
+ property, val);
+ }
+
+ return ret;
+}
+
+/**
+ * sde_crtc_set_property - set a crtc drm property
+ * @crtc: Pointer to drm crtc structure
+ * @property: Pointer to targeted drm property
+ * @val: Updated property value
+ * @Returns: Zero on success
+ */
+static int sde_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_property *property, uint64_t val)
+{
+ DBG("");
+
+ return sde_crtc_atomic_set_property(crtc, crtc->state, property, val);
+}
+
+/**
+ * sde_crtc_atomic_get_property - retrieve a crtc drm property
+ * @crtc: Pointer to drm crtc structure
+ * @state: Pointer to drm crtc state structure
+ * @property: Pointer to targeted drm property
+ * @val: Pointer to variable for receiving property value
+ * @Returns: Zero on success
+ */
+static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
+ const struct drm_crtc_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ int ret = -EINVAL;
+
+ if (!crtc || !state) {
+ DRM_ERROR("invalid argument(s)\n");
+ } else {
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(state);
+ ret = msm_property_atomic_get(&sde_crtc->property_info,
+ cstate->property_values, cstate->property_blobs,
+ property, val);
+ }
+
+ return ret;
}
static int _sde_debugfs_mixer_read(struct seq_file *s, void *data)
@@ -762,6 +934,30 @@
return single_open(file, _sde_debugfs_mixer_read, inode->i_private);
}
+static const struct drm_crtc_funcs sde_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = sde_crtc_destroy,
+ .page_flip = drm_atomic_helper_page_flip,
+ .set_property = sde_crtc_set_property,
+ .atomic_set_property = sde_crtc_atomic_set_property,
+ .atomic_get_property = sde_crtc_atomic_get_property,
+ .reset = sde_crtc_reset,
+ .atomic_duplicate_state = sde_crtc_duplicate_state,
+ .atomic_destroy_state = sde_crtc_destroy_state,
+ .cursor_set = sde_crtc_cursor_set,
+ .cursor_move = sde_crtc_cursor_move,
+};
+
+static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = {
+ .mode_fixup = sde_crtc_mode_fixup,
+ .mode_set_nofb = sde_crtc_mode_set_nofb,
+ .disable = sde_crtc_disable,
+ .enable = sde_crtc_enable,
+ .atomic_check = sde_crtc_atomic_check,
+ .atomic_begin = sde_crtc_atomic_begin,
+ .atomic_flush = sde_crtc_atomic_flush,
+};
+
static void _sde_crtc_init_debugfs(struct sde_crtc *sde_crtc,
struct sde_kms *sde_kms)
{
@@ -810,8 +1006,6 @@
sde_crtc->encoder = encoder;
spin_lock_init(&sde_crtc->lm_lock);
- sde_crtc_install_properties(crtc, &crtc->base);
-
drm_crtc_init_with_planes(dev, crtc, plane, NULL, &sde_crtc_funcs);
drm_crtc_helper_add(crtc, &sde_crtc_helper_funcs);
@@ -828,6 +1022,14 @@
_sde_crtc_init_debugfs(sde_crtc, kms);
+ /* create CRTC properties */
+ msm_property_init(&sde_crtc->property_info, &crtc->base, dev,
+ priv->crtc_property, sde_crtc->property_data,
+ CRTC_PROP_COUNT, CRTC_PROP_BLOBCOUNT,
+ sizeof(struct sde_crtc_state));
+
+ sde_crtc_install_properties(crtc);
+
DBG("%s: Successfully initialized crtc", sde_crtc->name);
return crtc;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index aaad958..c069bef 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -14,6 +14,8 @@
#define _SDE_CRTC_H_
#include "drm_crtc.h"
+#include "msm_prop.h"
+#include "sde_kms.h"
#define CRTC_DUAL_MIXERS 2
#define SDE_CRTC_NAME_SIZE 12
@@ -54,6 +56,8 @@
* @pending : Whether or not an update is pending
* @vsync_count : Running count of received vsync events
* @drm_requested_vblank : Whether vblanks have been enabled in the encoder
+ * @property_info : Opaque structure for generic property support
+ * @property_defaults : Array of default values for generic property support
* @stage_cfg : H/w mixer stage configuration
* @debugfs_root : Parent of debugfs node
*/
@@ -76,10 +80,37 @@
u32 vsync_count;
bool drm_requested_vblank;
+ struct msm_property_info property_info;
+ struct msm_property_data property_data[CRTC_PROP_COUNT];
+
struct sde_hw_stage_cfg stage_cfg;
struct dentry *debugfs_root;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
+/**
+ * struct sde_crtc_state - sde container for atomic crtc state
+ * @base: Base drm crtc state structure
+ * @property_values: Current crtc property values
+ * @property_blobs: Reference pointers for blob properties
+ */
+struct sde_crtc_state {
+ struct drm_crtc_state base;
+ uint64_t property_values[CRTC_PROP_COUNT];
+ struct drm_property_blob *property_blobs[CRTC_PROP_COUNT];
+};
+
+#define to_sde_crtc_state(x) \
+ container_of(x, struct sde_crtc_state, base)
+
+/**
+ * sde_crtc_get_property - query integer value of crtc property
+ * @S: Pointer to crtc state
+ * @X: Property index, from enum msm_mdp_crtc_property
+ * Returns: Integer value of requested property
+ */
+#define sde_crtc_get_property(S, X) \
+ ((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)]) : 0)
+
#endif /* _SDE_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 915732e..afb0444 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -376,7 +376,14 @@
void sde_plane_complete_flip(struct drm_plane *plane);
struct drm_plane *sde_plane_init(struct drm_device *dev,
uint32_t pipe, bool primary_plane);
-int sde_plane_wait_sync_fence(struct drm_plane *plane);
+
+/**
+ * sde_plane_wait_sync_fence - wait for sync fence object
+ * @plane: Pointer to DRM plane object
+ * @wait_ms: Wait timeout value
+ * Returns: Zero on success
+ */
+int sde_plane_wait_sync_fence(struct drm_plane *plane, uint32_t wait_ms);
/**
* sde_plane_color_fill(): Enables color fill on plane
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 424d88d..0aa6dbf 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -89,11 +89,10 @@
DBG("0x%llX", fd);
}
-int sde_plane_wait_sync_fence(struct drm_plane *plane)
+int sde_plane_wait_sync_fence(struct drm_plane *plane, uint32_t wait_ms)
{
struct sde_plane_state *pstate;
void *sync_fence;
- long wait_ms;
int ret = -EINVAL;
if (!plane) {
@@ -105,11 +104,8 @@
sync_fence = pstate->sync_fence;
if (sync_fence) {
- wait_ms = (long)sde_plane_get_property(pstate,
- PLANE_PROP_SYNC_FENCE_TIMEOUT);
-
DBG("%s", to_sde_plane(plane)->pipe_name);
- ret = sde_sync_wait(sync_fence, wait_ms);
+ ret = sde_sync_wait(sync_fence, (long)wait_ms);
if (!ret)
DBG("signaled");
else if (ret == -ETIME)
@@ -1091,10 +1087,6 @@
msm_property_install_range(&psde->property_info, "sync_fence",
0, ~0, ~0, PLANE_PROP_SYNC_FENCE);
- msm_property_install_range(&psde->property_info, "sync_fence_timeout",
- 0, ~0, 10000,
- PLANE_PROP_SYNC_FENCE_TIMEOUT);
-
/* standard properties */
msm_property_install_rotation(&psde->property_info,
BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y),