diff options
| -rw-r--r-- | Documentation/gpu/drm-kms.rst | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/Makefile | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 193 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_crtc_internal.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_encoder.c | 220 | ||||
| -rw-r--r-- | include/drm/drm_crtc.h | 134 | ||||
| -rw-r--r-- | include/drm/drm_encoder.h | 167 | 
7 files changed, 407 insertions, 329 deletions
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index fa948b4e029b..7f788caebea3 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -125,6 +125,15 @@ Connector Functions Reference  .. kernel-doc:: drivers/gpu/drm/drm_connector.c     :export: +Encoder Abstraction +=================== + +.. kernel-doc:: include/drm/drm_encoder.h +   :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_encoder.c +   :export: +  KMS Initialization and Cleanup  ============================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 193ff2d09479..efdb4176230f 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -13,7 +13,8 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \  		drm_trace_points.o drm_global.o drm_prime.o \  		drm_rect.o drm_vma_manager.o drm_flip_work.o \  		drm_modeset_lock.o drm_atomic.o drm_bridge.o \ -		drm_framebuffer.o drm_connector.o drm_blend.o +		drm_framebuffer.o drm_connector.o drm_blend.o \ +		drm_encoder.o  drm-$(CONFIG_COMPAT) += drm_ioc32.o  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7f2510524f09..219cd4ee23b7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -54,18 +54,6 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {  	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },  }; -static const struct drm_prop_enum_list drm_encoder_enum_list[] = { -	{ DRM_MODE_ENCODER_NONE, "None" }, -	{ DRM_MODE_ENCODER_DAC, "DAC" }, -	{ DRM_MODE_ENCODER_TMDS, "TMDS" }, -	{ DRM_MODE_ENCODER_LVDS, "LVDS" }, -	{ DRM_MODE_ENCODER_TVDAC, "TV" }, -	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, -	{ DRM_MODE_ENCODER_DSI, "DSI" }, -	{ DRM_MODE_ENCODER_DPMST, "DP MST" }, -	{ DRM_MODE_ENCODER_DPI, "DPI" }, -}; -  /*   * Optional properties   */ @@ -419,117 +407,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)  }  EXPORT_SYMBOL(drm_crtc_cleanup); -static int drm_encoder_register_all(struct drm_device *dev) -{ -	struct drm_encoder *encoder; -	int ret = 0; - -	drm_for_each_encoder(encoder, dev) { -		if (encoder->funcs->late_register) -			ret = encoder->funcs->late_register(encoder); -		if (ret) -			return ret; -	} - -	return 0; -} - -static void drm_encoder_unregister_all(struct drm_device *dev) -{ -	struct drm_encoder *encoder; - -	drm_for_each_encoder(encoder, dev) { -		if (encoder->funcs->early_unregister) -			encoder->funcs->early_unregister(encoder); -	} -} - -/** - * drm_encoder_init - Init a preallocated encoder - * @dev: drm device - * @encoder: the encoder to init - * @funcs: callbacks for this encoder - * @encoder_type: user visible type of the encoder - * @name: printf style format string for the encoder name, or NULL for default name - * - * Initialises a preallocated encoder. Encoder should be - * subclassed as part of driver encoder objects. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_encoder_init(struct drm_device *dev, -		      struct drm_encoder *encoder, -		      const struct drm_encoder_funcs *funcs, -		      int encoder_type, const char *name, ...) -{ -	int ret; - -	drm_modeset_lock_all(dev); - -	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); -	if (ret) -		goto out_unlock; - -	encoder->dev = dev; -	encoder->encoder_type = encoder_type; -	encoder->funcs = funcs; -	if (name) { -		va_list ap; - -		va_start(ap, name); -		encoder->name = kvasprintf(GFP_KERNEL, name, ap); -		va_end(ap); -	} else { -		encoder->name = kasprintf(GFP_KERNEL, "%s-%d", -					  drm_encoder_enum_list[encoder_type].name, -					  encoder->base.id); -	} -	if (!encoder->name) { -		ret = -ENOMEM; -		goto out_put; -	} - -	list_add_tail(&encoder->head, &dev->mode_config.encoder_list); -	encoder->index = dev->mode_config.num_encoder++; - -out_put: -	if (ret) -		drm_mode_object_unregister(dev, &encoder->base); - -out_unlock: -	drm_modeset_unlock_all(dev); - -	return ret; -} -EXPORT_SYMBOL(drm_encoder_init); - -/** - * drm_encoder_cleanup - cleans up an initialised encoder - * @encoder: encoder to cleanup - * - * Cleans up the encoder but doesn't free the object. - */ -void drm_encoder_cleanup(struct drm_encoder *encoder) -{ -	struct drm_device *dev = encoder->dev; - -	/* Note that the encoder_list is considered to be static; should we -	 * remove the drm_encoder at runtime we would have to decrement all -	 * the indices on the drm_encoder after us in the encoder_list. -	 */ - -	drm_modeset_lock_all(dev); -	drm_mode_object_unregister(dev, &encoder->base); -	kfree(encoder->name); -	list_del(&encoder->head); -	dev->mode_config.num_encoder--; -	drm_modeset_unlock_all(dev); - -	memset(encoder, 0, sizeof(*encoder)); -} -EXPORT_SYMBOL(drm_encoder_cleanup); -  static unsigned int drm_num_planes(struct drm_device *dev)  {  	unsigned int num = 0; @@ -1172,76 +1049,6 @@ int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,  	return 0;  } -static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) -{ -	struct drm_connector *connector; -	struct drm_device *dev = encoder->dev; -	bool uses_atomic = false; - -	/* For atomic drivers only state objects are synchronously updated and -	 * protected by modeset locks, so check those first. */ -	drm_for_each_connector(connector, dev) { -		if (!connector->state) -			continue; - -		uses_atomic = true; - -		if (connector->state->best_encoder != encoder) -			continue; - -		return connector->state->crtc; -	} - -	/* Don't return stale data (e.g. pending async disable). */ -	if (uses_atomic) -		return NULL; - -	return encoder->crtc; -} - -/** - * drm_mode_getencoder - get encoder configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Construct a encoder configuration structure to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getencoder(struct drm_device *dev, void *data, -			struct drm_file *file_priv) -{ -	struct drm_mode_get_encoder *enc_resp = data; -	struct drm_encoder *encoder; -	struct drm_crtc *crtc; - -	if (!drm_core_check_feature(dev, DRIVER_MODESET)) -		return -EINVAL; - -	encoder = drm_encoder_find(dev, enc_resp->encoder_id); -	if (!encoder) -		return -ENOENT; - -	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); -	crtc = drm_encoder_get_crtc(encoder); -	if (crtc) -		enc_resp->crtc_id = crtc->base.id; -	else -		enc_resp->crtc_id = 0; -	drm_modeset_unlock(&dev->mode_config.connection_mutex); - -	enc_resp->encoder_type = encoder->encoder_type; -	enc_resp->encoder_id = encoder->base.id; -	enc_resp->possible_crtcs = encoder->possible_crtcs; -	enc_resp->possible_clones = encoder->possible_clones; - -	return 0; -} -  /**   * drm_mode_getplane_res - enumerate all plane resources   * @dev: DRM device diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 62efb9d09a85..54f9a2c85965 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -105,8 +105,6 @@ int drm_mode_createblob_ioctl(struct drm_device *dev,  			      void *data, struct drm_file *file_priv);  int drm_mode_destroyblob_ioctl(struct drm_device *dev,  			       void *data, struct drm_file *file_priv); -int drm_mode_getencoder(struct drm_device *dev, -			void *data, struct drm_file *file_priv);  int drm_mode_gamma_get_ioctl(struct drm_device *dev,  			     void *data, struct drm_file *file_priv);  int drm_mode_gamma_set_ioctl(struct drm_device *dev, @@ -115,6 +113,14 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,  int drm_mode_page_flip_ioctl(struct drm_device *dev,  			     void *data, struct drm_file *file_priv); +/* drm_encoder.c */ +int drm_encoder_register_all(struct drm_device *dev); +void drm_encoder_unregister_all(struct drm_device *dev); + +/* IOCTL */ +int drm_mode_getencoder(struct drm_device *dev, +			void *data, struct drm_file *file_priv); +  /* drm_connector.c */  void drm_connector_ida_init(void);  void drm_connector_ida_destroy(void); diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c new file mode 100644 index 000000000000..bce781b7bb5f --- /dev/null +++ b/drivers/gpu/drm/drm_encoder.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission.  The copyright holders make no representations + * about the suitability of this software for any purpose.  It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include <drm/drmP.h> +#include <drm/drm_encoder.h> + +#include "drm_crtc_internal.h" + +static const struct drm_prop_enum_list drm_encoder_enum_list[] = { +	{ DRM_MODE_ENCODER_NONE, "None" }, +	{ DRM_MODE_ENCODER_DAC, "DAC" }, +	{ DRM_MODE_ENCODER_TMDS, "TMDS" }, +	{ DRM_MODE_ENCODER_LVDS, "LVDS" }, +	{ DRM_MODE_ENCODER_TVDAC, "TV" }, +	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, +	{ DRM_MODE_ENCODER_DSI, "DSI" }, +	{ DRM_MODE_ENCODER_DPMST, "DP MST" }, +	{ DRM_MODE_ENCODER_DPI, "DPI" }, +}; + +int drm_encoder_register_all(struct drm_device *dev) +{ +	struct drm_encoder *encoder; +	int ret = 0; + +	drm_for_each_encoder(encoder, dev) { +		if (encoder->funcs->late_register) +			ret = encoder->funcs->late_register(encoder); +		if (ret) +			return ret; +	} + +	return 0; +} + +void drm_encoder_unregister_all(struct drm_device *dev) +{ +	struct drm_encoder *encoder; + +	drm_for_each_encoder(encoder, dev) { +		if (encoder->funcs->early_unregister) +			encoder->funcs->early_unregister(encoder); +	} +} + +/** + * drm_encoder_init - Init a preallocated encoder + * @dev: drm device + * @encoder: the encoder to init + * @funcs: callbacks for this encoder + * @encoder_type: user visible type of the encoder + * @name: printf style format string for the encoder name, or NULL for default name + * + * Initialises a preallocated encoder. Encoder should be + * subclassed as part of driver encoder objects. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_encoder_init(struct drm_device *dev, +		      struct drm_encoder *encoder, +		      const struct drm_encoder_funcs *funcs, +		      int encoder_type, const char *name, ...) +{ +	int ret; + +	drm_modeset_lock_all(dev); + +	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); +	if (ret) +		goto out_unlock; + +	encoder->dev = dev; +	encoder->encoder_type = encoder_type; +	encoder->funcs = funcs; +	if (name) { +		va_list ap; + +		va_start(ap, name); +		encoder->name = kvasprintf(GFP_KERNEL, name, ap); +		va_end(ap); +	} else { +		encoder->name = kasprintf(GFP_KERNEL, "%s-%d", +					  drm_encoder_enum_list[encoder_type].name, +					  encoder->base.id); +	} +	if (!encoder->name) { +		ret = -ENOMEM; +		goto out_put; +	} + +	list_add_tail(&encoder->head, &dev->mode_config.encoder_list); +	encoder->index = dev->mode_config.num_encoder++; + +out_put: +	if (ret) +		drm_mode_object_unregister(dev, &encoder->base); + +out_unlock: +	drm_modeset_unlock_all(dev); + +	return ret; +} +EXPORT_SYMBOL(drm_encoder_init); + +/** + * drm_encoder_cleanup - cleans up an initialised encoder + * @encoder: encoder to cleanup + * + * Cleans up the encoder but doesn't free the object. + */ +void drm_encoder_cleanup(struct drm_encoder *encoder) +{ +	struct drm_device *dev = encoder->dev; + +	/* Note that the encoder_list is considered to be static; should we +	 * remove the drm_encoder at runtime we would have to decrement all +	 * the indices on the drm_encoder after us in the encoder_list. +	 */ + +	drm_modeset_lock_all(dev); +	drm_mode_object_unregister(dev, &encoder->base); +	kfree(encoder->name); +	list_del(&encoder->head); +	dev->mode_config.num_encoder--; +	drm_modeset_unlock_all(dev); + +	memset(encoder, 0, sizeof(*encoder)); +} +EXPORT_SYMBOL(drm_encoder_cleanup); + +static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) +{ +	struct drm_connector *connector; +	struct drm_device *dev = encoder->dev; +	bool uses_atomic = false; + +	/* For atomic drivers only state objects are synchronously updated and +	 * protected by modeset locks, so check those first. */ +	drm_for_each_connector(connector, dev) { +		if (!connector->state) +			continue; + +		uses_atomic = true; + +		if (connector->state->best_encoder != encoder) +			continue; + +		return connector->state->crtc; +	} + +	/* Don't return stale data (e.g. pending async disable). */ +	if (uses_atomic) +		return NULL; + +	return encoder->crtc; +} + +/** + * drm_mode_getencoder - get encoder configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Construct a encoder configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_getencoder(struct drm_device *dev, void *data, +			struct drm_file *file_priv) +{ +	struct drm_mode_get_encoder *enc_resp = data; +	struct drm_encoder *encoder; +	struct drm_crtc *crtc; + +	if (!drm_core_check_feature(dev, DRIVER_MODESET)) +		return -EINVAL; + +	encoder = drm_encoder_find(dev, enc_resp->encoder_id); +	if (!encoder) +		return -ENOENT; + +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +	crtc = drm_encoder_get_crtc(encoder); +	if (crtc) +		enc_resp->crtc_id = crtc->base.id; +	else +		enc_resp->crtc_id = 0; +	drm_modeset_unlock(&dev->mode_config.connection_mutex); + +	enc_resp->encoder_type = encoder->encoder_type; +	enc_resp->encoder_id = encoder->base.id; +	enc_resp->possible_crtcs = encoder->possible_crtcs; +	enc_resp->possible_clones = encoder->possible_clones; + +	return 0; +} diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index bb214a114329..c459867ecb9c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -40,6 +40,7 @@  #include <drm/drm_framebuffer.h>  #include <drm/drm_modes.h>  #include <drm/drm_connector.h> +#include <drm/drm_encoder.h>  struct drm_device;  struct drm_mode_set; @@ -662,97 +663,6 @@ struct drm_crtc {  };  /** - * struct drm_encoder_funcs - encoder controls - * - * Encoders sit between CRTCs and connectors. - */ -struct drm_encoder_funcs { -	/** -	 * @reset: -	 * -	 * Reset encoder hardware and software state to off. This function isn't -	 * called by the core directly, only through drm_mode_config_reset(). -	 * It's not a helper hook only for historical reasons. -	 */ -	void (*reset)(struct drm_encoder *encoder); - -	/** -	 * @destroy: -	 * -	 * Clean up encoder resources. This is only called at driver unload time -	 * through drm_mode_config_cleanup() since an encoder cannot be -	 * hotplugged in DRM. -	 */ -	void (*destroy)(struct drm_encoder *encoder); - -	/** -	 * @late_register: -	 * -	 * This optional hook can be used to register additional userspace -	 * interfaces attached to the encoder like debugfs interfaces. -	 * It is called late in the driver load sequence from drm_dev_register(). -	 * Everything added from this callback should be unregistered in -	 * the early_unregister callback. -	 * -	 * Returns: -	 * -	 * 0 on success, or a negative error code on failure. -	 */ -	int (*late_register)(struct drm_encoder *encoder); - -	/** -	 * @early_unregister: -	 * -	 * This optional hook should be used to unregister the additional -	 * userspace interfaces attached to the encoder from -	 * late_unregister(). It is called from drm_dev_unregister(), -	 * early in the driver unload sequence to disable userspace access -	 * before data structures are torndown. -	 */ -	void (*early_unregister)(struct drm_encoder *encoder); -}; - -/** - * struct drm_encoder - central DRM encoder structure - * @dev: parent DRM device - * @head: list management - * @base: base KMS object - * @name: human readable name, can be overwritten by the driver - * @encoder_type: one of the DRM_MODE_ENCODER_<foo> types in drm_mode.h - * @possible_crtcs: bitmask of potential CRTC bindings - * @possible_clones: bitmask of potential sibling encoders for cloning - * @crtc: currently bound CRTC - * @bridge: bridge associated to the encoder - * @funcs: control functions - * @helper_private: mid-layer private data - * - * CRTCs drive pixels to encoders, which convert them into signals - * appropriate for a given connector or set of connectors. - */ -struct drm_encoder { -	struct drm_device *dev; -	struct list_head head; - -	struct drm_mode_object base; -	char *name; -	int encoder_type; - -	/** -	 * @index: Position inside the mode_config.list, can be used as an array -	 * index. It is invariant over the lifetime of the encoder. -	 */ -	unsigned index; - -	uint32_t possible_crtcs; -	uint32_t possible_clones; - -	struct drm_crtc *crtc; -	struct drm_bridge *bridge; -	const struct drm_encoder_funcs *funcs; -	const struct drm_encoder_helper_funcs *helper_private; -}; - -/**   * struct drm_plane_state - mutable plane state   * @plane: backpointer to the plane   * @crtc: currently bound CRTC, NULL if disabled @@ -2114,7 +2024,6 @@ struct drm_mode_config {  		for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder)))  #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) -#define obj_to_encoder(x) container_of(x, struct drm_encoder, base)  #define obj_to_mode(x) container_of(x, struct drm_display_mode, base)  #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)  #define obj_to_property(x) container_of(x, struct drm_property, base) @@ -2159,37 +2068,6 @@ static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc)  	return 1 << drm_crtc_index(crtc);  } -extern __printf(5, 6) -int drm_encoder_init(struct drm_device *dev, -		     struct drm_encoder *encoder, -		     const struct drm_encoder_funcs *funcs, -		     int encoder_type, const char *name, ...); - -/** - * drm_encoder_index - find the index of a registered encoder - * @encoder: encoder to find index for - * - * Given a registered encoder, return the index of that encoder within a DRM - * device's list of encoders. - */ -static inline unsigned int drm_encoder_index(struct drm_encoder *encoder) -{ -	return encoder->index; -} - -/** - * drm_encoder_crtc_ok - can a given crtc drive a given encoder? - * @encoder: encoder to test - * @crtc: crtc to test - * - * Return false if @encoder can't be driven by @crtc, true otherwise. - */ -static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder, -				       struct drm_crtc *crtc) -{ -	return !!(encoder->possible_crtcs & drm_crtc_mask(crtc)); -} -  extern __printf(8, 9)  int drm_universal_plane_init(struct drm_device *dev,  			     struct drm_plane *plane, @@ -2225,8 +2103,6 @@ extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,  extern int drm_crtc_force_disable(struct drm_crtc *crtc);  extern int drm_crtc_force_disable_all(struct drm_device *dev); -extern void drm_encoder_cleanup(struct drm_encoder *encoder); -  extern void drm_mode_config_init(struct drm_device *dev);  extern void drm_mode_config_reset(struct drm_device *dev);  extern void drm_mode_config_cleanup(struct drm_device *dev); @@ -2338,14 +2214,6 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,  	return mo ? obj_to_crtc(mo) : NULL;  } -static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, -	uint32_t id) -{ -	struct drm_mode_object *mo; -	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); -	return mo ? obj_to_encoder(mo) : NULL; -} -  static inline struct drm_property *drm_property_find(struct drm_device *dev,  		uint32_t id)  { diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h new file mode 100644 index 000000000000..2712fd1a686b --- /dev/null +++ b/include/drm/drm_encoder.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission.  The copyright holders make no representations + * about the suitability of this software for any purpose.  It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_ENCODER_H__ +#define __DRM_ENCODER_H__ + +#include <linux/list.h> +#include <linux/ctype.h> +#include <drm/drm_modeset.h> + +/** + * struct drm_encoder_funcs - encoder controls + * + * Encoders sit between CRTCs and connectors. + */ +struct drm_encoder_funcs { +	/** +	 * @reset: +	 * +	 * Reset encoder hardware and software state to off. This function isn't +	 * called by the core directly, only through drm_mode_config_reset(). +	 * It's not a helper hook only for historical reasons. +	 */ +	void (*reset)(struct drm_encoder *encoder); + +	/** +	 * @destroy: +	 * +	 * Clean up encoder resources. This is only called at driver unload time +	 * through drm_mode_config_cleanup() since an encoder cannot be +	 * hotplugged in DRM. +	 */ +	void (*destroy)(struct drm_encoder *encoder); + +	/** +	 * @late_register: +	 * +	 * This optional hook can be used to register additional userspace +	 * interfaces attached to the encoder like debugfs interfaces. +	 * It is called late in the driver load sequence from drm_dev_register(). +	 * Everything added from this callback should be unregistered in +	 * the early_unregister callback. +	 * +	 * Returns: +	 * +	 * 0 on success, or a negative error code on failure. +	 */ +	int (*late_register)(struct drm_encoder *encoder); + +	/** +	 * @early_unregister: +	 * +	 * This optional hook should be used to unregister the additional +	 * userspace interfaces attached to the encoder from +	 * late_unregister(). It is called from drm_dev_unregister(), +	 * early in the driver unload sequence to disable userspace access +	 * before data structures are torndown. +	 */ +	void (*early_unregister)(struct drm_encoder *encoder); +}; + +/** + * struct drm_encoder - central DRM encoder structure + * @dev: parent DRM device + * @head: list management + * @base: base KMS object + * @name: human readable name, can be overwritten by the driver + * @encoder_type: one of the DRM_MODE_ENCODER_<foo> types in drm_mode.h + * @possible_crtcs: bitmask of potential CRTC bindings + * @possible_clones: bitmask of potential sibling encoders for cloning + * @crtc: currently bound CRTC + * @bridge: bridge associated to the encoder + * @funcs: control functions + * @helper_private: mid-layer private data + * + * CRTCs drive pixels to encoders, which convert them into signals + * appropriate for a given connector or set of connectors. + */ +struct drm_encoder { +	struct drm_device *dev; +	struct list_head head; + +	struct drm_mode_object base; +	char *name; +	int encoder_type; + +	/** +	 * @index: Position inside the mode_config.list, can be used as an array +	 * index. It is invariant over the lifetime of the encoder. +	 */ +	unsigned index; + +	uint32_t possible_crtcs; +	uint32_t possible_clones; + +	struct drm_crtc *crtc; +	struct drm_bridge *bridge; +	const struct drm_encoder_funcs *funcs; +	const struct drm_encoder_helper_funcs *helper_private; +}; + +#define obj_to_encoder(x) container_of(x, struct drm_encoder, base) + +__printf(5, 6) +int drm_encoder_init(struct drm_device *dev, +		     struct drm_encoder *encoder, +		     const struct drm_encoder_funcs *funcs, +		     int encoder_type, const char *name, ...); + +/** + * drm_encoder_index - find the index of a registered encoder + * @encoder: encoder to find index for + * + * Given a registered encoder, return the index of that encoder within a DRM + * device's list of encoders. + */ +static inline unsigned int drm_encoder_index(struct drm_encoder *encoder) +{ +	return encoder->index; +} + +/* FIXME: We have an include file mess still, drm_crtc.h needs untangling. */ +static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc); + +/** + * drm_encoder_crtc_ok - can a given crtc drive a given encoder? + * @encoder: encoder to test + * @crtc: crtc to test + * + * Return false if @encoder can't be driven by @crtc, true otherwise. + */ +static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder, +				       struct drm_crtc *crtc) +{ +	return !!(encoder->possible_crtcs & drm_crtc_mask(crtc)); +} + +static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, +	uint32_t id) +{ +	struct drm_mode_object *mo; +	mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); +	return mo ? obj_to_encoder(mo) : NULL; +} + +void drm_encoder_cleanup(struct drm_encoder *encoder); + +#endif  | 
