summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/xe/display
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2023-08-17 23:30:41 +0300
committerRodrigo Vivi <rodrigo.vivi@intel.com>2023-12-21 19:43:39 +0300
commit44e694958b95395bd1c41508c88c8ca141bf9bd7 (patch)
tree1b3e18abe5f05a6716e6dee725a3c2c50d5db30c /drivers/gpu/drm/xe/display
parenta839e365ac88f0fa9f8c7ae92b9e7e66bbd9e4d7 (diff)
downloadlinux-44e694958b95395bd1c41508c88c8ca141bf9bd7.tar.xz
drm/xe/display: Implement display support
As for display, the intent is to share the display code with the i915 driver so that there is maximum reuse there. We do this by recompiling i915/display code twice. Now that i915 has been adapted to support the Xe build, we can add the xe/display support. This initial work is a collaboration of many people and unfortunately this squashed patch won't fully honor the proper credits. But let's try to add a few from the squashed patches: Co-developed-by: Matthew Brost <matthew.brost@intel.com> Co-developed-by: Jani Nikula <jani.nikula@intel.com> Co-developed-by: Lucas De Marchi <lucas.demarchi@intel.com> Co-developed-by: Matt Roper <matthew.d.roper@intel.com> Co-developed-by: Mauro Carvalho Chehab <mchehab@kernel.org> Co-developed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Co-developed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Diffstat (limited to 'drivers/gpu/drm/xe/display')
-rw-r--r--drivers/gpu/drm/xe/display/ext/i915_irq.c77
-rw-r--r--drivers/gpu/drm/xe/display/ext/i915_utils.c22
-rw-r--r--drivers/gpu/drm/xe/display/intel_fb_bo.c74
-rw-r--r--drivers/gpu/drm/xe/display/intel_fb_bo.h24
-rw-r--r--drivers/gpu/drm/xe/display/intel_fbdev_fb.c104
-rw-r--r--drivers/gpu/drm/xe/display/intel_fbdev_fb.h21
-rw-r--r--drivers/gpu/drm/xe/display/xe_display_rps.c17
-rw-r--r--drivers/gpu/drm/xe/display/xe_fb_pin.c326
-rw-r--r--drivers/gpu/drm/xe/display/xe_hdcp_gsc.c24
-rw-r--r--drivers/gpu/drm/xe/display/xe_plane_initial.c291
10 files changed, 980 insertions, 0 deletions
diff --git a/drivers/gpu/drm/xe/display/ext/i915_irq.c b/drivers/gpu/drm/xe/display/ext/i915_irq.c
new file mode 100644
index 000000000000..bee191a4a97d
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/ext/i915_irq.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "i915_irq.h"
+#include "i915_reg.h"
+#include "intel_uncore.h"
+
+void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
+ i915_reg_t iir, i915_reg_t ier)
+{
+ intel_uncore_write(uncore, imr, 0xffffffff);
+ intel_uncore_posting_read(uncore, imr);
+
+ intel_uncore_write(uncore, ier, 0);
+
+ /* IIR can theoretically queue up two events. Be paranoid. */
+ intel_uncore_write(uncore, iir, 0xffffffff);
+ intel_uncore_posting_read(uncore, iir);
+ intel_uncore_write(uncore, iir, 0xffffffff);
+ intel_uncore_posting_read(uncore, iir);
+}
+
+/*
+ * We should clear IMR at preinstall/uninstall, and just check at postinstall.
+ */
+void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg)
+{
+ struct xe_device *xe = container_of(uncore, struct xe_device, uncore);
+ u32 val = intel_uncore_read(uncore, reg);
+
+ if (val == 0)
+ return;
+
+ drm_WARN(&xe->drm, 1,
+ "Interrupt register 0x%x is not zero: 0x%08x\n",
+ i915_mmio_reg_offset(reg), val);
+ intel_uncore_write(uncore, reg, 0xffffffff);
+ intel_uncore_posting_read(uncore, reg);
+ intel_uncore_write(uncore, reg, 0xffffffff);
+ intel_uncore_posting_read(uncore, reg);
+}
+
+void gen3_irq_init(struct intel_uncore *uncore,
+ i915_reg_t imr, u32 imr_val,
+ i915_reg_t ier, u32 ier_val,
+ i915_reg_t iir)
+{
+ gen3_assert_iir_is_zero(uncore, iir);
+
+ intel_uncore_write(uncore, ier, ier_val);
+ intel_uncore_write(uncore, imr, imr_val);
+ intel_uncore_posting_read(uncore, imr);
+}
+
+bool intel_irqs_enabled(struct xe_device *xe)
+{
+ /*
+ * XXX: i915 has a racy handling of the irq.enabled, since it doesn't
+ * lock its transitions. Because of that, the irq.enabled sometimes
+ * is not read with the irq.lock in place.
+ * However, the most critical cases like vblank and page flips are
+ * properly using the locks.
+ * We cannot take the lock in here or run any kind of assert because
+ * of i915 inconsistency.
+ * But at this point the xe irq is better protected against races,
+ * although the full solution would be protecting the i915 side.
+ */
+ return xe->irq.enabled;
+}
+
+void intel_synchronize_irq(struct xe_device *xe)
+{
+ synchronize_irq(to_pci_dev(xe->drm.dev)->irq);
+}
diff --git a/drivers/gpu/drm/xe/display/ext/i915_utils.c b/drivers/gpu/drm/xe/display/ext/i915_utils.c
new file mode 100644
index 000000000000..981edc2788bc
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/ext/i915_utils.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "i915_drv.h"
+
+bool i915_vtd_active(struct drm_i915_private *i915)
+{
+ if (device_iommu_mapped(i915->drm.dev))
+ return true;
+
+ /* Running as a guest, we assume the host is enforcing VT'd */
+ return i915_run_as_guest();
+}
+
+/* i915 specific, just put here for shutting it up */
+int __i915_inject_probe_error(struct drm_i915_private *i915, int err,
+ const char *func, int line)
+{
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/display/intel_fb_bo.c b/drivers/gpu/drm/xe/display/intel_fb_bo.c
new file mode 100644
index 000000000000..b21da7b745a5
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/intel_fb_bo.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include <drm/drm_modeset_helper.h>
+
+#include "i915_drv.h"
+#include "intel_display_types.h"
+#include "intel_fb_bo.h"
+
+void intel_fb_bo_framebuffer_fini(struct xe_bo *bo)
+{
+ if (bo->flags & XE_BO_CREATE_PINNED_BIT) {
+ /* Unpin our kernel fb first */
+ xe_bo_lock(bo, false);
+ xe_bo_unpin(bo);
+ xe_bo_unlock(bo);
+ }
+ xe_bo_put(bo);
+}
+
+int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb,
+ struct xe_bo *bo,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_i915_private *i915 = to_i915(bo->ttm.base.dev);
+ int ret;
+
+ xe_bo_get(bo);
+
+ ret = ttm_bo_reserve(&bo->ttm, true, false, NULL);
+ if (ret)
+ return ret;
+
+ if (!(bo->flags & XE_BO_SCANOUT_BIT)) {
+ /*
+ * XE_BO_SCANOUT_BIT should ideally be set at creation, or is
+ * automatically set when creating FB. We cannot change caching
+ * mode when the boect is VM_BINDed, so we can only set
+ * coherency with display when unbound.
+ */
+ if (XE_IOCTL_DBG(i915, !list_empty(&bo->ttm.base.gpuva.list))) {
+ ttm_bo_unreserve(&bo->ttm);
+ return -EINVAL;
+ }
+ bo->flags |= XE_BO_SCANOUT_BIT;
+ }
+ ttm_bo_unreserve(&bo->ttm);
+
+ return ret;
+}
+
+struct xe_bo *intel_fb_bo_lookup_valid_bo(struct drm_i915_private *i915,
+ struct drm_file *filp,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_i915_gem_object *bo;
+ struct drm_gem_object *gem = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+
+ if (!gem)
+ return ERR_PTR(-ENOENT);
+
+ bo = gem_to_xe_bo(gem);
+ /* Require vram placement or dma-buf import */
+ if (IS_DGFX(i915) &&
+ !xe_bo_can_migrate(gem_to_xe_bo(gem), XE_PL_VRAM0) &&
+ bo->ttm.type != ttm_bo_type_sg) {
+ drm_gem_object_put(gem);
+ return ERR_PTR(-EREMOTE);
+ }
+
+ return bo;
+}
diff --git a/drivers/gpu/drm/xe/display/intel_fb_bo.h b/drivers/gpu/drm/xe/display/intel_fb_bo.h
new file mode 100644
index 000000000000..5d365b925b7a
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/intel_fb_bo.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#ifndef __INTEL_FB_BO_H__
+#define __INTEL_FB_BO_H__
+
+struct drm_file;
+struct drm_mode_fb_cmd2;
+struct drm_i915_private;
+struct intel_framebuffer;
+struct xe_bo;
+
+void intel_fb_bo_framebuffer_fini(struct xe_bo *bo);
+int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb,
+ struct xe_bo *bo,
+ struct drm_mode_fb_cmd2 *mode_cmd);
+
+struct xe_bo *intel_fb_bo_lookup_valid_bo(struct drm_i915_private *i915,
+ struct drm_file *filp,
+ const struct drm_mode_fb_cmd2 *mode_cmd);
+
+#endif
diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
new file mode 100644
index 000000000000..51ae3561fd0d
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "intel_fbdev_fb.h"
+
+#include <drm/drm_fb_helper.h>
+
+#include "xe_gt.h"
+#include "xe_ttm_stolen_mgr.h"
+
+#include "i915_drv.h"
+#include "intel_display_types.h"
+
+struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_framebuffer *fb;
+ struct drm_device *dev = helper->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_mode_fb_cmd2 mode_cmd = {};
+ struct drm_i915_gem_object *obj;
+ int size;
+
+ /* we don't do packed 24bpp */
+ if (sizes->surface_bpp == 24)
+ sizes->surface_bpp = 32;
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+
+ mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
+ DIV_ROUND_UP(sizes->surface_bpp, 8), XE_PAGE_SIZE);
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ size = mode_cmd.pitches[0] * mode_cmd.height;
+ size = PAGE_ALIGN(size);
+ obj = ERR_PTR(-ENODEV);
+
+ if (!IS_DGFX(dev_priv)) {
+ obj = xe_bo_create_pin_map(dev_priv, xe_device_get_root_tile(dev_priv),
+ NULL, size,
+ ttm_bo_type_kernel, XE_BO_SCANOUT_BIT |
+ XE_BO_CREATE_STOLEN_BIT |
+ XE_BO_CREATE_PINNED_BIT);
+ if (!IS_ERR(obj))
+ drm_info(&dev_priv->drm, "Allocated fbdev into stolen\n");
+ else
+ drm_info(&dev_priv->drm, "Allocated fbdev into stolen failed: %li\n", PTR_ERR(obj));
+ }
+ if (IS_ERR(obj)) {
+ obj = xe_bo_create_pin_map(dev_priv, xe_device_get_root_tile(dev_priv), NULL, size,
+ ttm_bo_type_kernel, XE_BO_SCANOUT_BIT |
+ XE_BO_CREATE_VRAM_IF_DGFX(xe_device_get_root_tile(dev_priv)) |
+ XE_BO_CREATE_PINNED_BIT);
+ }
+
+ if (IS_ERR(obj)) {
+ drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj);
+ fb = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ fb = intel_framebuffer_create(obj, &mode_cmd);
+ if (IS_ERR(fb)) {
+ xe_bo_unpin_map_no_vm(obj);
+ goto err;
+ }
+
+ drm_gem_object_put(intel_bo_to_drm_bo(obj));
+ return fb;
+
+err:
+ return fb;
+}
+
+int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info,
+ struct drm_i915_gem_object *obj, struct i915_vma *vma)
+{
+ struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+
+ if (!(obj->flags & XE_BO_CREATE_SYSTEM_BIT)) {
+ if (obj->flags & XE_BO_CREATE_STOLEN_BIT)
+ info->fix.smem_start = xe_ttm_stolen_io_offset(obj, 0);
+ else
+ info->fix.smem_start =
+ pci_resource_start(pdev, 2) +
+ xe_bo_addr(obj, 0, XE_PAGE_SIZE);
+
+ info->fix.smem_len = obj->ttm.base.size;
+ } else {
+ /* XXX: Pure fiction, as the BO may not be physically accessible.. */
+ info->fix.smem_start = 0;
+ info->fix.smem_len = obj->ttm.base.size;
+ }
+ XE_WARN_ON(iosys_map_is_null(&obj->vmap));
+
+ info->screen_base = obj->vmap.vaddr_iomem;
+ info->screen_size = intel_bo_to_drm_bo(obj)->size;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.h b/drivers/gpu/drm/xe/display/intel_fbdev_fb.h
new file mode 100644
index 000000000000..ea186772e0bb
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_FBDEV_FB_H__
+#define __INTEL_FBDEV_FB_H__
+
+struct drm_fb_helper;
+struct drm_fb_helper_surface_size;
+struct drm_i915_gem_object;
+struct drm_i915_private;
+struct fb_info;
+struct i915_vma;
+
+struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes);
+int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info,
+ struct drm_i915_gem_object *obj, struct i915_vma *vma);
+
+#endif
diff --git a/drivers/gpu/drm/xe/display/xe_display_rps.c b/drivers/gpu/drm/xe/display/xe_display_rps.c
new file mode 100644
index 000000000000..ab21c581c192
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_display_rps.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "intel_display_rps.h"
+
+void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc,
+ struct dma_fence *fence)
+{
+}
+
+void intel_display_rps_mark_interactive(struct drm_i915_private *i915,
+ struct intel_atomic_state *state,
+ bool interactive)
+{
+}
diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c
new file mode 100644
index 000000000000..67b956a6da8d
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "intel_display_types.h"
+#include "intel_dpt.h"
+#include "intel_fb.h"
+#include "intel_fb_pin.h"
+#include "xe_ggtt.h"
+#include "xe_gt.h"
+
+#include <drm/ttm/ttm_bo.h>
+
+static void
+write_dpt_rotated(struct xe_bo *bo, struct iosys_map *map, u32 *dpt_ofs, u32 bo_ofs,
+ u32 width, u32 height, u32 src_stride, u32 dst_stride)
+{
+ struct xe_device *xe = xe_bo_device(bo);
+ struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
+ u32 column, row;
+
+ /* TODO: Maybe rewrite so we can traverse the bo addresses sequentially,
+ * by writing dpt/ggtt in a different order?
+ */
+
+ for (column = 0; column < width; column++) {
+ u32 src_idx = src_stride * (height - 1) + column + bo_ofs;
+
+ for (row = 0; row < height; row++) {
+ u64 pte = ggtt->pt_ops->pte_encode_bo(bo, src_idx * XE_PAGE_SIZE,
+ xe->pat.idx[XE_CACHE_WB]);
+
+ iosys_map_wr(map, *dpt_ofs, u64, pte);
+ *dpt_ofs += 8;
+ src_idx -= src_stride;
+ }
+
+ /* The DE ignores the PTEs for the padding tiles */
+ *dpt_ofs += (dst_stride - height) * 8;
+ }
+
+ /* Align to next page */
+ *dpt_ofs = ALIGN(*dpt_ofs, 4096);
+}
+
+static int __xe_pin_fb_vma_dpt(struct intel_framebuffer *fb,
+ const struct i915_gtt_view *view,
+ struct i915_vma *vma)
+{
+ struct xe_device *xe = to_xe_device(fb->base.dev);
+ struct xe_tile *tile0 = xe_device_get_root_tile(xe);
+ struct xe_ggtt *ggtt = tile0->mem.ggtt;
+ struct xe_bo *bo = intel_fb_obj(&fb->base), *dpt;
+ u32 dpt_size, size = bo->ttm.base.size;
+
+ if (view->type == I915_GTT_VIEW_NORMAL)
+ dpt_size = ALIGN(size / XE_PAGE_SIZE * 8, XE_PAGE_SIZE);
+ else
+ /* display uses 4K tiles instead of bytes here, convert to entries.. */
+ dpt_size = ALIGN(intel_rotation_info_size(&view->rotated) * 8,
+ XE_PAGE_SIZE);
+
+ dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
+ ttm_bo_type_kernel,
+ XE_BO_CREATE_VRAM0_BIT |
+ XE_BO_CREATE_GGTT_BIT);
+ if (IS_ERR(dpt))
+ dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
+ ttm_bo_type_kernel,
+ XE_BO_CREATE_STOLEN_BIT |
+ XE_BO_CREATE_GGTT_BIT);
+ if (IS_ERR(dpt))
+ dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
+ ttm_bo_type_kernel,
+ XE_BO_CREATE_SYSTEM_BIT |
+ XE_BO_CREATE_GGTT_BIT);
+ if (IS_ERR(dpt))
+ return PTR_ERR(dpt);
+
+ if (view->type == I915_GTT_VIEW_NORMAL) {
+ u32 x;
+
+ for (x = 0; x < size / XE_PAGE_SIZE; x++) {
+ u64 pte = ggtt->pt_ops->pte_encode_bo(bo, x * XE_PAGE_SIZE,
+ xe->pat.idx[XE_CACHE_WB]);
+
+ iosys_map_wr(&dpt->vmap, x * 8, u64, pte);
+ }
+ } else {
+ const struct intel_rotation_info *rot_info = &view->rotated;
+ u32 i, dpt_ofs = 0;
+
+ for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
+ write_dpt_rotated(bo, &dpt->vmap, &dpt_ofs,
+ rot_info->plane[i].offset,
+ rot_info->plane[i].width,
+ rot_info->plane[i].height,
+ rot_info->plane[i].src_stride,
+ rot_info->plane[i].dst_stride);
+ }
+
+ vma->dpt = dpt;
+ vma->node = dpt->ggtt_node;
+ return 0;
+}
+
+static void
+write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo_ofs,
+ u32 width, u32 height, u32 src_stride, u32 dst_stride)
+{
+ struct xe_device *xe = xe_bo_device(bo);
+ u32 column, row;
+
+ for (column = 0; column < width; column++) {
+ u32 src_idx = src_stride * (height - 1) + column + bo_ofs;
+
+ for (row = 0; row < height; row++) {
+ u64 pte = ggtt->pt_ops->pte_encode_bo(bo, src_idx * XE_PAGE_SIZE,
+ xe->pat.idx[XE_CACHE_WB]);
+
+ xe_ggtt_set_pte(ggtt, *ggtt_ofs, pte);
+ *ggtt_ofs += XE_PAGE_SIZE;
+ src_idx -= src_stride;
+ }
+
+ /* The DE ignores the PTEs for the padding tiles */
+ *ggtt_ofs += (dst_stride - height) * XE_PAGE_SIZE;
+ }
+}
+
+static int __xe_pin_fb_vma_ggtt(struct intel_framebuffer *fb,
+ const struct i915_gtt_view *view,
+ struct i915_vma *vma)
+{
+ struct xe_bo *bo = intel_fb_obj(&fb->base);
+ struct xe_device *xe = to_xe_device(fb->base.dev);
+ struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
+ u32 align;
+ int ret;
+
+ /* TODO: Consider sharing framebuffer mapping?
+ * embed i915_vma inside intel_framebuffer
+ */
+ xe_device_mem_access_get(tile_to_xe(ggtt->tile));
+ ret = mutex_lock_interruptible(&ggtt->lock);
+ if (ret)
+ goto out;
+
+ align = XE_PAGE_SIZE;
+ if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K)
+ align = max_t(u32, align, SZ_64K);
+
+ if (bo->ggtt_node.size && view->type == I915_GTT_VIEW_NORMAL) {
+ vma->node = bo->ggtt_node;
+ } else if (view->type == I915_GTT_VIEW_NORMAL) {
+ u32 x, size = bo->ttm.base.size;
+
+ ret = xe_ggtt_insert_special_node_locked(ggtt, &vma->node, size,
+ align, 0);
+ if (ret)
+ goto out_unlock;
+
+ for (x = 0; x < size; x += XE_PAGE_SIZE) {
+ u64 pte = ggtt->pt_ops->pte_encode_bo(bo, x,
+ xe->pat.idx[XE_CACHE_WB]);
+
+ xe_ggtt_set_pte(ggtt, vma->node.start + x, pte);
+ }
+ } else {
+ u32 i, ggtt_ofs;
+ const struct intel_rotation_info *rot_info = &view->rotated;
+
+ /* display seems to use tiles instead of bytes here, so convert it back.. */
+ u32 size = intel_rotation_info_size(rot_info) * XE_PAGE_SIZE;
+
+ ret = xe_ggtt_insert_special_node_locked(ggtt, &vma->node, size,
+ align, 0);
+ if (ret)
+ goto out_unlock;
+
+ ggtt_ofs = vma->node.start;
+
+ for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
+ write_ggtt_rotated(bo, ggtt, &ggtt_ofs,
+ rot_info->plane[i].offset,
+ rot_info->plane[i].width,
+ rot_info->plane[i].height,
+ rot_info->plane[i].src_stride,
+ rot_info->plane[i].dst_stride);
+ }
+
+ xe_ggtt_invalidate(ggtt);
+out_unlock:
+ mutex_unlock(&ggtt->lock);
+out:
+ xe_device_mem_access_put(tile_to_xe(ggtt->tile));
+ return ret;
+}
+
+static struct i915_vma *__xe_pin_fb_vma(struct intel_framebuffer *fb,
+ const struct i915_gtt_view *view)
+{
+ struct drm_device *dev = fb->base.dev;
+ struct xe_device *xe = to_xe_device(dev);
+ struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
+ struct xe_bo *bo = intel_fb_obj(&fb->base);
+ int ret;
+
+ if (!vma)
+ return ERR_PTR(-ENODEV);
+
+ /* Remapped view is only required on ADL-P, which xe doesn't support. */
+ if (XE_WARN_ON(view->type == I915_GTT_VIEW_REMAPPED)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /*
+ * Pin the framebuffer, we can't use xe_bo_(un)pin functions as the
+ * assumptions are incorrect for framebuffers
+ */
+ ret = ttm_bo_reserve(&bo->ttm, false, false, NULL);
+ if (ret)
+ goto err;
+
+ if (IS_DGFX(xe))
+ ret = xe_bo_migrate(bo, XE_PL_VRAM0);
+ else
+ ret = xe_bo_validate(bo, NULL, true);
+ if (!ret)
+ ttm_bo_pin(&bo->ttm);
+ ttm_bo_unreserve(&bo->ttm);
+ if (ret)
+ goto err;
+
+ vma->bo = bo;
+ if (intel_fb_uses_dpt(&fb->base))
+ ret = __xe_pin_fb_vma_dpt(fb, view, vma);
+ else
+ ret = __xe_pin_fb_vma_ggtt(fb, view, vma);
+ if (ret)
+ goto err_unpin;
+
+ return vma;
+
+err_unpin:
+ ttm_bo_reserve(&bo->ttm, false, false, NULL);
+ ttm_bo_unpin(&bo->ttm);
+ ttm_bo_unreserve(&bo->ttm);
+err:
+ kfree(vma);
+ return ERR_PTR(ret);
+}
+
+static void __xe_unpin_fb_vma(struct i915_vma *vma)
+{
+ struct xe_device *xe = to_xe_device(vma->bo->ttm.base.dev);
+ struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
+
+ if (vma->dpt)
+ xe_bo_unpin_map_no_vm(vma->dpt);
+ else if (!drm_mm_node_allocated(&vma->bo->ggtt_node) ||
+ vma->bo->ggtt_node.start != vma->node.start)
+ xe_ggtt_remove_node(ggtt, &vma->node);
+
+ ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);
+ ttm_bo_unpin(&vma->bo->ttm);
+ ttm_bo_unreserve(&vma->bo->ttm);
+ kfree(vma);
+}
+
+struct i915_vma *
+intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
+ bool phys_cursor,
+ const struct i915_gtt_view *view,
+ bool uses_fence,
+ unsigned long *out_flags)
+{
+ *out_flags = 0;
+
+ return __xe_pin_fb_vma(to_intel_framebuffer(fb), view);
+}
+
+void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags)
+{
+ __xe_unpin_fb_vma(vma);
+}
+
+int intel_plane_pin_fb(struct intel_plane_state *plane_state)
+{
+ struct drm_framebuffer *fb = plane_state->hw.fb;
+ struct xe_bo *bo = intel_fb_obj(fb);
+ struct i915_vma *vma;
+
+ /* We reject creating !SCANOUT fb's, so this is weird.. */
+ drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_SCANOUT_BIT));
+
+ vma = __xe_pin_fb_vma(to_intel_framebuffer(fb), &plane_state->view.gtt);
+ if (IS_ERR(vma))
+ return PTR_ERR(vma);
+
+ plane_state->ggtt_vma = vma;
+ return 0;
+}
+
+void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
+{
+ __xe_unpin_fb_vma(old_plane_state->ggtt_vma);
+ old_plane_state->ggtt_vma = NULL;
+}
+
+/*
+ * For Xe introduce dummy intel_dpt_create which just return NULL and
+ * intel_dpt_destroy which does nothing.
+ */
+struct i915_address_space *intel_dpt_create(struct intel_framebuffer *fb)
+{
+ return NULL;
+}
+
+void intel_dpt_destroy(struct i915_address_space *vm)
+{
+ return;
+} \ No newline at end of file
diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
new file mode 100644
index 000000000000..0453293af8ef
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2023, Intel Corporation.
+ */
+
+#include "i915_drv.h"
+#include "intel_hdcp_gsc.h"
+
+int intel_hdcp_gsc_init(struct drm_i915_private *i915)
+{
+ drm_info(&i915->drm, "HDCP support not yet implemented\n");
+ return -ENODEV;
+}
+
+void intel_hdcp_gsc_fini(struct drm_i915_private *i915)
+{
+}
+
+ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in,
+ size_t msg_in_len, u8 *msg_out,
+ size_t msg_out_len)
+{
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/xe/display/xe_plane_initial.c b/drivers/gpu/drm/xe/display/xe_plane_initial.c
new file mode 100644
index 000000000000..ccf83c12b545
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_plane_initial.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+/* for ioread64 */
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#include "xe_ggtt.h"
+
+#include "i915_drv.h"
+#include "intel_atomic_plane.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_plane_initial.h"
+
+static bool
+intel_reuse_initial_plane_obj(struct drm_i915_private *i915,
+ const struct intel_initial_plane_config *plane_config,
+ struct drm_framebuffer **fb)
+{
+ struct intel_crtc *crtc;
+
+ for_each_intel_crtc(&i915->drm, crtc) {
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+ struct intel_plane *plane =
+ to_intel_plane(crtc->base.primary);
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(plane->base.state);
+
+ if (!crtc_state->uapi.active)
+ continue;
+
+ if (!plane_state->ggtt_vma)
+ continue;
+
+ if (intel_plane_ggtt_offset(plane_state) == plane_config->base) {
+ *fb = plane_state->hw.fb;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static struct xe_bo *
+initial_plane_bo(struct xe_device *xe,
+ struct intel_initial_plane_config *plane_config)
+{
+ struct xe_tile *tile0 = xe_device_get_root_tile(xe);
+ struct xe_bo *bo;
+ resource_size_t phys_base;
+ u32 base, size, flags;
+ u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
+
+ if (plane_config->size == 0)
+ return NULL;
+
+ flags = XE_BO_CREATE_PINNED_BIT | XE_BO_SCANOUT_BIT | XE_BO_CREATE_GGTT_BIT;
+
+ base = round_down(plane_config->base, page_size);
+ if (IS_DGFX(xe)) {
+ u64 __iomem *gte = tile0->mem.ggtt->gsm;
+ u64 pte;
+
+ gte += base / XE_PAGE_SIZE;
+
+ pte = ioread64(gte);
+ if (!(pte & XE_GGTT_PTE_DM)) {
+ drm_err(&xe->drm,
+ "Initial plane programming missing DM bit\n");
+ return NULL;
+ }
+
+ phys_base = pte & ~(page_size - 1);
+ flags |= XE_BO_CREATE_VRAM0_BIT;
+
+ /*
+ * We don't currently expect this to ever be placed in the
+ * stolen portion.
+ */
+ if (phys_base >= tile0->mem.vram.usable_size) {
+ drm_err(&xe->drm,
+ "Initial plane programming using invalid range, phys_base=%pa\n",
+ &phys_base);
+ return NULL;
+ }
+
+ drm_dbg(&xe->drm,
+ "Using phys_base=%pa, based on initial plane programming\n",
+ &phys_base);
+ } else {
+ struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
+
+ if (!stolen)
+ return NULL;
+ phys_base = base;
+ flags |= XE_BO_CREATE_STOLEN_BIT;
+
+ /*
+ * If the FB is too big, just don't use it since fbdev is not very
+ * important and we should probably use that space with FBC or other
+ * features.
+ */
+ if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
+ plane_config->size * 2 >> PAGE_SHIFT >= stolen->size)
+ return NULL;
+ }
+
+ size = round_up(plane_config->base + plane_config->size,
+ page_size);
+ size -= base;
+
+ bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size, phys_base,
+ ttm_bo_type_kernel, flags);
+ if (IS_ERR(bo)) {
+ drm_dbg(&xe->drm,
+ "Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
+ &phys_base, size, flags, PTR_ERR(bo));
+ return NULL;
+ }
+
+ return bo;
+}
+
+static bool
+intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
+ struct intel_initial_plane_config *plane_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+ struct drm_framebuffer *fb = &plane_config->fb->base;
+ struct xe_bo *bo;
+
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case I915_FORMAT_MOD_X_TILED:
+ case I915_FORMAT_MOD_Y_TILED:
+ case I915_FORMAT_MOD_4_TILED:
+ break;
+ default:
+ drm_dbg(&dev_priv->drm,
+ "Unsupported modifier for initial FB: 0x%llx\n",
+ fb->modifier);
+ return false;
+ }
+
+ mode_cmd.pixel_format = fb->format->format;
+ mode_cmd.width = fb->width;
+ mode_cmd.height = fb->height;
+ mode_cmd.pitches[0] = fb->pitches[0];
+ mode_cmd.modifier[0] = fb->modifier;
+ mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
+
+ bo = initial_plane_bo(dev_priv, plane_config);
+ if (!bo)
+ return false;
+
+ if (intel_framebuffer_init(to_intel_framebuffer(fb),
+ bo, &mode_cmd)) {
+ drm_dbg_kms(&dev_priv->drm, "intel fb init failed\n");
+ goto err_bo;
+ }
+ /* Reference handed over to fb */
+ xe_bo_put(bo);
+
+ return true;
+
+err_bo:
+ xe_bo_unpin_map_no_vm(bo);
+ return false;
+}
+
+static void
+intel_find_initial_plane_obj(struct intel_crtc *crtc,
+ struct intel_initial_plane_config *plane_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_plane *plane =
+ to_intel_plane(crtc->base.primary);
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(plane->base.state);
+ struct intel_crtc_state *crtc_state =
+ to_intel_crtc_state(crtc->base.state);
+ struct drm_framebuffer *fb;
+ struct i915_vma *vma;
+
+ /*
+ * TODO:
+ * Disable planes if get_initial_plane_config() failed.
+ * Make sure things work if the surface base is not page aligned.
+ */
+ if (!plane_config->fb)
+ return;
+
+ if (intel_alloc_initial_plane_obj(crtc, plane_config))
+ fb = &plane_config->fb->base;
+ else if (!intel_reuse_initial_plane_obj(dev_priv, plane_config, &fb))
+ goto nofb;
+
+ plane_state->uapi.rotation = plane_config->rotation;
+ intel_fb_fill_view(to_intel_framebuffer(fb),
+ plane_state->uapi.rotation, &plane_state->view);
+
+ vma = intel_pin_and_fence_fb_obj(fb, false, &plane_state->view.gtt,
+ false, &plane_state->flags);
+ if (IS_ERR(vma))
+ goto nofb;
+
+ plane_state->ggtt_vma = vma;
+ plane_state->uapi.src_x = 0;
+ plane_state->uapi.src_y = 0;
+ plane_state->uapi.src_w = fb->width << 16;
+ plane_state->uapi.src_h = fb->height << 16;
+
+ plane_state->uapi.crtc_x = 0;
+ plane_state->uapi.crtc_y = 0;
+ plane_state->uapi.crtc_w = fb->width;
+ plane_state->uapi.crtc_h = fb->height;
+
+ plane_state->uapi.fb = fb;
+ drm_framebuffer_get(fb);
+
+ plane_state->uapi.crtc = &crtc->base;
+ intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
+
+ atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
+
+ plane_config->vma = vma;
+
+ /*
+ * Flip to the newly created mapping ASAP, so we can re-use the
+ * first part of GGTT for WOPCM, prevent flickering, and prevent
+ * the lookup of sysmem scratch pages.
+ */
+ plane->check_plane(crtc_state, plane_state);
+ plane->async_flip(plane, crtc_state, plane_state, true);
+ return;
+
+nofb:
+ /*
+ * We've failed to reconstruct the BIOS FB. Current display state
+ * indicates that the primary plane is visible, but has a NULL FB,
+ * which will lead to problems later if we don't fix it up. The
+ * simplest solution is to just disable the primary plane now and
+ * pretend the BIOS never had it enabled.
+ */
+ intel_plane_disable_noatomic(crtc, plane);
+}
+
+static void plane_config_fini(struct intel_initial_plane_config *plane_config)
+{
+ if (plane_config->fb) {
+ struct drm_framebuffer *fb = &plane_config->fb->base;
+
+ /* We may only have the stub and not a full framebuffer */
+ if (drm_framebuffer_read_refcount(fb))
+ drm_framebuffer_put(fb);
+ else
+ kfree(fb);
+ }
+}
+
+void intel_crtc_initial_plane_config(struct intel_crtc *crtc)
+{
+ struct xe_device *xe = to_xe_device(crtc->base.dev);
+ struct intel_initial_plane_config plane_config = {};
+
+ /*
+ * Note that reserving the BIOS fb up front prevents us
+ * from stuffing other stolen allocations like the ring
+ * on top. This prevents some ugliness at boot time, and
+ * can even allow for smooth boot transitions if the BIOS
+ * fb is large enough for the active pipe configuration.
+ */
+ xe->display.funcs.display->get_initial_plane_config(crtc, &plane_config);
+
+ /*
+ * If the fb is shared between multiple heads, we'll
+ * just get the first one.
+ */
+ intel_find_initial_plane_obj(crtc, &plane_config);
+
+ plane_config_fini(&plane_config);
+}