2014-12-24 02:41:52 +08:00
|
|
|
/*
|
|
|
|
* Copyright © 2014 Intel Corporation
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2015-01-14 00:55:00 +08:00
|
|
|
* DOC: atomic plane helpers
|
2014-12-24 02:41:52 +08:00
|
|
|
*
|
|
|
|
* The functions here are used by the atomic plane helper functions to
|
|
|
|
* implement legacy plane updates (i.e., drm_plane->update_plane() and
|
|
|
|
* drm_plane->disable_plane()). This allows plane updates to use the
|
|
|
|
* atomic state infrastructure and perform plane updates as separate
|
|
|
|
* prepare/check/commit/cleanup steps.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <drm/drmP.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
|
|
|
#include <drm/drm_plane_helper.h>
|
|
|
|
#include "intel_drv.h"
|
|
|
|
|
2018-11-13 17:28:04 +08:00
|
|
|
struct intel_plane *intel_plane_alloc(void)
|
2015-01-22 08:35:41 +08:00
|
|
|
{
|
2018-11-13 17:28:04 +08:00
|
|
|
struct intel_plane_state *plane_state;
|
|
|
|
struct intel_plane *plane;
|
2015-01-22 08:35:41 +08:00
|
|
|
|
2018-11-13 17:28:04 +08:00
|
|
|
plane = kzalloc(sizeof(*plane), GFP_KERNEL);
|
|
|
|
if (!plane)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
2015-01-22 08:35:41 +08:00
|
|
|
|
2018-11-13 17:28:04 +08:00
|
|
|
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
|
|
|
|
if (!plane_state) {
|
|
|
|
kfree(plane);
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
}
|
2015-01-22 08:35:41 +08:00
|
|
|
|
2018-11-13 17:28:04 +08:00
|
|
|
__drm_atomic_helper_plane_reset(&plane->base, &plane_state->base);
|
|
|
|
plane_state->scaler_id = -1;
|
|
|
|
|
|
|
|
return plane;
|
|
|
|
}
|
|
|
|
|
|
|
|
void intel_plane_free(struct intel_plane *plane)
|
|
|
|
{
|
|
|
|
intel_plane_destroy_state(&plane->base, plane->base.state);
|
|
|
|
kfree(plane);
|
2015-01-22 08:35:41 +08:00
|
|
|
}
|
|
|
|
|
2014-12-24 02:41:52 +08:00
|
|
|
/**
|
|
|
|
* intel_plane_duplicate_state - duplicate plane state
|
|
|
|
* @plane: drm plane
|
|
|
|
*
|
|
|
|
* Allocates and returns a copy of the plane state (both common and
|
|
|
|
* Intel-specific) for the specified plane.
|
|
|
|
*
|
2015-01-22 08:35:41 +08:00
|
|
|
* Returns: The newly allocated plane state, or NULL on failure.
|
2014-12-24 02:41:52 +08:00
|
|
|
*/
|
|
|
|
struct drm_plane_state *
|
|
|
|
intel_plane_duplicate_state(struct drm_plane *plane)
|
|
|
|
{
|
2015-01-22 08:35:41 +08:00
|
|
|
struct drm_plane_state *state;
|
|
|
|
struct intel_plane_state *intel_state;
|
2014-12-24 02:41:52 +08:00
|
|
|
|
2015-09-10 22:08:02 +08:00
|
|
|
intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL);
|
2014-12-24 02:41:52 +08:00
|
|
|
|
2015-01-22 08:35:41 +08:00
|
|
|
if (!intel_state)
|
2014-12-24 02:41:52 +08:00
|
|
|
return NULL;
|
|
|
|
|
2015-01-22 08:35:41 +08:00
|
|
|
state = &intel_state->base;
|
2015-04-21 22:12:58 +08:00
|
|
|
|
|
|
|
__drm_atomic_helper_plane_duplicate_state(plane, state);
|
2014-12-24 02:41:52 +08:00
|
|
|
|
2017-01-16 23:21:27 +08:00
|
|
|
intel_state->vma = NULL;
|
2018-02-20 21:42:06 +08:00
|
|
|
intel_state->flags = 0;
|
2017-01-16 23:21:27 +08:00
|
|
|
|
2015-01-22 08:35:41 +08:00
|
|
|
return state;
|
2014-12-24 02:41:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_plane_destroy_state - destroy plane state
|
|
|
|
* @plane: drm plane
|
2015-01-14 00:55:00 +08:00
|
|
|
* @state: state object to destroy
|
2014-12-24 02:41:52 +08:00
|
|
|
*
|
|
|
|
* Destroys the plane state (both common and Intel-specific) for the
|
|
|
|
* specified plane.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
intel_plane_destroy_state(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state)
|
|
|
|
{
|
2017-05-11 16:28:44 +08:00
|
|
|
WARN_ON(to_intel_plane_state(state)->vma);
|
2017-01-16 23:21:27 +08:00
|
|
|
|
2014-12-24 02:41:52 +08:00
|
|
|
drm_atomic_helper_plane_destroy_state(plane, state);
|
|
|
|
}
|
|
|
|
|
2017-08-23 23:22:23 +08:00
|
|
|
int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
const struct intel_plane_state *old_plane_state,
|
2016-12-12 18:34:55 +08:00
|
|
|
struct intel_plane_state *intel_state)
|
2014-12-24 02:41:52 +08:00
|
|
|
{
|
2016-12-12 18:34:55 +08:00
|
|
|
struct drm_plane *plane = intel_state->base.plane;
|
|
|
|
struct drm_plane_state *state = &intel_state->base;
|
2014-12-24 02:41:52 +08:00
|
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
2015-06-15 18:33:44 +08:00
|
|
|
int ret;
|
2014-12-24 02:41:52 +08:00
|
|
|
|
2018-09-20 18:27:06 +08:00
|
|
|
crtc_state->active_planes &= ~BIT(intel_plane->id);
|
|
|
|
crtc_state->nv12_planes &= ~BIT(intel_plane->id);
|
|
|
|
intel_state->base.visible = false;
|
|
|
|
|
|
|
|
/* If this is a cursor plane, no further checks are needed. */
|
2017-08-23 23:22:23 +08:00
|
|
|
if (!intel_state->base.crtc && !old_plane_state->base.crtc)
|
2015-01-22 08:35:48 +08:00
|
|
|
return 0;
|
|
|
|
|
2018-08-28 22:27:06 +08:00
|
|
|
ret = intel_plane->check_plane(crtc_state, intel_state);
|
2015-06-15 18:33:55 +08:00
|
|
|
if (ret)
|
2015-06-15 18:33:44 +08:00
|
|
|
return ret;
|
|
|
|
|
2017-03-03 01:14:51 +08:00
|
|
|
/* FIXME pre-g4x don't work like this */
|
2018-05-12 05:33:12 +08:00
|
|
|
if (state->visible)
|
2017-03-03 01:14:51 +08:00
|
|
|
crtc_state->active_planes |= BIT(intel_plane->id);
|
|
|
|
|
2018-05-12 05:33:12 +08:00
|
|
|
if (state->visible && state->fb->format->format == DRM_FORMAT_NV12)
|
|
|
|
crtc_state->nv12_planes |= BIT(intel_plane->id);
|
|
|
|
|
2018-11-28 00:37:42 +08:00
|
|
|
if (state->visible || old_plane_state->base.visible)
|
|
|
|
crtc_state->update_planes |= BIT(intel_plane->id);
|
|
|
|
|
2017-08-23 23:22:23 +08:00
|
|
|
return intel_plane_atomic_calc_changes(old_crtc_state,
|
|
|
|
&crtc_state->base,
|
|
|
|
old_plane_state,
|
|
|
|
state);
|
2014-12-24 02:41:52 +08:00
|
|
|
}
|
|
|
|
|
2016-12-12 18:34:55 +08:00
|
|
|
static int intel_plane_atomic_check(struct drm_plane *plane,
|
2017-08-23 23:22:23 +08:00
|
|
|
struct drm_plane_state *new_plane_state)
|
2016-12-12 18:34:55 +08:00
|
|
|
{
|
2017-08-23 23:22:23 +08:00
|
|
|
struct drm_atomic_state *state = new_plane_state->state;
|
|
|
|
const struct drm_plane_state *old_plane_state =
|
|
|
|
drm_atomic_get_old_plane_state(state, plane);
|
|
|
|
struct drm_crtc *crtc = new_plane_state->crtc ?: old_plane_state->crtc;
|
|
|
|
const struct drm_crtc_state *old_crtc_state;
|
|
|
|
struct drm_crtc_state *new_crtc_state;
|
2016-12-12 18:34:55 +08:00
|
|
|
|
2018-09-20 18:27:06 +08:00
|
|
|
new_plane_state->visible = false;
|
2016-12-12 18:34:55 +08:00
|
|
|
if (!crtc)
|
|
|
|
return 0;
|
|
|
|
|
2017-08-23 23:22:23 +08:00
|
|
|
old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
|
|
|
|
new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
2016-12-12 18:34:55 +08:00
|
|
|
|
2017-08-23 23:22:23 +08:00
|
|
|
return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
|
|
|
|
to_intel_crtc_state(new_crtc_state),
|
|
|
|
to_intel_plane_state(old_plane_state),
|
|
|
|
to_intel_plane_state(new_plane_state));
|
2016-12-12 18:34:55 +08:00
|
|
|
}
|
|
|
|
|
2018-09-20 18:27:08 +08:00
|
|
|
void intel_update_planes_on_crtc(struct intel_atomic_state *old_state,
|
|
|
|
struct intel_crtc *crtc,
|
|
|
|
struct intel_crtc_state *old_crtc_state,
|
|
|
|
struct intel_crtc_state *new_crtc_state)
|
2014-12-24 02:41:52 +08:00
|
|
|
{
|
2018-11-28 00:37:42 +08:00
|
|
|
u32 update_mask = new_crtc_state->update_planes;
|
2018-09-20 18:27:08 +08:00
|
|
|
struct intel_plane_state *new_plane_state;
|
|
|
|
struct intel_plane *plane;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_new_intel_plane_in_state(old_state, plane, new_plane_state, i) {
|
|
|
|
if (crtc->pipe != plane->pipe ||
|
|
|
|
!(update_mask & BIT(plane->id)))
|
|
|
|
continue;
|
2016-01-07 18:54:07 +08:00
|
|
|
|
2018-09-20 18:27:08 +08:00
|
|
|
if (new_plane_state->base.visible) {
|
|
|
|
trace_intel_update_plane(&plane->base, crtc);
|
2017-03-03 01:15:05 +08:00
|
|
|
|
2018-09-20 18:27:08 +08:00
|
|
|
plane->update_plane(plane, new_crtc_state, new_plane_state);
|
drm/i915/gen11: Link nv12 Y and UV planes in the atomic state, v5.
To make NV12 working on icl, we need to update 2 planes simultaneously.
I've chosen to do this in the CRTC step after plane validation is done,
so we know what planes are (in)visible. The linked Y plane will get
updated in intel_plane_update_planes_on_crtc(), by the call to
update_slave, which gets the master's plane_state as argument.
The link requires both planes for atomic_update to work,
so make sure skl_ddb_add_affected_planes() adds both states.
Changes since v1:
- Introduce icl_is_nv12_y_plane(), instead of hardcoding sprite numbers.
- Put all the state updating login in intel_plane_atomic_check_with_state().
- Clean up changes in intel_plane_atomic_check().
Changes since v2:
- Fix intel_atomic_get_old_plane_state() to actually return old state.
- Move visibility changes to preparation patch.
- Only try to find a Y plane on gen11, earlier platforms only require
a single plane.
Changes since v3:
- Fix checkpatch warning about to_intel_crtc() usage.
- Add affected planes from icl_add_linked_planes() before check_planes(),
it's a cleaner way to do this. (Ville)
Changes since v4:
- Clear plane links in icl_check_nv12_planes() for clarity.
- Only pass crtc_state to icl_check_nv12_planes().
- Use for_each_new_intel_plane_in_state() in icl_check_nv12_planes.
- Rename aux to linked. (Ville)
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181022135152.15324-1-maarten.lankhorst@linux.intel.com
[mlankhorst: Change bool slave to u32, to satisfy checkpatch]
[mlankhorst: Add WARN_ON's based on Ville's suggestion]
2018-10-22 21:51:52 +08:00
|
|
|
} else if (new_plane_state->slave) {
|
|
|
|
struct intel_plane *master =
|
|
|
|
new_plane_state->linked_plane;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We update the slave plane from this function because
|
|
|
|
* programming it from the master plane's update_plane
|
|
|
|
* callback runs into issues when the Y plane is
|
|
|
|
* reassigned, disabled or used by a different plane.
|
|
|
|
*
|
|
|
|
* The slave plane is updated with the master plane's
|
|
|
|
* plane_state.
|
|
|
|
*/
|
|
|
|
new_plane_state =
|
|
|
|
intel_atomic_get_new_plane_state(old_state, master);
|
|
|
|
|
|
|
|
trace_intel_update_plane(&plane->base, crtc);
|
|
|
|
|
|
|
|
plane->update_slave(plane, new_crtc_state, new_plane_state);
|
2018-09-20 18:27:08 +08:00
|
|
|
} else {
|
|
|
|
trace_intel_disable_plane(&plane->base, crtc);
|
2017-03-03 01:15:05 +08:00
|
|
|
|
2018-09-20 18:27:08 +08:00
|
|
|
plane->disable_plane(plane, crtc);
|
|
|
|
}
|
2017-03-03 01:15:05 +08:00
|
|
|
}
|
2014-12-24 02:41:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
|
|
|
|
.prepare_fb = intel_prepare_plane_fb,
|
|
|
|
.cleanup_fb = intel_cleanup_plane_fb,
|
|
|
|
.atomic_check = intel_plane_atomic_check,
|
|
|
|
};
|
|
|
|
|
2015-01-22 08:35:43 +08:00
|
|
|
/**
|
|
|
|
* intel_plane_atomic_get_property - fetch plane property value
|
|
|
|
* @plane: plane to fetch property for
|
|
|
|
* @state: state containing the property value
|
|
|
|
* @property: property to look up
|
|
|
|
* @val: pointer to write property value into
|
|
|
|
*
|
|
|
|
* The DRM core does not store shadow copies of properties for
|
|
|
|
* atomic-capable drivers. This entrypoint is used to fetch
|
|
|
|
* the current value of a driver-specific plane property.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
intel_plane_atomic_get_property(struct drm_plane *plane,
|
|
|
|
const struct drm_plane_state *state,
|
|
|
|
struct drm_property *property,
|
|
|
|
uint64_t *val)
|
|
|
|
{
|
2018-06-12 03:34:03 +08:00
|
|
|
DRM_DEBUG_KMS("Unknown property [PROP:%d:%s]\n",
|
|
|
|
property->base.id, property->name);
|
2015-02-26 21:49:18 +08:00
|
|
|
return -EINVAL;
|
2015-01-22 08:35:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_plane_atomic_set_property - set plane property value
|
|
|
|
* @plane: plane to set property for
|
|
|
|
* @state: state to update property value in
|
|
|
|
* @property: property to set
|
|
|
|
* @val: value to set property to
|
|
|
|
*
|
|
|
|
* Writes the specified property value for a plane into the provided atomic
|
|
|
|
* state object.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -EINVAL on unrecognized properties
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
intel_plane_atomic_set_property(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state,
|
|
|
|
struct drm_property *property,
|
|
|
|
uint64_t val)
|
|
|
|
{
|
2018-06-12 03:34:03 +08:00
|
|
|
DRM_DEBUG_KMS("Unknown property [PROP:%d:%s]\n",
|
|
|
|
property->base.id, property->name);
|
2015-02-26 21:49:18 +08:00
|
|
|
return -EINVAL;
|
2015-01-22 08:35:43 +08:00
|
|
|
}
|