aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-12-01 17:59:34 -0500
committerDave Airlie <airlied@redhat.com>2014-12-01 17:59:34 -0500
commit9be23ae4350bfd71c0cc2ea3494671ee90e5603b (patch)
tree4233411cc12265c675125d99fb0ea03c9172423b
parent5a0e9d72136d90f5456bcc465d318f49d3f45838 (diff)
parente5b5341c28c66a122982d3d8822a4f9a0938f923 (diff)
Merge tag 'topic/core-stuff-2014-11-28' of git://anongit.freedesktop.org/drm-intel into drm-next
So here's a pile of atomic fixes and improvements from various people. There's still more patches in-flight, so I think I'll keep collecting them in a separate branch. * tag 'topic/core-stuff-2014-11-28' of git://anongit.freedesktop.org/drm-intel: drm/atomic: clear plane's CRTC and FB when shutting down drm: Handle atomic state properly in kms getfoo ioctl drm: use mode_object_find helpers drm: fix indentation drm/msm: switch to atomic-helpers iterator macros drm/atomic: add plane iterator macros drm/atomic: track bitmask of planes attached to crtc drm: Free atomic state during cleanup drm: Make drm_atomic.h standalone includible drm: Make drm_atomic_helper.h standalone includible drm/plane: Add missing kerneldoc drm/plane: Pass old state to ->atomic_update() drm/atomic_helper: Cope with plane->crtc == NULL in disable helper drm/atomic: Drop per-plane locking TODO drm/atomic-helper: Skip vblank waits for unchanged fbs drm: Document that drm_dev_alloc doesn't need a parent
-rw-r--r--Documentation/DocBook/drm.tmpl1
-rw-r--r--drivers/gpu/drm/drm_atomic.c32
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c77
-rw-r--r--drivers/gpu/drm/drm_crtc.c75
-rw-r--r--drivers/gpu/drm/drm_drv.c2
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c6
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c9
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c3
-rw-r--r--drivers/gpu/drm/msm/msm_kms.h23
-rw-r--r--include/drm/drmP.h2
-rw-r--r--include/drm/drm_atomic.h6
-rw-r--r--include/drm/drm_atomic_helper.h26
-rw-r--r--include/drm/drm_crtc.h27
-rw-r--r--include/drm/drm_plane_helper.h7
16 files changed, 226 insertions, 75 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 8c54f9a393cf..3789f2db3c21 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2343,6 +2343,7 @@ void intel_crt_init(struct drm_device *dev)
2343 <title>Atomic State Reset and Initialization</title> 2343 <title>Atomic State Reset and Initialization</title>
2344!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization 2344!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
2345 </sect3> 2345 </sect3>
2346!Iinclude/drm/drm_atomic_helper.h
2346!Edrivers/gpu/drm/drm_atomic_helper.c 2347!Edrivers/gpu/drm/drm_atomic_helper.c
2347 </sect2> 2348 </sect2>
2348 <sect2> 2349 <sect2>
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index d3b46746b611..ff5f034cc405 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -243,12 +243,6 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
243 if (state->plane_states[index]) 243 if (state->plane_states[index])
244 return state->plane_states[index]; 244 return state->plane_states[index];
245 245
246 /*
247 * TODO: We currently don't have per-plane mutexes. So instead of trying
248 * crazy tricks with deferring plane->crtc and hoping for the best just
249 * grab all crtc locks. Once we have per-plane locks we must update this
250 * to only take the plane mutex.
251 */
252 ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); 246 ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
253 if (ret) 247 if (ret)
254 return ERR_PTR(ret); 248 return ERR_PTR(ret);
@@ -350,7 +344,8 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
350 344
351/** 345/**
352 * drm_atomic_set_crtc_for_plane - set crtc for plane 346 * drm_atomic_set_crtc_for_plane - set crtc for plane
353 * @plane_state: atomic state object for the plane 347 * @state: the incoming atomic state
348 * @plane: the plane whose incoming state to update
354 * @crtc: crtc to use for the plane 349 * @crtc: crtc to use for the plane
355 * 350 *
356 * Changing the assigned crtc for a plane requires us to grab the lock and state 351 * Changing the assigned crtc for a plane requires us to grab the lock and state
@@ -363,20 +358,35 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
363 * sequence must be restarted. All other errors are fatal. 358 * sequence must be restarted. All other errors are fatal.
364 */ 359 */
365int 360int
366drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, 361drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
367 struct drm_crtc *crtc) 362 struct drm_plane *plane, struct drm_crtc *crtc)
368{ 363{
364 struct drm_plane_state *plane_state =
365 drm_atomic_get_plane_state(state, plane);
369 struct drm_crtc_state *crtc_state; 366 struct drm_crtc_state *crtc_state;
370 367
368 if (WARN_ON(IS_ERR(plane_state)))
369 return PTR_ERR(plane_state);
370
371 if (plane_state->crtc) {
372 crtc_state = drm_atomic_get_crtc_state(plane_state->state,
373 plane_state->crtc);
374 if (WARN_ON(IS_ERR(crtc_state)))
375 return PTR_ERR(crtc_state);
376
377 crtc_state->plane_mask &= ~(1 << drm_plane_index(plane));
378 }
379
380 plane_state->crtc = crtc;
381
371 if (crtc) { 382 if (crtc) {
372 crtc_state = drm_atomic_get_crtc_state(plane_state->state, 383 crtc_state = drm_atomic_get_crtc_state(plane_state->state,
373 crtc); 384 crtc);
374 if (IS_ERR(crtc_state)) 385 if (IS_ERR(crtc_state))
375 return PTR_ERR(crtc_state); 386 return PTR_ERR(crtc_state);
387 crtc_state->plane_mask |= (1 << drm_plane_index(plane));
376 } 388 }
377 389
378 plane_state->crtc = crtc;
379
380 if (crtc) 390 if (crtc)
381 DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n", 391 DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
382 plane_state, crtc->base.id); 392 plane_state, crtc->base.id);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index a17b8e9c0a81..4a78a773151c 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -751,6 +751,33 @@ static void wait_for_fences(struct drm_device *dev,
751 } 751 }
752} 752}
753 753
754static bool framebuffer_changed(struct drm_device *dev,
755 struct drm_atomic_state *old_state,
756 struct drm_crtc *crtc)
757{
758 struct drm_plane *plane;
759 struct drm_plane_state *old_plane_state;
760 int nplanes = old_state->dev->mode_config.num_total_plane;
761 int i;
762
763 for (i = 0; i < nplanes; i++) {
764 plane = old_state->planes[i];
765 old_plane_state = old_state->plane_states[i];
766
767 if (!plane)
768 continue;
769
770 if (plane->state->crtc != crtc &&
771 old_plane_state->crtc != crtc)
772 continue;
773
774 if (plane->state->fb != old_plane_state->fb)
775 return true;
776 }
777
778 return false;
779}
780
754/** 781/**
755 * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs 782 * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs
756 * @dev: DRM device 783 * @dev: DRM device
@@ -758,7 +785,9 @@ static void wait_for_fences(struct drm_device *dev,
758 * 785 *
759 * Helper to, after atomic commit, wait for vblanks on all effected 786 * Helper to, after atomic commit, wait for vblanks on all effected
760 * crtcs (ie. before cleaning up old framebuffers using 787 * crtcs (ie. before cleaning up old framebuffers using
761 * drm_atomic_helper_cleanup_planes()) 788 * drm_atomic_helper_cleanup_planes()). It will only wait on crtcs where the
789 * framebuffers have actually changed to optimize for the legacy cursor and
790 * plane update use-case.
762 */ 791 */
763void 792void
764drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, 793drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
@@ -784,6 +813,9 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
784 if (!crtc->state->enable) 813 if (!crtc->state->enable)
785 continue; 814 continue;
786 815
816 if (!framebuffer_changed(dev, old_state, crtc))
817 continue;
818
787 ret = drm_crtc_vblank_get(crtc); 819 ret = drm_crtc_vblank_get(crtc);
788 if (ret != 0) 820 if (ret != 0)
789 continue; 821 continue;
@@ -1014,6 +1046,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
1014 for (i = 0; i < nplanes; i++) { 1046 for (i = 0; i < nplanes; i++) {
1015 struct drm_plane_helper_funcs *funcs; 1047 struct drm_plane_helper_funcs *funcs;
1016 struct drm_plane *plane = old_state->planes[i]; 1048 struct drm_plane *plane = old_state->planes[i];
1049 struct drm_plane_state *old_plane_state;
1017 1050
1018 if (!plane) 1051 if (!plane)
1019 continue; 1052 continue;
@@ -1023,7 +1056,9 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
1023 if (!funcs || !funcs->atomic_update) 1056 if (!funcs || !funcs->atomic_update)
1024 continue; 1057 continue;
1025 1058
1026 funcs->atomic_update(plane); 1059 old_plane_state = old_state->plane_states[i];
1060
1061 funcs->atomic_update(plane, old_plane_state);
1027 } 1062 }
1028 1063
1029 for (i = 0; i < ncrtcs; i++) { 1064 for (i = 0; i < ncrtcs; i++) {
@@ -1187,7 +1222,7 @@ retry:
1187 goto fail; 1222 goto fail;
1188 } 1223 }
1189 1224
1190 ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); 1225 ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
1191 if (ret != 0) 1226 if (ret != 0)
1192 goto fail; 1227 goto fail;
1193 drm_atomic_set_fb_for_plane(plane_state, fb); 1228 drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1243,6 +1278,17 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
1243 struct drm_plane_state *plane_state; 1278 struct drm_plane_state *plane_state;
1244 int ret = 0; 1279 int ret = 0;
1245 1280
1281 /*
1282 * FIXME: Without plane->crtc set we can't get at the implicit legacy
1283 * acquire context. The real fix will be to wire the acquire ctx through
1284 * everywhere we need it, but meanwhile prevent chaos by just skipping
1285 * this noop. The critical case is the cursor ioctls which a) only grab
1286 * crtc/cursor-plane locks (so we need the crtc to get at the right
1287 * acquire context) and b) can try to disable the plane multiple times.
1288 */
1289 if (!plane->crtc)
1290 return 0;
1291
1246 state = drm_atomic_state_alloc(plane->dev); 1292 state = drm_atomic_state_alloc(plane->dev);
1247 if (!state) 1293 if (!state)
1248 return -ENOMEM; 1294 return -ENOMEM;
@@ -1255,7 +1301,7 @@ retry:
1255 goto fail; 1301 goto fail;
1256 } 1302 }
1257 1303
1258 ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); 1304 ret = drm_atomic_set_crtc_for_plane(state, plane, NULL);
1259 if (ret != 0) 1305 if (ret != 0)
1260 goto fail; 1306 goto fail;
1261 drm_atomic_set_fb_for_plane(plane_state, NULL); 1307 drm_atomic_set_fb_for_plane(plane_state, NULL);
@@ -1406,11 +1452,24 @@ retry:
1406 goto fail; 1452 goto fail;
1407 } 1453 }
1408 1454
1455 primary_state = drm_atomic_get_plane_state(state, crtc->primary);
1456 if (IS_ERR(primary_state)) {
1457 ret = PTR_ERR(primary_state);
1458 goto fail;
1459 }
1460
1409 if (!set->mode) { 1461 if (!set->mode) {
1410 WARN_ON(set->fb); 1462 WARN_ON(set->fb);
1411 WARN_ON(set->num_connectors); 1463 WARN_ON(set->num_connectors);
1412 1464
1413 crtc_state->enable = false; 1465 crtc_state->enable = false;
1466
1467 ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL);
1468 if (ret != 0)
1469 goto fail;
1470
1471 drm_atomic_set_fb_for_plane(primary_state, NULL);
1472
1414 goto commit; 1473 goto commit;
1415 } 1474 }
1416 1475
@@ -1420,13 +1479,7 @@ retry:
1420 crtc_state->enable = true; 1479 crtc_state->enable = true;
1421 drm_mode_copy(&crtc_state->mode, set->mode); 1480 drm_mode_copy(&crtc_state->mode, set->mode);
1422 1481
1423 primary_state = drm_atomic_get_plane_state(state, crtc->primary); 1482 ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc);
1424 if (IS_ERR(primary_state)) {
1425 ret = PTR_ERR(primary_state);
1426 goto fail;
1427 }
1428
1429 ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
1430 if (ret != 0) 1483 if (ret != 0)
1431 goto fail; 1484 goto fail;
1432 drm_atomic_set_fb_for_plane(primary_state, set->fb); 1485 drm_atomic_set_fb_for_plane(primary_state, set->fb);
@@ -1698,7 +1751,7 @@ retry:
1698 goto fail; 1751 goto fail;
1699 } 1752 }
1700 1753
1701 ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); 1754 ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
1702 if (ret != 0) 1755 if (ret != 0)
1703 goto fail; 1756 goto fail;
1704 drm_atomic_set_fb_for_plane(plane_state, fb); 1757 drm_atomic_set_fb_for_plane(plane_state, fb);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 589a921d4313..de79283eaea7 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -721,6 +721,10 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
721 drm_mode_object_put(dev, &crtc->base); 721 drm_mode_object_put(dev, &crtc->base);
722 list_del(&crtc->head); 722 list_del(&crtc->head);
723 dev->mode_config.num_crtc--; 723 dev->mode_config.num_crtc--;
724
725 WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
726 if (crtc->state && crtc->funcs->atomic_destroy_state)
727 crtc->funcs->atomic_destroy_state(crtc, crtc->state);
724} 728}
725EXPORT_SYMBOL(drm_crtc_cleanup); 729EXPORT_SYMBOL(drm_crtc_cleanup);
726 730
@@ -918,6 +922,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
918 connector->name = NULL; 922 connector->name = NULL;
919 list_del(&connector->head); 923 list_del(&connector->head);
920 dev->mode_config.num_connector--; 924 dev->mode_config.num_connector--;
925
926 WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
927 if (connector->state && connector->funcs->atomic_destroy_state)
928 connector->funcs->atomic_destroy_state(connector,
929 connector->state);
921} 930}
922EXPORT_SYMBOL(drm_connector_cleanup); 931EXPORT_SYMBOL(drm_connector_cleanup);
923 932
@@ -1244,6 +1253,10 @@ void drm_plane_cleanup(struct drm_plane *plane)
1244 if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1253 if (plane->type == DRM_PLANE_TYPE_OVERLAY)
1245 dev->mode_config.num_overlay_plane--; 1254 dev->mode_config.num_overlay_plane--;
1246 drm_modeset_unlock_all(dev); 1255 drm_modeset_unlock_all(dev);
1256
1257 WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
1258 if (plane->state && plane->funcs->atomic_destroy_state)
1259 plane->funcs->atomic_destroy_state(plane, plane->state);
1247} 1260}
1248EXPORT_SYMBOL(drm_plane_cleanup); 1261EXPORT_SYMBOL(drm_plane_cleanup);
1249 1262
@@ -1955,6 +1968,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
1955 return true; 1968 return true;
1956} 1969}
1957 1970
1971static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
1972{
1973 /* For atomic drivers only state objects are synchronously updated and
1974 * protected by modeset locks, so check those first. */
1975 if (connector->state)
1976 return connector->state->best_encoder;
1977 return connector->encoder;
1978}
1979
1958/** 1980/**
1959 * drm_mode_getconnector - get connector configuration 1981 * drm_mode_getconnector - get connector configuration
1960 * @dev: drm device for the ioctl 1982 * @dev: drm device for the ioctl
@@ -1973,6 +1995,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
1973{ 1995{
1974 struct drm_mode_get_connector *out_resp = data; 1996 struct drm_mode_get_connector *out_resp = data;
1975 struct drm_connector *connector; 1997 struct drm_connector *connector;
1998 struct drm_encoder *encoder;
1976 struct drm_display_mode *mode; 1999 struct drm_display_mode *mode;
1977 int mode_count = 0; 2000 int mode_count = 0;
1978 int props_count = 0; 2001 int props_count = 0;
@@ -2028,8 +2051,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
2028 out_resp->subpixel = connector->display_info.subpixel_order; 2051 out_resp->subpixel = connector->display_info.subpixel_order;
2029 out_resp->connection = connector->status; 2052 out_resp->connection = connector->status;
2030 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2053 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2031 if (connector->encoder) 2054
2032 out_resp->encoder_id = connector->encoder->base.id; 2055 encoder = drm_connector_get_encoder(connector);
2056 if (encoder)
2057 out_resp->encoder_id = encoder->base.id;
2033 else 2058 else
2034 out_resp->encoder_id = 0; 2059 out_resp->encoder_id = 0;
2035 drm_modeset_unlock(&dev->mode_config.connection_mutex); 2060 drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2099,6 +2124,33 @@ out:
2099 return ret; 2124 return ret;
2100} 2125}
2101 2126
2127static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
2128{
2129 struct drm_connector *connector;
2130 struct drm_device *dev = encoder->dev;
2131 bool uses_atomic = false;
2132
2133 /* For atomic drivers only state objects are synchronously updated and
2134 * protected by modeset locks, so check those first. */
2135 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2136 if (!connector->state)
2137 continue;
2138
2139 uses_atomic = true;
2140
2141 if (connector->state->best_encoder != encoder)
2142 continue;
2143
2144 return connector->state->crtc;
2145 }
2146
2147 /* Don't return stale data (e.g. pending async disable). */
2148 if (uses_atomic)
2149 return NULL;
2150
2151 return encoder->crtc;
2152}
2153
2102/** 2154/**
2103 * drm_mode_getencoder - get encoder configuration 2155 * drm_mode_getencoder - get encoder configuration
2104 * @dev: drm device for the ioctl 2156 * @dev: drm device for the ioctl
@@ -2117,6 +2169,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
2117{ 2169{
2118 struct drm_mode_get_encoder *enc_resp = data; 2170 struct drm_mode_get_encoder *enc_resp = data;
2119 struct drm_encoder *encoder; 2171 struct drm_encoder *encoder;
2172 struct drm_crtc *crtc;
2120 2173
2121 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2174 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2122 return -EINVAL; 2175 return -EINVAL;
@@ -2126,7 +2179,10 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
2126 return -ENOENT; 2179 return -ENOENT;
2127 2180
2128 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2181 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2129 if (encoder->crtc) 2182 crtc = drm_encoder_get_crtc(encoder);
2183 if (crtc)
2184 enc_resp->crtc_id = crtc->base.id;
2185 else if (encoder->crtc)
2130 enc_resp->crtc_id = encoder->crtc->base.id; 2186 enc_resp->crtc_id = encoder->crtc->base.id;
2131 else 2187 else
2132 enc_resp->crtc_id = 0; 2188 enc_resp->crtc_id = 0;
@@ -2392,7 +2448,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2392 struct drm_file *file_priv) 2448 struct drm_file *file_priv)
2393{ 2449{
2394 struct drm_mode_set_plane *plane_req = data; 2450 struct drm_mode_set_plane *plane_req = data;
2395 struct drm_mode_object *obj;
2396 struct drm_plane *plane; 2451 struct drm_plane *plane;
2397 struct drm_crtc *crtc = NULL; 2452 struct drm_crtc *crtc = NULL;
2398 struct drm_framebuffer *fb = NULL; 2453 struct drm_framebuffer *fb = NULL;
@@ -2415,14 +2470,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2415 * First, find the plane, crtc, and fb objects. If not available, 2470 * First, find the plane, crtc, and fb objects. If not available,
2416 * we don't bother to call the driver. 2471 * we don't bother to call the driver.
2417 */ 2472 */
2418 obj = drm_mode_object_find(dev, plane_req->plane_id, 2473 plane = drm_plane_find(dev, plane_req->plane_id);
2419 DRM_MODE_OBJECT_PLANE); 2474 if (!plane) {
2420 if (!obj) {
2421 DRM_DEBUG_KMS("Unknown plane ID %d\n", 2475 DRM_DEBUG_KMS("Unknown plane ID %d\n",
2422 plane_req->plane_id); 2476 plane_req->plane_id);
2423 return -ENOENT; 2477 return -ENOENT;
2424 } 2478 }
2425 plane = obj_to_plane(obj);
2426 2479
2427 if (plane_req->fb_id) { 2480 if (plane_req->fb_id) {
2428 fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2481 fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
@@ -2432,14 +2485,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2432 return -ENOENT; 2485 return -ENOENT;
2433 } 2486 }
2434 2487
2435 obj = drm_mode_object_find(dev, plane_req->crtc_id, 2488 crtc = drm_crtc_find(dev, plane_req->crtc_id);
2436 DRM_MODE_OBJECT_CRTC); 2489 if (!crtc) {
2437 if (!obj) {
2438 DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2490 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
2439 plane_req->crtc_id); 2491 plane_req->crtc_id);
2440 return -ENOENT; 2492 return -ENOENT;
2441 } 2493 }
2442 crtc = obj_to_crtc(obj);
2443 } 2494 }
2444 2495
2445 /* 2496 /*
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 2e5c7d941313..4f41377b0b80 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -535,6 +535,8 @@ static void drm_fs_inode_free(struct inode *inode)
535 * The initial ref-count of the object is 1. Use drm_dev_ref() and 535 * The initial ref-count of the object is 1. Use drm_dev_ref() and
536 * drm_dev_unref() to take and drop further ref-counts. 536 * drm_dev_unref() to take and drop further ref-counts.
537 * 537 *
538 * Note that for purely virtual devices @parent can be NULL.
539 *
538 * RETURNS: 540 * RETURNS:
539 * Pointer to new DRM device, or NULL if out of memory. 541 * Pointer to new DRM device, or NULL if out of memory.
540 */ 542 */
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 93c6533c25da..18a1ac6ac22f 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -443,7 +443,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
443 crtc_funcs[i]->atomic_begin(crtc[i]); 443 crtc_funcs[i]->atomic_begin(crtc[i]);
444 } 444 }
445 445
446 plane_funcs->atomic_update(plane); 446 plane_funcs->atomic_update(plane, plane_state);
447 447
448 for (i = 0; i < 2; i++) { 448 for (i = 0; i < 2; i++) {
449 if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) 449 if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 6781aa994613..a7672e100d8b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -84,7 +84,7 @@ static void crtc_flush(struct drm_crtc *crtc)
84 struct drm_plane *plane; 84 struct drm_plane *plane;
85 uint32_t flush = 0; 85 uint32_t flush = 0;
86 86
87 for_each_plane_on_crtc(crtc, plane) { 87 drm_atomic_crtc_for_each_plane(plane, crtc) {
88 enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); 88 enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
89 flush |= pipe2flush(pipe_id); 89 flush |= pipe2flush(pipe_id);
90 } 90 }
@@ -197,7 +197,7 @@ static void setup_mixer(struct mdp4_kms *mdp4_kms)
197 struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); 197 struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
198 struct drm_plane *plane; 198 struct drm_plane *plane;
199 199
200 for_each_plane_on_crtc(crtc, plane) { 200 drm_atomic_crtc_for_each_plane(plane, crtc) {
201 enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); 201 enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
202 int idx = idxs[pipe_id]; 202 int idx = idxs[pipe_id];
203 mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer, 203 mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
@@ -221,7 +221,7 @@ static void blend_setup(struct drm_crtc *crtc)
221 mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); 221 mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
222 mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0); 222 mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
223 223
224 for_each_plane_on_crtc(crtc, plane) { 224 drm_atomic_crtc_for_each_plane(plane, crtc) {
225 enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); 225 enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
226 int idx = idxs[pipe_id]; 226 int idx = idxs[pipe_id];
227 if (idx > 0) { 227 if (idx > 0) {
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 76d0a40c7138..1e5ebe83647d 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -107,7 +107,8 @@ static int mdp4_plane_atomic_check(struct drm_plane *plane,
107 return 0; 107 return 0;
108} 108}
109 109
110static void mdp4_plane_atomic_update(struct drm_plane *plane) 110static void mdp4_plane_atomic_update(struct drm_plane *plane,
111 struct drm_plane_state *old_state)
111{ 112{
112 struct drm_plane_state *state = plane->state; 113 struct drm_plane_state *state = plane->state;
113 int ret; 114 int ret;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 0598bdea4ff4..0e9a2e3a82d7 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -91,7 +91,7 @@ static void crtc_flush_all(struct drm_crtc *crtc)
91 if (!mdp5_crtc->ctl) 91 if (!mdp5_crtc->ctl)
92 return; 92 return;
93 93
94 for_each_plane_on_crtc(crtc, plane) { 94 drm_atomic_crtc_for_each_plane(plane, crtc) {
95 flush_mask |= mdp5_plane_get_flush(plane); 95 flush_mask |= mdp5_plane_get_flush(plane);
96 } 96 }
97 flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); 97 flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
@@ -124,8 +124,9 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
124 } 124 }
125 spin_unlock_irqrestore(&dev->event_lock, flags); 125 spin_unlock_irqrestore(&dev->event_lock, flags);
126 126
127 for_each_plane_on_crtc(crtc, plane) 127 drm_atomic_crtc_for_each_plane(plane, crtc) {
128 mdp5_plane_complete_flip(plane); 128 mdp5_plane_complete_flip(plane);
129 }
129} 130}
130 131
131static void mdp5_crtc_destroy(struct drm_crtc *crtc) 132static void mdp5_crtc_destroy(struct drm_crtc *crtc)
@@ -195,7 +196,7 @@ static void blend_setup(struct drm_crtc *crtc)
195 if (!mdp5_crtc->ctl) 196 if (!mdp5_crtc->ctl)
196 goto out; 197 goto out;
197 198
198 for_each_plane_on_crtc(crtc, plane) { 199 drm_atomic_crtc_for_each_plane(plane, crtc) {
199 enum mdp_mixer_stage_id stage = 200 enum mdp_mixer_stage_id stage =
200 to_mdp5_plane_state(plane->state)->stage; 201 to_mdp5_plane_state(plane->state)->stage;
201 202
@@ -317,7 +318,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
317 /* verify that there are not too many planes attached to crtc 318 /* verify that there are not too many planes attached to crtc
318 * and that we don't have conflicting mixer stages: 319 * and that we don't have conflicting mixer stages:
319 */ 320 */
320 for_each_pending_plane_on_crtc(state->state, crtc, plane) { 321 drm_atomic_crtc_state_for_each_plane(plane, state) {
321 struct drm_plane_state *pstate; 322 struct drm_plane_state *pstate;
322 323
323 if (cnt >= ARRAY_SIZE(pstates)) { 324 if (cnt >= ARRAY_SIZE(pstates)) {
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 533df7caa310..26e5fdea6594 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -213,7 +213,8 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
213 return 0; 213 return 0;
214} 214}
215 215
216static void mdp5_plane_atomic_update(struct drm_plane *plane) 216static void mdp5_plane_atomic_update(struct drm_plane *plane,
217 struct drm_plane_state *old_state)
217{ 218{
218 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 219 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
219 struct drm_plane_state *state = plane->state; 220 struct drm_plane_state *state = plane->state;
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 7fb4876388e7..06437745bc2c 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -65,27 +65,4 @@ static inline void msm_kms_init(struct msm_kms *kms,
65struct msm_kms *mdp4_kms_init(struct drm_device *dev); 65struct msm_kms *mdp4_kms_init(struct drm_device *dev);
66struct msm_kms *mdp5_kms_init(struct drm_device *dev); 66struct msm_kms *mdp5_kms_init(struct drm_device *dev);
67 67
68/* TODO move these helper iterator macro somewhere common: */
69#define for_each_plane_on_crtc(_crtc, _plane) \
70 list_for_each_entry((_plane), &(_crtc)->dev->mode_config.plane_list, head) \
71 if ((_plane)->state->crtc == (_crtc))
72
73static inline bool
74__plane_will_be_attached_to_crtc(struct drm_atomic_state *state,
75 struct drm_plane *plane, struct drm_crtc *crtc)
76{
77 int idx = drm_plane_index(plane);
78
79 /* if plane is modified in incoming state, use the new state: */
80 if (state->plane_states[idx])
81 return state->plane_states[idx]->crtc == crtc;
82
83 /* otherwise, current state: */
84 return plane->state->crtc == crtc;
85}
86
87#define for_each_pending_plane_on_crtc(_state, _crtc, _plane) \
88 list_for_each_entry((_plane), &(_crtc)->dev->mode_config.plane_list, head) \
89 if (__plane_will_be_attached_to_crtc((_state), (_plane), (_crtc)))
90
91#endif /* __MSM_KMS_H__ */ 68#endif /* __MSM_KMS_H__ */
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index be776fb2db18..8ba35c622e22 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -809,7 +809,7 @@ struct drm_device {
809 struct drm_local_map *agp_buffer_map; 809 struct drm_local_map *agp_buffer_map;
810 unsigned int agp_buffer_token; 810 unsigned int agp_buffer_token;
811 811
812 struct drm_mode_config mode_config; /**< Current mode config */ 812 struct drm_mode_config mode_config; /**< Current mode config */
813 813
814 /** \name GEM information */ 814 /** \name GEM information */
815 /*@{ */ 815 /*@{ */
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 9d919168bc11..ad2229574dd9 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -28,6 +28,8 @@
28#ifndef DRM_ATOMIC_H_ 28#ifndef DRM_ATOMIC_H_
29#define DRM_ATOMIC_H_ 29#define DRM_ATOMIC_H_
30 30
31#include <drm/drm_crtc.h>
32
31struct drm_atomic_state * __must_check 33struct drm_atomic_state * __must_check
32drm_atomic_state_alloc(struct drm_device *dev); 34drm_atomic_state_alloc(struct drm_device *dev);
33void drm_atomic_state_clear(struct drm_atomic_state *state); 35void drm_atomic_state_clear(struct drm_atomic_state *state);
@@ -44,8 +46,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
44 struct drm_connector *connector); 46 struct drm_connector *connector);
45 47
46int __must_check 48int __must_check
47drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, 49drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
48 struct drm_crtc *crtc); 50 struct drm_plane *plane, struct drm_crtc *crtc);
49void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, 51void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
50 struct drm_framebuffer *fb); 52 struct drm_framebuffer *fb);
51int __must_check 53int __must_check
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 64b4e91b93bc..f956b413311e 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -28,6 +28,8 @@
28#ifndef DRM_ATOMIC_HELPER_H_ 28#ifndef DRM_ATOMIC_HELPER_H_
29#define DRM_ATOMIC_HELPER_H_ 29#define DRM_ATOMIC_HELPER_H_
30 30
31#include <drm/drm_crtc.h>
32
31int drm_atomic_helper_check(struct drm_device *dev, 33int drm_atomic_helper_check(struct drm_device *dev,
32 struct drm_atomic_state *state); 34 struct drm_atomic_state *state);
33int drm_atomic_helper_commit(struct drm_device *dev, 35int drm_atomic_helper_commit(struct drm_device *dev,
@@ -96,5 +98,29 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
96void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, 98void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
97 struct drm_connector_state *state); 99 struct drm_connector_state *state);
98 100
101/**
102 * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
103 * @plane: the loop cursor
104 * @crtc: the crtc whose planes are iterated
105 *
106 * This iterates over the current state, useful (for example) when applying
107 * atomic state after it has been checked and swapped. To iterate over the
108 * planes which *will* be attached (for ->atomic_check()) see
109 * drm_crtc_for_each_pending_plane()
110 */
111#define drm_atomic_crtc_for_each_plane(plane, crtc) \
112 drm_for_each_plane_mask(plane, (crtc)->dev, (crtc)->state->plane_mask)
113
114/**
115 * drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state
116 * @plane: the loop cursor
117 * @crtc_state: the incoming crtc-state
118 *
119 * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be
120 * attached if the specified state is applied. Useful during (for example)
121 * ->atomic_check() operations, to validate the incoming state
122 */
123#define drm_atomic_crtc_state_for_each_plane(plane, crtc_state) \
124 drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask)
99 125
100#endif /* DRM_ATOMIC_HELPER_H_ */ 126#endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b459e8fbbc25..dd2c16e43333 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -231,6 +231,7 @@ struct drm_atomic_state;
231 * struct drm_crtc_state - mutable CRTC state 231 * struct drm_crtc_state - mutable CRTC state
232 * @enable: whether the CRTC should be enabled, gates all other state 232 * @enable: whether the CRTC should be enabled, gates all other state
233 * @mode_changed: for use by helpers and drivers when computing state updates 233 * @mode_changed: for use by helpers and drivers when computing state updates
234 * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
234 * @last_vblank_count: for helpers and drivers to capture the vblank of the 235 * @last_vblank_count: for helpers and drivers to capture the vblank of the
235 * update to ensure framebuffer cleanup isn't done too early 236 * update to ensure framebuffer cleanup isn't done too early
236 * @planes_changed: for use by helpers and drivers when computing state updates 237 * @planes_changed: for use by helpers and drivers when computing state updates
@@ -247,6 +248,13 @@ struct drm_crtc_state {
247 bool planes_changed : 1; 248 bool planes_changed : 1;
248 bool mode_changed : 1; 249 bool mode_changed : 1;
249 250
251 /* attached planes bitmask:
252 * WARNING: transitional helpers do not maintain plane_mask so
253 * drivers not converted over to atomic helpers should not rely
254 * on plane_mask being accurate!
255 */
256 u32 plane_mask;
257
250 /* last_vblank_count: for vblank waits before cleanup */ 258 /* last_vblank_count: for vblank waits before cleanup */
251 u32 last_vblank_count; 259 u32 last_vblank_count;
252 260
@@ -438,7 +446,7 @@ struct drm_crtc {
438 * @state: backpointer to global drm_atomic_state 446 * @state: backpointer to global drm_atomic_state
439 */ 447 */
440struct drm_connector_state { 448struct drm_connector_state {
441 struct drm_crtc *crtc; 449 struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */
442 450
443 struct drm_encoder *best_encoder; 451 struct drm_encoder *best_encoder;
444 452
@@ -673,8 +681,8 @@ struct drm_connector {
673 * @state: backpointer to global drm_atomic_state 681 * @state: backpointer to global drm_atomic_state
674 */ 682 */
675struct drm_plane_state { 683struct drm_plane_state {
676 struct drm_crtc *crtc; 684 struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */
677 struct drm_framebuffer *fb; 685 struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */
678 struct fence *fence; 686 struct fence *fence;
679 687
680 /* Signed dest location allows it to be partially off screen */ 688 /* Signed dest location allows it to be partially off screen */
@@ -1054,6 +1062,19 @@ struct drm_mode_config {
1054 uint32_t cursor_width, cursor_height; 1062 uint32_t cursor_width, cursor_height;
1055}; 1063};
1056 1064
1065/**
1066 * drm_for_each_plane_mask - iterate over planes specified by bitmask
1067 * @plane: the loop cursor
1068 * @dev: the DRM device
1069 * @plane_mask: bitmask of plane indices
1070 *
1071 * Iterate over all planes specified by bitmask.
1072 */
1073#define drm_for_each_plane_mask(plane, dev, plane_mask) \
1074 list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
1075 if ((plane_mask) & (1 << drm_plane_index(plane)))
1076
1077
1057#define obj_to_crtc(x) container_of(x, struct drm_crtc, base) 1078#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
1058#define obj_to_connector(x) container_of(x, struct drm_connector, base) 1079#define obj_to_connector(x) container_of(x, struct drm_connector, base)
1059#define obj_to_encoder(x) container_of(x, struct drm_encoder, base) 1080#define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index c48f14d88690..a185392cafeb 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -49,6 +49,10 @@ extern int drm_crtc_init(struct drm_device *dev,
49 49
50/** 50/**
51 * drm_plane_helper_funcs - helper operations for CRTCs 51 * drm_plane_helper_funcs - helper operations for CRTCs
52 * @prepare_fb: prepare a framebuffer for use by the plane
53 * @cleanup_fb: cleanup a framebuffer when it's no longer used by the plane
54 * @atomic_check: check that a given atomic state is valid and can be applied
55 * @atomic_update: apply an atomic state to the plane
52 * 56 *
53 * The helper operations are called by the mid-layer CRTC helper. 57 * The helper operations are called by the mid-layer CRTC helper.
54 */ 58 */
@@ -60,7 +64,8 @@ struct drm_plane_helper_funcs {
60 64
61 int (*atomic_check)(struct drm_plane *plane, 65 int (*atomic_check)(struct drm_plane *plane,
62 struct drm_plane_state *state); 66 struct drm_plane_state *state);
63 void (*atomic_update)(struct drm_plane *plane); 67 void (*atomic_update)(struct drm_plane *plane,
68 struct drm_plane_state *old_state);
64}; 69};
65 70
66static inline void drm_plane_helper_add(struct drm_plane *plane, 71static inline void drm_plane_helper_add(struct drm_plane *plane,