xref: /linux/drivers/gpu/drm/xe/display/xe_initial_plane.c (revision c3fb1fb9e65fa6a108b4d19c61bdcb47fd4fe180)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2021 Intel Corporation
4  */
5 
6 #include <drm/intel/display_parent_interface.h>
7 
8 #include "regs/xe_gtt_defs.h"
9 
10 #include "intel_display_types.h"
11 #include "intel_fb.h"
12 #include "intel_fb_pin.h"
13 #include "xe_bo.h"
14 #include "xe_display_bo.h"
15 #include "xe_display_vma.h"
16 #include "xe_ggtt.h"
17 #include "xe_mmio.h"
18 #include "xe_vram_types.h"
19 
20 static struct xe_bo *
21 initial_plane_bo(struct xe_device *xe,
22 		 struct intel_initial_plane_config *plane_config)
23 {
24 	struct xe_tile *tile0 = xe_device_get_root_tile(xe);
25 	struct xe_bo *bo;
26 	resource_size_t phys_base;
27 	u32 base, size, flags;
28 	u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
29 
30 	if (plane_config->size == 0)
31 		return NULL;
32 
33 	flags = XE_BO_FLAG_FORCE_WC | XE_BO_FLAG_GGTT;
34 
35 	base = round_down(plane_config->base, page_size);
36 	if (IS_DGFX(xe)) {
37 		u64 pte = xe_ggtt_read_pte(tile0->mem.ggtt, base);
38 
39 		if (!(pte & XE_GGTT_PTE_DM)) {
40 			drm_err(&xe->drm,
41 				"Initial plane programming missing DM bit\n");
42 			return NULL;
43 		}
44 
45 		phys_base = pte & ~(page_size - 1);
46 		flags |= XE_BO_FLAG_VRAM0;
47 
48 		/*
49 		 * We don't currently expect this to ever be placed in the
50 		 * stolen portion.
51 		 */
52 		if (phys_base >= xe_vram_region_usable_size(tile0->mem.vram)) {
53 			drm_err(&xe->drm,
54 				"Initial plane programming using invalid range, phys_base=%pa\n",
55 				&phys_base);
56 			return NULL;
57 		}
58 
59 		drm_dbg(&xe->drm,
60 			"Using phys_base=%pa, based on initial plane programming\n",
61 			&phys_base);
62 	} else {
63 		struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
64 
65 		if (!stolen)
66 			return NULL;
67 		phys_base = base;
68 		flags |= XE_BO_FLAG_STOLEN;
69 
70 		if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
71 		    IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) &&
72 		    !xe_display_bo_fbdev_prefer_stolen(xe, plane_config->size)) {
73 			drm_info(&xe->drm, "Initial FB size exceeds half of stolen, discarding\n");
74 			return NULL;
75 		}
76 	}
77 
78 	size = round_up(plane_config->base + plane_config->size,
79 			page_size);
80 	size -= base;
81 
82 	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base,
83 					  ttm_bo_type_kernel, flags, 0, false);
84 	if (IS_ERR(bo)) {
85 		drm_dbg(&xe->drm,
86 			"Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
87 			&phys_base, size, flags, PTR_ERR(bo));
88 		return NULL;
89 	}
90 
91 	return bo;
92 }
93 
94 static struct drm_gem_object *
95 xe_alloc_initial_plane_obj(struct drm_device *drm,
96 			   struct intel_initial_plane_config *plane_config)
97 {
98 	struct xe_device *xe = to_xe_device(drm);
99 	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
100 	struct drm_framebuffer *fb = plane_config->fb;
101 	struct xe_bo *bo;
102 
103 	mode_cmd.pixel_format = fb->format->format;
104 	mode_cmd.width = fb->width;
105 	mode_cmd.height = fb->height;
106 	mode_cmd.pitches[0] = fb->pitches[0];
107 	mode_cmd.modifier[0] = fb->modifier;
108 	mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
109 
110 	bo = initial_plane_bo(xe, plane_config);
111 	if (!bo)
112 		return NULL;
113 
114 	if (intel_framebuffer_init(to_intel_framebuffer(fb),
115 				   &bo->ttm.base, fb->format, &mode_cmd)) {
116 		drm_dbg_kms(&xe->drm, "intel fb init failed\n");
117 		goto err_bo;
118 	}
119 	/* Reference handed over to fb */
120 	xe_bo_put(bo);
121 
122 	return &bo->ttm.base;
123 
124 err_bo:
125 	xe_bo_unpin_map_no_vm(bo);
126 	return NULL;
127 }
128 
129 static int
130 xe_initial_plane_setup(struct drm_plane_state *_plane_state,
131 		       struct intel_initial_plane_config *plane_config,
132 		       struct drm_framebuffer *fb,
133 		       struct i915_vma *_unused)
134 {
135 	struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state);
136 	struct i915_vma *vma;
137 	struct intel_fb_pin_params pin_params = {
138 		.view = &plane_state->view.gtt,
139 	};
140 
141 	vma = intel_fb_pin_to_ggtt(intel_fb_bo(fb), &pin_params, NULL);
142 	if (IS_ERR(vma))
143 		return PTR_ERR(vma);
144 
145 	plane_state->ggtt_vma = vma;
146 
147 	plane_state->surf = xe_ggtt_node_addr(plane_state->ggtt_vma->node);
148 
149 	plane_config->vma = vma;
150 
151 	return 0;
152 }
153 
154 static void xe_plane_config_fini(struct intel_initial_plane_config *plane_config)
155 {
156 }
157 
158 const struct intel_display_initial_plane_interface xe_display_initial_plane_interface = {
159 	.alloc_obj = xe_alloc_initial_plane_obj,
160 	.setup = xe_initial_plane_setup,
161 	.config_fini = xe_plane_config_fini,
162 };
163