diff options
author | Dave Airlie <airlied@redhat.com> | 2016-08-31 16:15:38 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-08-31 16:15:38 -0400 |
commit | 5e7a1d0170b06b1557768d6ddc93da1aed02961a (patch) | |
tree | a6fea1c85efa6c76d132d6851a56a46db8d2a5fd | |
parent | e9c3ddee6a08c5b25cdb06b524320a5a98250513 (diff) | |
parent | 339fd36238dd3494bc4617d181e7a37922c29ee9 (diff) |
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
...
44 files changed, 2667 insertions, 2152 deletions
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index fa948b4e029b..f9a991bb87d4 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst | |||
@@ -15,6 +15,15 @@ be setup by initializing the following fields. | |||
15 | - struct drm_mode_config_funcs \*funcs; | 15 | - struct drm_mode_config_funcs \*funcs; |
16 | Mode setting functions. | 16 | Mode setting functions. |
17 | 17 | ||
18 | Modeset Base Object Abstraction | ||
19 | =============================== | ||
20 | |||
21 | .. kernel-doc:: include/drm/drm_mode_object.h | ||
22 | :internal: | ||
23 | |||
24 | .. kernel-doc:: drivers/gpu/drm/drm_mode_object.c | ||
25 | :export: | ||
26 | |||
18 | KMS Data Structures | 27 | KMS Data Structures |
19 | =================== | 28 | =================== |
20 | 29 | ||
@@ -125,6 +134,21 @@ Connector Functions Reference | |||
125 | .. kernel-doc:: drivers/gpu/drm/drm_connector.c | 134 | .. kernel-doc:: drivers/gpu/drm/drm_connector.c |
126 | :export: | 135 | :export: |
127 | 136 | ||
137 | Encoder Abstraction | ||
138 | =================== | ||
139 | |||
140 | .. kernel-doc:: drivers/gpu/drm/drm_encoder.c | ||
141 | :doc: overview | ||
142 | |||
143 | Encoder Functions Reference | ||
144 | --------------------------- | ||
145 | |||
146 | .. kernel-doc:: include/drm/drm_encoder.h | ||
147 | :internal: | ||
148 | |||
149 | .. kernel-doc:: drivers/gpu/drm/drm_encoder.c | ||
150 | :export: | ||
151 | |||
128 | KMS Initialization and Cleanup | 152 | KMS Initialization and Cleanup |
129 | ============================== | 153 | ============================== |
130 | 154 | ||
@@ -198,46 +222,6 @@ future); drivers that do not wish to provide special handling for | |||
198 | primary planes may make use of the helper functions described in ? to | 222 | primary planes may make use of the helper functions described in ? to |
199 | create and register a primary plane with standard capabilities. | 223 | create and register a primary plane with standard capabilities. |
200 | 224 | ||
201 | Encoders (:c:type:`struct drm_encoder <drm_encoder>`) | ||
202 | ----------------------------------------------------- | ||
203 | |||
204 | An encoder takes pixel data from a CRTC and converts it to a format | ||
205 | suitable for any attached connectors. On some devices, it may be | ||
206 | possible to have a CRTC send data to more than one encoder. In that | ||
207 | case, both encoders would receive data from the same scanout buffer, | ||
208 | resulting in a "cloned" display configuration across the connectors | ||
209 | attached to each encoder. | ||
210 | |||
211 | Encoder Initialization | ||
212 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
213 | |||
214 | As for CRTCs, a KMS driver must create, initialize and register at least | ||
215 | one :c:type:`struct drm_encoder <drm_encoder>` instance. The | ||
216 | instance is allocated and zeroed by the driver, possibly as part of a | ||
217 | larger structure. | ||
218 | |||
219 | Drivers must initialize the :c:type:`struct drm_encoder | ||
220 | <drm_encoder>` possible_crtcs and possible_clones fields before | ||
221 | registering the encoder. Both fields are bitmasks of respectively the | ||
222 | CRTCs that the encoder can be connected to, and sibling encoders | ||
223 | candidate for cloning. | ||
224 | |||
225 | After being initialized, the encoder must be registered with a call to | ||
226 | :c:func:`drm_encoder_init()`. The function takes a pointer to the | ||
227 | encoder functions and an encoder type. Supported types are | ||
228 | |||
229 | - DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A | ||
230 | - DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort | ||
231 | - DRM_MODE_ENCODER_LVDS for display panels | ||
232 | - DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, | ||
233 | Component, SCART) | ||
234 | - DRM_MODE_ENCODER_VIRTUAL for virtual machine displays | ||
235 | |||
236 | Encoders must be attached to a CRTC to be used. DRM drivers leave | ||
237 | encoders unattached at initialization time. Applications (or the fbdev | ||
238 | compatibility layer when implemented) are responsible for attaching the | ||
239 | encoders they want to use to a CRTC. | ||
240 | |||
241 | Cleanup | 225 | Cleanup |
242 | ------- | 226 | ------- |
243 | 227 | ||
@@ -320,90 +304,17 @@ KMS Locking | |||
320 | KMS Properties | 304 | KMS Properties |
321 | ============== | 305 | ============== |
322 | 306 | ||
323 | Drivers may need to expose additional parameters to applications than | 307 | Property Types and Blob Property Support |
324 | those described in the previous sections. KMS supports attaching | 308 | ---------------------------------------- |
325 | properties to CRTCs, connectors and planes and offers a userspace API to | 309 | |
326 | list, get and set the property values. | 310 | .. kernel-doc:: drivers/gpu/drm/drm_property.c |
327 | 311 | :doc: overview | |
328 | Properties are identified by a name that uniquely defines the property | 312 | |
329 | purpose, and store an associated value. For all property types except | 313 | .. kernel-doc:: include/drm/drm_property.h |
330 | blob properties the value is a 64-bit unsigned integer. | 314 | :internal: |
331 | 315 | ||
332 | KMS differentiates between properties and property instances. Drivers | 316 | .. kernel-doc:: drivers/gpu/drm/drm_property.c |
333 | first create properties and then create and associate individual | 317 | :export: |
334 | instances of those properties to objects. A property can be instantiated | ||
335 | multiple times and associated with different objects. Values are stored | ||
336 | in property instances, and all other property information are stored in | ||
337 | the property and shared between all instances of the property. | ||
338 | |||
339 | Every property is created with a type that influences how the KMS core | ||
340 | handles the property. Supported property types are | ||
341 | |||
342 | DRM_MODE_PROP_RANGE | ||
343 | Range properties report their minimum and maximum admissible values. | ||
344 | The KMS core verifies that values set by application fit in that | ||
345 | range. | ||
346 | |||
347 | DRM_MODE_PROP_ENUM | ||
348 | Enumerated properties take a numerical value that ranges from 0 to | ||
349 | the number of enumerated values defined by the property minus one, | ||
350 | and associate a free-formed string name to each value. Applications | ||
351 | can retrieve the list of defined value-name pairs and use the | ||
352 | numerical value to get and set property instance values. | ||
353 | |||
354 | DRM_MODE_PROP_BITMASK | ||
355 | Bitmask properties are enumeration properties that additionally | ||
356 | restrict all enumerated values to the 0..63 range. Bitmask property | ||
357 | instance values combine one or more of the enumerated bits defined | ||
358 | by the property. | ||
359 | |||
360 | DRM_MODE_PROP_BLOB | ||
361 | Blob properties store a binary blob without any format restriction. | ||
362 | The binary blobs are created as KMS standalone objects, and blob | ||
363 | property instance values store the ID of their associated blob | ||
364 | object. | ||
365 | |||
366 | Blob properties are only used for the connector EDID property and | ||
367 | cannot be created by drivers. | ||
368 | |||
369 | To create a property drivers call one of the following functions | ||
370 | depending on the property type. All property creation functions take | ||
371 | property flags and name, as well as type-specific arguments. | ||
372 | |||
373 | - struct drm_property \*drm_property_create_range(struct | ||
374 | drm_device \*dev, int flags, const char \*name, uint64_t min, | ||
375 | uint64_t max); | ||
376 | Create a range property with the given minimum and maximum values. | ||
377 | |||
378 | - struct drm_property \*drm_property_create_enum(struct drm_device | ||
379 | \*dev, int flags, const char \*name, const struct | ||
380 | drm_prop_enum_list \*props, int num_values); | ||
381 | Create an enumerated property. The ``props`` argument points to an | ||
382 | array of ``num_values`` value-name pairs. | ||
383 | |||
384 | - struct drm_property \*drm_property_create_bitmask(struct | ||
385 | drm_device \*dev, int flags, const char \*name, const struct | ||
386 | drm_prop_enum_list \*props, int num_values); | ||
387 | Create a bitmask property. The ``props`` argument points to an array | ||
388 | of ``num_values`` value-name pairs. | ||
389 | |||
390 | Properties can additionally be created as immutable, in which case they | ||
391 | will be read-only for applications but can be modified by the driver. To | ||
392 | create an immutable property drivers must set the | ||
393 | DRM_MODE_PROP_IMMUTABLE flag at property creation time. | ||
394 | |||
395 | When no array of value-name pairs is readily available at property | ||
396 | creation time for enumerated or range properties, drivers can create the | ||
397 | property using the :c:func:`drm_property_create()` function and | ||
398 | manually add enumeration value-name pairs by calling the | ||
399 | :c:func:`drm_property_add_enum()` function. Care must be taken to | ||
400 | properly specify the property type through the ``flags`` argument. | ||
401 | |||
402 | After creating properties drivers can attach property instances to CRTC, | ||
403 | connector and plane objects by calling the | ||
404 | :c:func:`drm_object_attach_property()`. The function takes a | ||
405 | pointer to the target object, a pointer to the previously created | ||
406 | property and an initial instance value. | ||
407 | 318 | ||
408 | Blending and Z-Position properties | 319 | Blending and Z-Position properties |
409 | ---------------------------------- | 320 | ---------------------------------- |
diff --git a/Documentation/gpu/vga-switcheroo.rst b/Documentation/gpu/vga-switcheroo.rst index 463a74fc40d1..cbbdb994f1dd 100644 --- a/Documentation/gpu/vga-switcheroo.rst +++ b/Documentation/gpu/vga-switcheroo.rst | |||
@@ -1,3 +1,5 @@ | |||
1 | .. _vga_switcheroo: | ||
2 | |||
1 | ============== | 3 | ============== |
2 | VGA Switcheroo | 4 | VGA Switcheroo |
3 | ============== | 5 | ============== |
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index cbb64d9a82f8..536b5d477c3b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -108,24 +108,8 @@ config DRM_KMS_CMA_HELPER | |||
108 | 108 | ||
109 | source "drivers/gpu/drm/i2c/Kconfig" | 109 | source "drivers/gpu/drm/i2c/Kconfig" |
110 | 110 | ||
111 | config DRM_TDFX | ||
112 | tristate "3dfx Banshee/Voodoo3+" | ||
113 | depends on DRM && PCI | ||
114 | help | ||
115 | Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), | ||
116 | graphics card. If M is selected, the module will be called tdfx. | ||
117 | |||
118 | source "drivers/gpu/drm/arm/Kconfig" | 111 | source "drivers/gpu/drm/arm/Kconfig" |
119 | 112 | ||
120 | config DRM_R128 | ||
121 | tristate "ATI Rage 128" | ||
122 | depends on DRM && PCI | ||
123 | select FW_LOADER | ||
124 | help | ||
125 | Choose this option if you have an ATI Rage 128 graphics card. If M | ||
126 | is selected, the module will be called r128. AGP support for | ||
127 | this card is strongly suggested (unless you have a PCI version). | ||
128 | |||
129 | config DRM_RADEON | 113 | config DRM_RADEON |
130 | tristate "ATI Radeon" | 114 | tristate "ATI Radeon" |
131 | depends on DRM && PCI | 115 | depends on DRM && PCI |
@@ -166,49 +150,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig" | |||
166 | 150 | ||
167 | source "drivers/gpu/drm/nouveau/Kconfig" | 151 | source "drivers/gpu/drm/nouveau/Kconfig" |
168 | 152 | ||
169 | config DRM_I810 | ||
170 | tristate "Intel I810" | ||
171 | # !PREEMPT because of missing ioctl locking | ||
172 | depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN) | ||
173 | help | ||
174 | Choose this option if you have an Intel I810 graphics card. If M is | ||
175 | selected, the module will be called i810. AGP support is required | ||
176 | for this driver to work. | ||
177 | |||
178 | source "drivers/gpu/drm/i915/Kconfig" | 153 | source "drivers/gpu/drm/i915/Kconfig" |
179 | 154 | ||
180 | config DRM_MGA | ||
181 | tristate "Matrox g200/g400" | ||
182 | depends on DRM && PCI | ||
183 | select FW_LOADER | ||
184 | help | ||
185 | Choose this option if you have a Matrox G200, G400 or G450 graphics | ||
186 | card. If M is selected, the module will be called mga. AGP | ||
187 | support is required for this driver to work. | ||
188 | |||
189 | config DRM_SIS | ||
190 | tristate "SiS video cards" | ||
191 | depends on DRM && AGP | ||
192 | depends on FB_SIS || FB_SIS=n | ||
193 | help | ||
194 | Choose this option if you have a SiS 630 or compatible video | ||
195 | chipset. If M is selected the module will be called sis. AGP | ||
196 | support is required for this driver to work. | ||
197 | |||
198 | config DRM_VIA | ||
199 | tristate "Via unichrome video cards" | ||
200 | depends on DRM && PCI | ||
201 | help | ||
202 | Choose this option if you have a Via unichrome or compatible video | ||
203 | chipset. If M is selected the module will be called via. | ||
204 | |||
205 | config DRM_SAVAGE | ||
206 | tristate "Savage video cards" | ||
207 | depends on DRM && PCI | ||
208 | help | ||
209 | Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister | ||
210 | chipset. If M is selected the module will be called savage. | ||
211 | |||
212 | config DRM_VGEM | 155 | config DRM_VGEM |
213 | tristate "Virtual GEM provider" | 156 | tristate "Virtual GEM provider" |
214 | depends on DRM | 157 | depends on DRM |
@@ -279,3 +222,82 @@ source "drivers/gpu/drm/arc/Kconfig" | |||
279 | source "drivers/gpu/drm/hisilicon/Kconfig" | 222 | source "drivers/gpu/drm/hisilicon/Kconfig" |
280 | 223 | ||
281 | source "drivers/gpu/drm/mediatek/Kconfig" | 224 | source "drivers/gpu/drm/mediatek/Kconfig" |
225 | |||
226 | # Keep legacy drivers last | ||
227 | |||
228 | menuconfig DRM_LEGACY | ||
229 | bool "Enable legacy drivers (DANGEROUS)" | ||
230 | depends on DRM | ||
231 | depends on BROKEN | ||
232 | help | ||
233 | Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous | ||
234 | APIs to user-space, which can be used to circumvent access | ||
235 | restrictions and other security measures. For backwards compatibility | ||
236 | those drivers are still available, but their use is highly | ||
237 | inadvisable and might harm your system. | ||
238 | |||
239 | You are recommended to use the safe modeset-only drivers instead, and | ||
240 | perform 3D emulation in user-space. | ||
241 | |||
242 | Unless you have strong reasons to go rogue, say "N". | ||
243 | |||
244 | if DRM_LEGACY | ||
245 | |||
246 | config DRM_TDFX | ||
247 | tristate "3dfx Banshee/Voodoo3+" | ||
248 | depends on DRM && PCI | ||
249 | help | ||
250 | Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), | ||
251 | graphics card. If M is selected, the module will be called tdfx. | ||
252 | |||
253 | config DRM_R128 | ||
254 | tristate "ATI Rage 128" | ||
255 | depends on DRM && PCI | ||
256 | select FW_LOADER | ||
257 | help | ||
258 | Choose this option if you have an ATI Rage 128 graphics card. If M | ||
259 | is selected, the module will be called r128. AGP support for | ||
260 | this card is strongly suggested (unless you have a PCI version). | ||
261 | |||
262 | config DRM_I810 | ||
263 | tristate "Intel I810" | ||
264 | # !PREEMPT because of missing ioctl locking | ||
265 | depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN) | ||
266 | help | ||
267 | Choose this option if you have an Intel I810 graphics card. If M is | ||
268 | selected, the module will be called i810. AGP support is required | ||
269 | for this driver to work. | ||
270 | |||
271 | config DRM_MGA | ||
272 | tristate "Matrox g200/g400" | ||
273 | depends on DRM && PCI | ||
274 | select FW_LOADER | ||
275 | help | ||
276 | Choose this option if you have a Matrox G200, G400 or G450 graphics | ||
277 | card. If M is selected, the module will be called mga. AGP | ||
278 | support is required for this driver to work. | ||
279 | |||
280 | config DRM_SIS | ||
281 | tristate "SiS video cards" | ||
282 | depends on DRM && AGP | ||
283 | depends on FB_SIS || FB_SIS=n | ||
284 | help | ||
285 | Choose this option if you have a SiS 630 or compatible video | ||
286 | chipset. If M is selected the module will be called sis. AGP | ||
287 | support is required for this driver to work. | ||
288 | |||
289 | config DRM_VIA | ||
290 | tristate "Via unichrome video cards" | ||
291 | depends on DRM && PCI | ||
292 | help | ||
293 | Choose this option if you have a Via unichrome or compatible video | ||
294 | chipset. If M is selected the module will be called via. | ||
295 | |||
296 | config DRM_SAVAGE | ||
297 | tristate "Savage video cards" | ||
298 | depends on DRM && PCI | ||
299 | help | ||
300 | Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister | ||
301 | chipset. If M is selected the module will be called savage. | ||
302 | |||
303 | endif # DRM_LEGACY | ||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 4054c94a2301..439d89b25ae0 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ | |||
13 | drm_trace_points.o drm_global.o drm_prime.o \ | 13 | drm_trace_points.o drm_global.o drm_prime.o \ |
14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ | 14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ |
15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ | 15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ |
16 | drm_framebuffer.o drm_connector.o drm_blend.o | 16 | drm_framebuffer.o drm_connector.o drm_blend.o \ |
17 | drm_encoder.o drm_mode_object.o drm_property.o | ||
17 | 18 | ||
18 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
19 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | 20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o |
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 82171d223f2d..c383d724527f 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c | |||
@@ -91,7 +91,8 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) | |||
91 | 91 | ||
92 | drm_atomic_helper_commit_modeset_disables(drm, state); | 92 | drm_atomic_helper_commit_modeset_disables(drm, state); |
93 | drm_atomic_helper_commit_modeset_enables(drm, state); | 93 | drm_atomic_helper_commit_modeset_enables(drm, state); |
94 | drm_atomic_helper_commit_planes(drm, state, true); | 94 | drm_atomic_helper_commit_planes(drm, state, |
95 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
95 | 96 | ||
96 | malidp_atomic_commit_hw_done(state); | 97 | malidp_atomic_commit_hw_done(state); |
97 | 98 | ||
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index d4a3d61b7b06..8e7483d90c47 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
@@ -457,7 +457,7 @@ atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit) | |||
457 | 457 | ||
458 | /* Apply the atomic update. */ | 458 | /* Apply the atomic update. */ |
459 | drm_atomic_helper_commit_modeset_disables(dev, old_state); | 459 | drm_atomic_helper_commit_modeset_disables(dev, old_state); |
460 | drm_atomic_helper_commit_planes(dev, old_state, false); | 460 | drm_atomic_helper_commit_planes(dev, old_state, 0); |
461 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | 461 | drm_atomic_helper_commit_modeset_enables(dev, old_state); |
462 | 462 | ||
463 | drm_atomic_helper_wait_for_vblanks(dev, old_state); | 463 | drm_atomic_helper_wait_for_vblanks(dev, old_state); |
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 77ab47341658..cdf39aa3943c 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c | |||
@@ -940,10 +940,11 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) | |||
940 | */ | 940 | */ |
941 | 941 | ||
942 | /* | 942 | /* |
943 | * AVI data byte 1 differences: Colorspace in bits 4,5 rather than 5,6, | 943 | * AVI data byte 1 differences: Colorspace in bits 0,1 rather than 5,6, |
944 | * active aspect present in bit 6 rather than 4. | 944 | * scan info in bits 4,5 rather than 0,1 and active aspect present in |
945 | * bit 6 rather than 4. | ||
945 | */ | 946 | */ |
946 | val = (frame.colorspace & 3) << 4 | (frame.scan_mode & 0x3); | 947 | val = (frame.scan_mode & 3) << 4 | (frame.colorspace & 3); |
947 | if (frame.active_aspect & 15) | 948 | if (frame.active_aspect & 15) |
948 | val |= HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT; | 949 | val |= HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT; |
949 | if (frame.top_bar || frame.bottom_bar) | 950 | if (frame.top_bar || frame.bottom_bar) |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 9abe0a242f96..6fdd7ba47896 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -749,6 +749,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
749 | /* Right function depends upon target state. */ | 749 | /* Right function depends upon target state. */ |
750 | if (crtc->state->enable && funcs->prepare) | 750 | if (crtc->state->enable && funcs->prepare) |
751 | funcs->prepare(crtc); | 751 | funcs->prepare(crtc); |
752 | else if (funcs->atomic_disable) | ||
753 | funcs->atomic_disable(crtc, old_crtc_state); | ||
752 | else if (funcs->disable) | 754 | else if (funcs->disable) |
753 | funcs->disable(crtc); | 755 | funcs->disable(crtc); |
754 | else | 756 | else |
@@ -1146,7 +1148,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); | |||
1146 | * | 1148 | * |
1147 | * drm_atomic_helper_commit_modeset_enables(dev, state); | 1149 | * drm_atomic_helper_commit_modeset_enables(dev, state); |
1148 | * | 1150 | * |
1149 | * drm_atomic_helper_commit_planes(dev, state, true); | 1151 | * drm_atomic_helper_commit_planes(dev, state, |
1152 | * DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
1150 | * | 1153 | * |
1151 | * for committing the atomic update to hardware. See the kerneldoc entries for | 1154 | * for committing the atomic update to hardware. See the kerneldoc entries for |
1152 | * these three functions for more details. | 1155 | * these three functions for more details. |
@@ -1157,7 +1160,7 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state) | |||
1157 | 1160 | ||
1158 | drm_atomic_helper_commit_modeset_disables(dev, state); | 1161 | drm_atomic_helper_commit_modeset_disables(dev, state); |
1159 | 1162 | ||
1160 | drm_atomic_helper_commit_planes(dev, state, false); | 1163 | drm_atomic_helper_commit_planes(dev, state, 0); |
1161 | 1164 | ||
1162 | drm_atomic_helper_commit_modeset_enables(dev, state); | 1165 | drm_atomic_helper_commit_modeset_enables(dev, state); |
1163 | 1166 | ||
@@ -1676,7 +1679,7 @@ bool plane_crtc_active(struct drm_plane_state *state) | |||
1676 | * drm_atomic_helper_commit_planes - commit plane state | 1679 | * drm_atomic_helper_commit_planes - commit plane state |
1677 | * @dev: DRM device | 1680 | * @dev: DRM device |
1678 | * @old_state: atomic state object with old state structures | 1681 | * @old_state: atomic state object with old state structures |
1679 | * @active_only: Only commit on active CRTC if set | 1682 | * @flags: flags for committing plane state |
1680 | * | 1683 | * |
1681 | * This function commits the new plane state using the plane and atomic helper | 1684 | * This function commits the new plane state using the plane and atomic helper |
1682 | * functions for planes and crtcs. It assumes that the atomic state has already | 1685 | * 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) | |||
1696 | * most drivers don't need to be immediately notified of plane updates for a | 1699 | * most drivers don't need to be immediately notified of plane updates for a |
1697 | * disabled CRTC. | 1700 | * disabled CRTC. |
1698 | * | 1701 | * |
1699 | * Unless otherwise needed, drivers are advised to set the @active_only | 1702 | * Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in |
1700 | * parameters to true in order not to receive plane update notifications related | 1703 | * @flags in order not to receive plane update notifications related to a |
1701 | * to a disabled CRTC. This avoids the need to manually ignore plane updates in | 1704 | * disabled CRTC. This avoids the need to manually ignore plane updates in |
1702 | * driver code when the driver and/or hardware can't or just don't need to deal | 1705 | * driver code when the driver and/or hardware can't or just don't need to deal |
1703 | * with updates on disabled CRTCs, for example when supporting runtime PM. | 1706 | * with updates on disabled CRTCs, for example when supporting runtime PM. |
1704 | * | 1707 | * |
1705 | * The drm_atomic_helper_commit() default implementation only sets @active_only | 1708 | * Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant |
1706 | * to false to most closely match the behaviour of the legacy helpers. This should | 1709 | * display controllers require to disable a CRTC's planes when the CRTC is |
1707 | * not be copied blindly by drivers. | 1710 | * disabled. This function would skip the ->atomic_disable call for a plane if |
1711 | * the CRTC of the old plane state needs a modesetting operation. Of course, | ||
1712 | * the drivers need to disable the planes in their CRTC disable callbacks | ||
1713 | * since no one else would do that. | ||
1714 | * | ||
1715 | * The drm_atomic_helper_commit() default implementation doesn't set the | ||
1716 | * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers. | ||
1717 | * This should not be copied blindly by drivers. | ||
1708 | */ | 1718 | */ |
1709 | void drm_atomic_helper_commit_planes(struct drm_device *dev, | 1719 | void drm_atomic_helper_commit_planes(struct drm_device *dev, |
1710 | struct drm_atomic_state *old_state, | 1720 | struct drm_atomic_state *old_state, |
1711 | bool active_only) | 1721 | uint32_t flags) |
1712 | { | 1722 | { |
1713 | struct drm_crtc *crtc; | 1723 | struct drm_crtc *crtc; |
1714 | struct drm_crtc_state *old_crtc_state; | 1724 | struct drm_crtc_state *old_crtc_state; |
1715 | struct drm_plane *plane; | 1725 | struct drm_plane *plane; |
1716 | struct drm_plane_state *old_plane_state; | 1726 | struct drm_plane_state *old_plane_state; |
1717 | int i; | 1727 | int i; |
1728 | bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY; | ||
1729 | bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET; | ||
1718 | 1730 | ||
1719 | for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { | 1731 | for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { |
1720 | const struct drm_crtc_helper_funcs *funcs; | 1732 | const struct drm_crtc_helper_funcs *funcs; |
@@ -1758,10 +1770,19 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, | |||
1758 | /* | 1770 | /* |
1759 | * Special-case disabling the plane if drivers support it. | 1771 | * Special-case disabling the plane if drivers support it. |
1760 | */ | 1772 | */ |
1761 | if (disabling && funcs->atomic_disable) | 1773 | if (disabling && funcs->atomic_disable) { |
1774 | struct drm_crtc_state *crtc_state; | ||
1775 | |||
1776 | crtc_state = old_plane_state->crtc->state; | ||
1777 | |||
1778 | if (drm_atomic_crtc_needs_modeset(crtc_state) && | ||
1779 | no_disable) | ||
1780 | continue; | ||
1781 | |||
1762 | funcs->atomic_disable(plane, old_plane_state); | 1782 | funcs->atomic_disable(plane, old_plane_state); |
1763 | else if (plane->state->crtc || disabling) | 1783 | } else if (plane->state->crtc || disabling) { |
1764 | funcs->atomic_update(plane, old_plane_state); | 1784 | funcs->atomic_update(plane, old_plane_state); |
1785 | } | ||
1765 | } | 1786 | } |
1766 | 1787 | ||
1767 | for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { | 1788 | 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); | |||
1840 | 1861 | ||
1841 | /** | 1862 | /** |
1842 | * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes | 1863 | * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes |
1843 | * @crtc: CRTC | 1864 | * @old_crtc_state: atomic state object with the old CRTC state |
1844 | * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks | 1865 | * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks |
1845 | * | 1866 | * |
1846 | * Disables all planes associated with the given CRTC. This can be | 1867 | * Disables all planes associated with the given CRTC. This can be |
1847 | * used for instance in the CRTC helper disable callback to disable | 1868 | * used for instance in the CRTC helper atomic_disable callback to disable |
1848 | * all planes before shutting down the display pipeline. | 1869 | * all planes. |
1849 | * | 1870 | * |
1850 | * If the atomic-parameter is set the function calls the CRTC's | 1871 | * If the atomic-parameter is set the function calls the CRTC's |
1851 | * atomic_begin hook before and atomic_flush hook after disabling the | 1872 | * atomic_begin hook before and atomic_flush hook after disabling the |
@@ -1854,9 +1875,11 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc); | |||
1854 | * It is a bug to call this function without having implemented the | 1875 | * It is a bug to call this function without having implemented the |
1855 | * ->atomic_disable() plane hook. | 1876 | * ->atomic_disable() plane hook. |
1856 | */ | 1877 | */ |
1857 | void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, | 1878 | void |
1858 | bool atomic) | 1879 | drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state, |
1880 | bool atomic) | ||
1859 | { | 1881 | { |
1882 | struct drm_crtc *crtc = old_crtc_state->crtc; | ||
1860 | const struct drm_crtc_helper_funcs *crtc_funcs = | 1883 | const struct drm_crtc_helper_funcs *crtc_funcs = |
1861 | crtc->helper_private; | 1884 | crtc->helper_private; |
1862 | struct drm_plane *plane; | 1885 | struct drm_plane *plane; |
@@ -1864,11 +1887,11 @@ void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, | |||
1864 | if (atomic && crtc_funcs && crtc_funcs->atomic_begin) | 1887 | if (atomic && crtc_funcs && crtc_funcs->atomic_begin) |
1865 | crtc_funcs->atomic_begin(crtc, NULL); | 1888 | crtc_funcs->atomic_begin(crtc, NULL); |
1866 | 1889 | ||
1867 | drm_for_each_plane(plane, crtc->dev) { | 1890 | drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) { |
1868 | const struct drm_plane_helper_funcs *plane_funcs = | 1891 | const struct drm_plane_helper_funcs *plane_funcs = |
1869 | plane->helper_private; | 1892 | plane->helper_private; |
1870 | 1893 | ||
1871 | if (plane->state->crtc != crtc || !plane_funcs) | 1894 | if (!plane_funcs) |
1872 | continue; | 1895 | continue; |
1873 | 1896 | ||
1874 | WARN_ON(!plane_funcs->atomic_disable); | 1897 | WARN_ON(!plane_funcs->atomic_disable); |
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 255543086590..484046664d6c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c | |||
@@ -98,11 +98,11 @@ EXPORT_SYMBOL(drm_bridge_remove); | |||
98 | * @dev: DRM device | 98 | * @dev: DRM device |
99 | * @bridge: bridge control structure | 99 | * @bridge: bridge control structure |
100 | * | 100 | * |
101 | * called by a kms driver to link one of our encoder/bridge to the given | 101 | * Called by a kms driver to link one of our encoder/bridge to the given |
102 | * bridge. | 102 | * bridge. |
103 | * | 103 | * |
104 | * Note that setting up links between the bridge and our encoder/bridge | 104 | * Note that setting up links between the bridge and our encoder/bridge |
105 | * objects needs to be handled by the kms driver itself | 105 | * objects needs to be handled by the kms driver itself. |
106 | * | 106 | * |
107 | * RETURNS: | 107 | * RETURNS: |
108 | * Zero on success, error code on failure | 108 | * Zero on success, error code on failure |
@@ -125,6 +125,31 @@ int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge) | |||
125 | EXPORT_SYMBOL(drm_bridge_attach); | 125 | EXPORT_SYMBOL(drm_bridge_attach); |
126 | 126 | ||
127 | /** | 127 | /** |
128 | * drm_bridge_detach - deassociate given bridge from its DRM device | ||
129 | * | ||
130 | * @bridge: bridge control structure | ||
131 | * | ||
132 | * Called by a kms driver to unlink the given bridge from its DRM device. | ||
133 | * | ||
134 | * Note that tearing down links between the bridge and our encoder/bridge | ||
135 | * objects needs to be handled by the kms driver itself. | ||
136 | */ | ||
137 | void drm_bridge_detach(struct drm_bridge *bridge) | ||
138 | { | ||
139 | if (WARN_ON(!bridge)) | ||
140 | return; | ||
141 | |||
142 | if (WARN_ON(!bridge->dev)) | ||
143 | return; | ||
144 | |||
145 | if (bridge->funcs->detach) | ||
146 | bridge->funcs->detach(bridge); | ||
147 | |||
148 | bridge->dev = NULL; | ||
149 | } | ||
150 | EXPORT_SYMBOL(drm_bridge_detach); | ||
151 | |||
152 | /** | ||
128 | * DOC: bridge callbacks | 153 | * DOC: bridge callbacks |
129 | * | 154 | * |
130 | * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM | 155 | * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7b21281c4b78..a33dab27bb0d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -54,177 +54,9 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { | |||
54 | { DRM_PLANE_TYPE_CURSOR, "Cursor" }, | 54 | { DRM_PLANE_TYPE_CURSOR, "Cursor" }, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static const struct drm_prop_enum_list drm_encoder_enum_list[] = { | ||
58 | { DRM_MODE_ENCODER_NONE, "None" }, | ||
59 | { DRM_MODE_ENCODER_DAC, "DAC" }, | ||
60 | { DRM_MODE_ENCODER_TMDS, "TMDS" }, | ||
61 | { DRM_MODE_ENCODER_LVDS, "LVDS" }, | ||
62 | { DRM_MODE_ENCODER_TVDAC, "TV" }, | ||
63 | { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, | ||
64 | { DRM_MODE_ENCODER_DSI, "DSI" }, | ||
65 | { DRM_MODE_ENCODER_DPMST, "DP MST" }, | ||
66 | { DRM_MODE_ENCODER_DPI, "DPI" }, | ||
67 | }; | ||
68 | |||
69 | /* | 57 | /* |
70 | * Optional properties | 58 | * Optional properties |
71 | */ | 59 | */ |
72 | /* | ||
73 | * Internal function to assign a slot in the object idr and optionally | ||
74 | * register the object into the idr. | ||
75 | */ | ||
76 | int drm_mode_object_get_reg(struct drm_device *dev, | ||
77 | struct drm_mode_object *obj, | ||
78 | uint32_t obj_type, | ||
79 | bool register_obj, | ||
80 | void (*obj_free_cb)(struct kref *kref)) | ||
81 | { | ||
82 | int ret; | ||
83 | |||
84 | mutex_lock(&dev->mode_config.idr_mutex); | ||
85 | ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); | ||
86 | if (ret >= 0) { | ||
87 | /* | ||
88 | * Set up the object linking under the protection of the idr | ||
89 | * lock so that other users can't see inconsistent state. | ||
90 | */ | ||
91 | obj->id = ret; | ||
92 | obj->type = obj_type; | ||
93 | if (obj_free_cb) { | ||
94 | obj->free_cb = obj_free_cb; | ||
95 | kref_init(&obj->refcount); | ||
96 | } | ||
97 | } | ||
98 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
99 | |||
100 | return ret < 0 ? ret : 0; | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * drm_mode_object_get - allocate a new modeset identifier | ||
105 | * @dev: DRM device | ||
106 | * @obj: object pointer, used to generate unique ID | ||
107 | * @obj_type: object type | ||
108 | * | ||
109 | * Create a unique identifier based on @ptr in @dev's identifier space. Used | ||
110 | * for tracking modes, CRTCs and connectors. Note that despite the _get postfix | ||
111 | * modeset identifiers are _not_ reference counted. Hence don't use this for | ||
112 | * reference counted modeset objects like framebuffers. | ||
113 | * | ||
114 | * Returns: | ||
115 | * Zero on success, error code on failure. | ||
116 | */ | ||
117 | int drm_mode_object_get(struct drm_device *dev, | ||
118 | struct drm_mode_object *obj, uint32_t obj_type) | ||
119 | { | ||
120 | return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); | ||
121 | } | ||
122 | |||
123 | void drm_mode_object_register(struct drm_device *dev, | ||
124 | struct drm_mode_object *obj) | ||
125 | { | ||
126 | mutex_lock(&dev->mode_config.idr_mutex); | ||
127 | idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); | ||
128 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * drm_mode_object_unregister - free a modeset identifer | ||
133 | * @dev: DRM device | ||
134 | * @object: object to free | ||
135 | * | ||
136 | * Free @id from @dev's unique identifier pool. | ||
137 | * This function can be called multiple times, and guards against | ||
138 | * multiple removals. | ||
139 | * These modeset identifiers are _not_ reference counted. Hence don't use this | ||
140 | * for reference counted modeset objects like framebuffers. | ||
141 | */ | ||
142 | void drm_mode_object_unregister(struct drm_device *dev, | ||
143 | struct drm_mode_object *object) | ||
144 | { | ||
145 | mutex_lock(&dev->mode_config.idr_mutex); | ||
146 | if (object->id) { | ||
147 | idr_remove(&dev->mode_config.crtc_idr, object->id); | ||
148 | object->id = 0; | ||
149 | } | ||
150 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
151 | } | ||
152 | |||
153 | struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, | ||
154 | uint32_t id, uint32_t type) | ||
155 | { | ||
156 | struct drm_mode_object *obj = NULL; | ||
157 | |||
158 | mutex_lock(&dev->mode_config.idr_mutex); | ||
159 | obj = idr_find(&dev->mode_config.crtc_idr, id); | ||
160 | if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) | ||
161 | obj = NULL; | ||
162 | if (obj && obj->id != id) | ||
163 | obj = NULL; | ||
164 | |||
165 | if (obj && obj->free_cb) { | ||
166 | if (!kref_get_unless_zero(&obj->refcount)) | ||
167 | obj = NULL; | ||
168 | } | ||
169 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
170 | |||
171 | return obj; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * drm_mode_object_find - look up a drm object with static lifetime | ||
176 | * @dev: drm device | ||
177 | * @id: id of the mode object | ||
178 | * @type: type of the mode object | ||
179 | * | ||
180 | * This function is used to look up a modeset object. It will acquire a | ||
181 | * reference for reference counted objects. This reference must be dropped again | ||
182 | * by callind drm_mode_object_unreference(). | ||
183 | */ | ||
184 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | ||
185 | uint32_t id, uint32_t type) | ||
186 | { | ||
187 | struct drm_mode_object *obj = NULL; | ||
188 | |||
189 | obj = __drm_mode_object_find(dev, id, type); | ||
190 | return obj; | ||
191 | } | ||
192 | EXPORT_SYMBOL(drm_mode_object_find); | ||
193 | |||
194 | /** | ||
195 | * drm_mode_object_unreference - decr the object refcnt | ||
196 | * @obj: mode_object | ||
197 | * | ||
198 | * This functions decrements the object's refcount if it is a refcounted modeset | ||
199 | * object. It is a no-op on any other object. This is used to drop references | ||
200 | * acquired with drm_mode_object_reference(). | ||
201 | */ | ||
202 | void drm_mode_object_unreference(struct drm_mode_object *obj) | ||
203 | { | ||
204 | if (obj->free_cb) { | ||
205 | DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); | ||
206 | kref_put(&obj->refcount, obj->free_cb); | ||
207 | } | ||
208 | } | ||
209 | EXPORT_SYMBOL(drm_mode_object_unreference); | ||
210 | |||
211 | /** | ||
212 | * drm_mode_object_reference - incr the object refcnt | ||
213 | * @obj: mode_object | ||
214 | * | ||
215 | * This functions increments the object's refcount if it is a refcounted modeset | ||
216 | * object. It is a no-op on any other object. References should be dropped again | ||
217 | * by calling drm_mode_object_unreference(). | ||
218 | */ | ||
219 | void drm_mode_object_reference(struct drm_mode_object *obj) | ||
220 | { | ||
221 | if (obj->free_cb) { | ||
222 | DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); | ||
223 | kref_get(&obj->refcount); | ||
224 | } | ||
225 | } | ||
226 | EXPORT_SYMBOL(drm_mode_object_reference); | ||
227 | |||
228 | /** | 60 | /** |
229 | * drm_crtc_force_disable - Forcibly turn off a CRTC | 61 | * drm_crtc_force_disable - Forcibly turn off a CRTC |
230 | * @crtc: CRTC to turn off | 62 | * @crtc: CRTC to turn off |
@@ -419,117 +251,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) | |||
419 | } | 251 | } |
420 | EXPORT_SYMBOL(drm_crtc_cleanup); | 252 | EXPORT_SYMBOL(drm_crtc_cleanup); |
421 | 253 | ||
422 | static int drm_encoder_register_all(struct drm_device *dev) | ||
423 | { | ||
424 | struct drm_encoder *encoder; | ||
425 | int ret = 0; | ||
426 | |||
427 | drm_for_each_encoder(encoder, dev) { | ||
428 | if (encoder->funcs->late_register) | ||
429 | ret = encoder->funcs->late_register(encoder); | ||
430 | if (ret) | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static void drm_encoder_unregister_all(struct drm_device *dev) | ||
438 | { | ||
439 | struct drm_encoder *encoder; | ||
440 | |||
441 | drm_for_each_encoder(encoder, dev) { | ||
442 | if (encoder->funcs->early_unregister) | ||
443 | encoder->funcs->early_unregister(encoder); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * drm_encoder_init - Init a preallocated encoder | ||
449 | * @dev: drm device | ||
450 | * @encoder: the encoder to init | ||
451 | * @funcs: callbacks for this encoder | ||
452 | * @encoder_type: user visible type of the encoder | ||
453 | * @name: printf style format string for the encoder name, or NULL for default name | ||
454 | * | ||
455 | * Initialises a preallocated encoder. Encoder should be | ||
456 | * subclassed as part of driver encoder objects. | ||
457 | * | ||
458 | * Returns: | ||
459 | * Zero on success, error code on failure. | ||
460 | */ | ||
461 | int drm_encoder_init(struct drm_device *dev, | ||
462 | struct drm_encoder *encoder, | ||
463 | const struct drm_encoder_funcs *funcs, | ||
464 | int encoder_type, const char *name, ...) | ||
465 | { | ||
466 | int ret; | ||
467 | |||
468 | drm_modeset_lock_all(dev); | ||
469 | |||
470 | ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); | ||
471 | if (ret) | ||
472 | goto out_unlock; | ||
473 | |||
474 | encoder->dev = dev; | ||
475 | encoder->encoder_type = encoder_type; | ||
476 | encoder->funcs = funcs; | ||
477 | if (name) { | ||
478 | va_list ap; | ||
479 | |||
480 | va_start(ap, name); | ||
481 | encoder->name = kvasprintf(GFP_KERNEL, name, ap); | ||
482 | va_end(ap); | ||
483 | } else { | ||
484 | encoder->name = kasprintf(GFP_KERNEL, "%s-%d", | ||
485 | drm_encoder_enum_list[encoder_type].name, | ||
486 | encoder->base.id); | ||
487 | } | ||
488 | if (!encoder->name) { | ||
489 | ret = -ENOMEM; | ||
490 | goto out_put; | ||
491 | } | ||
492 | |||
493 | list_add_tail(&encoder->head, &dev->mode_config.encoder_list); | ||
494 | encoder->index = dev->mode_config.num_encoder++; | ||
495 | |||
496 | out_put: | ||
497 | if (ret) | ||
498 | drm_mode_object_unregister(dev, &encoder->base); | ||
499 | |||
500 | out_unlock: | ||
501 | drm_modeset_unlock_all(dev); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | EXPORT_SYMBOL(drm_encoder_init); | ||
506 | |||
507 | /** | ||
508 | * drm_encoder_cleanup - cleans up an initialised encoder | ||
509 | * @encoder: encoder to cleanup | ||
510 | * | ||
511 | * Cleans up the encoder but doesn't free the object. | ||
512 | */ | ||
513 | void drm_encoder_cleanup(struct drm_encoder *encoder) | ||
514 | { | ||
515 | struct drm_device *dev = encoder->dev; | ||
516 | |||
517 | /* Note that the encoder_list is considered to be static; should we | ||
518 | * remove the drm_encoder at runtime we would have to decrement all | ||
519 | * the indices on the drm_encoder after us in the encoder_list. | ||
520 | */ | ||
521 | |||
522 | drm_modeset_lock_all(dev); | ||
523 | drm_mode_object_unregister(dev, &encoder->base); | ||
524 | kfree(encoder->name); | ||
525 | list_del(&encoder->head); | ||
526 | dev->mode_config.num_encoder--; | ||
527 | drm_modeset_unlock_all(dev); | ||
528 | |||
529 | memset(encoder, 0, sizeof(*encoder)); | ||
530 | } | ||
531 | EXPORT_SYMBOL(drm_encoder_cleanup); | ||
532 | |||
533 | static unsigned int drm_num_planes(struct drm_device *dev) | 254 | static unsigned int drm_num_planes(struct drm_device *dev) |
534 | { | 255 | { |
535 | unsigned int num = 0; | 256 | unsigned int num = 0; |
@@ -1133,115 +854,6 @@ int drm_mode_getcrtc(struct drm_device *dev, | |||
1133 | return 0; | 854 | return 0; |
1134 | } | 855 | } |
1135 | 856 | ||
1136 | /* helper for getconnector and getproperties ioctls */ | ||
1137 | int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, | ||
1138 | uint32_t __user *prop_ptr, | ||
1139 | uint64_t __user *prop_values, | ||
1140 | uint32_t *arg_count_props) | ||
1141 | { | ||
1142 | int props_count; | ||
1143 | int i, ret, copied; | ||
1144 | |||
1145 | props_count = obj->properties->count; | ||
1146 | if (!atomic) | ||
1147 | props_count -= obj->properties->atomic_count; | ||
1148 | |||
1149 | if ((*arg_count_props >= props_count) && props_count) { | ||
1150 | for (i = 0, copied = 0; copied < props_count; i++) { | ||
1151 | struct drm_property *prop = obj->properties->properties[i]; | ||
1152 | uint64_t val; | ||
1153 | |||
1154 | if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) | ||
1155 | continue; | ||
1156 | |||
1157 | ret = drm_object_property_get_value(obj, prop, &val); | ||
1158 | if (ret) | ||
1159 | return ret; | ||
1160 | |||
1161 | if (put_user(prop->base.id, prop_ptr + copied)) | ||
1162 | return -EFAULT; | ||
1163 | |||
1164 | if (put_user(val, prop_values + copied)) | ||
1165 | return -EFAULT; | ||
1166 | |||
1167 | copied++; | ||
1168 | } | ||
1169 | } | ||
1170 | *arg_count_props = props_count; | ||
1171 | |||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) | ||
1176 | { | ||
1177 | struct drm_connector *connector; | ||
1178 | struct drm_device *dev = encoder->dev; | ||
1179 | bool uses_atomic = false; | ||
1180 | |||
1181 | /* For atomic drivers only state objects are synchronously updated and | ||
1182 | * protected by modeset locks, so check those first. */ | ||
1183 | drm_for_each_connector(connector, dev) { | ||
1184 | if (!connector->state) | ||
1185 | continue; | ||
1186 | |||
1187 | uses_atomic = true; | ||
1188 | |||
1189 | if (connector->state->best_encoder != encoder) | ||
1190 | continue; | ||
1191 | |||
1192 | return connector->state->crtc; | ||
1193 | } | ||
1194 | |||
1195 | /* Don't return stale data (e.g. pending async disable). */ | ||
1196 | if (uses_atomic) | ||
1197 | return NULL; | ||
1198 | |||
1199 | return encoder->crtc; | ||
1200 | } | ||
1201 | |||
1202 | /** | ||
1203 | * drm_mode_getencoder - get encoder configuration | ||
1204 | * @dev: drm device for the ioctl | ||
1205 | * @data: data pointer for the ioctl | ||
1206 | * @file_priv: drm file for the ioctl call | ||
1207 | * | ||
1208 | * Construct a encoder configuration structure to return to the user. | ||
1209 | * | ||
1210 | * Called by the user via ioctl. | ||
1211 | * | ||
1212 | * Returns: | ||
1213 | * Zero on success, negative errno on failure. | ||
1214 | */ | ||
1215 | int drm_mode_getencoder(struct drm_device *dev, void *data, | ||
1216 | struct drm_file *file_priv) | ||
1217 | { | ||
1218 | struct drm_mode_get_encoder *enc_resp = data; | ||
1219 | struct drm_encoder *encoder; | ||
1220 | struct drm_crtc *crtc; | ||
1221 | |||
1222 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1223 | return -EINVAL; | ||
1224 | |||
1225 | encoder = drm_encoder_find(dev, enc_resp->encoder_id); | ||
1226 | if (!encoder) | ||
1227 | return -ENOENT; | ||
1228 | |||
1229 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
1230 | crtc = drm_encoder_get_crtc(encoder); | ||
1231 | if (crtc) | ||
1232 | enc_resp->crtc_id = crtc->base.id; | ||
1233 | else | ||
1234 | enc_resp->crtc_id = 0; | ||
1235 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
1236 | |||
1237 | enc_resp->encoder_type = encoder->encoder_type; | ||
1238 | enc_resp->encoder_id = encoder->base.id; | ||
1239 | enc_resp->possible_crtcs = encoder->possible_crtcs; | ||
1240 | enc_resp->possible_clones = encoder->possible_clones; | ||
1241 | |||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | /** | 857 | /** |
1246 | * drm_mode_getplane_res - enumerate all plane resources | 858 | * drm_mode_getplane_res - enumerate all plane resources |
1247 | * @dev: DRM device | 859 | * @dev: DRM device |
@@ -2059,1077 +1671,9 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev, | |||
2059 | return drm_mode_cursor_common(dev, req, file_priv); | 1671 | return drm_mode_cursor_common(dev, req, file_priv); |
2060 | } | 1672 | } |
2061 | 1673 | ||
2062 | /** | 1674 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, |
2063 | * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description | 1675 | struct drm_property *property, |
2064 | * @bpp: bits per pixels | 1676 | uint64_t value) |
2065 | * @depth: bit depth per pixel | ||
2066 | * | ||
2067 | * Computes a drm fourcc pixel format code for the given @bpp/@depth values. | ||
2068 | * Useful in fbdev emulation code, since that deals in those values. | ||
2069 | */ | ||
2070 | uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) | ||
2071 | { | ||
2072 | uint32_t fmt; | ||
2073 | |||
2074 | switch (bpp) { | ||
2075 | case 8: | ||
2076 | fmt = DRM_FORMAT_C8; | ||
2077 | break; | ||
2078 | case 16: | ||
2079 | if (depth == 15) | ||
2080 | fmt = DRM_FORMAT_XRGB1555; | ||
2081 | else | ||
2082 | fmt = DRM_FORMAT_RGB565; | ||
2083 | break; | ||
2084 | case 24: | ||
2085 | fmt = DRM_FORMAT_RGB888; | ||
2086 | break; | ||
2087 | case 32: | ||
2088 | if (depth == 24) | ||
2089 | fmt = DRM_FORMAT_XRGB8888; | ||
2090 | else if (depth == 30) | ||
2091 | fmt = DRM_FORMAT_XRGB2101010; | ||
2092 | else | ||
2093 | fmt = DRM_FORMAT_ARGB8888; | ||
2094 | break; | ||
2095 | default: | ||
2096 | DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); | ||
2097 | fmt = DRM_FORMAT_XRGB8888; | ||
2098 | break; | ||
2099 | } | ||
2100 | |||
2101 | return fmt; | ||
2102 | } | ||
2103 | EXPORT_SYMBOL(drm_mode_legacy_fb_format); | ||
2104 | |||
2105 | static bool drm_property_type_valid(struct drm_property *property) | ||
2106 | { | ||
2107 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
2108 | return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
2109 | return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
2110 | } | ||
2111 | |||
2112 | /** | ||
2113 | * drm_property_create - create a new property type | ||
2114 | * @dev: drm device | ||
2115 | * @flags: flags specifying the property type | ||
2116 | * @name: name of the property | ||
2117 | * @num_values: number of pre-defined values | ||
2118 | * | ||
2119 | * This creates a new generic drm property which can then be attached to a drm | ||
2120 | * object with drm_object_attach_property. The returned property object must be | ||
2121 | * freed with drm_property_destroy. | ||
2122 | * | ||
2123 | * Note that the DRM core keeps a per-device list of properties and that, if | ||
2124 | * drm_mode_config_cleanup() is called, it will destroy all properties created | ||
2125 | * by the driver. | ||
2126 | * | ||
2127 | * Returns: | ||
2128 | * A pointer to the newly created property on success, NULL on failure. | ||
2129 | */ | ||
2130 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
2131 | const char *name, int num_values) | ||
2132 | { | ||
2133 | struct drm_property *property = NULL; | ||
2134 | int ret; | ||
2135 | |||
2136 | property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); | ||
2137 | if (!property) | ||
2138 | return NULL; | ||
2139 | |||
2140 | property->dev = dev; | ||
2141 | |||
2142 | if (num_values) { | ||
2143 | property->values = kcalloc(num_values, sizeof(uint64_t), | ||
2144 | GFP_KERNEL); | ||
2145 | if (!property->values) | ||
2146 | goto fail; | ||
2147 | } | ||
2148 | |||
2149 | ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); | ||
2150 | if (ret) | ||
2151 | goto fail; | ||
2152 | |||
2153 | property->flags = flags; | ||
2154 | property->num_values = num_values; | ||
2155 | INIT_LIST_HEAD(&property->enum_list); | ||
2156 | |||
2157 | if (name) { | ||
2158 | strncpy(property->name, name, DRM_PROP_NAME_LEN); | ||
2159 | property->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
2160 | } | ||
2161 | |||
2162 | list_add_tail(&property->head, &dev->mode_config.property_list); | ||
2163 | |||
2164 | WARN_ON(!drm_property_type_valid(property)); | ||
2165 | |||
2166 | return property; | ||
2167 | fail: | ||
2168 | kfree(property->values); | ||
2169 | kfree(property); | ||
2170 | return NULL; | ||
2171 | } | ||
2172 | EXPORT_SYMBOL(drm_property_create); | ||
2173 | |||
2174 | /** | ||
2175 | * drm_property_create_enum - create a new enumeration property type | ||
2176 | * @dev: drm device | ||
2177 | * @flags: flags specifying the property type | ||
2178 | * @name: name of the property | ||
2179 | * @props: enumeration lists with property values | ||
2180 | * @num_values: number of pre-defined values | ||
2181 | * | ||
2182 | * This creates a new generic drm property which can then be attached to a drm | ||
2183 | * object with drm_object_attach_property. The returned property object must be | ||
2184 | * freed with drm_property_destroy. | ||
2185 | * | ||
2186 | * Userspace is only allowed to set one of the predefined values for enumeration | ||
2187 | * properties. | ||
2188 | * | ||
2189 | * Returns: | ||
2190 | * A pointer to the newly created property on success, NULL on failure. | ||
2191 | */ | ||
2192 | struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
2193 | const char *name, | ||
2194 | const struct drm_prop_enum_list *props, | ||
2195 | int num_values) | ||
2196 | { | ||
2197 | struct drm_property *property; | ||
2198 | int i, ret; | ||
2199 | |||
2200 | flags |= DRM_MODE_PROP_ENUM; | ||
2201 | |||
2202 | property = drm_property_create(dev, flags, name, num_values); | ||
2203 | if (!property) | ||
2204 | return NULL; | ||
2205 | |||
2206 | for (i = 0; i < num_values; i++) { | ||
2207 | ret = drm_property_add_enum(property, i, | ||
2208 | props[i].type, | ||
2209 | props[i].name); | ||
2210 | if (ret) { | ||
2211 | drm_property_destroy(dev, property); | ||
2212 | return NULL; | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | return property; | ||
2217 | } | ||
2218 | EXPORT_SYMBOL(drm_property_create_enum); | ||
2219 | |||
2220 | /** | ||
2221 | * drm_property_create_bitmask - create a new bitmask property type | ||
2222 | * @dev: drm device | ||
2223 | * @flags: flags specifying the property type | ||
2224 | * @name: name of the property | ||
2225 | * @props: enumeration lists with property bitflags | ||
2226 | * @num_props: size of the @props array | ||
2227 | * @supported_bits: bitmask of all supported enumeration values | ||
2228 | * | ||
2229 | * This creates a new bitmask drm property which can then be attached to a drm | ||
2230 | * object with drm_object_attach_property. The returned property object must be | ||
2231 | * freed with drm_property_destroy. | ||
2232 | * | ||
2233 | * Compared to plain enumeration properties userspace is allowed to set any | ||
2234 | * or'ed together combination of the predefined property bitflag values | ||
2235 | * | ||
2236 | * Returns: | ||
2237 | * A pointer to the newly created property on success, NULL on failure. | ||
2238 | */ | ||
2239 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
2240 | int flags, const char *name, | ||
2241 | const struct drm_prop_enum_list *props, | ||
2242 | int num_props, | ||
2243 | uint64_t supported_bits) | ||
2244 | { | ||
2245 | struct drm_property *property; | ||
2246 | int i, ret, index = 0; | ||
2247 | int num_values = hweight64(supported_bits); | ||
2248 | |||
2249 | flags |= DRM_MODE_PROP_BITMASK; | ||
2250 | |||
2251 | property = drm_property_create(dev, flags, name, num_values); | ||
2252 | if (!property) | ||
2253 | return NULL; | ||
2254 | for (i = 0; i < num_props; i++) { | ||
2255 | if (!(supported_bits & (1ULL << props[i].type))) | ||
2256 | continue; | ||
2257 | |||
2258 | if (WARN_ON(index >= num_values)) { | ||
2259 | drm_property_destroy(dev, property); | ||
2260 | return NULL; | ||
2261 | } | ||
2262 | |||
2263 | ret = drm_property_add_enum(property, index++, | ||
2264 | props[i].type, | ||
2265 | props[i].name); | ||
2266 | if (ret) { | ||
2267 | drm_property_destroy(dev, property); | ||
2268 | return NULL; | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | return property; | ||
2273 | } | ||
2274 | EXPORT_SYMBOL(drm_property_create_bitmask); | ||
2275 | |||
2276 | static struct drm_property *property_create_range(struct drm_device *dev, | ||
2277 | int flags, const char *name, | ||
2278 | uint64_t min, uint64_t max) | ||
2279 | { | ||
2280 | struct drm_property *property; | ||
2281 | |||
2282 | property = drm_property_create(dev, flags, name, 2); | ||
2283 | if (!property) | ||
2284 | return NULL; | ||
2285 | |||
2286 | property->values[0] = min; | ||
2287 | property->values[1] = max; | ||
2288 | |||
2289 | return property; | ||
2290 | } | ||
2291 | |||
2292 | /** | ||
2293 | * drm_property_create_range - create a new unsigned ranged property type | ||
2294 | * @dev: drm device | ||
2295 | * @flags: flags specifying the property type | ||
2296 | * @name: name of the property | ||
2297 | * @min: minimum value of the property | ||
2298 | * @max: maximum value of the property | ||
2299 | * | ||
2300 | * This creates a new generic drm property which can then be attached to a drm | ||
2301 | * object with drm_object_attach_property. The returned property object must be | ||
2302 | * freed with drm_property_destroy. | ||
2303 | * | ||
2304 | * Userspace is allowed to set any unsigned integer value in the (min, max) | ||
2305 | * range inclusive. | ||
2306 | * | ||
2307 | * Returns: | ||
2308 | * A pointer to the newly created property on success, NULL on failure. | ||
2309 | */ | ||
2310 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
2311 | const char *name, | ||
2312 | uint64_t min, uint64_t max) | ||
2313 | { | ||
2314 | return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, | ||
2315 | name, min, max); | ||
2316 | } | ||
2317 | EXPORT_SYMBOL(drm_property_create_range); | ||
2318 | |||
2319 | /** | ||
2320 | * drm_property_create_signed_range - create a new signed ranged property type | ||
2321 | * @dev: drm device | ||
2322 | * @flags: flags specifying the property type | ||
2323 | * @name: name of the property | ||
2324 | * @min: minimum value of the property | ||
2325 | * @max: maximum value of the property | ||
2326 | * | ||
2327 | * This creates a new generic drm property which can then be attached to a drm | ||
2328 | * object with drm_object_attach_property. The returned property object must be | ||
2329 | * freed with drm_property_destroy. | ||
2330 | * | ||
2331 | * Userspace is allowed to set any signed integer value in the (min, max) | ||
2332 | * range inclusive. | ||
2333 | * | ||
2334 | * Returns: | ||
2335 | * A pointer to the newly created property on success, NULL on failure. | ||
2336 | */ | ||
2337 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
2338 | int flags, const char *name, | ||
2339 | int64_t min, int64_t max) | ||
2340 | { | ||
2341 | return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, | ||
2342 | name, I642U64(min), I642U64(max)); | ||
2343 | } | ||
2344 | EXPORT_SYMBOL(drm_property_create_signed_range); | ||
2345 | |||
2346 | /** | ||
2347 | * drm_property_create_object - create a new object property type | ||
2348 | * @dev: drm device | ||
2349 | * @flags: flags specifying the property type | ||
2350 | * @name: name of the property | ||
2351 | * @type: object type from DRM_MODE_OBJECT_* defines | ||
2352 | * | ||
2353 | * This creates a new generic drm property which can then be attached to a drm | ||
2354 | * object with drm_object_attach_property. The returned property object must be | ||
2355 | * freed with drm_property_destroy. | ||
2356 | * | ||
2357 | * Userspace is only allowed to set this to any property value of the given | ||
2358 | * @type. Only useful for atomic properties, which is enforced. | ||
2359 | * | ||
2360 | * Returns: | ||
2361 | * A pointer to the newly created property on success, NULL on failure. | ||
2362 | */ | ||
2363 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
2364 | int flags, const char *name, uint32_t type) | ||
2365 | { | ||
2366 | struct drm_property *property; | ||
2367 | |||
2368 | flags |= DRM_MODE_PROP_OBJECT; | ||
2369 | |||
2370 | if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) | ||
2371 | return NULL; | ||
2372 | |||
2373 | property = drm_property_create(dev, flags, name, 1); | ||
2374 | if (!property) | ||
2375 | return NULL; | ||
2376 | |||
2377 | property->values[0] = type; | ||
2378 | |||
2379 | return property; | ||
2380 | } | ||
2381 | EXPORT_SYMBOL(drm_property_create_object); | ||
2382 | |||
2383 | /** | ||
2384 | * drm_property_create_bool - create a new boolean property type | ||
2385 | * @dev: drm device | ||
2386 | * @flags: flags specifying the property type | ||
2387 | * @name: name of the property | ||
2388 | * | ||
2389 | * This creates a new generic drm property which can then be attached to a drm | ||
2390 | * object with drm_object_attach_property. The returned property object must be | ||
2391 | * freed with drm_property_destroy. | ||
2392 | * | ||
2393 | * This is implemented as a ranged property with only {0, 1} as valid values. | ||
2394 | * | ||
2395 | * Returns: | ||
2396 | * A pointer to the newly created property on success, NULL on failure. | ||
2397 | */ | ||
2398 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
2399 | const char *name) | ||
2400 | { | ||
2401 | return drm_property_create_range(dev, flags, name, 0, 1); | ||
2402 | } | ||
2403 | EXPORT_SYMBOL(drm_property_create_bool); | ||
2404 | |||
2405 | /** | ||
2406 | * drm_property_add_enum - add a possible value to an enumeration property | ||
2407 | * @property: enumeration property to change | ||
2408 | * @index: index of the new enumeration | ||
2409 | * @value: value of the new enumeration | ||
2410 | * @name: symbolic name of the new enumeration | ||
2411 | * | ||
2412 | * This functions adds enumerations to a property. | ||
2413 | * | ||
2414 | * It's use is deprecated, drivers should use one of the more specific helpers | ||
2415 | * to directly create the property with all enumerations already attached. | ||
2416 | * | ||
2417 | * Returns: | ||
2418 | * Zero on success, error code on failure. | ||
2419 | */ | ||
2420 | int drm_property_add_enum(struct drm_property *property, int index, | ||
2421 | uint64_t value, const char *name) | ||
2422 | { | ||
2423 | struct drm_property_enum *prop_enum; | ||
2424 | |||
2425 | if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
2426 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) | ||
2427 | return -EINVAL; | ||
2428 | |||
2429 | /* | ||
2430 | * Bitmask enum properties have the additional constraint of values | ||
2431 | * from 0 to 63 | ||
2432 | */ | ||
2433 | if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && | ||
2434 | (value > 63)) | ||
2435 | return -EINVAL; | ||
2436 | |||
2437 | if (!list_empty(&property->enum_list)) { | ||
2438 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
2439 | if (prop_enum->value == value) { | ||
2440 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
2441 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
2442 | return 0; | ||
2443 | } | ||
2444 | } | ||
2445 | } | ||
2446 | |||
2447 | prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); | ||
2448 | if (!prop_enum) | ||
2449 | return -ENOMEM; | ||
2450 | |||
2451 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
2452 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
2453 | prop_enum->value = value; | ||
2454 | |||
2455 | property->values[index] = value; | ||
2456 | list_add_tail(&prop_enum->head, &property->enum_list); | ||
2457 | return 0; | ||
2458 | } | ||
2459 | EXPORT_SYMBOL(drm_property_add_enum); | ||
2460 | |||
2461 | /** | ||
2462 | * drm_property_destroy - destroy a drm property | ||
2463 | * @dev: drm device | ||
2464 | * @property: property to destry | ||
2465 | * | ||
2466 | * This function frees a property including any attached resources like | ||
2467 | * enumeration values. | ||
2468 | */ | ||
2469 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property) | ||
2470 | { | ||
2471 | struct drm_property_enum *prop_enum, *pt; | ||
2472 | |||
2473 | list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { | ||
2474 | list_del(&prop_enum->head); | ||
2475 | kfree(prop_enum); | ||
2476 | } | ||
2477 | |||
2478 | if (property->num_values) | ||
2479 | kfree(property->values); | ||
2480 | drm_mode_object_unregister(dev, &property->base); | ||
2481 | list_del(&property->head); | ||
2482 | kfree(property); | ||
2483 | } | ||
2484 | EXPORT_SYMBOL(drm_property_destroy); | ||
2485 | |||
2486 | /** | ||
2487 | * drm_object_attach_property - attach a property to a modeset object | ||
2488 | * @obj: drm modeset object | ||
2489 | * @property: property to attach | ||
2490 | * @init_val: initial value of the property | ||
2491 | * | ||
2492 | * This attaches the given property to the modeset object with the given initial | ||
2493 | * value. Currently this function cannot fail since the properties are stored in | ||
2494 | * a statically sized array. | ||
2495 | */ | ||
2496 | void drm_object_attach_property(struct drm_mode_object *obj, | ||
2497 | struct drm_property *property, | ||
2498 | uint64_t init_val) | ||
2499 | { | ||
2500 | int count = obj->properties->count; | ||
2501 | |||
2502 | if (count == DRM_OBJECT_MAX_PROPERTY) { | ||
2503 | WARN(1, "Failed to attach object property (type: 0x%x). Please " | ||
2504 | "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " | ||
2505 | "you see this message on the same object type.\n", | ||
2506 | obj->type); | ||
2507 | return; | ||
2508 | } | ||
2509 | |||
2510 | obj->properties->properties[count] = property; | ||
2511 | obj->properties->values[count] = init_val; | ||
2512 | obj->properties->count++; | ||
2513 | if (property->flags & DRM_MODE_PROP_ATOMIC) | ||
2514 | obj->properties->atomic_count++; | ||
2515 | } | ||
2516 | EXPORT_SYMBOL(drm_object_attach_property); | ||
2517 | |||
2518 | /** | ||
2519 | * drm_object_property_set_value - set the value of a property | ||
2520 | * @obj: drm mode object to set property value for | ||
2521 | * @property: property to set | ||
2522 | * @val: value the property should be set to | ||
2523 | * | ||
2524 | * This functions sets a given property on a given object. This function only | ||
2525 | * changes the software state of the property, it does not call into the | ||
2526 | * driver's ->set_property callback. | ||
2527 | * | ||
2528 | * Returns: | ||
2529 | * Zero on success, error code on failure. | ||
2530 | */ | ||
2531 | int drm_object_property_set_value(struct drm_mode_object *obj, | ||
2532 | struct drm_property *property, uint64_t val) | ||
2533 | { | ||
2534 | int i; | ||
2535 | |||
2536 | for (i = 0; i < obj->properties->count; i++) { | ||
2537 | if (obj->properties->properties[i] == property) { | ||
2538 | obj->properties->values[i] = val; | ||
2539 | return 0; | ||
2540 | } | ||
2541 | } | ||
2542 | |||
2543 | return -EINVAL; | ||
2544 | } | ||
2545 | EXPORT_SYMBOL(drm_object_property_set_value); | ||
2546 | |||
2547 | /** | ||
2548 | * drm_object_property_get_value - retrieve the value of a property | ||
2549 | * @obj: drm mode object to get property value from | ||
2550 | * @property: property to retrieve | ||
2551 | * @val: storage for the property value | ||
2552 | * | ||
2553 | * This function retrieves the softare state of the given property for the given | ||
2554 | * property. Since there is no driver callback to retrieve the current property | ||
2555 | * value this might be out of sync with the hardware, depending upon the driver | ||
2556 | * and property. | ||
2557 | * | ||
2558 | * Returns: | ||
2559 | * Zero on success, error code on failure. | ||
2560 | */ | ||
2561 | int drm_object_property_get_value(struct drm_mode_object *obj, | ||
2562 | struct drm_property *property, uint64_t *val) | ||
2563 | { | ||
2564 | int i; | ||
2565 | |||
2566 | /* read-only properties bypass atomic mechanism and still store | ||
2567 | * their value in obj->properties->values[].. mostly to avoid | ||
2568 | * having to deal w/ EDID and similar props in atomic paths: | ||
2569 | */ | ||
2570 | if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && | ||
2571 | !(property->flags & DRM_MODE_PROP_IMMUTABLE)) | ||
2572 | return drm_atomic_get_property(obj, property, val); | ||
2573 | |||
2574 | for (i = 0; i < obj->properties->count; i++) { | ||
2575 | if (obj->properties->properties[i] == property) { | ||
2576 | *val = obj->properties->values[i]; | ||
2577 | return 0; | ||
2578 | } | ||
2579 | } | ||
2580 | |||
2581 | return -EINVAL; | ||
2582 | } | ||
2583 | EXPORT_SYMBOL(drm_object_property_get_value); | ||
2584 | |||
2585 | /** | ||
2586 | * drm_mode_getproperty_ioctl - get the property metadata | ||
2587 | * @dev: DRM device | ||
2588 | * @data: ioctl data | ||
2589 | * @file_priv: DRM file info | ||
2590 | * | ||
2591 | * This function retrieves the metadata for a given property, like the different | ||
2592 | * possible values for an enum property or the limits for a range property. | ||
2593 | * | ||
2594 | * Blob properties are special | ||
2595 | * | ||
2596 | * Called by the user via ioctl. | ||
2597 | * | ||
2598 | * Returns: | ||
2599 | * Zero on success, negative errno on failure. | ||
2600 | */ | ||
2601 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
2602 | void *data, struct drm_file *file_priv) | ||
2603 | { | ||
2604 | struct drm_mode_get_property *out_resp = data; | ||
2605 | struct drm_property *property; | ||
2606 | int enum_count = 0; | ||
2607 | int value_count = 0; | ||
2608 | int ret = 0, i; | ||
2609 | int copied; | ||
2610 | struct drm_property_enum *prop_enum; | ||
2611 | struct drm_mode_property_enum __user *enum_ptr; | ||
2612 | uint64_t __user *values_ptr; | ||
2613 | |||
2614 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2615 | return -EINVAL; | ||
2616 | |||
2617 | drm_modeset_lock_all(dev); | ||
2618 | property = drm_property_find(dev, out_resp->prop_id); | ||
2619 | if (!property) { | ||
2620 | ret = -ENOENT; | ||
2621 | goto done; | ||
2622 | } | ||
2623 | |||
2624 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
2625 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
2626 | list_for_each_entry(prop_enum, &property->enum_list, head) | ||
2627 | enum_count++; | ||
2628 | } | ||
2629 | |||
2630 | value_count = property->num_values; | ||
2631 | |||
2632 | strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); | ||
2633 | out_resp->name[DRM_PROP_NAME_LEN-1] = 0; | ||
2634 | out_resp->flags = property->flags; | ||
2635 | |||
2636 | if ((out_resp->count_values >= value_count) && value_count) { | ||
2637 | values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; | ||
2638 | for (i = 0; i < value_count; i++) { | ||
2639 | if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { | ||
2640 | ret = -EFAULT; | ||
2641 | goto done; | ||
2642 | } | ||
2643 | } | ||
2644 | } | ||
2645 | out_resp->count_values = value_count; | ||
2646 | |||
2647 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
2648 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
2649 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { | ||
2650 | copied = 0; | ||
2651 | enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; | ||
2652 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
2653 | |||
2654 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { | ||
2655 | ret = -EFAULT; | ||
2656 | goto done; | ||
2657 | } | ||
2658 | |||
2659 | if (copy_to_user(&enum_ptr[copied].name, | ||
2660 | &prop_enum->name, DRM_PROP_NAME_LEN)) { | ||
2661 | ret = -EFAULT; | ||
2662 | goto done; | ||
2663 | } | ||
2664 | copied++; | ||
2665 | } | ||
2666 | } | ||
2667 | out_resp->count_enum_blobs = enum_count; | ||
2668 | } | ||
2669 | |||
2670 | /* | ||
2671 | * NOTE: The idea seems to have been to use this to read all the blob | ||
2672 | * property values. But nothing ever added them to the corresponding | ||
2673 | * list, userspace always used the special-purpose get_blob ioctl to | ||
2674 | * read the value for a blob property. It also doesn't make a lot of | ||
2675 | * sense to return values here when everything else is just metadata for | ||
2676 | * the property itself. | ||
2677 | */ | ||
2678 | if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
2679 | out_resp->count_enum_blobs = 0; | ||
2680 | done: | ||
2681 | drm_modeset_unlock_all(dev); | ||
2682 | return ret; | ||
2683 | } | ||
2684 | |||
2685 | static void drm_property_free_blob(struct kref *kref) | ||
2686 | { | ||
2687 | struct drm_property_blob *blob = | ||
2688 | container_of(kref, struct drm_property_blob, base.refcount); | ||
2689 | |||
2690 | mutex_lock(&blob->dev->mode_config.blob_lock); | ||
2691 | list_del(&blob->head_global); | ||
2692 | mutex_unlock(&blob->dev->mode_config.blob_lock); | ||
2693 | |||
2694 | drm_mode_object_unregister(blob->dev, &blob->base); | ||
2695 | |||
2696 | kfree(blob); | ||
2697 | } | ||
2698 | |||
2699 | /** | ||
2700 | * drm_property_create_blob - Create new blob property | ||
2701 | * | ||
2702 | * Creates a new blob property for a specified DRM device, optionally | ||
2703 | * copying data. | ||
2704 | * | ||
2705 | * @dev: DRM device to create property for | ||
2706 | * @length: Length to allocate for blob data | ||
2707 | * @data: If specified, copies data into blob | ||
2708 | * | ||
2709 | * Returns: | ||
2710 | * New blob property with a single reference on success, or an ERR_PTR | ||
2711 | * value on failure. | ||
2712 | */ | ||
2713 | struct drm_property_blob * | ||
2714 | drm_property_create_blob(struct drm_device *dev, size_t length, | ||
2715 | const void *data) | ||
2716 | { | ||
2717 | struct drm_property_blob *blob; | ||
2718 | int ret; | ||
2719 | |||
2720 | if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) | ||
2721 | return ERR_PTR(-EINVAL); | ||
2722 | |||
2723 | blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); | ||
2724 | if (!blob) | ||
2725 | return ERR_PTR(-ENOMEM); | ||
2726 | |||
2727 | /* This must be explicitly initialised, so we can safely call list_del | ||
2728 | * on it in the removal handler, even if it isn't in a file list. */ | ||
2729 | INIT_LIST_HEAD(&blob->head_file); | ||
2730 | blob->length = length; | ||
2731 | blob->dev = dev; | ||
2732 | |||
2733 | if (data) | ||
2734 | memcpy(blob->data, data, length); | ||
2735 | |||
2736 | ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, | ||
2737 | true, drm_property_free_blob); | ||
2738 | if (ret) { | ||
2739 | kfree(blob); | ||
2740 | return ERR_PTR(-EINVAL); | ||
2741 | } | ||
2742 | |||
2743 | mutex_lock(&dev->mode_config.blob_lock); | ||
2744 | list_add_tail(&blob->head_global, | ||
2745 | &dev->mode_config.property_blob_list); | ||
2746 | mutex_unlock(&dev->mode_config.blob_lock); | ||
2747 | |||
2748 | return blob; | ||
2749 | } | ||
2750 | EXPORT_SYMBOL(drm_property_create_blob); | ||
2751 | |||
2752 | /** | ||
2753 | * drm_property_unreference_blob - Unreference a blob property | ||
2754 | * | ||
2755 | * Drop a reference on a blob property. May free the object. | ||
2756 | * | ||
2757 | * @blob: Pointer to blob property | ||
2758 | */ | ||
2759 | void drm_property_unreference_blob(struct drm_property_blob *blob) | ||
2760 | { | ||
2761 | if (!blob) | ||
2762 | return; | ||
2763 | |||
2764 | drm_mode_object_unreference(&blob->base); | ||
2765 | } | ||
2766 | EXPORT_SYMBOL(drm_property_unreference_blob); | ||
2767 | |||
2768 | /** | ||
2769 | * drm_property_destroy_user_blobs - destroy all blobs created by this client | ||
2770 | * @dev: DRM device | ||
2771 | * @file_priv: destroy all blobs owned by this file handle | ||
2772 | */ | ||
2773 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
2774 | struct drm_file *file_priv) | ||
2775 | { | ||
2776 | struct drm_property_blob *blob, *bt; | ||
2777 | |||
2778 | /* | ||
2779 | * When the file gets released that means no one else can access the | ||
2780 | * blob list any more, so no need to grab dev->blob_lock. | ||
2781 | */ | ||
2782 | list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { | ||
2783 | list_del_init(&blob->head_file); | ||
2784 | drm_property_unreference_blob(blob); | ||
2785 | } | ||
2786 | } | ||
2787 | |||
2788 | /** | ||
2789 | * drm_property_reference_blob - Take a reference on an existing property | ||
2790 | * | ||
2791 | * Take a new reference on an existing blob property. | ||
2792 | * | ||
2793 | * @blob: Pointer to blob property | ||
2794 | */ | ||
2795 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) | ||
2796 | { | ||
2797 | drm_mode_object_reference(&blob->base); | ||
2798 | return blob; | ||
2799 | } | ||
2800 | EXPORT_SYMBOL(drm_property_reference_blob); | ||
2801 | |||
2802 | /** | ||
2803 | * drm_property_lookup_blob - look up a blob property and take a reference | ||
2804 | * @dev: drm device | ||
2805 | * @id: id of the blob property | ||
2806 | * | ||
2807 | * If successful, this takes an additional reference to the blob property. | ||
2808 | * callers need to make sure to eventually unreference the returned property | ||
2809 | * again, using @drm_property_unreference_blob. | ||
2810 | */ | ||
2811 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
2812 | uint32_t id) | ||
2813 | { | ||
2814 | struct drm_mode_object *obj; | ||
2815 | struct drm_property_blob *blob = NULL; | ||
2816 | |||
2817 | obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); | ||
2818 | if (obj) | ||
2819 | blob = obj_to_blob(obj); | ||
2820 | return blob; | ||
2821 | } | ||
2822 | EXPORT_SYMBOL(drm_property_lookup_blob); | ||
2823 | |||
2824 | /** | ||
2825 | * drm_property_replace_global_blob - atomically replace existing blob property | ||
2826 | * @dev: drm device | ||
2827 | * @replace: location of blob property pointer to be replaced | ||
2828 | * @length: length of data for new blob, or 0 for no data | ||
2829 | * @data: content for new blob, or NULL for no data | ||
2830 | * @obj_holds_id: optional object for property holding blob ID | ||
2831 | * @prop_holds_id: optional property holding blob ID | ||
2832 | * @return 0 on success or error on failure | ||
2833 | * | ||
2834 | * This function will atomically replace a global property in the blob list, | ||
2835 | * optionally updating a property which holds the ID of that property. It is | ||
2836 | * guaranteed to be atomic: no caller will be allowed to see intermediate | ||
2837 | * results, and either the entire operation will succeed and clean up the | ||
2838 | * previous property, or it will fail and the state will be unchanged. | ||
2839 | * | ||
2840 | * If length is 0 or data is NULL, no new blob will be created, and the holding | ||
2841 | * property, if specified, will be set to 0. | ||
2842 | * | ||
2843 | * Access to the replace pointer is assumed to be protected by the caller, e.g. | ||
2844 | * by holding the relevant modesetting object lock for its parent. | ||
2845 | * | ||
2846 | * For example, a drm_connector has a 'PATH' property, which contains the ID | ||
2847 | * of a blob property with the value of the MST path information. Calling this | ||
2848 | * function with replace pointing to the connector's path_blob_ptr, length and | ||
2849 | * data set for the new path information, obj_holds_id set to the connector's | ||
2850 | * base object, and prop_holds_id set to the path property name, will perform | ||
2851 | * a completely atomic update. The access to path_blob_ptr is protected by the | ||
2852 | * caller holding a lock on the connector. | ||
2853 | */ | ||
2854 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
2855 | struct drm_property_blob **replace, | ||
2856 | size_t length, | ||
2857 | const void *data, | ||
2858 | struct drm_mode_object *obj_holds_id, | ||
2859 | struct drm_property *prop_holds_id) | ||
2860 | { | ||
2861 | struct drm_property_blob *new_blob = NULL; | ||
2862 | struct drm_property_blob *old_blob = NULL; | ||
2863 | int ret; | ||
2864 | |||
2865 | WARN_ON(replace == NULL); | ||
2866 | |||
2867 | old_blob = *replace; | ||
2868 | |||
2869 | if (length && data) { | ||
2870 | new_blob = drm_property_create_blob(dev, length, data); | ||
2871 | if (IS_ERR(new_blob)) | ||
2872 | return PTR_ERR(new_blob); | ||
2873 | } | ||
2874 | |||
2875 | /* This does not need to be synchronised with blob_lock, as the | ||
2876 | * get_properties ioctl locks all modesetting objects, and | ||
2877 | * obj_holds_id must be locked before calling here, so we cannot | ||
2878 | * have its value out of sync with the list membership modified | ||
2879 | * below under blob_lock. */ | ||
2880 | if (obj_holds_id) { | ||
2881 | ret = drm_object_property_set_value(obj_holds_id, | ||
2882 | prop_holds_id, | ||
2883 | new_blob ? | ||
2884 | new_blob->base.id : 0); | ||
2885 | if (ret != 0) | ||
2886 | goto err_created; | ||
2887 | } | ||
2888 | |||
2889 | drm_property_unreference_blob(old_blob); | ||
2890 | *replace = new_blob; | ||
2891 | |||
2892 | return 0; | ||
2893 | |||
2894 | err_created: | ||
2895 | drm_property_unreference_blob(new_blob); | ||
2896 | return ret; | ||
2897 | } | ||
2898 | EXPORT_SYMBOL(drm_property_replace_global_blob); | ||
2899 | |||
2900 | /** | ||
2901 | * drm_mode_getblob_ioctl - get the contents of a blob property value | ||
2902 | * @dev: DRM device | ||
2903 | * @data: ioctl data | ||
2904 | * @file_priv: DRM file info | ||
2905 | * | ||
2906 | * This function retrieves the contents of a blob property. The value stored in | ||
2907 | * an object's blob property is just a normal modeset object id. | ||
2908 | * | ||
2909 | * Called by the user via ioctl. | ||
2910 | * | ||
2911 | * Returns: | ||
2912 | * Zero on success, negative errno on failure. | ||
2913 | */ | ||
2914 | int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
2915 | void *data, struct drm_file *file_priv) | ||
2916 | { | ||
2917 | struct drm_mode_get_blob *out_resp = data; | ||
2918 | struct drm_property_blob *blob; | ||
2919 | int ret = 0; | ||
2920 | void __user *blob_ptr; | ||
2921 | |||
2922 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2923 | return -EINVAL; | ||
2924 | |||
2925 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
2926 | if (!blob) | ||
2927 | return -ENOENT; | ||
2928 | |||
2929 | if (out_resp->length == blob->length) { | ||
2930 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
2931 | if (copy_to_user(blob_ptr, blob->data, blob->length)) { | ||
2932 | ret = -EFAULT; | ||
2933 | goto unref; | ||
2934 | } | ||
2935 | } | ||
2936 | out_resp->length = blob->length; | ||
2937 | unref: | ||
2938 | drm_property_unreference_blob(blob); | ||
2939 | |||
2940 | return ret; | ||
2941 | } | ||
2942 | |||
2943 | /** | ||
2944 | * drm_mode_createblob_ioctl - create a new blob property | ||
2945 | * @dev: DRM device | ||
2946 | * @data: ioctl data | ||
2947 | * @file_priv: DRM file info | ||
2948 | * | ||
2949 | * This function creates a new blob property with user-defined values. In order | ||
2950 | * to give us sensible validation and checking when creating, rather than at | ||
2951 | * every potential use, we also require a type to be provided upfront. | ||
2952 | * | ||
2953 | * Called by the user via ioctl. | ||
2954 | * | ||
2955 | * Returns: | ||
2956 | * Zero on success, negative errno on failure. | ||
2957 | */ | ||
2958 | int drm_mode_createblob_ioctl(struct drm_device *dev, | ||
2959 | void *data, struct drm_file *file_priv) | ||
2960 | { | ||
2961 | struct drm_mode_create_blob *out_resp = data; | ||
2962 | struct drm_property_blob *blob; | ||
2963 | void __user *blob_ptr; | ||
2964 | int ret = 0; | ||
2965 | |||
2966 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2967 | return -EINVAL; | ||
2968 | |||
2969 | blob = drm_property_create_blob(dev, out_resp->length, NULL); | ||
2970 | if (IS_ERR(blob)) | ||
2971 | return PTR_ERR(blob); | ||
2972 | |||
2973 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
2974 | if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { | ||
2975 | ret = -EFAULT; | ||
2976 | goto out_blob; | ||
2977 | } | ||
2978 | |||
2979 | /* Dropping the lock between create_blob and our access here is safe | ||
2980 | * as only the same file_priv can remove the blob; at this point, it is | ||
2981 | * not associated with any file_priv. */ | ||
2982 | mutex_lock(&dev->mode_config.blob_lock); | ||
2983 | out_resp->blob_id = blob->base.id; | ||
2984 | list_add_tail(&blob->head_file, &file_priv->blobs); | ||
2985 | mutex_unlock(&dev->mode_config.blob_lock); | ||
2986 | |||
2987 | return 0; | ||
2988 | |||
2989 | out_blob: | ||
2990 | drm_property_unreference_blob(blob); | ||
2991 | return ret; | ||
2992 | } | ||
2993 | |||
2994 | /** | ||
2995 | * drm_mode_destroyblob_ioctl - destroy a user blob property | ||
2996 | * @dev: DRM device | ||
2997 | * @data: ioctl data | ||
2998 | * @file_priv: DRM file info | ||
2999 | * | ||
3000 | * Destroy an existing user-defined blob property. | ||
3001 | * | ||
3002 | * Called by the user via ioctl. | ||
3003 | * | ||
3004 | * Returns: | ||
3005 | * Zero on success, negative errno on failure. | ||
3006 | */ | ||
3007 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | ||
3008 | void *data, struct drm_file *file_priv) | ||
3009 | { | ||
3010 | struct drm_mode_destroy_blob *out_resp = data; | ||
3011 | struct drm_property_blob *blob = NULL, *bt; | ||
3012 | bool found = false; | ||
3013 | int ret = 0; | ||
3014 | |||
3015 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3016 | return -EINVAL; | ||
3017 | |||
3018 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
3019 | if (!blob) | ||
3020 | return -ENOENT; | ||
3021 | |||
3022 | mutex_lock(&dev->mode_config.blob_lock); | ||
3023 | /* Ensure the property was actually created by this user. */ | ||
3024 | list_for_each_entry(bt, &file_priv->blobs, head_file) { | ||
3025 | if (bt == blob) { | ||
3026 | found = true; | ||
3027 | break; | ||
3028 | } | ||
3029 | } | ||
3030 | |||
3031 | if (!found) { | ||
3032 | ret = -EPERM; | ||
3033 | goto err; | ||
3034 | } | ||
3035 | |||
3036 | /* We must drop head_file here, because we may not be the last | ||
3037 | * reference on the blob. */ | ||
3038 | list_del_init(&blob->head_file); | ||
3039 | mutex_unlock(&dev->mode_config.blob_lock); | ||
3040 | |||
3041 | /* One reference from lookup, and one from the filp. */ | ||
3042 | drm_property_unreference_blob(blob); | ||
3043 | drm_property_unreference_blob(blob); | ||
3044 | |||
3045 | return 0; | ||
3046 | |||
3047 | err: | ||
3048 | mutex_unlock(&dev->mode_config.blob_lock); | ||
3049 | drm_property_unreference_blob(blob); | ||
3050 | |||
3051 | return ret; | ||
3052 | } | ||
3053 | |||
3054 | /* Some properties could refer to dynamic refcnt'd objects, or things that | ||
3055 | * need special locking to handle lifetime issues (ie. to ensure the prop | ||
3056 | * value doesn't become invalid part way through the property update due to | ||
3057 | * race). The value returned by reference via 'obj' should be passed back | ||
3058 | * to drm_property_change_valid_put() after the property is set (and the | ||
3059 | * object to which the property is attached has a chance to take it's own | ||
3060 | * reference). | ||
3061 | */ | ||
3062 | bool drm_property_change_valid_get(struct drm_property *property, | ||
3063 | uint64_t value, struct drm_mode_object **ref) | ||
3064 | { | ||
3065 | int i; | ||
3066 | |||
3067 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | ||
3068 | return false; | ||
3069 | |||
3070 | *ref = NULL; | ||
3071 | |||
3072 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | ||
3073 | if (value < property->values[0] || value > property->values[1]) | ||
3074 | return false; | ||
3075 | return true; | ||
3076 | } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { | ||
3077 | int64_t svalue = U642I64(value); | ||
3078 | |||
3079 | if (svalue < U642I64(property->values[0]) || | ||
3080 | svalue > U642I64(property->values[1])) | ||
3081 | return false; | ||
3082 | return true; | ||
3083 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
3084 | uint64_t valid_mask = 0; | ||
3085 | |||
3086 | for (i = 0; i < property->num_values; i++) | ||
3087 | valid_mask |= (1ULL << property->values[i]); | ||
3088 | return !(value & ~valid_mask); | ||
3089 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { | ||
3090 | struct drm_property_blob *blob; | ||
3091 | |||
3092 | if (value == 0) | ||
3093 | return true; | ||
3094 | |||
3095 | blob = drm_property_lookup_blob(property->dev, value); | ||
3096 | if (blob) { | ||
3097 | *ref = &blob->base; | ||
3098 | return true; | ||
3099 | } else { | ||
3100 | return false; | ||
3101 | } | ||
3102 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
3103 | /* a zero value for an object property translates to null: */ | ||
3104 | if (value == 0) | ||
3105 | return true; | ||
3106 | |||
3107 | *ref = __drm_mode_object_find(property->dev, value, | ||
3108 | property->values[0]); | ||
3109 | return *ref != NULL; | ||
3110 | } | ||
3111 | |||
3112 | for (i = 0; i < property->num_values; i++) | ||
3113 | if (property->values[i] == value) | ||
3114 | return true; | ||
3115 | return false; | ||
3116 | } | ||
3117 | |||
3118 | void drm_property_change_valid_put(struct drm_property *property, | ||
3119 | struct drm_mode_object *ref) | ||
3120 | { | ||
3121 | if (!ref) | ||
3122 | return; | ||
3123 | |||
3124 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
3125 | drm_mode_object_unreference(ref); | ||
3126 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
3127 | drm_property_unreference_blob(obj_to_blob(ref)); | ||
3128 | } | ||
3129 | |||
3130 | static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | ||
3131 | struct drm_property *property, | ||
3132 | uint64_t value) | ||
3133 | { | 1677 | { |
3134 | int ret = -EINVAL; | 1678 | int ret = -EINVAL; |
3135 | struct drm_crtc *crtc = obj_to_crtc(obj); | 1679 | struct drm_crtc *crtc = obj_to_crtc(obj); |
@@ -3172,119 +1716,6 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane, | |||
3172 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); | 1716 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); |
3173 | 1717 | ||
3174 | /** | 1718 | /** |
3175 | * drm_mode_obj_get_properties_ioctl - get the current value of a object's property | ||
3176 | * @dev: DRM device | ||
3177 | * @data: ioctl data | ||
3178 | * @file_priv: DRM file info | ||
3179 | * | ||
3180 | * This function retrieves the current value for an object's property. Compared | ||
3181 | * to the connector specific ioctl this one is extended to also work on crtc and | ||
3182 | * plane objects. | ||
3183 | * | ||
3184 | * Called by the user via ioctl. | ||
3185 | * | ||
3186 | * Returns: | ||
3187 | * Zero on success, negative errno on failure. | ||
3188 | */ | ||
3189 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | ||
3190 | struct drm_file *file_priv) | ||
3191 | { | ||
3192 | struct drm_mode_obj_get_properties *arg = data; | ||
3193 | struct drm_mode_object *obj; | ||
3194 | int ret = 0; | ||
3195 | |||
3196 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3197 | return -EINVAL; | ||
3198 | |||
3199 | drm_modeset_lock_all(dev); | ||
3200 | |||
3201 | obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); | ||
3202 | if (!obj) { | ||
3203 | ret = -ENOENT; | ||
3204 | goto out; | ||
3205 | } | ||
3206 | if (!obj->properties) { | ||
3207 | ret = -EINVAL; | ||
3208 | goto out_unref; | ||
3209 | } | ||
3210 | |||
3211 | ret = drm_mode_object_get_properties(obj, file_priv->atomic, | ||
3212 | (uint32_t __user *)(unsigned long)(arg->props_ptr), | ||
3213 | (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), | ||
3214 | &arg->count_props); | ||
3215 | |||
3216 | out_unref: | ||
3217 | drm_mode_object_unreference(obj); | ||
3218 | out: | ||
3219 | drm_modeset_unlock_all(dev); | ||
3220 | return ret; | ||
3221 | } | ||
3222 | |||
3223 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | ||
3224 | struct drm_file *file_priv) | ||
3225 | { | ||
3226 | struct drm_mode_obj_set_property *arg = data; | ||
3227 | struct drm_mode_object *arg_obj; | ||
3228 | struct drm_mode_object *prop_obj; | ||
3229 | struct drm_property *property; | ||
3230 | int i, ret = -EINVAL; | ||
3231 | struct drm_mode_object *ref; | ||
3232 | |||
3233 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3234 | return -EINVAL; | ||
3235 | |||
3236 | drm_modeset_lock_all(dev); | ||
3237 | |||
3238 | arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); | ||
3239 | if (!arg_obj) { | ||
3240 | ret = -ENOENT; | ||
3241 | goto out; | ||
3242 | } | ||
3243 | if (!arg_obj->properties) | ||
3244 | goto out_unref; | ||
3245 | |||
3246 | for (i = 0; i < arg_obj->properties->count; i++) | ||
3247 | if (arg_obj->properties->properties[i]->base.id == arg->prop_id) | ||
3248 | break; | ||
3249 | |||
3250 | if (i == arg_obj->properties->count) | ||
3251 | goto out_unref; | ||
3252 | |||
3253 | prop_obj = drm_mode_object_find(dev, arg->prop_id, | ||
3254 | DRM_MODE_OBJECT_PROPERTY); | ||
3255 | if (!prop_obj) { | ||
3256 | ret = -ENOENT; | ||
3257 | goto out_unref; | ||
3258 | } | ||
3259 | property = obj_to_property(prop_obj); | ||
3260 | |||
3261 | if (!drm_property_change_valid_get(property, arg->value, &ref)) | ||
3262 | goto out_unref; | ||
3263 | |||
3264 | switch (arg_obj->type) { | ||
3265 | case DRM_MODE_OBJECT_CONNECTOR: | ||
3266 | ret = drm_mode_connector_set_obj_prop(arg_obj, property, | ||
3267 | arg->value); | ||
3268 | break; | ||
3269 | case DRM_MODE_OBJECT_CRTC: | ||
3270 | ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); | ||
3271 | break; | ||
3272 | case DRM_MODE_OBJECT_PLANE: | ||
3273 | ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), | ||
3274 | property, arg->value); | ||
3275 | break; | ||
3276 | } | ||
3277 | |||
3278 | drm_property_change_valid_put(property, ref); | ||
3279 | |||
3280 | out_unref: | ||
3281 | drm_mode_object_unreference(arg_obj); | ||
3282 | out: | ||
3283 | drm_modeset_unlock_all(dev); | ||
3284 | return ret; | ||
3285 | } | ||
3286 | |||
3287 | /** | ||
3288 | * drm_mode_crtc_set_gamma_size - set the gamma table size | 1719 | * drm_mode_crtc_set_gamma_size - set the gamma table size |
3289 | * @crtc: CRTC to set the gamma table size for | 1720 | * @crtc: CRTC to set the gamma table size for |
3290 | * @gamma_size: size of the gamma table | 1721 | * @gamma_size: size of the gamma table |
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 62efb9d09a85..a3622644bccf 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
@@ -33,29 +33,9 @@ | |||
33 | 33 | ||
34 | 34 | ||
35 | /* drm_crtc.c */ | 35 | /* drm_crtc.c */ |
36 | int drm_mode_object_get_reg(struct drm_device *dev, | 36 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, |
37 | struct drm_mode_object *obj, | 37 | struct drm_property *property, |
38 | uint32_t obj_type, | 38 | uint64_t value); |
39 | bool register_obj, | ||
40 | void (*obj_free_cb)(struct kref *kref)); | ||
41 | void drm_mode_object_register(struct drm_device *dev, | ||
42 | struct drm_mode_object *obj); | ||
43 | int drm_mode_object_get(struct drm_device *dev, | ||
44 | struct drm_mode_object *obj, uint32_t obj_type); | ||
45 | struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, | ||
46 | uint32_t id, uint32_t type); | ||
47 | void drm_mode_object_unregister(struct drm_device *dev, | ||
48 | struct drm_mode_object *object); | ||
49 | int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, | ||
50 | uint32_t __user *prop_ptr, | ||
51 | uint64_t __user *prop_values, | ||
52 | uint32_t *arg_count_props); | ||
53 | bool drm_property_change_valid_get(struct drm_property *property, | ||
54 | uint64_t value, | ||
55 | struct drm_mode_object **ref); | ||
56 | void drm_property_change_valid_put(struct drm_property *property, | ||
57 | struct drm_mode_object *ref); | ||
58 | |||
59 | int drm_plane_check_pixel_format(const struct drm_plane *plane, | 39 | int drm_plane_check_pixel_format(const struct drm_plane *plane, |
60 | u32 format); | 40 | u32 format); |
61 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, | 41 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, |
@@ -64,8 +44,6 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, | |||
64 | const struct drm_framebuffer *fb); | 44 | const struct drm_framebuffer *fb); |
65 | 45 | ||
66 | void drm_fb_release(struct drm_file *file_priv); | 46 | void drm_fb_release(struct drm_file *file_priv); |
67 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
68 | struct drm_file *file_priv); | ||
69 | 47 | ||
70 | /* dumb buffer support IOCTLs */ | 48 | /* dumb buffer support IOCTLs */ |
71 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, | 49 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, |
@@ -76,11 +54,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | |||
76 | void *data, struct drm_file *file_priv); | 54 | void *data, struct drm_file *file_priv); |
77 | 55 | ||
78 | /* IOCTLs */ | 56 | /* IOCTLs */ |
79 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | ||
80 | struct drm_file *file_priv); | ||
81 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | ||
82 | struct drm_file *file_priv); | ||
83 | |||
84 | int drm_mode_getresources(struct drm_device *dev, | 57 | int drm_mode_getresources(struct drm_device *dev, |
85 | void *data, struct drm_file *file_priv); | 58 | void *data, struct drm_file *file_priv); |
86 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | 59 | int drm_mode_getplane_res(struct drm_device *dev, void *data, |
@@ -97,6 +70,24 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
97 | void *data, struct drm_file *file_priv); | 70 | void *data, struct drm_file *file_priv); |
98 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | 71 | int drm_mode_cursor2_ioctl(struct drm_device *dev, |
99 | void *data, struct drm_file *file_priv); | 72 | void *data, struct drm_file *file_priv); |
73 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
74 | void *data, struct drm_file *file_priv); | ||
75 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
76 | void *data, struct drm_file *file_priv); | ||
77 | |||
78 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
79 | void *data, struct drm_file *file_priv); | ||
80 | |||
81 | /* drm_property.c */ | ||
82 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
83 | struct drm_file *file_priv); | ||
84 | bool drm_property_change_valid_get(struct drm_property *property, | ||
85 | uint64_t value, | ||
86 | struct drm_mode_object **ref); | ||
87 | void drm_property_change_valid_put(struct drm_property *property, | ||
88 | struct drm_mode_object *ref); | ||
89 | |||
90 | /* IOCTL */ | ||
100 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | 91 | int drm_mode_getproperty_ioctl(struct drm_device *dev, |
101 | void *data, struct drm_file *file_priv); | 92 | void *data, struct drm_file *file_priv); |
102 | int drm_mode_getblob_ioctl(struct drm_device *dev, | 93 | int drm_mode_getblob_ioctl(struct drm_device *dev, |
@@ -105,15 +96,40 @@ int drm_mode_createblob_ioctl(struct drm_device *dev, | |||
105 | void *data, struct drm_file *file_priv); | 96 | void *data, struct drm_file *file_priv); |
106 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | 97 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, |
107 | void *data, struct drm_file *file_priv); | 98 | void *data, struct drm_file *file_priv); |
99 | |||
100 | /* drm_mode_object.c */ | ||
101 | int drm_mode_object_get_reg(struct drm_device *dev, | ||
102 | struct drm_mode_object *obj, | ||
103 | uint32_t obj_type, | ||
104 | bool register_obj, | ||
105 | void (*obj_free_cb)(struct kref *kref)); | ||
106 | void drm_mode_object_register(struct drm_device *dev, | ||
107 | struct drm_mode_object *obj); | ||
108 | int drm_mode_object_get(struct drm_device *dev, | ||
109 | struct drm_mode_object *obj, uint32_t obj_type); | ||
110 | struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, | ||
111 | uint32_t id, uint32_t type); | ||
112 | void drm_mode_object_unregister(struct drm_device *dev, | ||
113 | struct drm_mode_object *object); | ||
114 | int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, | ||
115 | uint32_t __user *prop_ptr, | ||
116 | uint64_t __user *prop_values, | ||
117 | uint32_t *arg_count_props); | ||
118 | |||
119 | /* IOCTL */ | ||
120 | |||
121 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | ||
122 | struct drm_file *file_priv); | ||
123 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | ||
124 | struct drm_file *file_priv); | ||
125 | |||
126 | /* drm_encoder.c */ | ||
127 | int drm_encoder_register_all(struct drm_device *dev); | ||
128 | void drm_encoder_unregister_all(struct drm_device *dev); | ||
129 | |||
130 | /* IOCTL */ | ||
108 | int drm_mode_getencoder(struct drm_device *dev, | 131 | int drm_mode_getencoder(struct drm_device *dev, |
109 | void *data, struct drm_file *file_priv); | 132 | void *data, struct drm_file *file_priv); |
110 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
111 | void *data, struct drm_file *file_priv); | ||
112 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
113 | void *data, struct drm_file *file_priv); | ||
114 | |||
115 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
116 | void *data, struct drm_file *file_priv); | ||
117 | 133 | ||
118 | /* drm_connector.c */ | 134 | /* drm_connector.c */ |
119 | void drm_connector_ida_init(void); | 135 | void drm_connector_ida_init(void); |
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c new file mode 100644 index 000000000000..998a6743a586 --- /dev/null +++ b/drivers/gpu/drm/drm_encoder.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <linux/export.h> | ||
24 | #include <drm/drmP.h> | ||
25 | #include <drm/drm_encoder.h> | ||
26 | |||
27 | #include "drm_crtc_internal.h" | ||
28 | |||
29 | /** | ||
30 | * DOC: overview | ||
31 | * | ||
32 | * Encoders represent the connecting element between the CRTC (as the overall | ||
33 | * pixel pipeline, represented by struct &drm_crtc) and the connectors (as the | ||
34 | * generic sink entity, represented by struct &drm_connector). Encoders are | ||
35 | * objects exposed to userspace, originally to allow userspace to infer cloning | ||
36 | * and connector/CRTC restrictions. Unfortunately almost all drivers get this | ||
37 | * wrong, making the uabi pretty much useless. On top of that the exposed | ||
38 | * restrictions are too simple for todays hardware, and the recommend way to | ||
39 | * infer restrictions is by using the DRM_MODE_ATOMIC_TEST_ONLY flag for the | ||
40 | * atomic IOCTL. | ||
41 | * | ||
42 | * Otherwise encoders aren't used in the uapi at all (any modeset request from | ||
43 | * userspace directly connects a connector with a CRTC), drivers are therefore | ||
44 | * free to use them however they wish. Modeset helper libraries make strong use | ||
45 | * of encoders to facilitate code sharing. But for more complex settings it is | ||
46 | * usually better to move shared code into a separate &drm_bridge. Compared to | ||
47 | * encoders bridges also have the benefit of not being purely an internal | ||
48 | * abstraction since they are not exposed to userspace at all. | ||
49 | * | ||
50 | * Encoders are initialized with drm_encoder_init() and cleaned up using | ||
51 | * drm_encoder_cleanup(). | ||
52 | */ | ||
53 | static const struct drm_prop_enum_list drm_encoder_enum_list[] = { | ||
54 | { DRM_MODE_ENCODER_NONE, "None" }, | ||
55 | { DRM_MODE_ENCODER_DAC, "DAC" }, | ||
56 | { DRM_MODE_ENCODER_TMDS, "TMDS" }, | ||
57 | { DRM_MODE_ENCODER_LVDS, "LVDS" }, | ||
58 | { DRM_MODE_ENCODER_TVDAC, "TV" }, | ||
59 | { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, | ||
60 | { DRM_MODE_ENCODER_DSI, "DSI" }, | ||
61 | { DRM_MODE_ENCODER_DPMST, "DP MST" }, | ||
62 | { DRM_MODE_ENCODER_DPI, "DPI" }, | ||
63 | }; | ||
64 | |||
65 | int drm_encoder_register_all(struct drm_device *dev) | ||
66 | { | ||
67 | struct drm_encoder *encoder; | ||
68 | int ret = 0; | ||
69 | |||
70 | drm_for_each_encoder(encoder, dev) { | ||
71 | if (encoder->funcs->late_register) | ||
72 | ret = encoder->funcs->late_register(encoder); | ||
73 | if (ret) | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | void drm_encoder_unregister_all(struct drm_device *dev) | ||
81 | { | ||
82 | struct drm_encoder *encoder; | ||
83 | |||
84 | drm_for_each_encoder(encoder, dev) { | ||
85 | if (encoder->funcs->early_unregister) | ||
86 | encoder->funcs->early_unregister(encoder); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * drm_encoder_init - Init a preallocated encoder | ||
92 | * @dev: drm device | ||
93 | * @encoder: the encoder to init | ||
94 | * @funcs: callbacks for this encoder | ||
95 | * @encoder_type: user visible type of the encoder | ||
96 | * @name: printf style format string for the encoder name, or NULL for default name | ||
97 | * | ||
98 | * Initialises a preallocated encoder. Encoder should be subclassed as part of | ||
99 | * driver encoder objects. At driver unload time drm_encoder_cleanup() should be | ||
100 | * called from the driver's destroy hook in &drm_encoder_funcs. | ||
101 | * | ||
102 | * Returns: | ||
103 | * Zero on success, error code on failure. | ||
104 | */ | ||
105 | int drm_encoder_init(struct drm_device *dev, | ||
106 | struct drm_encoder *encoder, | ||
107 | const struct drm_encoder_funcs *funcs, | ||
108 | int encoder_type, const char *name, ...) | ||
109 | { | ||
110 | int ret; | ||
111 | |||
112 | drm_modeset_lock_all(dev); | ||
113 | |||
114 | ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); | ||
115 | if (ret) | ||
116 | goto out_unlock; | ||
117 | |||
118 | encoder->dev = dev; | ||
119 | encoder->encoder_type = encoder_type; | ||
120 | encoder->funcs = funcs; | ||
121 | if (name) { | ||
122 | va_list ap; | ||
123 | |||
124 | va_start(ap, name); | ||
125 | encoder->name = kvasprintf(GFP_KERNEL, name, ap); | ||
126 | va_end(ap); | ||
127 | } else { | ||
128 | encoder->name = kasprintf(GFP_KERNEL, "%s-%d", | ||
129 | drm_encoder_enum_list[encoder_type].name, | ||
130 | encoder->base.id); | ||
131 | } | ||
132 | if (!encoder->name) { | ||
133 | ret = -ENOMEM; | ||
134 | goto out_put; | ||
135 | } | ||
136 | |||
137 | list_add_tail(&encoder->head, &dev->mode_config.encoder_list); | ||
138 | encoder->index = dev->mode_config.num_encoder++; | ||
139 | |||
140 | out_put: | ||
141 | if (ret) | ||
142 | drm_mode_object_unregister(dev, &encoder->base); | ||
143 | |||
144 | out_unlock: | ||
145 | drm_modeset_unlock_all(dev); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | EXPORT_SYMBOL(drm_encoder_init); | ||
150 | |||
151 | /** | ||
152 | * drm_encoder_cleanup - cleans up an initialised encoder | ||
153 | * @encoder: encoder to cleanup | ||
154 | * | ||
155 | * Cleans up the encoder but doesn't free the object. | ||
156 | */ | ||
157 | void drm_encoder_cleanup(struct drm_encoder *encoder) | ||
158 | { | ||
159 | struct drm_device *dev = encoder->dev; | ||
160 | |||
161 | /* Note that the encoder_list is considered to be static; should we | ||
162 | * remove the drm_encoder at runtime we would have to decrement all | ||
163 | * the indices on the drm_encoder after us in the encoder_list. | ||
164 | */ | ||
165 | |||
166 | drm_modeset_lock_all(dev); | ||
167 | drm_mode_object_unregister(dev, &encoder->base); | ||
168 | kfree(encoder->name); | ||
169 | list_del(&encoder->head); | ||
170 | dev->mode_config.num_encoder--; | ||
171 | drm_modeset_unlock_all(dev); | ||
172 | |||
173 | memset(encoder, 0, sizeof(*encoder)); | ||
174 | } | ||
175 | EXPORT_SYMBOL(drm_encoder_cleanup); | ||
176 | |||
177 | static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) | ||
178 | { | ||
179 | struct drm_connector *connector; | ||
180 | struct drm_device *dev = encoder->dev; | ||
181 | bool uses_atomic = false; | ||
182 | |||
183 | /* For atomic drivers only state objects are synchronously updated and | ||
184 | * protected by modeset locks, so check those first. */ | ||
185 | drm_for_each_connector(connector, dev) { | ||
186 | if (!connector->state) | ||
187 | continue; | ||
188 | |||
189 | uses_atomic = true; | ||
190 | |||
191 | if (connector->state->best_encoder != encoder) | ||
192 | continue; | ||
193 | |||
194 | return connector->state->crtc; | ||
195 | } | ||
196 | |||
197 | /* Don't return stale data (e.g. pending async disable). */ | ||
198 | if (uses_atomic) | ||
199 | return NULL; | ||
200 | |||
201 | return encoder->crtc; | ||
202 | } | ||
203 | |||
204 | int drm_mode_getencoder(struct drm_device *dev, void *data, | ||
205 | struct drm_file *file_priv) | ||
206 | { | ||
207 | struct drm_mode_get_encoder *enc_resp = data; | ||
208 | struct drm_encoder *encoder; | ||
209 | struct drm_crtc *crtc; | ||
210 | |||
211 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | encoder = drm_encoder_find(dev, enc_resp->encoder_id); | ||
215 | if (!encoder) | ||
216 | return -ENOENT; | ||
217 | |||
218 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
219 | crtc = drm_encoder_get_crtc(encoder); | ||
220 | if (crtc) | ||
221 | enc_resp->crtc_id = crtc->base.id; | ||
222 | else | ||
223 | enc_resp->crtc_id = 0; | ||
224 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
225 | |||
226 | enc_resp->encoder_type = encoder->encoder_type; | ||
227 | enc_resp->encoder_id = encoder->base.id; | ||
228 | enc_resp->possible_crtcs = encoder->possible_crtcs; | ||
229 | enc_resp->possible_clones = encoder->possible_clones; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index c81546c15c93..29c56b4331e0 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c | |||
@@ -36,6 +36,49 @@ static char printable_char(int c) | |||
36 | } | 36 | } |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description | ||
40 | * @bpp: bits per pixels | ||
41 | * @depth: bit depth per pixel | ||
42 | * | ||
43 | * Computes a drm fourcc pixel format code for the given @bpp/@depth values. | ||
44 | * Useful in fbdev emulation code, since that deals in those values. | ||
45 | */ | ||
46 | uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) | ||
47 | { | ||
48 | uint32_t fmt; | ||
49 | |||
50 | switch (bpp) { | ||
51 | case 8: | ||
52 | fmt = DRM_FORMAT_C8; | ||
53 | break; | ||
54 | case 16: | ||
55 | if (depth == 15) | ||
56 | fmt = DRM_FORMAT_XRGB1555; | ||
57 | else | ||
58 | fmt = DRM_FORMAT_RGB565; | ||
59 | break; | ||
60 | case 24: | ||
61 | fmt = DRM_FORMAT_RGB888; | ||
62 | break; | ||
63 | case 32: | ||
64 | if (depth == 24) | ||
65 | fmt = DRM_FORMAT_XRGB8888; | ||
66 | else if (depth == 30) | ||
67 | fmt = DRM_FORMAT_XRGB2101010; | ||
68 | else | ||
69 | fmt = DRM_FORMAT_ARGB8888; | ||
70 | break; | ||
71 | default: | ||
72 | DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); | ||
73 | fmt = DRM_FORMAT_XRGB8888; | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | return fmt; | ||
78 | } | ||
79 | EXPORT_SYMBOL(drm_mode_legacy_fb_format); | ||
80 | |||
81 | /** | ||
39 | * drm_get_format_name - return a string for drm fourcc format | 82 | * drm_get_format_name - return a string for drm fourcc format |
40 | * @format: format to compute name of | 83 | * @format: format to compute name of |
41 | * | 84 | * |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 12b7753a0d27..b97c421c65f4 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -189,9 +189,8 @@ static int drm_getclient(struct drm_device *dev, void *data, | |||
189 | */ | 189 | */ |
190 | if (client->idx == 0) { | 190 | if (client->idx == 0) { |
191 | client->auth = file_priv->authenticated; | 191 | client->auth = file_priv->authenticated; |
192 | client->pid = pid_vnr(file_priv->pid); | 192 | client->pid = task_pid_vnr(current); |
193 | client->uid = from_kuid_munged(current_user_ns(), | 193 | client->uid = overflowuid; |
194 | file_priv->uid); | ||
195 | client->magic = 0; | 194 | client->magic = 0; |
196 | client->iocs = 0; | 195 | client->iocs = 0; |
197 | 196 | ||
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c new file mode 100644 index 000000000000..6edda8382a4c --- /dev/null +++ b/drivers/gpu/drm/drm_mode_object.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <linux/export.h> | ||
24 | #include <drm/drmP.h> | ||
25 | #include <drm/drm_mode_object.h> | ||
26 | |||
27 | #include "drm_crtc_internal.h" | ||
28 | |||
29 | /* | ||
30 | * Internal function to assign a slot in the object idr and optionally | ||
31 | * register the object into the idr. | ||
32 | */ | ||
33 | int drm_mode_object_get_reg(struct drm_device *dev, | ||
34 | struct drm_mode_object *obj, | ||
35 | uint32_t obj_type, | ||
36 | bool register_obj, | ||
37 | void (*obj_free_cb)(struct kref *kref)) | ||
38 | { | ||
39 | int ret; | ||
40 | |||
41 | mutex_lock(&dev->mode_config.idr_mutex); | ||
42 | ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); | ||
43 | if (ret >= 0) { | ||
44 | /* | ||
45 | * Set up the object linking under the protection of the idr | ||
46 | * lock so that other users can't see inconsistent state. | ||
47 | */ | ||
48 | obj->id = ret; | ||
49 | obj->type = obj_type; | ||
50 | if (obj_free_cb) { | ||
51 | obj->free_cb = obj_free_cb; | ||
52 | kref_init(&obj->refcount); | ||
53 | } | ||
54 | } | ||
55 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
56 | |||
57 | return ret < 0 ? ret : 0; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * drm_mode_object_get - allocate a new modeset identifier | ||
62 | * @dev: DRM device | ||
63 | * @obj: object pointer, used to generate unique ID | ||
64 | * @obj_type: object type | ||
65 | * | ||
66 | * Create a unique identifier based on @ptr in @dev's identifier space. Used | ||
67 | * for tracking modes, CRTCs and connectors. Note that despite the _get postfix | ||
68 | * modeset identifiers are _not_ reference counted. Hence don't use this for | ||
69 | * reference counted modeset objects like framebuffers. | ||
70 | * | ||
71 | * Returns: | ||
72 | * Zero on success, error code on failure. | ||
73 | */ | ||
74 | int drm_mode_object_get(struct drm_device *dev, | ||
75 | struct drm_mode_object *obj, uint32_t obj_type) | ||
76 | { | ||
77 | return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); | ||
78 | } | ||
79 | |||
80 | void drm_mode_object_register(struct drm_device *dev, | ||
81 | struct drm_mode_object *obj) | ||
82 | { | ||
83 | mutex_lock(&dev->mode_config.idr_mutex); | ||
84 | idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); | ||
85 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * drm_mode_object_unregister - free a modeset identifer | ||
90 | * @dev: DRM device | ||
91 | * @object: object to free | ||
92 | * | ||
93 | * Free @id from @dev's unique identifier pool. | ||
94 | * This function can be called multiple times, and guards against | ||
95 | * multiple removals. | ||
96 | * These modeset identifiers are _not_ reference counted. Hence don't use this | ||
97 | * for reference counted modeset objects like framebuffers. | ||
98 | */ | ||
99 | void drm_mode_object_unregister(struct drm_device *dev, | ||
100 | struct drm_mode_object *object) | ||
101 | { | ||
102 | mutex_lock(&dev->mode_config.idr_mutex); | ||
103 | if (object->id) { | ||
104 | idr_remove(&dev->mode_config.crtc_idr, object->id); | ||
105 | object->id = 0; | ||
106 | } | ||
107 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
108 | } | ||
109 | |||
110 | struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, | ||
111 | uint32_t id, uint32_t type) | ||
112 | { | ||
113 | struct drm_mode_object *obj = NULL; | ||
114 | |||
115 | mutex_lock(&dev->mode_config.idr_mutex); | ||
116 | obj = idr_find(&dev->mode_config.crtc_idr, id); | ||
117 | if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) | ||
118 | obj = NULL; | ||
119 | if (obj && obj->id != id) | ||
120 | obj = NULL; | ||
121 | |||
122 | if (obj && obj->free_cb) { | ||
123 | if (!kref_get_unless_zero(&obj->refcount)) | ||
124 | obj = NULL; | ||
125 | } | ||
126 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
127 | |||
128 | return obj; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * drm_mode_object_find - look up a drm object with static lifetime | ||
133 | * @dev: drm device | ||
134 | * @id: id of the mode object | ||
135 | * @type: type of the mode object | ||
136 | * | ||
137 | * This function is used to look up a modeset object. It will acquire a | ||
138 | * reference for reference counted objects. This reference must be dropped again | ||
139 | * by callind drm_mode_object_unreference(). | ||
140 | */ | ||
141 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | ||
142 | uint32_t id, uint32_t type) | ||
143 | { | ||
144 | struct drm_mode_object *obj = NULL; | ||
145 | |||
146 | obj = __drm_mode_object_find(dev, id, type); | ||
147 | return obj; | ||
148 | } | ||
149 | EXPORT_SYMBOL(drm_mode_object_find); | ||
150 | |||
151 | /** | ||
152 | * drm_mode_object_unreference - decr the object refcnt | ||
153 | * @obj: mode_object | ||
154 | * | ||
155 | * This function decrements the object's refcount if it is a refcounted modeset | ||
156 | * object. It is a no-op on any other object. This is used to drop references | ||
157 | * acquired with drm_mode_object_reference(). | ||
158 | */ | ||
159 | void drm_mode_object_unreference(struct drm_mode_object *obj) | ||
160 | { | ||
161 | if (obj->free_cb) { | ||
162 | DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); | ||
163 | kref_put(&obj->refcount, obj->free_cb); | ||
164 | } | ||
165 | } | ||
166 | EXPORT_SYMBOL(drm_mode_object_unreference); | ||
167 | |||
168 | /** | ||
169 | * drm_mode_object_reference - incr the object refcnt | ||
170 | * @obj: mode_object | ||
171 | * | ||
172 | * This function increments the object's refcount if it is a refcounted modeset | ||
173 | * object. It is a no-op on any other object. References should be dropped again | ||
174 | * by calling drm_mode_object_unreference(). | ||
175 | */ | ||
176 | void drm_mode_object_reference(struct drm_mode_object *obj) | ||
177 | { | ||
178 | if (obj->free_cb) { | ||
179 | DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); | ||
180 | kref_get(&obj->refcount); | ||
181 | } | ||
182 | } | ||
183 | EXPORT_SYMBOL(drm_mode_object_reference); | ||
184 | |||
185 | /** | ||
186 | * drm_object_attach_property - attach a property to a modeset object | ||
187 | * @obj: drm modeset object | ||
188 | * @property: property to attach | ||
189 | * @init_val: initial value of the property | ||
190 | * | ||
191 | * This attaches the given property to the modeset object with the given initial | ||
192 | * value. Currently this function cannot fail since the properties are stored in | ||
193 | * a statically sized array. | ||
194 | */ | ||
195 | void drm_object_attach_property(struct drm_mode_object *obj, | ||
196 | struct drm_property *property, | ||
197 | uint64_t init_val) | ||
198 | { | ||
199 | int count = obj->properties->count; | ||
200 | |||
201 | if (count == DRM_OBJECT_MAX_PROPERTY) { | ||
202 | WARN(1, "Failed to attach object property (type: 0x%x). Please " | ||
203 | "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " | ||
204 | "you see this message on the same object type.\n", | ||
205 | obj->type); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | obj->properties->properties[count] = property; | ||
210 | obj->properties->values[count] = init_val; | ||
211 | obj->properties->count++; | ||
212 | } | ||
213 | EXPORT_SYMBOL(drm_object_attach_property); | ||
214 | |||
215 | /** | ||
216 | * drm_object_property_set_value - set the value of a property | ||
217 | * @obj: drm mode object to set property value for | ||
218 | * @property: property to set | ||
219 | * @val: value the property should be set to | ||
220 | * | ||
221 | * This function sets a given property on a given object. This function only | ||
222 | * changes the software state of the property, it does not call into the | ||
223 | * driver's ->set_property callback. | ||
224 | * | ||
225 | * Note that atomic drivers should not have any need to call this, the core will | ||
226 | * ensure consistency of values reported back to userspace through the | ||
227 | * appropriate ->atomic_get_property callback. Only legacy drivers should call | ||
228 | * this function to update the tracked value (after clamping and other | ||
229 | * restrictions have been applied). | ||
230 | * | ||
231 | * Returns: | ||
232 | * Zero on success, error code on failure. | ||
233 | */ | ||
234 | int drm_object_property_set_value(struct drm_mode_object *obj, | ||
235 | struct drm_property *property, uint64_t val) | ||
236 | { | ||
237 | int i; | ||
238 | |||
239 | for (i = 0; i < obj->properties->count; i++) { | ||
240 | if (obj->properties->properties[i] == property) { | ||
241 | obj->properties->values[i] = val; | ||
242 | return 0; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | return -EINVAL; | ||
247 | } | ||
248 | EXPORT_SYMBOL(drm_object_property_set_value); | ||
249 | |||
250 | /** | ||
251 | * drm_object_property_get_value - retrieve the value of a property | ||
252 | * @obj: drm mode object to get property value from | ||
253 | * @property: property to retrieve | ||
254 | * @val: storage for the property value | ||
255 | * | ||
256 | * This function retrieves the softare state of the given property for the given | ||
257 | * property. Since there is no driver callback to retrieve the current property | ||
258 | * value this might be out of sync with the hardware, depending upon the driver | ||
259 | * and property. | ||
260 | * | ||
261 | * Atomic drivers should never call this function directly, the core will read | ||
262 | * out property values through the various ->atomic_get_property callbacks. | ||
263 | * | ||
264 | * Returns: | ||
265 | * Zero on success, error code on failure. | ||
266 | */ | ||
267 | int drm_object_property_get_value(struct drm_mode_object *obj, | ||
268 | struct drm_property *property, uint64_t *val) | ||
269 | { | ||
270 | int i; | ||
271 | |||
272 | /* read-only properties bypass atomic mechanism and still store | ||
273 | * their value in obj->properties->values[].. mostly to avoid | ||
274 | * having to deal w/ EDID and similar props in atomic paths: | ||
275 | */ | ||
276 | if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && | ||
277 | !(property->flags & DRM_MODE_PROP_IMMUTABLE)) | ||
278 | return drm_atomic_get_property(obj, property, val); | ||
279 | |||
280 | for (i = 0; i < obj->properties->count; i++) { | ||
281 | if (obj->properties->properties[i] == property) { | ||
282 | *val = obj->properties->values[i]; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | } | ||
287 | |||
288 | return -EINVAL; | ||
289 | } | ||
290 | EXPORT_SYMBOL(drm_object_property_get_value); | ||
291 | |||
292 | /* helper for getconnector and getproperties ioctls */ | ||
293 | int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, | ||
294 | uint32_t __user *prop_ptr, | ||
295 | uint64_t __user *prop_values, | ||
296 | uint32_t *arg_count_props) | ||
297 | { | ||
298 | int i, ret, count; | ||
299 | |||
300 | for (i = 0, count = 0; i < obj->properties->count; i++) { | ||
301 | struct drm_property *prop = obj->properties->properties[i]; | ||
302 | uint64_t val; | ||
303 | |||
304 | if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) | ||
305 | continue; | ||
306 | |||
307 | if (*arg_count_props > count) { | ||
308 | ret = drm_object_property_get_value(obj, prop, &val); | ||
309 | if (ret) | ||
310 | return ret; | ||
311 | |||
312 | if (put_user(prop->base.id, prop_ptr + count)) | ||
313 | return -EFAULT; | ||
314 | |||
315 | if (put_user(val, prop_values + count)) | ||
316 | return -EFAULT; | ||
317 | } | ||
318 | |||
319 | count++; | ||
320 | } | ||
321 | *arg_count_props = count; | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * drm_mode_obj_get_properties_ioctl - get the current value of a object's property | ||
328 | * @dev: DRM device | ||
329 | * @data: ioctl data | ||
330 | * @file_priv: DRM file info | ||
331 | * | ||
332 | * This function retrieves the current value for an object's property. Compared | ||
333 | * to the connector specific ioctl this one is extended to also work on crtc and | ||
334 | * plane objects. | ||
335 | * | ||
336 | * Called by the user via ioctl. | ||
337 | * | ||
338 | * Returns: | ||
339 | * Zero on success, negative errno on failure. | ||
340 | */ | ||
341 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | ||
342 | struct drm_file *file_priv) | ||
343 | { | ||
344 | struct drm_mode_obj_get_properties *arg = data; | ||
345 | struct drm_mode_object *obj; | ||
346 | int ret = 0; | ||
347 | |||
348 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
349 | return -EINVAL; | ||
350 | |||
351 | drm_modeset_lock_all(dev); | ||
352 | |||
353 | obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); | ||
354 | if (!obj) { | ||
355 | ret = -ENOENT; | ||
356 | goto out; | ||
357 | } | ||
358 | if (!obj->properties) { | ||
359 | ret = -EINVAL; | ||
360 | goto out_unref; | ||
361 | } | ||
362 | |||
363 | ret = drm_mode_object_get_properties(obj, file_priv->atomic, | ||
364 | (uint32_t __user *)(unsigned long)(arg->props_ptr), | ||
365 | (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), | ||
366 | &arg->count_props); | ||
367 | |||
368 | out_unref: | ||
369 | drm_mode_object_unreference(obj); | ||
370 | out: | ||
371 | drm_modeset_unlock_all(dev); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | ||
376 | struct drm_file *file_priv) | ||
377 | { | ||
378 | struct drm_mode_obj_set_property *arg = data; | ||
379 | struct drm_mode_object *arg_obj; | ||
380 | struct drm_mode_object *prop_obj; | ||
381 | struct drm_property *property; | ||
382 | int i, ret = -EINVAL; | ||
383 | struct drm_mode_object *ref; | ||
384 | |||
385 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
386 | return -EINVAL; | ||
387 | |||
388 | drm_modeset_lock_all(dev); | ||
389 | |||
390 | arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); | ||
391 | if (!arg_obj) { | ||
392 | ret = -ENOENT; | ||
393 | goto out; | ||
394 | } | ||
395 | if (!arg_obj->properties) | ||
396 | goto out_unref; | ||
397 | |||
398 | for (i = 0; i < arg_obj->properties->count; i++) | ||
399 | if (arg_obj->properties->properties[i]->base.id == arg->prop_id) | ||
400 | break; | ||
401 | |||
402 | if (i == arg_obj->properties->count) | ||
403 | goto out_unref; | ||
404 | |||
405 | prop_obj = drm_mode_object_find(dev, arg->prop_id, | ||
406 | DRM_MODE_OBJECT_PROPERTY); | ||
407 | if (!prop_obj) { | ||
408 | ret = -ENOENT; | ||
409 | goto out_unref; | ||
410 | } | ||
411 | property = obj_to_property(prop_obj); | ||
412 | |||
413 | if (!drm_property_change_valid_get(property, arg->value, &ref)) | ||
414 | goto out_unref; | ||
415 | |||
416 | switch (arg_obj->type) { | ||
417 | case DRM_MODE_OBJECT_CONNECTOR: | ||
418 | ret = drm_mode_connector_set_obj_prop(arg_obj, property, | ||
419 | arg->value); | ||
420 | break; | ||
421 | case DRM_MODE_OBJECT_CRTC: | ||
422 | ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); | ||
423 | break; | ||
424 | case DRM_MODE_OBJECT_PLANE: | ||
425 | ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), | ||
426 | property, arg->value); | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | drm_property_change_valid_put(property, ref); | ||
431 | |||
432 | out_unref: | ||
433 | drm_mode_object_unreference(arg_obj); | ||
434 | out: | ||
435 | drm_modeset_unlock_all(dev); | ||
436 | return ret; | ||
437 | } | ||
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index a0df377d7d1c..f6b64d7d3528 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c | |||
@@ -129,6 +129,7 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev) | |||
129 | { | 129 | { |
130 | bool poll = false; | 130 | bool poll = false; |
131 | struct drm_connector *connector; | 131 | struct drm_connector *connector; |
132 | unsigned long delay = DRM_OUTPUT_POLL_PERIOD; | ||
132 | 133 | ||
133 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | 134 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
134 | 135 | ||
@@ -141,8 +142,13 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev) | |||
141 | poll = true; | 142 | poll = true; |
142 | } | 143 | } |
143 | 144 | ||
145 | if (dev->mode_config.delayed_event) { | ||
146 | poll = true; | ||
147 | delay = 0; | ||
148 | } | ||
149 | |||
144 | if (poll) | 150 | if (poll) |
145 | schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); | 151 | schedule_delayed_work(&dev->mode_config.output_poll_work, delay); |
146 | } | 152 | } |
147 | EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked); | 153 | EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked); |
148 | 154 | ||
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c new file mode 100644 index 000000000000..4139afbcc267 --- /dev/null +++ b/drivers/gpu/drm/drm_property.c | |||
@@ -0,0 +1,899 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <linux/export.h> | ||
24 | #include <drm/drmP.h> | ||
25 | #include <drm/drm_property.h> | ||
26 | |||
27 | #include "drm_crtc_internal.h" | ||
28 | |||
29 | /** | ||
30 | * DOC: overview | ||
31 | * | ||
32 | * Properties as represented by &drm_property are used to extend the modeset | ||
33 | * interface exposed to userspace. For the atomic modeset IOCTL properties are | ||
34 | * even the only way to transport metadata about the desired new modeset | ||
35 | * configuration from userspace to the kernel. Properties have a well-defined | ||
36 | * value range, which is enforced by the drm core. See the documentation of the | ||
37 | * flags member of struct &drm_property for an overview of the different | ||
38 | * property types and ranges. | ||
39 | * | ||
40 | * Properties don't store the current value directly, but need to be | ||
41 | * instatiated by attaching them to a &drm_mode_object with | ||
42 | * drm_object_attach_property(). | ||
43 | * | ||
44 | * Property values are only 64bit. To support bigger piles of data (like gamma | ||
45 | * tables, color correction matrizes or large structures) a property can instead | ||
46 | * point at a &drm_property_blob with that additional data | ||
47 | * | ||
48 | * Properties are defined by their symbolic name, userspace must keep a | ||
49 | * per-object mapping from those names to the property ID used in the atomic | ||
50 | * IOCTL and in the get/set property IOCTL. | ||
51 | */ | ||
52 | |||
53 | static bool drm_property_type_valid(struct drm_property *property) | ||
54 | { | ||
55 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
56 | return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
57 | return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * drm_property_create - create a new property type | ||
62 | * @dev: drm device | ||
63 | * @flags: flags specifying the property type | ||
64 | * @name: name of the property | ||
65 | * @num_values: number of pre-defined values | ||
66 | * | ||
67 | * This creates a new generic drm property which can then be attached to a drm | ||
68 | * object with drm_object_attach_property. The returned property object must be | ||
69 | * freed with drm_property_destroy(), which is done automatically when calling | ||
70 | * drm_mode_config_cleanup(). | ||
71 | * | ||
72 | * Returns: | ||
73 | * A pointer to the newly created property on success, NULL on failure. | ||
74 | */ | ||
75 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
76 | const char *name, int num_values) | ||
77 | { | ||
78 | struct drm_property *property = NULL; | ||
79 | int ret; | ||
80 | |||
81 | property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); | ||
82 | if (!property) | ||
83 | return NULL; | ||
84 | |||
85 | property->dev = dev; | ||
86 | |||
87 | if (num_values) { | ||
88 | property->values = kcalloc(num_values, sizeof(uint64_t), | ||
89 | GFP_KERNEL); | ||
90 | if (!property->values) | ||
91 | goto fail; | ||
92 | } | ||
93 | |||
94 | ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); | ||
95 | if (ret) | ||
96 | goto fail; | ||
97 | |||
98 | property->flags = flags; | ||
99 | property->num_values = num_values; | ||
100 | INIT_LIST_HEAD(&property->enum_list); | ||
101 | |||
102 | if (name) { | ||
103 | strncpy(property->name, name, DRM_PROP_NAME_LEN); | ||
104 | property->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
105 | } | ||
106 | |||
107 | list_add_tail(&property->head, &dev->mode_config.property_list); | ||
108 | |||
109 | WARN_ON(!drm_property_type_valid(property)); | ||
110 | |||
111 | return property; | ||
112 | fail: | ||
113 | kfree(property->values); | ||
114 | kfree(property); | ||
115 | return NULL; | ||
116 | } | ||
117 | EXPORT_SYMBOL(drm_property_create); | ||
118 | |||
119 | /** | ||
120 | * drm_property_create_enum - create a new enumeration property type | ||
121 | * @dev: drm device | ||
122 | * @flags: flags specifying the property type | ||
123 | * @name: name of the property | ||
124 | * @props: enumeration lists with property values | ||
125 | * @num_values: number of pre-defined values | ||
126 | * | ||
127 | * This creates a new generic drm property which can then be attached to a drm | ||
128 | * object with drm_object_attach_property. The returned property object must be | ||
129 | * freed with drm_property_destroy(), which is done automatically when calling | ||
130 | * drm_mode_config_cleanup(). | ||
131 | * | ||
132 | * Userspace is only allowed to set one of the predefined values for enumeration | ||
133 | * properties. | ||
134 | * | ||
135 | * Returns: | ||
136 | * A pointer to the newly created property on success, NULL on failure. | ||
137 | */ | ||
138 | struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
139 | const char *name, | ||
140 | const struct drm_prop_enum_list *props, | ||
141 | int num_values) | ||
142 | { | ||
143 | struct drm_property *property; | ||
144 | int i, ret; | ||
145 | |||
146 | flags |= DRM_MODE_PROP_ENUM; | ||
147 | |||
148 | property = drm_property_create(dev, flags, name, num_values); | ||
149 | if (!property) | ||
150 | return NULL; | ||
151 | |||
152 | for (i = 0; i < num_values; i++) { | ||
153 | ret = drm_property_add_enum(property, i, | ||
154 | props[i].type, | ||
155 | props[i].name); | ||
156 | if (ret) { | ||
157 | drm_property_destroy(dev, property); | ||
158 | return NULL; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | return property; | ||
163 | } | ||
164 | EXPORT_SYMBOL(drm_property_create_enum); | ||
165 | |||
166 | /** | ||
167 | * drm_property_create_bitmask - create a new bitmask property type | ||
168 | * @dev: drm device | ||
169 | * @flags: flags specifying the property type | ||
170 | * @name: name of the property | ||
171 | * @props: enumeration lists with property bitflags | ||
172 | * @num_props: size of the @props array | ||
173 | * @supported_bits: bitmask of all supported enumeration values | ||
174 | * | ||
175 | * This creates a new bitmask drm property which can then be attached to a drm | ||
176 | * object with drm_object_attach_property. The returned property object must be | ||
177 | * freed with drm_property_destroy(), which is done automatically when calling | ||
178 | * drm_mode_config_cleanup(). | ||
179 | * | ||
180 | * Compared to plain enumeration properties userspace is allowed to set any | ||
181 | * or'ed together combination of the predefined property bitflag values | ||
182 | * | ||
183 | * Returns: | ||
184 | * A pointer to the newly created property on success, NULL on failure. | ||
185 | */ | ||
186 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
187 | int flags, const char *name, | ||
188 | const struct drm_prop_enum_list *props, | ||
189 | int num_props, | ||
190 | uint64_t supported_bits) | ||
191 | { | ||
192 | struct drm_property *property; | ||
193 | int i, ret, index = 0; | ||
194 | int num_values = hweight64(supported_bits); | ||
195 | |||
196 | flags |= DRM_MODE_PROP_BITMASK; | ||
197 | |||
198 | property = drm_property_create(dev, flags, name, num_values); | ||
199 | if (!property) | ||
200 | return NULL; | ||
201 | for (i = 0; i < num_props; i++) { | ||
202 | if (!(supported_bits & (1ULL << props[i].type))) | ||
203 | continue; | ||
204 | |||
205 | if (WARN_ON(index >= num_values)) { | ||
206 | drm_property_destroy(dev, property); | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | ret = drm_property_add_enum(property, index++, | ||
211 | props[i].type, | ||
212 | props[i].name); | ||
213 | if (ret) { | ||
214 | drm_property_destroy(dev, property); | ||
215 | return NULL; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | return property; | ||
220 | } | ||
221 | EXPORT_SYMBOL(drm_property_create_bitmask); | ||
222 | |||
223 | static struct drm_property *property_create_range(struct drm_device *dev, | ||
224 | int flags, const char *name, | ||
225 | uint64_t min, uint64_t max) | ||
226 | { | ||
227 | struct drm_property *property; | ||
228 | |||
229 | property = drm_property_create(dev, flags, name, 2); | ||
230 | if (!property) | ||
231 | return NULL; | ||
232 | |||
233 | property->values[0] = min; | ||
234 | property->values[1] = max; | ||
235 | |||
236 | return property; | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * drm_property_create_range - create a new unsigned ranged property type | ||
241 | * @dev: drm device | ||
242 | * @flags: flags specifying the property type | ||
243 | * @name: name of the property | ||
244 | * @min: minimum value of the property | ||
245 | * @max: maximum value of the property | ||
246 | * | ||
247 | * This creates a new generic drm property which can then be attached to a drm | ||
248 | * object with drm_object_attach_property. The returned property object must be | ||
249 | * freed with drm_property_destroy(), which is done automatically when calling | ||
250 | * drm_mode_config_cleanup(). | ||
251 | * | ||
252 | * Userspace is allowed to set any unsigned integer value in the (min, max) | ||
253 | * range inclusive. | ||
254 | * | ||
255 | * Returns: | ||
256 | * A pointer to the newly created property on success, NULL on failure. | ||
257 | */ | ||
258 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
259 | const char *name, | ||
260 | uint64_t min, uint64_t max) | ||
261 | { | ||
262 | return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, | ||
263 | name, min, max); | ||
264 | } | ||
265 | EXPORT_SYMBOL(drm_property_create_range); | ||
266 | |||
267 | /** | ||
268 | * drm_property_create_signed_range - create a new signed ranged property type | ||
269 | * @dev: drm device | ||
270 | * @flags: flags specifying the property type | ||
271 | * @name: name of the property | ||
272 | * @min: minimum value of the property | ||
273 | * @max: maximum value of the property | ||
274 | * | ||
275 | * This creates a new generic drm property which can then be attached to a drm | ||
276 | * object with drm_object_attach_property. The returned property object must be | ||
277 | * freed with drm_property_destroy(), which is done automatically when calling | ||
278 | * drm_mode_config_cleanup(). | ||
279 | * | ||
280 | * Userspace is allowed to set any signed integer value in the (min, max) | ||
281 | * range inclusive. | ||
282 | * | ||
283 | * Returns: | ||
284 | * A pointer to the newly created property on success, NULL on failure. | ||
285 | */ | ||
286 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
287 | int flags, const char *name, | ||
288 | int64_t min, int64_t max) | ||
289 | { | ||
290 | return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, | ||
291 | name, I642U64(min), I642U64(max)); | ||
292 | } | ||
293 | EXPORT_SYMBOL(drm_property_create_signed_range); | ||
294 | |||
295 | /** | ||
296 | * drm_property_create_object - create a new object property type | ||
297 | * @dev: drm device | ||
298 | * @flags: flags specifying the property type | ||
299 | * @name: name of the property | ||
300 | * @type: object type from DRM_MODE_OBJECT_* defines | ||
301 | * | ||
302 | * This creates a new generic drm property which can then be attached to a drm | ||
303 | * object with drm_object_attach_property. The returned property object must be | ||
304 | * freed with drm_property_destroy(), which is done automatically when calling | ||
305 | * drm_mode_config_cleanup(). | ||
306 | * | ||
307 | * Userspace is only allowed to set this to any property value of the given | ||
308 | * @type. Only useful for atomic properties, which is enforced. | ||
309 | * | ||
310 | * Returns: | ||
311 | * A pointer to the newly created property on success, NULL on failure. | ||
312 | */ | ||
313 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
314 | int flags, const char *name, | ||
315 | uint32_t type) | ||
316 | { | ||
317 | struct drm_property *property; | ||
318 | |||
319 | flags |= DRM_MODE_PROP_OBJECT; | ||
320 | |||
321 | if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) | ||
322 | return NULL; | ||
323 | |||
324 | property = drm_property_create(dev, flags, name, 1); | ||
325 | if (!property) | ||
326 | return NULL; | ||
327 | |||
328 | property->values[0] = type; | ||
329 | |||
330 | return property; | ||
331 | } | ||
332 | EXPORT_SYMBOL(drm_property_create_object); | ||
333 | |||
334 | /** | ||
335 | * drm_property_create_bool - create a new boolean property type | ||
336 | * @dev: drm device | ||
337 | * @flags: flags specifying the property type | ||
338 | * @name: name of the property | ||
339 | * | ||
340 | * This creates a new generic drm property which can then be attached to a drm | ||
341 | * object with drm_object_attach_property. The returned property object must be | ||
342 | * freed with drm_property_destroy(), which is done automatically when calling | ||
343 | * drm_mode_config_cleanup(). | ||
344 | * | ||
345 | * This is implemented as a ranged property with only {0, 1} as valid values. | ||
346 | * | ||
347 | * Returns: | ||
348 | * A pointer to the newly created property on success, NULL on failure. | ||
349 | */ | ||
350 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
351 | const char *name) | ||
352 | { | ||
353 | return drm_property_create_range(dev, flags, name, 0, 1); | ||
354 | } | ||
355 | EXPORT_SYMBOL(drm_property_create_bool); | ||
356 | |||
357 | /** | ||
358 | * drm_property_add_enum - add a possible value to an enumeration property | ||
359 | * @property: enumeration property to change | ||
360 | * @index: index of the new enumeration | ||
361 | * @value: value of the new enumeration | ||
362 | * @name: symbolic name of the new enumeration | ||
363 | * | ||
364 | * This functions adds enumerations to a property. | ||
365 | * | ||
366 | * It's use is deprecated, drivers should use one of the more specific helpers | ||
367 | * to directly create the property with all enumerations already attached. | ||
368 | * | ||
369 | * Returns: | ||
370 | * Zero on success, error code on failure. | ||
371 | */ | ||
372 | int drm_property_add_enum(struct drm_property *property, int index, | ||
373 | uint64_t value, const char *name) | ||
374 | { | ||
375 | struct drm_property_enum *prop_enum; | ||
376 | |||
377 | if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
378 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) | ||
379 | return -EINVAL; | ||
380 | |||
381 | /* | ||
382 | * Bitmask enum properties have the additional constraint of values | ||
383 | * from 0 to 63 | ||
384 | */ | ||
385 | if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && | ||
386 | (value > 63)) | ||
387 | return -EINVAL; | ||
388 | |||
389 | if (!list_empty(&property->enum_list)) { | ||
390 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
391 | if (prop_enum->value == value) { | ||
392 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
393 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
394 | return 0; | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); | ||
400 | if (!prop_enum) | ||
401 | return -ENOMEM; | ||
402 | |||
403 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
404 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
405 | prop_enum->value = value; | ||
406 | |||
407 | property->values[index] = value; | ||
408 | list_add_tail(&prop_enum->head, &property->enum_list); | ||
409 | return 0; | ||
410 | } | ||
411 | EXPORT_SYMBOL(drm_property_add_enum); | ||
412 | |||
413 | /** | ||
414 | * drm_property_destroy - destroy a drm property | ||
415 | * @dev: drm device | ||
416 | * @property: property to destry | ||
417 | * | ||
418 | * This function frees a property including any attached resources like | ||
419 | * enumeration values. | ||
420 | */ | ||
421 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property) | ||
422 | { | ||
423 | struct drm_property_enum *prop_enum, *pt; | ||
424 | |||
425 | list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { | ||
426 | list_del(&prop_enum->head); | ||
427 | kfree(prop_enum); | ||
428 | } | ||
429 | |||
430 | if (property->num_values) | ||
431 | kfree(property->values); | ||
432 | drm_mode_object_unregister(dev, &property->base); | ||
433 | list_del(&property->head); | ||
434 | kfree(property); | ||
435 | } | ||
436 | EXPORT_SYMBOL(drm_property_destroy); | ||
437 | |||
438 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
439 | void *data, struct drm_file *file_priv) | ||
440 | { | ||
441 | struct drm_mode_get_property *out_resp = data; | ||
442 | struct drm_property *property; | ||
443 | int enum_count = 0; | ||
444 | int value_count = 0; | ||
445 | int ret = 0, i; | ||
446 | int copied; | ||
447 | struct drm_property_enum *prop_enum; | ||
448 | struct drm_mode_property_enum __user *enum_ptr; | ||
449 | uint64_t __user *values_ptr; | ||
450 | |||
451 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
452 | return -EINVAL; | ||
453 | |||
454 | drm_modeset_lock_all(dev); | ||
455 | property = drm_property_find(dev, out_resp->prop_id); | ||
456 | if (!property) { | ||
457 | ret = -ENOENT; | ||
458 | goto done; | ||
459 | } | ||
460 | |||
461 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
462 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
463 | list_for_each_entry(prop_enum, &property->enum_list, head) | ||
464 | enum_count++; | ||
465 | } | ||
466 | |||
467 | value_count = property->num_values; | ||
468 | |||
469 | strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); | ||
470 | out_resp->name[DRM_PROP_NAME_LEN-1] = 0; | ||
471 | out_resp->flags = property->flags; | ||
472 | |||
473 | if ((out_resp->count_values >= value_count) && value_count) { | ||
474 | values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; | ||
475 | for (i = 0; i < value_count; i++) { | ||
476 | if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { | ||
477 | ret = -EFAULT; | ||
478 | goto done; | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | out_resp->count_values = value_count; | ||
483 | |||
484 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | ||
485 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
486 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { | ||
487 | copied = 0; | ||
488 | enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; | ||
489 | list_for_each_entry(prop_enum, &property->enum_list, head) { | ||
490 | |||
491 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { | ||
492 | ret = -EFAULT; | ||
493 | goto done; | ||
494 | } | ||
495 | |||
496 | if (copy_to_user(&enum_ptr[copied].name, | ||
497 | &prop_enum->name, DRM_PROP_NAME_LEN)) { | ||
498 | ret = -EFAULT; | ||
499 | goto done; | ||
500 | } | ||
501 | copied++; | ||
502 | } | ||
503 | } | ||
504 | out_resp->count_enum_blobs = enum_count; | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * NOTE: The idea seems to have been to use this to read all the blob | ||
509 | * property values. But nothing ever added them to the corresponding | ||
510 | * list, userspace always used the special-purpose get_blob ioctl to | ||
511 | * read the value for a blob property. It also doesn't make a lot of | ||
512 | * sense to return values here when everything else is just metadata for | ||
513 | * the property itself. | ||
514 | */ | ||
515 | if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
516 | out_resp->count_enum_blobs = 0; | ||
517 | done: | ||
518 | drm_modeset_unlock_all(dev); | ||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | static void drm_property_free_blob(struct kref *kref) | ||
523 | { | ||
524 | struct drm_property_blob *blob = | ||
525 | container_of(kref, struct drm_property_blob, base.refcount); | ||
526 | |||
527 | mutex_lock(&blob->dev->mode_config.blob_lock); | ||
528 | list_del(&blob->head_global); | ||
529 | mutex_unlock(&blob->dev->mode_config.blob_lock); | ||
530 | |||
531 | drm_mode_object_unregister(blob->dev, &blob->base); | ||
532 | |||
533 | kfree(blob); | ||
534 | } | ||
535 | |||
536 | /** | ||
537 | * drm_property_create_blob - Create new blob property | ||
538 | * @dev: DRM device to create property for | ||
539 | * @length: Length to allocate for blob data | ||
540 | * @data: If specified, copies data into blob | ||
541 | * | ||
542 | * Creates a new blob property for a specified DRM device, optionally | ||
543 | * copying data. Note that blob properties are meant to be invariant, hence the | ||
544 | * data must be filled out before the blob is used as the value of any property. | ||
545 | * | ||
546 | * Returns: | ||
547 | * New blob property with a single reference on success, or an ERR_PTR | ||
548 | * value on failure. | ||
549 | */ | ||
550 | struct drm_property_blob * | ||
551 | drm_property_create_blob(struct drm_device *dev, size_t length, | ||
552 | const void *data) | ||
553 | { | ||
554 | struct drm_property_blob *blob; | ||
555 | int ret; | ||
556 | |||
557 | if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) | ||
558 | return ERR_PTR(-EINVAL); | ||
559 | |||
560 | blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); | ||
561 | if (!blob) | ||
562 | return ERR_PTR(-ENOMEM); | ||
563 | |||
564 | /* This must be explicitly initialised, so we can safely call list_del | ||
565 | * on it in the removal handler, even if it isn't in a file list. */ | ||
566 | INIT_LIST_HEAD(&blob->head_file); | ||
567 | blob->length = length; | ||
568 | blob->dev = dev; | ||
569 | |||
570 | if (data) | ||
571 | memcpy(blob->data, data, length); | ||
572 | |||
573 | ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, | ||
574 | true, drm_property_free_blob); | ||
575 | if (ret) { | ||
576 | kfree(blob); | ||
577 | return ERR_PTR(-EINVAL); | ||
578 | } | ||
579 | |||
580 | mutex_lock(&dev->mode_config.blob_lock); | ||
581 | list_add_tail(&blob->head_global, | ||
582 | &dev->mode_config.property_blob_list); | ||
583 | mutex_unlock(&dev->mode_config.blob_lock); | ||
584 | |||
585 | return blob; | ||
586 | } | ||
587 | EXPORT_SYMBOL(drm_property_create_blob); | ||
588 | |||
589 | /** | ||
590 | * drm_property_unreference_blob - Unreference a blob property | ||
591 | * @blob: Pointer to blob property | ||
592 | * | ||
593 | * Drop a reference on a blob property. May free the object. | ||
594 | */ | ||
595 | void drm_property_unreference_blob(struct drm_property_blob *blob) | ||
596 | { | ||
597 | if (!blob) | ||
598 | return; | ||
599 | |||
600 | drm_mode_object_unreference(&blob->base); | ||
601 | } | ||
602 | EXPORT_SYMBOL(drm_property_unreference_blob); | ||
603 | |||
604 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
605 | struct drm_file *file_priv) | ||
606 | { | ||
607 | struct drm_property_blob *blob, *bt; | ||
608 | |||
609 | /* | ||
610 | * When the file gets released that means no one else can access the | ||
611 | * blob list any more, so no need to grab dev->blob_lock. | ||
612 | */ | ||
613 | list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { | ||
614 | list_del_init(&blob->head_file); | ||
615 | drm_property_unreference_blob(blob); | ||
616 | } | ||
617 | } | ||
618 | |||
619 | /** | ||
620 | * drm_property_reference_blob - Take a reference on an existing property | ||
621 | * @blob: Pointer to blob property | ||
622 | * | ||
623 | * Take a new reference on an existing blob property. Returns @blob, which | ||
624 | * allows this to be used as a shorthand in assignments. | ||
625 | */ | ||
626 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) | ||
627 | { | ||
628 | drm_mode_object_reference(&blob->base); | ||
629 | return blob; | ||
630 | } | ||
631 | EXPORT_SYMBOL(drm_property_reference_blob); | ||
632 | |||
633 | /** | ||
634 | * drm_property_lookup_blob - look up a blob property and take a reference | ||
635 | * @dev: drm device | ||
636 | * @id: id of the blob property | ||
637 | * | ||
638 | * If successful, this takes an additional reference to the blob property. | ||
639 | * callers need to make sure to eventually unreference the returned property | ||
640 | * again, using @drm_property_unreference_blob. | ||
641 | * | ||
642 | * Return: | ||
643 | * NULL on failure, pointer to the blob on success. | ||
644 | */ | ||
645 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
646 | uint32_t id) | ||
647 | { | ||
648 | struct drm_mode_object *obj; | ||
649 | struct drm_property_blob *blob = NULL; | ||
650 | |||
651 | obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); | ||
652 | if (obj) | ||
653 | blob = obj_to_blob(obj); | ||
654 | return blob; | ||
655 | } | ||
656 | EXPORT_SYMBOL(drm_property_lookup_blob); | ||
657 | |||
658 | /** | ||
659 | * drm_property_replace_global_blob - replace existing blob property | ||
660 | * @dev: drm device | ||
661 | * @replace: location of blob property pointer to be replaced | ||
662 | * @length: length of data for new blob, or 0 for no data | ||
663 | * @data: content for new blob, or NULL for no data | ||
664 | * @obj_holds_id: optional object for property holding blob ID | ||
665 | * @prop_holds_id: optional property holding blob ID | ||
666 | * @return 0 on success or error on failure | ||
667 | * | ||
668 | * This function will replace a global property in the blob list, optionally | ||
669 | * updating a property which holds the ID of that property. | ||
670 | * | ||
671 | * If length is 0 or data is NULL, no new blob will be created, and the holding | ||
672 | * property, if specified, will be set to 0. | ||
673 | * | ||
674 | * Access to the replace pointer is assumed to be protected by the caller, e.g. | ||
675 | * by holding the relevant modesetting object lock for its parent. | ||
676 | * | ||
677 | * For example, a drm_connector has a 'PATH' property, which contains the ID | ||
678 | * of a blob property with the value of the MST path information. Calling this | ||
679 | * function with replace pointing to the connector's path_blob_ptr, length and | ||
680 | * data set for the new path information, obj_holds_id set to the connector's | ||
681 | * base object, and prop_holds_id set to the path property name, will perform | ||
682 | * a completely atomic update. The access to path_blob_ptr is protected by the | ||
683 | * caller holding a lock on the connector. | ||
684 | */ | ||
685 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
686 | struct drm_property_blob **replace, | ||
687 | size_t length, | ||
688 | const void *data, | ||
689 | struct drm_mode_object *obj_holds_id, | ||
690 | struct drm_property *prop_holds_id) | ||
691 | { | ||
692 | struct drm_property_blob *new_blob = NULL; | ||
693 | struct drm_property_blob *old_blob = NULL; | ||
694 | int ret; | ||
695 | |||
696 | WARN_ON(replace == NULL); | ||
697 | |||
698 | old_blob = *replace; | ||
699 | |||
700 | if (length && data) { | ||
701 | new_blob = drm_property_create_blob(dev, length, data); | ||
702 | if (IS_ERR(new_blob)) | ||
703 | return PTR_ERR(new_blob); | ||
704 | } | ||
705 | |||
706 | if (obj_holds_id) { | ||
707 | ret = drm_object_property_set_value(obj_holds_id, | ||
708 | prop_holds_id, | ||
709 | new_blob ? | ||
710 | new_blob->base.id : 0); | ||
711 | if (ret != 0) | ||
712 | goto err_created; | ||
713 | } | ||
714 | |||
715 | drm_property_unreference_blob(old_blob); | ||
716 | *replace = new_blob; | ||
717 | |||
718 | return 0; | ||
719 | |||
720 | err_created: | ||
721 | drm_property_unreference_blob(new_blob); | ||
722 | return ret; | ||
723 | } | ||
724 | EXPORT_SYMBOL(drm_property_replace_global_blob); | ||
725 | |||
726 | int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
727 | void *data, struct drm_file *file_priv) | ||
728 | { | ||
729 | struct drm_mode_get_blob *out_resp = data; | ||
730 | struct drm_property_blob *blob; | ||
731 | int ret = 0; | ||
732 | void __user *blob_ptr; | ||
733 | |||
734 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
735 | return -EINVAL; | ||
736 | |||
737 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
738 | if (!blob) | ||
739 | return -ENOENT; | ||
740 | |||
741 | if (out_resp->length == blob->length) { | ||
742 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
743 | if (copy_to_user(blob_ptr, blob->data, blob->length)) { | ||
744 | ret = -EFAULT; | ||
745 | goto unref; | ||
746 | } | ||
747 | } | ||
748 | out_resp->length = blob->length; | ||
749 | unref: | ||
750 | drm_property_unreference_blob(blob); | ||
751 | |||
752 | return ret; | ||
753 | } | ||
754 | |||
755 | int drm_mode_createblob_ioctl(struct drm_device *dev, | ||
756 | void *data, struct drm_file *file_priv) | ||
757 | { | ||
758 | struct drm_mode_create_blob *out_resp = data; | ||
759 | struct drm_property_blob *blob; | ||
760 | void __user *blob_ptr; | ||
761 | int ret = 0; | ||
762 | |||
763 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
764 | return -EINVAL; | ||
765 | |||
766 | blob = drm_property_create_blob(dev, out_resp->length, NULL); | ||
767 | if (IS_ERR(blob)) | ||
768 | return PTR_ERR(blob); | ||
769 | |||
770 | blob_ptr = (void __user *)(unsigned long)out_resp->data; | ||
771 | if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { | ||
772 | ret = -EFAULT; | ||
773 | goto out_blob; | ||
774 | } | ||
775 | |||
776 | /* Dropping the lock between create_blob and our access here is safe | ||
777 | * as only the same file_priv can remove the blob; at this point, it is | ||
778 | * not associated with any file_priv. */ | ||
779 | mutex_lock(&dev->mode_config.blob_lock); | ||
780 | out_resp->blob_id = blob->base.id; | ||
781 | list_add_tail(&blob->head_file, &file_priv->blobs); | ||
782 | mutex_unlock(&dev->mode_config.blob_lock); | ||
783 | |||
784 | return 0; | ||
785 | |||
786 | out_blob: | ||
787 | drm_property_unreference_blob(blob); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | ||
792 | void *data, struct drm_file *file_priv) | ||
793 | { | ||
794 | struct drm_mode_destroy_blob *out_resp = data; | ||
795 | struct drm_property_blob *blob = NULL, *bt; | ||
796 | bool found = false; | ||
797 | int ret = 0; | ||
798 | |||
799 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
800 | return -EINVAL; | ||
801 | |||
802 | blob = drm_property_lookup_blob(dev, out_resp->blob_id); | ||
803 | if (!blob) | ||
804 | return -ENOENT; | ||
805 | |||
806 | mutex_lock(&dev->mode_config.blob_lock); | ||
807 | /* Ensure the property was actually created by this user. */ | ||
808 | list_for_each_entry(bt, &file_priv->blobs, head_file) { | ||
809 | if (bt == blob) { | ||
810 | found = true; | ||
811 | break; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | if (!found) { | ||
816 | ret = -EPERM; | ||
817 | goto err; | ||
818 | } | ||
819 | |||
820 | /* We must drop head_file here, because we may not be the last | ||
821 | * reference on the blob. */ | ||
822 | list_del_init(&blob->head_file); | ||
823 | mutex_unlock(&dev->mode_config.blob_lock); | ||
824 | |||
825 | /* One reference from lookup, and one from the filp. */ | ||
826 | drm_property_unreference_blob(blob); | ||
827 | drm_property_unreference_blob(blob); | ||
828 | |||
829 | return 0; | ||
830 | |||
831 | err: | ||
832 | mutex_unlock(&dev->mode_config.blob_lock); | ||
833 | drm_property_unreference_blob(blob); | ||
834 | |||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | /* Some properties could refer to dynamic refcnt'd objects, or things that | ||
839 | * need special locking to handle lifetime issues (ie. to ensure the prop | ||
840 | * value doesn't become invalid part way through the property update due to | ||
841 | * race). The value returned by reference via 'obj' should be passed back | ||
842 | * to drm_property_change_valid_put() after the property is set (and the | ||
843 | * object to which the property is attached has a chance to take it's own | ||
844 | * reference). | ||
845 | */ | ||
846 | bool drm_property_change_valid_get(struct drm_property *property, | ||
847 | uint64_t value, struct drm_mode_object **ref) | ||
848 | { | ||
849 | int i; | ||
850 | |||
851 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | ||
852 | return false; | ||
853 | |||
854 | *ref = NULL; | ||
855 | |||
856 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | ||
857 | if (value < property->values[0] || value > property->values[1]) | ||
858 | return false; | ||
859 | return true; | ||
860 | } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { | ||
861 | int64_t svalue = U642I64(value); | ||
862 | |||
863 | if (svalue < U642I64(property->values[0]) || | ||
864 | svalue > U642I64(property->values[1])) | ||
865 | return false; | ||
866 | return true; | ||
867 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||
868 | uint64_t valid_mask = 0; | ||
869 | |||
870 | for (i = 0; i < property->num_values; i++) | ||
871 | valid_mask |= (1ULL << property->values[i]); | ||
872 | return !(value & ~valid_mask); | ||
873 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB) || | ||
874 | drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
875 | /* a zero value for an object property translates to null: */ | ||
876 | if (value == 0) | ||
877 | return true; | ||
878 | |||
879 | *ref = __drm_mode_object_find(property->dev, value, | ||
880 | property->values[0]); | ||
881 | return *ref != NULL; | ||
882 | } | ||
883 | |||
884 | for (i = 0; i < property->num_values; i++) | ||
885 | if (property->values[i] == value) | ||
886 | return true; | ||
887 | return false; | ||
888 | } | ||
889 | |||
890 | void drm_property_change_valid_put(struct drm_property *property, | ||
891 | struct drm_mode_object *ref) | ||
892 | { | ||
893 | if (!ref) | ||
894 | return; | ||
895 | |||
896 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT) || | ||
897 | drm_property_type_is(property, DRM_MODE_PROP_BLOB)) | ||
898 | drm_mode_object_unreference(ref); | ||
899 | } | ||
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index bada17166512..7b6d26e64977 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c | |||
@@ -34,6 +34,12 @@ static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = { | |||
34 | .destroy = drm_encoder_cleanup, | 34 | .destroy = drm_encoder_cleanup, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, | ||
38 | struct drm_crtc_state *state) | ||
39 | { | ||
40 | return drm_atomic_add_affected_planes(state->state, crtc); | ||
41 | } | ||
42 | |||
37 | static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc) | 43 | static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc) |
38 | { | 44 | { |
39 | struct drm_simple_display_pipe *pipe; | 45 | struct drm_simple_display_pipe *pipe; |
@@ -57,6 +63,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc) | |||
57 | } | 63 | } |
58 | 64 | ||
59 | static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { | 65 | static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { |
66 | .atomic_check = drm_simple_kms_crtc_check, | ||
60 | .disable = drm_simple_kms_crtc_disable, | 67 | .disable = drm_simple_kms_crtc_disable, |
61 | .enable = drm_simple_kms_crtc_enable, | 68 | .enable = drm_simple_kms_crtc_enable, |
62 | }; | 69 | }; |
@@ -133,16 +140,61 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { | |||
133 | }; | 140 | }; |
134 | 141 | ||
135 | /** | 142 | /** |
143 | * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe | ||
144 | * @pipe: simple display pipe object | ||
145 | * @bridge: bridge to attach | ||
146 | * | ||
147 | * Makes it possible to still use the drm_simple_display_pipe helpers when | ||
148 | * a DRM bridge has to be used. | ||
149 | * | ||
150 | * Note that you probably want to initialize the pipe by passing a NULL | ||
151 | * connector to drm_simple_display_pipe_init(). | ||
152 | * | ||
153 | * Returns: | ||
154 | * Zero on success, negative error code on failure. | ||
155 | */ | ||
156 | int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, | ||
157 | struct drm_bridge *bridge) | ||
158 | { | ||
159 | bridge->encoder = &pipe->encoder; | ||
160 | pipe->encoder.bridge = bridge; | ||
161 | return drm_bridge_attach(pipe->encoder.dev, bridge); | ||
162 | } | ||
163 | EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge); | ||
164 | |||
165 | /** | ||
166 | * drm_simple_display_pipe_detach_bridge - Detach the bridge from the display pipe | ||
167 | * @pipe: simple display pipe object | ||
168 | * | ||
169 | * Detaches the drm bridge previously attached with | ||
170 | * drm_simple_display_pipe_attach_bridge() | ||
171 | */ | ||
172 | void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe *pipe) | ||
173 | { | ||
174 | if (WARN_ON(!pipe->encoder.bridge)) | ||
175 | return; | ||
176 | |||
177 | drm_bridge_detach(pipe->encoder.bridge); | ||
178 | pipe->encoder.bridge = NULL; | ||
179 | } | ||
180 | EXPORT_SYMBOL(drm_simple_display_pipe_detach_bridge); | ||
181 | |||
182 | /** | ||
136 | * drm_simple_display_pipe_init - Initialize a simple display pipeline | 183 | * drm_simple_display_pipe_init - Initialize a simple display pipeline |
137 | * @dev: DRM device | 184 | * @dev: DRM device |
138 | * @pipe: simple display pipe object to initialize | 185 | * @pipe: simple display pipe object to initialize |
139 | * @funcs: callbacks for the display pipe (optional) | 186 | * @funcs: callbacks for the display pipe (optional) |
140 | * @formats: array of supported formats (DRM_FORMAT\_\*) | 187 | * @formats: array of supported formats (DRM_FORMAT\_\*) |
141 | * @format_count: number of elements in @formats | 188 | * @format_count: number of elements in @formats |
142 | * @connector: connector to attach and register | 189 | * @connector: connector to attach and register (optional) |
143 | * | 190 | * |
144 | * Sets up a display pipeline which consist of a really simple | 191 | * Sets up a display pipeline which consist of a really simple |
145 | * plane-crtc-encoder pipe coupled with the provided connector. | 192 | * plane-crtc-encoder pipe. |
193 | * | ||
194 | * If a connector is supplied, the pipe will be coupled with the provided | ||
195 | * connector. You may supply a NULL connector when using drm bridges, that | ||
196 | * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()). | ||
197 | * | ||
146 | * Teardown of a simple display pipe is all handled automatically by the drm | 198 | * Teardown of a simple display pipe is all handled automatically by the drm |
147 | * core through calling drm_mode_config_cleanup(). Drivers afterwards need to | 199 | * core through calling drm_mode_config_cleanup(). Drivers afterwards need to |
148 | * release the memory for the structure themselves. | 200 | * release the memory for the structure themselves. |
@@ -181,7 +233,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev, | |||
181 | encoder->possible_crtcs = 1 << drm_crtc_index(crtc); | 233 | encoder->possible_crtcs = 1 << drm_crtc_index(crtc); |
182 | ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, | 234 | ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, |
183 | DRM_MODE_ENCODER_NONE, NULL); | 235 | DRM_MODE_ENCODER_NONE, NULL); |
184 | if (ret) | 236 | if (ret || !connector) |
185 | return ret; | 237 | return ret; |
186 | 238 | ||
187 | return drm_mode_connector_attach_encoder(connector, encoder); | 239 | return drm_mode_connector_attach_encoder(connector, encoder); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 877d2efa28e2..486943e70f70 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -105,7 +105,7 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) | |||
105 | atomic_inc(&exynos_crtc->pending_update); | 105 | atomic_inc(&exynos_crtc->pending_update); |
106 | } | 106 | } |
107 | 107 | ||
108 | drm_atomic_helper_commit_planes(dev, state, false); | 108 | drm_atomic_helper_commit_planes(dev, state, 0); |
109 | 109 | ||
110 | exynos_atomic_wait_for_commit(state); | 110 | exynos_atomic_wait_for_commit(state); |
111 | 111 | ||
diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index ab696ca7eeec..eab6d889bde9 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c | |||
@@ -163,10 +163,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) | |||
163 | if (bclp > 255) | 163 | if (bclp > 255) |
164 | return ASLE_BACKLIGHT_FAILED; | 164 | return ASLE_BACKLIGHT_FAILED; |
165 | 165 | ||
166 | if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) { | 166 | gma_backlight_set(dev, bclp * bd->props.max_brightness / 255); |
167 | int max = bd->props.max_brightness; | ||
168 | gma_backlight_set(dev, bclp * max / 255); | ||
169 | } | ||
170 | 167 | ||
171 | asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID; | 168 | asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID; |
172 | 169 | ||
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 438bac8fbc2b..56dfc4cd50c6 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
@@ -193,7 +193,8 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) | |||
193 | 193 | ||
194 | drm_atomic_helper_commit_modeset_disables(dev, state); | 194 | drm_atomic_helper_commit_modeset_disables(dev, state); |
195 | 195 | ||
196 | drm_atomic_helper_commit_planes(dev, state, true); | 196 | drm_atomic_helper_commit_planes(dev, state, |
197 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
197 | 198 | ||
198 | drm_atomic_helper_commit_modeset_enables(dev, state); | 199 | drm_atomic_helper_commit_modeset_enables(dev, state); |
199 | 200 | ||
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 0e769abd0c2c..72c1ae4e02d4 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c | |||
@@ -70,13 +70,15 @@ static void mtk_atomic_complete(struct mtk_drm_private *private, | |||
70 | * | 70 | * |
71 | * drm_atomic_helper_commit_modeset_disables(dev, state); | 71 | * drm_atomic_helper_commit_modeset_disables(dev, state); |
72 | * drm_atomic_helper_commit_modeset_enables(dev, state); | 72 | * drm_atomic_helper_commit_modeset_enables(dev, state); |
73 | * drm_atomic_helper_commit_planes(dev, state, true); | 73 | * drm_atomic_helper_commit_planes(dev, state, |
74 | * DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
74 | * | 75 | * |
75 | * See the kerneldoc entries for these three functions for more details. | 76 | * See the kerneldoc entries for these three functions for more details. |
76 | */ | 77 | */ |
77 | drm_atomic_helper_commit_modeset_disables(drm, state); | 78 | drm_atomic_helper_commit_modeset_disables(drm, state); |
78 | drm_atomic_helper_commit_modeset_enables(drm, state); | 79 | drm_atomic_helper_commit_modeset_enables(drm, state); |
79 | drm_atomic_helper_commit_planes(drm, state, true); | 80 | drm_atomic_helper_commit_planes(drm, state, |
81 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
80 | 82 | ||
81 | drm_atomic_helper_wait_for_vblanks(drm, state); | 83 | drm_atomic_helper_wait_for_vblanks(drm, state); |
82 | 84 | ||
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 4a8a6f1f1151..5df252cebf1c 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c | |||
@@ -118,7 +118,7 @@ static void complete_commit(struct msm_commit *c, bool async) | |||
118 | 118 | ||
119 | drm_atomic_helper_commit_modeset_disables(dev, state); | 119 | drm_atomic_helper_commit_modeset_disables(dev, state); |
120 | 120 | ||
121 | drm_atomic_helper_commit_planes(dev, state, false); | 121 | drm_atomic_helper_commit_planes(dev, state, 0); |
122 | 122 | ||
123 | drm_atomic_helper_commit_modeset_enables(dev, state); | 123 | drm_atomic_helper_commit_modeset_enables(dev, state); |
124 | 124 | ||
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 3dd78f2045f9..e1cfba51cff6 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
@@ -96,7 +96,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) | |||
96 | dispc_runtime_get(); | 96 | dispc_runtime_get(); |
97 | 97 | ||
98 | drm_atomic_helper_commit_modeset_disables(dev, old_state); | 98 | drm_atomic_helper_commit_modeset_disables(dev, old_state); |
99 | drm_atomic_helper_commit_planes(dev, old_state, false); | 99 | drm_atomic_helper_commit_planes(dev, old_state, 0); |
100 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | 100 | drm_atomic_helper_commit_modeset_enables(dev, old_state); |
101 | 101 | ||
102 | omap_atomic_wait_for_completion(dev, old_state); | 102 | omap_atomic_wait_for_completion(dev, old_state); |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index f03eb55318c1..bd9c3bb9252c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c | |||
@@ -257,7 +257,8 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit) | |||
257 | /* Apply the atomic update. */ | 257 | /* Apply the atomic update. */ |
258 | drm_atomic_helper_commit_modeset_disables(dev, old_state); | 258 | drm_atomic_helper_commit_modeset_disables(dev, old_state); |
259 | drm_atomic_helper_commit_modeset_enables(dev, old_state); | 259 | drm_atomic_helper_commit_modeset_enables(dev, old_state); |
260 | drm_atomic_helper_commit_planes(dev, old_state, true); | 260 | drm_atomic_helper_commit_planes(dev, old_state, |
261 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
261 | 262 | ||
262 | drm_atomic_helper_wait_for_vblanks(dev, old_state); | 263 | drm_atomic_helper_wait_for_vblanks(dev, old_state); |
263 | 264 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index ba45d9d8bb62..60bcc48f84b9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c | |||
@@ -245,7 +245,8 @@ rockchip_atomic_commit_tail(struct drm_atomic_state *state) | |||
245 | 245 | ||
246 | drm_atomic_helper_commit_modeset_enables(dev, state); | 246 | drm_atomic_helper_commit_modeset_enables(dev, state); |
247 | 247 | ||
248 | drm_atomic_helper_commit_planes(dev, state, true); | 248 | drm_atomic_helper_commit_planes(dev, state, |
249 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
249 | 250 | ||
250 | drm_atomic_helper_commit_hw_done(state); | 251 | drm_atomic_helper_commit_hw_done(state); |
251 | 252 | ||
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index f8311b2bc84e..7cd3804c6dee 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c | |||
@@ -178,7 +178,7 @@ static void sti_atomic_complete(struct sti_private *private, | |||
178 | */ | 178 | */ |
179 | 179 | ||
180 | drm_atomic_helper_commit_modeset_disables(drm, state); | 180 | drm_atomic_helper_commit_modeset_disables(drm, state); |
181 | drm_atomic_helper_commit_planes(drm, state, false); | 181 | drm_atomic_helper_commit_planes(drm, state, 0); |
182 | drm_atomic_helper_commit_modeset_enables(drm, state); | 182 | drm_atomic_helper_commit_modeset_enables(drm, state); |
183 | 183 | ||
184 | drm_atomic_helper_wait_for_vblanks(drm, state); | 184 | drm_atomic_helper_wait_for_vblanks(drm, state); |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 755264d9db22..4b9f1c79cd7b 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -57,7 +57,8 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, | |||
57 | 57 | ||
58 | drm_atomic_helper_commit_modeset_disables(drm, state); | 58 | drm_atomic_helper_commit_modeset_disables(drm, state); |
59 | drm_atomic_helper_commit_modeset_enables(drm, state); | 59 | drm_atomic_helper_commit_modeset_enables(drm, state); |
60 | drm_atomic_helper_commit_planes(drm, state, true); | 60 | drm_atomic_helper_commit_planes(drm, state, |
61 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
61 | 62 | ||
62 | drm_atomic_helper_wait_for_vblanks(drm, state); | 63 | drm_atomic_helper_wait_for_vblanks(drm, state); |
63 | 64 | ||
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 3404d245d28d..4405e4bc8056 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | |||
@@ -118,7 +118,7 @@ static int tilcdc_commit(struct drm_device *dev, | |||
118 | 118 | ||
119 | drm_atomic_helper_commit_modeset_disables(dev, state); | 119 | drm_atomic_helper_commit_modeset_disables(dev, state); |
120 | 120 | ||
121 | drm_atomic_helper_commit_planes(dev, state, false); | 121 | drm_atomic_helper_commit_planes(dev, state, 0); |
122 | 122 | ||
123 | drm_atomic_helper_commit_modeset_enables(dev, state); | 123 | drm_atomic_helper_commit_modeset_enables(dev, state); |
124 | 124 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 4ac894d993cd..c1f65c6c8e60 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c | |||
@@ -44,7 +44,7 @@ vc4_atomic_complete_commit(struct vc4_commit *c) | |||
44 | 44 | ||
45 | drm_atomic_helper_commit_modeset_disables(dev, state); | 45 | drm_atomic_helper_commit_modeset_disables(dev, state); |
46 | 46 | ||
47 | drm_atomic_helper_commit_planes(dev, state, false); | 47 | drm_atomic_helper_commit_planes(dev, state, 0); |
48 | 48 | ||
49 | drm_atomic_helper_commit_modeset_enables(dev, state); | 49 | drm_atomic_helper_commit_modeset_enables(dev, state); |
50 | 50 | ||
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 4e192aa2d021..7cf3678623c3 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c | |||
@@ -338,7 +338,8 @@ static void vgdev_atomic_commit_tail(struct drm_atomic_state *state) | |||
338 | 338 | ||
339 | drm_atomic_helper_commit_modeset_disables(dev, state); | 339 | drm_atomic_helper_commit_modeset_disables(dev, state); |
340 | drm_atomic_helper_commit_modeset_enables(dev, state); | 340 | drm_atomic_helper_commit_modeset_enables(dev, state); |
341 | drm_atomic_helper_commit_planes(dev, state, true); | 341 | drm_atomic_helper_commit_planes(dev, state, |
342 | DRM_PLANE_COMMIT_ACTIVE_ONLY); | ||
342 | 343 | ||
343 | drm_atomic_helper_commit_hw_done(state); | 344 | drm_atomic_helper_commit_hw_done(state); |
344 | 345 | ||
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 5a02e499f32b..f86682825d68 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h | |||
@@ -65,14 +65,19 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, | |||
65 | 65 | ||
66 | int drm_atomic_helper_prepare_planes(struct drm_device *dev, | 66 | int drm_atomic_helper_prepare_planes(struct drm_device *dev, |
67 | struct drm_atomic_state *state); | 67 | struct drm_atomic_state *state); |
68 | |||
69 | #define DRM_PLANE_COMMIT_ACTIVE_ONLY BIT(0) | ||
70 | #define DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET BIT(1) | ||
71 | |||
68 | void drm_atomic_helper_commit_planes(struct drm_device *dev, | 72 | void drm_atomic_helper_commit_planes(struct drm_device *dev, |
69 | struct drm_atomic_state *state, | 73 | struct drm_atomic_state *state, |
70 | bool active_only); | 74 | uint32_t flags); |
71 | void drm_atomic_helper_cleanup_planes(struct drm_device *dev, | 75 | void drm_atomic_helper_cleanup_planes(struct drm_device *dev, |
72 | struct drm_atomic_state *old_state); | 76 | struct drm_atomic_state *old_state); |
73 | void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state); | 77 | void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state); |
74 | void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, | 78 | void |
75 | bool atomic); | 79 | drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state, |
80 | bool atomic); | ||
76 | 81 | ||
77 | void drm_atomic_helper_swap_state(struct drm_atomic_state *state, | 82 | void drm_atomic_helper_swap_state(struct drm_atomic_state *state, |
78 | bool stall); | 83 | bool stall); |
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f1576db6c044..66b7d6744dd2 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
28 | #include <drm/drm_modeset.h> | 28 | #include <drm/drm_mode_object.h> |
29 | 29 | ||
30 | struct drm_connector_helper_funcs; | 30 | struct drm_connector_helper_funcs; |
31 | struct drm_device; | 31 | struct drm_device; |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7c8a77b181c2..8ca71d66282b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -36,10 +36,12 @@ | |||
36 | #include <uapi/drm/drm_fourcc.h> | 36 | #include <uapi/drm/drm_fourcc.h> |
37 | #include <drm/drm_modeset_lock.h> | 37 | #include <drm/drm_modeset_lock.h> |
38 | #include <drm/drm_rect.h> | 38 | #include <drm/drm_rect.h> |
39 | #include <drm/drm_modeset.h> | 39 | #include <drm/drm_mode_object.h> |
40 | #include <drm/drm_framebuffer.h> | 40 | #include <drm/drm_framebuffer.h> |
41 | #include <drm/drm_modes.h> | 41 | #include <drm/drm_modes.h> |
42 | #include <drm/drm_connector.h> | 42 | #include <drm/drm_connector.h> |
43 | #include <drm/drm_encoder.h> | ||
44 | #include <drm/drm_property.h> | ||
43 | 45 | ||
44 | struct drm_device; | 46 | struct drm_device; |
45 | struct drm_mode_set; | 47 | struct drm_mode_set; |
@@ -81,33 +83,6 @@ struct drm_tile_group { | |||
81 | u8 group_data[8]; | 83 | u8 group_data[8]; |
82 | }; | 84 | }; |
83 | 85 | ||
84 | struct drm_property_blob { | ||
85 | struct drm_mode_object base; | ||
86 | struct drm_device *dev; | ||
87 | struct list_head head_global; | ||
88 | struct list_head head_file; | ||
89 | size_t length; | ||
90 | unsigned char data[]; | ||
91 | }; | ||
92 | |||
93 | struct drm_property_enum { | ||
94 | uint64_t value; | ||
95 | struct list_head head; | ||
96 | char name[DRM_PROP_NAME_LEN]; | ||
97 | }; | ||
98 | |||
99 | struct drm_property { | ||
100 | struct list_head head; | ||
101 | struct drm_mode_object base; | ||
102 | uint32_t flags; | ||
103 | char name[DRM_PROP_NAME_LEN]; | ||
104 | uint32_t num_values; | ||
105 | uint64_t *values; | ||
106 | struct drm_device *dev; | ||
107 | |||
108 | struct list_head enum_list; | ||
109 | }; | ||
110 | |||
111 | struct drm_crtc; | 86 | struct drm_crtc; |
112 | struct drm_encoder; | 87 | struct drm_encoder; |
113 | struct drm_pending_vblank_event; | 88 | struct drm_pending_vblank_event; |
@@ -680,97 +655,6 @@ struct drm_crtc { | |||
680 | }; | 655 | }; |
681 | 656 | ||
682 | /** | 657 | /** |
683 | * struct drm_encoder_funcs - encoder controls | ||
684 | * | ||
685 | * Encoders sit between CRTCs and connectors. | ||
686 | */ | ||
687 | struct drm_encoder_funcs { | ||
688 | /** | ||
689 | * @reset: | ||
690 | * | ||
691 | * Reset encoder hardware and software state to off. This function isn't | ||
692 | * called by the core directly, only through drm_mode_config_reset(). | ||
693 | * It's not a helper hook only for historical reasons. | ||
694 | */ | ||
695 | void (*reset)(struct drm_encoder *encoder); | ||
696 | |||
697 | /** | ||
698 | * @destroy: | ||
699 | * | ||
700 | * Clean up encoder resources. This is only called at driver unload time | ||
701 | * through drm_mode_config_cleanup() since an encoder cannot be | ||
702 | * hotplugged in DRM. | ||
703 | */ | ||
704 | void (*destroy)(struct drm_encoder *encoder); | ||
705 | |||
706 | /** | ||
707 | * @late_register: | ||
708 | * | ||
709 | * This optional hook can be used to register additional userspace | ||
710 | * interfaces attached to the encoder like debugfs interfaces. | ||
711 | * It is called late in the driver load sequence from drm_dev_register(). | ||
712 | * Everything added from this callback should be unregistered in | ||
713 | * the early_unregister callback. | ||
714 | * | ||
715 | * Returns: | ||
716 | * | ||
717 | * 0 on success, or a negative error code on failure. | ||
718 | */ | ||
719 | int (*late_register)(struct drm_encoder *encoder); | ||
720 | |||
721 | /** | ||
722 | * @early_unregister: | ||
723 | * | ||
724 | * This optional hook should be used to unregister the additional | ||
725 | * userspace interfaces attached to the encoder from | ||
726 | * late_unregister(). It is called from drm_dev_unregister(), | ||
727 | * early in the driver unload sequence to disable userspace access | ||
728 | * before data structures are torndown. | ||
729 | */ | ||
730 | void (*early_unregister)(struct drm_encoder *encoder); | ||
731 | }; | ||
732 | |||
733 | /** | ||
734 | * struct drm_encoder - central DRM encoder structure | ||
735 | * @dev: parent DRM device | ||
736 | * @head: list management | ||
737 | * @base: base KMS object | ||
738 | * @name: human readable name, can be overwritten by the driver | ||
739 | * @encoder_type: one of the DRM_MODE_ENCODER_<foo> types in drm_mode.h | ||
740 | * @possible_crtcs: bitmask of potential CRTC bindings | ||
741 | * @possible_clones: bitmask of potential sibling encoders for cloning | ||
742 | * @crtc: currently bound CRTC | ||
743 | * @bridge: bridge associated to the encoder | ||
744 | * @funcs: control functions | ||
745 | * @helper_private: mid-layer private data | ||
746 | * | ||
747 | * CRTCs drive pixels to encoders, which convert them into signals | ||
748 | * appropriate for a given connector or set of connectors. | ||
749 | */ | ||
750 | struct drm_encoder { | ||
751 | struct drm_device *dev; | ||
752 | struct list_head head; | ||
753 | |||
754 | struct drm_mode_object base; | ||
755 | char *name; | ||
756 | int encoder_type; | ||
757 | |||
758 | /** | ||
759 | * @index: Position inside the mode_config.list, can be used as an array | ||
760 | * index. It is invariant over the lifetime of the encoder. | ||
761 | */ | ||
762 | unsigned index; | ||
763 | |||
764 | uint32_t possible_crtcs; | ||
765 | uint32_t possible_clones; | ||
766 | |||
767 | struct drm_crtc *crtc; | ||
768 | struct drm_bridge *bridge; | ||
769 | const struct drm_encoder_funcs *funcs; | ||
770 | const struct drm_encoder_helper_funcs *helper_private; | ||
771 | }; | ||
772 | |||
773 | /** | ||
774 | * struct drm_plane_state - mutable plane state | 658 | * struct drm_plane_state - mutable plane state |
775 | * @plane: backpointer to the plane | 659 | * @plane: backpointer to the plane |
776 | * @crtc: currently bound CRTC, NULL if disabled | 660 | * @crtc: currently bound CRTC, NULL if disabled |
@@ -1136,12 +1020,33 @@ struct drm_plane { | |||
1136 | 1020 | ||
1137 | /** | 1021 | /** |
1138 | * struct drm_bridge_funcs - drm_bridge control functions | 1022 | * struct drm_bridge_funcs - drm_bridge control functions |
1139 | * @attach: Called during drm_bridge_attach | ||
1140 | */ | 1023 | */ |
1141 | struct drm_bridge_funcs { | 1024 | struct drm_bridge_funcs { |
1025 | /** | ||
1026 | * @attach: | ||
1027 | * | ||
1028 | * This callback is invoked whenever our bridge is being attached to a | ||
1029 | * &drm_encoder. | ||
1030 | * | ||
1031 | * The attach callback is optional. | ||
1032 | * | ||
1033 | * RETURNS: | ||
1034 | * | ||
1035 | * Zero on success, error code on failure. | ||
1036 | */ | ||
1142 | int (*attach)(struct drm_bridge *bridge); | 1037 | int (*attach)(struct drm_bridge *bridge); |
1143 | 1038 | ||
1144 | /** | 1039 | /** |
1040 | * @detach: | ||
1041 | * | ||
1042 | * This callback is invoked whenever our bridge is being detached from a | ||
1043 | * &drm_encoder. | ||
1044 | * | ||
1045 | * The detach callback is optional. | ||
1046 | */ | ||
1047 | void (*detach)(struct drm_bridge *bridge); | ||
1048 | |||
1049 | /** | ||
1145 | * @mode_fixup: | 1050 | * @mode_fixup: |
1146 | * | 1051 | * |
1147 | * This callback is used to validate and adjust a mode. The paramater | 1052 | * This callback is used to validate and adjust a mode. The paramater |
@@ -1155,6 +1060,8 @@ struct drm_bridge_funcs { | |||
1155 | * this function passes all other callbacks must succeed for this | 1060 | * this function passes all other callbacks must succeed for this |
1156 | * configuration. | 1061 | * configuration. |
1157 | * | 1062 | * |
1063 | * The mode_fixup callback is optional. | ||
1064 | * | ||
1158 | * NOTE: | 1065 | * NOTE: |
1159 | * | 1066 | * |
1160 | * This function is called in the check phase of atomic modesets, which | 1067 | * This function is called in the check phase of atomic modesets, which |
@@ -2109,18 +2016,11 @@ struct drm_mode_config { | |||
2109 | for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder))) | 2016 | for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder))) |
2110 | 2017 | ||
2111 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) | 2018 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) |
2112 | #define obj_to_encoder(x) container_of(x, struct drm_encoder, base) | ||
2113 | #define obj_to_mode(x) container_of(x, struct drm_display_mode, base) | 2019 | #define obj_to_mode(x) container_of(x, struct drm_display_mode, base) |
2114 | #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) | 2020 | #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) |
2115 | #define obj_to_property(x) container_of(x, struct drm_property, base) | ||
2116 | #define obj_to_blob(x) container_of(x, struct drm_property_blob, base) | 2021 | #define obj_to_blob(x) container_of(x, struct drm_property_blob, base) |
2117 | #define obj_to_plane(x) container_of(x, struct drm_plane, base) | 2022 | #define obj_to_plane(x) container_of(x, struct drm_plane, base) |
2118 | 2023 | ||
2119 | struct drm_prop_enum_list { | ||
2120 | int type; | ||
2121 | char *name; | ||
2122 | }; | ||
2123 | |||
2124 | extern __printf(6, 7) | 2024 | extern __printf(6, 7) |
2125 | int drm_crtc_init_with_planes(struct drm_device *dev, | 2025 | int drm_crtc_init_with_planes(struct drm_device *dev, |
2126 | struct drm_crtc *crtc, | 2026 | struct drm_crtc *crtc, |
@@ -2154,37 +2054,6 @@ static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc) | |||
2154 | return 1 << drm_crtc_index(crtc); | 2054 | return 1 << drm_crtc_index(crtc); |
2155 | } | 2055 | } |
2156 | 2056 | ||
2157 | extern __printf(5, 6) | ||
2158 | int drm_encoder_init(struct drm_device *dev, | ||
2159 | struct drm_encoder *encoder, | ||
2160 | const struct drm_encoder_funcs *funcs, | ||
2161 | int encoder_type, const char *name, ...); | ||
2162 | |||
2163 | /** | ||
2164 | * drm_encoder_index - find the index of a registered encoder | ||
2165 | * @encoder: encoder to find index for | ||
2166 | * | ||
2167 | * Given a registered encoder, return the index of that encoder within a DRM | ||
2168 | * device's list of encoders. | ||
2169 | */ | ||
2170 | static inline unsigned int drm_encoder_index(struct drm_encoder *encoder) | ||
2171 | { | ||
2172 | return encoder->index; | ||
2173 | } | ||
2174 | |||
2175 | /** | ||
2176 | * drm_encoder_crtc_ok - can a given crtc drive a given encoder? | ||
2177 | * @encoder: encoder to test | ||
2178 | * @crtc: crtc to test | ||
2179 | * | ||
2180 | * Return false if @encoder can't be driven by @crtc, true otherwise. | ||
2181 | */ | ||
2182 | static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder, | ||
2183 | struct drm_crtc *crtc) | ||
2184 | { | ||
2185 | return !!(encoder->possible_crtcs & drm_crtc_mask(crtc)); | ||
2186 | } | ||
2187 | |||
2188 | extern __printf(8, 9) | 2057 | extern __printf(8, 9) |
2189 | int drm_universal_plane_init(struct drm_device *dev, | 2058 | int drm_universal_plane_init(struct drm_device *dev, |
2190 | struct drm_plane *plane, | 2059 | struct drm_plane *plane, |
@@ -2220,75 +2089,15 @@ extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, | |||
2220 | extern int drm_crtc_force_disable(struct drm_crtc *crtc); | 2089 | extern int drm_crtc_force_disable(struct drm_crtc *crtc); |
2221 | extern int drm_crtc_force_disable_all(struct drm_device *dev); | 2090 | extern int drm_crtc_force_disable_all(struct drm_device *dev); |
2222 | 2091 | ||
2223 | extern void drm_encoder_cleanup(struct drm_encoder *encoder); | ||
2224 | |||
2225 | extern void drm_mode_config_init(struct drm_device *dev); | 2092 | extern void drm_mode_config_init(struct drm_device *dev); |
2226 | extern void drm_mode_config_reset(struct drm_device *dev); | 2093 | extern void drm_mode_config_reset(struct drm_device *dev); |
2227 | extern void drm_mode_config_cleanup(struct drm_device *dev); | 2094 | extern void drm_mode_config_cleanup(struct drm_device *dev); |
2228 | 2095 | ||
2229 | static inline bool drm_property_type_is(struct drm_property *property, | ||
2230 | uint32_t type) | ||
2231 | { | ||
2232 | /* instanceof for props.. handles extended type vs original types: */ | ||
2233 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
2234 | return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type; | ||
2235 | return property->flags & type; | ||
2236 | } | ||
2237 | |||
2238 | extern int drm_object_property_set_value(struct drm_mode_object *obj, | ||
2239 | struct drm_property *property, | ||
2240 | uint64_t val); | ||
2241 | extern int drm_object_property_get_value(struct drm_mode_object *obj, | ||
2242 | struct drm_property *property, | ||
2243 | uint64_t *value); | ||
2244 | |||
2245 | extern void drm_object_attach_property(struct drm_mode_object *obj, | ||
2246 | struct drm_property *property, | ||
2247 | uint64_t init_val); | ||
2248 | extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
2249 | const char *name, int num_values); | ||
2250 | extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
2251 | const char *name, | ||
2252 | const struct drm_prop_enum_list *props, | ||
2253 | int num_values); | ||
2254 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
2255 | int flags, const char *name, | ||
2256 | const struct drm_prop_enum_list *props, | ||
2257 | int num_props, | ||
2258 | uint64_t supported_bits); | ||
2259 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
2260 | const char *name, | ||
2261 | uint64_t min, uint64_t max); | ||
2262 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
2263 | int flags, const char *name, | ||
2264 | int64_t min, int64_t max); | ||
2265 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
2266 | int flags, const char *name, uint32_t type); | ||
2267 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
2268 | const char *name); | ||
2269 | struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, | ||
2270 | size_t length, | ||
2271 | const void *data); | ||
2272 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
2273 | uint32_t id); | ||
2274 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
2275 | struct drm_property_blob **replace, | ||
2276 | size_t length, | ||
2277 | const void *data, | ||
2278 | struct drm_mode_object *obj_holds_id, | ||
2279 | struct drm_property *prop_holds_id); | ||
2280 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob); | ||
2281 | void drm_property_unreference_blob(struct drm_property_blob *blob); | ||
2282 | extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); | ||
2283 | extern int drm_property_add_enum(struct drm_property *property, int index, | ||
2284 | uint64_t value, const char *name); | ||
2285 | extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | 2096 | extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, |
2286 | int gamma_size); | 2097 | int gamma_size); |
2287 | 2098 | ||
2288 | extern int drm_mode_set_config_internal(struct drm_mode_set *set); | 2099 | extern int drm_mode_set_config_internal(struct drm_mode_set *set); |
2289 | 2100 | ||
2290 | extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); | ||
2291 | |||
2292 | extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, | 2101 | extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, |
2293 | char topology[8]); | 2102 | char topology[8]); |
2294 | extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, | 2103 | 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, | |||
2333 | return mo ? obj_to_crtc(mo) : NULL; | 2142 | return mo ? obj_to_crtc(mo) : NULL; |
2334 | } | 2143 | } |
2335 | 2144 | ||
2336 | static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, | ||
2337 | uint32_t id) | ||
2338 | { | ||
2339 | struct drm_mode_object *mo; | ||
2340 | mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); | ||
2341 | return mo ? obj_to_encoder(mo) : NULL; | ||
2342 | } | ||
2343 | |||
2344 | static inline struct drm_property *drm_property_find(struct drm_device *dev, | ||
2345 | uint32_t id) | ||
2346 | { | ||
2347 | struct drm_mode_object *mo; | ||
2348 | mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY); | ||
2349 | return mo ? obj_to_property(mo) : NULL; | ||
2350 | } | ||
2351 | |||
2352 | /* | 2145 | /* |
2353 | * Extract a degamma/gamma LUT value provided by user and round it to the | 2146 | * Extract a degamma/gamma LUT value provided by user and round it to the |
2354 | * precision supported by the hardware. | 2147 | * precision supported by the hardware. |
@@ -2444,6 +2237,7 @@ extern int drm_bridge_add(struct drm_bridge *bridge); | |||
2444 | extern void drm_bridge_remove(struct drm_bridge *bridge); | 2237 | extern void drm_bridge_remove(struct drm_bridge *bridge); |
2445 | extern struct drm_bridge *of_drm_find_bridge(struct device_node *np); | 2238 | extern struct drm_bridge *of_drm_find_bridge(struct device_node *np); |
2446 | extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge); | 2239 | extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge); |
2240 | extern void drm_bridge_detach(struct drm_bridge *bridge); | ||
2447 | 2241 | ||
2448 | bool drm_bridge_mode_fixup(struct drm_bridge *bridge, | 2242 | bool drm_bridge_mode_fixup(struct drm_bridge *bridge, |
2449 | const struct drm_display_mode *mode, | 2243 | const struct drm_display_mode *mode, |
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h new file mode 100644 index 000000000000..fce0203094f7 --- /dev/null +++ b/include/drm/drm_encoder.h | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef __DRM_ENCODER_H__ | ||
24 | #define __DRM_ENCODER_H__ | ||
25 | |||
26 | #include <linux/list.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <drm/drm_mode_object.h> | ||
29 | |||
30 | /** | ||
31 | * struct drm_encoder_funcs - encoder controls | ||
32 | * | ||
33 | * Encoders sit between CRTCs and connectors. | ||
34 | */ | ||
35 | struct drm_encoder_funcs { | ||
36 | /** | ||
37 | * @reset: | ||
38 | * | ||
39 | * Reset encoder hardware and software state to off. This function isn't | ||
40 | * called by the core directly, only through drm_mode_config_reset(). | ||
41 | * It's not a helper hook only for historical reasons. | ||
42 | */ | ||
43 | void (*reset)(struct drm_encoder *encoder); | ||
44 | |||
45 | /** | ||
46 | * @destroy: | ||
47 | * | ||
48 | * Clean up encoder resources. This is only called at driver unload time | ||
49 | * through drm_mode_config_cleanup() since an encoder cannot be | ||
50 | * hotplugged in DRM. | ||
51 | */ | ||
52 | void (*destroy)(struct drm_encoder *encoder); | ||
53 | |||
54 | /** | ||
55 | * @late_register: | ||
56 | * | ||
57 | * This optional hook can be used to register additional userspace | ||
58 | * interfaces attached to the encoder like debugfs interfaces. | ||
59 | * It is called late in the driver load sequence from drm_dev_register(). | ||
60 | * Everything added from this callback should be unregistered in | ||
61 | * the early_unregister callback. | ||
62 | * | ||
63 | * Returns: | ||
64 | * | ||
65 | * 0 on success, or a negative error code on failure. | ||
66 | */ | ||
67 | int (*late_register)(struct drm_encoder *encoder); | ||
68 | |||
69 | /** | ||
70 | * @early_unregister: | ||
71 | * | ||
72 | * This optional hook should be used to unregister the additional | ||
73 | * userspace interfaces attached to the encoder from | ||
74 | * late_unregister(). It is called from drm_dev_unregister(), | ||
75 | * early in the driver unload sequence to disable userspace access | ||
76 | * before data structures are torndown. | ||
77 | */ | ||
78 | void (*early_unregister)(struct drm_encoder *encoder); | ||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * struct drm_encoder - central DRM encoder structure | ||
83 | * @dev: parent DRM device | ||
84 | * @head: list management | ||
85 | * @base: base KMS object | ||
86 | * @name: human readable name, can be overwritten by the driver | ||
87 | * @crtc: currently bound CRTC | ||
88 | * @bridge: bridge associated to the encoder | ||
89 | * @funcs: control functions | ||
90 | * @helper_private: mid-layer private data | ||
91 | * | ||
92 | * CRTCs drive pixels to encoders, which convert them into signals | ||
93 | * appropriate for a given connector or set of connectors. | ||
94 | */ | ||
95 | struct drm_encoder { | ||
96 | struct drm_device *dev; | ||
97 | struct list_head head; | ||
98 | |||
99 | struct drm_mode_object base; | ||
100 | char *name; | ||
101 | /** | ||
102 | * @encoder_type: | ||
103 | * | ||
104 | * One of the DRM_MODE_ENCODER_<foo> types in drm_mode.h. The following | ||
105 | * encoder types are defined thus far: | ||
106 | * | ||
107 | * - DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A. | ||
108 | * | ||
109 | * - DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort. | ||
110 | * | ||
111 | * - DRM_MODE_ENCODER_LVDS for display panels, or in general any panel | ||
112 | * with a proprietary parallel connector. | ||
113 | * | ||
114 | * - DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, | ||
115 | * Component, SCART). | ||
116 | * | ||
117 | * - DRM_MODE_ENCODER_VIRTUAL for virtual machine displays | ||
118 | * | ||
119 | * - DRM_MODE_ENCODER_DSI for panels connected using the DSI serial bus. | ||
120 | * | ||
121 | * - DRM_MODE_ENCODER_DPI for panels connected using the DPI parallel | ||
122 | * bus. | ||
123 | * | ||
124 | * - DRM_MODE_ENCODER_DPMST for special fake encoders used to allow | ||
125 | * mutliple DP MST streams to share one physical encoder. | ||
126 | */ | ||
127 | int encoder_type; | ||
128 | |||
129 | /** | ||
130 | * @index: Position inside the mode_config.list, can be used as an array | ||
131 | * index. It is invariant over the lifetime of the encoder. | ||
132 | */ | ||
133 | unsigned index; | ||
134 | |||
135 | /** | ||
136 | * @possible_crtcs: Bitmask of potential CRTC bindings, using | ||
137 | * drm_crtc_index() as the index into the bitfield. The driver must set | ||
138 | * the bits for all &drm_crtc objects this encoder can be connected to | ||
139 | * before calling drm_encoder_init(). | ||
140 | * | ||
141 | * In reality almost every driver gets this wrong. | ||
142 | * | ||
143 | * Note that since CRTC objects can't be hotplugged the assigned indices | ||
144 | * are stable and hence known before registering all objects. | ||
145 | */ | ||
146 | uint32_t possible_crtcs; | ||
147 | |||
148 | /** | ||
149 | * @possible_clones: Bitmask of potential sibling encoders for cloning, | ||
150 | * using drm_encoder_index() as the index into the bitfield. The driver | ||
151 | * must set the bits for all &drm_encoder objects which can clone a | ||
152 | * &drm_crtc together with this encoder before calling | ||
153 | * drm_encoder_init(). Drivers should set the bit representing the | ||
154 | * encoder itself, too. Cloning bits should be set such that when two | ||
155 | * encoders can be used in a cloned configuration, they both should have | ||
156 | * each another bits set. | ||
157 | * | ||
158 | * In reality almost every driver gets this wrong. | ||
159 | * | ||
160 | * Note that since encoder objects can't be hotplugged the assigned indices | ||
161 | * are stable and hence known before registering all objects. | ||
162 | */ | ||
163 | uint32_t possible_clones; | ||
164 | |||
165 | struct drm_crtc *crtc; | ||
166 | struct drm_bridge *bridge; | ||
167 | const struct drm_encoder_funcs *funcs; | ||
168 | const struct drm_encoder_helper_funcs *helper_private; | ||
169 | }; | ||
170 | |||
171 | #define obj_to_encoder(x) container_of(x, struct drm_encoder, base) | ||
172 | |||
173 | __printf(5, 6) | ||
174 | int drm_encoder_init(struct drm_device *dev, | ||
175 | struct drm_encoder *encoder, | ||
176 | const struct drm_encoder_funcs *funcs, | ||
177 | int encoder_type, const char *name, ...); | ||
178 | |||
179 | /** | ||
180 | * drm_encoder_index - find the index of a registered encoder | ||
181 | * @encoder: encoder to find index for | ||
182 | * | ||
183 | * Given a registered encoder, return the index of that encoder within a DRM | ||
184 | * device's list of encoders. | ||
185 | */ | ||
186 | static inline unsigned int drm_encoder_index(struct drm_encoder *encoder) | ||
187 | { | ||
188 | return encoder->index; | ||
189 | } | ||
190 | |||
191 | /* FIXME: We have an include file mess still, drm_crtc.h needs untangling. */ | ||
192 | static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc); | ||
193 | |||
194 | /** | ||
195 | * drm_encoder_crtc_ok - can a given crtc drive a given encoder? | ||
196 | * @encoder: encoder to test | ||
197 | * @crtc: crtc to test | ||
198 | * | ||
199 | * Returns false if @encoder can't be driven by @crtc, true otherwise. | ||
200 | */ | ||
201 | static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder, | ||
202 | struct drm_crtc *crtc) | ||
203 | { | ||
204 | return !!(encoder->possible_crtcs & drm_crtc_mask(crtc)); | ||
205 | } | ||
206 | |||
207 | /** | ||
208 | * drm_encoder_find - find a &drm_encoder | ||
209 | * @dev: DRM device | ||
210 | * @id: encoder id | ||
211 | * | ||
212 | * Returns the encoder with @id, NULL if it doesn't exist. Simple wrapper around | ||
213 | * drm_mode_object_find(). | ||
214 | */ | ||
215 | static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, | ||
216 | uint32_t id) | ||
217 | { | ||
218 | struct drm_mode_object *mo; | ||
219 | |||
220 | mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); | ||
221 | |||
222 | return mo ? obj_to_encoder(mo) : NULL; | ||
223 | } | ||
224 | |||
225 | void drm_encoder_cleanup(struct drm_encoder *encoder); | ||
226 | |||
227 | #endif | ||
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index edc6cfd3aa34..797fb5f80c45 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h | |||
@@ -491,7 +491,7 @@ static inline int | |||
491 | drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, | 491 | drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, |
492 | const char *name, bool primary) | 492 | const char *name, bool primary) |
493 | { | 493 | { |
494 | #if IS_ENABLED(CONFIG_FB) | 494 | #if IS_REACHABLE(CONFIG_FB) |
495 | return remove_conflicting_framebuffers(a, name, primary); | 495 | return remove_conflicting_framebuffers(a, name, primary); |
496 | #else | 496 | #else |
497 | return 0; | 497 | return 0; |
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index b106337de1bf..30c30fa87ee8 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <uapi/drm/drm_fourcc.h> | 26 | #include <uapi/drm/drm_fourcc.h> |
27 | 27 | ||
28 | uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); | ||
28 | void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); | 29 | void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); |
29 | int drm_format_num_planes(uint32_t format); | 30 | int drm_format_num_planes(uint32_t format); |
30 | int drm_format_plane_cpp(uint32_t format, int plane); | 31 | int drm_format_plane_cpp(uint32_t format, int plane); |
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 50deb40d3bfd..b2554c50a903 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
28 | #include <drm/drm_modeset.h> | 28 | #include <drm/drm_mode_object.h> |
29 | 29 | ||
30 | struct drm_framebuffer; | 30 | struct drm_framebuffer; |
31 | struct drm_file; | 31 | struct drm_file; |
diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h new file mode 100644 index 000000000000..be3d93839ae2 --- /dev/null +++ b/include/drm/drm_mode_object.h | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef __DRM_MODESET_H__ | ||
24 | #define __DRM_MODESET_H__ | ||
25 | |||
26 | #include <linux/kref.h> | ||
27 | struct drm_object_properties; | ||
28 | struct drm_property; | ||
29 | |||
30 | /** | ||
31 | * struct drm_mode_object - base structure for modeset objects | ||
32 | * @id: userspace visible identifier | ||
33 | * @type: type of the object, one of DRM_MODE_OBJECT\_\* | ||
34 | * @properties: properties attached to this object, including values | ||
35 | * @refcount: reference count for objects which with dynamic lifetime | ||
36 | * @free_cb: free function callback, only set for objects with dynamic lifetime | ||
37 | * | ||
38 | * Base structure for modeset objects visible to userspace. Objects can be | ||
39 | * looked up using drm_mode_object_find(). Besides basic uapi interface | ||
40 | * properties like @id and @type it provides two services: | ||
41 | * | ||
42 | * - It tracks attached properties and their values. This is used by &drm_crtc, | ||
43 | * &drm_plane and &drm_connector. Properties are attached by calling | ||
44 | * drm_object_attach_property() before the object is visible to userspace. | ||
45 | * | ||
46 | * - For objects with dynamic lifetimes (as indicated by a non-NULL @free_cb) it | ||
47 | * provides reference counting through drm_mode_object_reference() and | ||
48 | * drm_mode_object_unreference(). This is used by &drm_framebuffer, | ||
49 | * &drm_connector and &drm_property_blob. These objects provide specialized | ||
50 | * reference counting wrappers. | ||
51 | */ | ||
52 | struct drm_mode_object { | ||
53 | uint32_t id; | ||
54 | uint32_t type; | ||
55 | struct drm_object_properties *properties; | ||
56 | struct kref refcount; | ||
57 | void (*free_cb)(struct kref *kref); | ||
58 | }; | ||
59 | |||
60 | #define DRM_OBJECT_MAX_PROPERTY 24 | ||
61 | /** | ||
62 | * struct drm_object_properties - property tracking for &drm_mode_object | ||
63 | */ | ||
64 | struct drm_object_properties { | ||
65 | /** | ||
66 | * @count: number of valid properties, must be less than or equal to | ||
67 | * DRM_OBJECT_MAX_PROPERTY. | ||
68 | */ | ||
69 | |||
70 | int count; | ||
71 | /** | ||
72 | * @properties: Array of pointers to &drm_property. | ||
73 | * | ||
74 | * NOTE: if we ever start dynamically destroying properties (ie. | ||
75 | * not at drm_mode_config_cleanup() time), then we'd have to do | ||
76 | * a better job of detaching property from mode objects to avoid | ||
77 | * dangling property pointers: | ||
78 | */ | ||
79 | struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; | ||
80 | |||
81 | /** | ||
82 | * @values: Array to store the property values, matching @properties. Do | ||
83 | * not read/write values directly, but use | ||
84 | * drm_object_property_get_value() and drm_object_property_set_value(). | ||
85 | * | ||
86 | * Note that atomic drivers do not store mutable properties in this | ||
87 | * array, but only the decoded values in the corresponding state | ||
88 | * structure. The decoding is done using the ->atomic_get_property and | ||
89 | * ->atomic_set_property hooks of the corresponding object. Hence atomic | ||
90 | * drivers should not use drm_object_property_set_value() and | ||
91 | * drm_object_property_get_value() on mutable objects, i.e. those | ||
92 | * without the DRM_MODE_PROP_IMMUTABLE flag set. | ||
93 | */ | ||
94 | uint64_t values[DRM_OBJECT_MAX_PROPERTY]; | ||
95 | }; | ||
96 | |||
97 | /* Avoid boilerplate. I'm tired of typing. */ | ||
98 | #define DRM_ENUM_NAME_FN(fnname, list) \ | ||
99 | const char *fnname(int val) \ | ||
100 | { \ | ||
101 | int i; \ | ||
102 | for (i = 0; i < ARRAY_SIZE(list); i++) { \ | ||
103 | if (list[i].type == val) \ | ||
104 | return list[i].name; \ | ||
105 | } \ | ||
106 | return "(unknown)"; \ | ||
107 | } | ||
108 | |||
109 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | ||
110 | uint32_t id, uint32_t type); | ||
111 | void drm_mode_object_reference(struct drm_mode_object *obj); | ||
112 | void drm_mode_object_unreference(struct drm_mode_object *obj); | ||
113 | |||
114 | int drm_object_property_set_value(struct drm_mode_object *obj, | ||
115 | struct drm_property *property, | ||
116 | uint64_t val); | ||
117 | int drm_object_property_get_value(struct drm_mode_object *obj, | ||
118 | struct drm_property *property, | ||
119 | uint64_t *value); | ||
120 | |||
121 | void drm_object_attach_property(struct drm_mode_object *obj, | ||
122 | struct drm_property *property, | ||
123 | uint64_t init_val); | ||
124 | #endif | ||
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 1621e9b32330..011f199d3bcf 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h | |||
@@ -27,7 +27,7 @@ | |||
27 | #ifndef __DRM_MODES_H__ | 27 | #ifndef __DRM_MODES_H__ |
28 | #define __DRM_MODES_H__ | 28 | #define __DRM_MODES_H__ |
29 | 29 | ||
30 | #include <drm/drm_modeset.h> | 30 | #include <drm/drm_mode_object.h> |
31 | #include <drm/drm_connector.h> | 31 | #include <drm/drm_connector.h> |
32 | 32 | ||
33 | /* | 33 | /* |
diff --git a/include/drm/drm_modeset.h b/include/drm/drm_modeset.h deleted file mode 100644 index fe910d5efe12..000000000000 --- a/include/drm/drm_modeset.h +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef __DRM_MODESET_H__ | ||
24 | #define __DRM_MODESET_H__ | ||
25 | |||
26 | #include <linux/kref.h> | ||
27 | struct drm_object_properties; | ||
28 | struct drm_property; | ||
29 | |||
30 | struct drm_mode_object { | ||
31 | uint32_t id; | ||
32 | uint32_t type; | ||
33 | struct drm_object_properties *properties; | ||
34 | struct kref refcount; | ||
35 | void (*free_cb)(struct kref *kref); | ||
36 | }; | ||
37 | |||
38 | #define DRM_OBJECT_MAX_PROPERTY 24 | ||
39 | struct drm_object_properties { | ||
40 | int count, atomic_count; | ||
41 | /* NOTE: if we ever start dynamically destroying properties (ie. | ||
42 | * not at drm_mode_config_cleanup() time), then we'd have to do | ||
43 | * a better job of detaching property from mode objects to avoid | ||
44 | * dangling property pointers: | ||
45 | */ | ||
46 | struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; | ||
47 | /* do not read/write values directly, but use drm_object_property_get_value() | ||
48 | * and drm_object_property_set_value(): | ||
49 | */ | ||
50 | uint64_t values[DRM_OBJECT_MAX_PROPERTY]; | ||
51 | }; | ||
52 | |||
53 | /* Avoid boilerplate. I'm tired of typing. */ | ||
54 | #define DRM_ENUM_NAME_FN(fnname, list) \ | ||
55 | const char *fnname(int val) \ | ||
56 | { \ | ||
57 | int i; \ | ||
58 | for (i = 0; i < ARRAY_SIZE(list); i++) { \ | ||
59 | if (list[i].type == val) \ | ||
60 | return list[i].name; \ | ||
61 | } \ | ||
62 | return "(unknown)"; \ | ||
63 | } | ||
64 | |||
65 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | ||
66 | uint32_t id, uint32_t type); | ||
67 | void drm_mode_object_reference(struct drm_mode_object *obj); | ||
68 | void drm_mode_object_unreference(struct drm_mode_object *obj); | ||
69 | |||
70 | #endif | ||
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 6c8d3dad66ec..10e449c86dbd 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h | |||
@@ -266,6 +266,8 @@ struct drm_crtc_helper_funcs { | |||
266 | * disable anything at the CRTC level. To ensure that runtime PM | 266 | * disable anything at the CRTC level. To ensure that runtime PM |
267 | * handling (using either DPMS or the new "ACTIVE" property) works | 267 | * handling (using either DPMS or the new "ACTIVE" property) works |
268 | * @disable must be the inverse of @enable for atomic drivers. | 268 | * @disable must be the inverse of @enable for atomic drivers. |
269 | * Atomic drivers should consider to use @atomic_disable instead of | ||
270 | * this one. | ||
269 | * | 271 | * |
270 | * NOTE: | 272 | * NOTE: |
271 | * | 273 | * |
@@ -391,6 +393,28 @@ struct drm_crtc_helper_funcs { | |||
391 | */ | 393 | */ |
392 | void (*atomic_flush)(struct drm_crtc *crtc, | 394 | void (*atomic_flush)(struct drm_crtc *crtc, |
393 | struct drm_crtc_state *old_crtc_state); | 395 | struct drm_crtc_state *old_crtc_state); |
396 | |||
397 | /** | ||
398 | * @atomic_disable: | ||
399 | * | ||
400 | * This callback should be used to disable the CRTC. With the atomic | ||
401 | * drivers it is called after all encoders connected to this CRTC have | ||
402 | * been shut off already using their own ->disable hook. If that | ||
403 | * sequence is too simple drivers can just add their own hooks and call | ||
404 | * it from this CRTC callback here by looping over all encoders | ||
405 | * connected to it using for_each_encoder_on_crtc(). | ||
406 | * | ||
407 | * This hook is used only by atomic helpers. Atomic drivers don't | ||
408 | * need to implement it if there's no need to disable anything at the | ||
409 | * CRTC level. | ||
410 | * | ||
411 | * Comparing to @disable, this one provides the additional input | ||
412 | * parameter @old_crtc_state which could be used to access the old | ||
413 | * state. Atomic drivers should consider to use this one instead | ||
414 | * of @disable. | ||
415 | */ | ||
416 | void (*atomic_disable)(struct drm_crtc *crtc, | ||
417 | struct drm_crtc_state *old_crtc_state); | ||
394 | }; | 418 | }; |
395 | 419 | ||
396 | /** | 420 | /** |
diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h new file mode 100644 index 000000000000..30ab289be05d --- /dev/null +++ b/include/drm/drm_property.h | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef __DRM_PROPERTY_H__ | ||
24 | #define __DRM_PROPERTY_H__ | ||
25 | |||
26 | #include <linux/list.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <drm/drm_mode_object.h> | ||
29 | |||
30 | /** | ||
31 | * struct drm_property_enum - symbolic values for enumerations | ||
32 | * @value: numeric property value for this enum entry | ||
33 | * @head: list of enum values, linked to enum_list in &drm_property | ||
34 | * @name: symbolic name for the enum | ||
35 | * | ||
36 | * For enumeration and bitmask properties this structure stores the symbolic | ||
37 | * decoding for each value. This is used for example for the rotation property. | ||
38 | */ | ||
39 | struct drm_property_enum { | ||
40 | uint64_t value; | ||
41 | struct list_head head; | ||
42 | char name[DRM_PROP_NAME_LEN]; | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * struct drm_property - modeset object property | ||
47 | * | ||
48 | * This structure represent a modeset object property. It combines both the name | ||
49 | * of the property with the set of permissible values. This means that when a | ||
50 | * driver wants to use a property with the same name on different objects, but | ||
51 | * with different value ranges, then it must create property for each one. An | ||
52 | * example would be rotation of &drm_plane, when e.g. the primary plane cannot | ||
53 | * be rotated. But if both the name and the value range match, then the same | ||
54 | * property structure can be instantiated multiple times for the same object. | ||
55 | * Userspace must be able to cope with this and cannot assume that the same | ||
56 | * symbolic property will have the same modeset object ID on all modeset | ||
57 | * objects. | ||
58 | * | ||
59 | * Properties are created by one of the special functions, as explained in | ||
60 | * detail in the @flags structure member. | ||
61 | * | ||
62 | * To actually expose a property it must be attached to each object using | ||
63 | * drm_object_attach_property(). Currently properties can only be attached to | ||
64 | * &drm_connector, &drm_crtc and &drm_plane. | ||
65 | * | ||
66 | * Properties are also used as the generic metadatatransport for the atomic | ||
67 | * IOCTL. Everything that was set directly in structures in the legacy modeset | ||
68 | * IOCTLs (like the plane source or destination windows, or e.g. the links to | ||
69 | * the CRTC) is exposed as a property with the DRM_MODE_PROP_ATOMIC flag set. | ||
70 | */ | ||
71 | struct drm_property { | ||
72 | /** | ||
73 | * @head: per-device list of properties, for cleanup. | ||
74 | */ | ||
75 | struct list_head head; | ||
76 | |||
77 | /** | ||
78 | * @base: base KMS object | ||
79 | */ | ||
80 | struct drm_mode_object base; | ||
81 | |||
82 | /** | ||
83 | * @flags: | ||
84 | * | ||
85 | * Property flags and type. A property needs to be one of the following | ||
86 | * types: | ||
87 | * | ||
88 | * DRM_MODE_PROP_RANGE | ||
89 | * Range properties report their minimum and maximum admissible unsigned values. | ||
90 | * The KMS core verifies that values set by application fit in that | ||
91 | * range. The range is unsigned. Range properties are created using | ||
92 | * drm_property_create_range(). | ||
93 | * | ||
94 | * DRM_MODE_PROP_SIGNED_RANGE | ||
95 | * Range properties report their minimum and maximum admissible unsigned values. | ||
96 | * The KMS core verifies that values set by application fit in that | ||
97 | * range. The range is signed. Range properties are created using | ||
98 | * drm_property_create_signed_range(). | ||
99 | * | ||
100 | * DRM_MODE_PROP_ENUM | ||
101 | * Enumerated properties take a numerical value that ranges from 0 to | ||
102 | * the number of enumerated values defined by the property minus one, | ||
103 | * and associate a free-formed string name to each value. Applications | ||
104 | * can retrieve the list of defined value-name pairs and use the | ||
105 | * numerical value to get and set property instance values. Enum | ||
106 | * properties are created using drm_property_create_enum(). | ||
107 | * | ||
108 | * DRM_MODE_PROP_BITMASK | ||
109 | * Bitmask properties are enumeration properties that additionally | ||
110 | * restrict all enumerated values to the 0..63 range. Bitmask property | ||
111 | * instance values combine one or more of the enumerated bits defined | ||
112 | * by the property. Bitmask properties are created using | ||
113 | * drm_property_create_bitmask(). | ||
114 | * | ||
115 | * DRM_MODE_PROB_OBJECT | ||
116 | * Object properties are used to link modeset objects. This is used | ||
117 | * extensively in the atomic support to create the display pipeline, | ||
118 | * by linking &drm_framebuffer to &drm_plane, &drm_plane to | ||
119 | * &drm_crtc and &drm_connector to &drm_crtc. An object property can | ||
120 | * only link to a specific type of &drm_mode_object, this limit is | ||
121 | * enforced by the core. Object properties are created using | ||
122 | * drm_property_create_object(). | ||
123 | * | ||
124 | * Object properties work like blob properties, but in a more | ||
125 | * general fashion. They are limited to atomic drivers and must have | ||
126 | * the DRM_MODE_PROP_ATOMIC flag set. | ||
127 | * | ||
128 | * DRM_MODE_PROP_BLOB | ||
129 | * Blob properties store a binary blob without any format restriction. | ||
130 | * The binary blobs are created as KMS standalone objects, and blob | ||
131 | * property instance values store the ID of their associated blob | ||
132 | * object. Blob properties are created by calling | ||
133 | * drm_property_create() with DRM_MODE_PROP_BLOB as the type. | ||
134 | * | ||
135 | * Actual blob objects to contain blob data are created using | ||
136 | * drm_property_create_blob(), or through the corresponding IOCTL. | ||
137 | * | ||
138 | * Besides the built-in limit to only accept blob objects blob | ||
139 | * properties work exactly like object properties. The only reasons | ||
140 | * blob properties exist is backwards compatibility with existing | ||
141 | * userspace. | ||
142 | * | ||
143 | * In addition a property can have any combination of the below flags: | ||
144 | * | ||
145 | * DRM_MODE_PROP_ATOMIC | ||
146 | * Set for properties which encode atomic modeset state. Such | ||
147 | * properties are not exposed to legacy userspace. | ||
148 | * | ||
149 | * DRM_MODE_PROP_IMMUTABLE | ||
150 | * Set for properties where userspace cannot be changed by | ||
151 | * userspace. The kernel is allowed to update the value of these | ||
152 | * properties. This is generally used to expose probe state to | ||
153 | * usersapce, e.g. the EDID, or the connector path property on DP | ||
154 | * MST sinks. | ||
155 | */ | ||
156 | uint32_t flags; | ||
157 | |||
158 | /** | ||
159 | * @name: symbolic name of the properties | ||
160 | */ | ||
161 | char name[DRM_PROP_NAME_LEN]; | ||
162 | |||
163 | /** | ||
164 | * @num_values: size of the @values array. | ||
165 | */ | ||
166 | uint32_t num_values; | ||
167 | |||
168 | /** | ||
169 | * @values: | ||
170 | * | ||
171 | * Array with limits and values for the property. The | ||
172 | * interpretation of these limits is dependent upon the type per @flags. | ||
173 | */ | ||
174 | uint64_t *values; | ||
175 | |||
176 | /** | ||
177 | * @dev: DRM device | ||
178 | */ | ||
179 | struct drm_device *dev; | ||
180 | |||
181 | /** | ||
182 | * @enum_list: | ||
183 | * | ||
184 | * List of &drm_prop_enum_list structures with the symbolic names for | ||
185 | * enum and bitmask values. | ||
186 | */ | ||
187 | struct list_head enum_list; | ||
188 | }; | ||
189 | |||
190 | /** | ||
191 | * struct drm_property_blob - Blob data for &drm_property | ||
192 | * @base: base KMS object | ||
193 | * @dev: DRM device | ||
194 | * @head_global: entry on the global blob list in &drm_mode_config | ||
195 | * property_blob_list. | ||
196 | * @head_file: entry on the per-file blob list in &drm_file blobs list. | ||
197 | * @length: size of the blob in bytes, invariant over the lifetime of the object | ||
198 | * @data: actual data, embedded at the end of this structure | ||
199 | * | ||
200 | * Blobs are used to store bigger values than what fits directly into the 64 | ||
201 | * bits available for a &drm_property. | ||
202 | * | ||
203 | * Blobs are reference counted using drm_property_reference_blob() and | ||
204 | * drm_property_unreference_blob(). They are created using | ||
205 | * drm_property_create_blob(). | ||
206 | */ | ||
207 | struct drm_property_blob { | ||
208 | struct drm_mode_object base; | ||
209 | struct drm_device *dev; | ||
210 | struct list_head head_global; | ||
211 | struct list_head head_file; | ||
212 | size_t length; | ||
213 | unsigned char data[]; | ||
214 | }; | ||
215 | |||
216 | struct drm_prop_enum_list { | ||
217 | int type; | ||
218 | char *name; | ||
219 | }; | ||
220 | |||
221 | #define obj_to_property(x) container_of(x, struct drm_property, base) | ||
222 | |||
223 | /** | ||
224 | * drm_property_type_is - check the type of a property | ||
225 | * @property: property to check | ||
226 | * @type: property type to compare with | ||
227 | * | ||
228 | * This is a helper function becauase the uapi encoding of property types is | ||
229 | * a bit special for historical reasons. | ||
230 | */ | ||
231 | static inline bool drm_property_type_is(struct drm_property *property, | ||
232 | uint32_t type) | ||
233 | { | ||
234 | /* instanceof for props.. handles extended type vs original types: */ | ||
235 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
236 | return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type; | ||
237 | return property->flags & type; | ||
238 | } | ||
239 | |||
240 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
241 | const char *name, int num_values); | ||
242 | struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, | ||
243 | const char *name, | ||
244 | const struct drm_prop_enum_list *props, | ||
245 | int num_values); | ||
246 | struct drm_property *drm_property_create_bitmask(struct drm_device *dev, | ||
247 | int flags, const char *name, | ||
248 | const struct drm_prop_enum_list *props, | ||
249 | int num_props, | ||
250 | uint64_t supported_bits); | ||
251 | struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, | ||
252 | const char *name, | ||
253 | uint64_t min, uint64_t max); | ||
254 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | ||
255 | int flags, const char *name, | ||
256 | int64_t min, int64_t max); | ||
257 | struct drm_property *drm_property_create_object(struct drm_device *dev, | ||
258 | int flags, const char *name, uint32_t type); | ||
259 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
260 | const char *name); | ||
261 | int drm_property_add_enum(struct drm_property *property, int index, | ||
262 | uint64_t value, const char *name); | ||
263 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property); | ||
264 | |||
265 | struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, | ||
266 | size_t length, | ||
267 | const void *data); | ||
268 | struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | ||
269 | uint32_t id); | ||
270 | int drm_property_replace_global_blob(struct drm_device *dev, | ||
271 | struct drm_property_blob **replace, | ||
272 | size_t length, | ||
273 | const void *data, | ||
274 | struct drm_mode_object *obj_holds_id, | ||
275 | struct drm_property *prop_holds_id); | ||
276 | struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob); | ||
277 | void drm_property_unreference_blob(struct drm_property_blob *blob); | ||
278 | |||
279 | /** | ||
280 | * drm_connector_find - find property object | ||
281 | * @dev: DRM device | ||
282 | * @id: property object id | ||
283 | * | ||
284 | * This function looks up the property object specified by id and returns it. | ||
285 | */ | ||
286 | static inline struct drm_property *drm_property_find(struct drm_device *dev, | ||
287 | uint32_t id) | ||
288 | { | ||
289 | struct drm_mode_object *mo; | ||
290 | mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PROPERTY); | ||
291 | return mo ? obj_to_property(mo) : NULL; | ||
292 | } | ||
293 | |||
294 | #endif | ||
diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index 269039722f91..5d112f75e04c 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h | |||
@@ -60,6 +60,12 @@ struct drm_simple_display_pipe_funcs { | |||
60 | * | 60 | * |
61 | * This function is called when the underlying plane state is updated. | 61 | * This function is called when the underlying plane state is updated. |
62 | * This hook is optional. | 62 | * This hook is optional. |
63 | * | ||
64 | * This is the function drivers should submit the | ||
65 | * &drm_pending_vblank_event from. Using either | ||
66 | * drm_crtc_arm_vblank_event(), when the driver supports vblank | ||
67 | * interrupt handling, or drm_crtc_send_vblank_event() directly in case | ||
68 | * the hardware lacks vblank support entirely. | ||
63 | */ | 69 | */ |
64 | void (*update)(struct drm_simple_display_pipe *pipe, | 70 | void (*update)(struct drm_simple_display_pipe *pipe, |
65 | struct drm_plane_state *plane_state); | 71 | struct drm_plane_state *plane_state); |
@@ -85,6 +91,11 @@ struct drm_simple_display_pipe { | |||
85 | const struct drm_simple_display_pipe_funcs *funcs; | 91 | const struct drm_simple_display_pipe_funcs *funcs; |
86 | }; | 92 | }; |
87 | 93 | ||
94 | int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, | ||
95 | struct drm_bridge *bridge); | ||
96 | |||
97 | void drm_simple_display_pipe_detach_bridge(struct drm_simple_display_pipe *pipe); | ||
98 | |||
88 | int drm_simple_display_pipe_init(struct drm_device *dev, | 99 | int drm_simple_display_pipe_init(struct drm_device *dev, |
89 | struct drm_simple_display_pipe *pipe, | 100 | struct drm_simple_display_pipe *pipe, |
90 | const struct drm_simple_display_pipe_funcs *funcs, | 101 | const struct drm_simple_display_pipe_funcs *funcs, |