drm/msm/sde: input fence support for planes
Consolidate property default definitions to a single location, and
enable planes-related support for the input fence property.
Add sde_fence.h/c for Android fence API wrappers.
Change-Id: I8785f8cdaf32d62373678aa9c35dd94d39d7992f
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 4bbfc1a..be0181a 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -12,6 +12,7 @@
#include <linux/debugfs.h>
#include <uapi/drm/sde_drm.h>
#include "sde_kms.h"
+#include "sde_fence.h"
#include "sde_formats.h"
#include "sde_hw_sspp.h"
@@ -50,6 +51,9 @@
char pipe_name[SDE_NAME_SIZE];
+ /* cache property default values (for reset) */
+ uint64_t property_defaults[PLANE_PROP_COUNT];
+
/* debugfs related stuff */
struct dentry *debugfs_root;
struct sde_debugfs_regset32 debugfs_src;
@@ -63,15 +67,56 @@
return state->fb && state->crtc;
}
+/* helper to update a state's sync fence pointer from the property */
+static void _sde_plane_update_sync_fence(struct drm_plane *plane,
+ struct sde_plane_state *pstate, uint64_t fd)
+{
+ if (!plane || !pstate)
+ return;
+
+ /* clear previous reference */
+ if (pstate->sync_fence)
+ sde_sync_put(pstate->sync_fence);
+
+ /* get fence pointer for later */
+ pstate->sync_fence = sde_sync_get(fd);
+
+ DBG("0x%llX", fd);
+}
+
+void *sde_plane_get_sync_fence(struct drm_plane *plane)
+{
+ struct sde_plane_state *pstate;
+ void *ret = NULL;
+
+ if (!plane) {
+ DRM_ERROR("Invalid plane\n");
+ } else if (!plane->state) {
+ DRM_ERROR("Invalid plane state\n");
+ } else {
+ pstate = to_sde_plane_state(plane->state);
+ ret = pstate->sync_fence;
+
+ DBG("%s", to_sde_plane(plane)->pipe_name);
+ }
+
+ return ret;
+}
+
static void _sde_plane_set_scanout(struct drm_plane *plane,
struct sde_plane_state *pstate,
struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
{
- struct sde_plane *psde = to_sde_plane(plane);
+ struct sde_plane *psde;
unsigned int shift;
int i;
- if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
+ if (!plane || !pstate || !pipe_cfg || !fb)
+ return;
+
+ psde = to_sde_plane(plane);
+
+ if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
/* stride */
if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
BIT(SDE_DRM_DEINTERLACE))
@@ -405,6 +450,7 @@
DRM_ERROR("Invalid crtc/fb\n");
return -EINVAL;
}
+
psde = to_sde_plane(plane);
pstate = to_sde_plane_state(plane->state);
nplanes = drm_format_num_planes(fb->pixel_format);
@@ -634,7 +680,7 @@
if (!new_state->fb)
return 0;
- DBG("%s: prepare: FB[%u]", psde->pipe_name, fb->base.id);
+ DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
return msm_framebuffer_prepare(fb, psde->mmu_id);
}
@@ -647,7 +693,7 @@
if (!fb)
return;
- DBG("%s: cleanup: FB[%u]", psde->pipe_name, fb->base.id);
+ DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
msm_framebuffer_cleanup(fb, psde->mmu_id);
}
@@ -721,8 +767,6 @@
struct drm_plane_state *state;
struct sde_plane_state *pstate;
- DBG("%s: update", sde_plane->pipe_name);
-
if (!plane || !plane->state) {
DRM_ERROR("Invalid plane/state\n");
return;
@@ -732,6 +776,8 @@
state = plane->state;
pstate = to_sde_plane_state(state);
+ DBG("%s: update", sde_plane->pipe_name);
+
if (!sde_plane_enabled(state)) {
pstate->pending = true;
} else if (pstate->mode_changed) {
@@ -752,12 +798,28 @@
}
}
+static inline struct drm_property **_sde_plane_get_property_entry(
+ struct drm_device *dev, enum msm_mdp_plane_property property)
+{
+ struct msm_drm_private *priv;
+
+ if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
+ return NULL;
+
+ priv = dev->dev_private;
+
+ return &(priv->plane_property[property]);
+}
+
static void _sde_plane_install_range_property(struct drm_plane *plane,
struct drm_device *dev, const char *name,
uint64_t min, uint64_t max, uint64_t init,
- struct drm_property **prop)
+ enum msm_mdp_plane_property property)
{
- if (plane && dev && name && prop) {
+ struct drm_property **prop;
+
+ prop = _sde_plane_get_property_entry(dev, property);
+ if (plane && name && prop) {
/* only create the property once */
if (*prop == 0) {
*prop = drm_property_create_range(dev,
@@ -766,6 +828,9 @@
DRM_ERROR("Create %s property failed\n", name);
}
+ /* save init value for later */
+ to_sde_plane(plane)->property_defaults[property] = init;
+
/* always attach property, if created */
if (*prop)
drm_object_attach_property(&plane->base, *prop, init);
@@ -773,9 +838,13 @@
}
static void _sde_plane_install_rotation_property(struct drm_plane *plane,
- struct drm_device *dev, struct drm_property **prop)
+ struct drm_device *dev, enum msm_mdp_plane_property property)
{
- if (plane && dev && prop) {
+ struct sde_plane *psde;
+ struct drm_property **prop;
+
+ prop = _sde_plane_get_property_entry(dev, property);
+ if (plane && prop) {
/* only create the property once */
if (*prop == 0) {
*prop = drm_mode_create_rotation_property(dev,
@@ -785,18 +854,27 @@
DRM_ERROR("Create rotation property failed\n");
}
+ /* save init value for later */
+ psde = to_sde_plane(plane);
+ psde->property_defaults[property] = 0;
+
/* always attach property, if created */
if (*prop)
- drm_object_attach_property(&plane->base, *prop, 0);
+ drm_object_attach_property(&plane->base, *prop,
+ psde->property_defaults[property]);
}
}
static void _sde_plane_install_enum_property(struct drm_plane *plane,
struct drm_device *dev, const char *name, int is_bitmask,
const struct drm_prop_enum_list *values, int num_values,
- struct drm_property **prop)
+ enum msm_mdp_plane_property property)
{
- if (plane && dev && name && prop && values && num_values) {
+ struct sde_plane *psde;
+ struct drm_property **prop;
+
+ prop = _sde_plane_get_property_entry(dev, property);
+ if (plane && name && prop && values && num_values) {
/* only create the property once */
if (*prop == 0) {
/* 'bitmask' is a special type of 'enum' */
@@ -812,17 +890,26 @@
DRM_ERROR("Create %s property failed\n", name);
}
+ /* save init value for later */
+ psde = to_sde_plane(plane);
+ psde->property_defaults[property] = 0;
+
/* always attach property, if created */
if (*prop)
- drm_object_attach_property(&plane->base, *prop, 0);
+ drm_object_attach_property(&plane->base, *prop,
+ psde->property_defaults[property]);
}
}
static void _sde_plane_install_blob_property(struct drm_plane *plane,
struct drm_device *dev, const char *name,
- struct drm_property **prop)
+ enum msm_mdp_plane_property property)
{
- if (plane && dev && name && prop) {
+ struct sde_plane *psde;
+ struct drm_property **prop;
+
+ prop = _sde_plane_get_property_entry(dev, property);
+ if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
/* only create the property once */
if (*prop == 0) {
/* use 'create' for blob property place holder */
@@ -832,9 +919,14 @@
DRM_ERROR("Create %s property failed\n", name);
}
+ /* save init value for later */
+ psde = to_sde_plane(plane);
+ psde->property_defaults[property] = 0;
+
/* always attach property, if created */
if (*prop)
- drm_object_attach_property(&plane->base, *prop, 0);
+ drm_object_attach_property(&plane->base, *prop,
+ psde->property_defaults[property]);
}
}
@@ -852,8 +944,7 @@
} else if (!property) {
DRM_ERROR("Incoming property is NULL\n");
} else {
- prop_array = ((struct msm_drm_private *)
- (plane->dev->dev_private))->plane_property;
+ prop_array = _sde_plane_get_property_entry(plane->dev, 0);
if (!prop_array)
/* should never hit this */
DRM_ERROR("Invalid property array\n");
@@ -863,6 +954,9 @@
if (prop_array[idx] == property)
break;
}
+
+ if (idx == PLANE_PROP_COUNT)
+ DRM_ERROR("Invalid property pointer\n");
}
return idx;
@@ -884,7 +978,6 @@
};
struct sde_plane *psde = to_sde_plane(plane);
struct drm_device *dev = plane->dev;
- struct msm_drm_private *dev_priv = dev->dev_private;
DBG("");
@@ -894,34 +987,35 @@
}
/* range properties */
- _sde_plane_install_range_property(plane, dev, "zpos", 0, 255, 1,
- &(dev_priv->plane_property[PLANE_PROP_ZPOS]));
+ _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
+ plane->type == DRM_PLANE_TYPE_PRIMARY ?
+ STAGE_BASE : STAGE0 + drm_plane_index(plane),
+ PLANE_PROP_ZPOS);
_sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
- &(dev_priv->plane_property[PLANE_PROP_ALPHA]));
+ PLANE_PROP_ALPHA);
- _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, 0,
- &(dev_priv->plane_property[PLANE_PROP_SYNC_FENCE]));
+ _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
+ PLANE_PROP_SYNC_FENCE);
/* standard properties */
- _sde_plane_install_rotation_property(plane, dev,
- &(dev_priv->plane_property[PLANE_PROP_ROTATION]));
+ _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
/* enum/bitmask properties */
_sde_plane_install_enum_property(plane, dev, "blend_op", 0,
e_blend_op, ARRAY_SIZE(e_blend_op),
- &(dev_priv->plane_property[PLANE_PROP_BLEND_OP]));
+ PLANE_PROP_BLEND_OP);
_sde_plane_install_enum_property(plane, dev, "src_config", 1,
e_src_config, ARRAY_SIZE(e_src_config),
- &(dev_priv->plane_property[PLANE_PROP_SRC_CONFIG]));
+ PLANE_PROP_SRC_CONFIG);
/* blob properties */
if (psde->features & SDE_SSPP_SCALER)
_sde_plane_install_blob_property(plane, dev, "scaler",
- &(dev_priv->plane_property[PLANE_PROP_SCALER]));
+ PLANE_PROP_SCALER);
if (psde->features & BIT(SDE_SSPP_CSC))
_sde_plane_install_blob_property(plane, dev, "csc",
- &(dev_priv->plane_property[PLANE_PROP_CSC]));
+ PLANE_PROP_CSC);
}
static int sde_plane_atomic_set_property(struct drm_plane *plane,
@@ -941,7 +1035,7 @@
DBG("Set property %d <= %d", idx, (int)val);
pstate = to_sde_plane_state(state);
- /* extra handling for incoming blob properties */
+ /* extra handling for incoming properties */
if ((property->flags & DRM_MODE_PROP_BLOB) &&
(idx < PLANE_PROP_BLOBCOUNT)) {
/* DRM lookup also takes a reference */
@@ -961,6 +1055,8 @@
drm_property_unreference_blob(*pr_blob);
*pr_blob = blob;
}
+ } else if (idx == PLANE_PROP_SYNC_FENCE) {
+ _sde_plane_update_sync_fence(plane, pstate, val);
}
pstate->property_values[idx] = val;
ret = 0;
@@ -972,15 +1068,13 @@
static int sde_plane_set_property(struct drm_plane *plane,
struct drm_property *property, uint64_t val)
{
- int rc;
-
DBG("");
if (!plane)
return -EINVAL;
- rc = sde_plane_atomic_set_property(plane, plane->state, property, val);
- return rc;
+ return sde_plane_atomic_set_property(plane,
+ plane->state, property, val);
}
static int sde_plane_atomic_get_property(struct drm_plane *plane,
@@ -990,8 +1084,6 @@
struct sde_plane_state *pstate;
int idx, ret = -EINVAL;
- DBG("");
-
idx = _sde_plane_get_property_index(plane, property);
if (!state) {
DRM_ERROR("Invalid state\n");
@@ -1001,7 +1093,7 @@
pstate = to_sde_plane_state(state);
*val = pstate->property_values[idx];
- DBG("Get property %d %lld", idx, *val);
+ DBG("%d 0x%llX", idx, *val);
ret = 0;
}
@@ -1039,18 +1131,26 @@
DBG("");
+ if (!plane || !state) {
+ DRM_ERROR("Invalid plane/state\n");
+ return;
+ }
+
/* remove ref count for frame buffers */
if (state->fb)
drm_framebuffer_unreference(state->fb);
pstate = to_sde_plane_state(state);
+ /* remove ref count for fence */
+ if (pstate->sync_fence)
+ sde_sync_put(pstate->sync_fence);
+
/* remove ref count for blobs */
for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
if (pstate->property_blobs[i])
drm_property_unreference_blob(
pstate->property_blobs[i]);
-
kfree(pstate);
}
@@ -1063,14 +1163,23 @@
if (WARN_ON(!plane->state))
return NULL;
- DBG("");
pstate = kmemdup(to_sde_plane_state(plane->state),
sizeof(*pstate), GFP_KERNEL);
+
+ DBG("");
+
if (pstate) {
/* add ref count for frame buffer */
if (pstate->base.fb)
drm_framebuffer_reference(pstate->base.fb);
+ /* add ref count for fence */
+ if (pstate->sync_fence) {
+ pstate->sync_fence = 0;
+ _sde_plane_update_sync_fence(plane, pstate, pstate->
+ property_values[PLANE_PROP_SYNC_FENCE]);
+ }
+
/* add ref count for blobs */
for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
if (pstate->property_blobs[i])
@@ -1086,23 +1195,32 @@
static void sde_plane_reset(struct drm_plane *plane)
{
+ struct sde_plane *psde;
struct sde_plane_state *pstate;
+ int i;
DBG("");
- if (plane->state && plane->state->fb)
- drm_framebuffer_unreference(plane->state->fb);
- kfree(to_sde_plane_state(plane->state));
+ if (!plane) {
+ DRM_ERROR("Invalid plane\n");
+ return;
+ }
+
+ /* remove previous state, if present */
+ if (plane->state)
+ sde_plane_destroy_state(plane, plane->state);
+ plane->state = 0;
+
pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+ if (!pstate) {
+ DRM_ERROR("Failed to re-allocate plane state\n");
+ return;
+ }
- /* assign default blend parameters */
- pstate->property_values[PLANE_PROP_ALPHA] = 255;
-
- if (plane->type == DRM_PLANE_TYPE_PRIMARY)
- pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
- else
- pstate->property_values[PLANE_PROP_ZPOS] =
- STAGE0 + drm_plane_index(plane);
+ /* assign default property values */
+ psde = to_sde_plane(plane);
+ for (i = 0; i < PLANE_PROP_COUNT; ++i)
+ pstate->property_values[i] = psde->property_defaults[i];
pstate->base.plane = plane;