diff options
author | Thierry Reding <treding@nvidia.com> | 2015-12-02 11:50:04 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-12-02 17:11:17 -0500 |
commit | 1494276000db789c6d2acd85747be4707051c801 (patch) | |
tree | bf2dda38924cfcb41ae23374ab670640c951f754 | |
parent | 06eaae46381737a6236ad6fe81e5358fad3bbbe5 (diff) |
drm/atomic-helper: Implement subsystem-level suspend/resume
Provide subsystem-level suspend and resume helpers that can be used to
implement suspend/resume on atomic mode-setting enabled drivers.
v2: simplify locking, enhance kerneldoc comments
v3: pass lock acquisition context by parameter, improve kerneldoc
v4: - remove redundant code (already provided by atomic helpers)
(Maarten Lankhorst)
- move backoff dance from drm_modeset_lock_all_ctx() into suspend
helper (Daniel Vetter)
v5: handle potential EDEADLK from drm_atomic_helper_duplicate_state()
and drm_atomic_helper_disable_all() (Daniel Vetter)
Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1449075005-13937-2-git-send-email-thierry.reding@gmail.com
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 162 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 6 | ||||
-rw-r--r-- | include/drm/drm_atomic_helper.h | 6 |
3 files changed, 173 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index a800b2c75522..d9053ebf4903 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1861,6 +1861,161 @@ commit: | |||
1861 | } | 1861 | } |
1862 | 1862 | ||
1863 | /** | 1863 | /** |
1864 | * drm_atomic_helper_disable_all - disable all currently active outputs | ||
1865 | * @dev: DRM device | ||
1866 | * @ctx: lock acquisition context | ||
1867 | * | ||
1868 | * Loops through all connectors, finding those that aren't turned off and then | ||
1869 | * turns them off by setting their DPMS mode to OFF and deactivating the CRTC | ||
1870 | * that they are connected to. | ||
1871 | * | ||
1872 | * This is used for example in suspend/resume to disable all currently active | ||
1873 | * functions when suspending. | ||
1874 | * | ||
1875 | * Note that if callers haven't already acquired all modeset locks this might | ||
1876 | * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). | ||
1877 | * | ||
1878 | * Returns: | ||
1879 | * 0 on success or a negative error code on failure. | ||
1880 | * | ||
1881 | * See also: | ||
1882 | * drm_atomic_helper_suspend(), drm_atomic_helper_resume() | ||
1883 | */ | ||
1884 | int drm_atomic_helper_disable_all(struct drm_device *dev, | ||
1885 | struct drm_modeset_acquire_ctx *ctx) | ||
1886 | { | ||
1887 | struct drm_atomic_state *state; | ||
1888 | struct drm_connector *conn; | ||
1889 | int err; | ||
1890 | |||
1891 | state = drm_atomic_state_alloc(dev); | ||
1892 | if (!state) | ||
1893 | return -ENOMEM; | ||
1894 | |||
1895 | state->acquire_ctx = ctx; | ||
1896 | |||
1897 | drm_for_each_connector(conn, dev) { | ||
1898 | struct drm_crtc *crtc = conn->state->crtc; | ||
1899 | struct drm_crtc_state *crtc_state; | ||
1900 | |||
1901 | if (!crtc || conn->dpms != DRM_MODE_DPMS_ON) | ||
1902 | continue; | ||
1903 | |||
1904 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
1905 | if (IS_ERR(crtc_state)) { | ||
1906 | err = PTR_ERR(crtc_state); | ||
1907 | goto free; | ||
1908 | } | ||
1909 | |||
1910 | crtc_state->active = false; | ||
1911 | } | ||
1912 | |||
1913 | err = drm_atomic_commit(state); | ||
1914 | |||
1915 | free: | ||
1916 | if (err < 0) | ||
1917 | drm_atomic_state_free(state); | ||
1918 | |||
1919 | return err; | ||
1920 | } | ||
1921 | EXPORT_SYMBOL(drm_atomic_helper_disable_all); | ||
1922 | |||
1923 | /** | ||
1924 | * drm_atomic_helper_suspend - subsystem-level suspend helper | ||
1925 | * @dev: DRM device | ||
1926 | * | ||
1927 | * Duplicates the current atomic state, disables all active outputs and then | ||
1928 | * returns a pointer to the original atomic state to the caller. Drivers can | ||
1929 | * pass this pointer to the drm_atomic_helper_resume() helper upon resume to | ||
1930 | * restore the output configuration that was active at the time the system | ||
1931 | * entered suspend. | ||
1932 | * | ||
1933 | * Note that it is potentially unsafe to use this. The atomic state object | ||
1934 | * returned by this function is assumed to be persistent. Drivers must ensure | ||
1935 | * that this holds true. Before calling this function, drivers must make sure | ||
1936 | * to suspend fbdev emulation so that nothing can be using the device. | ||
1937 | * | ||
1938 | * Returns: | ||
1939 | * A pointer to a copy of the state before suspend on success or an ERR_PTR()- | ||
1940 | * encoded error code on failure. Drivers should store the returned atomic | ||
1941 | * state object and pass it to the drm_atomic_helper_resume() helper upon | ||
1942 | * resume. | ||
1943 | * | ||
1944 | * See also: | ||
1945 | * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(), | ||
1946 | * drm_atomic_helper_resume() | ||
1947 | */ | ||
1948 | struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev) | ||
1949 | { | ||
1950 | struct drm_modeset_acquire_ctx ctx; | ||
1951 | struct drm_atomic_state *state; | ||
1952 | int err; | ||
1953 | |||
1954 | drm_modeset_acquire_init(&ctx, 0); | ||
1955 | |||
1956 | retry: | ||
1957 | err = drm_modeset_lock_all_ctx(dev, &ctx); | ||
1958 | if (err < 0) { | ||
1959 | state = ERR_PTR(err); | ||
1960 | goto unlock; | ||
1961 | } | ||
1962 | |||
1963 | state = drm_atomic_helper_duplicate_state(dev, &ctx); | ||
1964 | if (IS_ERR(state)) | ||
1965 | goto unlock; | ||
1966 | |||
1967 | err = drm_atomic_helper_disable_all(dev, &ctx); | ||
1968 | if (err < 0) { | ||
1969 | drm_atomic_state_free(state); | ||
1970 | state = ERR_PTR(err); | ||
1971 | goto unlock; | ||
1972 | } | ||
1973 | |||
1974 | unlock: | ||
1975 | if (PTR_ERR(state) == -EDEADLK) { | ||
1976 | drm_modeset_backoff(&ctx); | ||
1977 | goto retry; | ||
1978 | } | ||
1979 | |||
1980 | drm_modeset_drop_locks(&ctx); | ||
1981 | drm_modeset_acquire_fini(&ctx); | ||
1982 | return state; | ||
1983 | } | ||
1984 | EXPORT_SYMBOL(drm_atomic_helper_suspend); | ||
1985 | |||
1986 | /** | ||
1987 | * drm_atomic_helper_resume - subsystem-level resume helper | ||
1988 | * @dev: DRM device | ||
1989 | * @state: atomic state to resume to | ||
1990 | * | ||
1991 | * Calls drm_mode_config_reset() to synchronize hardware and software states, | ||
1992 | * grabs all modeset locks and commits the atomic state object. This can be | ||
1993 | * used in conjunction with the drm_atomic_helper_suspend() helper to | ||
1994 | * implement suspend/resume for drivers that support atomic mode-setting. | ||
1995 | * | ||
1996 | * Returns: | ||
1997 | * 0 on success or a negative error code on failure. | ||
1998 | * | ||
1999 | * See also: | ||
2000 | * drm_atomic_helper_suspend() | ||
2001 | */ | ||
2002 | int drm_atomic_helper_resume(struct drm_device *dev, | ||
2003 | struct drm_atomic_state *state) | ||
2004 | { | ||
2005 | struct drm_mode_config *config = &dev->mode_config; | ||
2006 | int err; | ||
2007 | |||
2008 | drm_mode_config_reset(dev); | ||
2009 | drm_modeset_lock_all(dev); | ||
2010 | state->acquire_ctx = config->acquire_ctx; | ||
2011 | err = drm_atomic_commit(state); | ||
2012 | drm_modeset_unlock_all(dev); | ||
2013 | |||
2014 | return err; | ||
2015 | } | ||
2016 | EXPORT_SYMBOL(drm_atomic_helper_resume); | ||
2017 | |||
2018 | /** | ||
1864 | * drm_atomic_helper_crtc_set_property - helper for crtc properties | 2019 | * drm_atomic_helper_crtc_set_property - helper for crtc properties |
1865 | * @crtc: DRM crtc | 2020 | * @crtc: DRM crtc |
1866 | * @property: DRM property | 2021 | * @property: DRM property |
@@ -2472,7 +2627,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); | |||
2472 | * @ctx: lock acquisition context | 2627 | * @ctx: lock acquisition context |
2473 | * | 2628 | * |
2474 | * Makes a copy of the current atomic state by looping over all objects and | 2629 | * Makes a copy of the current atomic state by looping over all objects and |
2475 | * duplicating their respective states. | 2630 | * duplicating their respective states. This is used for example by suspend/ |
2631 | * resume support code to save the state prior to suspend such that it can | ||
2632 | * be restored upon resume. | ||
2476 | * | 2633 | * |
2477 | * Note that this treats atomic state as persistent between save and restore. | 2634 | * Note that this treats atomic state as persistent between save and restore. |
2478 | * Drivers must make sure that this is possible and won't result in confusion | 2635 | * Drivers must make sure that this is possible and won't result in confusion |
@@ -2484,6 +2641,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); | |||
2484 | * Returns: | 2641 | * Returns: |
2485 | * A pointer to the copy of the atomic state object on success or an | 2642 | * A pointer to the copy of the atomic state object on success or an |
2486 | * ERR_PTR()-encoded error code on failure. | 2643 | * ERR_PTR()-encoded error code on failure. |
2644 | * | ||
2645 | * See also: | ||
2646 | * drm_atomic_helper_suspend(), drm_atomic_helper_resume() | ||
2487 | */ | 2647 | */ |
2488 | struct drm_atomic_state * | 2648 | struct drm_atomic_state * |
2489 | drm_atomic_helper_duplicate_state(struct drm_device *dev, | 2649 | drm_atomic_helper_duplicate_state(struct drm_device *dev, |
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 6b4cf25fed12..10d0989db273 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -855,6 +855,12 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); | |||
855 | * due to slight differences in allocating shared resources when the | 855 | * due to slight differences in allocating shared resources when the |
856 | * configuration is restored in a different order than when userspace set it up) | 856 | * configuration is restored in a different order than when userspace set it up) |
857 | * need to use their own restore logic. | 857 | * need to use their own restore logic. |
858 | * | ||
859 | * This function is deprecated. New drivers should implement atomic mode- | ||
860 | * setting and use the atomic suspend/resume helpers. | ||
861 | * | ||
862 | * See also: | ||
863 | * drm_atomic_helper_suspend(), drm_atomic_helper_resume() | ||
858 | */ | 864 | */ |
859 | void drm_helper_resume_force_mode(struct drm_device *dev) | 865 | void drm_helper_resume_force_mode(struct drm_device *dev) |
860 | { | 866 | { |
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index b7d423732f47..a286cce98720 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h | |||
@@ -83,6 +83,12 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set); | |||
83 | int __drm_atomic_helper_set_config(struct drm_mode_set *set, | 83 | int __drm_atomic_helper_set_config(struct drm_mode_set *set, |
84 | struct drm_atomic_state *state); | 84 | struct drm_atomic_state *state); |
85 | 85 | ||
86 | int drm_atomic_helper_disable_all(struct drm_device *dev, | ||
87 | struct drm_modeset_acquire_ctx *ctx); | ||
88 | struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); | ||
89 | int drm_atomic_helper_resume(struct drm_device *dev, | ||
90 | struct drm_atomic_state *state); | ||
91 | |||
86 | int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, | 92 | int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, |
87 | struct drm_property *property, | 93 | struct drm_property *property, |
88 | uint64_t val); | 94 | uint64_t val); |