mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Rework the plane init calls to do the gen test one level higher. Rework some of the plane helpers so they can live in new file, there is still some scope to clean up the plane/fb interactions later. v2: drop atomic code back, rename file to Ville suggestions, add header file. v3: move scaler bits back v4: drop wrong new includes (Ville) v5: integrate the ccs gen12 changes v6: fix unrelated code movement (Ville) Signed-off-by: Dave Airlie <airlied@redhat.com> [Jani: fixed up sparse warnings.] Signed-off-by: Jani Nikula <jani.nikula@intel.com> Reported-by: kernel test robot <lkp@intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/4e88a5c6b9ab3b93cc2b6c7d78c26ae86f6abbd0.1612536383.git.jani.nikula@intel.com
334 lines
8.9 KiB
C
334 lines
8.9 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2020 Intel Corporation
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_fourcc.h>
|
|
#include <drm/drm_plane.h>
|
|
#include <drm/drm_plane_helper.h>
|
|
|
|
#include "intel_atomic.h"
|
|
#include "intel_atomic_plane.h"
|
|
#include "intel_color.h"
|
|
#include "intel_crtc.h"
|
|
#include "intel_cursor.h"
|
|
#include "intel_display_debugfs.h"
|
|
#include "intel_display_types.h"
|
|
#include "intel_pipe_crc.h"
|
|
#include "intel_sprite.h"
|
|
#include "i9xx_plane.h"
|
|
#include "skl_universal_plane.h"
|
|
|
|
static void assert_vblank_disabled(struct drm_crtc *crtc)
|
|
{
|
|
if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
|
|
drm_crtc_vblank_put(crtc);
|
|
}
|
|
|
|
u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
|
|
{
|
|
struct drm_device *dev = crtc->base.dev;
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
|
|
|
|
if (!vblank->max_vblank_count)
|
|
return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
|
|
|
|
return crtc->base.funcs->get_vblank_counter(&crtc->base);
|
|
}
|
|
|
|
u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
|
|
{
|
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
|
u32 mode_flags = crtc->mode_flags;
|
|
|
|
/*
|
|
* From Gen 11, In case of dsi cmd mode, frame counter wouldnt
|
|
* have updated at the beginning of TE, if we want to use
|
|
* the hw counter, then we would find it updated in only
|
|
* the next TE, hence switching to sw counter.
|
|
*/
|
|
if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
|
|
return 0;
|
|
|
|
/*
|
|
* On i965gm the hardware frame counter reads
|
|
* zero when the TV encoder is enabled :(
|
|
*/
|
|
if (IS_I965GM(dev_priv) &&
|
|
(crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
|
|
return 0;
|
|
|
|
if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
|
|
return 0xffffffff; /* full 32 bit counter */
|
|
else if (INTEL_GEN(dev_priv) >= 3)
|
|
return 0xffffff; /* only 24 bits of frame count */
|
|
else
|
|
return 0; /* Gen2 doesn't have a hardware frame counter */
|
|
}
|
|
|
|
void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
|
|
{
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
|
|
|
assert_vblank_disabled(&crtc->base);
|
|
drm_crtc_set_max_vblank_count(&crtc->base,
|
|
intel_crtc_max_vblank_count(crtc_state));
|
|
drm_crtc_vblank_on(&crtc->base);
|
|
}
|
|
|
|
void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
|
|
{
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
|
|
|
drm_crtc_vblank_off(&crtc->base);
|
|
assert_vblank_disabled(&crtc->base);
|
|
}
|
|
|
|
struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
|
|
{
|
|
struct intel_crtc_state *crtc_state;
|
|
|
|
crtc_state = kmalloc(sizeof(*crtc_state), GFP_KERNEL);
|
|
|
|
if (crtc_state)
|
|
intel_crtc_state_reset(crtc_state, crtc);
|
|
|
|
return crtc_state;
|
|
}
|
|
|
|
void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
|
|
struct intel_crtc *crtc)
|
|
{
|
|
memset(crtc_state, 0, sizeof(*crtc_state));
|
|
|
|
__drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
|
|
|
|
crtc_state->cpu_transcoder = INVALID_TRANSCODER;
|
|
crtc_state->master_transcoder = INVALID_TRANSCODER;
|
|
crtc_state->hsw_workaround_pipe = INVALID_PIPE;
|
|
crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID;
|
|
crtc_state->scaler_state.scaler_id = -1;
|
|
crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
|
|
}
|
|
|
|
static struct intel_crtc *intel_crtc_alloc(void)
|
|
{
|
|
struct intel_crtc_state *crtc_state;
|
|
struct intel_crtc *crtc;
|
|
|
|
crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
|
|
if (!crtc)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
crtc_state = intel_crtc_state_alloc(crtc);
|
|
if (!crtc_state) {
|
|
kfree(crtc);
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
crtc->base.state = &crtc_state->uapi;
|
|
crtc->config = crtc_state;
|
|
|
|
return crtc;
|
|
}
|
|
|
|
static void intel_crtc_free(struct intel_crtc *crtc)
|
|
{
|
|
intel_crtc_destroy_state(&crtc->base, crtc->base.state);
|
|
kfree(crtc);
|
|
}
|
|
|
|
static void intel_crtc_destroy(struct drm_crtc *crtc)
|
|
{
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
drm_crtc_cleanup(crtc);
|
|
kfree(intel_crtc);
|
|
}
|
|
|
|
static int intel_crtc_late_register(struct drm_crtc *crtc)
|
|
{
|
|
intel_crtc_debugfs_add(crtc);
|
|
return 0;
|
|
}
|
|
|
|
#define INTEL_CRTC_FUNCS \
|
|
.set_config = drm_atomic_helper_set_config, \
|
|
.destroy = intel_crtc_destroy, \
|
|
.page_flip = drm_atomic_helper_page_flip, \
|
|
.atomic_duplicate_state = intel_crtc_duplicate_state, \
|
|
.atomic_destroy_state = intel_crtc_destroy_state, \
|
|
.set_crc_source = intel_crtc_set_crc_source, \
|
|
.verify_crc_source = intel_crtc_verify_crc_source, \
|
|
.get_crc_sources = intel_crtc_get_crc_sources, \
|
|
.late_register = intel_crtc_late_register
|
|
|
|
static const struct drm_crtc_funcs bdw_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
.get_vblank_counter = g4x_get_vblank_counter,
|
|
.enable_vblank = bdw_enable_vblank,
|
|
.disable_vblank = bdw_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
static const struct drm_crtc_funcs ilk_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
.get_vblank_counter = g4x_get_vblank_counter,
|
|
.enable_vblank = ilk_enable_vblank,
|
|
.disable_vblank = ilk_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
static const struct drm_crtc_funcs g4x_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
.get_vblank_counter = g4x_get_vblank_counter,
|
|
.enable_vblank = i965_enable_vblank,
|
|
.disable_vblank = i965_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
static const struct drm_crtc_funcs i965_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
.get_vblank_counter = i915_get_vblank_counter,
|
|
.enable_vblank = i965_enable_vblank,
|
|
.disable_vblank = i965_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
static const struct drm_crtc_funcs i915gm_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
.get_vblank_counter = i915_get_vblank_counter,
|
|
.enable_vblank = i915gm_enable_vblank,
|
|
.disable_vblank = i915gm_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
static const struct drm_crtc_funcs i915_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
.get_vblank_counter = i915_get_vblank_counter,
|
|
.enable_vblank = i8xx_enable_vblank,
|
|
.disable_vblank = i8xx_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
static const struct drm_crtc_funcs i8xx_crtc_funcs = {
|
|
INTEL_CRTC_FUNCS,
|
|
|
|
/* no hw vblank counter */
|
|
.enable_vblank = i8xx_enable_vblank,
|
|
.disable_vblank = i8xx_disable_vblank,
|
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
|
};
|
|
|
|
int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|
{
|
|
struct intel_plane *primary, *cursor;
|
|
const struct drm_crtc_funcs *funcs;
|
|
struct intel_crtc *crtc;
|
|
int sprite, ret;
|
|
|
|
crtc = intel_crtc_alloc();
|
|
if (IS_ERR(crtc))
|
|
return PTR_ERR(crtc);
|
|
|
|
crtc->pipe = pipe;
|
|
crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
|
primary = skl_universal_plane_create(dev_priv, pipe,
|
|
PLANE_PRIMARY);
|
|
else
|
|
primary = intel_primary_plane_create(dev_priv, pipe);
|
|
if (IS_ERR(primary)) {
|
|
ret = PTR_ERR(primary);
|
|
goto fail;
|
|
}
|
|
crtc->plane_ids_mask |= BIT(primary->id);
|
|
|
|
for_each_sprite(dev_priv, pipe, sprite) {
|
|
struct intel_plane *plane;
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
|
plane = skl_universal_plane_create(dev_priv, pipe,
|
|
PLANE_SPRITE0 + sprite);
|
|
else
|
|
plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
|
|
if (IS_ERR(plane)) {
|
|
ret = PTR_ERR(plane);
|
|
goto fail;
|
|
}
|
|
crtc->plane_ids_mask |= BIT(plane->id);
|
|
}
|
|
|
|
cursor = intel_cursor_plane_create(dev_priv, pipe);
|
|
if (IS_ERR(cursor)) {
|
|
ret = PTR_ERR(cursor);
|
|
goto fail;
|
|
}
|
|
crtc->plane_ids_mask |= BIT(cursor->id);
|
|
|
|
if (HAS_GMCH(dev_priv)) {
|
|
if (IS_CHERRYVIEW(dev_priv) ||
|
|
IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
|
|
funcs = &g4x_crtc_funcs;
|
|
else if (IS_GEN(dev_priv, 4))
|
|
funcs = &i965_crtc_funcs;
|
|
else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
|
|
funcs = &i915gm_crtc_funcs;
|
|
else if (IS_GEN(dev_priv, 3))
|
|
funcs = &i915_crtc_funcs;
|
|
else
|
|
funcs = &i8xx_crtc_funcs;
|
|
} else {
|
|
if (INTEL_GEN(dev_priv) >= 8)
|
|
funcs = &bdw_crtc_funcs;
|
|
else
|
|
funcs = &ilk_crtc_funcs;
|
|
}
|
|
|
|
ret = drm_crtc_init_with_planes(&dev_priv->drm, &crtc->base,
|
|
&primary->base, &cursor->base,
|
|
funcs, "pipe %c", pipe_name(pipe));
|
|
if (ret)
|
|
goto fail;
|
|
|
|
BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||
|
|
dev_priv->pipe_to_crtc_mapping[pipe] != NULL);
|
|
dev_priv->pipe_to_crtc_mapping[pipe] = crtc;
|
|
|
|
if (INTEL_GEN(dev_priv) < 9) {
|
|
enum i9xx_plane_id i9xx_plane = primary->i9xx_plane;
|
|
|
|
BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
|
|
dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);
|
|
dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
|
|
}
|
|
|
|
if (INTEL_GEN(dev_priv) >= 10)
|
|
drm_crtc_create_scaling_filter_property(&crtc->base,
|
|
BIT(DRM_SCALING_FILTER_DEFAULT) |
|
|
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
|
|
|
|
intel_color_init(crtc);
|
|
|
|
intel_crtc_crc_init(crtc);
|
|
|
|
drm_WARN_ON(&dev_priv->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
intel_crtc_free(crtc);
|
|
|
|
return ret;
|
|
}
|