// SPDX-License-Identifier: MIT
/*
* Copyright © 2020 Intel Corporation
*/
#include <linux/kernel.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_blend.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_atomic_plane.h"
#include "intel_cursor.h"
#include "intel_cursor_regs.h"
#include "intel_de.h"
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_fb.h"
#include "intel_fb_pin.h"
#include "intel_frontbuffer.h"
#include "intel_psr.h"
#include "intel_psr_regs.h"
#include "intel_vblank.h"
#include "skl_watermark.h"
#include "gem/i915_gem_object.h"
/* Cursor formats */
static const u32 intel_cursor_formats[] = {
DRM_FORMAT_ARGB8888,
};
static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
u32 base;
if (DISPLAY_INFO(dev_priv)->cursor_needs_physical)
base = plane_state->phys_dma_addr;
else
base = intel_plane_ggtt_offset(plane_state);
return base + plane_state->view.color_plane[0].offset;
}
static u32 intel_cursor_position(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state,
bool early_tpt)
{
int x = plane_state->uapi.dst.x1;
int y = plane_state->uapi.dst.y1;
u32 pos = 0;
/*
* Formula from Bspec:
* MAX(-1 * <Cursor vertical size from CUR_CTL base on cursor mode
* select setting> + 1, CUR_POS Y Position - Update region Y position
*/
if (early_tpt)
y = max(-1 * drm_rect_height(&plane_state->uapi.dst) + 1,
y - crtc_state->psr2_su_area.y1);
if (x < 0) {
pos |= CURSOR_POS_X_SIGN;
x = -x;
}
pos |= CURSOR_POS_X(x);
if (y < 0) {
pos |= CURSOR_POS_Y_SIGN;
y = -y;
}
pos |= CURSOR_POS_Y(y);
return pos;
}
static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
{
const struct drm_mode_config *config =
&plane_state->uapi.plane->dev->mode_config;
int width = drm_rect_width(&plane_state->uapi.dst);
int height = drm_rect_height(&plane_state->uapi.dst);
return width > 0 && width <= config->cursor_width &&
height > 0 && height <= config->cursor_height;
}
static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->uapi.plane->dev);
unsigned int rotation = plane_state->hw.rotation;
int src_x, src_y;
u32 offset;
int ret;
ret = intel_plane_compute_gtt(plane_state);
if (ret)
return ret;
if (!plane_state->uapi.visible)
return 0;
src_x = plane_state->uapi.src.x1 >> 16;
src_y = plane_state->uapi.src.y1 >> 16;
intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
plane_state, 0);
if (src_x != 0 || src_y != 0) {
drm_dbg_kms(&dev_priv->drm,
"Arbitrary cursor panning not supported\n");
return -EINVAL;
}
/*
* Put the final coordinates back so that the src
* coordinate checks will see the right values.
*/
drm_rect_translate_to(&plane_state->uapi.src,
src_x << 16, src_y << 16);
/* ILK+ do this automagically in hardware */
if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
const struct drm_framebuffer *fb = plane_state->hw.fb;
int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
offset += (src_h * src_w - 1) * fb->format->cpp[0];
}
plane_state->view.color_plane[0].offset = offset;
plane_state->view.color_plane[0].x = src_x;
plane_state->view.color_plane[0].y = src_y;
return 0;
}
static int intel_check_cursor(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
const struct drm_rect src = plane_state->uapi.src;
const struct drm_rect dst = plane_state