drm/msm: add generic property/state handling

Add generic atomic properties and private state structure
handling. The 'msm_property' class of helper functions capture
common code for storing local property values, handling atomic
state/property callbacks and basic blob property management.

Change-Id: I5be2d9c45d21c9d50e340036fdd7638e6b8c7ab9
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 4a34ffb..54b76721 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -64,6 +64,7 @@
 	msm_rd.o \
 	msm_ringbuffer.o \
 	msm_evtlog.o \
+	msm_prop.o \
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 msm-$(CONFIG_SYNC) += sde/sde_fence.o
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
new file mode 100644
index 0000000..23e2555
--- /dev/null
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -0,0 +1,525 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm_prop.h"
+
+void msm_property_init(struct msm_property_info *info,
+		struct drm_mode_object *base,
+		struct drm_device *dev,
+		struct drm_property **property_array,
+		struct msm_property_data *property_data,
+		uint32_t property_count,
+		uint32_t blob_count,
+		uint32_t state_size)
+{
+	/* prevent access if any of these are NULL */
+	if (!base || !dev || !property_array || !property_data) {
+		property_count = 0;
+		blob_count = 0;
+
+		DRM_ERROR("invalid arguments, forcing zero properties\n");
+		return;
+	}
+
+	/* can't have more blob properties than total properties */
+	if (blob_count > property_count) {
+		blob_count = property_count;
+
+		DBG("Capping number of blob properties to %d", blob_count);
+	}
+
+	if (!info) {
+		DRM_ERROR("info pointer is NULL\n");
+	} else {
+		info->base = base;
+		info->dev = dev;
+		info->property_array = property_array;
+		info->property_data = property_data;
+		info->property_count = property_count;
+		info->blob_count = blob_count;
+		info->install_request = 0;
+		info->install_count = 0;
+		info->recent_idx = 0;
+		info->state_size = state_size;
+		info->state_cache_size = 0;
+		mutex_init(&info->property_lock);
+
+		memset(property_data,
+				0,
+				sizeof(struct msm_property_data) *
+				property_count);
+	}
+}
+
+void msm_property_destroy(struct msm_property_info *info)
+{
+	if (!info)
+		return;
+
+	/* free state cache */
+	while (info->state_cache_size > 0)
+		kfree(info->state_cache[--(info->state_cache_size)]);
+
+	mutex_destroy(&info->property_lock);
+}
+
+void msm_property_install_range(struct msm_property_info *info,
+		const char *name, uint64_t min, uint64_t max, uint64_t init,
+		uint32_t property_idx)
+{
+	struct drm_property **prop;
+
+	if (!info)
+		return;
+
+	++info->install_request;
+
+	if (!name || (property_idx >= info->property_count)) {
+		DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
+	} else {
+		prop = &info->property_array[property_idx];
+		/*
+		 * Properties need to be attached to each drm object that
+		 * uses them, but only need to be created once
+		 */
+		if (*prop == 0) {
+			*prop = drm_property_create_range(info->dev,
+					0 /* flags */, name, min, max);
+			if (*prop == 0)
+				DRM_ERROR("create %s property failed\n", name);
+		}
+
+		/* save init value for later */
+		info->property_data[property_idx].default_value = init;
+
+		/* always attach property, if created */
+		if (*prop) {
+			drm_object_attach_property(info->base, *prop, init);
+			++info->install_count;
+		}
+	}
+}
+
+void msm_property_install_rotation(struct msm_property_info *info,
+		unsigned int supported_rotations, uint32_t property_idx)
+{
+	struct drm_property **prop;
+
+	if (!info)
+		return;
+
+	++info->install_request;
+
+	if (property_idx >= info->property_count) {
+		DRM_ERROR("invalid property index %d\n", property_idx);
+	} else {
+		prop = &info->property_array[property_idx];
+		/*
+		 * Properties need to be attached to each drm object that
+		 * uses them, but only need to be created once
+		 */
+		if (*prop == 0) {
+			*prop = drm_mode_create_rotation_property(info->dev,
+					supported_rotations);
+			if (*prop == 0)
+				DRM_ERROR("create rotation property failed\n");
+		}
+
+		/* save init value for later */
+		info->property_data[property_idx].default_value = 0;
+
+		/* always attach property, if created */
+		if (*prop) {
+			drm_object_attach_property(info->base, *prop, 0);
+			++info->install_count;
+		}
+	}
+}
+
+void msm_property_install_enum(struct msm_property_info *info,
+		const char *name, int is_bitmask,
+		const struct drm_prop_enum_list *values, int num_values,
+		uint32_t property_idx)
+{
+	struct drm_property **prop;
+
+	if (!info)
+		return;
+
+	++info->install_request;
+
+	if (!name || !values || !num_values ||
+			(property_idx >= info->property_count)) {
+		DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
+	} else {
+		prop = &info->property_array[property_idx];
+		/*
+		 * Properties need to be attached to each drm object that
+		 * uses them, but only need to be created once
+		 */
+		if (*prop == 0) {
+			/* 'bitmask' is a special type of 'enum' */
+			if (is_bitmask)
+				*prop = drm_property_create_bitmask(info->dev,
+						DRM_MODE_PROP_BITMASK, name,
+						values, num_values, -1);
+			else
+				*prop = drm_property_create_enum(info->dev,
+						DRM_MODE_PROP_ENUM, name,
+						values, num_values);
+			if (*prop == 0)
+				DRM_ERROR("create %s property failed\n", name);
+		}
+
+		/* save init value for later */
+		info->property_data[property_idx].default_value = 0;
+
+		/* always attach property, if created */
+		if (*prop) {
+			drm_object_attach_property(info->base, *prop, 0);
+			++info->install_count;
+		}
+	}
+}
+
+void msm_property_install_blob(struct msm_property_info *info,
+		const char *name, int flags, uint32_t property_idx)
+{
+	struct drm_property **prop;
+
+	if (!info)
+		return;
+
+	++info->install_request;
+
+	if (!name || (property_idx >= info->blob_count)) {
+		DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
+	} else {
+		prop = &info->property_array[property_idx];
+		/*
+		 * Properties need to be attached to each drm object that
+		 * uses them, but only need to be created once
+		 */
+		if (*prop == 0) {
+			/* use 'create' for blob property place holder */
+			*prop = drm_property_create(info->dev,
+					DRM_MODE_PROP_BLOB | flags, name, 0);
+			if (*prop == 0)
+				DRM_ERROR("create %s property failed\n", name);
+		}
+
+		/* save init value for later */
+		info->property_data[property_idx].default_value = 0;
+
+		/* always attach property, if created */
+		if (*prop) {
+			drm_object_attach_property(info->base, *prop, -1);
+			++info->install_count;
+		}
+	}
+}
+
+int msm_property_install_get_status(struct msm_property_info *info)
+{
+	int rc = -ENOMEM;
+
+	if (info && (info->install_request == info->install_count))
+		rc = 0;
+
+	return rc;
+}
+
+int msm_property_index(struct msm_property_info *info,
+		struct drm_property *property)
+{
+	uint32_t count;
+	int32_t idx;
+	int rc = -EINVAL;
+
+	if (!info || !property) {
+		DRM_ERROR("invalid argument(s)\n");
+	} else {
+		/*
+		 * Linear search, but start from last found index. This will
+		 * help if any single property is accessed multiple times in a
+		 * row. Ideally, we could keep a list of properties sorted in
+		 * the order of most recent access, but that may be overkill
+		 * for now.
+		 */
+		mutex_lock(&info->property_lock);
+		idx = info->recent_idx;
+		count = info->property_count;
+		while (count) {
+			--count;
+
+			/* stop searching on match */
+			if (info->property_array[idx] == property) {
+				info->recent_idx = idx;
+				rc = idx;
+				break;
+			}
+
+			/* move to next valid index */
+			if (--idx < 0)
+				idx = info->property_count - 1;
+		}
+		mutex_unlock(&info->property_lock);
+	}
+
+	return rc;
+}
+
+int msm_property_atomic_set(struct msm_property_info *info,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs,
+		struct drm_property *property, uint64_t val)
+{
+	struct drm_property_blob *blob;
+	int property_idx, rc = -EINVAL;
+
+	property_idx = msm_property_index(info, property);
+	if (!info || (property_idx == -EINVAL) || !property_values) {
+		DRM_ERROR("invalid argument(s)\n");
+	} else {
+		/* extra handling for incoming properties */
+		mutex_lock(&info->property_lock);
+		if ((property->flags & DRM_MODE_PROP_BLOB) &&
+			(property_idx < info->blob_count) &&
+			property_blobs) {
+			/* DRM lookup also takes a reference */
+			blob = drm_property_lookup_blob(info->dev,
+				(uint32_t)val);
+			if (!blob) {
+				DRM_ERROR("blob not found\n");
+				val = 0;
+			} else {
+				DBG("Blob %u saved", blob->base.id);
+				val = blob->base.id;
+
+				/* save blob - need to clear previous ref */
+				if (property_blobs[property_idx])
+					drm_property_unreference_blob(
+						property_blobs[property_idx]);
+				property_blobs[property_idx] = blob;
+			}
+		}
+		property_values[property_idx] = val;
+		mutex_unlock(&info->property_lock);
+		DBG("%s - %lld", property->name, val);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int msm_property_atomic_get(struct msm_property_info *info,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs,
+		struct drm_property *property, uint64_t *val)
+{
+	int property_idx, rc = -EINVAL;
+
+	property_idx = msm_property_index(info, property);
+	if (!info || (property_idx == -EINVAL) || !property_values || !val) {
+		DRM_ERROR("invalid argument(s)\n");
+	} else {
+		mutex_lock(&info->property_lock);
+		*val = property_values[property_idx];
+		mutex_unlock(&info->property_lock);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+void *msm_property_alloc_state(struct msm_property_info *info)
+{
+	void *state = NULL;
+
+	if (!info) {
+		DRM_ERROR("invalid property info\n");
+		return NULL;
+	}
+
+	mutex_lock(&info->property_lock);
+	if (info->state_cache_size)
+		state = info->state_cache[--(info->state_cache_size)];
+	mutex_unlock(&info->property_lock);
+
+	if (!state && info->state_size)
+		state = kmalloc(info->state_size, GFP_KERNEL);
+
+	if (!state)
+		DRM_ERROR("failed to allocate state\n");
+
+	return state;
+}
+
+/**
+ * _msm_property_free_state - helper function for freeing local state objects
+ * @info: Pointer to property info container struct
+ * @st: Pointer to state object
+ */
+static void _msm_property_free_state(struct msm_property_info *info, void *st)
+{
+	if (!info || !st)
+		return;
+
+	mutex_lock(&info->property_lock);
+	if (info->state_cache_size < MSM_PROP_STATE_CACHE_SIZE)
+		info->state_cache[(info->state_cache_size)++] = st;
+	else
+		kfree(st);
+	mutex_unlock(&info->property_lock);
+}
+
+void msm_property_reset_state(struct msm_property_info *info, void *state,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs)
+{
+	uint32_t i;
+
+	if (!info) {
+		DRM_ERROR("invalid property info\n");
+		return;
+	}
+
+	if (state)
+		memset(state, 0, info->state_size);
+
+	/*
+	 * Assign default property values. This helper is mostly used
+	 * to initialize newly created state objects.
+	 */
+	if (property_values)
+		for (i = 0; i < info->property_count; ++i)
+			property_values[i] =
+				info->property_data[i].default_value;
+
+	if (property_blobs)
+		for (i = 0; i < info->blob_count; ++i)
+			property_blobs[i] = 0;
+}
+
+void msm_property_duplicate_state(struct msm_property_info *info,
+		void *old_state, void *state,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs)
+{
+	uint32_t i;
+
+	if (!info || !old_state || !state) {
+		DRM_ERROR("invalid argument(s)\n");
+		return;
+	}
+
+	memcpy(state, old_state, info->state_size);
+
+	if (property_blobs) {
+		/* add ref count for blobs */
+		for (i = 0; i < info->blob_count; ++i)
+			if (property_blobs[i])
+				drm_property_reference_blob(property_blobs[i]);
+	}
+}
+
+void msm_property_destroy_state(struct msm_property_info *info, void *state,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs)
+{
+	uint32_t i;
+
+	if (!info || !state) {
+		DRM_ERROR("invalid argument(s)\n");
+		return;
+	}
+	if (property_blobs) {
+		/* remove ref count for blobs */
+		for (i = 0; i < info->blob_count; ++i)
+			if (property_blobs[i])
+				drm_property_unreference_blob(
+						property_blobs[i]);
+	}
+
+	_msm_property_free_state(info, state);
+}
+
+void *msm_property_get_blob(struct msm_property_info *info,
+		struct drm_property_blob **property_blobs,
+		size_t *byte_len,
+		uint32_t property_idx)
+{
+	struct drm_property_blob *blob;
+	size_t len = 0;
+	void *rc = 0;
+
+	if (!info || (property_idx >= info->blob_count)) {
+		DRM_ERROR("invalid argument(s)\n");
+	} else {
+		blob = property_blobs[property_idx];
+		if (blob) {
+			len = blob->length;
+			rc = &blob->data;
+		}
+	}
+
+	if (byte_len)
+		*byte_len = len;
+
+	return rc;
+}
+
+int msm_property_set_blob(struct msm_property_info *info,
+		struct drm_property_blob **blob_reference,
+		void *blob_data,
+		size_t byte_len,
+		uint32_t property_idx)
+{
+	struct drm_property_blob *blob = NULL;
+	int rc = -EINVAL;
+
+	if (!info || !blob_reference || (property_idx >= info->blob_count)) {
+		DRM_ERROR("invalid argument(s)\n");
+	} else {
+		/* create blob */
+		if (blob_data && byte_len) {
+			blob = drm_property_create_blob(info->dev,
+					byte_len,
+					blob_data);
+			if (IS_ERR_OR_NULL(blob)) {
+				rc = PTR_ERR(blob);
+				DRM_ERROR("failed to create blob, %d\n", rc);
+				goto exit;
+			}
+		}
+
+		/* update drm object */
+		rc = drm_object_property_set_value(info->base,
+				info->property_array[property_idx],
+				blob ? blob->base.id : 0);
+		if (rc) {
+			DRM_ERROR("failed to set blob to property\n");
+			if (blob)
+				drm_property_unreference_blob(blob);
+			goto exit;
+		}
+
+		/* update local reference */
+		if (*blob_reference)
+			drm_property_unreference_blob(*blob_reference);
+		*blob_reference = blob;
+	}
+
+exit:
+	return rc;
+}
+
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
new file mode 100644
index 0000000..6c59dd7
--- /dev/null
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -0,0 +1,292 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_PROP_H_
+#define _MSM_PROP_H_
+
+#include "msm_drv.h"
+
+#define MSM_PROP_STATE_CACHE_SIZE	2
+
+/**
+ * struct msm_property_data - opaque structure for tracking per
+ *                            drm-object per property stuff
+ * @default_value: Default property value for this drm object
+ */
+struct msm_property_data {
+	uint64_t default_value;
+};
+
+/**
+ * struct msm_property_info: Structure for property/state helper functions
+ * @base: Pointer to base drm object (plane/crtc/etc.)
+ * @dev: Pointer to drm device object
+ * @property_array: Pointer to array for storing created property objects
+ * @property_data: Pointer to array for storing private property data
+ * @property_count: Total number of properties
+ * @blob_count: Total number of blob properties, should be <= count
+ * @install_request: Total number of property 'install' requests
+ * @install_count: Total number of successful 'install' requests
+ * @recent_idx: Index of property most recently accessed by set/get
+ * @state_cache: Cache of local states, to prevent alloc/free thrashing
+ * @state_size: Size of local state structures
+ * @state_cache_size: Number of state structures currently stored in state_cache
+ * @property_lock: Mutex to protect local variables
+ */
+struct msm_property_info {
+	struct drm_mode_object *base;
+	struct drm_device *dev;
+
+	struct drm_property **property_array;
+	struct msm_property_data *property_data;
+	uint32_t property_count;
+	uint32_t blob_count;
+	uint32_t install_request;
+	uint32_t install_count;
+
+	int32_t recent_idx;
+
+	void *state_cache[MSM_PROP_STATE_CACHE_SIZE];
+	uint32_t state_size;
+	int32_t state_cache_size;
+	struct mutex property_lock;
+};
+
+/**
+ * msm_property_get_default - query default value of a property
+ * @info: Pointer to property info container struct
+ * @property_idx: Property index
+ * Returns: Default value for specified property
+ */
+static inline
+uint64_t msm_property_get_default(struct msm_property_info *info,
+		uint32_t property_idx)
+{
+	uint64_t rc = 0;
+
+	if (!info)
+		return 0;
+
+	mutex_lock(&info->property_lock);
+	if (property_idx < info->property_count)
+		rc = info->property_data[property_idx].default_value;
+	mutex_unlock(&info->property_lock);
+
+	return rc;
+}
+
+/**
+ * msm_property_init - initialize property info structure
+ * @info: Pointer to property info container struct
+ * @base: Pointer to base drm object (plane/crtc/etc.)
+ * @dev: Pointer to drm device object
+ * @property_array: Pointer to array for storing created property objects
+ * @property_data: Pointer to array for storing private property data
+ * @property_count: Total number of properties
+ * @blob_count: Total number of blob properties, should be <= count
+ * @state_size: Size of local state object
+ */
+void msm_property_init(struct msm_property_info *info,
+		struct drm_mode_object *base,
+		struct drm_device *dev,
+		struct drm_property **property_array,
+		struct msm_property_data *property_data,
+		uint32_t property_count,
+		uint32_t blob_count,
+		uint32_t state_size);
+
+/**
+ * msm_property_destroy - destroy helper info structure
+ *
+ * @info: Pointer to property info container struct
+ */
+void msm_property_destroy(struct msm_property_info *info);
+
+/**
+ * msm_property_install_range - install standard drm range property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default property value
+ * @property_idx: Property index
+ */
+void msm_property_install_range(struct msm_property_info *info,
+		const char *name,
+		uint64_t min,
+		uint64_t max,
+		uint64_t init,
+		uint32_t property_idx);
+
+/**
+ * msm_property_install_rotation - install standard drm rotation property
+ * @info: Pointer to property info container struct
+ * @supported_rotations: Bitmask of supported rotation values (see
+ *                       drm_mode_create_rotation_property for more details)
+ * @property_idx: Property index
+ */
+void msm_property_install_rotation(struct msm_property_info *info,
+		unsigned int supported_rotations,
+		uint32_t property_idx);
+
+/**
+ * msm_property_install_enum - install standard drm enum/bitmask property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @is_bitmask: Set to non-zero to create a bitmask property, rather than an
+ *              enumeration one
+ * @values: Array of allowable enumeration/bitmask values
+ * @num_values: Size of values array
+ * @property_idx: Property index
+ */
+void msm_property_install_enum(struct msm_property_info *info,
+		const char *name,
+		int is_bitmask,
+		const struct drm_prop_enum_list *values,
+		int num_values,
+		uint32_t property_idx);
+
+/**
+ * msm_property_install_blob - install standard drm blob property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Extra flags for property creation
+ * @property_idx: Property index
+ */
+void msm_property_install_blob(struct msm_property_info *info,
+		const char *name,
+		int flags,
+		uint32_t property_idx);
+
+/**
+ * msm_property_install_get_status - query overal status of property additions
+ * @info: Pointer to property info container struct
+ * Returns: Zero if previous property install calls were all successful
+ */
+int msm_property_install_get_status(struct msm_property_info *info);
+
+/**
+ * msm_property_index - determine property index from drm_property ptr
+ * @info: Pointer to property info container struct
+ * @property: Incoming property pointer
+ * Returns: Valid property index, or -EINVAL on error
+ */
+int msm_property_index(struct msm_property_info *info,
+		struct drm_property *property);
+
+/**
+ * msm_property_atomic_set - helper function for atomic property set callback
+ * @info: Pointer to property info container struct
+ * @property_values: Pointer to property values cache array
+ * @property_blobs: Pointer to property blobs cache array
+ * @property: Incoming property pointer
+ * @val: Incoming property value
+ * Returns: Zero on success
+ */
+int msm_property_atomic_set(struct msm_property_info *info,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs,
+		struct drm_property *property,
+		uint64_t val);
+
+/**
+ * msm_property_atomic_get - helper function for atomic property get callback
+ * @info: Pointer to property info container struct
+ * @property_values: Pointer to property values cache array
+ * @property_blobs: Pointer to property blobs cache array
+ * @property: Incoming property pointer
+ * @val: Pointer to variable for receiving property value
+ * Returns: Zero on success
+ */
+int msm_property_atomic_get(struct msm_property_info *info,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs,
+		struct drm_property *property,
+		uint64_t *val);
+
+/**
+ * msm_property_alloc_state - helper function for allocating local state objects
+ * @info: Pointer to property info container struct
+ */
+void *msm_property_alloc_state(struct msm_property_info *info);
+
+/**
+ * msm_property_reset_state - helper function for state reset callback
+ * @info: Pointer to property info container struct
+ * @state: Pointer to local state structure
+ * @property_values: Pointer to property values cache array
+ * @property_blobs: Pointer to property blobs cache array
+ */
+void msm_property_reset_state(struct msm_property_info *info,
+		void *state,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs);
+
+/**
+ * msm_property_duplicate_state - helper function for duplicate state cb
+ * @info: Pointer to property info container struct
+ * @old_state: Pointer to original state structure
+ * @state: Pointer to newly created state structure
+ * @property_values: Pointer to property values cache array
+ * @property_blobs: Pointer to property blobs cache array
+ */
+void msm_property_duplicate_state(struct msm_property_info *info,
+		void *old_state,
+		void *state,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs);
+
+/**
+ * msm_property_destroy_state - helper function for destroy state cb
+ * @info: Pointer to property info container struct
+ * @state: Pointer to local state structure
+ * @property_values: Pointer to property values cache array
+ * @property_blobs: Pointer to property blobs cache array
+ */
+void msm_property_destroy_state(struct msm_property_info *info,
+		void *state,
+		uint64_t *property_values,
+		struct drm_property_blob **property_blobs);
+
+/**
+ * msm_property_get_blob - obtain cached data pointer for drm blob property
+ * @info: Pointer to property info container struct
+ * @property_blobs: Pointer to property blobs cache array
+ * @byte_len: Optional pointer to variable for accepting blob size
+ * @property_idx: Property index
+ * Returns: Pointer to blob data
+ */
+void *msm_property_get_blob(struct msm_property_info *info,
+		struct drm_property_blob **property_blobs,
+		size_t *byte_len,
+		uint32_t property_idx);
+
+/**
+ * msm_property_set_blob - update blob property on a drm object
+ * This function updates the blob property value of the given drm object. Its
+ * intended use is to update blob properties that have been created with the
+ * DRM_MODE_PROP_IMMUTABLE flag set.
+ * @info: Pointer to property info container struct
+ * @blob_reference: Reference to a pointer that holds the created data blob
+ * @blob_data: Pointer to blob data
+ * @byte_len: Length of blob data, in bytes
+ * @property_idx: Property index
+ * Returns: Zero on success
+ */
+int msm_property_set_blob(struct msm_property_info *info,
+		struct drm_property_blob **blob_reference,
+		void *blob_data,
+		size_t byte_len,
+		uint32_t property_idx);
+
+#endif /* _MSM_PROP_H_ */
+