Commit 116d86dd authored by Jocelyn Falempe's avatar Jocelyn Falempe Committed by Maarten Lankhorst
Browse files

drm/i915/display: Add drm_panic support for Y-tiling with DPT



On Alder Lake and later, it's not possible to disable tiling when DPT
is enabled.
So this commit implements Y-Tiling support, to still be able to draw
the panic screen.

Signed-off-by: default avatarJocelyn Falempe <jfalempe@redhat.com>
Link: https://lore.kernel.org/r/20250624091501.257661-10-jfalempe@redhat.com


Signed-off-by: default avatarMaarten Lankhorst <dev@lankhorst.se>
parent 31d886b6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -146,6 +146,8 @@ struct intel_framebuffer {

	unsigned int min_alignment;
	unsigned int vtd_guard;

	unsigned int (*panic_tiling)(unsigned int x, unsigned int y, unsigned int width);
};

enum intel_hotplug_state {
+62 −2
Original line number Diff line number Diff line
@@ -1272,6 +1272,32 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
	intel_plane_unpin_fb(old_plane_state);
}

/* Handle Y-tiling, only if DPT is enabled (otherwise disabling tiling is easier)
 * All DPT hardware have 128-bytes width tiling, so Y-tile dimension is 32x32
 * pixels for 32bits pixels.
 */
#define YTILE_WIDTH	32
#define YTILE_HEIGHT	32
#define YTILE_SIZE (YTILE_WIDTH * YTILE_HEIGHT * 4)

static unsigned int intel_ytile_get_offset(unsigned int width, unsigned int x, unsigned int y)
{
	u32 offset;
	unsigned int swizzle;
	unsigned int width_in_blocks = DIV_ROUND_UP(width, 32);

	/* Block offset */
	offset = ((y / YTILE_HEIGHT) * width_in_blocks + (x / YTILE_WIDTH)) * YTILE_SIZE;

	x = x % YTILE_WIDTH;
	y = y % YTILE_HEIGHT;

	/* bit order inside a block is x4 x3 x2 y4 y3 y2 y1 y0 x1 x0 */
	swizzle = (x & 3) | ((y & 0x1f) << 2) | ((x & 0x1c) << 5);
	offset += swizzle * 4;
	return offset;
}

static void intel_panic_flush(struct drm_plane *plane)
{
	struct intel_plane_state *plane_state = to_intel_plane_state(plane->state);
@@ -1295,6 +1321,35 @@ static void intel_panic_flush(struct drm_plane *plane)
		iplane->disable_tiling(iplane);
}

static unsigned int (*intel_get_tiling_func(u64 fb_modifier))(unsigned int width,
							      unsigned int x,
							      unsigned int y)
{
	switch (fb_modifier) {
	case I915_FORMAT_MOD_Y_TILED:
	case I915_FORMAT_MOD_Y_TILED_CCS:
	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
		return intel_ytile_get_offset;
	case I915_FORMAT_MOD_4_TILED:
	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
	case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
	case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
	case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
	case I915_FORMAT_MOD_4_TILED_BMG_CCS:
	case I915_FORMAT_MOD_4_TILED_LNL_CCS:
	case I915_FORMAT_MOD_X_TILED:
	case I915_FORMAT_MOD_Yf_TILED:
	case I915_FORMAT_MOD_Yf_TILED_CCS:
	default:
	/* Not supported yet */
		return NULL;
	}
}

static int intel_get_scanout_buffer(struct drm_plane *plane,
				    struct drm_scanout_buffer *sb)
{
@@ -1320,8 +1375,13 @@ static int intel_get_scanout_buffer(struct drm_plane *plane,
	} else {
		int ret;
		/* Can't disable tiling if DPT is in use */
		if (intel_fb_uses_dpt(fb))
		if (intel_fb_uses_dpt(fb)) {
			if (fb->format->cpp[0] != 4)
				return -EOPNOTSUPP;
			intel_fb->panic_tiling = intel_get_tiling_func(fb->modifier);
			if (!intel_fb->panic_tiling)
				return -EOPNOTSUPP;
		}
		sb->private = intel_fb;
		ret = intel_bo_panic_setup(sb);
		if (ret)
+11 −4
Original line number Diff line number Diff line
@@ -2795,15 +2795,22 @@ static void skl_disable_tiling(struct intel_plane *plane)
{
	struct intel_plane_state *state = to_intel_plane_state(plane->base.state);
	struct intel_display *display = to_intel_display(plane);
	u32 stride = state->view.color_plane[0].scanout_stride / 64;
	const struct drm_framebuffer *fb = state->hw.fb;
	u32 plane_ctl;

	plane_ctl = intel_de_read(display, PLANE_CTL(plane->pipe, plane->id));
	plane_ctl &= ~PLANE_CTL_TILED_MASK;

	if (intel_fb_uses_dpt(fb)) {
		/* if DPT is enabled, keep tiling, but disable compression */
		plane_ctl &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
	} else {
		/* if DPT is not supported, disable tiling, and update stride */
		u32 stride = state->view.color_plane[0].scanout_stride / 64;

		plane_ctl &= ~PLANE_CTL_TILED_MASK;
		intel_de_write_fw(display, PLANE_STRIDE(plane->pipe, plane->id),
				  PLANE_STRIDE_(stride));

	}
	intel_de_write_fw(display, PLANE_CTL(plane->pipe, plane->id), plane_ctl);

	intel_de_write_fw(display, PLANE_SURF(plane->pipe, plane->id),
+15 −1
Original line number Diff line number Diff line
@@ -400,6 +400,15 @@ static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj
	return pages;
}

static void i915_gem_object_panic_map_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
						unsigned int y, u32 color)
{
	struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
	unsigned int offset = fb->panic_tiling(sb->width, x, y);

	iosys_map_wr(&sb->map[0], offset, u32, color);
}

/*
 * The scanout buffer pages are not mapped, so for each pixel,
 * use kmap_local_page_try_from_panic() to map the page, and write the pixel.
@@ -413,6 +422,9 @@ static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb,
	struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
	struct i915_panic_data *panic = to_i915_panic_data(fb);

	if (fb->panic_tiling)
		offset = fb->panic_tiling(sb->width, x, y);
	else
		offset = y * sb->pitch[0] + x * sb->format->cpp[0];

	new_page = offset >> PAGE_SHIFT;
@@ -459,6 +471,8 @@ int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb)
		else
			iosys_map_set_vaddr(&sb->map[0], ptr);

		if (fb->panic_tiling)
			sb->set_pixel = i915_gem_object_panic_map_set_pixel;
		return 0;
	}
	if (i915_gem_object_has_struct_page(obj)) {
+4 −1
Original line number Diff line number Diff line
@@ -104,6 +104,9 @@ static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int
	unsigned int new_page;
	unsigned int offset;

	if (fb->panic_tiling)
		offset = fb->panic_tiling(sb->width, x, y);
	else
		offset = y * sb->pitch[0] + x * sb->format->cpp[0];

	new_page = offset >> PAGE_SHIFT;