mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-29 21:06:41 +07:00
Merge tag 'topic/drm-misc-2016-08-31' of git://anongit.freedesktop.org/drm-intel into drm-next
More -misc stuff - moar drm_crtc.c split up&documentation - some fixes for the simple kms helpers (Andrea) - I included all the dri1 patches from David - we're not removing any code or drivers, and it seems to have worked as a wake-up call to motivate a few more people to upstream kms conversions for these. Feel free to revert if you disagree strongly. - a few other single patches * tag 'topic/drm-misc-2016-08-31' of git://anongit.freedesktop.org/drm-intel: (24 commits) drm: drm_probe_helper: Fix output_poll_work scheduling drm: bridge/dw-hdmi: Fix colorspace and scan information registers values drm/doc: Polish docs for drm_property&drm_property_blob drm: Unify handling of blob and object properties drm: Extract drm_property.[hc] drm: move drm_mode_legacy_fb_format to drm_fourcc.c drm/doc: Polish docs for drm_mode_object drm: Remove drm_mode_object->atomic_count drm: Extract drm_mode_object.[hc] drm/doc: Polish kerneldoc for encoders drm: Extract drm_encoder.[hc] drm/fb-helper: don't call remove_conflicting_framebuffers for FB=m && DRM=y drm/atomic-helper: Add NO_DISABLE_AFTER_MODESET flag support for plane commit drm/atomic-helper: Disable appropriate planes in disable_planes_on_crtc() drm/atomic-helper: Add atomic_disable CRTC helper callback drm: simple_kms_helper: add support for bridges drm: simple_kms_helper: make connector optional at init time drm/bridge: introduce bridge detaching mechanism drm/simple-helpers: Always add planes to the state update drm: reduce GETCLIENT to a minimum ...
This commit is contained in:
commit
5e7a1d0170
@ -15,6 +15,15 @@ be setup by initializing the following fields.
|
||||
- struct drm_mode_config_funcs \*funcs;
|
||||
Mode setting functions.
|
||||
|
||||
Modeset Base Object Abstraction
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mode_object.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mode_object.c
|
||||
:export:
|
||||
|
||||
KMS Data Structures
|
||||
===================
|
||||
|
||||
@ -125,6 +134,21 @@ Connector Functions Reference
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_connector.c
|
||||
:export:
|
||||
|
||||
Encoder Abstraction
|
||||
===================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_encoder.c
|
||||
:doc: overview
|
||||
|
||||
Encoder Functions Reference
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: include/drm/drm_encoder.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_encoder.c
|
||||
:export:
|
||||
|
||||
KMS Initialization and Cleanup
|
||||
==============================
|
||||
|
||||
@ -198,46 +222,6 @@ future); drivers that do not wish to provide special handling for
|
||||
primary planes may make use of the helper functions described in ? to
|
||||
create and register a primary plane with standard capabilities.
|
||||
|
||||
Encoders (:c:type:`struct drm_encoder <drm_encoder>`)
|
||||
-----------------------------------------------------
|
||||
|
||||
An encoder takes pixel data from a CRTC and converts it to a format
|
||||
suitable for any attached connectors. On some devices, it may be
|
||||
possible to have a CRTC send data to more than one encoder. In that
|
||||
case, both encoders would receive data from the same scanout buffer,
|
||||
resulting in a "cloned" display configuration across the connectors
|
||||
attached to each encoder.
|
||||
|
||||
Encoder Initialization
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As for CRTCs, a KMS driver must create, initialize and register at least
|
||||
one :c:type:`struct drm_encoder <drm_encoder>` instance. The
|
||||
instance is allocated and zeroed by the driver, possibly as part of a
|
||||
larger structure.
|
||||
|
||||
Drivers must initialize the :c:type:`struct drm_encoder
|
||||
<drm_encoder>` possible_crtcs and possible_clones fields before
|
||||
registering the encoder. Both fields are bitmasks of respectively the
|
||||
CRTCs that the encoder can be connected to, and sibling encoders
|
||||
candidate for cloning.
|
||||
|
||||
After being initialized, the encoder must be registered with a call to
|
||||
:c:func:`drm_encoder_init()`. The function takes a pointer to the
|
||||
encoder functions and an encoder type. Supported types are
|
||||
|
||||
- DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A
|
||||
- DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort
|
||||
- DRM_MODE_ENCODER_LVDS for display panels
|
||||
- DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video,
|
||||
Component, SCART)
|
||||
- DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
|
||||
|
||||
Encoders must be attached to a CRTC to be used. DRM drivers leave
|
||||
encoders unattached at initialization time. Applications (or the fbdev
|
||||
compatibility layer when implemented) are responsible for attaching the
|
||||
encoders they want to use to a CRTC.
|
||||
|
||||
Cleanup
|
||||
-------
|
||||
|
||||
@ -320,90 +304,17 @@ KMS Locking
|
||||
KMS Properties
|
||||
==============
|
||||
|
||||
Drivers may need to expose additional parameters to applications than
|
||||
those described in the previous sections. KMS supports attaching
|
||||
properties to CRTCs, connectors and planes and offers a userspace API to
|
||||
list, get and set the property values.
|
||||
Property Types and Blob Property Support
|
||||
----------------------------------------
|
||||
|
||||
Properties are identified by a name that uniquely defines the property
|
||||
purpose, and store an associated value. For all property types except
|
||||
blob properties the value is a 64-bit unsigned integer.
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_property.c
|
||||
:doc: overview
|
||||
|
||||
KMS differentiates between properties and property instances. Drivers
|
||||
first create properties and then create and associate individual
|
||||
instances of those properties to objects. A property can be instantiated
|
||||
multiple times and associated with different objects. Values are stored
|
||||
in property instances, and all other property information are stored in
|
||||
the property and shared between all instances of the property.
|
||||
.. kernel-doc:: include/drm/drm_property.h
|
||||
:internal:
|
||||
|
||||
Every property is created with a type that influences how the KMS core
|
||||
handles the property. Supported property types are
|
||||
|
||||
DRM_MODE_PROP_RANGE
|
||||
Range properties report their minimum and maximum admissible values.
|
||||
The KMS core verifies that values set by application fit in that
|
||||
range.
|
||||
|
||||
DRM_MODE_PROP_ENUM
|
||||
Enumerated properties take a numerical value that ranges from 0 to
|
||||
the number of enumerated values defined by the property minus one,
|
||||
and associate a free-formed string name to each value. Applications
|
||||
can retrieve the list of defined value-name pairs and use the
|
||||
numerical value to get and set property instance values.
|
||||
|
||||
DRM_MODE_PROP_BITMASK
|
||||
Bitmask properties are enumeration properties that additionally
|
||||
restrict all enumerated values to the 0..63 range. Bitmask property
|
||||
instance values combine one or more of the enumerated bits defined
|
||||
by the property.
|
||||
|
||||
DRM_MODE_PROP_BLOB
|
||||
Blob properties store a binary blob without any format restriction.
|
||||
The binary blobs are created as KMS standalone objects, and blob
|
||||
property instance values store the ID of their associated blob
|
||||
object.
|
||||
|
||||
Blob properties are only used for the connector EDID property and
|
||||
cannot be created by drivers.
|
||||
|
||||
To create a property drivers call one of the following functions
|
||||
depending on the property type. All property creation functions take
|
||||
property flags and name, as well as type-specific arguments.
|
||||
|
||||
- struct drm_property \*drm_property_create_range(struct
|
||||
drm_device \*dev, int flags, const char \*name, uint64_t min,
|
||||
uint64_t max);
|
||||
Create a range property with the given minimum and maximum values.
|
||||
|
||||
- struct drm_property \*drm_property_create_enum(struct drm_device
|
||||
\*dev, int flags, const char \*name, const struct
|
||||
drm_prop_enum_list \*props, int num_values);
|
||||
Create an enumerated property. The ``props`` argument points to an
|
||||
array of ``num_values`` value-name pairs.
|
||||
|
||||
- struct drm_property \*drm_property_create_bitmask(struct
|
||||
drm_device \*dev, int flags, const char \*name, const struct
|
||||
drm_prop_enum_list \*props, int num_values);
|
||||
Create a bitmask property. The ``props`` argument points to an array
|
||||
of ``num_values`` value-name pairs.
|
||||
|
||||
Properties can additionally be created as immutable, in which case they
|
||||
will be read-only for applications but can be modified by the driver. To
|
||||
create an immutable property drivers must set the
|
||||
DRM_MODE_PROP_IMMUTABLE flag at property creation time.
|
||||
|
||||
When no array of value-name pairs is readily available at property
|
||||
creation time for enumerated or range properties, drivers can create the
|
||||
property using the :c:func:`drm_property_create()` function and
|
||||
manually add enumeration value-name pairs by calling the
|
||||
:c:func:`drm_property_add_enum()` function. Care must be taken to
|
||||
properly specify the property type through the ``flags`` argument.
|
||||
|
||||
After creating properties drivers can attach property instances to CRTC,
|
||||
connector and plane objects by calling the
|
||||
:c:func:`drm_object_attach_property()`. The function takes a
|
||||
pointer to the target object, a pointer to the previously created
|
||||
property and an initial instance value.
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_property.c
|
||||
:export:
|
||||
|
||||
Blending and Z-Position properties
|
||||
----------------------------------
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _vga_switcheroo:
|
||||
|
||||
==============
|
||||
VGA Switcheroo
|
||||
==============
|
||||
|
@ -108,24 +108,8 @@ config DRM_KMS_CMA_HELPER
|
||||
|
||||
source "drivers/gpu/drm/i2c/Kconfig"
|
||||
|
||||
config DRM_TDFX
|
||||
tristate "3dfx Banshee/Voodoo3+"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
|
||||
graphics card. If M is selected, the module will be called tdfx.
|
||||
|
||||
source "drivers/gpu/drm/arm/Kconfig"
|
||||
|
||||
config DRM_R128
|
||||
tristate "ATI Rage 128"
|
||||
depends on DRM && PCI
|
||||
select FW_LOADER
|
||||
help
|
||||
Choose this option if you have an ATI Rage 128 graphics card. If M
|
||||
is selected, the module will be called r128. AGP support for
|
||||
this card is strongly suggested (unless you have a PCI version).
|
||||
|
||||
config DRM_RADEON
|
||||
tristate "ATI Radeon"
|
||||
depends on DRM && PCI
|
||||
@ -166,49 +150,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/nouveau/Kconfig"
|
||||
|
||||
config DRM_I810
|
||||
tristate "Intel I810"
|
||||
# !PREEMPT because of missing ioctl locking
|
||||
depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN)
|
||||
help
|
||||
Choose this option if you have an Intel I810 graphics card. If M is
|
||||
selected, the module will be called i810. AGP support is required
|
||||
for this driver to work.
|
||||
|
||||
source "drivers/gpu/drm/i915/Kconfig"
|
||||
|
||||
config DRM_MGA
|
||||
tristate "Matrox g200/g400"
|
||||
depends on DRM && PCI
|
||||
select FW_LOADER
|
||||
help
|
||||
Choose this option if you have a Matrox G200, G400 or G450 graphics
|
||||
card. If M is selected, the module will be called mga. AGP
|
||||
support is required for this driver to work.
|
||||
|
||||
config DRM_SIS
|
||||
tristate "SiS video cards"
|
||||
depends on DRM && AGP
|
||||
depends on FB_SIS || FB_SIS=n
|
||||
help
|
||||
Choose this option if you have a SiS 630 or compatible video
|
||||
chipset. If M is selected the module will be called sis. AGP
|
||||
support is required for this driver to work.
|
||||
|
||||
config DRM_VIA
|
||||
tristate "Via unichrome video cards"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a Via unichrome or compatible video
|
||||
chipset. If M is selected the module will be called via.
|
||||
|
||||
config DRM_SAVAGE
|
||||
tristate "Savage video cards"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
|
||||
chipset. If M is selected the module will be called savage.
|
||||
|
||||
config DRM_VGEM
|
||||
tristate "Virtual GEM provider"
|
||||
depends on DRM
|
||||
@ -279,3 +222,82 @@ source "drivers/gpu/drm/arc/Kconfig"
|
||||
source "drivers/gpu/drm/hisilicon/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/mediatek/Kconfig"
|
||||
|
||||
# Keep legacy drivers last
|
||||
|
||||
menuconfig DRM_LEGACY
|
||||
bool "Enable legacy drivers (DANGEROUS)"
|
||||
depends on DRM
|
||||
depends on BROKEN
|
||||
help
|
||||
Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
|
||||
APIs to user-space, which can be used to circumvent access
|
||||
restrictions and other security measures. For backwards compatibility
|
||||
those drivers are still available, but their use is highly
|
||||
inadvisable and might harm your system.
|
||||
|
||||
You are recommended to use the safe modeset-only drivers instead, and
|
||||
perform 3D emulation in user-space.
|
||||
|
||||
Unless you have strong reasons to go rogue, say "N".
|
||||
|
||||
if DRM_LEGACY
|
||||
|
||||
config DRM_TDFX
|
||||
tristate "3dfx Banshee/Voodoo3+"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
|
||||
graphics card. If M is selected, the module will be called tdfx.
|
||||
|
||||
config DRM_R128
|
||||
tristate "ATI Rage 128"
|
||||
depends on DRM && PCI
|
||||
select FW_LOADER
|
||||
help
|
||||
Choose this option if you have an ATI Rage 128 graphics card. If M
|
||||
is selected, the module will be called r128. AGP support for
|
||||
this card is strongly suggested (unless you have a PCI version).
|
||||
|
||||
config DRM_I810
|
||||
tristate "Intel I810"
|
||||
# !PREEMPT because of missing ioctl locking
|
||||
depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN)
|
||||
help
|
||||
Choose this option if you have an Intel I810 graphics card. If M is
|
||||
selected, the module will be called i810. AGP support is required
|
||||
for this driver to work.
|
||||
|
||||
config DRM_MGA
|
||||
tristate "Matrox g200/g400"
|
||||
depends on DRM && PCI
|
||||
select FW_LOADER
|
||||
help
|
||||
Choose this option if you have a Matrox G200, G400 or G450 graphics
|
||||
card. If M is selected, the module will be called mga. AGP
|
||||
support is required for this driver to work.
|
||||
|
||||
config DRM_SIS
|
||||
tristate "SiS video cards"
|
||||
depends on DRM && AGP
|
||||
depends on FB_SIS || FB_SIS=n
|
||||
help
|
||||
Choose this option if you have a SiS 630 or compatible video
|
||||
chipset. If M is selected the module will be called sis. AGP
|
||||
support is required for this driver to work.
|
||||
|
||||
config DRM_VIA
|
||||
tristate "Via unichrome video cards"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a Via unichrome or compatible video
|
||||
chipset. If M is selected the module will be called via.
|
||||
|
||||
config DRM_SAVAGE
|
||||
tristate "Savage video cards"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
|
||||
chipset. If M is selected the module will be called savage.
|
||||
|
||||
endif # DRM_LEGACY
|
||||
|
@ -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_mode_object.o drm_property.o
|
||||
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
|
||||
|
@ -91,7 +91,8 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(drm, state);
|
||||
drm_atomic_helper_commit_modeset_enables(drm, state);
|
||||
drm_atomic_helper_commit_planes(drm, state, true);
|
||||
drm_atomic_helper_commit_planes(drm, state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
malidp_atomic_commit_hw_done(state);
|
||||
|
||||
|
@ -457,7 +457,7 @@ atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit)
|
||||
|
||||
/* Apply the atomic update. */
|
||||
drm_atomic_helper_commit_modeset_disables(dev, old_state);
|
||||
drm_atomic_helper_commit_planes(dev, old_state, false);
|
||||
drm_atomic_helper_commit_planes(dev, old_state, 0);
|
||||
drm_atomic_helper_commit_modeset_enables(dev, old_state);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, old_state);
|
||||
|
@ -940,10 +940,11 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
*/
|
||||
|
||||
/*
|
||||
* AVI data byte 1 differences: Colorspace in bits 4,5 rather than 5,6,
|
||||
* active aspect present in bit 6 rather than 4.
|
||||
* AVI data byte 1 differences: Colorspace in bits 0,1 rather than 5,6,
|
||||
* scan info in bits 4,5 rather than 0,1 and active aspect present in
|
||||
* bit 6 rather than 4.
|
||||
*/
|
||||
val = (frame.colorspace & 3) << 4 | (frame.scan_mode & 0x3);
|
||||
val = (frame.scan_mode & 3) << 4 | (frame.colorspace & 3);
|
||||
if (frame.active_aspect & 15)
|
||||
val |= HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT;
|
||||
if (frame.top_bar || frame.bottom_bar)
|
||||
|
@ -749,6 +749,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
|
||||
/* Right function depends upon target state. */
|
||||
if (crtc->state->enable && funcs->prepare)
|
||||
funcs->prepare(crtc);
|
||||
else if (funcs->atomic_disable)
|
||||
funcs->atomic_disable(crtc, old_crtc_state);
|
||||
else if (funcs->disable)
|
||||
funcs->disable(crtc);
|
||||
else
|
||||
@ -1146,7 +1148,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
|
||||
*
|
||||
* drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
*
|
||||
* drm_atomic_helper_commit_planes(dev, state, true);
|
||||
* drm_atomic_helper_commit_planes(dev, state,
|
||||
* DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
*
|
||||
* for committing the atomic update to hardware. See the kerneldoc entries for
|
||||
* these three functions for more details.
|
||||
@ -1157,7 +1160,7 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, false);
|
||||
drm_atomic_helper_commit_planes(dev, state, 0);
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
|
||||
@ -1676,7 +1679,7 @@ bool plane_crtc_active(struct drm_plane_state *state)
|
||||
* drm_atomic_helper_commit_planes - commit plane state
|
||||
* @dev: DRM device
|
||||
* @old_state: atomic state object with old state structures
|
||||
* @active_only: Only commit on active CRTC if set
|
||||
* @flags: flags for committing plane state
|
||||
*
|
||||
* This function commits the new plane state using the plane and atomic helper
|
||||
* functions for planes and crtcs. It assumes that the atomic state has already
|
||||
@ -1696,25 +1699,34 @@ bool plane_crtc_active(struct drm_plane_state *state)
|
||||
* most drivers don't need to be immediately notified of plane updates for a
|
||||
* disabled CRTC.
|
||||
*
|
||||
* Unless otherwise needed, drivers are advised to set the @active_only
|
||||
* parameters to true in order not to receive plane update notifications related
|
||||
* to a disabled CRTC. This avoids the need to manually ignore plane updates in
|
||||
* Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in
|
||||
* @flags in order not to receive plane update notifications related to a
|
||||
* disabled CRTC. This avoids the need to manually ignore plane updates in
|
||||
* driver code when the driver and/or hardware can't or just don't need to deal
|
||||
* with updates on disabled CRTCs, for example when supporting runtime PM.
|
||||
*
|
||||
* The drm_atomic_helper_commit() default implementation only sets @active_only
|
||||
* to false to most closely match the behaviour of the legacy helpers. This should
|
||||
* not be copied blindly by drivers.
|
||||
* Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant
|
||||
* display controllers require to disable a CRTC's planes when the CRTC is
|
||||
* disabled. This function would skip the ->atomic_disable call for a plane if
|
||||
* the CRTC of the old plane state needs a modesetting operation. Of course,
|
||||
* the drivers need to disable the planes in their CRTC disable callbacks
|
||||
* since no one else would do that.
|
||||
*
|
||||
* The drm_atomic_helper_commit() default implementation doesn't set the
|
||||
* ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers.
|
||||
* This should not be copied blindly by drivers.
|
||||
*/
|
||||
void drm_atomic_helper_commit_planes(struct drm_device *dev,
|
||||
struct drm_atomic_state *old_state,
|
||||
bool active_only)
|
||||
uint32_t flags)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
struct drm_plane *plane;
|
||||
struct drm_plane_state *old_plane_state;
|
||||
int i;
|
||||
bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY;
|
||||
bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET;
|
||||
|
||||
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
|
||||
const struct drm_crtc_helper_funcs *funcs;
|
||||
@ -1758,10 +1770,19 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
|
||||
/*
|
||||
* Special-case disabling the plane if drivers support it.
|
||||
*/
|
||||
if (disabling && funcs->atomic_disable)
|
||||
if (disabling && funcs->atomic_disable) {
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
crtc_state = old_plane_state->crtc->state;
|
||||
|
||||
if (drm_atomic_crtc_needs_modeset(crtc_state) &&
|
||||
no_disable)
|
||||
continue;
|
||||
|
||||
funcs->atomic_disable(plane, old_plane_state);
|
||||
else if (plane->state->crtc || disabling)
|
||||
} else if (plane->state->crtc || disabling) {
|
||||
funcs->atomic_update(plane, old_plane_state);
|
||||
}
|
||||
}
|
||||
|
||||
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
|
||||
@ -1840,12 +1861,12 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
|
||||
* @crtc: CRTC
|
||||
* @old_crtc_state: atomic state object with the old CRTC state
|
||||
* @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
|
||||
*
|
||||
* Disables all planes associated with the given CRTC. This can be
|
||||
* used for instance in the CRTC helper disable callback to disable
|
||||
* all planes before shutting down the display pipeline.
|
||||
* used for instance in the CRTC helper atomic_disable callback to disable
|
||||
* all planes.
|
||||
*
|
||||
* If the atomic-parameter is set the function calls the CRTC's
|
||||
* atomic_begin hook before and atomic_flush hook after disabling the
|
||||
@ -1854,9 +1875,11 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
|
||||
* It is a bug to call this function without having implemented the
|
||||
* ->atomic_disable() plane hook.
|
||||
*/
|
||||
void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
|
||||
bool atomic)
|
||||
void
|
||||
drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
|
||||
bool atomic)
|
||||
{
|
||||
struct drm_crtc *crtc = old_crtc_state->crtc;
|
||||
const struct drm_crtc_helper_funcs *crtc_funcs =
|
||||
crtc->helper_private;
|
||||
struct drm_plane *plane;
|
||||
@ -1864,11 +1887,11 @@ void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
|
||||
if (atomic && crtc_funcs && crtc_funcs->atomic_begin)
|
||||
crtc_funcs->atomic_begin(crtc, NULL);
|
||||
|
||||
drm_for_each_plane(plane, crtc->dev) {
|
||||
drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
|
||||
const struct drm_plane_helper_funcs *plane_funcs =
|
||||
plane->helper_private;
|
||||
|
||||
if (plane->state->crtc != crtc || !plane_funcs)
|
||||
if (!plane_funcs)
|
||||
continue;
|
||||
|
||||
WARN_ON(!plane_funcs->atomic_disable);
|
||||
|
@ -98,11 +98,11 @@ EXPORT_SYMBOL(drm_bridge_remove);
|
||||
* @dev: DRM device
|
||||
* @bridge: bridge control structure
|
||||
*
|
||||
* called by a kms driver to link one of our encoder/bridge to the given
|
||||
* Called by a kms driver to link one of our encoder/bridge to the given
|
||||
* bridge.
|
||||
*
|
||||
* Note that setting up links between the bridge and our encoder/bridge
|
||||
* objects needs to be handled by the kms driver itself
|
||||
* objects needs to be handled by the kms driver itself.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, error code on failure
|
||||
@ -124,6 +124,31 @@ int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_attach);
|
||||
|
||||
/**
|
||||
* drm_bridge_detach - deassociate given bridge from its DRM device
|
||||
*
|
||||
* @bridge: bridge control structure
|
||||
*
|
||||
* Called by a kms driver to unlink the given bridge from its DRM device.
|
||||
*
|
||||
* Note that tearing down links between the bridge and our encoder/bridge
|
||||
* objects needs to be handled by the kms driver itself.
|
||||
*/
|
||||
void drm_bridge_detach(struct drm_bridge *bridge)
|
||||
{
|
||||
if (WARN_ON(!bridge))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!bridge->dev))
|
||||
return;
|
||||
|
||||
if (bridge->funcs->detach)
|
||||
bridge->funcs->detach(bridge);
|
||||
|
||||
bridge->dev = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_detach);
|
||||
|
||||
/**
|
||||
* DOC: bridge callbacks
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,71 @@
|
||||
|
||||
|
||||
/* drm_crtc.c */
|
||||
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t value);
|
||||
int drm_plane_check_pixel_format(const struct drm_plane *plane,
|
||||
u32 format);
|
||||
int drm_crtc_check_viewport(const struct drm_crtc *crtc,
|
||||
int x, int y,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_framebuffer *fb);
|
||||
|
||||
void drm_fb_release(struct drm_file *file_priv);
|
||||
|
||||
/* dumb buffer support IOCTLs */
|
||||
int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
/* IOCTLs */
|
||||
int drm_mode_getresources(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int drm_mode_getcrtc(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_setcrtc(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getplane(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_setplane(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_cursor_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_cursor2_ioctl(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,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
/* drm_property.c */
|
||||
void drm_property_destroy_user_blobs(struct drm_device *dev,
|
||||
struct drm_file *file_priv);
|
||||
bool drm_property_change_valid_get(struct drm_property *property,
|
||||
uint64_t value,
|
||||
struct drm_mode_object **ref);
|
||||
void drm_property_change_valid_put(struct drm_property *property,
|
||||
struct drm_mode_object *ref);
|
||||
|
||||
/* IOCTL */
|
||||
int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getblob_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
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);
|
||||
|
||||
/* drm_mode_object.c */
|
||||
int drm_mode_object_get_reg(struct drm_device *dev,
|
||||
struct drm_mode_object *obj,
|
||||
uint32_t obj_type,
|
||||
@ -50,70 +115,21 @@ int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
|
||||
uint32_t __user *prop_ptr,
|
||||
uint64_t __user *prop_values,
|
||||
uint32_t *arg_count_props);
|
||||
bool drm_property_change_valid_get(struct drm_property *property,
|
||||
uint64_t value,
|
||||
struct drm_mode_object **ref);
|
||||
void drm_property_change_valid_put(struct drm_property *property,
|
||||
struct drm_mode_object *ref);
|
||||
|
||||
int drm_plane_check_pixel_format(const struct drm_plane *plane,
|
||||
u32 format);
|
||||
int drm_crtc_check_viewport(const struct drm_crtc *crtc,
|
||||
int x, int y,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_framebuffer *fb);
|
||||
/* IOCTL */
|
||||
|
||||
void drm_fb_release(struct drm_file *file_priv);
|
||||
void drm_property_destroy_user_blobs(struct drm_device *dev,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* dumb buffer support IOCTLs */
|
||||
int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
/* IOCTLs */
|
||||
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
int drm_mode_getresources(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int drm_mode_getcrtc(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_setcrtc(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getplane(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_setplane(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_cursor_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_cursor2_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
int drm_mode_getblob_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
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);
|
||||
/* 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);
|
||||
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,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
/* drm_connector.c */
|
||||
void drm_connector_ida_init(void);
|
||||
|
232
drivers/gpu/drm/drm_encoder.c
Normal file
232
drivers/gpu/drm/drm_encoder.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
*
|
||||
* Encoders represent the connecting element between the CRTC (as the overall
|
||||
* pixel pipeline, represented by struct &drm_crtc) and the connectors (as the
|
||||
* generic sink entity, represented by struct &drm_connector). Encoders are
|
||||
* objects exposed to userspace, originally to allow userspace to infer cloning
|
||||
* and connector/CRTC restrictions. Unfortunately almost all drivers get this
|
||||
* wrong, making the uabi pretty much useless. On top of that the exposed
|
||||
* restrictions are too simple for todays hardware, and the recommend way to
|
||||
* infer restrictions is by using the DRM_MODE_ATOMIC_TEST_ONLY flag for the
|
||||
* atomic IOCTL.
|
||||
*
|
||||
* Otherwise encoders aren't used in the uapi at all (any modeset request from
|
||||
* userspace directly connects a connector with a CRTC), drivers are therefore
|
||||
* free to use them however they wish. Modeset helper libraries make strong use
|
||||
* of encoders to facilitate code sharing. But for more complex settings it is
|
||||
* usually better to move shared code into a separate &drm_bridge. Compared to
|
||||
* encoders bridges also have the benefit of not being purely an internal
|
||||
* abstraction since they are not exposed to userspace at all.
|
||||
*
|
||||
* Encoders are initialized with drm_encoder_init() and cleaned up using
|
||||
* drm_encoder_cleanup().
|
||||
*/
|
||||
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. At driver unload time drm_encoder_cleanup() should be
|
||||
* called from the driver's destroy hook in &drm_encoder_funcs.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
@ -35,6 +35,49 @@ static char printable_char(int c)
|
||||
return isascii(c) && isprint(c) ? c : '?';
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
|
||||
* @bpp: bits per pixels
|
||||
* @depth: bit depth per pixel
|
||||
*
|
||||
* Computes a drm fourcc pixel format code for the given @bpp/@depth values.
|
||||
* Useful in fbdev emulation code, since that deals in those values.
|
||||
*/
|
||||
uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
|
||||
{
|
||||
uint32_t fmt;
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
fmt = DRM_FORMAT_C8;
|
||||
break;
|
||||
case 16:
|
||||
if (depth == 15)
|
||||
fmt = DRM_FORMAT_XRGB1555;
|
||||
else
|
||||
fmt = DRM_FORMAT_RGB565;
|
||||
break;
|
||||
case 24:
|
||||
fmt = DRM_FORMAT_RGB888;
|
||||
break;
|
||||
case 32:
|
||||
if (depth == 24)
|
||||
fmt = DRM_FORMAT_XRGB8888;
|
||||
else if (depth == 30)
|
||||
fmt = DRM_FORMAT_XRGB2101010;
|
||||
else
|
||||
fmt = DRM_FORMAT_ARGB8888;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
|
||||
fmt = DRM_FORMAT_XRGB8888;
|
||||
break;
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_legacy_fb_format);
|
||||
|
||||
/**
|
||||
* drm_get_format_name - return a string for drm fourcc format
|
||||
* @format: format to compute name of
|
||||
|
@ -189,9 +189,8 @@ static int drm_getclient(struct drm_device *dev, void *data,
|
||||
*/
|
||||
if (client->idx == 0) {
|
||||
client->auth = file_priv->authenticated;
|
||||
client->pid = pid_vnr(file_priv->pid);
|
||||
client->uid = from_kuid_munged(current_user_ns(),
|
||||
file_priv->uid);
|
||||
client->pid = task_pid_vnr(current);
|
||||
client->uid = overflowuid;
|
||||
client->magic = 0;
|
||||
client->iocs = 0;
|
||||
|
||||
|
437
drivers/gpu/drm/drm_mode_object.c
Normal file
437
drivers/gpu/drm/drm_mode_object.c
Normal file
@ -0,0 +1,437 @@
|
||||
/*
|
||||
* 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_mode_object.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
|
||||
/*
|
||||
* Internal function to assign a slot in the object idr and optionally
|
||||
* register the object into the idr.
|
||||
*/
|
||||
int drm_mode_object_get_reg(struct drm_device *dev,
|
||||
struct drm_mode_object *obj,
|
||||
uint32_t obj_type,
|
||||
bool register_obj,
|
||||
void (*obj_free_cb)(struct kref *kref))
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
|
||||
if (ret >= 0) {
|
||||
/*
|
||||
* Set up the object linking under the protection of the idr
|
||||
* lock so that other users can't see inconsistent state.
|
||||
*/
|
||||
obj->id = ret;
|
||||
obj->type = obj_type;
|
||||
if (obj_free_cb) {
|
||||
obj->free_cb = obj_free_cb;
|
||||
kref_init(&obj->refcount);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_object_get - allocate a new modeset identifier
|
||||
* @dev: DRM device
|
||||
* @obj: object pointer, used to generate unique ID
|
||||
* @obj_type: object type
|
||||
*
|
||||
* Create a unique identifier based on @ptr in @dev's identifier space. Used
|
||||
* for tracking modes, CRTCs and connectors. Note that despite the _get postfix
|
||||
* modeset identifiers are _not_ reference counted. Hence don't use this for
|
||||
* reference counted modeset objects like framebuffers.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_mode_object_get(struct drm_device *dev,
|
||||
struct drm_mode_object *obj, uint32_t obj_type)
|
||||
{
|
||||
return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL);
|
||||
}
|
||||
|
||||
void drm_mode_object_register(struct drm_device *dev,
|
||||
struct drm_mode_object *obj)
|
||||
{
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
|
||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_object_unregister - free a modeset identifer
|
||||
* @dev: DRM device
|
||||
* @object: object to free
|
||||
*
|
||||
* Free @id from @dev's unique identifier pool.
|
||||
* This function can be called multiple times, and guards against
|
||||
* multiple removals.
|
||||
* These modeset identifiers are _not_ reference counted. Hence don't use this
|
||||
* for reference counted modeset objects like framebuffers.
|
||||
*/
|
||||
void drm_mode_object_unregister(struct drm_device *dev,
|
||||
struct drm_mode_object *object)
|
||||
{
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
if (object->id) {
|
||||
idr_remove(&dev->mode_config.crtc_idr, object->id);
|
||||
object->id = 0;
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
}
|
||||
|
||||
struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
|
||||
uint32_t id, uint32_t type)
|
||||
{
|
||||
struct drm_mode_object *obj = NULL;
|
||||
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
obj = idr_find(&dev->mode_config.crtc_idr, id);
|
||||
if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
|
||||
obj = NULL;
|
||||
if (obj && obj->id != id)
|
||||
obj = NULL;
|
||||
|
||||
if (obj && obj->free_cb) {
|
||||
if (!kref_get_unless_zero(&obj->refcount))
|
||||
obj = NULL;
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_object_find - look up a drm object with static lifetime
|
||||
* @dev: drm device
|
||||
* @id: id of the mode object
|
||||
* @type: type of the mode object
|
||||
*
|
||||
* This function is used to look up a modeset object. It will acquire a
|
||||
* reference for reference counted objects. This reference must be dropped again
|
||||
* by callind drm_mode_object_unreference().
|
||||
*/
|
||||
struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
|
||||
uint32_t id, uint32_t type)
|
||||
{
|
||||
struct drm_mode_object *obj = NULL;
|
||||
|
||||
obj = __drm_mode_object_find(dev, id, type);
|
||||
return obj;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_object_find);
|
||||
|
||||
/**
|
||||
* drm_mode_object_unreference - decr the object refcnt
|
||||
* @obj: mode_object
|
||||
*
|
||||
* This function decrements the object's refcount if it is a refcounted modeset
|
||||
* object. It is a no-op on any other object. This is used to drop references
|
||||
* acquired with drm_mode_object_reference().
|
||||
*/
|
||||
void drm_mode_object_unreference(struct drm_mode_object *obj)
|
||||
{
|
||||
if (obj->free_cb) {
|
||||
DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
|
||||
kref_put(&obj->refcount, obj->free_cb);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_object_unreference);
|
||||
|
||||
/**
|
||||
* drm_mode_object_reference - incr the object refcnt
|
||||
* @obj: mode_object
|
||||
*
|
||||
* This function increments the object's refcount if it is a refcounted modeset
|
||||
* object. It is a no-op on any other object. References should be dropped again
|
||||
* by calling drm_mode_object_unreference().
|
||||
*/
|
||||
void drm_mode_object_reference(struct drm_mode_object *obj)
|
||||
{
|
||||
if (obj->free_cb) {
|
||||
DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
|
||||
kref_get(&obj->refcount);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_object_reference);
|
||||
|
||||
/**
|
||||
* drm_object_attach_property - attach a property to a modeset object
|
||||
* @obj: drm modeset object
|
||||
* @property: property to attach
|
||||
* @init_val: initial value of the property
|
||||
*
|
||||
* This attaches the given property to the modeset object with the given initial
|
||||
* value. Currently this function cannot fail since the properties are stored in
|
||||
* a statically sized array.
|
||||
*/
|
||||
void drm_object_attach_property(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t init_val)
|
||||
{
|
||||
int count = obj->properties->count;
|
||||
|
||||
if (count == DRM_OBJECT_MAX_PROPERTY) {
|
||||
WARN(1, "Failed to attach object property (type: 0x%x). Please "
|
||||
"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
|
||||
"you see this message on the same object type.\n",
|
||||
obj->type);
|
||||
return;
|
||||
}
|
||||
|
||||
obj->properties->properties[count] = property;
|
||||
obj->properties->values[count] = init_val;
|
||||
obj->properties->count++;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_object_attach_property);
|
||||
|
||||
/**
|
||||
* drm_object_property_set_value - set the value of a property
|
||||
* @obj: drm mode object to set property value for
|
||||
* @property: property to set
|
||||
* @val: value the property should be set to
|
||||
*
|
||||
* This function sets a given property on a given object. This function only
|
||||
* changes the software state of the property, it does not call into the
|
||||
* driver's ->set_property callback.
|
||||
*
|
||||
* Note that atomic drivers should not have any need to call this, the core will
|
||||
* ensure consistency of values reported back to userspace through the
|
||||
* appropriate ->atomic_get_property callback. Only legacy drivers should call
|
||||
* this function to update the tracked value (after clamping and other
|
||||
* restrictions have been applied).
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_object_property_set_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property, uint64_t val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < obj->properties->count; i++) {
|
||||
if (obj->properties->properties[i] == property) {
|
||||
obj->properties->values[i] = val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_object_property_set_value);
|
||||
|
||||
/**
|
||||
* drm_object_property_get_value - retrieve the value of a property
|
||||
* @obj: drm mode object to get property value from
|
||||
* @property: property to retrieve
|
||||
* @val: storage for the property value
|
||||
*
|
||||
* This function retrieves the softare state of the given property for the given
|
||||
* property. Since there is no driver callback to retrieve the current property
|
||||
* value this might be out of sync with the hardware, depending upon the driver
|
||||
* and property.
|
||||
*
|
||||
* Atomic drivers should never call this function directly, the core will read
|
||||
* out property values through the various ->atomic_get_property callbacks.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property, uint64_t *val)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* read-only properties bypass atomic mechanism and still store
|
||||
* their value in obj->properties->values[].. mostly to avoid
|
||||
* having to deal w/ EDID and similar props in atomic paths:
|
||||
*/
|
||||
if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
|
||||
!(property->flags & DRM_MODE_PROP_IMMUTABLE))
|
||||
return drm_atomic_get_property(obj, property, val);
|
||||
|
||||
for (i = 0; i < obj->properties->count; i++) {
|
||||
if (obj->properties->properties[i] == property) {
|
||||
*val = obj->properties->values[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_object_property_get_value);
|
||||
|
||||
/* helper for getconnector and getproperties ioctls */
|
||||
int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
|
||||
uint32_t __user *prop_ptr,
|
||||
uint64_t __user *prop_values,
|
||||
uint32_t *arg_count_props)
|
||||
{
|
||||
int i, ret, count;
|
||||
|
||||
for (i = 0, count = 0; i < obj->properties->count; i++) {
|
||||
struct drm_property *prop = obj->properties->properties[i];
|
||||
uint64_t val;
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
|
||||
continue;
|
||||
|
||||
if (*arg_count_props > count) {
|
||||
ret = drm_object_property_get_value(obj, prop, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (put_user(prop->base.id, prop_ptr + count))
|
||||
return -EFAULT;
|
||||
|
||||
if (put_user(val, prop_values + count))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
*arg_count_props = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_obj_get_properties_ioctl - get the current value of a object's property
|
||||
* @dev: DRM device
|
||||
* @data: ioctl data
|
||||
* @file_priv: DRM file info
|
||||
*
|
||||
* This function retrieves the current value for an object's property. Compared
|
||||
* to the connector specific ioctl this one is extended to also work on crtc and
|
||||
* plane objects.
|
||||
*
|
||||
* Called by the user via ioctl.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_obj_get_properties *arg = data;
|
||||
struct drm_mode_object *obj;
|
||||
int ret = 0;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
|
||||
if (!obj) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (!obj->properties) {
|
||||
ret = -EINVAL;
|
||||
goto out_unref;
|
||||
}
|
||||
|
||||
ret = drm_mode_object_get_properties(obj, file_priv->atomic,
|
||||
(uint32_t __user *)(unsigned long)(arg->props_ptr),
|
||||
(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
|
||||
&arg->count_props);
|
||||
|
||||
out_unref:
|
||||
drm_mode_object_unreference(obj);
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_obj_set_property *arg = data;
|
||||
struct drm_mode_object *arg_obj;
|
||||
struct drm_mode_object *prop_obj;
|
||||
struct drm_property *property;
|
||||
int i, ret = -EINVAL;
|
||||
struct drm_mode_object *ref;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
|
||||
if (!arg_obj) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (!arg_obj->properties)
|
||||
goto out_unref;
|
||||
|
||||
for (i = 0; i < arg_obj->properties->count; i++)
|
||||
if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
|
||||
break;
|
||||
|
||||
if (i == arg_obj->properties->count)
|
||||
goto out_unref;
|
||||
|
||||
prop_obj = drm_mode_object_find(dev, arg->prop_id,
|
||||
DRM_MODE_OBJECT_PROPERTY);
|
||||
if (!prop_obj) {
|
||||
ret = -ENOENT;
|
||||
goto out_unref;
|
||||
}
|
||||
property = obj_to_property(prop_obj);
|
||||
|
||||
if (!drm_property_change_valid_get(property, arg->value, &ref))
|
||||
goto out_unref;
|
||||
|
||||
switch (arg_obj->type) {
|
||||
case DRM_MODE_OBJECT_CONNECTOR:
|
||||
ret = drm_mode_connector_set_obj_prop(arg_obj, property,
|
||||
arg->value);
|
||||
break;
|
||||
case DRM_MODE_OBJECT_CRTC:
|
||||
ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
|
||||
break;
|
||||
case DRM_MODE_OBJECT_PLANE:
|
||||
ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
|
||||
property, arg->value);
|
||||
break;
|
||||
}
|
||||
|
||||
drm_property_change_valid_put(property, ref);
|
||||
|
||||
out_unref:
|
||||
drm_mode_object_unreference(arg_obj);
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
@ -129,6 +129,7 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
|
||||
{
|
||||
bool poll = false;
|
||||
struct drm_connector *connector;
|
||||
unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
|
||||
@ -141,8 +142,13 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
|
||||
poll = true;
|
||||
}
|
||||
|
||||
if (dev->mode_config.delayed_event) {
|
||||
poll = true;
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
if (poll)
|
||||
schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
|
||||
schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked);
|
||||
|
||||
|
899
drivers/gpu/drm/drm_property.c
Normal file
899
drivers/gpu/drm/drm_property.c
Normal file
@ -0,0 +1,899 @@
|
||||
/*
|
||||
* 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_property.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
*
|
||||
* Properties as represented by &drm_property are used to extend the modeset
|
||||
* interface exposed to userspace. For the atomic modeset IOCTL properties are
|
||||
* even the only way to transport metadata about the desired new modeset
|
||||
* configuration from userspace to the kernel. Properties have a well-defined
|
||||
* value range, which is enforced by the drm core. See the documentation of the
|
||||
* flags member of struct &drm_property for an overview of the different
|
||||
* property types and ranges.
|
||||
*
|
||||
* Properties don't store the current value directly, but need to be
|
||||
* instatiated by attaching them to a &drm_mode_object with
|
||||
* drm_object_attach_property().
|
||||
*
|
||||
* Property values are only 64bit. To support bigger piles of data (like gamma
|
||||
* tables, color correction matrizes or large structures) a property can instead
|
||||
* point at a &drm_property_blob with that additional data
|
||||
*
|
||||
* Properties are defined by their symbolic name, userspace must keep a
|
||||
* per-object mapping from those names to the property ID used in the atomic
|
||||
* IOCTL and in the get/set property IOCTL.
|
||||
*/
|
||||
|
||||
static bool drm_property_type_valid(struct drm_property *property)
|
||||
{
|
||||
if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
|
||||
return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
|
||||
return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_property_create - create a new property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @num_values: number of pre-defined values
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
||||
const char *name, int num_values)
|
||||
{
|
||||
struct drm_property *property = NULL;
|
||||
int ret;
|
||||
|
||||
property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
property->dev = dev;
|
||||
|
||||
if (num_values) {
|
||||
property->values = kcalloc(num_values, sizeof(uint64_t),
|
||||
GFP_KERNEL);
|
||||
if (!property->values)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
property->flags = flags;
|
||||
property->num_values = num_values;
|
||||
INIT_LIST_HEAD(&property->enum_list);
|
||||
|
||||
if (name) {
|
||||
strncpy(property->name, name, DRM_PROP_NAME_LEN);
|
||||
property->name[DRM_PROP_NAME_LEN-1] = '\0';
|
||||
}
|
||||
|
||||
list_add_tail(&property->head, &dev->mode_config.property_list);
|
||||
|
||||
WARN_ON(!drm_property_type_valid(property));
|
||||
|
||||
return property;
|
||||
fail:
|
||||
kfree(property->values);
|
||||
kfree(property);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create);
|
||||
|
||||
/**
|
||||
* drm_property_create_enum - create a new enumeration property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @props: enumeration lists with property values
|
||||
* @num_values: number of pre-defined values
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* Userspace is only allowed to set one of the predefined values for enumeration
|
||||
* properties.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_values)
|
||||
{
|
||||
struct drm_property *property;
|
||||
int i, ret;
|
||||
|
||||
flags |= DRM_MODE_PROP_ENUM;
|
||||
|
||||
property = drm_property_create(dev, flags, name, num_values);
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < num_values; i++) {
|
||||
ret = drm_property_add_enum(property, i,
|
||||
props[i].type,
|
||||
props[i].name);
|
||||
if (ret) {
|
||||
drm_property_destroy(dev, property);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_enum);
|
||||
|
||||
/**
|
||||
* drm_property_create_bitmask - create a new bitmask property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @props: enumeration lists with property bitflags
|
||||
* @num_props: size of the @props array
|
||||
* @supported_bits: bitmask of all supported enumeration values
|
||||
*
|
||||
* This creates a new bitmask drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* Compared to plain enumeration properties userspace is allowed to set any
|
||||
* or'ed together combination of the predefined property bitflag values
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_props,
|
||||
uint64_t supported_bits)
|
||||
{
|
||||
struct drm_property *property;
|
||||
int i, ret, index = 0;
|
||||
int num_values = hweight64(supported_bits);
|
||||
|
||||
flags |= DRM_MODE_PROP_BITMASK;
|
||||
|
||||
property = drm_property_create(dev, flags, name, num_values);
|
||||
if (!property)
|
||||
return NULL;
|
||||
for (i = 0; i < num_props; i++) {
|
||||
if (!(supported_bits & (1ULL << props[i].type)))
|
||||
continue;
|
||||
|
||||
if (WARN_ON(index >= num_values)) {
|
||||
drm_property_destroy(dev, property);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = drm_property_add_enum(property, index++,
|
||||
props[i].type,
|
||||
props[i].name);
|
||||
if (ret) {
|
||||
drm_property_destroy(dev, property);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_bitmask);
|
||||
|
||||
static struct drm_property *property_create_range(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
uint64_t min, uint64_t max)
|
||||
{
|
||||
struct drm_property *property;
|
||||
|
||||
property = drm_property_create(dev, flags, name, 2);
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
property->values[0] = min;
|
||||
property->values[1] = max;
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_property_create_range - create a new unsigned ranged property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @min: minimum value of the property
|
||||
* @max: maximum value of the property
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* Userspace is allowed to set any unsigned integer value in the (min, max)
|
||||
* range inclusive.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
uint64_t min, uint64_t max)
|
||||
{
|
||||
return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
|
||||
name, min, max);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_range);
|
||||
|
||||
/**
|
||||
* drm_property_create_signed_range - create a new signed ranged property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @min: minimum value of the property
|
||||
* @max: maximum value of the property
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* Userspace is allowed to set any signed integer value in the (min, max)
|
||||
* range inclusive.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
int64_t min, int64_t max)
|
||||
{
|
||||
return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
|
||||
name, I642U64(min), I642U64(max));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_signed_range);
|
||||
|
||||
/**
|
||||
* drm_property_create_object - create a new object property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @type: object type from DRM_MODE_OBJECT_* defines
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* Userspace is only allowed to set this to any property value of the given
|
||||
* @type. Only useful for atomic properties, which is enforced.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create_object(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
uint32_t type)
|
||||
{
|
||||
struct drm_property *property;
|
||||
|
||||
flags |= DRM_MODE_PROP_OBJECT;
|
||||
|
||||
if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
|
||||
return NULL;
|
||||
|
||||
property = drm_property_create(dev, flags, name, 1);
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
property->values[0] = type;
|
||||
|
||||
return property;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_object);
|
||||
|
||||
/**
|
||||
* drm_property_create_bool - create a new boolean property type
|
||||
* @dev: drm device
|
||||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* object with drm_object_attach_property. The returned property object must be
|
||||
* freed with drm_property_destroy(), which is done automatically when calling
|
||||
* drm_mode_config_cleanup().
|
||||
*
|
||||
* This is implemented as a ranged property with only {0, 1} as valid values.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the newly created property on success, NULL on failure.
|
||||
*/
|
||||
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
|
||||
const char *name)
|
||||
{
|
||||
return drm_property_create_range(dev, flags, name, 0, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_bool);
|
||||
|
||||
/**
|
||||
* drm_property_add_enum - add a possible value to an enumeration property
|
||||
* @property: enumeration property to change
|
||||
* @index: index of the new enumeration
|
||||
* @value: value of the new enumeration
|
||||
* @name: symbolic name of the new enumeration
|
||||
*
|
||||
* This functions adds enumerations to a property.
|
||||
*
|
||||
* It's use is deprecated, drivers should use one of the more specific helpers
|
||||
* to directly create the property with all enumerations already attached.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_property_add_enum(struct drm_property *property, int index,
|
||||
uint64_t value, const char *name)
|
||||
{
|
||||
struct drm_property_enum *prop_enum;
|
||||
|
||||
if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
|
||||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Bitmask enum properties have the additional constraint of values
|
||||
* from 0 to 63
|
||||
*/
|
||||
if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
|
||||
(value > 63))
|
||||
return -EINVAL;
|
||||
|
||||
if (!list_empty(&property->enum_list)) {
|
||||
list_for_each_entry(prop_enum, &property->enum_list, head) {
|
||||
if (prop_enum->value == value) {
|
||||
strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
|
||||
prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
|
||||
if (!prop_enum)
|
||||
return -ENOMEM;
|
||||
|
||||
strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
|
||||
prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
|
||||
prop_enum->value = value;
|
||||
|
||||
property->values[index] = value;
|
||||
list_add_tail(&prop_enum->head, &property->enum_list);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_add_enum);
|
||||
|
||||
/**
|
||||
* drm_property_destroy - destroy a drm property
|
||||
* @dev: drm device
|
||||
* @property: property to destry
|
||||
*
|
||||
* This function frees a property including any attached resources like
|
||||
* enumeration values.
|
||||
*/
|
||||
void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
|
||||
{
|
||||
struct drm_property_enum *prop_enum, *pt;
|
||||
|
||||
list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
|
||||
list_del(&prop_enum->head);
|
||||
kfree(prop_enum);
|
||||
}
|
||||
|
||||
if (property->num_values)
|
||||
kfree(property->values);
|
||||
drm_mode_object_unregister(dev, &property->base);
|
||||
list_del(&property->head);
|
||||
kfree(property);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_destroy);
|
||||
|
||||
int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_get_property *out_resp = data;
|
||||
struct drm_property *property;
|
||||
int enum_count = 0;
|
||||
int value_count = 0;
|
||||
int ret = 0, i;
|
||||
int copied;
|
||||
struct drm_property_enum *prop_enum;
|
||||
struct drm_mode_property_enum __user *enum_ptr;
|
||||
uint64_t __user *values_ptr;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
property = drm_property_find(dev, out_resp->prop_id);
|
||||
if (!property) {
|
||||
ret = -ENOENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
|
||||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
|
||||
list_for_each_entry(prop_enum, &property->enum_list, head)
|
||||
enum_count++;
|
||||
}
|
||||
|
||||
value_count = property->num_values;
|
||||
|
||||
strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
|
||||
out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
|
||||
out_resp->flags = property->flags;
|
||||
|
||||
if ((out_resp->count_values >= value_count) && value_count) {
|
||||
values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
|
||||
for (i = 0; i < value_count; i++) {
|
||||
if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
|
||||
ret = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
out_resp->count_values = value_count;
|
||||
|
||||
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
|
||||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
|
||||
if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
|
||||
copied = 0;
|
||||
enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
|
||||
list_for_each_entry(prop_enum, &property->enum_list, head) {
|
||||
|
||||
if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
|
||||
ret = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (copy_to_user(&enum_ptr[copied].name,
|
||||
&prop_enum->name, DRM_PROP_NAME_LEN)) {
|
||||
ret = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
copied++;
|
||||
}
|
||||
}
|
||||
out_resp->count_enum_blobs = enum_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: The idea seems to have been to use this to read all the blob
|
||||
* property values. But nothing ever added them to the corresponding
|
||||
* list, userspace always used the special-purpose get_blob ioctl to
|
||||
* read the value for a blob property. It also doesn't make a lot of
|
||||
* sense to return values here when everything else is just metadata for
|
||||
* the property itself.
|
||||
*/
|
||||
if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
|
||||
out_resp->count_enum_blobs = 0;
|
||||
done:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void drm_property_free_blob(struct kref *kref)
|
||||
{
|
||||
struct drm_property_blob *blob =
|
||||
container_of(kref, struct drm_property_blob, base.refcount);
|
||||
|
||||
mutex_lock(&blob->dev->mode_config.blob_lock);
|
||||
list_del(&blob->head_global);
|
||||
mutex_unlock(&blob->dev->mode_config.blob_lock);
|
||||
|
||||
drm_mode_object_unregister(blob->dev, &blob->base);
|
||||
|
||||
kfree(blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_property_create_blob - Create new blob property
|
||||
* @dev: DRM device to create property for
|
||||
* @length: Length to allocate for blob data
|
||||
* @data: If specified, copies data into blob
|
||||
*
|
||||
* Creates a new blob property for a specified DRM device, optionally
|
||||
* copying data. Note that blob properties are meant to be invariant, hence the
|
||||
* data must be filled out before the blob is used as the value of any property.
|
||||
*
|
||||
* Returns:
|
||||
* New blob property with a single reference on success, or an ERR_PTR
|
||||
* value on failure.
|
||||
*/
|
||||
struct drm_property_blob *
|
||||
drm_property_create_blob(struct drm_device *dev, size_t length,
|
||||
const void *data)
|
||||
{
|
||||
struct drm_property_blob *blob;
|
||||
int ret;
|
||||
|
||||
if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
|
||||
if (!blob)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* This must be explicitly initialised, so we can safely call list_del
|
||||
* on it in the removal handler, even if it isn't in a file list. */
|
||||
INIT_LIST_HEAD(&blob->head_file);
|
||||
blob->length = length;
|
||||
blob->dev = dev;
|
||||
|
||||
if (data)
|
||||
memcpy(blob->data, data, length);
|
||||
|
||||
ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
|
||||
true, drm_property_free_blob);
|
||||
if (ret) {
|
||||
kfree(blob);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mode_config.blob_lock);
|
||||
list_add_tail(&blob->head_global,
|
||||
&dev->mode_config.property_blob_list);
|
||||
mutex_unlock(&dev->mode_config.blob_lock);
|
||||
|
||||
return blob;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_blob);
|
||||
|
||||
/**
|
||||
* drm_property_unreference_blob - Unreference a blob property
|
||||
* @blob: Pointer to blob property
|
||||
*
|
||||
* Drop a reference on a blob property. May free the object.
|
||||
*/
|
||||
void drm_property_unreference_blob(struct drm_property_blob *blob)
|
||||
{
|
||||
if (!blob)
|
||||
return;
|
||||
|
||||
drm_mode_object_unreference(&blob->base);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_unreference_blob);
|
||||
|
||||
void drm_property_destroy_user_blobs(struct drm_device *dev,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_property_blob *blob, *bt;
|
||||
|
||||
/*
|
||||
* When the file gets released that means no one else can access the
|
||||
* blob list any more, so no need to grab dev->blob_lock.
|
||||
*/
|
||||
list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
|
||||
list_del_init(&blob->head_file);
|
||||
drm_property_unreference_blob(blob);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_property_reference_blob - Take a reference on an existing property
|
||||
* @blob: Pointer to blob property
|
||||
*
|
||||
* Take a new reference on an existing blob property. Returns @blob, which
|
||||
* allows this to be used as a shorthand in assignments.
|
||||
*/
|
||||
struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob)
|
||||
{
|
||||
drm_mode_object_reference(&blob->base);
|
||||
return blob;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_reference_blob);
|
||||
|
||||
/**
|
||||
* drm_property_lookup_blob - look up a blob property and take a reference
|
||||
* @dev: drm device
|
||||
* @id: id of the blob property
|
||||
*
|
||||
* If successful, this takes an additional reference to the blob property.
|
||||
* callers need to make sure to eventually unreference the returned property
|
||||
* again, using @drm_property_unreference_blob.
|
||||
*
|
||||
* Return:
|
||||
* NULL on failure, pointer to the blob on success.
|
||||
*/
|
||||
struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
|
||||
uint32_t id)
|
||||
{
|
||||
struct drm_mode_object *obj;
|
||||
struct drm_property_blob *blob = NULL;
|
||||
|
||||
obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB);
|
||||
if (obj)
|
||||
blob = obj_to_blob(obj);
|
||||
return blob;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_lookup_blob);
|
||||
|
||||
/**
|
||||
* drm_property_replace_global_blob - replace existing blob property
|
||||
* @dev: drm device
|
||||
* @replace: location of blob property pointer to be replaced
|
||||
* @length: length of data for new blob, or 0 for no data
|
||||
* @data: content for new blob, or NULL for no data
|
||||
* @obj_holds_id: optional object for property holding blob ID
|
||||
* @prop_holds_id: optional property holding blob ID
|
||||
* @return 0 on success or error on failure
|
||||
*
|
||||
* This function will replace a global property in the blob list, optionally
|
||||
* updating a property which holds the ID of that property.
|
||||
*
|
||||
* If length is 0 or data is NULL, no new blob will be created, and the holding
|
||||
* property, if specified, will be set to 0.
|
||||
*
|
||||
* Access to the replace pointer is assumed to be protected by the caller, e.g.
|
||||
* by holding the relevant modesetting object lock for its parent.
|
||||
*
|
||||
* For example, a drm_connector has a 'PATH' property, which contains the ID
|
||||
* of a blob property with the value of the MST path information. Calling this
|
||||
* function with replace pointing to the connector's path_blob_ptr, length and
|
||||
* data set for the new path information, obj_holds_id set to the connector's
|
||||
* base object, and prop_holds_id set to the path property name, will perform
|
||||
* a completely atomic update. The access to path_blob_ptr is protected by the
|
||||
* caller holding a lock on the connector.
|
||||
*/
|
||||
int drm_property_replace_global_blob(struct drm_device *dev,
|
||||
struct drm_property_blob **replace,
|
||||
size_t length,
|
||||
const void *data,
|
||||
struct drm_mode_object *obj_holds_id,
|
||||
struct drm_property *prop_holds_id)
|
||||
{
|
||||
struct drm_property_blob *new_blob = NULL;
|
||||
struct drm_property_blob *old_blob = NULL;
|
||||
int ret;
|
||||
|
||||
WARN_ON(replace == NULL);
|
||||
|
||||
old_blob = *replace;
|
||||
|
||||
if (length && data) {
|
||||
new_blob = drm_property_create_blob(dev, length, data);
|
||||
if (IS_ERR(new_blob))
|
||||
return PTR_ERR(new_blob);
|
||||
}
|
||||
|
||||
if (obj_holds_id) {
|
||||
ret = drm_object_property_set_value(obj_holds_id,
|
||||
prop_holds_id,
|
||||
new_blob ?
|
||||
new_blob->base.id : 0);
|
||||
if (ret != 0)
|
||||
goto err_created;
|
||||
}
|
||||
|
||||
drm_property_unreference_blob(old_blob);
|
||||
*replace = new_blob;
|
||||
|
||||
return 0;
|
||||
|
||||
err_created:
|
||||
drm_property_unreference_blob(new_blob);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_replace_global_blob);
|
||||
|
||||
int drm_mode_getblob_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_get_blob *out_resp = data;
|
||||
struct drm_property_blob *blob;
|
||||
int ret = 0;
|
||||
void __user *blob_ptr;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
blob = drm_property_lookup_blob(dev, out_resp->blob_id);
|
||||
if (!blob)
|
||||
return -ENOENT;
|
||||
|
||||
if (out_resp->length == blob->length) {
|
||||
blob_ptr = (void __user *)(unsigned long)out_resp->data;
|
||||
if (copy_to_user(blob_ptr, blob->data, blob->length)) {
|
||||
ret = -EFAULT;
|
||||
goto unref;
|
||||
}
|
||||
}
|
||||
out_resp->length = blob->length;
|
||||
unref:
|
||||
drm_property_unreference_blob(blob);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int drm_mode_createblob_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_create_blob *out_resp = data;
|
||||
struct drm_property_blob *blob;
|
||||
void __user *blob_ptr;
|
||||
int ret = 0;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
blob = drm_property_create_blob(dev, out_resp->length, NULL);
|
||||
if (IS_ERR(blob))
|
||||
return PTR_ERR(blob);
|
||||
|
||||
blob_ptr = (void __user *)(unsigned long)out_resp->data;
|
||||
if (copy_from_user(blob->data, blob_ptr, out_resp->length)) {
|
||||
ret = -EFAULT;
|
||||
goto out_blob;
|
||||
}
|
||||
|
||||
/* Dropping the lock between create_blob and our access here is safe
|
||||
* as only the same file_priv can remove the blob; at this point, it is
|
||||
* not associated with any file_priv. */
|
||||
mutex_lock(&dev->mode_config.blob_lock);
|
||||
out_resp->blob_id = blob->base.id;
|
||||
list_add_tail(&blob->head_file, &file_priv->blobs);
|
||||
mutex_unlock(&dev->mode_config.blob_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
out_blob:
|
||||
drm_property_unreference_blob(blob);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int drm_mode_destroyblob_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_destroy_blob *out_resp = data;
|
||||
struct drm_property_blob *blob = NULL, *bt;
|
||||
bool found = false;
|
||||
int ret = 0;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
blob = drm_property_lookup_blob(dev, out_resp->blob_id);
|
||||
if (!blob)
|
||||
return -ENOENT;
|
||||
|
||||
mutex_lock(&dev->mode_config.blob_lock);
|
||||
/* Ensure the property was actually created by this user. */
|
||||
list_for_each_entry(bt, &file_priv->blobs, head_file) {
|
||||
if (bt == blob) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ret = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We must drop head_file here, because we may not be the last
|
||||
* reference on the blob. */
|
||||
list_del_init(&blob->head_file);
|
||||
mutex_unlock(&dev->mode_config.blob_lock);
|
||||
|
||||
/* One reference from lookup, and one from the filp. */
|
||||
drm_property_unreference_blob(blob);
|
||||
drm_property_unreference_blob(blob);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_unlock(&dev->mode_config.blob_lock);
|
||||
drm_property_unreference_blob(blob);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Some properties could refer to dynamic refcnt'd objects, or things that
|
||||
* need special locking to handle lifetime issues (ie. to ensure the prop
|
||||
* value doesn't become invalid part way through the property update due to
|
||||
* race). The value returned by reference via 'obj' should be passed back
|
||||
* to drm_property_change_valid_put() after the property is set (and the
|
||||
* object to which the property is attached has a chance to take it's own
|
||||
* reference).
|
||||
*/
|
||||
bool drm_property_change_valid_get(struct drm_property *property,
|
||||
uint64_t value, struct drm_mode_object **ref)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (property->flags & DRM_MODE_PROP_IMMUTABLE)
|
||||
return false;
|
||||
|
||||
*ref = NULL;
|
||||
|
||||
if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
|
||||
if (value < property->values[0] || value > property->values[1])
|
||||
return false;
|
||||
return true;
|
||||
} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
|
||||
int64_t svalue = U642I64(value);
|
||||
|
||||
if (svalue < U642I64(property->values[0]) ||
|
||||
svalue > U642I64(property->values[1]))
|
||||
return false;
|
||||
return true;
|
||||
} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
|
||||
uint64_t valid_mask = 0;
|
||||
|
||||
for (i = 0; i < property->num_values; i++)
|
||||
valid_mask |= (1ULL << property->values[i]);
|
||||
return !(value & ~valid_mask);
|
||||
} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB) ||
|
||||
drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
|
||||
/* a zero value for an object property translates to null: */
|
||||
if (value == 0)
|
||||
return true;
|
||||
|
||||
*ref = __drm_mode_object_find(property->dev, value,
|
||||
property->values[0]);
|
||||
return *ref != NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < property->num_values; i++)
|
||||
if (property->values[i] == value)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void drm_property_change_valid_put(struct drm_property *property,
|
||||
struct drm_mode_object *ref)
|
||||
{
|
||||
if (!ref)
|
||||
return;
|
||||
|
||||
if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT) ||
|
||||
drm_property_type_is(property, DRM_MODE_PROP_BLOB))
|
||||
drm_mode_object_unreference(ref);
|
||||
}
|
@ -34,6 +34,12 @@ static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
return drm_atomic_add_affected_planes(state->state, crtc);
|
||||
}
|
||||
|
||||
static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_simple_display_pipe *pipe;
|
||||
@ -57,6 +63,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc)
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
|
||||
.atomic_check = drm_simple_kms_crtc_check,
|
||||
.disable = drm_simple_kms_crtc_disable,
|
||||
.enable = drm_simple_kms_crtc_enable,
|
||||
};
|
||||
@ -132,6 +139,46 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
|
||||
* @pipe: simple display pipe object
|
||||
* @bridge: bridge to attach
|
||||
*
|
||||
* Makes it possible to still use the drm_simple_display_pipe helpers when
|
||||
* a DRM bridge has to be used.
|
||||
*
|
||||
* Note that you probably want to initialize the pipe by passing a NULL
|
||||
* connector to drm_simple_display_pipe_init().
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code on failure.
|
||||
*/
|
||||
int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
bridge->encoder = &pipe->encoder;
|
||||
pipe->encoder.bridge = bridge;
|
||||
return drm_bridge_attach(pipe->encoder.dev, bridge);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
|
||||
|
||||
/**
|
||||
* drm_simple_display_pipe_detach_bridge - Detach the bridge from the display pipe
|
||||
* @pipe: simple display pipe object
|
||||
*
|
||||
* Detaches the drm bridge previously attached with
|
||||
* drm_simple_display_pipe_attach_bridge()
|
||||
*/
|
||||
void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe *pipe)
|
||||
{
|
||||
if (WARN_ON(!pipe->encoder.bridge))
|
||||
return;
|
||||
|
||||
drm_bridge_detach(pipe->encoder.bridge);
|
||||
pipe->encoder.bridge = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_simple_display_pipe_detach_bridge);
|
||||
|
||||
/**
|
||||
* drm_simple_display_pipe_init - Initialize a simple display pipeline
|
||||
* @dev: DRM device
|
||||
@ -139,10 +186,15 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
|
||||
* @funcs: callbacks for the display pipe (optional)
|
||||
* @formats: array of supported formats (DRM_FORMAT\_\*)
|
||||
* @format_count: number of elements in @formats
|
||||
* @connector: connector to attach and register
|
||||
* @connector: connector to attach and register (optional)
|
||||
*
|
||||
* Sets up a display pipeline which consist of a really simple
|
||||
* plane-crtc-encoder pipe coupled with the provided connector.
|
||||
* plane-crtc-encoder pipe.
|
||||
*
|
||||
* If a connector is supplied, the pipe will be coupled with the provided
|
||||
* connector. You may supply a NULL connector when using drm bridges, that
|
||||
* handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
|
||||
*
|
||||
* Teardown of a simple display pipe is all handled automatically by the drm
|
||||
* core through calling drm_mode_config_cleanup(). Drivers afterwards need to
|
||||
* release the memory for the structure themselves.
|
||||
@ -181,7 +233,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev,
|
||||
encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
|
||||
ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs,
|
||||
DRM_MODE_ENCODER_NONE, NULL);
|
||||
if (ret)
|
||||
if (ret || !connector)
|
||||
return ret;
|
||||
|
||||
return drm_mode_connector_attach_encoder(connector, encoder);
|
||||
|
@ -105,7 +105,7 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
|
||||
atomic_inc(&exynos_crtc->pending_update);
|
||||
}
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, false);
|
||||
drm_atomic_helper_commit_planes(dev, state, 0);
|
||||
|
||||
exynos_atomic_wait_for_commit(state);
|
||||
|
||||
|
@ -163,10 +163,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||
if (bclp > 255)
|
||||
return ASLE_BACKLIGHT_FAILED;
|
||||
|
||||
if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) {
|
||||
int max = bd->props.max_brightness;
|
||||
gma_backlight_set(dev, bclp * max / 255);
|
||||
}
|
||||
gma_backlight_set(dev, bclp * bd->props.max_brightness / 255);
|
||||
|
||||
asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;
|
||||
|
||||
|
@ -193,7 +193,8 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, true);
|
||||
drm_atomic_helper_commit_planes(dev, state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
|
||||
|
@ -70,13 +70,15 @@ static void mtk_atomic_complete(struct mtk_drm_private *private,
|
||||
*
|
||||
* drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
* drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
* drm_atomic_helper_commit_planes(dev, state, true);
|
||||
* drm_atomic_helper_commit_planes(dev, state,
|
||||
* DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
*
|
||||
* See the kerneldoc entries for these three functions for more details.
|
||||
*/
|
||||
drm_atomic_helper_commit_modeset_disables(drm, state);
|
||||
drm_atomic_helper_commit_modeset_enables(drm, state);
|
||||
drm_atomic_helper_commit_planes(drm, state, true);
|
||||
drm_atomic_helper_commit_planes(drm, state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(drm, state);
|
||||
|
||||
|
@ -118,7 +118,7 @@ static void complete_commit(struct msm_commit *c, bool async)
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, false);
|
||||
drm_atomic_helper_commit_planes(dev, state, 0);
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
|
||||
|
@ -96,7 +96,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
|
||||
dispc_runtime_get();
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, old_state);
|
||||
drm_atomic_helper_commit_planes(dev, old_state, false);
|
||||
drm_atomic_helper_commit_planes(dev, old_state, 0);
|
||||
drm_atomic_helper_commit_modeset_enables(dev, old_state);
|
||||
|
||||
omap_atomic_wait_for_completion(dev, old_state);
|
||||
|
@ -257,7 +257,8 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit)
|
||||
/* Apply the atomic update. */
|
||||
drm_atomic_helper_commit_modeset_disables(dev, old_state);
|
||||
drm_atomic_helper_commit_modeset_enables(dev, old_state);
|
||||
drm_atomic_helper_commit_planes(dev, old_state, true);
|
||||
drm_atomic_helper_commit_planes(dev, old_state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, old_state);
|
||||
|
||||
|
@ -245,7 +245,8 @@ rockchip_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, true);
|
||||
drm_atomic_helper_commit_planes(dev, state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
drm_atomic_helper_commit_hw_done(state);
|
||||
|
||||
|
@ -178,7 +178,7 @@ static void sti_atomic_complete(struct sti_private *private,
|
||||
*/
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(drm, state);
|
||||
drm_atomic_helper_commit_planes(drm, state, false);
|
||||
drm_atomic_helper_commit_planes(drm, state, 0);
|
||||
drm_atomic_helper_commit_modeset_enables(drm, state);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(drm, state);
|
||||
|
@ -57,7 +57,8 @@ static void tegra_atomic_complete(struct tegra_drm *tegra,
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(drm, state);
|
||||
drm_atomic_helper_commit_modeset_enables(drm, state);
|
||||
drm_atomic_helper_commit_planes(drm, state, true);
|
||||
drm_atomic_helper_commit_planes(drm, state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(drm, state);
|
||||
|
||||
|
@ -118,7 +118,7 @@ static int tilcdc_commit(struct drm_device *dev,
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, false);
|
||||
drm_atomic_helper_commit_planes(dev, state, 0);
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
|
||||
|
@ -44,7 +44,7 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, state, false);
|
||||
drm_atomic_helper_commit_planes(dev, state, 0);
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
|
||||
|
@ -338,7 +338,8 @@ static void vgdev_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
drm_atomic_helper_commit_modeset_enables(dev, state);
|
||||
drm_atomic_helper_commit_planes(dev, state, true);
|
||||
drm_atomic_helper_commit_planes(dev, state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
drm_atomic_helper_commit_hw_done(state);
|
||||
|
||||
|
@ -65,14 +65,19 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
|
||||
|
||||
int drm_atomic_helper_prepare_planes(struct drm_device *dev,
|
||||
struct drm_atomic_state *state);
|
||||
|
||||
#define DRM_PLANE_COMMIT_ACTIVE_ONLY BIT(0)
|
||||
#define DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET BIT(1)
|
||||
|
||||
void drm_atomic_helper_commit_planes(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
bool active_only);
|
||||
uint32_t flags);
|
||||
void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
|
||||
struct drm_atomic_state *old_state);
|
||||
void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state);
|
||||
void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
|
||||
bool atomic);
|
||||
void
|
||||
drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
|
||||
bool atomic);
|
||||
|
||||
void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
|
||||
bool stall);
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <drm/drm_modeset.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
|
||||
struct drm_connector_helper_funcs;
|
||||
struct drm_device;
|
||||
|
@ -36,10 +36,12 @@
|
||||
#include <uapi/drm/drm_fourcc.h>
|
||||
#include <drm/drm_modeset_lock.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_modeset.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_property.h>
|
||||
|
||||
struct drm_device;
|
||||
struct drm_mode_set;
|
||||
@ -81,33 +83,6 @@ struct drm_tile_group {
|
||||
u8 group_data[8];
|
||||
};
|
||||
|
||||
struct drm_property_blob {
|
||||
struct drm_mode_object base;
|
||||
struct drm_device *dev;
|
||||
struct list_head head_global;
|
||||
struct list_head head_file;
|
||||
size_t length;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
struct drm_property_enum {
|
||||
uint64_t value;
|
||||
struct list_head head;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
};
|
||||
|
||||
struct drm_property {
|
||||
struct list_head head;
|
||||
struct drm_mode_object base;
|
||||
uint32_t flags;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
uint32_t num_values;
|
||||
uint64_t *values;
|
||||
struct drm_device *dev;
|
||||
|
||||
struct list_head enum_list;
|
||||
};
|
||||
|
||||
struct drm_crtc;
|
||||
struct drm_encoder;
|
||||
struct drm_pending_vblank_event;
|
||||
@ -679,97 +654,6 @@ struct drm_crtc {
|
||||
struct drm_modeset_acquire_ctx *acquire_ctx;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -1136,11 +1020,32 @@ struct drm_plane {
|
||||
|
||||
/**
|
||||
* struct drm_bridge_funcs - drm_bridge control functions
|
||||
* @attach: Called during drm_bridge_attach
|
||||
*/
|
||||
struct drm_bridge_funcs {
|
||||
/**
|
||||
* @attach:
|
||||
*
|
||||
* This callback is invoked whenever our bridge is being attached to a
|
||||
* &drm_encoder.
|
||||
*
|
||||
* The attach callback is optional.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int (*attach)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @detach:
|
||||
*
|
||||
* This callback is invoked whenever our bridge is being detached from a
|
||||
* &drm_encoder.
|
||||
*
|
||||
* The detach callback is optional.
|
||||
*/
|
||||
void (*detach)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @mode_fixup:
|
||||
*
|
||||
@ -1155,6 +1060,8 @@ struct drm_bridge_funcs {
|
||||
* this function passes all other callbacks must succeed for this
|
||||
* configuration.
|
||||
*
|
||||
* The mode_fixup callback is optional.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* This function is called in the check phase of atomic modesets, which
|
||||
@ -2109,18 +2016,11 @@ 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)
|
||||
#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
|
||||
#define obj_to_plane(x) container_of(x, struct drm_plane, base)
|
||||
|
||||
struct drm_prop_enum_list {
|
||||
int type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
extern __printf(6, 7)
|
||||
int drm_crtc_init_with_planes(struct drm_device *dev,
|
||||
struct drm_crtc *crtc,
|
||||
@ -2154,37 +2054,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,
|
||||
@ -2220,75 +2089,15 @@ 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);
|
||||
|
||||
static inline bool drm_property_type_is(struct drm_property *property,
|
||||
uint32_t type)
|
||||
{
|
||||
/* instanceof for props.. handles extended type vs original types: */
|
||||
if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
|
||||
return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
|
||||
return property->flags & type;
|
||||
}
|
||||
|
||||
extern int drm_object_property_set_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t val);
|
||||
extern int drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *value);
|
||||
|
||||
extern void drm_object_attach_property(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t init_val);
|
||||
extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
||||
const char *name, int num_values);
|
||||
extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_values);
|
||||
struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_props,
|
||||
uint64_t supported_bits);
|
||||
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
uint64_t min, uint64_t max);
|
||||
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
int64_t min, int64_t max);
|
||||
struct drm_property *drm_property_create_object(struct drm_device *dev,
|
||||
int flags, const char *name, uint32_t type);
|
||||
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
|
||||
const char *name);
|
||||
struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
|
||||
size_t length,
|
||||
const void *data);
|
||||
struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
|
||||
uint32_t id);
|
||||
int drm_property_replace_global_blob(struct drm_device *dev,
|
||||
struct drm_property_blob **replace,
|
||||
size_t length,
|
||||
const void *data,
|
||||
struct drm_mode_object *obj_holds_id,
|
||||
struct drm_property *prop_holds_id);
|
||||
struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob);
|
||||
void drm_property_unreference_blob(struct drm_property_blob *blob);
|
||||
extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
|
||||
extern int drm_property_add_enum(struct drm_property *property, int index,
|
||||
uint64_t value, const char *name);
|
||||
extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
||||
int gamma_size);
|
||||
|
||||
extern int drm_mode_set_config_internal(struct drm_mode_set *set);
|
||||
|
||||
extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
|
||||
|
||||
extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
|
||||
char topology[8]);
|
||||
extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
|
||||
@ -2333,22 +2142,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)
|
||||
{
|
||||
struct drm_mode_object *mo;
|
||||
mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
|
||||
return mo ? obj_to_property(mo) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a degamma/gamma LUT value provided by user and round it to the
|
||||
* precision supported by the hardware.
|
||||
@ -2444,6 +2237,7 @@ extern int drm_bridge_add(struct drm_bridge *bridge);
|
||||
extern void drm_bridge_remove(struct drm_bridge *bridge);
|
||||
extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
|
||||
extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
|
||||
extern void drm_bridge_detach(struct drm_bridge *bridge);
|
||||
|
||||
bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
|
227
include/drm/drm_encoder.h
Normal file
227
include/drm/drm_encoder.h
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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_mode_object.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
|
||||
* @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;
|
||||
/**
|
||||
* @encoder_type:
|
||||
*
|
||||
* One of the DRM_MODE_ENCODER_<foo> types in drm_mode.h. The following
|
||||
* encoder types are defined thus far:
|
||||
*
|
||||
* - DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A.
|
||||
*
|
||||
* - DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort.
|
||||
*
|
||||
* - DRM_MODE_ENCODER_LVDS for display panels, or in general any panel
|
||||
* with a proprietary parallel connector.
|
||||
*
|
||||
* - DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video,
|
||||
* Component, SCART).
|
||||
*
|
||||
* - DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
|
||||
*
|
||||
* - DRM_MODE_ENCODER_DSI for panels connected using the DSI serial bus.
|
||||
*
|
||||
* - DRM_MODE_ENCODER_DPI for panels connected using the DPI parallel
|
||||
* bus.
|
||||
*
|
||||
* - DRM_MODE_ENCODER_DPMST for special fake encoders used to allow
|
||||
* mutliple DP MST streams to share one physical encoder.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @possible_crtcs: Bitmask of potential CRTC bindings, using
|
||||
* drm_crtc_index() as the index into the bitfield. The driver must set
|
||||
* the bits for all &drm_crtc objects this encoder can be connected to
|
||||
* before calling drm_encoder_init().
|
||||
*
|
||||
* In reality almost every driver gets this wrong.
|
||||
*
|
||||
* Note that since CRTC objects can't be hotplugged the assigned indices
|
||||
* are stable and hence known before registering all objects.
|
||||
*/
|
||||
uint32_t possible_crtcs;
|
||||
|
||||
/**
|
||||
* @possible_clones: Bitmask of potential sibling encoders for cloning,
|
||||
* using drm_encoder_index() as the index into the bitfield. The driver
|
||||
* must set the bits for all &drm_encoder objects which can clone a
|
||||
* &drm_crtc together with this encoder before calling
|
||||
* drm_encoder_init(). Drivers should set the bit representing the
|
||||
* encoder itself, too. Cloning bits should be set such that when two
|
||||
* encoders can be used in a cloned configuration, they both should have
|
||||
* each another bits set.
|
||||
*
|
||||
* In reality almost every driver gets this wrong.
|
||||
*
|
||||
* Note that since encoder objects can't be hotplugged the assigned indices
|
||||
* are stable and hence known before registering all objects.
|
||||
*/
|
||||
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
|
||||
*
|
||||
* Returns 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_encoder_find - find a &drm_encoder
|
||||
* @dev: DRM device
|
||||
* @id: encoder id
|
||||
*
|
||||
* Returns the encoder with @id, NULL if it doesn't exist. Simple wrapper around
|
||||
* drm_mode_object_find().
|
||||
*/
|
||||
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
|
@ -491,7 +491,7 @@ static inline int
|
||||
drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
const char *name, bool primary)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FB)
|
||||
#if IS_REACHABLE(CONFIG_FB)
|
||||
return remove_conflicting_framebuffers(a, name, primary);
|
||||
#else
|
||||
return 0;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <uapi/drm/drm_fourcc.h>
|
||||
|
||||
uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
|
||||
void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp);
|
||||
int drm_format_num_planes(uint32_t format);
|
||||
int drm_format_plane_cpp(uint32_t format, int plane);
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <drm/drm_modeset.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
|
||||
struct drm_framebuffer;
|
||||
struct drm_file;
|
||||
|
124
include/drm/drm_mode_object.h
Normal file
124
include/drm/drm_mode_object.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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_MODESET_H__
|
||||
#define __DRM_MODESET_H__
|
||||
|
||||
#include <linux/kref.h>
|
||||
struct drm_object_properties;
|
||||
struct drm_property;
|
||||
|
||||
/**
|
||||
* struct drm_mode_object - base structure for modeset objects
|
||||
* @id: userspace visible identifier
|
||||
* @type: type of the object, one of DRM_MODE_OBJECT\_\*
|
||||
* @properties: properties attached to this object, including values
|
||||
* @refcount: reference count for objects which with dynamic lifetime
|
||||
* @free_cb: free function callback, only set for objects with dynamic lifetime
|
||||
*
|
||||
* Base structure for modeset objects visible to userspace. Objects can be
|
||||
* looked up using drm_mode_object_find(). Besides basic uapi interface
|
||||
* properties like @id and @type it provides two services:
|
||||
*
|
||||
* - It tracks attached properties and their values. This is used by &drm_crtc,
|
||||
* &drm_plane and &drm_connector. Properties are attached by calling
|
||||
* drm_object_attach_property() before the object is visible to userspace.
|
||||
*
|
||||
* - For objects with dynamic lifetimes (as indicated by a non-NULL @free_cb) it
|
||||
* provides reference counting through drm_mode_object_reference() and
|
||||
* drm_mode_object_unreference(). This is used by &drm_framebuffer,
|
||||
* &drm_connector and &drm_property_blob. These objects provide specialized
|
||||
* reference counting wrappers.
|
||||
*/
|
||||
struct drm_mode_object {
|
||||
uint32_t id;
|
||||
uint32_t type;
|
||||
struct drm_object_properties *properties;
|
||||
struct kref refcount;
|
||||
void (*free_cb)(struct kref *kref);
|
||||
};
|
||||
|
||||
#define DRM_OBJECT_MAX_PROPERTY 24
|
||||
/**
|
||||
* struct drm_object_properties - property tracking for &drm_mode_object
|
||||
*/
|
||||
struct drm_object_properties {
|
||||
/**
|
||||
* @count: number of valid properties, must be less than or equal to
|
||||
* DRM_OBJECT_MAX_PROPERTY.
|
||||
*/
|
||||
|
||||
int count;
|
||||
/**
|
||||
* @properties: Array of pointers to &drm_property.
|
||||
*
|
||||
* NOTE: if we ever start dynamically destroying properties (ie.
|
||||
* not at drm_mode_config_cleanup() time), then we'd have to do
|
||||
* a better job of detaching property from mode objects to avoid
|
||||
* dangling property pointers:
|
||||
*/
|
||||
struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
|
||||
|
||||
/**
|
||||
* @values: Array to store the property values, matching @properties. Do
|
||||
* not read/write values directly, but use
|
||||
* drm_object_property_get_value() and drm_object_property_set_value().
|
||||
*
|
||||
* Note that atomic drivers do not store mutable properties in this
|
||||
* array, but only the decoded values in the corresponding state
|
||||
* structure. The decoding is done using the ->atomic_get_property and
|
||||
* ->atomic_set_property hooks of the corresponding object. Hence atomic
|
||||
* drivers should not use drm_object_property_set_value() and
|
||||
* drm_object_property_get_value() on mutable objects, i.e. those
|
||||
* without the DRM_MODE_PROP_IMMUTABLE flag set.
|
||||
*/
|
||||
uint64_t values[DRM_OBJECT_MAX_PROPERTY];
|
||||
};
|
||||
|
||||
/* Avoid boilerplate. I'm tired of typing. */
|
||||
#define DRM_ENUM_NAME_FN(fnname, list) \
|
||||
const char *fnname(int val) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(list); i++) { \
|
||||
if (list[i].type == val) \
|
||||
return list[i].name; \
|
||||
} \
|
||||
return "(unknown)"; \
|
||||
}
|
||||
|
||||
struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
|
||||
uint32_t id, uint32_t type);
|
||||
void drm_mode_object_reference(struct drm_mode_object *obj);
|
||||
void drm_mode_object_unreference(struct drm_mode_object *obj);
|
||||
|
||||
int drm_object_property_set_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t val);
|
||||
int drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *value);
|
||||
|
||||
void drm_object_attach_property(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t init_val);
|
||||
#endif
|
@ -27,7 +27,7 @@
|
||||
#ifndef __DRM_MODES_H__
|
||||
#define __DRM_MODES_H__
|
||||
|
||||
#include <drm/drm_modeset.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
#include <drm/drm_connector.h>
|
||||
|
||||
/*
|
||||
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* 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_MODESET_H__
|
||||
#define __DRM_MODESET_H__
|
||||
|
||||
#include <linux/kref.h>
|
||||
struct drm_object_properties;
|
||||
struct drm_property;
|
||||
|
||||
struct drm_mode_object {
|
||||
uint32_t id;
|
||||
uint32_t type;
|
||||
struct drm_object_properties *properties;
|
||||
struct kref refcount;
|
||||
void (*free_cb)(struct kref *kref);
|
||||
};
|
||||
|
||||
#define DRM_OBJECT_MAX_PROPERTY 24
|
||||
struct drm_object_properties {
|
||||
int count, atomic_count;
|
||||
/* NOTE: if we ever start dynamically destroying properties (ie.
|
||||
* not at drm_mode_config_cleanup() time), then we'd have to do
|
||||
* a better job of detaching property from mode objects to avoid
|
||||
* dangling property pointers:
|
||||
*/
|
||||
struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
|
||||
/* do not read/write values directly, but use drm_object_property_get_value()
|
||||
* and drm_object_property_set_value():
|
||||
*/
|
||||
uint64_t values[DRM_OBJECT_MAX_PROPERTY];
|
||||
};
|
||||
|
||||
/* Avoid boilerplate. I'm tired of typing. */
|
||||
#define DRM_ENUM_NAME_FN(fnname, list) \
|
||||
const char *fnname(int val) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(list); i++) { \
|
||||
if (list[i].type == val) \
|
||||
return list[i].name; \
|
||||
} \
|
||||
return "(unknown)"; \
|
||||
}
|
||||
|
||||
struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
|
||||
uint32_t id, uint32_t type);
|
||||
void drm_mode_object_reference(struct drm_mode_object *obj);
|
||||
void drm_mode_object_unreference(struct drm_mode_object *obj);
|
||||
|
||||
#endif
|
@ -266,6 +266,8 @@ struct drm_crtc_helper_funcs {
|
||||
* disable anything at the CRTC level. To ensure that runtime PM
|
||||
* handling (using either DPMS or the new "ACTIVE" property) works
|
||||
* @disable must be the inverse of @enable for atomic drivers.
|
||||
* Atomic drivers should consider to use @atomic_disable instead of
|
||||
* this one.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
@ -391,6 +393,28 @@ struct drm_crtc_helper_funcs {
|
||||
*/
|
||||
void (*atomic_flush)(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state);
|
||||
|
||||
/**
|
||||
* @atomic_disable:
|
||||
*
|
||||
* This callback should be used to disable the CRTC. With the atomic
|
||||
* drivers it is called after all encoders connected to this CRTC have
|
||||
* been shut off already using their own ->disable hook. If that
|
||||
* sequence is too simple drivers can just add their own hooks and call
|
||||
* it from this CRTC callback here by looping over all encoders
|
||||
* connected to it using for_each_encoder_on_crtc().
|
||||
*
|
||||
* This hook is used only by atomic helpers. Atomic drivers don't
|
||||
* need to implement it if there's no need to disable anything at the
|
||||
* CRTC level.
|
||||
*
|
||||
* Comparing to @disable, this one provides the additional input
|
||||
* parameter @old_crtc_state which could be used to access the old
|
||||
* state. Atomic drivers should consider to use this one instead
|
||||
* of @disable.
|
||||
*/
|
||||
void (*atomic_disable)(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state);
|
||||
};
|
||||
|
||||
/**
|
||||
|
294
include/drm/drm_property.h
Normal file
294
include/drm/drm_property.h
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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_PROPERTY_H__
|
||||
#define __DRM_PROPERTY_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
|
||||
/**
|
||||
* struct drm_property_enum - symbolic values for enumerations
|
||||
* @value: numeric property value for this enum entry
|
||||
* @head: list of enum values, linked to enum_list in &drm_property
|
||||
* @name: symbolic name for the enum
|
||||
*
|
||||
* For enumeration and bitmask properties this structure stores the symbolic
|
||||
* decoding for each value. This is used for example for the rotation property.
|
||||
*/
|
||||
struct drm_property_enum {
|
||||
uint64_t value;
|
||||
struct list_head head;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_property - modeset object property
|
||||
*
|
||||
* This structure represent a modeset object property. It combines both the name
|
||||
* of the property with the set of permissible values. This means that when a
|
||||
* driver wants to use a property with the same name on different objects, but
|
||||
* with different value ranges, then it must create property for each one. An
|
||||
* example would be rotation of &drm_plane, when e.g. the primary plane cannot
|
||||
* be rotated. But if both the name and the value range match, then the same
|
||||
* property structure can be instantiated multiple times for the same object.
|
||||
* Userspace must be able to cope with this and cannot assume that the same
|
||||
* symbolic property will have the same modeset object ID on all modeset
|
||||
* objects.
|
||||
*
|
||||
* Properties are created by one of the special functions, as explained in
|
||||
* detail in the @flags structure member.
|
||||
*
|
||||
* To actually expose a property it must be attached to each object using
|
||||
* drm_object_attach_property(). Currently properties can only be attached to
|
||||
* &drm_connector, &drm_crtc and &drm_plane.
|
||||
*
|
||||
* Properties are also used as the generic metadatatransport for the atomic
|
||||
* IOCTL. Everything that was set directly in structures in the legacy modeset
|
||||
* IOCTLs (like the plane source or destination windows, or e.g. the links to
|
||||
* the CRTC) is exposed as a property with the DRM_MODE_PROP_ATOMIC flag set.
|
||||
*/
|
||||
struct drm_property {
|
||||
/**
|
||||
* @head: per-device list of properties, for cleanup.
|
||||
*/
|
||||
struct list_head head;
|
||||
|
||||
/**
|
||||
* @base: base KMS object
|
||||
*/
|
||||
struct drm_mode_object base;
|
||||
|
||||
/**
|
||||
* @flags:
|
||||
*
|
||||
* Property flags and type. A property needs to be one of the following
|
||||
* types:
|
||||
*
|
||||
* DRM_MODE_PROP_RANGE
|
||||
* Range properties report their minimum and maximum admissible unsigned values.
|
||||
* The KMS core verifies that values set by application fit in that
|
||||
* range. The range is unsigned. Range properties are created using
|
||||
* drm_property_create_range().
|
||||
*
|
||||
* DRM_MODE_PROP_SIGNED_RANGE
|
||||
* Range properties report their minimum and maximum admissible unsigned values.
|
||||
* The KMS core verifies that values set by application fit in that
|
||||
* range. The range is signed. Range properties are created using
|
||||
* drm_property_create_signed_range().
|
||||
*
|
||||
* DRM_MODE_PROP_ENUM
|
||||
* Enumerated properties take a numerical value that ranges from 0 to
|
||||
* the number of enumerated values defined by the property minus one,
|
||||
* and associate a free-formed string name to each value. Applications
|
||||
* can retrieve the list of defined value-name pairs and use the
|
||||
* numerical value to get and set property instance values. Enum
|
||||
* properties are created using drm_property_create_enum().
|
||||
*
|
||||
* DRM_MODE_PROP_BITMASK
|
||||
* Bitmask properties are enumeration properties that additionally
|
||||
* restrict all enumerated values to the 0..63 range. Bitmask property
|
||||
* instance values combine one or more of the enumerated bits defined
|
||||
* by the property. Bitmask properties are created using
|
||||
* drm_property_create_bitmask().
|
||||
*
|
||||
* DRM_MODE_PROB_OBJECT
|
||||
* Object properties are used to link modeset objects. This is used
|
||||
* extensively in the atomic support to create the display pipeline,
|
||||
* by linking &drm_framebuffer to &drm_plane, &drm_plane to
|
||||
* &drm_crtc and &drm_connector to &drm_crtc. An object property can
|
||||
* only link to a specific type of &drm_mode_object, this limit is
|
||||
* enforced by the core. Object properties are created using
|
||||
* drm_property_create_object().
|
||||
*
|
||||
* Object properties work like blob properties, but in a more
|
||||
* general fashion. They are limited to atomic drivers and must have
|
||||
* the DRM_MODE_PROP_ATOMIC flag set.
|
||||
*
|
||||
* DRM_MODE_PROP_BLOB
|
||||
* Blob properties store a binary blob without any format restriction.
|
||||
* The binary blobs are created as KMS standalone objects, and blob
|
||||
* property instance values store the ID of their associated blob
|
||||
* object. Blob properties are created by calling
|
||||
* drm_property_create() with DRM_MODE_PROP_BLOB as the type.
|
||||
*
|
||||
* Actual blob objects to contain blob data are created using
|
||||
* drm_property_create_blob(), or through the corresponding IOCTL.
|
||||
*
|
||||
* Besides the built-in limit to only accept blob objects blob
|
||||
* properties work exactly like object properties. The only reasons
|
||||
* blob properties exist is backwards compatibility with existing
|
||||
* userspace.
|
||||
*
|
||||
* In addition a property can have any combination of the below flags:
|
||||
*
|
||||
* DRM_MODE_PROP_ATOMIC
|
||||
* Set for properties which encode atomic modeset state. Such
|
||||
* properties are not exposed to legacy userspace.
|
||||
*
|
||||
* DRM_MODE_PROP_IMMUTABLE
|
||||
* Set for properties where userspace cannot be changed by
|
||||
* userspace. The kernel is allowed to update the value of these
|
||||
* properties. This is generally used to expose probe state to
|
||||
* usersapce, e.g. the EDID, or the connector path property on DP
|
||||
* MST sinks.
|
||||
*/
|
||||
uint32_t flags;
|
||||
|
||||
/**
|
||||
* @name: symbolic name of the properties
|
||||
*/
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
|
||||
/**
|
||||
* @num_values: size of the @values array.
|
||||
*/
|
||||
uint32_t num_values;
|
||||
|
||||
/**
|
||||
* @values:
|
||||
*
|
||||
* Array with limits and values for the property. The
|
||||
* interpretation of these limits is dependent upon the type per @flags.
|
||||
*/
|
||||
uint64_t *values;
|
||||
|
||||
/**
|
||||
* @dev: DRM device
|
||||
*/
|
||||
struct drm_device *dev;
|
||||
|
||||
/**
|
||||
* @enum_list:
|
||||
*
|
||||
* List of &drm_prop_enum_list structures with the symbolic names for
|
||||
* enum and bitmask values.
|
||||
*/
|
||||
struct list_head enum_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_property_blob - Blob data for &drm_property
|
||||
* @base: base KMS object
|
||||
* @dev: DRM device
|
||||
* @head_global: entry on the global blob list in &drm_mode_config
|
||||
* property_blob_list.
|
||||
* @head_file: entry on the per-file blob list in &drm_file blobs list.
|
||||
* @length: size of the blob in bytes, invariant over the lifetime of the object
|
||||
* @data: actual data, embedded at the end of this structure
|
||||
*
|
||||
* Blobs are used to store bigger values than what fits directly into the 64
|
||||
* bits available for a &drm_property.
|
||||
*
|
||||
* Blobs are reference counted using drm_property_reference_blob() and
|
||||
* drm_property_unreference_blob(). They are created using
|
||||
* drm_property_create_blob().
|
||||
*/
|
||||
struct drm_property_blob {
|
||||
struct drm_mode_object base;
|
||||
struct drm_device *dev;
|
||||
struct list_head head_global;
|
||||
struct list_head head_file;
|
||||
size_t length;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
struct drm_prop_enum_list {
|
||||
int type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
#define obj_to_property(x) container_of(x, struct drm_property, base)
|
||||
|
||||
/**
|
||||
* drm_property_type_is - check the type of a property
|
||||
* @property: property to check
|
||||
* @type: property type to compare with
|
||||
*
|
||||
* This is a helper function becauase the uapi encoding of property types is
|
||||
* a bit special for historical reasons.
|
||||
*/
|
||||
static inline bool drm_property_type_is(struct drm_property *property,
|
||||
uint32_t type)
|
||||
{
|
||||
/* instanceof for props.. handles extended type vs original types: */
|
||||
if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
|
||||
return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type;
|
||||
return property->flags & type;
|
||||
}
|
||||
|
||||
struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
||||
const char *name, int num_values);
|
||||
struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_values);
|
||||
struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_props,
|
||||
uint64_t supported_bits);
|
||||
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
uint64_t min, uint64_t max);
|
||||
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
|
||||
int flags, const char *name,
|
||||
int64_t min, int64_t max);
|
||||
struct drm_property *drm_property_create_object(struct drm_device *dev,
|
||||
int flags, const char *name, uint32_t type);
|
||||
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
|
||||
const char *name);
|
||||
int drm_property_add_enum(struct drm_property *property, int index,
|
||||
uint64_t value, const char *name);
|
||||
void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
|
||||
|
||||
struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
|
||||
size_t length,
|
||||
const void *data);
|
||||
struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
|
||||
uint32_t id);
|
||||
int drm_property_replace_global_blob(struct drm_device *dev,
|
||||
struct drm_property_blob **replace,
|
||||
size_t length,
|
||||
const void *data,
|
||||
struct drm_mode_object *obj_holds_id,
|
||||
struct drm_property *prop_holds_id);
|
||||
struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob);
|
||||
void drm_property_unreference_blob(struct drm_property_blob *blob);
|
||||
|
||||
/**
|
||||
* drm_connector_find - find property object
|
||||
* @dev: DRM device
|
||||
* @id: property object id
|
||||
*
|
||||
* This function looks up the property object specified by id and returns it.
|
||||
*/
|
||||
static inline struct drm_property *drm_property_find(struct drm_device *dev,
|
||||
uint32_t id)
|
||||
{
|
||||
struct drm_mode_object *mo;
|
||||
mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY);
|
||||
return mo ? obj_to_property(mo) : NULL;
|
||||
}
|
||||
|
||||
#endif
|
@ -60,6 +60,12 @@ struct drm_simple_display_pipe_funcs {
|
||||
*
|
||||
* This function is called when the underlying plane state is updated.
|
||||
* This hook is optional.
|
||||
*
|
||||
* This is the function drivers should submit the
|
||||
* &drm_pending_vblank_event from. Using either
|
||||
* drm_crtc_arm_vblank_event(), when the driver supports vblank
|
||||
* interrupt handling, or drm_crtc_send_vblank_event() directly in case
|
||||
* the hardware lacks vblank support entirely.
|
||||
*/
|
||||
void (*update)(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *plane_state);
|
||||
@ -85,6 +91,11 @@ struct drm_simple_display_pipe {
|
||||
const struct drm_simple_display_pipe_funcs *funcs;
|
||||
};
|
||||
|
||||
int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_bridge *bridge);
|
||||
|
||||
void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe *pipe);
|
||||
|
||||
int drm_simple_display_pipe_init(struct drm_device *dev,
|
||||
struct drm_simple_display_pipe *pipe,
|
||||
const struct drm_simple_display_pipe_funcs *funcs,
|
||||
|
Loading…
Reference in New Issue
Block a user