/* 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 <linux/list.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
 * @dirty_node: Linked list node to track if property is dirty or not
 */
struct msm_property_data {
	uint64_t default_value;
	struct list_head dirty_node;
};

/**
 * 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
 * @dirty_list: List of all properties that have been 'atomic_set' but not
 *              yet cleared with 'msm_property_pop_dirty'
 * @is_active: Whether or not drm component properties are 'active'
 * @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;

	struct list_head dirty_list;
	bool is_active;

	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_set_is_active - set overall 'active' status for all properties
 * @info: Pointer to property info container struct
 * @is_active: New 'is active' status
 */
static inline
void msm_property_set_is_active(struct msm_property_info *info, bool is_active)
{
	if (info) {
		mutex_lock(&info->property_lock);
		info->is_active = is_active;
		mutex_unlock(&info->property_lock);
	}
}

/**
 * msm_property_get_is_active - query property 'is active' status
 * @info: Pointer to property info container struct
 * Returns: Current 'is active's status
 */
static inline
bool msm_property_get_is_active(struct msm_property_info *info)
{
	bool rc = false;

	if (info) {
		mutex_lock(&info->property_lock);
		rc = info->is_active;
		mutex_unlock(&info->property_lock);
	}

	return rc;
}

/**
 * msm_property_pop_dirty - determine next dirty property and clear
 *                          its dirty flag
 * @info: Pointer to property info container struct
 * Returns: Valid msm property index on success,
 *          -EAGAIN if no dirty properties are available
 *          Property indicies returned from this function are similar
 *          to those returned by the msm_property_index function.
 */
int msm_property_pop_dirty(struct msm_property_info *info);

/**
 * 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
 * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
 * @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,
		int flags,
		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
 * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
 * @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
 * @default_value: Default value of current property
 */
void msm_property_install_enum(struct msm_property_info *info,
		const char *name,
		int flags,
		int is_bitmask,
		const struct drm_prop_enum_list *values,
		int num_values,
		uint32_t property_idx,
		uint64_t default_value);

/**
 * 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);

/**
 * msm_property_set_property - update property on a drm object
 * This function updates the property value of the given drm object. Its
 * intended use is to update properties that have been created with the
 * DRM_MODE_PROP_IMMUTABLE flag set.
 * Note: This function cannot be called on a blob.
 * @info: Pointer to property info container struct
 * @property_values: Pointer to property values cache array
 * @property_idx: Property index
 * @val: value of the property to set
 * Returns: Zero on success
 */
int msm_property_set_property(struct msm_property_info *info,
		uint64_t *property_values,
		uint32_t property_idx,
		uint64_t val);

#endif /* _MSM_PROP_H_ */

