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
Unified · Split
| @@ -2343,6 +2343,7 @@ void intel_crt_init(struct drm_device *dev) · 2342 unmodified lines | ||
| 2343 | 2343 | <title>Atomic State Reset and Initialization</title> |
| 2344 | 2344 | !Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization |
| 2345 | 2345 | </sect3> |
| 2346 | +!Iinclude/drm/drm_atomic_helper.h | |
| 2346 | 2347 | !Edrivers/gpu/drm/drm_atomic_helper.c |
| 2347 | 2348 | </sect2> |
| 2348 | 2349 | <sect2> |
| @@ -243,12 +243,6 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, · 242 unmodified lines | ||
| 243 | 243 | if (state->plane_states[index]) |
| 244 | 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 | 246 | ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); |
| 253 | 247 | if (ret) |
| 254 | 248 | return ERR_PTR(ret); |
| @@ -350,7 +344,8 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); · 95 unmodified lines | ||
| 350 | 344 | |
| 351 | 345 | /** |
| 352 | 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 | 349 | * @crtc: crtc to use for the plane |
| 355 | 350 | * |
| 356 | 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); · 6 unmodified lines | ||
| 363 | 358 | * sequence must be restarted. All other errors are fatal. |
| 364 | 359 | */ |
| 365 | 360 | int |
| 366 | −drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, | |
| 367 | − struct drm_crtc *crtc) | |
| 361 | +drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, | |
| 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 | 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 | 382 | if (crtc) { |
| 372 | 383 | crtc_state = drm_atomic_get_crtc_state(plane_state->state, |
| 373 | 384 | crtc); |
| 374 | 385 | if (IS_ERR(crtc_state)) |
| 375 | 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 | 390 | if (crtc) |
| 381 | 391 | DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n", |
| 382 | 392 | plane_state, crtc->base.id); |
| @@ -751,6 +751,33 @@ static void wait_for_fences(struct drm_device *dev, · 750 unmodified lines | ||
| 751 | 751 | } |
| 752 | 752 | } |
| 753 | 753 | |
| 754 | +static 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 | 782 | * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs |
| 756 | 783 | * @dev: DRM device |
| @@ -758,7 +785,9 @@ static void wait_for_fences(struct drm_device *dev, · 1 unmodified line | ||
| 758 | 785 | * |
| 759 | 786 | * Helper to, after atomic commit, wait for vblanks on all effected |
| 760 | 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 | */ |
| 763 | 792 | void |
| 764 | 793 | drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, |
| @@ -784,6 +813,9 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, · 19 unmodified lines | ||
| 784 | 813 | if (!crtc->state->enable) |
| 785 | 814 | continue; |
| 786 | 815 | |
| 816 | + if (!framebuffer_changed(dev, old_state, crtc)) | |
| 817 | + continue; | |
| 818 | + | |
| 787 | 819 | ret = drm_crtc_vblank_get(crtc); |
| 788 | 820 | if (ret != 0) |
| 789 | 821 | continue; |
| @@ -1014,6 +1046,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, · 224 unmodified lines | ||
| 1014 | 1046 | for (i = 0; i < nplanes; i++) { |
| 1015 | 1047 | struct drm_plane_helper_funcs *funcs; |
| 1016 | 1048 | struct drm_plane *plane = old_state->planes[i]; |
| 1049 | + struct drm_plane_state *old_plane_state; | |
| 1017 | 1050 | |
| 1018 | 1051 | if (!plane) |
| 1019 | 1052 | continue; |
| @@ -1023,7 +1056,9 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, · 3 unmodified lines | ||
| 1023 | 1056 | if (!funcs || !funcs->atomic_update) |
| 1024 | 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 | 1064 | for (i = 0; i < ncrtcs; i++) { |
| @@ -1187,7 +1222,7 @@ retry: · 157 unmodified lines | ||
| 1187 | 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 | 1226 | if (ret != 0) |
| 1192 | 1227 | goto fail; |
| 1193 | 1228 | drm_atomic_set_fb_for_plane(plane_state, fb); |
| @@ -1243,6 +1278,17 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane) · 49 unmodified lines | ||
| 1243 | 1278 | struct drm_plane_state *plane_state; |
| 1244 | 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 | 1292 | state = drm_atomic_state_alloc(plane->dev); |
| 1247 | 1293 | if (!state) |
| 1248 | 1294 | return -ENOMEM; |
| @@ -1255,7 +1301,7 @@ retry: · 6 unmodified lines | ||
| 1255 | 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 | 1305 | if (ret != 0) |
| 1260 | 1306 | goto fail; |
| 1261 | 1307 | drm_atomic_set_fb_for_plane(plane_state, NULL); |
| @@ -1406,11 +1452,24 @@ retry: · 144 unmodified lines | ||
| 1406 | 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 | 1461 | if (!set->mode) { |
| 1410 | 1462 | WARN_ON(set->fb); |
| 1411 | 1463 | WARN_ON(set->num_connectors); |
| 1412 | 1464 | |
| 1413 | 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 | 1473 | goto commit; |
| 1415 | 1474 | } |
| 1416 | 1475 | |
| @@ -1420,13 +1479,7 @@ retry: · 3 unmodified lines | ||
| 1420 | 1479 | crtc_state->enable = true; |
| 1421 | 1480 | drm_mode_copy(&crtc_state->mode, set->mode); |
| 1422 | 1481 | |
| 1423 | − primary_state = drm_atomic_get_plane_state(state, crtc->primary); | |
| 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); | |
| 1482 | + ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc); | |
| 1430 | 1483 | if (ret != 0) |
| 1431 | 1484 | goto fail; |
| 1432 | 1485 | drm_atomic_set_fb_for_plane(primary_state, set->fb); |
| @@ -1698,7 +1751,7 @@ retry: · 265 unmodified lines | ||
| 1698 | 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 | 1755 | if (ret != 0) |
| 1703 | 1756 | goto fail; |
| 1704 | 1757 | drm_atomic_set_fb_for_plane(plane_state, fb); |
| @@ -721,6 +721,10 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) · 720 unmodified lines | ||
| 721 | 721 | drm_mode_object_put(dev, &crtc->base); |
| 722 | 722 | list_del(&crtc->head); |
| 723 | 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 | } |
| 725 | 729 | EXPORT_SYMBOL(drm_crtc_cleanup); |
| 726 | 730 | |
| @@ -918,6 +922,11 @@ void drm_connector_cleanup(struct drm_connector *connector) · 191 unmodified lines | ||
| 918 | 922 | connector->name = NULL; |
| 919 | 923 | list_del(&connector->head); |
| 920 | 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 | } |
| 922 | 931 | EXPORT_SYMBOL(drm_connector_cleanup); |
| 923 | 932 | |
| @@ -1244,6 +1253,10 @@ void drm_plane_cleanup(struct drm_plane *plane) · 320 unmodified lines | ||
| 1244 | 1253 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
| 1245 | 1254 | dev->mode_config.num_overlay_plane--; |
| 1246 | 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 | } |
| 1248 | 1261 | EXPORT_SYMBOL(drm_plane_cleanup); |
| 1249 | 1262 | |
| @@ -1955,6 +1968,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, · 705 unmodified lines | ||
| 1955 | 1968 | return true; |
| 1956 | 1969 | } |
| 1957 | 1970 | |
| 1971 | +static 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 | 1981 | * drm_mode_getconnector - get connector configuration |
| 1960 | 1982 | * @dev: drm device for the ioctl |
| @@ -1973,6 +1995,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, · 12 unmodified lines | ||
| 1973 | 1995 | { |
| 1974 | 1996 | struct drm_mode_get_connector *out_resp = data; |
| 1975 | 1997 | struct drm_connector *connector; |
| 1998 | + struct drm_encoder *encoder; | |
| 1976 | 1999 | struct drm_display_mode *mode; |
| 1977 | 2000 | int mode_count = 0; |
| 1978 | 2001 | int props_count = 0; |
| @@ -2028,8 +2051,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, · 49 unmodified lines | ||
| 2028 | 2051 | out_resp->subpixel = connector->display_info.subpixel_order; |
| 2029 | 2052 | out_resp->connection = connector->status; |
| 2030 | 2053 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
| 2031 | − if (connector->encoder) | |
| 2032 | − out_resp->encoder_id = connector->encoder->base.id; | |
| 2054 | + | |
| 2055 | + encoder = drm_connector_get_encoder(connector); | |
| 2056 | + if (encoder) | |
| 2057 | + out_resp->encoder_id = encoder->base.id; | |
| 2033 | 2058 | else |
| 2034 | 2059 | out_resp->encoder_id = 0; |
| 2035 | 2060 | drm_modeset_unlock(&dev->mode_config.connection_mutex); |
| @@ -2099,6 +2124,33 @@ out: · 63 unmodified lines | ||
| 2099 | 2124 | return ret; |
| 2100 | 2125 | } |
| 2101 | 2126 | |
| 2127 | +static 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 | 2155 | * drm_mode_getencoder - get encoder configuration |
| 2104 | 2156 | * @dev: drm device for the ioctl |
| @@ -2117,6 +2169,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, · 12 unmodified lines | ||
| 2117 | 2169 | { |
| 2118 | 2170 | struct drm_mode_get_encoder *enc_resp = data; |
| 2119 | 2171 | struct drm_encoder *encoder; |
| 2172 | + struct drm_crtc *crtc; | |
| 2120 | 2173 | |
| 2121 | 2174 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 2122 | 2175 | return -EINVAL; |
| @@ -2126,7 +2179,10 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, · 3 unmodified lines | ||
| 2126 | 2179 | return -ENOENT; |
| 2127 | 2180 | |
| 2128 | 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 | 2186 | enc_resp->crtc_id = encoder->crtc->base.id; |
| 2131 | 2187 | else |
| 2132 | 2188 | enc_resp->crtc_id = 0; |
| @@ -2392,7 +2448,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, · 259 unmodified lines | ||
| 2392 | 2448 | struct drm_file *file_priv) |
| 2393 | 2449 | { |
| 2394 | 2450 | struct drm_mode_set_plane *plane_req = data; |
| 2395 | − struct drm_mode_object *obj; | |
| 2396 | 2451 | struct drm_plane *plane; |
| 2397 | 2452 | struct drm_crtc *crtc = NULL; |
| 2398 | 2453 | struct drm_framebuffer *fb = NULL; |
| @@ -2415,14 +2470,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data, · 16 unmodified lines | ||
| 2415 | 2470 | * First, find the plane, crtc, and fb objects. If not available, |
| 2416 | 2471 | * we don't bother to call the driver. |
| 2417 | 2472 | */ |
| 2418 | − obj = drm_mode_object_find(dev, plane_req->plane_id, | |
| 2419 | − DRM_MODE_OBJECT_PLANE); | |
| 2420 | − if (!obj) { | |
| 2473 | + plane = drm_plane_find(dev, plane_req->plane_id); | |
| 2474 | + if (!plane) { | |
| 2421 | 2475 | DRM_DEBUG_KMS("Unknown plane ID %d\n", |
| 2422 | 2476 | plane_req->plane_id); |
| 2423 | 2477 | return -ENOENT; |
| 2424 | 2478 | } |
| 2425 | − plane = obj_to_plane(obj); | |
| 2426 | 2479 | |
| 2427 | 2480 | if (plane_req->fb_id) { |
| 2428 | 2481 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); |
| @@ -2432,14 +2485,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data, · 3 unmodified lines | ||
| 2432 | 2485 | return -ENOENT; |
| 2433 | 2486 | } |
| 2434 | 2487 | |
| 2435 | − obj = drm_mode_object_find(dev, plane_req->crtc_id, | |
| 2436 | − DRM_MODE_OBJECT_CRTC); | |
| 2437 | − if (!obj) { | |
| 2488 | + crtc = drm_crtc_find(dev, plane_req->crtc_id); | |
| 2489 | + if (!crtc) { | |
| 2438 | 2490 | DRM_DEBUG_KMS("Unknown crtc ID %d\n", |
| 2439 | 2491 | plane_req->crtc_id); |
| 2440 | 2492 | return -ENOENT; |
| 2441 | 2493 | } |
| 2442 | − crtc = obj_to_crtc(obj); | |
| 2443 | 2494 | } |
| 2444 | 2495 | |
| 2445 | 2496 | /* |
| @@ -535,6 +535,8 @@ static void drm_fs_inode_free(struct inode *inode) · 534 unmodified lines | ||
| 535 | 535 | * The initial ref-count of the object is 1. Use drm_dev_ref() and |
| 536 | 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 | 540 | * RETURNS: |
| 539 | 541 | * Pointer to new DRM device, or NULL if out of memory. |
| 540 | 542 | */ |
| @@ -443,7 +443,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, · 442 unmodified lines | ||
| 443 | 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 | 448 | for (i = 0; i < 2; i++) { |
| 449 | 449 | if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) |
| @@ -84,7 +84,7 @@ static void crtc_flush(struct drm_crtc *crtc) · 83 unmodified lines | ||
| 84 | 84 | struct drm_plane *plane; |
| 85 | 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 | 88 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); |
| 89 | 89 | flush |= pipe2flush(pipe_id); |
| 90 | 90 | } |
| @@ -197,7 +197,7 @@ static void setup_mixer(struct mdp4_kms *mdp4_kms) · 106 unmodified lines | ||
| 197 | 197 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
| 198 | 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 | 201 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); |
| 202 | 202 | int idx = idxs[pipe_id]; |
| 203 | 203 | mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer, |
| @@ -221,7 +221,7 @@ static void blend_setup(struct drm_crtc *crtc) · 17 unmodified lines | ||
| 221 | 221 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); |
| 222 | 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 | 225 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); |
| 226 | 226 | int idx = idxs[pipe_id]; |
| 227 | 227 | if (idx > 0) { |
| @@ -107,7 +107,8 @@ static int mdp4_plane_atomic_check(struct drm_plane *plane, · 106 unmodified lines | ||
| 107 | 107 | return 0; |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | −static void mdp4_plane_atomic_update(struct drm_plane *plane) | |
| 110 | +static void mdp4_plane_atomic_update(struct drm_plane *plane, | |
| 111 | + struct drm_plane_state *old_state) | |
| 111 | 112 | { |
| 112 | 113 | struct drm_plane_state *state = plane->state; |
| 113 | 114 | int ret; |
| @@ -91,7 +91,7 @@ static void crtc_flush_all(struct drm_crtc *crtc) · 90 unmodified lines | ||
| 91 | 91 | if (!mdp5_crtc->ctl) |
| 92 | 92 | return; |
| 93 | 93 | |
| 94 | − for_each_plane_on_crtc(crtc, plane) { | |
| 94 | + drm_atomic_crtc_for_each_plane(plane, crtc) { | |
| 95 | 95 | flush_mask |= mdp5_plane_get_flush(plane); |
| 96 | 96 | } |
| 97 | 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) · 26 unmodified lines | ||
| 124 | 124 | } |
| 125 | 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 | 128 | mdp5_plane_complete_flip(plane); |
| 129 | + } | |
| 129 | 130 | } |
| 130 | 131 | |
| 131 | 132 | static void mdp5_crtc_destroy(struct drm_crtc *crtc) |
| @@ -195,7 +196,7 @@ static void blend_setup(struct drm_crtc *crtc) · 63 unmodified lines | ||
| 195 | 196 | if (!mdp5_crtc->ctl) |
| 196 | 197 | goto out; |
| 197 | 198 | |
| 198 | − for_each_plane_on_crtc(crtc, plane) { | |
| 199 | + drm_atomic_crtc_for_each_plane(plane, crtc) { | |
| 199 | 200 | enum mdp_mixer_stage_id stage = |
| 200 | 201 | to_mdp5_plane_state(plane->state)->stage; |
| 201 | 202 | |
| @@ -317,7 +318,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, · 115 unmodified lines | ||
| 317 | 318 | /* verify that there are not too many planes attached to crtc |
| 318 | 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 | 322 | struct drm_plane_state *pstate; |
| 322 | 323 | |
| 323 | 324 | if (cnt >= ARRAY_SIZE(pstates)) { |
| @@ -213,7 +213,8 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, · 212 unmodified lines | ||
| 213 | 213 | return 0; |
| 214 | 214 | } |
| 215 | 215 | |
| 216 | −static void mdp5_plane_atomic_update(struct drm_plane *plane) | |
| 216 | +static void mdp5_plane_atomic_update(struct drm_plane *plane, | |
| 217 | + struct drm_plane_state *old_state) | |
| 217 | 218 | { |
| 218 | 219 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); |
| 219 | 220 | struct drm_plane_state *state = plane->state; |
| @@ -65,27 +65,4 @@ static inline void msm_kms_init(struct msm_kms *kms, · 64 unmodified lines | ||
| 65 | 65 | struct msm_kms *mdp4_kms_init(struct drm_device *dev); |
| 66 | 66 | struct 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 | − | |
| 73 | −static 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 | 68 | #endif /* __MSM_KMS_H__ */ |
| @@ -809,7 +809,7 @@ struct drm_device { · 808 unmodified lines | ||
| 809 | 809 | struct drm_local_map *agp_buffer_map; |
| 810 | 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 | 814 | /** \name GEM information */ |
| 815 | 815 | /*@{ */ |
| @@ -28,6 +28,8 @@ · 27 unmodified lines | ||
| 28 | 28 | #ifndef DRM_ATOMIC_H_ |
| 29 | 29 | #define DRM_ATOMIC_H_ |
| 30 | 30 | |
| 31 | +#include <drm/drm_crtc.h> | |
| 32 | + | |
| 31 | 33 | struct drm_atomic_state * __must_check |
| 32 | 34 | drm_atomic_state_alloc(struct drm_device *dev); |
| 33 | 35 | void drm_atomic_state_clear(struct drm_atomic_state *state); |
| @@ -44,8 +46,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, · 10 unmodified lines | ||
| 44 | 46 | struct drm_connector *connector); |
| 45 | 47 | |
| 46 | 48 | int __must_check |
| 47 | −drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, | |
| 48 | − struct drm_crtc *crtc); | |
| 49 | +drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, | |
| 50 | + struct drm_plane *plane, struct drm_crtc *crtc); | |
| 49 | 51 | void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, |
| 50 | 52 | struct drm_framebuffer *fb); |
| 51 | 53 | int __must_check |
| @@ -28,6 +28,8 @@ · 27 unmodified lines | ||
| 28 | 28 | #ifndef DRM_ATOMIC_HELPER_H_ |
| 29 | 29 | #define DRM_ATOMIC_HELPER_H_ |
| 30 | 30 | |
| 31 | +#include <drm/drm_crtc.h> | |
| 32 | + | |
| 31 | 33 | int drm_atomic_helper_check(struct drm_device *dev, |
| 32 | 34 | struct drm_atomic_state *state); |
| 33 | 35 | int drm_atomic_helper_commit(struct drm_device *dev, |
| @@ -96,5 +98,29 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); · 62 unmodified lines | ||
| 96 | 98 | void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, |
| 97 | 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 | 126 | #endif /* DRM_ATOMIC_HELPER_H_ */ |
| @@ -231,6 +231,7 @@ struct drm_atomic_state; · 230 unmodified lines | ||
| 231 | 231 | * struct drm_crtc_state - mutable CRTC state |
| 232 | 232 | * @enable: whether the CRTC should be enabled, gates all other state |
| 233 | 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 | 235 | * @last_vblank_count: for helpers and drivers to capture the vblank of the |
| 235 | 236 | * update to ensure framebuffer cleanup isn't done too early |
| 236 | 237 | * @planes_changed: for use by helpers and drivers when computing state updates |
| @@ -247,6 +248,13 @@ struct drm_crtc_state { · 10 unmodified lines | ||
| 247 | 248 | bool planes_changed : 1; |
| 248 | 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 | 258 | /* last_vblank_count: for vblank waits before cleanup */ |
| 251 | 259 | u32 last_vblank_count; |
| 252 | 260 | |
| @@ -438,7 +446,7 @@ struct drm_crtc { · 185 unmodified lines | ||
| 438 | 446 | * @state: backpointer to global drm_atomic_state |
| 439 | 447 | */ |
| 440 | 448 | struct 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 | 451 | struct drm_encoder *best_encoder; |
| 444 | 452 | |
| @@ -673,8 +681,8 @@ struct drm_connector { · 228 unmodified lines | ||
| 673 | 681 | * @state: backpointer to global drm_atomic_state |
| 674 | 682 | */ |
| 675 | 683 | struct drm_plane_state { |
| 676 | − struct drm_crtc *crtc; | |
| 677 | − struct drm_framebuffer *fb; | |
| 684 | + struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ | |
| 685 | + struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ | |
| 678 | 686 | struct fence *fence; |
| 679 | 687 | |
| 680 | 688 | /* Signed dest location allows it to be partially off screen */ |
| @@ -1054,6 +1062,19 @@ struct drm_mode_config { · 373 unmodified lines | ||
| 1054 | 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 | 1078 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) |
| 1058 | 1079 | #define obj_to_connector(x) container_of(x, struct drm_connector, base) |
| 1059 | 1080 | #define obj_to_encoder(x) container_of(x, struct drm_encoder, base) |
| @@ -49,6 +49,10 @@ extern int drm_crtc_init(struct drm_device *dev, · 48 unmodified lines | ||
| 49 | 49 | |
| 50 | 50 | /** |
| 51 | 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 | 57 | * The helper operations are called by the mid-layer CRTC helper. |
| 54 | 58 | */ |
| @@ -60,7 +64,8 @@ struct drm_plane_helper_funcs { · 5 unmodified lines | ||
| 60 | 64 | |
| 61 | 65 | int (*atomic_check)(struct drm_plane *plane, |
| 62 | 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 | |
| 66 | 71 | static inline void drm_plane_helper_add(struct drm_plane *plane, |