@@ -80,6 +80,27 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
80
80
}
81
81
}
82
82
83
+ static bool
84
+ check_pending_encoder_assignment (struct drm_atomic_state * state ,
85
+ struct drm_encoder * new_encoder ,
86
+ struct drm_connector * new_connector )
87
+ {
88
+ struct drm_connector * connector ;
89
+ struct drm_connector_state * conn_state ;
90
+ int i ;
91
+
92
+ for_each_connector_in_state (state , connector , conn_state , i ) {
93
+ if (conn_state -> best_encoder != new_encoder )
94
+ continue ;
95
+
96
+ /* encoder already assigned and we're trying to re-steal it! */
97
+ if (connector -> state -> best_encoder != conn_state -> best_encoder )
98
+ return false;
99
+ }
100
+
101
+ return true;
102
+ }
103
+
83
104
static struct drm_crtc *
84
105
get_current_crtc_for_encoder (struct drm_device * dev ,
85
106
struct drm_encoder * encoder )
@@ -229,6 +250,13 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
229
250
return 0 ;
230
251
}
231
252
253
+ if (!check_pending_encoder_assignment (state , new_encoder , connector )) {
254
+ DRM_DEBUG_ATOMIC ("Encoder for [CONNECTOR:%d:%s] already assigned\n" ,
255
+ connector -> base .id ,
256
+ connector -> name );
257
+ return - EINVAL ;
258
+ }
259
+
232
260
encoder_crtc = get_current_crtc_for_encoder (state -> dev ,
233
261
new_encoder );
234
262
@@ -1341,6 +1369,49 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
1341
1369
}
1342
1370
EXPORT_SYMBOL (drm_atomic_helper_commit_planes_on_crtc );
1343
1371
1372
+ /**
1373
+ * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
1374
+ * @crtc: CRTC
1375
+ * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
1376
+ *
1377
+ * Disables all planes associated with the given CRTC. This can be
1378
+ * used for instance in the CRTC helper disable callback to disable
1379
+ * all planes before shutting down the display pipeline.
1380
+ *
1381
+ * If the atomic-parameter is set the function calls the CRTC's
1382
+ * atomic_begin hook before and atomic_flush hook after disabling the
1383
+ * planes.
1384
+ *
1385
+ * It is a bug to call this function without having implemented the
1386
+ * ->atomic_disable() plane hook.
1387
+ */
1388
+ void drm_atomic_helper_disable_planes_on_crtc (struct drm_crtc * crtc ,
1389
+ bool atomic )
1390
+ {
1391
+ const struct drm_crtc_helper_funcs * crtc_funcs =
1392
+ crtc -> helper_private ;
1393
+ struct drm_plane * plane ;
1394
+
1395
+ if (atomic && crtc_funcs && crtc_funcs -> atomic_begin )
1396
+ crtc_funcs -> atomic_begin (crtc , NULL );
1397
+
1398
+ drm_for_each_plane (plane , crtc -> dev ) {
1399
+ const struct drm_plane_helper_funcs * plane_funcs =
1400
+ plane -> helper_private ;
1401
+
1402
+ if (plane -> state -> crtc != crtc || !plane_funcs )
1403
+ continue ;
1404
+
1405
+ WARN_ON (!plane_funcs -> atomic_disable );
1406
+ if (plane_funcs -> atomic_disable )
1407
+ plane_funcs -> atomic_disable (plane , NULL );
1408
+ }
1409
+
1410
+ if (atomic && crtc_funcs && crtc_funcs -> atomic_flush )
1411
+ crtc_funcs -> atomic_flush (crtc , NULL );
1412
+ }
1413
+ EXPORT_SYMBOL (drm_atomic_helper_disable_planes_on_crtc );
1414
+
1344
1415
/**
1345
1416
* drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
1346
1417
* @dev: DRM device
@@ -1817,6 +1888,161 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
1817
1888
return 0 ;
1818
1889
}
1819
1890
1891
+ /**
1892
+ * drm_atomic_helper_disable_all - disable all currently active outputs
1893
+ * @dev: DRM device
1894
+ * @ctx: lock acquisition context
1895
+ *
1896
+ * Loops through all connectors, finding those that aren't turned off and then
1897
+ * turns them off by setting their DPMS mode to OFF and deactivating the CRTC
1898
+ * that they are connected to.
1899
+ *
1900
+ * This is used for example in suspend/resume to disable all currently active
1901
+ * functions when suspending.
1902
+ *
1903
+ * Note that if callers haven't already acquired all modeset locks this might
1904
+ * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
1905
+ *
1906
+ * Returns:
1907
+ * 0 on success or a negative error code on failure.
1908
+ *
1909
+ * See also:
1910
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
1911
+ */
1912
+ int drm_atomic_helper_disable_all (struct drm_device * dev ,
1913
+ struct drm_modeset_acquire_ctx * ctx )
1914
+ {
1915
+ struct drm_atomic_state * state ;
1916
+ struct drm_connector * conn ;
1917
+ int err ;
1918
+
1919
+ state = drm_atomic_state_alloc (dev );
1920
+ if (!state )
1921
+ return - ENOMEM ;
1922
+
1923
+ state -> acquire_ctx = ctx ;
1924
+
1925
+ drm_for_each_connector (conn , dev ) {
1926
+ struct drm_crtc * crtc = conn -> state -> crtc ;
1927
+ struct drm_crtc_state * crtc_state ;
1928
+
1929
+ if (!crtc || conn -> dpms != DRM_MODE_DPMS_ON )
1930
+ continue ;
1931
+
1932
+ crtc_state = drm_atomic_get_crtc_state (state , crtc );
1933
+ if (IS_ERR (crtc_state )) {
1934
+ err = PTR_ERR (crtc_state );
1935
+ goto free ;
1936
+ }
1937
+
1938
+ crtc_state -> active = false;
1939
+ }
1940
+
1941
+ err = drm_atomic_commit (state );
1942
+
1943
+ free :
1944
+ if (err < 0 )
1945
+ drm_atomic_state_free (state );
1946
+
1947
+ return err ;
1948
+ }
1949
+ EXPORT_SYMBOL (drm_atomic_helper_disable_all );
1950
+
1951
+ /**
1952
+ * drm_atomic_helper_suspend - subsystem-level suspend helper
1953
+ * @dev: DRM device
1954
+ *
1955
+ * Duplicates the current atomic state, disables all active outputs and then
1956
+ * returns a pointer to the original atomic state to the caller. Drivers can
1957
+ * pass this pointer to the drm_atomic_helper_resume() helper upon resume to
1958
+ * restore the output configuration that was active at the time the system
1959
+ * entered suspend.
1960
+ *
1961
+ * Note that it is potentially unsafe to use this. The atomic state object
1962
+ * returned by this function is assumed to be persistent. Drivers must ensure
1963
+ * that this holds true. Before calling this function, drivers must make sure
1964
+ * to suspend fbdev emulation so that nothing can be using the device.
1965
+ *
1966
+ * Returns:
1967
+ * A pointer to a copy of the state before suspend on success or an ERR_PTR()-
1968
+ * encoded error code on failure. Drivers should store the returned atomic
1969
+ * state object and pass it to the drm_atomic_helper_resume() helper upon
1970
+ * resume.
1971
+ *
1972
+ * See also:
1973
+ * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
1974
+ * drm_atomic_helper_resume()
1975
+ */
1976
+ struct drm_atomic_state * drm_atomic_helper_suspend (struct drm_device * dev )
1977
+ {
1978
+ struct drm_modeset_acquire_ctx ctx ;
1979
+ struct drm_atomic_state * state ;
1980
+ int err ;
1981
+
1982
+ drm_modeset_acquire_init (& ctx , 0 );
1983
+
1984
+ retry :
1985
+ err = drm_modeset_lock_all_ctx (dev , & ctx );
1986
+ if (err < 0 ) {
1987
+ state = ERR_PTR (err );
1988
+ goto unlock ;
1989
+ }
1990
+
1991
+ state = drm_atomic_helper_duplicate_state (dev , & ctx );
1992
+ if (IS_ERR (state ))
1993
+ goto unlock ;
1994
+
1995
+ err = drm_atomic_helper_disable_all (dev , & ctx );
1996
+ if (err < 0 ) {
1997
+ drm_atomic_state_free (state );
1998
+ state = ERR_PTR (err );
1999
+ goto unlock ;
2000
+ }
2001
+
2002
+ unlock :
2003
+ if (PTR_ERR (state ) == - EDEADLK ) {
2004
+ drm_modeset_backoff (& ctx );
2005
+ goto retry ;
2006
+ }
2007
+
2008
+ drm_modeset_drop_locks (& ctx );
2009
+ drm_modeset_acquire_fini (& ctx );
2010
+ return state ;
2011
+ }
2012
+ EXPORT_SYMBOL (drm_atomic_helper_suspend );
2013
+
2014
+ /**
2015
+ * drm_atomic_helper_resume - subsystem-level resume helper
2016
+ * @dev: DRM device
2017
+ * @state: atomic state to resume to
2018
+ *
2019
+ * Calls drm_mode_config_reset() to synchronize hardware and software states,
2020
+ * grabs all modeset locks and commits the atomic state object. This can be
2021
+ * used in conjunction with the drm_atomic_helper_suspend() helper to
2022
+ * implement suspend/resume for drivers that support atomic mode-setting.
2023
+ *
2024
+ * Returns:
2025
+ * 0 on success or a negative error code on failure.
2026
+ *
2027
+ * See also:
2028
+ * drm_atomic_helper_suspend()
2029
+ */
2030
+ int drm_atomic_helper_resume (struct drm_device * dev ,
2031
+ struct drm_atomic_state * state )
2032
+ {
2033
+ struct drm_mode_config * config = & dev -> mode_config ;
2034
+ int err ;
2035
+
2036
+ drm_mode_config_reset (dev );
2037
+ drm_modeset_lock_all (dev );
2038
+ state -> acquire_ctx = config -> acquire_ctx ;
2039
+ err = drm_atomic_commit (state );
2040
+ drm_modeset_unlock_all (dev );
2041
+
2042
+ return err ;
2043
+ }
2044
+ EXPORT_SYMBOL (drm_atomic_helper_resume );
2045
+
1820
2046
/**
1821
2047
* drm_atomic_helper_crtc_set_property - helper for crtc properties
1822
2048
* @crtc: DRM crtc
@@ -2429,7 +2655,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
2429
2655
* @ctx: lock acquisition context
2430
2656
*
2431
2657
* Makes a copy of the current atomic state by looping over all objects and
2432
- * duplicating their respective states.
2658
+ * duplicating their respective states. This is used for example by suspend/
2659
+ * resume support code to save the state prior to suspend such that it can
2660
+ * be restored upon resume.
2433
2661
*
2434
2662
* Note that this treats atomic state as persistent between save and restore.
2435
2663
* Drivers must make sure that this is possible and won't result in confusion
@@ -2441,6 +2669,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
2441
2669
* Returns:
2442
2670
* A pointer to the copy of the atomic state object on success or an
2443
2671
* ERR_PTR()-encoded error code on failure.
2672
+ *
2673
+ * See also:
2674
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
2444
2675
*/
2445
2676
struct drm_atomic_state *
2446
2677
drm_atomic_helper_duplicate_state (struct drm_device * dev ,
0 commit comments