Skip to content

Commit 47c0fd7

Browse files
committed
Merge tag 'topic/drm-misc-2015-12-04' of git://anongit.freedesktop.org/drm-intel into drm-next
New -misc pull. Big thing is Thierry's atomic helpers for system suspend resume, which I'd like to use in i915 too. Hence the pull. * tag 'topic/drm-misc-2015-12-04' of git://anongit.freedesktop.org/drm-intel: drm: keep connector status change logging human readable drm/atomic-helper: Reject attempts at re-stealing encoders drm/atomic-helper: Implement subsystem-level suspend/resume drm: Implement drm_modeset_lock_all_ctx() drm/gma500: Add driver private mutex for the fault handler drm/gma500: Drop dev->struct_mutex from mmap offset function drm/gma500: Drop dev->struct_mutex from fbdev init/teardown code drm/gma500: Drop dev->struct_mutex from modeset code drm/gma500: Use correct unref in the gem bo create function drm/edid: Make the detailed timing CEA/HDMI mode fixup accept up to 5kHz clock difference drm/atomic_helper: Add drm_atomic_helper_disable_planes_on_crtc() drm: Serialise multiple event readers drm: Drop dev->event_lock spinlock around faulting copy_to_user()
2 parents 80d6900 + 4e15f2a commit 47c0fd7

17 files changed

+445
-97
lines changed

drivers/gpu/drm/drm_atomic.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,12 +1188,7 @@ void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
11881188
retry:
11891189
drm_modeset_backoff(state->acquire_ctx);
11901190

1191-
ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
1192-
state->acquire_ctx);
1193-
if (ret)
1194-
goto retry;
1195-
ret = drm_modeset_lock_all_crtcs(state->dev,
1196-
state->acquire_ctx);
1191+
ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx);
11971192
if (ret)
11981193
goto retry;
11991194
}

drivers/gpu/drm/drm_atomic_helper.c

Lines changed: 232 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,27 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
8080
}
8181
}
8282

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+
83104
static struct drm_crtc *
84105
get_current_crtc_for_encoder(struct drm_device *dev,
85106
struct drm_encoder *encoder)
@@ -229,6 +250,13 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
229250
return 0;
230251
}
231252

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+
232260
encoder_crtc = get_current_crtc_for_encoder(state->dev,
233261
new_encoder);
234262

@@ -1341,6 +1369,49 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
13411369
}
13421370
EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
13431371

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+
13441415
/**
13451416
* drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
13461417
* @dev: DRM device
@@ -1817,6 +1888,161 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
18171888
return 0;
18181889
}
18191890

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+
18202046
/**
18212047
* drm_atomic_helper_crtc_set_property - helper for crtc properties
18222048
* @crtc: DRM crtc
@@ -2429,7 +2655,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
24292655
* @ctx: lock acquisition context
24302656
*
24312657
* 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.
24332661
*
24342662
* Note that this treats atomic state as persistent between save and restore.
24352663
* 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);
24412669
* Returns:
24422670
* A pointer to the copy of the atomic state object on success or an
24432671
* ERR_PTR()-encoded error code on failure.
2672+
*
2673+
* See also:
2674+
* drm_atomic_helper_suspend(), drm_atomic_helper_resume()
24442675
*/
24452676
struct drm_atomic_state *
24462677
drm_atomic_helper_duplicate_state(struct drm_device *dev,

drivers/gpu/drm/drm_crtc_helper.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,12 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
855855
* due to slight differences in allocating shared resources when the
856856
* configuration is restored in a different order than when userspace set it up)
857857
* 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()
858864
*/
859865
void drm_helper_resume_force_mode(struct drm_device *dev)
860866
{

drivers/gpu/drm/drm_edid.c

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,6 +2545,33 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
25452545
return clock;
25462546
}
25472547

2548+
static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match,
2549+
unsigned int clock_tolerance)
2550+
{
2551+
u8 mode;
2552+
2553+
if (!to_match->clock)
2554+
return 0;
2555+
2556+
for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
2557+
const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
2558+
unsigned int clock1, clock2;
2559+
2560+
/* Check both 60Hz and 59.94Hz */
2561+
clock1 = cea_mode->clock;
2562+
clock2 = cea_mode_alternate_clock(cea_mode);
2563+
2564+
if (abs(to_match->clock - clock1) > clock_tolerance &&
2565+
abs(to_match->clock - clock2) > clock_tolerance)
2566+
continue;
2567+
2568+
if (drm_mode_equal_no_clocks(to_match, cea_mode))
2569+
return mode + 1;
2570+
}
2571+
2572+
return 0;
2573+
}
2574+
25482575
/**
25492576
* drm_match_cea_mode - look for a CEA mode matching given mode
25502577
* @to_match: display mode
@@ -2609,6 +2636,33 @@ hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode)
26092636
return cea_mode_alternate_clock(hdmi_mode);
26102637
}
26112638

2639+
static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match,
2640+
unsigned int clock_tolerance)
2641+
{
2642+
u8 mode;
2643+
2644+
if (!to_match->clock)
2645+
return 0;
2646+
2647+
for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
2648+
const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
2649+
unsigned int clock1, clock2;
2650+
2651+
/* Make sure to also match alternate clocks */
2652+
clock1 = hdmi_mode->clock;
2653+
clock2 = hdmi_mode_alternate_clock(hdmi_mode);
2654+
2655+
if (abs(to_match->clock - clock1) > clock_tolerance &&
2656+
abs(to_match->clock - clock2) > clock_tolerance)
2657+
continue;
2658+
2659+
if (drm_mode_equal_no_clocks(to_match, hdmi_mode))
2660+
return mode + 1;
2661+
}
2662+
2663+
return 0;
2664+
}
2665+
26122666
/*
26132667
* drm_match_hdmi_mode - look for a HDMI mode matching given mode
26142668
* @to_match: display mode
@@ -3119,14 +3173,18 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
31193173
u8 mode_idx;
31203174
const char *type;
31213175

3122-
mode_idx = drm_match_cea_mode(mode) - 1;
3176+
/*
3177+
* allow 5kHz clock difference either way to account for
3178+
* the 10kHz clock resolution limit of detailed timings.
3179+
*/
3180+
mode_idx = drm_match_cea_mode_clock_tolerance(mode, 5) - 1;
31233181
if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
31243182
type = "CEA";
31253183
cea_mode = &edid_cea_modes[mode_idx];
31263184
clock1 = cea_mode->clock;
31273185
clock2 = cea_mode_alternate_clock(cea_mode);
31283186
} else {
3129-
mode_idx = drm_match_hdmi_mode(mode) - 1;
3187+
mode_idx = drm_match_hdmi_mode_clock_tolerance(mode, 5) - 1;
31303188
if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
31313189
type = "HDMI";
31323190
cea_mode = &edid_4k_modes[mode_idx];

0 commit comments

Comments
 (0)