drm/i915: Use full atomic modeset.
Huzzah! \o/ Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Родитель
9b01435d28
Коммит
74c090b1bd
|
@ -1731,7 +1731,7 @@ static int __init i915_init(void)
|
|||
* to the atomic ioctl and the atomic properties. Only plane operations on
|
||||
* a single CRTC will actually work.
|
||||
*/
|
||||
if (i915.nuclear_pageflip)
|
||||
if (driver.driver_features & DRIVER_MODESET)
|
||||
driver.driver_features |= DRIVER_ATOMIC;
|
||||
|
||||
return drm_pci_init(&driver, &i915_pci_driver);
|
||||
|
|
|
@ -2614,7 +2614,6 @@ struct i915_params {
|
|||
int use_mmio_flip;
|
||||
int mmio_debug;
|
||||
bool verbose_state_checks;
|
||||
bool nuclear_pageflip;
|
||||
int edp_vswing;
|
||||
};
|
||||
extern struct i915_params i915 __read_mostly;
|
||||
|
|
|
@ -51,7 +51,6 @@ struct i915_params i915 __read_mostly = {
|
|||
.use_mmio_flip = 0,
|
||||
.mmio_debug = 0,
|
||||
.verbose_state_checks = 1,
|
||||
.nuclear_pageflip = 0,
|
||||
.edp_vswing = 0,
|
||||
};
|
||||
|
||||
|
@ -176,10 +175,6 @@ module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
|
|||
MODULE_PARM_DESC(verbose_state_checks,
|
||||
"Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");
|
||||
|
||||
module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600);
|
||||
MODULE_PARM_DESC(nuclear_pageflip,
|
||||
"Force atomic modeset functionality; only planes work for now (default: false).");
|
||||
|
||||
/* WA to get away with the default setting in VBT for early platforms.Will be removed */
|
||||
module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400);
|
||||
MODULE_PARM_DESC(edp_vswing,
|
||||
|
|
|
@ -35,129 +35,6 @@
|
|||
#include <drm/drm_plane_helper.h>
|
||||
#include "intel_drv.h"
|
||||
|
||||
|
||||
/**
|
||||
* intel_atomic_check - validate state object
|
||||
* @dev: drm device
|
||||
* @state: state to validate
|
||||
*/
|
||||
int intel_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
int nplanes = dev->mode_config.num_total_plane;
|
||||
int ncrtcs = dev->mode_config.num_crtc;
|
||||
int nconnectors = dev->mode_config.num_connector;
|
||||
enum pipe nuclear_pipe = INVALID_PIPE;
|
||||
struct intel_crtc *nuclear_crtc = NULL;
|
||||
struct intel_crtc_state *crtc_state = NULL;
|
||||
int ret;
|
||||
int i;
|
||||
bool not_nuclear = false;
|
||||
|
||||
to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq;
|
||||
|
||||
/*
|
||||
* FIXME: At the moment, we only support "nuclear pageflip" on a
|
||||
* single CRTC. Cross-crtc updates will be added later.
|
||||
*/
|
||||
for (i = 0; i < nplanes; i++) {
|
||||
struct intel_plane *plane = to_intel_plane(state->planes[i]);
|
||||
if (!plane)
|
||||
continue;
|
||||
|
||||
if (nuclear_pipe == INVALID_PIPE) {
|
||||
nuclear_pipe = plane->pipe;
|
||||
} else if (nuclear_pipe != plane->pipe) {
|
||||
DRM_DEBUG_KMS("i915 only support atomic plane operations on a single CRTC at the moment\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: We only handle planes for now; make sure there are no CRTC's
|
||||
* or connectors involved.
|
||||
*/
|
||||
state->allow_modeset = false;
|
||||
for (i = 0; i < ncrtcs; i++) {
|
||||
struct intel_crtc *crtc = to_intel_crtc(state->crtcs[i]);
|
||||
if (crtc)
|
||||
memset(&crtc->atomic, 0, sizeof(crtc->atomic));
|
||||
if (crtc && crtc->pipe != nuclear_pipe)
|
||||
not_nuclear = true;
|
||||
if (crtc && crtc->pipe == nuclear_pipe) {
|
||||
nuclear_crtc = crtc;
|
||||
crtc_state = to_intel_crtc_state(state->crtc_states[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nconnectors; i++)
|
||||
if (state->connectors[i] != NULL)
|
||||
not_nuclear = true;
|
||||
|
||||
if (not_nuclear) {
|
||||
DRM_DEBUG_KMS("i915 only supports atomic plane operations at the moment\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* intel_atomic_commit - commit validated state object
|
||||
* @dev: DRM device
|
||||
* @state: the top-level driver state object
|
||||
* @async: asynchronous commit
|
||||
*
|
||||
* This function commits a top-level state object that has been validated
|
||||
* with drm_atomic_helper_check().
|
||||
*
|
||||
* FIXME: Atomic modeset support for i915 is not yet complete. At the moment
|
||||
* we can only handle plane-related operations and do not yet support
|
||||
* asynchronous commit.
|
||||
*
|
||||
* RETURNS
|
||||
* Zero for success or -errno.
|
||||
*/
|
||||
int intel_atomic_commit(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
bool async)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_crtc *crtc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (async) {
|
||||
DRM_DEBUG_KMS("i915 does not yet support async commit\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = drm_atomic_helper_prepare_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Point of no return */
|
||||
drm_atomic_helper_swap_state(dev, state);
|
||||
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state);
|
||||
|
||||
drm_atomic_helper_commit_planes_on_crtc(crtc_state);
|
||||
}
|
||||
|
||||
/* FIXME: This function should eventually call __intel_set_mode when needed */
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, state);
|
||||
drm_atomic_helper_cleanup_planes(dev, state);
|
||||
drm_atomic_state_free(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_connector_atomic_get_property - fetch connector property value
|
||||
* @connector: connector to fetch property for
|
||||
|
|
|
@ -86,7 +86,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
|
|||
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
|
||||
struct intel_crtc_state *pipe_config);
|
||||
|
||||
static int intel_set_mode(struct drm_atomic_state *state);
|
||||
static int intel_framebuffer_init(struct drm_device *dev,
|
||||
struct intel_framebuffer *ifb,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
|
@ -111,14 +110,6 @@ static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
|
|||
int num_connectors);
|
||||
static void intel_modeset_setup_hw_state(struct drm_device *dev);
|
||||
|
||||
static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
|
||||
{
|
||||
if (!connector->mst_port)
|
||||
return connector->encoder;
|
||||
else
|
||||
return &connector->mst_port->mst_encoders[pipe]->base;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int min, max;
|
||||
} intel_range_t;
|
||||
|
@ -6262,7 +6253,7 @@ int intel_display_suspend(struct drm_device *dev)
|
|||
}
|
||||
|
||||
if (crtc_mask) {
|
||||
ret = intel_set_mode(state);
|
||||
ret = drm_atomic_commit(state);
|
||||
|
||||
if (!ret) {
|
||||
for_each_crtc(dev, crtc)
|
||||
|
@ -6316,7 +6307,7 @@ int intel_crtc_control(struct drm_crtc *crtc, bool enable)
|
|||
}
|
||||
pipe_config->base.active = enable;
|
||||
|
||||
ret = intel_set_mode(state);
|
||||
ret = drm_atomic_commit(state);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
|
@ -10430,7 +10421,7 @@ retry:
|
|||
|
||||
drm_mode_copy(&crtc_state->base.mode, mode);
|
||||
|
||||
if (intel_set_mode(state)) {
|
||||
if (drm_atomic_commit(state)) {
|
||||
DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
|
||||
if (old->release_fb)
|
||||
old->release_fb->funcs->destroy(old->release_fb);
|
||||
|
@ -10498,7 +10489,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
|
|||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = intel_set_mode(state);
|
||||
ret = drm_atomic_commit(state);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
|
@ -13119,7 +13110,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
|
|||
}
|
||||
|
||||
|
||||
/* Code that should eventually be part of atomic_check() */
|
||||
static int intel_modeset_checks(struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *dev = state->dev;
|
||||
|
@ -13160,15 +13150,20 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_modeset_compute_config(struct drm_atomic_state *state)
|
||||
/**
|
||||
* intel_atomic_check - validate state object
|
||||
* @dev: drm device
|
||||
* @state: state to validate
|
||||
*/
|
||||
static int intel_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int ret, i;
|
||||
bool any_ms = false;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(state->dev, state);
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -13231,9 +13226,26 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
|
|||
return drm_atomic_helper_check_planes(state->dev, state);
|
||||
}
|
||||
|
||||
static int __intel_set_mode(struct drm_atomic_state *state)
|
||||
/**
|
||||
* intel_atomic_commit - commit validated state object
|
||||
* @dev: DRM device
|
||||
* @state: the top-level driver state object
|
||||
* @async: asynchronous commit
|
||||
*
|
||||
* This function commits a top-level state object that has been validated
|
||||
* with drm_atomic_helper_check().
|
||||
*
|
||||
* FIXME: Atomic modeset support for i915 is not yet complete. At the moment
|
||||
* we can only handle plane-related operations and do not yet support
|
||||
* asynchronous commit.
|
||||
*
|
||||
* RETURNS
|
||||
* Zero for success or -errno.
|
||||
*/
|
||||
static int intel_atomic_commit(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
bool async)
|
||||
{
|
||||
struct drm_device *dev = state->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
@ -13241,6 +13253,11 @@ static int __intel_set_mode(struct drm_atomic_state *state)
|
|||
int i;
|
||||
bool any_ms = false;
|
||||
|
||||
if (async) {
|
||||
DRM_DEBUG_KMS("i915 does not yet support async commit\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = drm_atomic_helper_prepare_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -13285,34 +13302,14 @@ static int __intel_set_mode(struct drm_atomic_state *state)
|
|||
|
||||
/* FIXME: add subpixel order */
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, state);
|
||||
drm_atomic_helper_cleanup_planes(dev, state);
|
||||
|
||||
drm_atomic_state_free(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_set_mode_checked(struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *dev = state->dev;
|
||||
int ret;
|
||||
|
||||
ret = __intel_set_mode(state);
|
||||
if (ret == 0)
|
||||
if (any_ms)
|
||||
intel_modeset_check_state(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_set_mode(struct drm_atomic_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_modeset_compute_config(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return intel_set_mode_checked(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_crtc_restore_mode(struct drm_crtc *crtc)
|
||||
|
@ -13339,7 +13336,7 @@ retry:
|
|||
goto out;
|
||||
|
||||
crtc_state->mode_changed = true;
|
||||
ret = intel_set_mode(state);
|
||||
ret = drm_atomic_commit(state);
|
||||
}
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
|
@ -13355,201 +13352,9 @@ out:
|
|||
|
||||
#undef for_each_intel_crtc_masked
|
||||
|
||||
static bool intel_connector_in_mode_set(struct intel_connector *connector,
|
||||
struct drm_mode_set *set)
|
||||
{
|
||||
int ro;
|
||||
|
||||
for (ro = 0; ro < set->num_connectors; ro++)
|
||||
if (set->connectors[ro] == &connector->base)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_modeset_stage_output_state(struct drm_device *dev,
|
||||
struct drm_mode_set *set,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct intel_connector *connector;
|
||||
struct drm_connector *drm_connector;
|
||||
struct drm_connector_state *connector_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int i, ret;
|
||||
|
||||
/* The upper layers ensure that we either disable a crtc or have a list
|
||||
* of connectors. For paranoia, double-check this. */
|
||||
WARN_ON(!set->fb && (set->num_connectors != 0));
|
||||
WARN_ON(set->fb && (set->num_connectors == 0));
|
||||
|
||||
for_each_intel_connector(dev, connector) {
|
||||
bool in_mode_set = intel_connector_in_mode_set(connector, set);
|
||||
|
||||
if (!in_mode_set && connector->base.state->crtc != set->crtc)
|
||||
continue;
|
||||
|
||||
connector_state =
|
||||
drm_atomic_get_connector_state(state, &connector->base);
|
||||
if (IS_ERR(connector_state))
|
||||
return PTR_ERR(connector_state);
|
||||
|
||||
if (in_mode_set) {
|
||||
int pipe = to_intel_crtc(set->crtc)->pipe;
|
||||
connector_state->best_encoder =
|
||||
&intel_find_encoder(connector, pipe)->base;
|
||||
}
|
||||
|
||||
if (connector->base.state->crtc != set->crtc)
|
||||
continue;
|
||||
|
||||
/* If we disable the crtc, disable all its connectors. Also, if
|
||||
* the connector is on the changing crtc but not on the new
|
||||
* connector list, disable it. */
|
||||
if (!set->fb || !in_mode_set) {
|
||||
connector_state->best_encoder = NULL;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
|
||||
connector->base.base.id,
|
||||
connector->base.name);
|
||||
}
|
||||
}
|
||||
/* connector->new_encoder is now updated for all connectors. */
|
||||
|
||||
for_each_connector_in_state(state, drm_connector, connector_state, i) {
|
||||
connector = to_intel_connector(drm_connector);
|
||||
|
||||
if (!connector_state->best_encoder) {
|
||||
ret = drm_atomic_set_crtc_for_connector(connector_state,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (intel_connector_in_mode_set(connector, set)) {
|
||||
struct drm_crtc *crtc = connector->base.state->crtc;
|
||||
|
||||
/* If this connector was in a previous crtc, add it
|
||||
* to the state. We might need to disable it. */
|
||||
if (crtc) {
|
||||
crtc_state =
|
||||
drm_atomic_get_crtc_state(state, crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
}
|
||||
|
||||
ret = drm_atomic_set_crtc_for_connector(connector_state,
|
||||
set->crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make sure the new CRTC will work with the encoder */
|
||||
if (!drm_encoder_crtc_ok(connector_state->best_encoder,
|
||||
connector_state->crtc)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
|
||||
connector->base.base.id,
|
||||
connector->base.name,
|
||||
connector_state->crtc->base.id);
|
||||
|
||||
if (connector_state->best_encoder != &connector->encoder->base)
|
||||
connector->encoder =
|
||||
to_intel_encoder(connector_state->best_encoder);
|
||||
}
|
||||
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
bool has_connectors;
|
||||
|
||||
ret = drm_atomic_add_affected_connectors(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc);
|
||||
if (has_connectors != crtc_state->enable)
|
||||
crtc_state->enable =
|
||||
crtc_state->active = has_connectors;
|
||||
}
|
||||
|
||||
ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode,
|
||||
set->fb, set->x, set->y);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
crtc_state = drm_atomic_get_crtc_state(state, set->crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
|
||||
ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (set->num_connectors)
|
||||
crtc_state->active = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_crtc_set_config(struct drm_mode_set *set)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_atomic_state *state = NULL;
|
||||
int ret;
|
||||
|
||||
BUG_ON(!set);
|
||||
BUG_ON(!set->crtc);
|
||||
BUG_ON(!set->crtc->helper_private);
|
||||
|
||||
/* Enforce sane interface api - has been abused by the fb helper. */
|
||||
BUG_ON(!set->mode && set->fb);
|
||||
BUG_ON(set->fb && set->num_connectors == 0);
|
||||
|
||||
if (set->fb) {
|
||||
DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
|
||||
set->crtc->base.id, set->fb->base.id,
|
||||
(int)set->num_connectors, set->x, set->y);
|
||||
} else {
|
||||
DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
|
||||
}
|
||||
|
||||
dev = set->crtc->dev;
|
||||
|
||||
state = drm_atomic_state_alloc(dev);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
state->acquire_ctx = dev->mode_config.acquire_ctx;
|
||||
|
||||
ret = intel_modeset_stage_output_state(dev, set, state);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = intel_modeset_compute_config(state);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
intel_update_pipe_size(to_intel_crtc(set->crtc));
|
||||
|
||||
ret = intel_set_mode_checked(state);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
|
||||
set->crtc->base.id, ret);
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
drm_atomic_state_free(state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs intel_crtc_funcs = {
|
||||
.gamma_set = intel_crtc_gamma_set,
|
||||
.set_config = intel_crtc_set_config,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.destroy = intel_crtc_destroy,
|
||||
.page_flip = intel_crtc_page_flip,
|
||||
.atomic_duplicate_state = intel_crtc_duplicate_state,
|
||||
|
@ -15654,7 +15459,7 @@ void intel_display_resume(struct drm_device *dev)
|
|||
intel_modeset_setup_hw_state(dev);
|
||||
|
||||
i915_redisable_vga(dev);
|
||||
ret = intel_set_mode(state);
|
||||
ret = drm_atomic_commit(state);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1393,11 +1393,6 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
|
|||
void intel_tv_init(struct drm_device *dev);
|
||||
|
||||
/* intel_atomic.c */
|
||||
int intel_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state);
|
||||
int intel_atomic_commit(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
bool async);
|
||||
int intel_connector_atomic_get_property(struct drm_connector *connector,
|
||||
const struct drm_connector_state *state,
|
||||
struct drm_property *property,
|
||||
|
|
Загрузка…
Ссылка в новой задаче