drm: Extract drm_plane.[hc]

Just pure code movement, cleanup and polish will happen in later
patches.

v2: Don't forget all the ioctl! To extract those cleanly I decided to
put check_src_coords into drm_framebuffer.c (and give it a
drm_framebuffer_ prefix), since that just checks framebuffer
constraints.

v3: rebase over PAGE_FLIP_TARGET.

Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>

[seanpaul]
This patch as posted on the list was rebased on:

commit 6f00975c61
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Sat Aug 20 12:22:11 2016 +0200

    drm: Reject page_flip for !DRIVER_MODESET

so as a result of moving the page_flip ioctl, this fix has
been rolled into this patch.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
This commit is contained in:
Daniel Vetter
2016-09-21 10:59:24 +02:00
committed by Sean Paul
parent ce2f2c3f82
commit 43968d7b80
9 changed files with 1681 additions and 1583 deletions

View File

@@ -44,6 +44,7 @@
#include <drm/drm_property.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
#include <drm/drm_plane.h>
struct drm_device;
struct drm_mode_set;
@@ -656,525 +657,6 @@ struct drm_crtc {
struct drm_modeset_acquire_ctx *acquire_ctx;
};
/**
* struct drm_plane_state - mutable plane state
* @plane: backpointer to the plane
* @crtc: currently bound CRTC, NULL if disabled
* @fb: currently bound framebuffer
* @fence: optional fence to wait for before scanning out @fb
* @crtc_x: left position of visible portion of plane on crtc
* @crtc_y: upper position of visible portion of plane on crtc
* @crtc_w: width of visible portion of plane on crtc
* @crtc_h: height of visible portion of plane on crtc
* @src_x: left position of visible portion of plane within
* plane (in 16.16)
* @src_y: upper position of visible portion of plane within
* plane (in 16.16)
* @src_w: width of visible portion of plane (in 16.16)
* @src_h: height of visible portion of plane (in 16.16)
* @rotation: rotation of the plane
* @zpos: priority of the given plane on crtc (optional)
* @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1
* where N is the number of active planes for given crtc
* @src: clipped source coordinates of the plane (in 16.16)
* @dst: clipped destination coordinates of the plane
* @visible: visibility of the plane
* @state: backpointer to global drm_atomic_state
*/
struct drm_plane_state {
struct drm_plane *plane;
struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */
struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */
struct fence *fence;
/* Signed dest location allows it to be partially off screen */
int32_t crtc_x, crtc_y;
uint32_t crtc_w, crtc_h;
/* Source values are 16.16 fixed point */
uint32_t src_x, src_y;
uint32_t src_h, src_w;
/* Plane rotation */
unsigned int rotation;
/* Plane zpos */
unsigned int zpos;
unsigned int normalized_zpos;
/* Clipped coordinates */
struct drm_rect src, dst;
/*
* Is the plane actually visible? Can be false even
* if fb!=NULL and crtc!=NULL, due to clipping.
*/
bool visible;
struct drm_atomic_state *state;
};
/**
* struct drm_plane_funcs - driver plane control functions
*/
struct drm_plane_funcs {
/**
* @update_plane:
*
* This is the legacy entry point to enable and configure the plane for
* the given CRTC and framebuffer. It is never called to disable the
* plane, i.e. the passed-in crtc and fb paramters are never NULL.
*
* The source rectangle in frame buffer memory coordinates is given by
* the src_x, src_y, src_w and src_h parameters (as 16.16 fixed point
* values). Devices that don't support subpixel plane coordinates can
* ignore the fractional part.
*
* The destination rectangle in CRTC coordinates is given by the
* crtc_x, crtc_y, crtc_w and crtc_h parameters (as integer values).
* Devices scale the source rectangle to the destination rectangle. If
* scaling is not supported, and the source rectangle size doesn't match
* the destination rectangle size, the driver must return a
* -<errorname>EINVAL</errorname> error.
*
* Drivers implementing atomic modeset should use
* drm_atomic_helper_update_plane() to implement this hook.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int (*update_plane)(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
/**
* @disable_plane:
*
* This is the legacy entry point to disable the plane. The DRM core
* calls this method in response to a DRM_IOCTL_MODE_SETPLANE IOCTL call
* with the frame buffer ID set to 0. Disabled planes must not be
* processed by the CRTC.
*
* Drivers implementing atomic modeset should use
* drm_atomic_helper_disable_plane() to implement this hook.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int (*disable_plane)(struct drm_plane *plane);
/**
* @destroy:
*
* Clean up plane resources. This is only called at driver unload time
* through drm_mode_config_cleanup() since a plane cannot be hotplugged
* in DRM.
*/
void (*destroy)(struct drm_plane *plane);
/**
* @reset:
*
* Reset plane 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.
*
* Atomic drivers can use drm_atomic_helper_plane_reset() to reset
* atomic state using this hook.
*/
void (*reset)(struct drm_plane *plane);
/**
* @set_property:
*
* This is the legacy entry point to update a property attached to the
* plane.
*
* Drivers implementing atomic modeset should use
* drm_atomic_helper_plane_set_property() to implement this hook.
*
* This callback is optional if the driver does not support any legacy
* driver-private properties.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int (*set_property)(struct drm_plane *plane,
struct drm_property *property, uint64_t val);
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this plane and return it.
* The core and helpers gurantee that any atomic state duplicated with
* this hook and still owned by the caller (i.e. not transferred to the
* driver by calling ->atomic_commit() from struct
* &drm_mode_config_funcs) will be cleaned up by calling the
* @atomic_destroy_state hook in this structure.
*
* Atomic drivers which don't subclass struct &drm_plane_state should use
* drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the
* state structure to extend it with driver-private state should use
* __drm_atomic_helper_plane_duplicate_state() to make sure shared state is
* duplicated in a consistent fashion across drivers.
*
* It is an error to call this hook before plane->state has been
* initialized correctly.
*
* NOTE:
*
* If the duplicate state references refcounted resources this hook must
* acquire a reference for each of them. The driver must release these
* references again in @atomic_destroy_state.
*
* RETURNS:
*
* Duplicated atomic state or NULL when the allocation failed.
*/
struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
/**
* @atomic_destroy_state:
*
* Destroy a state duplicated with @atomic_duplicate_state and release
* or unreference all resources it references
*/
void (*atomic_destroy_state)(struct drm_plane *plane,
struct drm_plane_state *state);
/**
* @atomic_set_property:
*
* Decode a driver-private property value and store the decoded value
* into the passed-in state structure. Since the atomic core decodes all
* standardized properties (even for extensions beyond the core set of
* properties which might not be implemented by all drivers) this
* requires drivers to subclass the state structure.
*
* Such driver-private properties should really only be implemented for
* truly hardware/vendor specific state. Instead it is preferred to
* standardize atomic extension and decode the properties used to expose
* such an extension in the core.
*
* Do not call this function directly, use
* drm_atomic_plane_set_property() instead.
*
* This callback is optional if the driver does not support any
* driver-private atomic properties.
*
* NOTE:
*
* This function is called in the state assembly phase of atomic
* modesets, which can be aborted for any reason (including on
* userspace's request to just check whether a configuration would be
* possible). Drivers MUST NOT touch any persistent state (hardware or
* software) or data structures except the passed in @state parameter.
*
* Also since userspace controls in which order properties are set this
* function must not do any input validation (since the state update is
* incomplete and hence likely inconsistent). Instead any such input
* validation must be done in the various atomic_check callbacks.
*
* RETURNS:
*
* 0 if the property has been found, -EINVAL if the property isn't
* implemented by the driver (which shouldn't ever happen, the core only
* asks for properties attached to this plane). No other validation is
* allowed by the driver. The core already checks that the property
* value is within the range (integer, valid enum value, ...) the driver
* set when registering the property.
*/
int (*atomic_set_property)(struct drm_plane *plane,
struct drm_plane_state *state,
struct drm_property *property,
uint64_t val);
/**
* @atomic_get_property:
*
* Reads out the decoded driver-private property. This is used to
* implement the GETPLANE IOCTL.
*
* Do not call this function directly, use
* drm_atomic_plane_get_property() instead.
*
* This callback is optional if the driver does not support any
* driver-private atomic properties.
*
* RETURNS:
*
* 0 on success, -EINVAL if the property isn't implemented by the
* driver (which should never happen, the core only asks for
* properties attached to this plane).
*/
int (*atomic_get_property)(struct drm_plane *plane,
const struct drm_plane_state *state,
struct drm_property *property,
uint64_t *val);
/**
* @late_register:
*
* This optional hook can be used to register additional userspace
* interfaces attached to the plane 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_plane *plane);
/**
* @early_unregister:
*
* This optional hook should be used to unregister the additional
* userspace interfaces attached to the plane 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_plane *plane);
};
enum drm_plane_type {
DRM_PLANE_TYPE_OVERLAY,
DRM_PLANE_TYPE_PRIMARY,
DRM_PLANE_TYPE_CURSOR,
};
/**
* struct drm_plane - central DRM plane control structure
* @dev: DRM device this plane belongs to
* @head: for list management
* @name: human readable name, can be overwritten by the driver
* @base: base mode object
* @possible_crtcs: pipes this plane can be bound to
* @format_types: array of formats supported by this plane
* @format_count: number of formats supported
* @format_default: driver hasn't supplied supported formats for the plane
* @crtc: currently bound CRTC
* @fb: currently bound fb
* @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
* drm_mode_set_config_internal() to implement correct refcounting.
* @funcs: helper functions
* @properties: property tracking for this plane
* @type: type of plane (overlay, primary, cursor)
* @state: current atomic state for this plane
* @zpos_property: zpos property for this plane
* @helper_private: mid-layer private data
*/
struct drm_plane {
struct drm_device *dev;
struct list_head head;
char *name;
/**
* @mutex:
*
* Protects modeset plane state, together with the mutex of &drm_crtc
* this plane is linked to (when active, getting actived or getting
* disabled).
*/
struct drm_modeset_lock mutex;
struct drm_mode_object base;
uint32_t possible_crtcs;
uint32_t *format_types;
unsigned int format_count;
bool format_default;
struct drm_crtc *crtc;
struct drm_framebuffer *fb;
struct drm_framebuffer *old_fb;
const struct drm_plane_funcs *funcs;
struct drm_object_properties properties;
enum drm_plane_type type;
/**
* @index: Position inside the mode_config.list, can be used as an array
* index. It is invariant over the lifetime of the plane.
*/
unsigned index;
const struct drm_plane_helper_funcs *helper_private;
struct drm_plane_state *state;
struct drm_property *zpos_property;
};
/**
* struct drm_crtc_commit - track modeset commits on a CRTC
*
* This structure is used to track pending modeset changes and atomic commit on
* a per-CRTC basis. Since updating the list should never block this structure
* is reference counted to allow waiters to safely wait on an event to complete,
* without holding any locks.
*
* It has 3 different events in total to allow a fine-grained synchronization
* between outstanding updates::
*
* atomic commit thread hardware
*
* write new state into hardware ----> ...
* signal hw_done
* switch to new state on next
* ... v/hblank
*
* wait for buffers to show up ...
*
* ... send completion irq
* irq handler signals flip_done
* cleanup old buffers
*
* signal cleanup_done
*
* wait for flip_done <----
* clean up atomic state
*
* The important bit to know is that cleanup_done is the terminal event, but the
* ordering between flip_done and hw_done is entirely up to the specific driver
* and modeset state change.
*
* For an implementation of how to use this look at
* drm_atomic_helper_setup_commit() from the atomic helper library.
*/
struct drm_crtc_commit {
/**
* @crtc:
*
* DRM CRTC for this commit.
*/
struct drm_crtc *crtc;
/**
* @ref:
*
* Reference count for this structure. Needed to allow blocking on
* completions without the risk of the completion disappearing
* meanwhile.
*/
struct kref ref;
/**
* @flip_done:
*
* Will be signaled when the hardware has flipped to the new set of
* buffers. Signals at the same time as when the drm event for this
* commit is sent to userspace, or when an out-fence is singalled. Note
* that for most hardware, in most cases this happens after @hw_done is
* signalled.
*/
struct completion flip_done;
/**
* @hw_done:
*
* Will be signalled when all hw register changes for this commit have
* been written out. Especially when disabling a pipe this can be much
* later than than @flip_done, since that can signal already when the
* screen goes black, whereas to fully shut down a pipe more register
* I/O is required.
*
* Note that this does not need to include separately reference-counted
* resources like backing storage buffer pinning, or runtime pm
* management.
*/
struct completion hw_done;
/**
* @cleanup_done:
*
* Will be signalled after old buffers have been cleaned up by calling
* drm_atomic_helper_cleanup_planes(). Since this can only happen after
* a vblank wait completed it might be a bit later. This completion is
* useful to throttle updates and avoid hardware updates getting ahead
* of the buffer cleanup too much.
*/
struct completion cleanup_done;
/**
* @commit_entry:
*
* Entry on the per-CRTC commit_list. Protected by crtc->commit_lock.
*/
struct list_head commit_entry;
/**
* @event:
*
* &drm_pending_vblank_event pointer to clean up private events.
*/
struct drm_pending_vblank_event *event;
};
struct __drm_planes_state {
struct drm_plane *ptr;
struct drm_plane_state *state;
};
struct __drm_crtcs_state {
struct drm_crtc *ptr;
struct drm_crtc_state *state;
struct drm_crtc_commit *commit;
};
struct __drm_connnectors_state {
struct drm_connector *ptr;
struct drm_connector_state *state;
};
/**
* struct drm_atomic_state - the global state object for atomic updates
* @dev: parent DRM device
* @allow_modeset: allow full modeset
* @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
* @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL.
* @planes: pointer to array of structures with per-plane data
* @crtcs: pointer to array of CRTC pointers
* @num_connector: size of the @connectors and @connector_states arrays
* @connectors: pointer to array of structures with per-connector data
* @acquire_ctx: acquire context for this atomic modeset state update
*/
struct drm_atomic_state {
struct drm_device *dev;
bool allow_modeset : 1;
bool legacy_cursor_update : 1;
bool legacy_set_config : 1;
struct __drm_planes_state *planes;
struct __drm_crtcs_state *crtcs;
int num_connector;
struct __drm_connnectors_state *connectors;
struct drm_modeset_acquire_ctx *acquire_ctx;
/**
* @commit_work:
*
* Work item which can be used by the driver or helpers to execute the
* commit without blocking.
*/
struct work_struct commit_work;
};
/**
* struct drm_mode_set - new values for a CRTC config change
* @fb: framebuffer to use for new config
@@ -1825,20 +1307,7 @@ struct drm_mode_config {
struct drm_mode_config_helper_funcs *helper_private;
};
/**
* drm_for_each_plane_mask - iterate over planes specified by bitmask
* @plane: the loop cursor
* @dev: the DRM device
* @plane_mask: bitmask of plane indices
*
* Iterate over all planes specified by bitmask.
*/
#define drm_for_each_plane_mask(plane, dev, plane_mask) \
list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
#define obj_to_plane(x) container_of(x, struct drm_plane, base)
extern __printf(6, 7)
int drm_crtc_init_with_planes(struct drm_device *dev,
@@ -1873,36 +1342,6 @@ static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc)
return 1 << drm_crtc_index(crtc);
}
extern __printf(8, 9)
int drm_universal_plane_init(struct drm_device *dev,
struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats,
unsigned int format_count,
enum drm_plane_type type,
const char *name, ...);
extern int drm_plane_init(struct drm_device *dev,
struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
bool is_primary);
extern void drm_plane_cleanup(struct drm_plane *plane);
/**
* drm_plane_index - find the index of a registered plane
* @plane: plane to find index for
*
* Given a registered plane, return the index of that plane within a DRM
* device's list of planes.
*/
static inline unsigned int drm_plane_index(struct drm_plane *plane)
{
return plane->index;
}
extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx);
extern void drm_plane_force_disable(struct drm_plane *plane);
extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
int *hdisplay, int *vdisplay);
extern int drm_crtc_force_disable(struct drm_crtc *crtc);
@@ -1924,10 +1363,6 @@ extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
extern void drm_mode_put_tile_group(struct drm_device *dev,
struct drm_tile_group *tg);
extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
struct drm_property *property,
uint64_t value);
extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
unsigned int supported_rotations);
extern unsigned int drm_rotation_simplify(unsigned int rotation,
@@ -1945,14 +1380,6 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
unsigned int zpos);
/* Helpers */
static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
uint32_t id)
{
struct drm_mode_object *mo;
mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE);
return mo ? obj_to_plane(mo) : NULL;
}
static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev,
uint32_t id)
{
@@ -1980,14 +1407,6 @@ static inline uint32_t drm_color_lut_extract(uint32_t user_input,
return clamp_val(val, 0, max);
}
/* Plane list iterator for legacy (overlay only) planes. */
#define drm_for_each_legacy_plane(plane, dev) \
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
#define drm_for_each_plane(plane, dev) \
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
#define drm_for_each_crtc(crtc, dev) \
list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head)