xref: /linux/drivers/gpu/drm/i915/display/intel_initial_plane.c (revision d639d9fa162aadec1ae9980c4dcf6e50bd2f8290)
1 // SPDX-License-Identifier: MIT
2 /* Copyright © 2025 Intel Corporation */
3 
4 #include <linux/iopoll.h>
5 
6 #include <drm/drm_blend.h>
7 #include <drm/drm_print.h>
8 #include <drm/intel/display_parent_interface.h>
9 
10 #include "intel_crtc.h"
11 #include "intel_de.h"
12 #include "intel_display_core.h"
13 #include "intel_display_regs.h"
14 #include "intel_display_types.h"
15 #include "intel_fb.h"
16 #include "intel_frontbuffer.h"
17 #include "intel_initial_plane.h"
18 #include "intel_parent.h"
19 #include "intel_plane.h"
20 
21 struct intel_initial_plane_configs {
22 	struct intel_initial_plane_config config[I915_MAX_PIPES];
23 };
24 
25 void intel_initial_plane_vblank_wait(struct intel_crtc *crtc)
26 {
27 	struct intel_display *display = to_intel_display(crtc);
28 	u32 start_ts, end_ts;
29 	int ret;
30 
31 	/* xe doesn't have interrupts enabled this early */
32 	if (intel_parent_irq_enabled(display)) {
33 		intel_crtc_wait_for_next_vblank(crtc);
34 		return;
35 	}
36 
37 	start_ts = intel_de_read(display, PIPE_FRMTMSTMP(crtc->pipe));
38 
39 	ret = poll_timeout_us(end_ts = intel_de_read(display, PIPE_FRMTMSTMP(crtc->pipe)),
40 			      end_ts != start_ts, 1000, 1000 * 1000, false);
41 	if (ret)
42 		drm_warn(display->drm, "[CRTC:%d:%s] early vblank wait timed out\n",
43 			 crtc->base.base.id, crtc->base.name);
44 }
45 
46 static const struct intel_plane_state *
47 intel_reuse_initial_plane_obj(struct intel_crtc *this,
48 			      const struct intel_initial_plane_configs *all_plane_configs)
49 {
50 	struct intel_display *display = to_intel_display(this);
51 	struct intel_crtc *crtc;
52 
53 	for_each_intel_crtc(display, crtc) {
54 		struct intel_plane *plane =
55 			to_intel_plane(crtc->base.primary);
56 		const struct intel_plane_state *plane_state =
57 			to_intel_plane_state(plane->base.state);
58 		const struct intel_crtc_state *crtc_state =
59 			to_intel_crtc_state(crtc->base.state);
60 
61 		if (!crtc_state->hw.active)
62 			continue;
63 
64 		if (!plane_state->ggtt_vma)
65 			continue;
66 
67 		if (all_plane_configs->config[this->pipe].base ==
68 		    all_plane_configs->config[crtc->pipe].base)
69 			return plane_state;
70 	}
71 
72 	return NULL;
73 }
74 
75 static struct drm_gem_object *
76 intel_alloc_initial_plane_obj(struct intel_display *display,
77 			      struct intel_initial_plane_config *plane_config)
78 {
79 	struct drm_framebuffer *fb = plane_config->fb;
80 
81 	switch (fb->modifier) {
82 	case DRM_FORMAT_MOD_LINEAR:
83 		break;
84 	case I915_FORMAT_MOD_X_TILED:
85 	case I915_FORMAT_MOD_Y_TILED:
86 		/* fenced region needed for linear CPU access to tiled FB */
87 		if (intel_parent_has_fenced_regions(display))
88 			break;
89 		fallthrough;
90 	default:
91 		drm_dbg_kms(display->drm, "Unsupported modifier for initial FB: 0x%llx\n",
92 			    fb->modifier);
93 		return NULL;
94 	}
95 
96 	/*
97 	 * Would need to preserve the DPT, its GGTT
98 	 * mapping, and the actual FB memory.
99 	 */
100 	if (intel_fb_modifier_uses_dpt(display, fb->modifier)) {
101 		drm_dbg_kms(display->drm, "DPT not supported for initial FB\n");
102 		return NULL;
103 	}
104 
105 	/*
106 	 * Would need to preserve the 270 degree rotated
107 	 * GGTT mapping used by the display hardware.
108 	 */
109 	if (drm_rotation_90_or_270(plane_config->rotation)) {
110 		drm_dbg_kms(display->drm, "90/270 degree rotation not supported for initial FB\n");
111 		return NULL;
112 	}
113 
114 	return display->parent->initial_plane->alloc_obj(display->drm, plane_config);
115 }
116 
117 static void
118 intel_find_initial_plane_obj(struct intel_crtc *crtc,
119 			     struct intel_initial_plane_configs *all_plane_configs)
120 {
121 	struct intel_display *display = to_intel_display(crtc);
122 	struct intel_initial_plane_config *plane_config = &all_plane_configs->config[crtc->pipe];
123 	struct intel_plane *plane = to_intel_plane(crtc->base.primary);
124 	struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state);
125 	struct drm_framebuffer *fb;
126 	struct i915_vma *vma;
127 	int ret;
128 
129 	/*
130 	 * TODO:
131 	 *   Disable planes if get_initial_plane_config() failed.
132 	 *   Make sure things work if the surface base is not page aligned.
133 	 */
134 	if (!plane_config->fb)
135 		return;
136 
137 	if (intel_alloc_initial_plane_obj(display, plane_config)) {
138 		fb = plane_config->fb;
139 		vma = plane_config->vma;
140 	} else {
141 		const struct intel_plane_state *other_plane_state;
142 
143 		other_plane_state = intel_reuse_initial_plane_obj(crtc, all_plane_configs);
144 		if (!other_plane_state)
145 			goto nofb;
146 
147 		fb = other_plane_state->hw.fb;
148 		vma = other_plane_state->ggtt_vma;
149 	}
150 
151 	plane_state->uapi.rotation = plane_config->rotation;
152 	intel_fb_fill_view(to_intel_framebuffer(fb),
153 			   plane_state->uapi.rotation, &plane_state->view);
154 
155 	ret = display->parent->initial_plane->setup(plane->base.state, plane_config, fb, vma);
156 	if (ret)
157 		goto nofb;
158 
159 	plane_state->uapi.src_x = 0;
160 	plane_state->uapi.src_y = 0;
161 	plane_state->uapi.src_w = fb->width << 16;
162 	plane_state->uapi.src_h = fb->height << 16;
163 
164 	plane_state->uapi.crtc_x = 0;
165 	plane_state->uapi.crtc_y = 0;
166 	plane_state->uapi.crtc_w = fb->width;
167 	plane_state->uapi.crtc_h = fb->height;
168 
169 	plane_state->uapi.fb = fb;
170 	drm_framebuffer_get(fb);
171 
172 	plane_state->uapi.crtc = &crtc->base;
173 	intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
174 
175 	atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
176 
177 	return;
178 
179 nofb:
180 	/*
181 	 * We've failed to reconstruct the BIOS FB.  Current display state
182 	 * indicates that the primary plane is visible, but has a NULL FB,
183 	 * which will lead to problems later if we don't fix it up.  The
184 	 * simplest solution is to just disable the primary plane now and
185 	 * pretend the BIOS never had it enabled.
186 	 */
187 	intel_plane_disable_noatomic(crtc, plane);
188 }
189 
190 static void plane_config_fini(struct intel_display *display,
191 			      struct intel_initial_plane_config *plane_config)
192 {
193 	if (plane_config->fb) {
194 		struct drm_framebuffer *fb = plane_config->fb;
195 
196 		/* We may only have the stub and not a full framebuffer */
197 		if (drm_framebuffer_read_refcount(fb))
198 			drm_framebuffer_put(fb);
199 		else
200 			kfree(fb);
201 	}
202 
203 	display->parent->initial_plane->config_fini(plane_config);
204 }
205 
206 void intel_initial_plane_config(struct intel_display *display)
207 {
208 	struct intel_initial_plane_configs all_plane_configs = {};
209 	struct intel_crtc *crtc;
210 
211 	for_each_intel_crtc(display, crtc) {
212 		const struct intel_crtc_state *crtc_state =
213 			to_intel_crtc_state(crtc->base.state);
214 		struct intel_initial_plane_config *plane_config =
215 			&all_plane_configs.config[crtc->pipe];
216 
217 		if (!crtc_state->hw.active)
218 			continue;
219 
220 		/*
221 		 * Note that reserving the BIOS fb up front prevents us
222 		 * from stuffing other stolen allocations like the ring
223 		 * on top.  This prevents some ugliness at boot time, and
224 		 * can even allow for smooth boot transitions if the BIOS
225 		 * fb is large enough for the active pipe configuration.
226 		 */
227 		display->modeset.funcs->get_initial_plane_config(crtc, plane_config);
228 
229 		/*
230 		 * If the fb is shared between multiple heads, we'll
231 		 * just get the first one.
232 		 */
233 		intel_find_initial_plane_obj(crtc, &all_plane_configs);
234 
235 		if (display->modeset.funcs->fixup_initial_plane_config(crtc, plane_config))
236 			intel_initial_plane_vblank_wait(crtc);
237 
238 		plane_config_fini(display, plane_config);
239 	}
240 }
241