diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
| -rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 316 |
1 files changed, 235 insertions, 81 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aecb5d69bc2d..87a2a446d2b7 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
| @@ -42,14 +42,14 @@ | |||
| 42 | * add their own additional internal state. | 42 | * add their own additional internal state. |
| 43 | * | 43 | * |
| 44 | * This library also provides default implementations for the check callback in | 44 | * This library also provides default implementations for the check callback in |
| 45 | * drm_atomic_helper_check and for the commit callback with | 45 | * drm_atomic_helper_check() and for the commit callback with |
| 46 | * drm_atomic_helper_commit. But the individual stages and callbacks are expose | 46 | * drm_atomic_helper_commit(). But the individual stages and callbacks are |
| 47 | * to allow drivers to mix and match and e.g. use the plane helpers only | 47 | * exposed to allow drivers to mix and match and e.g. use the plane helpers only |
| 48 | * together with a driver private modeset implementation. | 48 | * together with a driver private modeset implementation. |
| 49 | * | 49 | * |
| 50 | * This library also provides implementations for all the legacy driver | 50 | * This library also provides implementations for all the legacy driver |
| 51 | * interfaces on top of the atomic interface. See drm_atomic_helper_set_config, | 51 | * interfaces on top of the atomic interface. See drm_atomic_helper_set_config(), |
| 52 | * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the | 52 | * drm_atomic_helper_disable_plane(), drm_atomic_helper_disable_plane() and the |
| 53 | * various functions to implement set_property callbacks. New drivers must not | 53 | * various functions to implement set_property callbacks. New drivers must not |
| 54 | * implement these functions themselves but must use the provided helpers. | 54 | * implement these functions themselves but must use the provided helpers. |
| 55 | */ | 55 | */ |
| @@ -993,6 +993,22 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); | |||
| 993 | * object. This can still fail when e.g. the framebuffer reservation fails. For | 993 | * object. This can still fail when e.g. the framebuffer reservation fails. For |
| 994 | * now this doesn't implement asynchronous commits. | 994 | * now this doesn't implement asynchronous commits. |
| 995 | * | 995 | * |
| 996 | * Note that right now this function does not support async commits, and hence | ||
| 997 | * driver writers must implement their own version for now. Also note that the | ||
| 998 | * default ordering of how the various stages are called is to match the legacy | ||
| 999 | * modeset helper library closest. One peculiarity of that is that it doesn't | ||
| 1000 | * mesh well with runtime PM at all. | ||
| 1001 | * | ||
| 1002 | * For drivers supporting runtime PM the recommended sequence is | ||
| 1003 | * | ||
| 1004 | * drm_atomic_helper_commit_modeset_disables(dev, state); | ||
| 1005 | * | ||
| 1006 | * drm_atomic_helper_commit_modeset_enables(dev, state); | ||
| 1007 | * | ||
| 1008 | * drm_atomic_helper_commit_planes(dev, state, true); | ||
| 1009 | * | ||
| 1010 | * See the kerneldoc entries for these three functions for more details. | ||
| 1011 | * | ||
| 996 | * RETURNS | 1012 | * RETURNS |
| 997 | * Zero for success or -errno. | 1013 | * Zero for success or -errno. |
| 998 | */ | 1014 | */ |
| @@ -1037,7 +1053,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, | |||
| 1037 | 1053 | ||
| 1038 | drm_atomic_helper_commit_modeset_disables(dev, state); | 1054 | drm_atomic_helper_commit_modeset_disables(dev, state); |
| 1039 | 1055 | ||
| 1040 | drm_atomic_helper_commit_planes(dev, state); | 1056 | drm_atomic_helper_commit_planes(dev, state, false); |
| 1041 | 1057 | ||
| 1042 | drm_atomic_helper_commit_modeset_enables(dev, state); | 1058 | drm_atomic_helper_commit_modeset_enables(dev, state); |
| 1043 | 1059 | ||
| @@ -1077,7 +1093,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); | |||
| 1077 | * work item, which allows nice concurrent updates on disjoint sets of crtcs. | 1093 | * work item, which allows nice concurrent updates on disjoint sets of crtcs. |
| 1078 | * | 1094 | * |
| 1079 | * 3. The software state is updated synchronously with | 1095 | * 3. The software state is updated synchronously with |
| 1080 | * drm_atomic_helper_swap_state. Doing this under the protection of all modeset | 1096 | * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset |
| 1081 | * locks means concurrent callers never see inconsistent state. And doing this | 1097 | * locks means concurrent callers never see inconsistent state. And doing this |
| 1082 | * while it's guaranteed that no relevant async worker runs means that async | 1098 | * while it's guaranteed that no relevant async worker runs means that async |
| 1083 | * workers do not need grab any locks. Actually they must not grab locks, for | 1099 | * workers do not need grab any locks. Actually they must not grab locks, for |
| @@ -1111,17 +1127,14 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev, | |||
| 1111 | const struct drm_plane_helper_funcs *funcs; | 1127 | const struct drm_plane_helper_funcs *funcs; |
| 1112 | struct drm_plane *plane = state->planes[i]; | 1128 | struct drm_plane *plane = state->planes[i]; |
| 1113 | struct drm_plane_state *plane_state = state->plane_states[i]; | 1129 | struct drm_plane_state *plane_state = state->plane_states[i]; |
| 1114 | struct drm_framebuffer *fb; | ||
| 1115 | 1130 | ||
| 1116 | if (!plane) | 1131 | if (!plane) |
| 1117 | continue; | 1132 | continue; |
| 1118 | 1133 | ||
| 1119 | funcs = plane->helper_private; | 1134 | funcs = plane->helper_private; |
| 1120 | 1135 | ||
| 1121 | fb = plane_state->fb; | 1136 | if (funcs->prepare_fb) { |
| 1122 | 1137 | ret = funcs->prepare_fb(plane, plane_state); | |
| 1123 | if (fb && funcs->prepare_fb) { | ||
| 1124 | ret = funcs->prepare_fb(plane, fb, plane_state); | ||
| 1125 | if (ret) | 1138 | if (ret) |
| 1126 | goto fail; | 1139 | goto fail; |
| 1127 | } | 1140 | } |
| @@ -1134,17 +1147,14 @@ fail: | |||
| 1134 | const struct drm_plane_helper_funcs *funcs; | 1147 | const struct drm_plane_helper_funcs *funcs; |
| 1135 | struct drm_plane *plane = state->planes[i]; | 1148 | struct drm_plane *plane = state->planes[i]; |
| 1136 | struct drm_plane_state *plane_state = state->plane_states[i]; | 1149 | struct drm_plane_state *plane_state = state->plane_states[i]; |
| 1137 | struct drm_framebuffer *fb; | ||
| 1138 | 1150 | ||
| 1139 | if (!plane) | 1151 | if (!plane) |
| 1140 | continue; | 1152 | continue; |
| 1141 | 1153 | ||
| 1142 | funcs = plane->helper_private; | 1154 | funcs = plane->helper_private; |
| 1143 | 1155 | ||
| 1144 | fb = state->plane_states[i]->fb; | 1156 | if (funcs->cleanup_fb) |
| 1145 | 1157 | funcs->cleanup_fb(plane, plane_state); | |
| 1146 | if (fb && funcs->cleanup_fb) | ||
| 1147 | funcs->cleanup_fb(plane, fb, plane_state); | ||
| 1148 | 1158 | ||
| 1149 | } | 1159 | } |
| 1150 | 1160 | ||
| @@ -1152,10 +1162,16 @@ fail: | |||
| 1152 | } | 1162 | } |
| 1153 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); | 1163 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); |
| 1154 | 1164 | ||
| 1165 | bool plane_crtc_active(struct drm_plane_state *state) | ||
| 1166 | { | ||
| 1167 | return state->crtc && state->crtc->state->active; | ||
| 1168 | } | ||
| 1169 | |||
| 1155 | /** | 1170 | /** |
| 1156 | * drm_atomic_helper_commit_planes - commit plane state | 1171 | * drm_atomic_helper_commit_planes - commit plane state |
| 1157 | * @dev: DRM device | 1172 | * @dev: DRM device |
| 1158 | * @old_state: atomic state object with old state structures | 1173 | * @old_state: atomic state object with old state structures |
| 1174 | * @active_only: Only commit on active CRTC if set | ||
| 1159 | * | 1175 | * |
| 1160 | * This function commits the new plane state using the plane and atomic helper | 1176 | * This function commits the new plane state using the plane and atomic helper |
| 1161 | * functions for planes and crtcs. It assumes that the atomic state has already | 1177 | * functions for planes and crtcs. It assumes that the atomic state has already |
| @@ -1168,9 +1184,26 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); | |||
| 1168 | * Note that this function does all plane updates across all CRTCs in one step. | 1184 | * Note that this function does all plane updates across all CRTCs in one step. |
| 1169 | * If the hardware can't support this approach look at | 1185 | * If the hardware can't support this approach look at |
| 1170 | * drm_atomic_helper_commit_planes_on_crtc() instead. | 1186 | * drm_atomic_helper_commit_planes_on_crtc() instead. |
| 1187 | * | ||
| 1188 | * Plane parameters can be updated by applications while the associated CRTC is | ||
| 1189 | * disabled. The DRM/KMS core will store the parameters in the plane state, | ||
| 1190 | * which will be available to the driver when the CRTC is turned on. As a result | ||
| 1191 | * most drivers don't need to be immediately notified of plane updates for a | ||
| 1192 | * disabled CRTC. | ||
| 1193 | * | ||
| 1194 | * Unless otherwise needed, drivers are advised to set the @active_only | ||
| 1195 | * parameters to true in order not to receive plane update notifications related | ||
| 1196 | * to a disabled CRTC. This avoids the need to manually ignore plane updates in | ||
| 1197 | * driver code when the driver and/or hardware can't or just don't need to deal | ||
| 1198 | * with updates on disabled CRTCs, for example when supporting runtime PM. | ||
| 1199 | * | ||
| 1200 | * The drm_atomic_helper_commit() default implementation only sets @active_only | ||
| 1201 | * to false to most closely match the behaviour of the legacy helpers. This should | ||
| 1202 | * not be copied blindly by drivers. | ||
| 1171 | */ | 1203 | */ |
| 1172 | void drm_atomic_helper_commit_planes(struct drm_device *dev, | 1204 | void drm_atomic_helper_commit_planes(struct drm_device *dev, |
| 1173 | struct drm_atomic_state *old_state) | 1205 | struct drm_atomic_state *old_state, |
| 1206 | bool active_only) | ||
| 1174 | { | 1207 | { |
| 1175 | struct drm_crtc *crtc; | 1208 | struct drm_crtc *crtc; |
| 1176 | struct drm_crtc_state *old_crtc_state; | 1209 | struct drm_crtc_state *old_crtc_state; |
| @@ -1186,25 +1219,43 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, | |||
| 1186 | if (!funcs || !funcs->atomic_begin) | 1219 | if (!funcs || !funcs->atomic_begin) |
| 1187 | continue; | 1220 | continue; |
| 1188 | 1221 | ||
| 1222 | if (active_only && !crtc->state->active) | ||
| 1223 | continue; | ||
| 1224 | |||
| 1189 | funcs->atomic_begin(crtc, old_crtc_state); | 1225 | funcs->atomic_begin(crtc, old_crtc_state); |
| 1190 | } | 1226 | } |
| 1191 | 1227 | ||
| 1192 | for_each_plane_in_state(old_state, plane, old_plane_state, i) { | 1228 | for_each_plane_in_state(old_state, plane, old_plane_state, i) { |
| 1193 | const struct drm_plane_helper_funcs *funcs; | 1229 | const struct drm_plane_helper_funcs *funcs; |
| 1230 | bool disabling; | ||
| 1194 | 1231 | ||
| 1195 | funcs = plane->helper_private; | 1232 | funcs = plane->helper_private; |
| 1196 | 1233 | ||
| 1197 | if (!funcs) | 1234 | if (!funcs) |
| 1198 | continue; | 1235 | continue; |
| 1199 | 1236 | ||
| 1237 | disabling = drm_atomic_plane_disabling(plane, old_plane_state); | ||
| 1238 | |||
| 1239 | if (active_only) { | ||
| 1240 | /* | ||
| 1241 | * Skip planes related to inactive CRTCs. If the plane | ||
| 1242 | * is enabled use the state of the current CRTC. If the | ||
| 1243 | * plane is being disabled use the state of the old | ||
| 1244 | * CRTC to avoid skipping planes being disabled on an | ||
| 1245 | * active CRTC. | ||
| 1246 | */ | ||
| 1247 | if (!disabling && !plane_crtc_active(plane->state)) | ||
| 1248 | continue; | ||
| 1249 | if (disabling && !plane_crtc_active(old_plane_state)) | ||
| 1250 | continue; | ||
| 1251 | } | ||
| 1252 | |||
| 1200 | /* | 1253 | /* |
| 1201 | * Special-case disabling the plane if drivers support it. | 1254 | * Special-case disabling the plane if drivers support it. |
| 1202 | */ | 1255 | */ |
| 1203 | if (drm_atomic_plane_disabling(plane, old_plane_state) && | 1256 | if (disabling && funcs->atomic_disable) |
| 1204 | funcs->atomic_disable) | ||
| 1205 | funcs->atomic_disable(plane, old_plane_state); | 1257 | funcs->atomic_disable(plane, old_plane_state); |
| 1206 | else if (plane->state->crtc || | 1258 | else if (plane->state->crtc || disabling) |
| 1207 | drm_atomic_plane_disabling(plane, old_plane_state)) | ||
| 1208 | funcs->atomic_update(plane, old_plane_state); | 1259 | funcs->atomic_update(plane, old_plane_state); |
| 1209 | } | 1260 | } |
| 1210 | 1261 | ||
| @@ -1216,6 +1267,9 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, | |||
| 1216 | if (!funcs || !funcs->atomic_flush) | 1267 | if (!funcs || !funcs->atomic_flush) |
| 1217 | continue; | 1268 | continue; |
| 1218 | 1269 | ||
| 1270 | if (active_only && !crtc->state->active) | ||
| 1271 | continue; | ||
| 1272 | |||
| 1219 | funcs->atomic_flush(crtc, old_crtc_state); | 1273 | funcs->atomic_flush(crtc, old_crtc_state); |
| 1220 | } | 1274 | } |
| 1221 | } | 1275 | } |
| @@ -1300,14 +1354,11 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev, | |||
| 1300 | 1354 | ||
| 1301 | for_each_plane_in_state(old_state, plane, plane_state, i) { | 1355 | for_each_plane_in_state(old_state, plane, plane_state, i) { |
| 1302 | const struct drm_plane_helper_funcs *funcs; | 1356 | const struct drm_plane_helper_funcs *funcs; |
| 1303 | struct drm_framebuffer *old_fb; | ||
| 1304 | 1357 | ||
| 1305 | funcs = plane->helper_private; | 1358 | funcs = plane->helper_private; |
| 1306 | 1359 | ||
| 1307 | old_fb = plane_state->fb; | 1360 | if (funcs->cleanup_fb) |
| 1308 | 1361 | funcs->cleanup_fb(plane, plane_state); | |
| 1309 | if (old_fb && funcs->cleanup_fb) | ||
| 1310 | funcs->cleanup_fb(plane, old_fb, plane_state); | ||
| 1311 | } | 1362 | } |
| 1312 | } | 1363 | } |
| 1313 | EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); | 1364 | EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); |
| @@ -1334,7 +1385,7 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); | |||
| 1334 | * | 1385 | * |
| 1335 | * 4. Actually commit the hardware state. | 1386 | * 4. Actually commit the hardware state. |
| 1336 | * | 1387 | * |
| 1337 | * 5. Call drm_atomic_helper_cleanup_planes with @state, which since step 3 | 1388 | * 5. Call drm_atomic_helper_cleanup_planes() with @state, which since step 3 |
| 1338 | * contains the old state. Also do any other cleanup required with that state. | 1389 | * contains the old state. Also do any other cleanup required with that state. |
| 1339 | */ | 1390 | */ |
| 1340 | void drm_atomic_helper_swap_state(struct drm_device *dev, | 1391 | void drm_atomic_helper_swap_state(struct drm_device *dev, |
| @@ -1502,21 +1553,9 @@ retry: | |||
| 1502 | goto fail; | 1553 | goto fail; |
| 1503 | } | 1554 | } |
| 1504 | 1555 | ||
| 1505 | ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); | 1556 | ret = __drm_atomic_helper_disable_plane(plane, plane_state); |
| 1506 | if (ret != 0) | 1557 | if (ret != 0) |
| 1507 | goto fail; | 1558 | goto fail; |
| 1508 | drm_atomic_set_fb_for_plane(plane_state, NULL); | ||
| 1509 | plane_state->crtc_x = 0; | ||
| 1510 | plane_state->crtc_y = 0; | ||
| 1511 | plane_state->crtc_h = 0; | ||
| 1512 | plane_state->crtc_w = 0; | ||
| 1513 | plane_state->src_x = 0; | ||
| 1514 | plane_state->src_y = 0; | ||
| 1515 | plane_state->src_h = 0; | ||
| 1516 | plane_state->src_w = 0; | ||
| 1517 | |||
| 1518 | if (plane == plane->crtc->cursor) | ||
| 1519 | state->legacy_cursor_update = true; | ||
| 1520 | 1559 | ||
| 1521 | ret = drm_atomic_commit(state); | 1560 | ret = drm_atomic_commit(state); |
| 1522 | if (ret != 0) | 1561 | if (ret != 0) |
| @@ -1546,6 +1585,32 @@ backoff: | |||
| 1546 | } | 1585 | } |
| 1547 | EXPORT_SYMBOL(drm_atomic_helper_disable_plane); | 1586 | EXPORT_SYMBOL(drm_atomic_helper_disable_plane); |
| 1548 | 1587 | ||
| 1588 | /* just used from fb-helper and atomic-helper: */ | ||
| 1589 | int __drm_atomic_helper_disable_plane(struct drm_plane *plane, | ||
| 1590 | struct drm_plane_state *plane_state) | ||
| 1591 | { | ||
| 1592 | int ret; | ||
| 1593 | |||
| 1594 | ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); | ||
| 1595 | if (ret != 0) | ||
| 1596 | return ret; | ||
| 1597 | |||
| 1598 | drm_atomic_set_fb_for_plane(plane_state, NULL); | ||
| 1599 | plane_state->crtc_x = 0; | ||
| 1600 | plane_state->crtc_y = 0; | ||
| 1601 | plane_state->crtc_h = 0; | ||
| 1602 | plane_state->crtc_w = 0; | ||
| 1603 | plane_state->src_x = 0; | ||
| 1604 | plane_state->src_y = 0; | ||
| 1605 | plane_state->src_h = 0; | ||
| 1606 | plane_state->src_w = 0; | ||
| 1607 | |||
| 1608 | if (plane->crtc && (plane == plane->crtc->cursor)) | ||
| 1609 | plane_state->state->legacy_cursor_update = true; | ||
| 1610 | |||
| 1611 | return 0; | ||
| 1612 | } | ||
| 1613 | |||
| 1549 | static int update_output_state(struct drm_atomic_state *state, | 1614 | static int update_output_state(struct drm_atomic_state *state, |
| 1550 | struct drm_mode_set *set) | 1615 | struct drm_mode_set *set) |
| 1551 | { | 1616 | { |
| @@ -1629,8 +1694,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) | |||
| 1629 | { | 1694 | { |
| 1630 | struct drm_atomic_state *state; | 1695 | struct drm_atomic_state *state; |
| 1631 | struct drm_crtc *crtc = set->crtc; | 1696 | struct drm_crtc *crtc = set->crtc; |
| 1632 | struct drm_crtc_state *crtc_state; | ||
| 1633 | struct drm_plane_state *primary_state; | ||
| 1634 | int ret = 0; | 1697 | int ret = 0; |
| 1635 | 1698 | ||
| 1636 | state = drm_atomic_state_alloc(crtc->dev); | 1699 | state = drm_atomic_state_alloc(crtc->dev); |
| @@ -1639,17 +1702,54 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) | |||
| 1639 | 1702 | ||
| 1640 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); | 1703 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); |
| 1641 | retry: | 1704 | retry: |
| 1642 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | 1705 | ret = __drm_atomic_helper_set_config(set, state); |
| 1643 | if (IS_ERR(crtc_state)) { | 1706 | if (ret != 0) |
| 1644 | ret = PTR_ERR(crtc_state); | ||
| 1645 | goto fail; | 1707 | goto fail; |
| 1646 | } | ||
| 1647 | 1708 | ||
| 1648 | primary_state = drm_atomic_get_plane_state(state, crtc->primary); | 1709 | ret = drm_atomic_commit(state); |
| 1649 | if (IS_ERR(primary_state)) { | 1710 | if (ret != 0) |
| 1650 | ret = PTR_ERR(primary_state); | ||
| 1651 | goto fail; | 1711 | goto fail; |
| 1652 | } | 1712 | |
| 1713 | /* Driver takes ownership of state on successful commit. */ | ||
| 1714 | return 0; | ||
| 1715 | fail: | ||
| 1716 | if (ret == -EDEADLK) | ||
| 1717 | goto backoff; | ||
| 1718 | |||
| 1719 | drm_atomic_state_free(state); | ||
| 1720 | |||
| 1721 | return ret; | ||
| 1722 | backoff: | ||
| 1723 | drm_atomic_state_clear(state); | ||
| 1724 | drm_atomic_legacy_backoff(state); | ||
| 1725 | |||
| 1726 | /* | ||
| 1727 | * Someone might have exchanged the framebuffer while we dropped locks | ||
| 1728 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
| 1729 | * core does for us. | ||
| 1730 | */ | ||
| 1731 | crtc->primary->old_fb = crtc->primary->fb; | ||
| 1732 | |||
| 1733 | goto retry; | ||
| 1734 | } | ||
| 1735 | EXPORT_SYMBOL(drm_atomic_helper_set_config); | ||
| 1736 | |||
| 1737 | /* just used from fb-helper and atomic-helper: */ | ||
| 1738 | int __drm_atomic_helper_set_config(struct drm_mode_set *set, | ||
| 1739 | struct drm_atomic_state *state) | ||
| 1740 | { | ||
| 1741 | struct drm_crtc_state *crtc_state; | ||
| 1742 | struct drm_plane_state *primary_state; | ||
| 1743 | struct drm_crtc *crtc = set->crtc; | ||
| 1744 | int ret; | ||
| 1745 | |||
| 1746 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
| 1747 | if (IS_ERR(crtc_state)) | ||
| 1748 | return PTR_ERR(crtc_state); | ||
| 1749 | |||
| 1750 | primary_state = drm_atomic_get_plane_state(state, crtc->primary); | ||
| 1751 | if (IS_ERR(primary_state)) | ||
| 1752 | return PTR_ERR(primary_state); | ||
| 1653 | 1753 | ||
| 1654 | if (!set->mode) { | 1754 | if (!set->mode) { |
| 1655 | WARN_ON(set->fb); | 1755 | WARN_ON(set->fb); |
| @@ -1657,13 +1757,13 @@ retry: | |||
| 1657 | 1757 | ||
| 1658 | ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); | 1758 | ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); |
| 1659 | if (ret != 0) | 1759 | if (ret != 0) |
| 1660 | goto fail; | 1760 | return ret; |
| 1661 | 1761 | ||
| 1662 | crtc_state->active = false; | 1762 | crtc_state->active = false; |
| 1663 | 1763 | ||
| 1664 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); | 1764 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); |
| 1665 | if (ret != 0) | 1765 | if (ret != 0) |
| 1666 | goto fail; | 1766 | return ret; |
| 1667 | 1767 | ||
| 1668 | drm_atomic_set_fb_for_plane(primary_state, NULL); | 1768 | drm_atomic_set_fb_for_plane(primary_state, NULL); |
| 1669 | 1769 | ||
| @@ -1675,13 +1775,14 @@ retry: | |||
| 1675 | 1775 | ||
| 1676 | ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); | 1776 | ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); |
| 1677 | if (ret != 0) | 1777 | if (ret != 0) |
| 1678 | goto fail; | 1778 | return ret; |
| 1679 | 1779 | ||
| 1680 | crtc_state->active = true; | 1780 | crtc_state->active = true; |
| 1681 | 1781 | ||
| 1682 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); | 1782 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); |
| 1683 | if (ret != 0) | 1783 | if (ret != 0) |
| 1684 | goto fail; | 1784 | return ret; |
| 1785 | |||
| 1685 | drm_atomic_set_fb_for_plane(primary_state, set->fb); | 1786 | drm_atomic_set_fb_for_plane(primary_state, set->fb); |
| 1686 | primary_state->crtc_x = 0; | 1787 | primary_state->crtc_x = 0; |
| 1687 | primary_state->crtc_y = 0; | 1788 | primary_state->crtc_y = 0; |
| @@ -1695,35 +1796,10 @@ retry: | |||
| 1695 | commit: | 1796 | commit: |
| 1696 | ret = update_output_state(state, set); | 1797 | ret = update_output_state(state, set); |
| 1697 | if (ret) | 1798 | if (ret) |
| 1698 | goto fail; | 1799 | return ret; |
| 1699 | |||
| 1700 | ret = drm_atomic_commit(state); | ||
| 1701 | if (ret != 0) | ||
| 1702 | goto fail; | ||
| 1703 | 1800 | ||
| 1704 | /* Driver takes ownership of state on successful commit. */ | ||
| 1705 | return 0; | 1801 | return 0; |
| 1706 | fail: | ||
| 1707 | if (ret == -EDEADLK) | ||
| 1708 | goto backoff; | ||
| 1709 | |||
| 1710 | drm_atomic_state_free(state); | ||
| 1711 | |||
| 1712 | return ret; | ||
| 1713 | backoff: | ||
| 1714 | drm_atomic_state_clear(state); | ||
| 1715 | drm_atomic_legacy_backoff(state); | ||
| 1716 | |||
| 1717 | /* | ||
| 1718 | * Someone might have exchanged the framebuffer while we dropped locks | ||
| 1719 | * in the backoff code. We need to fix up the fb refcount tracking the | ||
| 1720 | * core does for us. | ||
| 1721 | */ | ||
| 1722 | crtc->primary->old_fb = crtc->primary->fb; | ||
| 1723 | |||
| 1724 | goto retry; | ||
| 1725 | } | 1802 | } |
| 1726 | EXPORT_SYMBOL(drm_atomic_helper_set_config); | ||
| 1727 | 1803 | ||
| 1728 | /** | 1804 | /** |
| 1729 | * drm_atomic_helper_crtc_set_property - helper for crtc properties | 1805 | * drm_atomic_helper_crtc_set_property - helper for crtc properties |
| @@ -2333,6 +2409,84 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) | |||
| 2333 | EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); | 2409 | EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); |
| 2334 | 2410 | ||
| 2335 | /** | 2411 | /** |
| 2412 | * drm_atomic_helper_duplicate_state - duplicate an atomic state object | ||
| 2413 | * @dev: DRM device | ||
| 2414 | * @ctx: lock acquisition context | ||
| 2415 | * | ||
| 2416 | * Makes a copy of the current atomic state by looping over all objects and | ||
| 2417 | * duplicating their respective states. | ||
| 2418 | * | ||
| 2419 | * Note that this treats atomic state as persistent between save and restore. | ||
| 2420 | * Drivers must make sure that this is possible and won't result in confusion | ||
| 2421 | * or erroneous behaviour. | ||
| 2422 | * | ||
| 2423 | * Note that if callers haven't already acquired all modeset locks this might | ||
| 2424 | * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). | ||
| 2425 | * | ||
| 2426 | * Returns: | ||
| 2427 | * A pointer to the copy of the atomic state object on success or an | ||
| 2428 | * ERR_PTR()-encoded error code on failure. | ||
| 2429 | */ | ||
| 2430 | struct drm_atomic_state * | ||
| 2431 | drm_atomic_helper_duplicate_state(struct drm_device *dev, | ||
| 2432 | struct drm_modeset_acquire_ctx *ctx) | ||
| 2433 | { | ||
| 2434 | struct drm_atomic_state *state; | ||
| 2435 | struct drm_connector *conn; | ||
| 2436 | struct drm_plane *plane; | ||
| 2437 | struct drm_crtc *crtc; | ||
| 2438 | int err = 0; | ||
| 2439 | |||
| 2440 | state = drm_atomic_state_alloc(dev); | ||
| 2441 | if (!state) | ||
| 2442 | return ERR_PTR(-ENOMEM); | ||
| 2443 | |||
| 2444 | state->acquire_ctx = ctx; | ||
| 2445 | |||
| 2446 | drm_for_each_crtc(crtc, dev) { | ||
| 2447 | struct drm_crtc_state *crtc_state; | ||
| 2448 | |||
| 2449 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
| 2450 | if (IS_ERR(crtc_state)) { | ||
| 2451 | err = PTR_ERR(crtc_state); | ||
| 2452 | goto free; | ||
| 2453 | } | ||
| 2454 | } | ||
| 2455 | |||
| 2456 | drm_for_each_plane(plane, dev) { | ||
| 2457 | struct drm_plane_state *plane_state; | ||
| 2458 | |||
| 2459 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
| 2460 | if (IS_ERR(plane_state)) { | ||
| 2461 | err = PTR_ERR(plane_state); | ||
| 2462 | goto free; | ||
| 2463 | } | ||
| 2464 | } | ||
| 2465 | |||
| 2466 | drm_for_each_connector(conn, dev) { | ||
| 2467 | struct drm_connector_state *conn_state; | ||
| 2468 | |||
| 2469 | conn_state = drm_atomic_get_connector_state(state, conn); | ||
| 2470 | if (IS_ERR(conn_state)) { | ||
| 2471 | err = PTR_ERR(conn_state); | ||
| 2472 | goto free; | ||
| 2473 | } | ||
| 2474 | } | ||
| 2475 | |||
| 2476 | /* clear the acquire context so that it isn't accidentally reused */ | ||
| 2477 | state->acquire_ctx = NULL; | ||
| 2478 | |||
| 2479 | free: | ||
| 2480 | if (err < 0) { | ||
| 2481 | drm_atomic_state_free(state); | ||
| 2482 | state = ERR_PTR(err); | ||
| 2483 | } | ||
| 2484 | |||
| 2485 | return state; | ||
| 2486 | } | ||
| 2487 | EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); | ||
| 2488 | |||
| 2489 | /** | ||
| 2336 | * __drm_atomic_helper_connector_destroy_state - release connector state | 2490 | * __drm_atomic_helper_connector_destroy_state - release connector state |
| 2337 | * @connector: connector object | 2491 | * @connector: connector object |
| 2338 | * @state: connector state object to release | 2492 | * @state: connector state object to release |
