diff options
| -rw-r--r-- | Documentation/DocBook/drm.tmpl | 91 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 730 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 106 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 345 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_crtc_internal.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_drv.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_plane_helper.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_atomic.c | 20 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 2 | ||||
| -rw-r--r-- | include/drm/drmP.h | 4 | ||||
| -rw-r--r-- | include/drm/drm_atomic.h | 13 | ||||
| -rw-r--r-- | include/drm/drm_atomic_helper.h | 4 | ||||
| -rw-r--r-- | include/drm/drm_crtc.h | 70 | ||||
| -rw-r--r-- | include/uapi/drm/drm.h | 8 | ||||
| -rw-r--r-- | include/uapi/drm/drm_mode.h | 30 |
19 files changed, 1294 insertions, 159 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 8a0b2a84f4bf..640c2a30563f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl | |||
| @@ -239,6 +239,14 @@ | |||
| 239 | Driver supports dedicated render nodes. | 239 | Driver supports dedicated render nodes. |
| 240 | </para></listitem> | 240 | </para></listitem> |
| 241 | </varlistentry> | 241 | </varlistentry> |
| 242 | <varlistentry> | ||
| 243 | <term>DRIVER_ATOMIC</term> | ||
| 244 | <listitem><para> | ||
| 245 | Driver supports atomic properties. In this case the driver | ||
| 246 | must implement appropriate obj->atomic_get_property() vfuncs | ||
| 247 | for any modeset objects with driver specific properties. | ||
| 248 | </para></listitem> | ||
| 249 | </varlistentry> | ||
| 242 | </variablelist> | 250 | </variablelist> |
| 243 | </sect3> | 251 | </sect3> |
| 244 | <sect3> | 252 | <sect3> |
| @@ -2565,8 +2573,8 @@ void intel_crt_init(struct drm_device *dev) | |||
| 2565 | <td valign="top" >Description/Restrictions</td> | 2573 | <td valign="top" >Description/Restrictions</td> |
| 2566 | </tr> | 2574 | </tr> |
| 2567 | <tr> | 2575 | <tr> |
| 2568 | <td rowspan="25" valign="top" >DRM</td> | 2576 | <td rowspan="36" valign="top" >DRM</td> |
| 2569 | <td rowspan="4" valign="top" >Generic</td> | 2577 | <td rowspan="5" valign="top" >Connector</td> |
| 2570 | <td valign="top" >“EDID”</td> | 2578 | <td valign="top" >“EDID”</td> |
| 2571 | <td valign="top" >BLOB | IMMUTABLE</td> | 2579 | <td valign="top" >BLOB | IMMUTABLE</td> |
| 2572 | <td valign="top" >0</td> | 2580 | <td valign="top" >0</td> |
| @@ -2595,7 +2603,14 @@ void intel_crt_init(struct drm_device *dev) | |||
| 2595 | <td valign="top" >Contains tiling information for a connector.</td> | 2603 | <td valign="top" >Contains tiling information for a connector.</td> |
| 2596 | </tr> | 2604 | </tr> |
| 2597 | <tr> | 2605 | <tr> |
| 2598 | <td rowspan="1" valign="top" >Plane</td> | 2606 | <td valign="top" >“CRTC_ID”</td> |
| 2607 | <td valign="top" >OBJECT</td> | ||
| 2608 | <td valign="top" >DRM_MODE_OBJECT_CRTC</td> | ||
| 2609 | <td valign="top" >Connector</td> | ||
| 2610 | <td valign="top" >CRTC that connector is attached to (atomic)</td> | ||
| 2611 | </tr> | ||
| 2612 | <tr> | ||
| 2613 | <td rowspan="11" valign="top" >Plane</td> | ||
| 2599 | <td valign="top" >“type”</td> | 2614 | <td valign="top" >“type”</td> |
| 2600 | <td valign="top" >ENUM | IMMUTABLE</td> | 2615 | <td valign="top" >ENUM | IMMUTABLE</td> |
| 2601 | <td valign="top" >{ "Overlay", "Primary", "Cursor" }</td> | 2616 | <td valign="top" >{ "Overlay", "Primary", "Cursor" }</td> |
| @@ -2603,6 +2618,76 @@ void intel_crt_init(struct drm_device *dev) | |||
| 2603 | <td valign="top" >Plane type</td> | 2618 | <td valign="top" >Plane type</td> |
| 2604 | </tr> | 2619 | </tr> |
| 2605 | <tr> | 2620 | <tr> |
| 2621 | <td valign="top" >“SRC_X”</td> | ||
| 2622 | <td valign="top" >RANGE</td> | ||
| 2623 | <td valign="top" >Min=0, Max=UINT_MAX</td> | ||
| 2624 | <td valign="top" >Plane</td> | ||
| 2625 | <td valign="top" >Scanout source x coordinate in 16.16 fixed point (atomic)</td> | ||
| 2626 | </tr> | ||
| 2627 | <tr> | ||
| 2628 | <td valign="top" >“SRC_Y”</td> | ||
| 2629 | <td valign="top" >RANGE</td> | ||
| 2630 | <td valign="top" >Min=0, Max=UINT_MAX</td> | ||
| 2631 | <td valign="top" >Plane</td> | ||
| 2632 | <td valign="top" >Scanout source y coordinate in 16.16 fixed point (atomic)</td> | ||
| 2633 | </tr> | ||
| 2634 | <tr> | ||
| 2635 | <td valign="top" >“SRC_W”</td> | ||
| 2636 | <td valign="top" >RANGE</td> | ||
| 2637 | <td valign="top" >Min=0, Max=UINT_MAX</td> | ||
| 2638 | <td valign="top" >Plane</td> | ||
| 2639 | <td valign="top" >Scanout source width in 16.16 fixed point (atomic)</td> | ||
| 2640 | </tr> | ||
| 2641 | <tr> | ||
| 2642 | <td valign="top" >“SRC_H”</td> | ||
| 2643 | <td valign="top" >RANGE</td> | ||
| 2644 | <td valign="top" >Min=0, Max=UINT_MAX</td> | ||
| 2645 | <td valign="top" >Plane</td> | ||
| 2646 | <td valign="top" >Scanout source height in 16.16 fixed point (atomic)</td> | ||
| 2647 | </tr> | ||
| 2648 | <tr> | ||
| 2649 | <td valign="top" >“CRTC_X”</td> | ||
| 2650 | <td valign="top" >SIGNED_RANGE</td> | ||
| 2651 | <td valign="top" >Min=INT_MIN, Max=INT_MAX</td> | ||
| 2652 | <td valign="top" >Plane</td> | ||
| 2653 | <td valign="top" >Scanout CRTC (destination) x coordinate (atomic)</td> | ||
| 2654 | </tr> | ||
| 2655 | <tr> | ||
| 2656 | <td valign="top" >“CRTC_Y”</td> | ||
| 2657 | <td valign="top" >SIGNED_RANGE</td> | ||
| 2658 | <td valign="top" >Min=INT_MIN, Max=INT_MAX</td> | ||
| 2659 | <td valign="top" >Plane</td> | ||
| 2660 | <td valign="top" >Scanout CRTC (destination) y coordinate (atomic)</td> | ||
| 2661 | </tr> | ||
| 2662 | <tr> | ||
| 2663 | <td valign="top" >“CRTC_W”</td> | ||
| 2664 | <td valign="top" >RANGE</td> | ||
| 2665 | <td valign="top" >Min=0, Max=UINT_MAX</td> | ||
| 2666 | <td valign="top" >Plane</td> | ||
| 2667 | <td valign="top" >Scanout CRTC (destination) width (atomic)</td> | ||
| 2668 | </tr> | ||
| 2669 | <tr> | ||
| 2670 | <td valign="top" >“CRTC_H”</td> | ||
| 2671 | <td valign="top" >RANGE</td> | ||
| 2672 | <td valign="top" >Min=0, Max=UINT_MAX</td> | ||
| 2673 | <td valign="top" >Plane</td> | ||
| 2674 | <td valign="top" >Scanout CRTC (destination) height (atomic)</td> | ||
| 2675 | </tr> | ||
| 2676 | <tr> | ||
| 2677 | <td valign="top" >“FB_ID”</td> | ||
| 2678 | <td valign="top" >OBJECT</td> | ||
| 2679 | <td valign="top" >DRM_MODE_OBJECT_FB</td> | ||
| 2680 | <td valign="top" >Plane</td> | ||
| 2681 | <td valign="top" >Scanout framebuffer (atomic)</td> | ||
| 2682 | </tr> | ||
| 2683 | <tr> | ||
| 2684 | <td valign="top" >“CRTC_ID”</td> | ||
| 2685 | <td valign="top" >OBJECT</td> | ||
| 2686 | <td valign="top" >DRM_MODE_OBJECT_CRTC</td> | ||
| 2687 | <td valign="top" >Plane</td> | ||
| 2688 | <td valign="top" >CRTC that plane is attached to (atomic)</td> | ||
| 2689 | </tr> | ||
| 2690 | <tr> | ||
| 2606 | <td rowspan="2" valign="top" >DVI-I</td> | 2691 | <td rowspan="2" valign="top" >DVI-I</td> |
| 2607 | <td valign="top" >“subconnector”</td> | 2692 | <td valign="top" >“subconnector”</td> |
| 2608 | <td valign="top" >ENUM</td> | 2693 | <td valign="top" >ENUM</td> |
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index ff5f034cc405..1e38dfc8e462 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
| @@ -56,6 +56,11 @@ drm_atomic_state_alloc(struct drm_device *dev) | |||
| 56 | if (!state) | 56 | if (!state) |
| 57 | return NULL; | 57 | return NULL; |
| 58 | 58 | ||
| 59 | /* TODO legacy paths should maybe do a better job about | ||
| 60 | * setting this appropriately? | ||
| 61 | */ | ||
| 62 | state->allow_modeset = true; | ||
| 63 | |||
| 59 | state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); | 64 | state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); |
| 60 | 65 | ||
| 61 | state->crtcs = kcalloc(dev->mode_config.num_crtc, | 66 | state->crtcs = kcalloc(dev->mode_config.num_crtc, |
| @@ -217,6 +222,70 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, | |||
| 217 | EXPORT_SYMBOL(drm_atomic_get_crtc_state); | 222 | EXPORT_SYMBOL(drm_atomic_get_crtc_state); |
| 218 | 223 | ||
| 219 | /** | 224 | /** |
| 225 | * drm_atomic_crtc_set_property - set property on CRTC | ||
| 226 | * @crtc: the drm CRTC to set a property on | ||
| 227 | * @state: the state object to update with the new property value | ||
| 228 | * @property: the property to set | ||
| 229 | * @val: the new property value | ||
| 230 | * | ||
| 231 | * Use this instead of calling crtc->atomic_set_property directly. | ||
| 232 | * This function handles generic/core properties and calls out to | ||
| 233 | * driver's ->atomic_set_property() for driver properties. To ensure | ||
| 234 | * consistent behavior you must call this function rather than the | ||
| 235 | * driver hook directly. | ||
| 236 | * | ||
| 237 | * RETURNS: | ||
| 238 | * Zero on success, error code on failure | ||
| 239 | */ | ||
| 240 | int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | ||
| 241 | struct drm_crtc_state *state, struct drm_property *property, | ||
| 242 | uint64_t val) | ||
| 243 | { | ||
| 244 | if (crtc->funcs->atomic_set_property) | ||
| 245 | return crtc->funcs->atomic_set_property(crtc, state, property, val); | ||
| 246 | return -EINVAL; | ||
| 247 | } | ||
| 248 | EXPORT_SYMBOL(drm_atomic_crtc_set_property); | ||
| 249 | |||
| 250 | /* | ||
| 251 | * This function handles generic/core properties and calls out to | ||
| 252 | * driver's ->atomic_get_property() for driver properties. To ensure | ||
| 253 | * consistent behavior you must call this function rather than the | ||
| 254 | * driver hook directly. | ||
| 255 | */ | ||
| 256 | int drm_atomic_crtc_get_property(struct drm_crtc *crtc, | ||
| 257 | const struct drm_crtc_state *state, | ||
| 258 | struct drm_property *property, uint64_t *val) | ||
| 259 | { | ||
| 260 | if (crtc->funcs->atomic_get_property) | ||
| 261 | return crtc->funcs->atomic_get_property(crtc, state, property, val); | ||
| 262 | return -EINVAL; | ||
| 263 | } | ||
| 264 | |||
| 265 | /** | ||
| 266 | * drm_atomic_crtc_check - check crtc state | ||
| 267 | * @crtc: crtc to check | ||
| 268 | * @state: crtc state to check | ||
| 269 | * | ||
| 270 | * Provides core sanity checks for crtc state. | ||
| 271 | * | ||
| 272 | * RETURNS: | ||
| 273 | * Zero on success, error code on failure | ||
| 274 | */ | ||
| 275 | static int drm_atomic_crtc_check(struct drm_crtc *crtc, | ||
| 276 | struct drm_crtc_state *state) | ||
| 277 | { | ||
| 278 | /* NOTE: we explicitly don't enforce constraints such as primary | ||
| 279 | * layer covering entire screen, since that is something we want | ||
| 280 | * to allow (on hw that supports it). For hw that does not, it | ||
| 281 | * should be checked in driver's crtc->atomic_check() vfunc. | ||
| 282 | * | ||
| 283 | * TODO: Add generic modeset state checks once we support those. | ||
| 284 | */ | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | /** | ||
| 220 | * drm_atomic_get_plane_state - get plane state | 289 | * drm_atomic_get_plane_state - get plane state |
| 221 | * @state: global atomic state object | 290 | * @state: global atomic state object |
| 222 | * @plane: plane to get state object for | 291 | * @plane: plane to get state object for |
| @@ -272,6 +341,183 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, | |||
| 272 | EXPORT_SYMBOL(drm_atomic_get_plane_state); | 341 | EXPORT_SYMBOL(drm_atomic_get_plane_state); |
| 273 | 342 | ||
| 274 | /** | 343 | /** |
| 344 | * drm_atomic_plane_set_property - set property on plane | ||
| 345 | * @plane: the drm plane to set a property on | ||
| 346 | * @state: the state object to update with the new property value | ||
| 347 | * @property: the property to set | ||
| 348 | * @val: the new property value | ||
| 349 | * | ||
| 350 | * Use this instead of calling plane->atomic_set_property directly. | ||
| 351 | * This function handles generic/core properties and calls out to | ||
| 352 | * driver's ->atomic_set_property() for driver properties. To ensure | ||
| 353 | * consistent behavior you must call this function rather than the | ||
| 354 | * driver hook directly. | ||
| 355 | * | ||
| 356 | * RETURNS: | ||
| 357 | * Zero on success, error code on failure | ||
| 358 | */ | ||
| 359 | int drm_atomic_plane_set_property(struct drm_plane *plane, | ||
| 360 | struct drm_plane_state *state, struct drm_property *property, | ||
| 361 | uint64_t val) | ||
| 362 | { | ||
| 363 | struct drm_device *dev = plane->dev; | ||
| 364 | struct drm_mode_config *config = &dev->mode_config; | ||
| 365 | |||
| 366 | if (property == config->prop_fb_id) { | ||
| 367 | struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val); | ||
| 368 | drm_atomic_set_fb_for_plane(state, fb); | ||
| 369 | if (fb) | ||
| 370 | drm_framebuffer_unreference(fb); | ||
| 371 | } else if (property == config->prop_crtc_id) { | ||
| 372 | struct drm_crtc *crtc = drm_crtc_find(dev, val); | ||
| 373 | return drm_atomic_set_crtc_for_plane(state, crtc); | ||
| 374 | } else if (property == config->prop_crtc_x) { | ||
| 375 | state->crtc_x = U642I64(val); | ||
| 376 | } else if (property == config->prop_crtc_y) { | ||
| 377 | state->crtc_y = U642I64(val); | ||
| 378 | } else if (property == config->prop_crtc_w) { | ||
| 379 | state->crtc_w = val; | ||
| 380 | } else if (property == config->prop_crtc_h) { | ||
| 381 | state->crtc_h = val; | ||
| 382 | } else if (property == config->prop_src_x) { | ||
| 383 | state->src_x = val; | ||
| 384 | } else if (property == config->prop_src_y) { | ||
| 385 | state->src_y = val; | ||
| 386 | } else if (property == config->prop_src_w) { | ||
| 387 | state->src_w = val; | ||
| 388 | } else if (property == config->prop_src_h) { | ||
| 389 | state->src_h = val; | ||
| 390 | } else if (plane->funcs->atomic_set_property) { | ||
| 391 | return plane->funcs->atomic_set_property(plane, state, | ||
| 392 | property, val); | ||
| 393 | } else { | ||
| 394 | return -EINVAL; | ||
| 395 | } | ||
| 396 | |||
| 397 | return 0; | ||
| 398 | } | ||
| 399 | EXPORT_SYMBOL(drm_atomic_plane_set_property); | ||
| 400 | |||
| 401 | /* | ||
| 402 | * This function handles generic/core properties and calls out to | ||
| 403 | * driver's ->atomic_get_property() for driver properties. To ensure | ||
| 404 | * consistent behavior you must call this function rather than the | ||
| 405 | * driver hook directly. | ||
| 406 | */ | ||
| 407 | static int | ||
| 408 | drm_atomic_plane_get_property(struct drm_plane *plane, | ||
| 409 | const struct drm_plane_state *state, | ||
| 410 | struct drm_property *property, uint64_t *val) | ||
| 411 | { | ||
| 412 | struct drm_device *dev = plane->dev; | ||
| 413 | struct drm_mode_config *config = &dev->mode_config; | ||
| 414 | |||
| 415 | if (property == config->prop_fb_id) { | ||
| 416 | *val = (state->fb) ? state->fb->base.id : 0; | ||
| 417 | } else if (property == config->prop_crtc_id) { | ||
| 418 | *val = (state->crtc) ? state->crtc->base.id : 0; | ||
| 419 | } else if (property == config->prop_crtc_x) { | ||
| 420 | *val = I642U64(state->crtc_x); | ||
| 421 | } else if (property == config->prop_crtc_y) { | ||
| 422 | *val = I642U64(state->crtc_y); | ||
| 423 | } else if (property == config->prop_crtc_w) { | ||
| 424 | *val = state->crtc_w; | ||
| 425 | } else if (property == config->prop_crtc_h) { | ||
| 426 | *val = state->crtc_h; | ||
| 427 | } else if (property == config->prop_src_x) { | ||
| 428 | *val = state->src_x; | ||
| 429 | } else if (property == config->prop_src_y) { | ||
| 430 | *val = state->src_y; | ||
| 431 | } else if (property == config->prop_src_w) { | ||
| 432 | *val = state->src_w; | ||
| 433 | } else if (property == config->prop_src_h) { | ||
| 434 | *val = state->src_h; | ||
| 435 | } else if (plane->funcs->atomic_get_property) { | ||
| 436 | return plane->funcs->atomic_get_property(plane, state, property, val); | ||
| 437 | } else { | ||
| 438 | return -EINVAL; | ||
| 439 | } | ||
| 440 | |||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 444 | /** | ||
| 445 | * drm_atomic_plane_check - check plane state | ||
| 446 | * @plane: plane to check | ||
| 447 | * @state: plane state to check | ||
| 448 | * | ||
| 449 | * Provides core sanity checks for plane state. | ||
| 450 | * | ||
| 451 | * RETURNS: | ||
| 452 | * Zero on success, error code on failure | ||
| 453 | */ | ||
| 454 | static int drm_atomic_plane_check(struct drm_plane *plane, | ||
| 455 | struct drm_plane_state *state) | ||
| 456 | { | ||
| 457 | unsigned int fb_width, fb_height; | ||
| 458 | unsigned int i; | ||
| 459 | |||
| 460 | /* either *both* CRTC and FB must be set, or neither */ | ||
| 461 | if (WARN_ON(state->crtc && !state->fb)) { | ||
| 462 | DRM_DEBUG_KMS("CRTC set but no FB\n"); | ||
| 463 | return -EINVAL; | ||
| 464 | } else if (WARN_ON(state->fb && !state->crtc)) { | ||
| 465 | DRM_DEBUG_KMS("FB set but no CRTC\n"); | ||
| 466 | return -EINVAL; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* if disabled, we don't care about the rest of the state: */ | ||
| 470 | if (!state->crtc) | ||
| 471 | return 0; | ||
| 472 | |||
| 473 | /* Check whether this plane is usable on this CRTC */ | ||
| 474 | if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { | ||
| 475 | DRM_DEBUG_KMS("Invalid crtc for plane\n"); | ||
| 476 | return -EINVAL; | ||
| 477 | } | ||
| 478 | |||
| 479 | /* Check whether this plane supports the fb pixel format. */ | ||
| 480 | for (i = 0; i < plane->format_count; i++) | ||
| 481 | if (state->fb->pixel_format == plane->format_types[i]) | ||
| 482 | break; | ||
| 483 | if (i == plane->format_count) { | ||
| 484 | DRM_DEBUG_KMS("Invalid pixel format %s\n", | ||
| 485 | drm_get_format_name(state->fb->pixel_format)); | ||
| 486 | return -EINVAL; | ||
| 487 | } | ||
| 488 | |||
| 489 | /* Give drivers some help against integer overflows */ | ||
| 490 | if (state->crtc_w > INT_MAX || | ||
| 491 | state->crtc_x > INT_MAX - (int32_t) state->crtc_w || | ||
| 492 | state->crtc_h > INT_MAX || | ||
| 493 | state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { | ||
| 494 | DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", | ||
| 495 | state->crtc_w, state->crtc_h, | ||
| 496 | state->crtc_x, state->crtc_y); | ||
| 497 | return -ERANGE; | ||
| 498 | } | ||
| 499 | |||
| 500 | fb_width = state->fb->width << 16; | ||
| 501 | fb_height = state->fb->height << 16; | ||
| 502 | |||
| 503 | /* Make sure source coordinates are inside the fb. */ | ||
| 504 | if (state->src_w > fb_width || | ||
| 505 | state->src_x > fb_width - state->src_w || | ||
| 506 | state->src_h > fb_height || | ||
| 507 | state->src_y > fb_height - state->src_h) { | ||
| 508 | DRM_DEBUG_KMS("Invalid source coordinates " | ||
| 509 | "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", | ||
| 510 | state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, | ||
| 511 | state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, | ||
| 512 | state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, | ||
| 513 | state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); | ||
| 514 | return -ENOSPC; | ||
| 515 | } | ||
| 516 | |||
| 517 | return 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | /** | ||
| 275 | * drm_atomic_get_connector_state - get connector state | 521 | * drm_atomic_get_connector_state - get connector state |
| 276 | * @state: global atomic state object | 522 | * @state: global atomic state object |
| 277 | * @connector: connector to get state object for | 523 | * @connector: connector to get state object for |
| @@ -343,9 +589,113 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, | |||
| 343 | EXPORT_SYMBOL(drm_atomic_get_connector_state); | 589 | EXPORT_SYMBOL(drm_atomic_get_connector_state); |
| 344 | 590 | ||
| 345 | /** | 591 | /** |
| 592 | * drm_atomic_connector_set_property - set property on connector. | ||
| 593 | * @connector: the drm connector to set a property on | ||
| 594 | * @state: the state object to update with the new property value | ||
| 595 | * @property: the property to set | ||
| 596 | * @val: the new property value | ||
| 597 | * | ||
| 598 | * Use this instead of calling connector->atomic_set_property directly. | ||
| 599 | * This function handles generic/core properties and calls out to | ||
| 600 | * driver's ->atomic_set_property() for driver properties. To ensure | ||
| 601 | * consistent behavior you must call this function rather than the | ||
| 602 | * driver hook directly. | ||
| 603 | * | ||
| 604 | * RETURNS: | ||
| 605 | * Zero on success, error code on failure | ||
| 606 | */ | ||
| 607 | int drm_atomic_connector_set_property(struct drm_connector *connector, | ||
| 608 | struct drm_connector_state *state, struct drm_property *property, | ||
| 609 | uint64_t val) | ||
| 610 | { | ||
| 611 | struct drm_device *dev = connector->dev; | ||
| 612 | struct drm_mode_config *config = &dev->mode_config; | ||
| 613 | |||
| 614 | if (property == config->prop_crtc_id) { | ||
| 615 | struct drm_crtc *crtc = drm_crtc_find(dev, val); | ||
| 616 | return drm_atomic_set_crtc_for_connector(state, crtc); | ||
| 617 | } else if (property == config->dpms_property) { | ||
| 618 | /* setting DPMS property requires special handling, which | ||
| 619 | * is done in legacy setprop path for us. Disallow (for | ||
| 620 | * now?) atomic writes to DPMS property: | ||
| 621 | */ | ||
| 622 | return -EINVAL; | ||
| 623 | } else if (connector->funcs->atomic_set_property) { | ||
| 624 | return connector->funcs->atomic_set_property(connector, | ||
| 625 | state, property, val); | ||
| 626 | } else { | ||
| 627 | return -EINVAL; | ||
| 628 | } | ||
| 629 | } | ||
| 630 | EXPORT_SYMBOL(drm_atomic_connector_set_property); | ||
| 631 | |||
| 632 | /* | ||
| 633 | * This function handles generic/core properties and calls out to | ||
| 634 | * driver's ->atomic_get_property() for driver properties. To ensure | ||
| 635 | * consistent behavior you must call this function rather than the | ||
| 636 | * driver hook directly. | ||
| 637 | */ | ||
| 638 | static int | ||
| 639 | drm_atomic_connector_get_property(struct drm_connector *connector, | ||
| 640 | const struct drm_connector_state *state, | ||
| 641 | struct drm_property *property, uint64_t *val) | ||
| 642 | { | ||
| 643 | struct drm_device *dev = connector->dev; | ||
| 644 | struct drm_mode_config *config = &dev->mode_config; | ||
| 645 | |||
| 646 | if (property == config->prop_crtc_id) { | ||
| 647 | *val = (state->crtc) ? state->crtc->base.id : 0; | ||
| 648 | } else if (property == config->dpms_property) { | ||
| 649 | *val = connector->dpms; | ||
| 650 | } else if (connector->funcs->atomic_get_property) { | ||
| 651 | return connector->funcs->atomic_get_property(connector, | ||
| 652 | state, property, val); | ||
| 653 | } else { | ||
| 654 | return -EINVAL; | ||
| 655 | } | ||
| 656 | |||
| 657 | return 0; | ||
| 658 | } | ||
| 659 | |||
| 660 | int drm_atomic_get_property(struct drm_mode_object *obj, | ||
| 661 | struct drm_property *property, uint64_t *val) | ||
| 662 | { | ||
| 663 | struct drm_device *dev = property->dev; | ||
| 664 | int ret; | ||
| 665 | |||
| 666 | switch (obj->type) { | ||
| 667 | case DRM_MODE_OBJECT_CONNECTOR: { | ||
| 668 | struct drm_connector *connector = obj_to_connector(obj); | ||
| 669 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); | ||
| 670 | ret = drm_atomic_connector_get_property(connector, | ||
| 671 | connector->state, property, val); | ||
| 672 | break; | ||
| 673 | } | ||
| 674 | case DRM_MODE_OBJECT_CRTC: { | ||
| 675 | struct drm_crtc *crtc = obj_to_crtc(obj); | ||
| 676 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
| 677 | ret = drm_atomic_crtc_get_property(crtc, | ||
| 678 | crtc->state, property, val); | ||
| 679 | break; | ||
| 680 | } | ||
| 681 | case DRM_MODE_OBJECT_PLANE: { | ||
| 682 | struct drm_plane *plane = obj_to_plane(obj); | ||
| 683 | WARN_ON(!drm_modeset_is_locked(&plane->mutex)); | ||
| 684 | ret = drm_atomic_plane_get_property(plane, | ||
| 685 | plane->state, property, val); | ||
| 686 | break; | ||
| 687 | } | ||
| 688 | default: | ||
| 689 | ret = -EINVAL; | ||
| 690 | break; | ||
| 691 | } | ||
| 692 | |||
| 693 | return ret; | ||
| 694 | } | ||
| 695 | |||
| 696 | /** | ||
| 346 | * drm_atomic_set_crtc_for_plane - set crtc for plane | 697 | * drm_atomic_set_crtc_for_plane - set crtc for plane |
| 347 | * @state: the incoming atomic state | 698 | * @plane_state: the plane whose incoming state to update |
| 348 | * @plane: the plane whose incoming state to update | ||
| 349 | * @crtc: crtc to use for the plane | 699 | * @crtc: crtc to use for the plane |
| 350 | * | 700 | * |
| 351 | * Changing the assigned crtc for a plane requires us to grab the lock and state | 701 | * Changing the assigned crtc for a plane requires us to grab the lock and state |
| @@ -358,16 +708,12 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); | |||
| 358 | * sequence must be restarted. All other errors are fatal. | 708 | * sequence must be restarted. All other errors are fatal. |
| 359 | */ | 709 | */ |
| 360 | int | 710 | int |
| 361 | drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, | 711 | drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, |
| 362 | struct drm_plane *plane, struct drm_crtc *crtc) | 712 | struct drm_crtc *crtc) |
| 363 | { | 713 | { |
| 364 | struct drm_plane_state *plane_state = | 714 | struct drm_plane *plane = plane_state->plane; |
| 365 | drm_atomic_get_plane_state(state, plane); | ||
| 366 | struct drm_crtc_state *crtc_state; | 715 | struct drm_crtc_state *crtc_state; |
| 367 | 716 | ||
| 368 | if (WARN_ON(IS_ERR(plane_state))) | ||
| 369 | return PTR_ERR(plane_state); | ||
| 370 | |||
| 371 | if (plane_state->crtc) { | 717 | if (plane_state->crtc) { |
| 372 | crtc_state = drm_atomic_get_crtc_state(plane_state->state, | 718 | crtc_state = drm_atomic_get_crtc_state(plane_state->state, |
| 373 | plane_state->crtc); | 719 | plane_state->crtc); |
| @@ -583,14 +929,62 @@ EXPORT_SYMBOL(drm_atomic_legacy_backoff); | |||
| 583 | */ | 929 | */ |
| 584 | int drm_atomic_check_only(struct drm_atomic_state *state) | 930 | int drm_atomic_check_only(struct drm_atomic_state *state) |
| 585 | { | 931 | { |
| 586 | struct drm_mode_config *config = &state->dev->mode_config; | 932 | struct drm_device *dev = state->dev; |
| 933 | struct drm_mode_config *config = &dev->mode_config; | ||
| 934 | int nplanes = config->num_total_plane; | ||
| 935 | int ncrtcs = config->num_crtc; | ||
| 936 | int i, ret = 0; | ||
| 587 | 937 | ||
| 588 | DRM_DEBUG_KMS("checking %p\n", state); | 938 | DRM_DEBUG_KMS("checking %p\n", state); |
| 589 | 939 | ||
| 940 | for (i = 0; i < nplanes; i++) { | ||
| 941 | struct drm_plane *plane = state->planes[i]; | ||
| 942 | |||
| 943 | if (!plane) | ||
| 944 | continue; | ||
| 945 | |||
| 946 | ret = drm_atomic_plane_check(plane, state->plane_states[i]); | ||
| 947 | if (ret) { | ||
| 948 | DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n", | ||
| 949 | plane->base.id); | ||
| 950 | return ret; | ||
| 951 | } | ||
| 952 | } | ||
| 953 | |||
| 954 | for (i = 0; i < ncrtcs; i++) { | ||
| 955 | struct drm_crtc *crtc = state->crtcs[i]; | ||
| 956 | |||
| 957 | if (!crtc) | ||
| 958 | continue; | ||
| 959 | |||
| 960 | ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]); | ||
| 961 | if (ret) { | ||
| 962 | DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n", | ||
| 963 | crtc->base.id); | ||
| 964 | return ret; | ||
| 965 | } | ||
| 966 | } | ||
| 967 | |||
| 590 | if (config->funcs->atomic_check) | 968 | if (config->funcs->atomic_check) |
| 591 | return config->funcs->atomic_check(state->dev, state); | 969 | ret = config->funcs->atomic_check(state->dev, state); |
| 592 | else | 970 | |
| 593 | return 0; | 971 | if (!state->allow_modeset) { |
| 972 | for (i = 0; i < ncrtcs; i++) { | ||
| 973 | struct drm_crtc *crtc = state->crtcs[i]; | ||
| 974 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
| 975 | |||
| 976 | if (!crtc) | ||
| 977 | continue; | ||
| 978 | |||
| 979 | if (crtc_state->mode_changed) { | ||
| 980 | DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", | ||
| 981 | crtc->base.id); | ||
| 982 | return -EINVAL; | ||
| 983 | } | ||
| 984 | } | ||
| 985 | } | ||
| 986 | |||
| 987 | return ret; | ||
| 594 | } | 988 | } |
| 595 | EXPORT_SYMBOL(drm_atomic_check_only); | 989 | EXPORT_SYMBOL(drm_atomic_check_only); |
| 596 | 990 | ||
| @@ -655,3 +1049,313 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) | |||
| 655 | return config->funcs->atomic_commit(state->dev, state, true); | 1049 | return config->funcs->atomic_commit(state->dev, state, true); |
| 656 | } | 1050 | } |
| 657 | EXPORT_SYMBOL(drm_atomic_async_commit); | 1051 | EXPORT_SYMBOL(drm_atomic_async_commit); |
| 1052 | |||
| 1053 | /* | ||
| 1054 | * The big monstor ioctl | ||
| 1055 | */ | ||
| 1056 | |||
| 1057 | static struct drm_pending_vblank_event *create_vblank_event( | ||
| 1058 | struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) | ||
| 1059 | { | ||
| 1060 | struct drm_pending_vblank_event *e = NULL; | ||
| 1061 | unsigned long flags; | ||
| 1062 | |||
| 1063 | spin_lock_irqsave(&dev->event_lock, flags); | ||
| 1064 | if (file_priv->event_space < sizeof e->event) { | ||
| 1065 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
| 1066 | goto out; | ||
| 1067 | } | ||
| 1068 | file_priv->event_space -= sizeof e->event; | ||
| 1069 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
| 1070 | |||
| 1071 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
| 1072 | if (e == NULL) { | ||
| 1073 | spin_lock_irqsave(&dev->event_lock, flags); | ||
| 1074 | file_priv->event_space += sizeof e->event; | ||
| 1075 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
| 1076 | goto out; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | e->event.base.type = DRM_EVENT_FLIP_COMPLETE; | ||
| 1080 | e->event.base.length = sizeof e->event; | ||
| 1081 | e->event.user_data = user_data; | ||
| 1082 | e->base.event = &e->event.base; | ||
| 1083 | e->base.file_priv = file_priv; | ||
| 1084 | e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; | ||
| 1085 | |||
| 1086 | out: | ||
| 1087 | return e; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static void destroy_vblank_event(struct drm_device *dev, | ||
| 1091 | struct drm_file *file_priv, struct drm_pending_vblank_event *e) | ||
| 1092 | { | ||
| 1093 | unsigned long flags; | ||
| 1094 | |||
| 1095 | spin_lock_irqsave(&dev->event_lock, flags); | ||
| 1096 | file_priv->event_space += sizeof e->event; | ||
| 1097 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
| 1098 | kfree(e); | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | static int atomic_set_prop(struct drm_atomic_state *state, | ||
| 1102 | struct drm_mode_object *obj, struct drm_property *prop, | ||
| 1103 | uint64_t prop_value) | ||
| 1104 | { | ||
| 1105 | struct drm_mode_object *ref; | ||
| 1106 | int ret; | ||
| 1107 | |||
| 1108 | if (!drm_property_change_valid_get(prop, prop_value, &ref)) | ||
| 1109 | return -EINVAL; | ||
| 1110 | |||
| 1111 | switch (obj->type) { | ||
| 1112 | case DRM_MODE_OBJECT_CONNECTOR: { | ||
| 1113 | struct drm_connector *connector = obj_to_connector(obj); | ||
| 1114 | struct drm_connector_state *connector_state; | ||
| 1115 | |||
| 1116 | connector_state = drm_atomic_get_connector_state(state, connector); | ||
| 1117 | if (IS_ERR(connector_state)) { | ||
| 1118 | ret = PTR_ERR(connector_state); | ||
| 1119 | break; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | ret = drm_atomic_connector_set_property(connector, | ||
| 1123 | connector_state, prop, prop_value); | ||
| 1124 | break; | ||
| 1125 | } | ||
| 1126 | case DRM_MODE_OBJECT_CRTC: { | ||
| 1127 | struct drm_crtc *crtc = obj_to_crtc(obj); | ||
| 1128 | struct drm_crtc_state *crtc_state; | ||
| 1129 | |||
| 1130 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
| 1131 | if (IS_ERR(crtc_state)) { | ||
| 1132 | ret = PTR_ERR(crtc_state); | ||
| 1133 | break; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | ret = drm_atomic_crtc_set_property(crtc, | ||
| 1137 | crtc_state, prop, prop_value); | ||
| 1138 | break; | ||
| 1139 | } | ||
| 1140 | case DRM_MODE_OBJECT_PLANE: { | ||
| 1141 | struct drm_plane *plane = obj_to_plane(obj); | ||
| 1142 | struct drm_plane_state *plane_state; | ||
| 1143 | |||
| 1144 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
| 1145 | if (IS_ERR(plane_state)) { | ||
| 1146 | ret = PTR_ERR(plane_state); | ||
| 1147 | break; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | ret = drm_atomic_plane_set_property(plane, | ||
| 1151 | plane_state, prop, prop_value); | ||
| 1152 | break; | ||
| 1153 | } | ||
| 1154 | default: | ||
| 1155 | ret = -EINVAL; | ||
| 1156 | break; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | drm_property_change_valid_put(prop, ref); | ||
| 1160 | return ret; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | int drm_mode_atomic_ioctl(struct drm_device *dev, | ||
| 1164 | void *data, struct drm_file *file_priv) | ||
| 1165 | { | ||
| 1166 | struct drm_mode_atomic *arg = data; | ||
| 1167 | uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); | ||
| 1168 | uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); | ||
| 1169 | uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); | ||
| 1170 | uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); | ||
| 1171 | unsigned int copied_objs, copied_props; | ||
| 1172 | struct drm_atomic_state *state; | ||
| 1173 | struct drm_modeset_acquire_ctx ctx; | ||
| 1174 | struct drm_plane *plane; | ||
| 1175 | unsigned plane_mask = 0; | ||
| 1176 | int ret = 0; | ||
| 1177 | unsigned int i, j; | ||
| 1178 | |||
| 1179 | /* disallow for drivers not supporting atomic: */ | ||
| 1180 | if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) | ||
| 1181 | return -EINVAL; | ||
| 1182 | |||
| 1183 | /* disallow for userspace that has not enabled atomic cap (even | ||
| 1184 | * though this may be a bit overkill, since legacy userspace | ||
| 1185 | * wouldn't know how to call this ioctl) | ||
| 1186 | */ | ||
| 1187 | if (!file_priv->atomic) | ||
| 1188 | return -EINVAL; | ||
| 1189 | |||
| 1190 | if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) | ||
| 1191 | return -EINVAL; | ||
| 1192 | |||
| 1193 | if (arg->reserved) | ||
| 1194 | return -EINVAL; | ||
| 1195 | |||
| 1196 | if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) && | ||
| 1197 | !dev->mode_config.async_page_flip) | ||
| 1198 | return -EINVAL; | ||
| 1199 | |||
| 1200 | /* can't test and expect an event at the same time. */ | ||
| 1201 | if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && | ||
| 1202 | (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) | ||
| 1203 | return -EINVAL; | ||
| 1204 | |||
| 1205 | drm_modeset_acquire_init(&ctx, 0); | ||
| 1206 | |||
| 1207 | state = drm_atomic_state_alloc(dev); | ||
| 1208 | if (!state) | ||
| 1209 | return -ENOMEM; | ||
| 1210 | |||
| 1211 | state->acquire_ctx = &ctx; | ||
| 1212 | state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); | ||
| 1213 | |||
| 1214 | retry: | ||
| 1215 | copied_objs = 0; | ||
| 1216 | copied_props = 0; | ||
| 1217 | |||
| 1218 | for (i = 0; i < arg->count_objs; i++) { | ||
| 1219 | uint32_t obj_id, count_props; | ||
| 1220 | struct drm_mode_object *obj; | ||
| 1221 | |||
| 1222 | if (get_user(obj_id, objs_ptr + copied_objs)) { | ||
| 1223 | ret = -EFAULT; | ||
| 1224 | goto fail; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); | ||
| 1228 | if (!obj || !obj->properties) { | ||
| 1229 | ret = -ENOENT; | ||
| 1230 | goto fail; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | if (obj->type == DRM_MODE_OBJECT_PLANE) { | ||
| 1234 | plane = obj_to_plane(obj); | ||
| 1235 | plane_mask |= (1 << drm_plane_index(plane)); | ||
| 1236 | plane->old_fb = plane->fb; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | if (get_user(count_props, count_props_ptr + copied_objs)) { | ||
| 1240 | ret = -EFAULT; | ||
| 1241 | goto fail; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | copied_objs++; | ||
| 1245 | |||
| 1246 | for (j = 0; j < count_props; j++) { | ||
| 1247 | uint32_t prop_id; | ||
| 1248 | uint64_t prop_value; | ||
| 1249 | struct drm_property *prop; | ||
| 1250 | |||
| 1251 | if (get_user(prop_id, props_ptr + copied_props)) { | ||
| 1252 | ret = -EFAULT; | ||
| 1253 | goto fail; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | prop = drm_property_find(dev, prop_id); | ||
| 1257 | if (!prop) { | ||
| 1258 | ret = -ENOENT; | ||
| 1259 | goto fail; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | if (get_user(prop_value, prop_values_ptr + copied_props)) { | ||
| 1263 | ret = -EFAULT; | ||
| 1264 | goto fail; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | ret = atomic_set_prop(state, obj, prop, prop_value); | ||
| 1268 | if (ret) | ||
| 1269 | goto fail; | ||
| 1270 | |||
| 1271 | copied_props++; | ||
| 1272 | } | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
| 1276 | int ncrtcs = dev->mode_config.num_crtc; | ||
| 1277 | |||
| 1278 | for (i = 0; i < ncrtcs; i++) { | ||
| 1279 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
| 1280 | struct drm_pending_vblank_event *e; | ||
| 1281 | |||
| 1282 | if (!crtc_state) | ||
| 1283 | continue; | ||
| 1284 | |||
| 1285 | e = create_vblank_event(dev, file_priv, arg->user_data); | ||
| 1286 | if (!e) { | ||
| 1287 | ret = -ENOMEM; | ||
| 1288 | goto fail; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | crtc_state->event = e; | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { | ||
| 1296 | ret = drm_atomic_check_only(state); | ||
| 1297 | /* _check_only() does not free state, unlike _commit() */ | ||
| 1298 | drm_atomic_state_free(state); | ||
| 1299 | } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { | ||
| 1300 | ret = drm_atomic_async_commit(state); | ||
| 1301 | } else { | ||
| 1302 | ret = drm_atomic_commit(state); | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping | ||
| 1306 | * locks (ie. while it is still safe to deref plane->state). We | ||
| 1307 | * need to do this here because the driver entry points cannot | ||
| 1308 | * distinguish between legacy and atomic ioctls. | ||
| 1309 | */ | ||
| 1310 | drm_for_each_plane_mask(plane, dev, plane_mask) { | ||
| 1311 | if (ret == 0) { | ||
| 1312 | struct drm_framebuffer *new_fb = plane->state->fb; | ||
| 1313 | if (new_fb) | ||
| 1314 | drm_framebuffer_reference(new_fb); | ||
| 1315 | plane->fb = new_fb; | ||
| 1316 | plane->crtc = plane->state->crtc; | ||
| 1317 | } else { | ||
| 1318 | plane->old_fb = NULL; | ||
| 1319 | } | ||
| 1320 | if (plane->old_fb) { | ||
| 1321 | drm_framebuffer_unreference(plane->old_fb); | ||
| 1322 | plane->old_fb = NULL; | ||
| 1323 | } | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | drm_modeset_drop_locks(&ctx); | ||
| 1327 | drm_modeset_acquire_fini(&ctx); | ||
| 1328 | |||
| 1329 | return ret; | ||
| 1330 | |||
| 1331 | fail: | ||
| 1332 | if (ret == -EDEADLK) | ||
| 1333 | goto backoff; | ||
| 1334 | |||
| 1335 | if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
| 1336 | int ncrtcs = dev->mode_config.num_crtc; | ||
| 1337 | |||
| 1338 | for (i = 0; i < ncrtcs; i++) { | ||
| 1339 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
| 1340 | |||
| 1341 | if (!crtc_state) | ||
| 1342 | continue; | ||
| 1343 | |||
| 1344 | destroy_vblank_event(dev, file_priv, crtc_state->event); | ||
| 1345 | crtc_state->event = NULL; | ||
| 1346 | } | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | drm_atomic_state_free(state); | ||
| 1350 | |||
| 1351 | drm_modeset_drop_locks(&ctx); | ||
| 1352 | drm_modeset_acquire_fini(&ctx); | ||
| 1353 | |||
| 1354 | return ret; | ||
| 1355 | |||
| 1356 | backoff: | ||
| 1357 | drm_atomic_state_clear(state); | ||
| 1358 | drm_modeset_backoff(&ctx); | ||
| 1359 | |||
| 1360 | goto retry; | ||
| 1361 | } | ||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bbdbe4721573..541ba833ed36 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
| @@ -330,7 +330,29 @@ mode_fixup(struct drm_atomic_state *state) | |||
| 330 | return 0; | 330 | return 0; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | static int | 333 | /** |
| 334 | * drm_atomic_helper_check - validate state object for modeset changes | ||
| 335 | * @dev: DRM device | ||
| 336 | * @state: the driver state object | ||
| 337 | * | ||
| 338 | * Check the state object to see if the requested state is physically possible. | ||
| 339 | * This does all the crtc and connector related computations for an atomic | ||
| 340 | * update. It computes and updates crtc_state->mode_changed, adds any additional | ||
| 341 | * connectors needed for full modesets and calls down into ->mode_fixup | ||
| 342 | * functions of the driver backend. | ||
| 343 | * | ||
| 344 | * IMPORTANT: | ||
| 345 | * | ||
| 346 | * Drivers which update ->mode_changed (e.g. in their ->atomic_check hooks if a | ||
| 347 | * plane update can't be done without a full modeset) _must_ call this function | ||
| 348 | * afterwards after that change. It is permitted to call this function multiple | ||
| 349 | * times for the same update, e.g. when the ->atomic_check functions depend upon | ||
| 350 | * the adjusted dotclock for fifo space allocation and watermark computation. | ||
| 351 | * | ||
| 352 | * RETURNS | ||
| 353 | * Zero for success or -errno | ||
| 354 | */ | ||
| 355 | int | ||
| 334 | drm_atomic_helper_check_modeset(struct drm_device *dev, | 356 | drm_atomic_helper_check_modeset(struct drm_device *dev, |
| 335 | struct drm_atomic_state *state) | 357 | struct drm_atomic_state *state) |
| 336 | { | 358 | { |
| @@ -406,23 +428,23 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, | |||
| 406 | 428 | ||
| 407 | return mode_fixup(state); | 429 | return mode_fixup(state); |
| 408 | } | 430 | } |
| 431 | EXPORT_SYMBOL(drm_atomic_helper_check_modeset); | ||
| 409 | 432 | ||
| 410 | /** | 433 | /** |
| 411 | * drm_atomic_helper_check - validate state object | 434 | * drm_atomic_helper_check - validate state object for modeset changes |
| 412 | * @dev: DRM device | 435 | * @dev: DRM device |
| 413 | * @state: the driver state object | 436 | * @state: the driver state object |
| 414 | * | 437 | * |
| 415 | * Check the state object to see if the requested state is physically possible. | 438 | * Check the state object to see if the requested state is physically possible. |
| 416 | * Only crtcs and planes have check callbacks, so for any additional (global) | 439 | * This does all the plane update related checks using by calling into the |
| 417 | * checking that a driver needs it can simply wrap that around this function. | 440 | * ->atomic_check hooks provided by the driver. |
| 418 | * Drivers without such needs can directly use this as their ->atomic_check() | ||
| 419 | * callback. | ||
| 420 | * | 441 | * |
| 421 | * RETURNS | 442 | * RETURNS |
| 422 | * Zero for success or -errno | 443 | * Zero for success or -errno |
| 423 | */ | 444 | */ |
| 424 | int drm_atomic_helper_check(struct drm_device *dev, | 445 | int |
| 425 | struct drm_atomic_state *state) | 446 | drm_atomic_helper_check_planes(struct drm_device *dev, |
| 447 | struct drm_atomic_state *state) | ||
| 426 | { | 448 | { |
| 427 | int nplanes = dev->mode_config.num_total_plane; | 449 | int nplanes = dev->mode_config.num_total_plane; |
| 428 | int ncrtcs = dev->mode_config.num_crtc; | 450 | int ncrtcs = dev->mode_config.num_crtc; |
| @@ -445,7 +467,7 @@ int drm_atomic_helper_check(struct drm_device *dev, | |||
| 445 | 467 | ||
| 446 | ret = funcs->atomic_check(plane, plane_state); | 468 | ret = funcs->atomic_check(plane, plane_state); |
| 447 | if (ret) { | 469 | if (ret) { |
| 448 | DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n", | 470 | DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n", |
| 449 | plane->base.id); | 471 | plane->base.id); |
| 450 | return ret; | 472 | return ret; |
| 451 | } | 473 | } |
| @@ -465,16 +487,49 @@ int drm_atomic_helper_check(struct drm_device *dev, | |||
| 465 | 487 | ||
| 466 | ret = funcs->atomic_check(crtc, state->crtc_states[i]); | 488 | ret = funcs->atomic_check(crtc, state->crtc_states[i]); |
| 467 | if (ret) { | 489 | if (ret) { |
| 468 | DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n", | 490 | DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n", |
| 469 | crtc->base.id); | 491 | crtc->base.id); |
| 470 | return ret; | 492 | return ret; |
| 471 | } | 493 | } |
| 472 | } | 494 | } |
| 473 | 495 | ||
| 496 | return ret; | ||
| 497 | } | ||
| 498 | EXPORT_SYMBOL(drm_atomic_helper_check_planes); | ||
| 499 | |||
| 500 | /** | ||
| 501 | * drm_atomic_helper_check - validate state object | ||
| 502 | * @dev: DRM device | ||
| 503 | * @state: the driver state object | ||
| 504 | * | ||
| 505 | * Check the state object to see if the requested state is physically possible. | ||
| 506 | * Only crtcs and planes have check callbacks, so for any additional (global) | ||
| 507 | * checking that a driver needs it can simply wrap that around this function. | ||
| 508 | * Drivers without such needs can directly use this as their ->atomic_check() | ||
| 509 | * callback. | ||
| 510 | * | ||
| 511 | * This just wraps the two parts of the state checking for planes and modeset | ||
| 512 | * state in the default order: First it calls drm_atomic_helper_check_modeset() | ||
| 513 | * and then drm_atomic_helper_check_planes(). The assumption is that the | ||
| 514 | * ->atomic_check functions depend upon an updated adjusted_mode.clock to | ||
| 515 | * e.g. properly compute watermarks. | ||
| 516 | * | ||
| 517 | * RETURNS | ||
| 518 | * Zero for success or -errno | ||
| 519 | */ | ||
| 520 | int drm_atomic_helper_check(struct drm_device *dev, | ||
| 521 | struct drm_atomic_state *state) | ||
| 522 | { | ||
| 523 | int ret; | ||
| 524 | |||
| 474 | ret = drm_atomic_helper_check_modeset(dev, state); | 525 | ret = drm_atomic_helper_check_modeset(dev, state); |
| 475 | if (ret) | 526 | if (ret) |
| 476 | return ret; | 527 | return ret; |
| 477 | 528 | ||
| 529 | ret = drm_atomic_helper_check_planes(dev, state); | ||
| 530 | if (ret) | ||
| 531 | return ret; | ||
| 532 | |||
| 478 | return ret; | 533 | return ret; |
| 479 | } | 534 | } |
| 480 | EXPORT_SYMBOL(drm_atomic_helper_check); | 535 | EXPORT_SYMBOL(drm_atomic_helper_check); |
| @@ -1222,7 +1277,7 @@ retry: | |||
| 1222 | goto fail; | 1277 | goto fail; |
| 1223 | } | 1278 | } |
| 1224 | 1279 | ||
| 1225 | ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); | 1280 | ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); |
| 1226 | if (ret != 0) | 1281 | if (ret != 0) |
| 1227 | goto fail; | 1282 | goto fail; |
| 1228 | drm_atomic_set_fb_for_plane(plane_state, fb); | 1283 | drm_atomic_set_fb_for_plane(plane_state, fb); |
| @@ -1301,7 +1356,7 @@ retry: | |||
| 1301 | goto fail; | 1356 | goto fail; |
| 1302 | } | 1357 | } |
| 1303 | 1358 | ||
| 1304 | ret = drm_atomic_set_crtc_for_plane(state, plane, NULL); | 1359 | ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); |
| 1305 | if (ret != 0) | 1360 | if (ret != 0) |
| 1306 | goto fail; | 1361 | goto fail; |
| 1307 | drm_atomic_set_fb_for_plane(plane_state, NULL); | 1362 | drm_atomic_set_fb_for_plane(plane_state, NULL); |
| @@ -1464,7 +1519,7 @@ retry: | |||
| 1464 | 1519 | ||
| 1465 | crtc_state->enable = false; | 1520 | crtc_state->enable = false; |
| 1466 | 1521 | ||
| 1467 | ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL); | 1522 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); |
| 1468 | if (ret != 0) | 1523 | if (ret != 0) |
| 1469 | goto fail; | 1524 | goto fail; |
| 1470 | 1525 | ||
| @@ -1479,7 +1534,7 @@ retry: | |||
| 1479 | crtc_state->enable = true; | 1534 | crtc_state->enable = true; |
| 1480 | drm_mode_copy(&crtc_state->mode, set->mode); | 1535 | drm_mode_copy(&crtc_state->mode, set->mode); |
| 1481 | 1536 | ||
| 1482 | ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc); | 1537 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); |
| 1483 | if (ret != 0) | 1538 | if (ret != 0) |
| 1484 | goto fail; | 1539 | goto fail; |
| 1485 | drm_atomic_set_fb_for_plane(primary_state, set->fb); | 1540 | drm_atomic_set_fb_for_plane(primary_state, set->fb); |
| @@ -1558,8 +1613,8 @@ retry: | |||
| 1558 | goto fail; | 1613 | goto fail; |
| 1559 | } | 1614 | } |
| 1560 | 1615 | ||
| 1561 | ret = crtc->funcs->atomic_set_property(crtc, crtc_state, | 1616 | ret = drm_atomic_crtc_set_property(crtc, crtc_state, |
| 1562 | property, val); | 1617 | property, val); |
| 1563 | if (ret) | 1618 | if (ret) |
| 1564 | goto fail; | 1619 | goto fail; |
| 1565 | 1620 | ||
| @@ -1617,8 +1672,8 @@ retry: | |||
| 1617 | goto fail; | 1672 | goto fail; |
| 1618 | } | 1673 | } |
| 1619 | 1674 | ||
| 1620 | ret = plane->funcs->atomic_set_property(plane, plane_state, | 1675 | ret = drm_atomic_plane_set_property(plane, plane_state, |
| 1621 | property, val); | 1676 | property, val); |
| 1622 | if (ret) | 1677 | if (ret) |
| 1623 | goto fail; | 1678 | goto fail; |
| 1624 | 1679 | ||
| @@ -1676,8 +1731,8 @@ retry: | |||
| 1676 | goto fail; | 1731 | goto fail; |
| 1677 | } | 1732 | } |
| 1678 | 1733 | ||
| 1679 | ret = connector->funcs->atomic_set_property(connector, connector_state, | 1734 | ret = drm_atomic_connector_set_property(connector, connector_state, |
| 1680 | property, val); | 1735 | property, val); |
| 1681 | if (ret) | 1736 | if (ret) |
| 1682 | goto fail; | 1737 | goto fail; |
| 1683 | 1738 | ||
| @@ -1751,7 +1806,7 @@ retry: | |||
| 1751 | goto fail; | 1806 | goto fail; |
| 1752 | } | 1807 | } |
| 1753 | 1808 | ||
| 1754 | ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); | 1809 | ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); |
| 1755 | if (ret != 0) | 1810 | if (ret != 0) |
| 1756 | goto fail; | 1811 | goto fail; |
| 1757 | drm_atomic_set_fb_for_plane(plane_state, fb); | 1812 | drm_atomic_set_fb_for_plane(plane_state, fb); |
| @@ -1814,6 +1869,9 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) | |||
| 1814 | { | 1869 | { |
| 1815 | kfree(crtc->state); | 1870 | kfree(crtc->state); |
| 1816 | crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); | 1871 | crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); |
| 1872 | |||
| 1873 | if (crtc->state) | ||
| 1874 | crtc->state->crtc = crtc; | ||
| 1817 | } | 1875 | } |
| 1818 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); | 1876 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); |
| 1819 | 1877 | ||
| @@ -1873,6 +1931,9 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane) | |||
| 1873 | 1931 | ||
| 1874 | kfree(plane->state); | 1932 | kfree(plane->state); |
| 1875 | plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); | 1933 | plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); |
| 1934 | |||
| 1935 | if (plane->state) | ||
| 1936 | plane->state->plane = plane; | ||
| 1876 | } | 1937 | } |
| 1877 | EXPORT_SYMBOL(drm_atomic_helper_plane_reset); | 1938 | EXPORT_SYMBOL(drm_atomic_helper_plane_reset); |
| 1878 | 1939 | ||
| @@ -1930,6 +1991,9 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) | |||
| 1930 | { | 1991 | { |
| 1931 | kfree(connector->state); | 1992 | kfree(connector->state); |
| 1932 | connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL); | 1993 | connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL); |
| 1994 | |||
| 1995 | if (connector->state) | ||
| 1996 | connector->state->connector = connector; | ||
| 1933 | } | 1997 | } |
| 1934 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); | 1998 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); |
| 1935 | 1999 | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2892d746a1e9..7e4acad3f6f9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <drm/drm_edid.h> | 38 | #include <drm/drm_edid.h> |
| 39 | #include <drm/drm_fourcc.h> | 39 | #include <drm/drm_fourcc.h> |
| 40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
| 41 | #include <drm/drm_atomic.h> | ||
| 41 | 42 | ||
| 42 | #include "drm_crtc_internal.h" | 43 | #include "drm_crtc_internal.h" |
| 43 | #include "drm_internal.h" | 44 | #include "drm_internal.h" |
| @@ -830,6 +831,7 @@ int drm_connector_init(struct drm_device *dev, | |||
| 830 | const struct drm_connector_funcs *funcs, | 831 | const struct drm_connector_funcs *funcs, |
| 831 | int connector_type) | 832 | int connector_type) |
| 832 | { | 833 | { |
| 834 | struct drm_mode_config *config = &dev->mode_config; | ||
| 833 | int ret; | 835 | int ret; |
| 834 | struct ida *connector_ida = | 836 | struct ida *connector_ida = |
| 835 | &drm_connector_enum_list[connector_type].ida; | 837 | &drm_connector_enum_list[connector_type].ida; |
| @@ -868,16 +870,20 @@ int drm_connector_init(struct drm_device *dev, | |||
| 868 | 870 | ||
| 869 | /* We should add connectors at the end to avoid upsetting the connector | 871 | /* We should add connectors at the end to avoid upsetting the connector |
| 870 | * index too much. */ | 872 | * index too much. */ |
| 871 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | 873 | list_add_tail(&connector->head, &config->connector_list); |
| 872 | dev->mode_config.num_connector++; | 874 | config->num_connector++; |
| 873 | 875 | ||
| 874 | if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) | 876 | if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) |
| 875 | drm_object_attach_property(&connector->base, | 877 | drm_object_attach_property(&connector->base, |
| 876 | dev->mode_config.edid_property, | 878 | config->edid_property, |
| 877 | 0); | 879 | 0); |
| 878 | 880 | ||
| 879 | drm_object_attach_property(&connector->base, | 881 | drm_object_attach_property(&connector->base, |
| 880 | dev->mode_config.dpms_property, 0); | 882 | config->dpms_property, 0); |
| 883 | |||
| 884 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
| 885 | drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); | ||
| 886 | } | ||
| 881 | 887 | ||
| 882 | connector->debugfs_entry = NULL; | 888 | connector->debugfs_entry = NULL; |
| 883 | 889 | ||
| @@ -1168,6 +1174,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
| 1168 | const uint32_t *formats, uint32_t format_count, | 1174 | const uint32_t *formats, uint32_t format_count, |
| 1169 | enum drm_plane_type type) | 1175 | enum drm_plane_type type) |
| 1170 | { | 1176 | { |
| 1177 | struct drm_mode_config *config = &dev->mode_config; | ||
| 1171 | int ret; | 1178 | int ret; |
| 1172 | 1179 | ||
| 1173 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | 1180 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); |
| @@ -1192,15 +1199,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
| 1192 | plane->possible_crtcs = possible_crtcs; | 1199 | plane->possible_crtcs = possible_crtcs; |
| 1193 | plane->type = type; | 1200 | plane->type = type; |
| 1194 | 1201 | ||
| 1195 | list_add_tail(&plane->head, &dev->mode_config.plane_list); | 1202 | list_add_tail(&plane->head, &config->plane_list); |
| 1196 | dev->mode_config.num_total_plane++; | 1203 | config->num_total_plane++; |
| 1197 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | 1204 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
| 1198 | dev->mode_config.num_overlay_plane++; | 1205 | config->num_overlay_plane++; |
| 1199 | 1206 | ||
| 1200 | drm_object_attach_property(&plane->base, | 1207 | drm_object_attach_property(&plane->base, |
| 1201 | dev->mode_config.plane_type_property, | 1208 | config->plane_type_property, |
| 1202 | plane->type); | 1209 | plane->type); |
| 1203 | 1210 | ||
| 1211 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
| 1212 | drm_object_attach_property(&plane->base, config->prop_fb_id, 0); | ||
| 1213 | drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); | ||
| 1214 | drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); | ||
| 1215 | drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); | ||
| 1216 | drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); | ||
| 1217 | drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); | ||
| 1218 | drm_object_attach_property(&plane->base, config->prop_src_x, 0); | ||
| 1219 | drm_object_attach_property(&plane->base, config->prop_src_y, 0); | ||
| 1220 | drm_object_attach_property(&plane->base, config->prop_src_w, 0); | ||
| 1221 | drm_object_attach_property(&plane->base, config->prop_src_h, 0); | ||
| 1222 | } | ||
| 1223 | |||
| 1204 | return 0; | 1224 | return 0; |
| 1205 | } | 1225 | } |
| 1206 | EXPORT_SYMBOL(drm_universal_plane_init); | 1226 | EXPORT_SYMBOL(drm_universal_plane_init); |
| @@ -1322,50 +1342,109 @@ void drm_plane_force_disable(struct drm_plane *plane) | |||
| 1322 | } | 1342 | } |
| 1323 | EXPORT_SYMBOL(drm_plane_force_disable); | 1343 | EXPORT_SYMBOL(drm_plane_force_disable); |
| 1324 | 1344 | ||
| 1325 | static int drm_mode_create_standard_connector_properties(struct drm_device *dev) | 1345 | static int drm_mode_create_standard_properties(struct drm_device *dev) |
| 1326 | { | 1346 | { |
| 1327 | struct drm_property *edid; | 1347 | struct drm_property *prop; |
| 1328 | struct drm_property *dpms; | ||
| 1329 | struct drm_property *dev_path; | ||
| 1330 | 1348 | ||
| 1331 | /* | 1349 | /* |
| 1332 | * Standard properties (apply to all connectors) | 1350 | * Standard properties (apply to all connectors) |
| 1333 | */ | 1351 | */ |
| 1334 | edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | | 1352 | prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | |
| 1335 | DRM_MODE_PROP_IMMUTABLE, | 1353 | DRM_MODE_PROP_IMMUTABLE, |
| 1336 | "EDID", 0); | 1354 | "EDID", 0); |
| 1337 | dev->mode_config.edid_property = edid; | 1355 | if (!prop) |
| 1356 | return -ENOMEM; | ||
| 1357 | dev->mode_config.edid_property = prop; | ||
| 1338 | 1358 | ||
| 1339 | dpms = drm_property_create_enum(dev, 0, | 1359 | prop = drm_property_create_enum(dev, 0, |
| 1340 | "DPMS", drm_dpms_enum_list, | 1360 | "DPMS", drm_dpms_enum_list, |
| 1341 | ARRAY_SIZE(drm_dpms_enum_list)); | 1361 | ARRAY_SIZE(drm_dpms_enum_list)); |
| 1342 | dev->mode_config.dpms_property = dpms; | 1362 | if (!prop) |
| 1343 | 1363 | return -ENOMEM; | |
| 1344 | dev_path = drm_property_create(dev, | 1364 | dev->mode_config.dpms_property = prop; |
| 1345 | DRM_MODE_PROP_BLOB | | ||
| 1346 | DRM_MODE_PROP_IMMUTABLE, | ||
| 1347 | "PATH", 0); | ||
| 1348 | dev->mode_config.path_property = dev_path; | ||
| 1349 | |||
| 1350 | dev->mode_config.tile_property = drm_property_create(dev, | ||
| 1351 | DRM_MODE_PROP_BLOB | | ||
| 1352 | DRM_MODE_PROP_IMMUTABLE, | ||
| 1353 | "TILE", 0); | ||
| 1354 | 1365 | ||
| 1355 | return 0; | 1366 | prop = drm_property_create(dev, |
| 1356 | } | 1367 | DRM_MODE_PROP_BLOB | |
| 1368 | DRM_MODE_PROP_IMMUTABLE, | ||
| 1369 | "PATH", 0); | ||
| 1370 | if (!prop) | ||
| 1371 | return -ENOMEM; | ||
| 1372 | dev->mode_config.path_property = prop; | ||
| 1357 | 1373 | ||
| 1358 | static int drm_mode_create_standard_plane_properties(struct drm_device *dev) | 1374 | prop = drm_property_create(dev, |
| 1359 | { | 1375 | DRM_MODE_PROP_BLOB | |
| 1360 | struct drm_property *type; | 1376 | DRM_MODE_PROP_IMMUTABLE, |
| 1377 | "TILE", 0); | ||
| 1378 | if (!prop) | ||
| 1379 | return -ENOMEM; | ||
| 1380 | dev->mode_config.tile_property = prop; | ||
| 1361 | 1381 | ||
| 1362 | /* | 1382 | prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, |
| 1363 | * Standard properties (apply to all planes) | ||
| 1364 | */ | ||
| 1365 | type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, | ||
| 1366 | "type", drm_plane_type_enum_list, | 1383 | "type", drm_plane_type_enum_list, |
| 1367 | ARRAY_SIZE(drm_plane_type_enum_list)); | 1384 | ARRAY_SIZE(drm_plane_type_enum_list)); |
| 1368 | dev->mode_config.plane_type_property = type; | 1385 | if (!prop) |
| 1386 | return -ENOMEM; | ||
| 1387 | dev->mode_config.plane_type_property = prop; | ||
| 1388 | |||
| 1389 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1390 | "SRC_X", 0, UINT_MAX); | ||
| 1391 | if (!prop) | ||
| 1392 | return -ENOMEM; | ||
| 1393 | dev->mode_config.prop_src_x = prop; | ||
| 1394 | |||
| 1395 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1396 | "SRC_Y", 0, UINT_MAX); | ||
| 1397 | if (!prop) | ||
| 1398 | return -ENOMEM; | ||
| 1399 | dev->mode_config.prop_src_y = prop; | ||
| 1400 | |||
| 1401 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1402 | "SRC_W", 0, UINT_MAX); | ||
| 1403 | if (!prop) | ||
| 1404 | return -ENOMEM; | ||
| 1405 | dev->mode_config.prop_src_w = prop; | ||
| 1406 | |||
| 1407 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1408 | "SRC_H", 0, UINT_MAX); | ||
| 1409 | if (!prop) | ||
| 1410 | return -ENOMEM; | ||
| 1411 | dev->mode_config.prop_src_h = prop; | ||
| 1412 | |||
| 1413 | prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1414 | "CRTC_X", INT_MIN, INT_MAX); | ||
| 1415 | if (!prop) | ||
| 1416 | return -ENOMEM; | ||
| 1417 | dev->mode_config.prop_crtc_x = prop; | ||
| 1418 | |||
| 1419 | prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1420 | "CRTC_Y", INT_MIN, INT_MAX); | ||
| 1421 | if (!prop) | ||
| 1422 | return -ENOMEM; | ||
| 1423 | dev->mode_config.prop_crtc_y = prop; | ||
| 1424 | |||
| 1425 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1426 | "CRTC_W", 0, INT_MAX); | ||
| 1427 | if (!prop) | ||
| 1428 | return -ENOMEM; | ||
| 1429 | dev->mode_config.prop_crtc_w = prop; | ||
| 1430 | |||
| 1431 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1432 | "CRTC_H", 0, INT_MAX); | ||
| 1433 | if (!prop) | ||
| 1434 | return -ENOMEM; | ||
| 1435 | dev->mode_config.prop_crtc_h = prop; | ||
| 1436 | |||
| 1437 | prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1438 | "FB_ID", DRM_MODE_OBJECT_FB); | ||
| 1439 | if (!prop) | ||
| 1440 | return -ENOMEM; | ||
| 1441 | dev->mode_config.prop_fb_id = prop; | ||
| 1442 | |||
| 1443 | prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, | ||
| 1444 | "CRTC_ID", DRM_MODE_OBJECT_CRTC); | ||
| 1445 | if (!prop) | ||
| 1446 | return -ENOMEM; | ||
| 1447 | dev->mode_config.prop_crtc_id = prop; | ||
| 1369 | 1448 | ||
| 1370 | return 0; | 1449 | return 0; |
| 1371 | } | 1450 | } |
| @@ -1991,6 +2070,44 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne | |||
| 1991 | return connector->encoder; | 2070 | return connector->encoder; |
| 1992 | } | 2071 | } |
| 1993 | 2072 | ||
| 2073 | /* helper for getconnector and getproperties ioctls */ | ||
| 2074 | static int get_properties(struct drm_mode_object *obj, bool atomic, | ||
| 2075 | uint32_t __user *prop_ptr, uint64_t __user *prop_values, | ||
| 2076 | uint32_t *arg_count_props) | ||
| 2077 | { | ||
| 2078 | int props_count; | ||
| 2079 | int i, ret, copied; | ||
| 2080 | |||
| 2081 | props_count = obj->properties->count; | ||
| 2082 | if (!atomic) | ||
| 2083 | props_count -= obj->properties->atomic_count; | ||
| 2084 | |||
| 2085 | if ((*arg_count_props >= props_count) && props_count) { | ||
| 2086 | for (i = 0, copied = 0; copied < props_count; i++) { | ||
| 2087 | struct drm_property *prop = obj->properties->properties[i]; | ||
| 2088 | uint64_t val; | ||
| 2089 | |||
| 2090 | if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) | ||
| 2091 | continue; | ||
| 2092 | |||
| 2093 | ret = drm_object_property_get_value(obj, prop, &val); | ||
| 2094 | if (ret) | ||
| 2095 | return ret; | ||
| 2096 | |||
| 2097 | if (put_user(prop->base.id, prop_ptr + copied)) | ||
| 2098 | return -EFAULT; | ||
| 2099 | |||
| 2100 | if (put_user(val, prop_values + copied)) | ||
| 2101 | return -EFAULT; | ||
| 2102 | |||
| 2103 | copied++; | ||
| 2104 | } | ||
| 2105 | } | ||
| 2106 | *arg_count_props = props_count; | ||
| 2107 | |||
| 2108 | return 0; | ||
| 2109 | } | ||
| 2110 | |||
| 1994 | /** | 2111 | /** |
| 1995 | * drm_mode_getconnector - get connector configuration | 2112 | * drm_mode_getconnector - get connector configuration |
| 1996 | * @dev: drm device for the ioctl | 2113 | * @dev: drm device for the ioctl |
| @@ -2012,15 +2129,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2012 | struct drm_encoder *encoder; | 2129 | struct drm_encoder *encoder; |
| 2013 | struct drm_display_mode *mode; | 2130 | struct drm_display_mode *mode; |
| 2014 | int mode_count = 0; | 2131 | int mode_count = 0; |
| 2015 | int props_count = 0; | ||
| 2016 | int encoders_count = 0; | 2132 | int encoders_count = 0; |
| 2017 | int ret = 0; | 2133 | int ret = 0; |
| 2018 | int copied = 0; | 2134 | int copied = 0; |
| 2019 | int i; | 2135 | int i; |
| 2020 | struct drm_mode_modeinfo u_mode; | 2136 | struct drm_mode_modeinfo u_mode; |
| 2021 | struct drm_mode_modeinfo __user *mode_ptr; | 2137 | struct drm_mode_modeinfo __user *mode_ptr; |
| 2022 | uint32_t __user *prop_ptr; | ||
| 2023 | uint64_t __user *prop_values; | ||
| 2024 | uint32_t __user *encoder_ptr; | 2138 | uint32_t __user *encoder_ptr; |
| 2025 | 2139 | ||
| 2026 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2140 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| @@ -2031,6 +2145,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2031 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); | 2145 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); |
| 2032 | 2146 | ||
| 2033 | mutex_lock(&dev->mode_config.mutex); | 2147 | mutex_lock(&dev->mode_config.mutex); |
| 2148 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
| 2034 | 2149 | ||
| 2035 | connector = drm_connector_find(dev, out_resp->connector_id); | 2150 | connector = drm_connector_find(dev, out_resp->connector_id); |
| 2036 | if (!connector) { | 2151 | if (!connector) { |
| @@ -2038,8 +2153,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2038 | goto out; | 2153 | goto out; |
| 2039 | } | 2154 | } |
| 2040 | 2155 | ||
| 2041 | props_count = connector->properties.count; | ||
| 2042 | |||
| 2043 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) | 2156 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) |
| 2044 | if (connector->encoder_ids[i] != 0) | 2157 | if (connector->encoder_ids[i] != 0) |
| 2045 | encoders_count++; | 2158 | encoders_count++; |
| @@ -2062,14 +2175,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2062 | out_resp->mm_height = connector->display_info.height_mm; | 2175 | out_resp->mm_height = connector->display_info.height_mm; |
| 2063 | out_resp->subpixel = connector->display_info.subpixel_order; | 2176 | out_resp->subpixel = connector->display_info.subpixel_order; |
| 2064 | out_resp->connection = connector->status; | 2177 | out_resp->connection = connector->status; |
| 2065 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
| 2066 | |||
| 2067 | encoder = drm_connector_get_encoder(connector); | 2178 | encoder = drm_connector_get_encoder(connector); |
| 2068 | if (encoder) | 2179 | if (encoder) |
| 2069 | out_resp->encoder_id = encoder->base.id; | 2180 | out_resp->encoder_id = encoder->base.id; |
| 2070 | else | 2181 | else |
| 2071 | out_resp->encoder_id = 0; | 2182 | out_resp->encoder_id = 0; |
| 2072 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
| 2073 | 2183 | ||
| 2074 | /* | 2184 | /* |
| 2075 | * This ioctl is called twice, once to determine how much space is | 2185 | * This ioctl is called twice, once to determine how much space is |
| @@ -2093,26 +2203,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2093 | } | 2203 | } |
| 2094 | out_resp->count_modes = mode_count; | 2204 | out_resp->count_modes = mode_count; |
| 2095 | 2205 | ||
| 2096 | if ((out_resp->count_props >= props_count) && props_count) { | 2206 | ret = get_properties(&connector->base, file_priv->atomic, |
| 2097 | copied = 0; | 2207 | (uint32_t __user *)(unsigned long)(out_resp->props_ptr), |
| 2098 | prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); | 2208 | (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), |
| 2099 | prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); | 2209 | &out_resp->count_props); |
| 2100 | for (i = 0; i < connector->properties.count; i++) { | 2210 | if (ret) |
| 2101 | if (put_user(connector->properties.ids[i], | 2211 | goto out; |
| 2102 | prop_ptr + copied)) { | ||
| 2103 | ret = -EFAULT; | ||
| 2104 | goto out; | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | if (put_user(connector->properties.values[i], | ||
| 2108 | prop_values + copied)) { | ||
| 2109 | ret = -EFAULT; | ||
| 2110 | goto out; | ||
| 2111 | } | ||
| 2112 | copied++; | ||
| 2113 | } | ||
| 2114 | } | ||
| 2115 | out_resp->count_props = props_count; | ||
| 2116 | 2212 | ||
| 2117 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { | 2213 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { |
| 2118 | copied = 0; | 2214 | copied = 0; |
| @@ -2131,6 +2227,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2131 | out_resp->count_encoders = encoders_count; | 2227 | out_resp->count_encoders = encoders_count; |
| 2132 | 2228 | ||
| 2133 | out: | 2229 | out: |
| 2230 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
| 2134 | mutex_unlock(&dev->mode_config.mutex); | 2231 | mutex_unlock(&dev->mode_config.mutex); |
| 2135 | 2232 | ||
| 2136 | return ret; | 2233 | return ret; |
| @@ -3823,9 +3920,11 @@ void drm_object_attach_property(struct drm_mode_object *obj, | |||
| 3823 | return; | 3920 | return; |
| 3824 | } | 3921 | } |
| 3825 | 3922 | ||
| 3826 | obj->properties->ids[count] = property->base.id; | 3923 | obj->properties->properties[count] = property; |
| 3827 | obj->properties->values[count] = init_val; | 3924 | obj->properties->values[count] = init_val; |
| 3828 | obj->properties->count++; | 3925 | obj->properties->count++; |
| 3926 | if (property->flags & DRM_MODE_PROP_ATOMIC) | ||
| 3927 | obj->properties->atomic_count++; | ||
| 3829 | } | 3928 | } |
| 3830 | EXPORT_SYMBOL(drm_object_attach_property); | 3929 | EXPORT_SYMBOL(drm_object_attach_property); |
| 3831 | 3930 | ||
| @@ -3848,7 +3947,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj, | |||
| 3848 | int i; | 3947 | int i; |
| 3849 | 3948 | ||
| 3850 | for (i = 0; i < obj->properties->count; i++) { | 3949 | for (i = 0; i < obj->properties->count; i++) { |
| 3851 | if (obj->properties->ids[i] == property->base.id) { | 3950 | if (obj->properties->properties[i] == property) { |
| 3852 | obj->properties->values[i] = val; | 3951 | obj->properties->values[i] = val; |
| 3853 | return 0; | 3952 | return 0; |
| 3854 | } | 3953 | } |
| @@ -3877,8 +3976,16 @@ int drm_object_property_get_value(struct drm_mode_object *obj, | |||
| 3877 | { | 3976 | { |
| 3878 | int i; | 3977 | int i; |
| 3879 | 3978 | ||
| 3979 | /* read-only properties bypass atomic mechanism and still store | ||
| 3980 | * their value in obj->properties->values[].. mostly to avoid | ||
| 3981 | * having to deal w/ EDID and similar props in atomic paths: | ||
| 3982 | */ | ||
| 3983 | if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && | ||
| 3984 | !(property->flags & DRM_MODE_PROP_IMMUTABLE)) | ||
| 3985 | return drm_atomic_get_property(obj, property, val); | ||
| 3986 | |||
| 3880 | for (i = 0; i < obj->properties->count; i++) { | 3987 | for (i = 0; i < obj->properties->count; i++) { |
| 3881 | if (obj->properties->ids[i] == property->base.id) { | 3988 | if (obj->properties->properties[i] == property) { |
| 3882 | *val = obj->properties->values[i]; | 3989 | *val = obj->properties->values[i]; |
| 3883 | return 0; | 3990 | return 0; |
| 3884 | } | 3991 | } |
| @@ -4194,14 +4301,24 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, | |||
| 4194 | } | 4301 | } |
| 4195 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); | 4302 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); |
| 4196 | 4303 | ||
| 4197 | static bool drm_property_change_is_valid(struct drm_property *property, | 4304 | /* Some properties could refer to dynamic refcnt'd objects, or things that |
| 4198 | uint64_t value) | 4305 | * need special locking to handle lifetime issues (ie. to ensure the prop |
| 4306 | * value doesn't become invalid part way through the property update due to | ||
| 4307 | * race). The value returned by reference via 'obj' should be passed back | ||
| 4308 | * to drm_property_change_valid_put() after the property is set (and the | ||
| 4309 | * object to which the property is attached has a chance to take it's own | ||
| 4310 | * reference). | ||
| 4311 | */ | ||
| 4312 | bool drm_property_change_valid_get(struct drm_property *property, | ||
| 4313 | uint64_t value, struct drm_mode_object **ref) | ||
| 4199 | { | 4314 | { |
| 4200 | int i; | 4315 | int i; |
| 4201 | 4316 | ||
| 4202 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | 4317 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) |
| 4203 | return false; | 4318 | return false; |
| 4204 | 4319 | ||
| 4320 | *ref = NULL; | ||
| 4321 | |||
| 4205 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | 4322 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { |
| 4206 | if (value < property->values[0] || value > property->values[1]) | 4323 | if (value < property->values[0] || value > property->values[1]) |
| 4207 | return false; | 4324 | return false; |
| @@ -4223,20 +4340,29 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
| 4223 | /* Only the driver knows */ | 4340 | /* Only the driver knows */ |
| 4224 | return true; | 4341 | return true; |
| 4225 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | 4342 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { |
| 4226 | struct drm_mode_object *obj; | ||
| 4227 | |||
| 4228 | /* a zero value for an object property translates to null: */ | 4343 | /* a zero value for an object property translates to null: */ |
| 4229 | if (value == 0) | 4344 | if (value == 0) |
| 4230 | return true; | 4345 | return true; |
| 4231 | /* | 4346 | |
| 4232 | * NOTE: use _object_find() directly to bypass restriction on | 4347 | /* handle refcnt'd objects specially: */ |
| 4233 | * looking up refcnt'd objects (ie. fb's). For a refcnt'd | 4348 | if (property->values[0] == DRM_MODE_OBJECT_FB) { |
| 4234 | * object this could race against object finalization, so it | 4349 | struct drm_framebuffer *fb; |
| 4235 | * simply tells us that the object *was* valid. Which is good | 4350 | fb = drm_framebuffer_lookup(property->dev, value); |
| 4236 | * enough. | 4351 | if (fb) { |
| 4237 | */ | 4352 | *ref = &fb->base; |
| 4238 | obj = _object_find(property->dev, value, property->values[0]); | 4353 | return true; |
| 4239 | return obj != NULL; | 4354 | } else { |
| 4355 | return false; | ||
| 4356 | } | ||
| 4357 | } else { | ||
| 4358 | return _object_find(property->dev, value, property->values[0]) != NULL; | ||
| 4359 | } | ||
| 4360 | } else { | ||
| 4361 | int i; | ||
| 4362 | for (i = 0; i < property->num_values; i++) | ||
| 4363 | if (property->values[i] == value) | ||
| 4364 | return true; | ||
| 4365 | return false; | ||
| 4240 | } | 4366 | } |
| 4241 | 4367 | ||
| 4242 | for (i = 0; i < property->num_values; i++) | 4368 | for (i = 0; i < property->num_values; i++) |
| @@ -4245,6 +4371,18 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
| 4245 | return false; | 4371 | return false; |
| 4246 | } | 4372 | } |
| 4247 | 4373 | ||
| 4374 | void drm_property_change_valid_put(struct drm_property *property, | ||
| 4375 | struct drm_mode_object *ref) | ||
| 4376 | { | ||
| 4377 | if (!ref) | ||
| 4378 | return; | ||
| 4379 | |||
| 4380 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
| 4381 | if (property->values[0] == DRM_MODE_OBJECT_FB) | ||
| 4382 | drm_framebuffer_unreference(obj_to_fb(ref)); | ||
| 4383 | } | ||
| 4384 | } | ||
| 4385 | |||
| 4248 | /** | 4386 | /** |
| 4249 | * drm_mode_connector_property_set_ioctl - set the current value of a connector property | 4387 | * drm_mode_connector_property_set_ioctl - set the current value of a connector property |
| 4250 | * @dev: DRM device | 4388 | * @dev: DRM device |
| @@ -4360,11 +4498,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
| 4360 | struct drm_mode_obj_get_properties *arg = data; | 4498 | struct drm_mode_obj_get_properties *arg = data; |
| 4361 | struct drm_mode_object *obj; | 4499 | struct drm_mode_object *obj; |
| 4362 | int ret = 0; | 4500 | int ret = 0; |
| 4363 | int i; | ||
| 4364 | int copied = 0; | ||
| 4365 | int props_count = 0; | ||
| 4366 | uint32_t __user *props_ptr; | ||
| 4367 | uint64_t __user *prop_values_ptr; | ||
| 4368 | 4501 | ||
| 4369 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 4502 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 4370 | return -EINVAL; | 4503 | return -EINVAL; |
| @@ -4381,30 +4514,11 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
| 4381 | goto out; | 4514 | goto out; |
| 4382 | } | 4515 | } |
| 4383 | 4516 | ||
| 4384 | props_count = obj->properties->count; | 4517 | ret = get_properties(obj, file_priv->atomic, |
| 4518 | (uint32_t __user *)(unsigned long)(arg->props_ptr), | ||
| 4519 | (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), | ||
| 4520 | &arg->count_props); | ||
| 4385 | 4521 | ||
| 4386 | /* This ioctl is called twice, once to determine how much space is | ||
| 4387 | * needed, and the 2nd time to fill it. */ | ||
| 4388 | if ((arg->count_props >= props_count) && props_count) { | ||
| 4389 | copied = 0; | ||
| 4390 | props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); | ||
| 4391 | prop_values_ptr = (uint64_t __user *)(unsigned long) | ||
| 4392 | (arg->prop_values_ptr); | ||
| 4393 | for (i = 0; i < props_count; i++) { | ||
| 4394 | if (put_user(obj->properties->ids[i], | ||
| 4395 | props_ptr + copied)) { | ||
| 4396 | ret = -EFAULT; | ||
| 4397 | goto out; | ||
| 4398 | } | ||
| 4399 | if (put_user(obj->properties->values[i], | ||
| 4400 | prop_values_ptr + copied)) { | ||
| 4401 | ret = -EFAULT; | ||
| 4402 | goto out; | ||
| 4403 | } | ||
| 4404 | copied++; | ||
| 4405 | } | ||
| 4406 | } | ||
| 4407 | arg->count_props = props_count; | ||
| 4408 | out: | 4522 | out: |
| 4409 | drm_modeset_unlock_all(dev); | 4523 | drm_modeset_unlock_all(dev); |
| 4410 | return ret; | 4524 | return ret; |
| @@ -4433,8 +4547,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
| 4433 | struct drm_mode_object *arg_obj; | 4547 | struct drm_mode_object *arg_obj; |
| 4434 | struct drm_mode_object *prop_obj; | 4548 | struct drm_mode_object *prop_obj; |
| 4435 | struct drm_property *property; | 4549 | struct drm_property *property; |
| 4436 | int ret = -EINVAL; | 4550 | int i, ret = -EINVAL; |
| 4437 | int i; | 4551 | struct drm_mode_object *ref; |
| 4438 | 4552 | ||
| 4439 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 4553 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 4440 | return -EINVAL; | 4554 | return -EINVAL; |
| @@ -4450,7 +4564,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
| 4450 | goto out; | 4564 | goto out; |
| 4451 | 4565 | ||
| 4452 | for (i = 0; i < arg_obj->properties->count; i++) | 4566 | for (i = 0; i < arg_obj->properties->count; i++) |
| 4453 | if (arg_obj->properties->ids[i] == arg->prop_id) | 4567 | if (arg_obj->properties->properties[i]->base.id == arg->prop_id) |
| 4454 | break; | 4568 | break; |
| 4455 | 4569 | ||
| 4456 | if (i == arg_obj->properties->count) | 4570 | if (i == arg_obj->properties->count) |
| @@ -4464,7 +4578,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
| 4464 | } | 4578 | } |
| 4465 | property = obj_to_property(prop_obj); | 4579 | property = obj_to_property(prop_obj); |
| 4466 | 4580 | ||
| 4467 | if (!drm_property_change_is_valid(property, arg->value)) | 4581 | if (!drm_property_change_valid_get(property, arg->value, &ref)) |
| 4468 | goto out; | 4582 | goto out; |
| 4469 | 4583 | ||
| 4470 | switch (arg_obj->type) { | 4584 | switch (arg_obj->type) { |
| @@ -4481,6 +4595,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
| 4481 | break; | 4595 | break; |
| 4482 | } | 4596 | } |
| 4483 | 4597 | ||
| 4598 | drm_property_change_valid_put(property, ref); | ||
| 4599 | |||
| 4484 | out: | 4600 | out: |
| 4485 | drm_modeset_unlock_all(dev); | 4601 | drm_modeset_unlock_all(dev); |
| 4486 | return ret; | 4602 | return ret; |
| @@ -5225,8 +5341,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
| 5225 | idr_init(&dev->mode_config.tile_idr); | 5341 | idr_init(&dev->mode_config.tile_idr); |
| 5226 | 5342 | ||
| 5227 | drm_modeset_lock_all(dev); | 5343 | drm_modeset_lock_all(dev); |
| 5228 | drm_mode_create_standard_connector_properties(dev); | 5344 | drm_mode_create_standard_properties(dev); |
| 5229 | drm_mode_create_standard_plane_properties(dev); | ||
| 5230 | drm_modeset_unlock_all(dev); | 5345 | drm_modeset_unlock_all(dev); |
| 5231 | 5346 | ||
| 5232 | /* Just to be sure */ | 5347 | /* Just to be sure */ |
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d552708409de..b1979e7bdc88 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
| @@ -946,6 +946,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod | |||
| 946 | crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); | 946 | crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); |
| 947 | if (!crtc_state) | 947 | if (!crtc_state) |
| 948 | return -ENOMEM; | 948 | return -ENOMEM; |
| 949 | crtc_state->crtc = crtc; | ||
| 949 | 950 | ||
| 950 | crtc_state->enable = true; | 951 | crtc_state->enable = true; |
| 951 | crtc_state->planes_changed = true; | 952 | crtc_state->planes_changed = true; |
| @@ -1005,6 +1006,7 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |||
| 1005 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | 1006 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); |
| 1006 | if (!plane_state) | 1007 | if (!plane_state) |
| 1007 | return -ENOMEM; | 1008 | return -ENOMEM; |
| 1009 | plane_state->plane = plane; | ||
| 1008 | 1010 | ||
| 1009 | plane_state->crtc = crtc; | 1011 | plane_state->crtc = crtc; |
| 1010 | drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); | 1012 | drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); |
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index a2945ee6d675..247dc8b62564 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
| @@ -36,3 +36,9 @@ int drm_mode_object_get(struct drm_device *dev, | |||
| 36 | void drm_mode_object_put(struct drm_device *dev, | 36 | void drm_mode_object_put(struct drm_device *dev, |
| 37 | struct drm_mode_object *object); | 37 | struct drm_mode_object *object); |
| 38 | 38 | ||
| 39 | /* drm_atomic.c */ | ||
| 40 | int drm_atomic_get_property(struct drm_mode_object *obj, | ||
| 41 | struct drm_property *property, uint64_t *val); | ||
| 42 | int drm_mode_atomic_ioctl(struct drm_device *dev, | ||
| 43 | void *data, struct drm_file *file_priv); | ||
| 44 | |||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 4f41377b0b80..d51213464672 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -40,15 +40,19 @@ | |||
| 40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | 40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ |
| 41 | EXPORT_SYMBOL(drm_debug); | 41 | EXPORT_SYMBOL(drm_debug); |
| 42 | 42 | ||
| 43 | bool drm_atomic = 0; | ||
| 44 | |||
| 43 | MODULE_AUTHOR(CORE_AUTHOR); | 45 | MODULE_AUTHOR(CORE_AUTHOR); |
| 44 | MODULE_DESCRIPTION(CORE_DESC); | 46 | MODULE_DESCRIPTION(CORE_DESC); |
| 45 | MODULE_LICENSE("GPL and additional rights"); | 47 | MODULE_LICENSE("GPL and additional rights"); |
| 46 | MODULE_PARM_DESC(debug, "Enable debug output"); | 48 | MODULE_PARM_DESC(debug, "Enable debug output"); |
| 49 | MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API"); | ||
| 47 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); | 50 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); |
| 48 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); | 51 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); |
| 49 | MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); | 52 | MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); |
| 50 | 53 | ||
| 51 | module_param_named(debug, drm_debug, int, 0600); | 54 | module_param_named(debug, drm_debug, int, 0600); |
| 55 | module_param_named_unsafe(atomic, drm_atomic, bool, 0600); | ||
| 52 | 56 | ||
| 53 | static DEFINE_SPINLOCK(drm_minor_lock); | 57 | static DEFINE_SPINLOCK(drm_minor_lock); |
| 54 | static struct idr drm_minors_idr; | 58 | static struct idr drm_minors_idr; |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 00587a1e3c83..3785d66721f2 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <drm/drm_core.h> | 32 | #include <drm/drm_core.h> |
| 33 | #include "drm_legacy.h" | 33 | #include "drm_legacy.h" |
| 34 | #include "drm_internal.h" | 34 | #include "drm_internal.h" |
| 35 | #include "drm_crtc_internal.h" | ||
| 35 | 36 | ||
| 36 | #include <linux/pci.h> | 37 | #include <linux/pci.h> |
| 37 | #include <linux/export.h> | 38 | #include <linux/export.h> |
| @@ -345,6 +346,17 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 345 | return -EINVAL; | 346 | return -EINVAL; |
| 346 | file_priv->universal_planes = req->value; | 347 | file_priv->universal_planes = req->value; |
| 347 | break; | 348 | break; |
| 349 | case DRM_CLIENT_CAP_ATOMIC: | ||
| 350 | /* for now, hide behind experimental drm.atomic moduleparam */ | ||
| 351 | if (!drm_atomic) | ||
| 352 | return -EINVAL; | ||
| 353 | if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) | ||
| 354 | return -EINVAL; | ||
| 355 | if (req->value > 1) | ||
| 356 | return -EINVAL; | ||
| 357 | file_priv->atomic = req->value; | ||
| 358 | file_priv->universal_planes = req->value; | ||
| 359 | break; | ||
| 348 | default: | 360 | default: |
| 349 | return -EINVAL; | 361 | return -EINVAL; |
| 350 | } | 362 | } |
| @@ -620,6 +632,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { | |||
| 620 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 632 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
| 621 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 633 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
| 622 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 634 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
| 635 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||
| 623 | }; | 636 | }; |
| 624 | 637 | ||
| 625 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) | 638 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 391dfb7d1086..f24c4cfe674b 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
| @@ -523,6 +523,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
| 523 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | 523 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); |
| 524 | if (!plane_state) | 524 | if (!plane_state) |
| 525 | return -ENOMEM; | 525 | return -ENOMEM; |
| 526 | plane_state->plane = plane; | ||
| 526 | 527 | ||
| 527 | plane_state->crtc = crtc; | 528 | plane_state->crtc = crtc; |
| 528 | drm_atomic_set_fb_for_plane(plane_state, fb); | 529 | drm_atomic_set_fb_for_plane(plane_state, fb); |
| @@ -569,6 +570,7 @@ int drm_plane_helper_disable(struct drm_plane *plane) | |||
| 569 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | 570 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); |
| 570 | if (!plane_state) | 571 | if (!plane_state) |
| 571 | return -ENOMEM; | 572 | return -ENOMEM; |
| 573 | plane_state->plane = plane; | ||
| 572 | 574 | ||
| 573 | plane_state->crtc = NULL; | 575 | plane_state->crtc = NULL; |
| 574 | drm_atomic_set_fb_for_plane(plane_state, NULL); | 576 | drm_atomic_set_fb_for_plane(plane_state, NULL); |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 26e5fdea6594..fc76f630e5b1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | |||
| @@ -113,6 +113,7 @@ static void mdp5_plane_reset(struct drm_plane *plane) | |||
| 113 | } else { | 113 | } else { |
| 114 | mdp5_state->zpos = 1 + drm_plane_index(plane); | 114 | mdp5_state->zpos = 1 + drm_plane_index(plane); |
| 115 | } | 115 | } |
| 116 | mdp5_state->base.plane = plane; | ||
| 116 | 117 | ||
| 117 | plane->state = &mdp5_state->base; | 118 | plane->state = &mdp5_state->base; |
| 118 | } | 119 | } |
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 191968256c58..2c396540e279 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c | |||
| @@ -127,6 +127,26 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) | |||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | 129 | ||
| 130 | int msm_atomic_check(struct drm_device *dev, | ||
| 131 | struct drm_atomic_state *state) | ||
| 132 | { | ||
| 133 | int ret; | ||
| 134 | |||
| 135 | /* | ||
| 136 | * msm ->atomic_check can update ->mode_changed for pixel format | ||
| 137 | * changes, hence must be run before we check the modeset changes. | ||
| 138 | */ | ||
| 139 | ret = drm_atomic_helper_check_planes(dev, state); | ||
| 140 | if (ret) | ||
| 141 | return ret; | ||
| 142 | |||
| 143 | ret = drm_atomic_helper_check_modeset(dev, state); | ||
| 144 | if (ret) | ||
| 145 | return ret; | ||
| 146 | |||
| 147 | return ret; | ||
| 148 | } | ||
| 149 | |||
| 130 | /** | 150 | /** |
| 131 | * drm_atomic_helper_commit - commit validated state object | 151 | * drm_atomic_helper_commit - commit validated state object |
| 132 | * @dev: DRM device | 152 | * @dev: DRM device |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9a61546a0b05..f1ebedde6346 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
| @@ -29,7 +29,7 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) | |||
| 29 | static const struct drm_mode_config_funcs mode_config_funcs = { | 29 | static const struct drm_mode_config_funcs mode_config_funcs = { |
| 30 | .fb_create = msm_framebuffer_create, | 30 | .fb_create = msm_framebuffer_create, |
| 31 | .output_poll_changed = msm_fb_output_poll_changed, | 31 | .output_poll_changed = msm_fb_output_poll_changed, |
| 32 | .atomic_check = drm_atomic_helper_check, | 32 | .atomic_check = msm_atomic_check, |
| 33 | .atomic_commit = msm_atomic_commit, | 33 | .atomic_commit = msm_atomic_commit, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b69ef2d5a26c..22e5391a7ce8 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
| @@ -148,6 +148,8 @@ void __msm_fence_worker(struct work_struct *work); | |||
| 148 | (_cb)->func = _func; \ | 148 | (_cb)->func = _func; \ |
| 149 | } while (0) | 149 | } while (0) |
| 150 | 150 | ||
| 151 | int msm_atomic_check(struct drm_device *dev, | ||
| 152 | struct drm_atomic_state *state); | ||
| 151 | int msm_atomic_commit(struct drm_device *dev, | 153 | int msm_atomic_commit(struct drm_device *dev, |
| 152 | struct drm_atomic_state *state, bool async); | 154 | struct drm_atomic_state *state, bool async); |
| 153 | 155 | ||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a5f6a1f563c4..e928625a9da0 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -143,6 +143,7 @@ void drm_err(const char *format, ...); | |||
| 143 | #define DRIVER_MODESET 0x2000 | 143 | #define DRIVER_MODESET 0x2000 |
| 144 | #define DRIVER_PRIME 0x4000 | 144 | #define DRIVER_PRIME 0x4000 |
| 145 | #define DRIVER_RENDER 0x8000 | 145 | #define DRIVER_RENDER 0x8000 |
| 146 | #define DRIVER_ATOMIC 0x10000 | ||
| 146 | 147 | ||
| 147 | /***********************************************************************/ | 148 | /***********************************************************************/ |
| 148 | /** \name Macros to make printk easier */ | 149 | /** \name Macros to make printk easier */ |
| @@ -283,6 +284,8 @@ struct drm_file { | |||
| 283 | * in the plane list | 284 | * in the plane list |
| 284 | */ | 285 | */ |
| 285 | unsigned universal_planes:1; | 286 | unsigned universal_planes:1; |
| 287 | /* true if client understands atomic properties */ | ||
| 288 | unsigned atomic:1; | ||
| 286 | 289 | ||
| 287 | struct pid *pid; | 290 | struct pid *pid; |
| 288 | kuid_t uid; | 291 | kuid_t uid; |
| @@ -954,6 +957,7 @@ extern void drm_master_put(struct drm_master **master); | |||
| 954 | extern void drm_put_dev(struct drm_device *dev); | 957 | extern void drm_put_dev(struct drm_device *dev); |
| 955 | extern void drm_unplug_dev(struct drm_device *dev); | 958 | extern void drm_unplug_dev(struct drm_device *dev); |
| 956 | extern unsigned int drm_debug; | 959 | extern unsigned int drm_debug; |
| 960 | extern bool drm_atomic; | ||
| 957 | 961 | ||
| 958 | /* Debugfs support */ | 962 | /* Debugfs support */ |
| 959 | #if defined(CONFIG_DEBUG_FS) | 963 | #if defined(CONFIG_DEBUG_FS) |
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index ad2229574dd9..51168a8b723a 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
| @@ -38,16 +38,25 @@ void drm_atomic_state_free(struct drm_atomic_state *state); | |||
| 38 | struct drm_crtc_state * __must_check | 38 | struct drm_crtc_state * __must_check |
| 39 | drm_atomic_get_crtc_state(struct drm_atomic_state *state, | 39 | drm_atomic_get_crtc_state(struct drm_atomic_state *state, |
| 40 | struct drm_crtc *crtc); | 40 | struct drm_crtc *crtc); |
| 41 | int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | ||
| 42 | struct drm_crtc_state *state, struct drm_property *property, | ||
| 43 | uint64_t val); | ||
| 41 | struct drm_plane_state * __must_check | 44 | struct drm_plane_state * __must_check |
| 42 | drm_atomic_get_plane_state(struct drm_atomic_state *state, | 45 | drm_atomic_get_plane_state(struct drm_atomic_state *state, |
| 43 | struct drm_plane *plane); | 46 | struct drm_plane *plane); |
| 47 | int drm_atomic_plane_set_property(struct drm_plane *plane, | ||
| 48 | struct drm_plane_state *state, struct drm_property *property, | ||
| 49 | uint64_t val); | ||
| 44 | struct drm_connector_state * __must_check | 50 | struct drm_connector_state * __must_check |
| 45 | drm_atomic_get_connector_state(struct drm_atomic_state *state, | 51 | drm_atomic_get_connector_state(struct drm_atomic_state *state, |
| 46 | struct drm_connector *connector); | 52 | struct drm_connector *connector); |
| 53 | int drm_atomic_connector_set_property(struct drm_connector *connector, | ||
| 54 | struct drm_connector_state *state, struct drm_property *property, | ||
| 55 | uint64_t val); | ||
| 47 | 56 | ||
| 48 | int __must_check | 57 | int __must_check |
| 49 | drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, | 58 | drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, |
| 50 | struct drm_plane *plane, struct drm_crtc *crtc); | 59 | struct drm_crtc *crtc); |
| 51 | void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, | 60 | void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, |
| 52 | struct drm_framebuffer *fb); | 61 | struct drm_framebuffer *fb); |
| 53 | int __must_check | 62 | int __must_check |
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index f956b413311e..2095917ff8c7 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h | |||
| @@ -30,6 +30,10 @@ | |||
| 30 | 30 | ||
| 31 | #include <drm/drm_crtc.h> | 31 | #include <drm/drm_crtc.h> |
| 32 | 32 | ||
| 33 | int drm_atomic_helper_check_modeset(struct drm_device *dev, | ||
| 34 | struct drm_atomic_state *state); | ||
| 35 | int drm_atomic_helper_check_planes(struct drm_device *dev, | ||
| 36 | struct drm_atomic_state *state); | ||
| 33 | int drm_atomic_helper_check(struct drm_device *dev, | 37 | int drm_atomic_helper_check(struct drm_device *dev, |
| 34 | struct drm_atomic_state *state); | 38 | struct drm_atomic_state *state); |
| 35 | int drm_atomic_helper_commit(struct drm_device *dev, | 39 | int drm_atomic_helper_commit(struct drm_device *dev, |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 291239f2fafc..6588bffb6518 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
| @@ -63,8 +63,16 @@ struct drm_mode_object { | |||
| 63 | 63 | ||
| 64 | #define DRM_OBJECT_MAX_PROPERTY 24 | 64 | #define DRM_OBJECT_MAX_PROPERTY 24 |
| 65 | struct drm_object_properties { | 65 | struct drm_object_properties { |
| 66 | int count; | 66 | int count, atomic_count; |
| 67 | uint32_t ids[DRM_OBJECT_MAX_PROPERTY]; | 67 | /* NOTE: if we ever start dynamically destroying properties (ie. |
| 68 | * not at drm_mode_config_cleanup() time), then we'd have to do | ||
| 69 | * a better job of detaching property from mode objects to avoid | ||
| 70 | * dangling property pointers: | ||
| 71 | */ | ||
| 72 | struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY]; | ||
| 73 | /* do not read/write values directly, but use drm_object_property_get_value() | ||
| 74 | * and drm_object_property_set_value(): | ||
| 75 | */ | ||
| 68 | uint64_t values[DRM_OBJECT_MAX_PROPERTY]; | 76 | uint64_t values[DRM_OBJECT_MAX_PROPERTY]; |
| 69 | }; | 77 | }; |
| 70 | 78 | ||
| @@ -237,7 +245,9 @@ struct drm_atomic_state; | |||
| 237 | 245 | ||
| 238 | /** | 246 | /** |
| 239 | * struct drm_crtc_state - mutable CRTC state | 247 | * struct drm_crtc_state - mutable CRTC state |
| 248 | * @crtc: backpointer to the CRTC | ||
| 240 | * @enable: whether the CRTC should be enabled, gates all other state | 249 | * @enable: whether the CRTC should be enabled, gates all other state |
| 250 | * @active: whether the CRTC is actively displaying (used for DPMS) | ||
| 241 | * @mode_changed: for use by helpers and drivers when computing state updates | 251 | * @mode_changed: for use by helpers and drivers when computing state updates |
| 242 | * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes | 252 | * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes |
| 243 | * @last_vblank_count: for helpers and drivers to capture the vblank of the | 253 | * @last_vblank_count: for helpers and drivers to capture the vblank of the |
| @@ -248,9 +258,18 @@ struct drm_atomic_state; | |||
| 248 | * @event: optional pointer to a DRM event to signal upon completion of the | 258 | * @event: optional pointer to a DRM event to signal upon completion of the |
| 249 | * state update | 259 | * state update |
| 250 | * @state: backpointer to global drm_atomic_state | 260 | * @state: backpointer to global drm_atomic_state |
| 261 | * | ||
| 262 | * Note that the distinction between @enable and @active is rather subtile: | ||
| 263 | * Flipping @active while @enable is set without changing anything else may | ||
| 264 | * never return in a failure from the ->atomic_check callback. Userspace assumes | ||
| 265 | * that a DPMS On will always succeed. In other words: @enable controls resource | ||
| 266 | * assignment, @active controls the actual hardware state. | ||
| 251 | */ | 267 | */ |
| 252 | struct drm_crtc_state { | 268 | struct drm_crtc_state { |
| 269 | struct drm_crtc *crtc; | ||
| 270 | |||
| 253 | bool enable; | 271 | bool enable; |
| 272 | bool active; | ||
| 254 | 273 | ||
| 255 | /* computed state bits used by helpers and drivers */ | 274 | /* computed state bits used by helpers and drivers */ |
| 256 | bool planes_changed : 1; | 275 | bool planes_changed : 1; |
| @@ -292,6 +311,9 @@ struct drm_crtc_state { | |||
| 292 | * @atomic_duplicate_state: duplicate the atomic state for this CRTC | 311 | * @atomic_duplicate_state: duplicate the atomic state for this CRTC |
| 293 | * @atomic_destroy_state: destroy an atomic state for this CRTC | 312 | * @atomic_destroy_state: destroy an atomic state for this CRTC |
| 294 | * @atomic_set_property: set a property on an atomic state for this CRTC | 313 | * @atomic_set_property: set a property on an atomic state for this CRTC |
| 314 | * (do not call directly, use drm_atomic_crtc_set_property()) | ||
| 315 | * @atomic_get_property: get a property on an atomic state for this CRTC | ||
| 316 | * (do not call directly, use drm_atomic_crtc_get_property()) | ||
| 295 | * | 317 | * |
| 296 | * The drm_crtc_funcs structure is the central CRTC management structure | 318 | * The drm_crtc_funcs structure is the central CRTC management structure |
| 297 | * in the DRM. Each CRTC controls one or more connectors (note that the name | 319 | * in the DRM. Each CRTC controls one or more connectors (note that the name |
| @@ -351,6 +373,10 @@ struct drm_crtc_funcs { | |||
| 351 | struct drm_crtc_state *state, | 373 | struct drm_crtc_state *state, |
| 352 | struct drm_property *property, | 374 | struct drm_property *property, |
| 353 | uint64_t val); | 375 | uint64_t val); |
| 376 | int (*atomic_get_property)(struct drm_crtc *crtc, | ||
| 377 | const struct drm_crtc_state *state, | ||
| 378 | struct drm_property *property, | ||
| 379 | uint64_t *val); | ||
| 354 | }; | 380 | }; |
| 355 | 381 | ||
| 356 | /** | 382 | /** |
| @@ -449,11 +475,14 @@ struct drm_crtc { | |||
| 449 | 475 | ||
| 450 | /** | 476 | /** |
| 451 | * struct drm_connector_state - mutable connector state | 477 | * struct drm_connector_state - mutable connector state |
| 478 | * @connector: backpointer to the connector | ||
| 452 | * @crtc: CRTC to connect connector to, NULL if disabled | 479 | * @crtc: CRTC to connect connector to, NULL if disabled |
| 453 | * @best_encoder: can be used by helpers and drivers to select the encoder | 480 | * @best_encoder: can be used by helpers and drivers to select the encoder |
| 454 | * @state: backpointer to global drm_atomic_state | 481 | * @state: backpointer to global drm_atomic_state |
| 455 | */ | 482 | */ |
| 456 | struct drm_connector_state { | 483 | struct drm_connector_state { |
| 484 | struct drm_connector *connector; | ||
| 485 | |||
| 457 | struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */ | 486 | struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */ |
| 458 | 487 | ||
| 459 | struct drm_encoder *best_encoder; | 488 | struct drm_encoder *best_encoder; |
| @@ -475,6 +504,9 @@ struct drm_connector_state { | |||
| 475 | * @atomic_duplicate_state: duplicate the atomic state for this connector | 504 | * @atomic_duplicate_state: duplicate the atomic state for this connector |
| 476 | * @atomic_destroy_state: destroy an atomic state for this connector | 505 | * @atomic_destroy_state: destroy an atomic state for this connector |
| 477 | * @atomic_set_property: set a property on an atomic state for this connector | 506 | * @atomic_set_property: set a property on an atomic state for this connector |
| 507 | * (do not call directly, use drm_atomic_connector_set_property()) | ||
| 508 | * @atomic_get_property: get a property on an atomic state for this connector | ||
| 509 | * (do not call directly, use drm_atomic_connector_get_property()) | ||
| 478 | * | 510 | * |
| 479 | * Each CRTC may have one or more connectors attached to it. The functions | 511 | * Each CRTC may have one or more connectors attached to it. The functions |
| 480 | * below allow the core DRM code to control connectors, enumerate available modes, | 512 | * below allow the core DRM code to control connectors, enumerate available modes, |
| @@ -508,6 +540,10 @@ struct drm_connector_funcs { | |||
| 508 | struct drm_connector_state *state, | 540 | struct drm_connector_state *state, |
| 509 | struct drm_property *property, | 541 | struct drm_property *property, |
| 510 | uint64_t val); | 542 | uint64_t val); |
| 543 | int (*atomic_get_property)(struct drm_connector *connector, | ||
| 544 | const struct drm_connector_state *state, | ||
| 545 | struct drm_property *property, | ||
| 546 | uint64_t *val); | ||
| 511 | }; | 547 | }; |
| 512 | 548 | ||
| 513 | /** | 549 | /** |
| @@ -693,6 +729,7 @@ struct drm_connector { | |||
| 693 | 729 | ||
| 694 | /** | 730 | /** |
| 695 | * struct drm_plane_state - mutable plane state | 731 | * struct drm_plane_state - mutable plane state |
| 732 | * @plane: backpointer to the plane | ||
| 696 | * @crtc: currently bound CRTC, NULL if disabled | 733 | * @crtc: currently bound CRTC, NULL if disabled |
| 697 | * @fb: currently bound framebuffer | 734 | * @fb: currently bound framebuffer |
| 698 | * @fence: optional fence to wait for before scanning out @fb | 735 | * @fence: optional fence to wait for before scanning out @fb |
| @@ -709,6 +746,8 @@ struct drm_connector { | |||
| 709 | * @state: backpointer to global drm_atomic_state | 746 | * @state: backpointer to global drm_atomic_state |
| 710 | */ | 747 | */ |
| 711 | struct drm_plane_state { | 748 | struct drm_plane_state { |
| 749 | struct drm_plane *plane; | ||
| 750 | |||
| 712 | struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ | 751 | struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ |
| 713 | struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ | 752 | struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ |
| 714 | struct fence *fence; | 753 | struct fence *fence; |
| @@ -735,6 +774,9 @@ struct drm_plane_state { | |||
| 735 | * @atomic_duplicate_state: duplicate the atomic state for this plane | 774 | * @atomic_duplicate_state: duplicate the atomic state for this plane |
| 736 | * @atomic_destroy_state: destroy an atomic state for this plane | 775 | * @atomic_destroy_state: destroy an atomic state for this plane |
| 737 | * @atomic_set_property: set a property on an atomic state for this plane | 776 | * @atomic_set_property: set a property on an atomic state for this plane |
| 777 | * (do not call directly, use drm_atomic_plane_set_property()) | ||
| 778 | * @atomic_get_property: get a property on an atomic state for this plane | ||
| 779 | * (do not call directly, use drm_atomic_plane_get_property()) | ||
| 738 | */ | 780 | */ |
| 739 | struct drm_plane_funcs { | 781 | struct drm_plane_funcs { |
| 740 | int (*update_plane)(struct drm_plane *plane, | 782 | int (*update_plane)(struct drm_plane *plane, |
| @@ -758,6 +800,10 @@ struct drm_plane_funcs { | |||
| 758 | struct drm_plane_state *state, | 800 | struct drm_plane_state *state, |
| 759 | struct drm_property *property, | 801 | struct drm_property *property, |
| 760 | uint64_t val); | 802 | uint64_t val); |
| 803 | int (*atomic_get_property)(struct drm_plane *plane, | ||
| 804 | const struct drm_plane_state *state, | ||
| 805 | struct drm_property *property, | ||
| 806 | uint64_t *val); | ||
| 761 | }; | 807 | }; |
| 762 | 808 | ||
| 763 | enum drm_plane_type { | 809 | enum drm_plane_type { |
| @@ -856,7 +902,7 @@ struct drm_bridge { | |||
| 856 | /** | 902 | /** |
| 857 | * struct struct drm_atomic_state - the global state object for atomic updates | 903 | * struct struct drm_atomic_state - the global state object for atomic updates |
| 858 | * @dev: parent DRM device | 904 | * @dev: parent DRM device |
| 859 | * @flags: state flags like async update | 905 | * @allow_modeset: allow full modeset |
| 860 | * @planes: pointer to array of plane pointers | 906 | * @planes: pointer to array of plane pointers |
| 861 | * @plane_states: pointer to array of plane states pointers | 907 | * @plane_states: pointer to array of plane states pointers |
| 862 | * @crtcs: pointer to array of CRTC pointers | 908 | * @crtcs: pointer to array of CRTC pointers |
| @@ -868,7 +914,7 @@ struct drm_bridge { | |||
| 868 | */ | 914 | */ |
| 869 | struct drm_atomic_state { | 915 | struct drm_atomic_state { |
| 870 | struct drm_device *dev; | 916 | struct drm_device *dev; |
| 871 | uint32_t flags; | 917 | bool allow_modeset : 1; |
| 872 | struct drm_plane **planes; | 918 | struct drm_plane **planes; |
| 873 | struct drm_plane_state **plane_states; | 919 | struct drm_plane_state **plane_states; |
| 874 | struct drm_crtc **crtcs; | 920 | struct drm_crtc **crtcs; |
| @@ -1053,6 +1099,16 @@ struct drm_mode_config { | |||
| 1053 | struct drm_property *tile_property; | 1099 | struct drm_property *tile_property; |
| 1054 | struct drm_property *plane_type_property; | 1100 | struct drm_property *plane_type_property; |
| 1055 | struct drm_property *rotation_property; | 1101 | struct drm_property *rotation_property; |
| 1102 | struct drm_property *prop_src_x; | ||
| 1103 | struct drm_property *prop_src_y; | ||
| 1104 | struct drm_property *prop_src_w; | ||
| 1105 | struct drm_property *prop_src_h; | ||
| 1106 | struct drm_property *prop_crtc_x; | ||
| 1107 | struct drm_property *prop_crtc_y; | ||
| 1108 | struct drm_property *prop_crtc_w; | ||
| 1109 | struct drm_property *prop_crtc_h; | ||
| 1110 | struct drm_property *prop_fb_id; | ||
| 1111 | struct drm_property *prop_crtc_id; | ||
| 1056 | 1112 | ||
| 1057 | /* DVI-I properties */ | 1113 | /* DVI-I properties */ |
| 1058 | struct drm_property *dvi_i_subconnector_property; | 1114 | struct drm_property *dvi_i_subconnector_property; |
| @@ -1290,6 +1346,10 @@ extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); | |||
| 1290 | extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev); | 1346 | extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev); |
| 1291 | extern int drm_mode_create_dirty_info_property(struct drm_device *dev); | 1347 | extern int drm_mode_create_dirty_info_property(struct drm_device *dev); |
| 1292 | extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev); | 1348 | extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev); |
| 1349 | extern bool drm_property_change_valid_get(struct drm_property *property, | ||
| 1350 | uint64_t value, struct drm_mode_object **ref); | ||
| 1351 | extern void drm_property_change_valid_put(struct drm_property *property, | ||
| 1352 | struct drm_mode_object *ref); | ||
| 1293 | 1353 | ||
| 1294 | extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, | 1354 | extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, |
| 1295 | struct drm_encoder *encoder); | 1355 | struct drm_encoder *encoder); |
| @@ -1381,6 +1441,8 @@ extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
| 1381 | extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, | 1441 | extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, |
| 1382 | struct drm_property *property, | 1442 | struct drm_property *property, |
| 1383 | uint64_t value); | 1443 | uint64_t value); |
| 1444 | extern int drm_mode_atomic_ioctl(struct drm_device *dev, | ||
| 1445 | void *data, struct drm_file *file_priv); | ||
| 1384 | 1446 | ||
| 1385 | extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, | 1447 | extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, |
| 1386 | int *bpp); | 1448 | int *bpp); |
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index b0b855613641..01b2d6d0e355 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h | |||
| @@ -654,6 +654,13 @@ struct drm_get_cap { | |||
| 654 | */ | 654 | */ |
| 655 | #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 | 655 | #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 |
| 656 | 656 | ||
| 657 | /** | ||
| 658 | * DRM_CLIENT_CAP_ATOMIC | ||
| 659 | * | ||
| 660 | * If set to 1, the DRM core will expose atomic properties to userspace | ||
| 661 | */ | ||
| 662 | #define DRM_CLIENT_CAP_ATOMIC 3 | ||
| 663 | |||
| 657 | /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ | 664 | /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ |
| 658 | struct drm_set_client_cap { | 665 | struct drm_set_client_cap { |
| 659 | __u64 capability; | 666 | __u64 capability; |
| @@ -777,6 +784,7 @@ struct drm_prime_handle { | |||
| 777 | #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) | 784 | #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) |
| 778 | #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) | 785 | #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) |
| 779 | #define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2) | 786 | #define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2) |
| 787 | #define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic) | ||
| 780 | 788 | ||
| 781 | /** | 789 | /** |
| 782 | * Device specific ioctls should only be in their respective headers | 790 | * Device specific ioctls should only be in their respective headers |
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index aae71cb32123..ca788e01dab2 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h | |||
| @@ -272,6 +272,13 @@ struct drm_mode_get_connector { | |||
| 272 | #define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) | 272 | #define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) |
| 273 | #define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) | 273 | #define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) |
| 274 | 274 | ||
| 275 | /* the PROP_ATOMIC flag is used to hide properties from userspace that | ||
| 276 | * is not aware of atomic properties. This is mostly to work around | ||
| 277 | * older userspace (DDX drivers) that read/write each prop they find, | ||
| 278 | * witout being aware that this could be triggering a lengthy modeset. | ||
| 279 | */ | ||
| 280 | #define DRM_MODE_PROP_ATOMIC 0x80000000 | ||
| 281 | |||
| 275 | struct drm_mode_property_enum { | 282 | struct drm_mode_property_enum { |
| 276 | __u64 value; | 283 | __u64 value; |
| 277 | char name[DRM_PROP_NAME_LEN]; | 284 | char name[DRM_PROP_NAME_LEN]; |
| @@ -519,4 +526,27 @@ struct drm_mode_destroy_dumb { | |||
| 519 | uint32_t handle; | 526 | uint32_t handle; |
| 520 | }; | 527 | }; |
| 521 | 528 | ||
| 529 | /* page-flip flags are valid, plus: */ | ||
| 530 | #define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 | ||
| 531 | #define DRM_MODE_ATOMIC_NONBLOCK 0x0200 | ||
| 532 | #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 | ||
| 533 | |||
| 534 | #define DRM_MODE_ATOMIC_FLAGS (\ | ||
| 535 | DRM_MODE_PAGE_FLIP_EVENT |\ | ||
| 536 | DRM_MODE_PAGE_FLIP_ASYNC |\ | ||
| 537 | DRM_MODE_ATOMIC_TEST_ONLY |\ | ||
| 538 | DRM_MODE_ATOMIC_NONBLOCK |\ | ||
| 539 | DRM_MODE_ATOMIC_ALLOW_MODESET) | ||
| 540 | |||
| 541 | struct drm_mode_atomic { | ||
| 542 | __u32 flags; | ||
| 543 | __u32 count_objs; | ||
| 544 | __u64 objs_ptr; | ||
| 545 | __u64 count_props_ptr; | ||
| 546 | __u64 props_ptr; | ||
| 547 | __u64 prop_values_ptr; | ||
| 548 | __u64 reserved; | ||
| 549 | __u64 user_data; | ||
| 550 | }; | ||
| 551 | |||
| 522 | #endif | 552 | #endif |
