Message ID | 1471467366-26444-1-git-send-email-daniel.vetter@ffwll.ch (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, On 08/18/2016 02:25 AM, Daniel Vetter wrote: > Same treatment as before. Only hiccup is drm_crtc_mask, which > unfortunately can't be resolved until drm_crtc.h is less of a monster. > Untangle the header loop with a forward delcaration for that static s/delcaration/declaration > inline. > > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> > --- > Documentation/gpu/drm-kms.rst | 9 ++ > drivers/gpu/drm/Makefile | 3 +- > drivers/gpu/drm/drm_crtc.c | 193 ------------------------------- > drivers/gpu/drm/drm_crtc_internal.h | 10 +- > drivers/gpu/drm/drm_encoder.c | 220 ++++++++++++++++++++++++++++++++++++ > include/drm/drm_crtc.h | 134 +--------------------- > include/drm/drm_encoder.h | 167 +++++++++++++++++++++++++++ > 7 files changed, 407 insertions(+), 329 deletions(-) > create mode 100644 drivers/gpu/drm/drm_encoder.c > create mode 100644 include/drm/drm_encoder.h > <snip> > + > +/** > + * 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, ...) Alignment with the open parentheses is needed here. > +{ > + 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 3fa0275e509f..61d81fb3c8fc 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 > @@ -2091,7 +2001,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) > @@ -2136,37 +2045,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, > @@ -2202,8 +2080,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); > @@ -2315,14 +2191,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) and here. > +{ > + struct drm_mode_object *mo; > + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); checkpatch --strict asks for a blank line above too. Otherwise: Reviewed-by: Archit Taneja <architt@codeaurora.org> Thanks, Archit > + return mo ? obj_to_encoder(mo) : NULL; > +} > + > +void drm_encoder_cleanup(struct drm_encoder *encoder); > + > +#endif >
On Thu, Aug 25, 2016 at 05:53:51PM +0530, Archit Taneja wrote: > > Hi, > > On 08/18/2016 02:25 AM, Daniel Vetter wrote: > > Same treatment as before. Only hiccup is drm_crtc_mask, which > > unfortunately can't be resolved until drm_crtc.h is less of a monster. > > Untangle the header loop with a forward delcaration for that static > > s/delcaration/declaration > > > inline. > > > > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> > > --- > > Documentation/gpu/drm-kms.rst | 9 ++ > > drivers/gpu/drm/Makefile | 3 +- > > drivers/gpu/drm/drm_crtc.c | 193 ------------------------------- > > drivers/gpu/drm/drm_crtc_internal.h | 10 +- > > drivers/gpu/drm/drm_encoder.c | 220 ++++++++++++++++++++++++++++++++++++ > > include/drm/drm_crtc.h | 134 +--------------------- > > include/drm/drm_encoder.h | 167 +++++++++++++++++++++++++++ > > 7 files changed, 407 insertions(+), 329 deletions(-) > > create mode 100644 drivers/gpu/drm/drm_encoder.c > > create mode 100644 include/drm/drm_encoder.h > > > > <snip> > > > + > > +/** > > + * 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, ...) > > Alignment with the open parentheses is needed here. > > > +{ > > + 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 3fa0275e509f..61d81fb3c8fc 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 > > @@ -2091,7 +2001,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) > > @@ -2136,37 +2045,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, > > @@ -2202,8 +2080,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); > > @@ -2315,14 +2191,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) > > and here. > > > +{ > > + struct drm_mode_object *mo; > > + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); > > checkpatch --strict asks for a blank line above too. Otherwise: > > Reviewed-by: Archit Taneja <architt@codeaurora.org> I intentionally don't reformat/touch code when moving it, at all. Ok if I just fix the typo in the commit message? -Daniel > > Thanks, > Archit > > > + return mo ? obj_to_encoder(mo) : NULL; > > +} > > + > > +void drm_encoder_cleanup(struct drm_encoder *encoder); > > + > > +#endif > > > > -- > Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, > a Linux Foundation Collaborative Project
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 8a80c1a45d13..f89711b16d3e 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; @@ -1167,76 +1044,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 97b00312a3cf..69f2b21ddad3 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 3fa0275e509f..61d81fb3c8fc 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 @@ -2091,7 +2001,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) @@ -2136,37 +2045,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, @@ -2202,8 +2080,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); @@ -2315,14 +2191,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
Same treatment as before. Only hiccup is drm_crtc_mask, which unfortunately can't be resolved until drm_crtc.h is less of a monster. Untangle the header loop with a forward delcaration for that static inline. Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> --- Documentation/gpu/drm-kms.rst | 9 ++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_crtc.c | 193 ------------------------------- drivers/gpu/drm/drm_crtc_internal.h | 10 +- drivers/gpu/drm/drm_encoder.c | 220 ++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 134 +--------------------- include/drm/drm_encoder.h | 167 +++++++++++++++++++++++++++ 7 files changed, 407 insertions(+), 329 deletions(-) create mode 100644 drivers/gpu/drm/drm_encoder.c create mode 100644 include/drm/drm_encoder.h