xref: /linux/drivers/gpu/drm/i915/display/intel_initial_plane.c (revision 5bad00377ec844d93947fd4c081abd2000a63dfc)
1 // SPDX-License-Identifier: MIT
2 /* Copyright © 2025 Intel Corporation */
3 
4 #include <drm/drm_print.h>
5 #include <drm/intel/display_parent_interface.h>
6 
7 #include "intel_display_core.h"
8 #include "intel_display_types.h"
9 #include "intel_fb.h"
10 #include "intel_frontbuffer.h"
11 #include "intel_initial_plane.h"
12 #include "intel_plane.h"
13 
14 void intel_initial_plane_vblank_wait(struct intel_crtc *crtc)
15 {
16 	struct intel_display *display = to_intel_display(crtc);
17 
18 	display->parent->initial_plane->vblank_wait(&crtc->base);
19 }
20 
21 static const struct intel_plane_state *
22 intel_reuse_initial_plane_obj(struct intel_crtc *this,
23 			      const struct intel_initial_plane_config plane_configs[])
24 {
25 	struct intel_display *display = to_intel_display(this);
26 	struct intel_crtc *crtc;
27 
28 	for_each_intel_crtc(display->drm, crtc) {
29 		struct intel_plane *plane =
30 			to_intel_plane(crtc->base.primary);
31 		const struct intel_plane_state *plane_state =
32 			to_intel_plane_state(plane->base.state);
33 		const struct intel_crtc_state *crtc_state =
34 			to_intel_crtc_state(crtc->base.state);
35 
36 		if (!crtc_state->hw.active)
37 			continue;
38 
39 		if (!plane_state->ggtt_vma)
40 			continue;
41 
42 		if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base)
43 			return plane_state;
44 	}
45 
46 	return NULL;
47 }
48 
49 static struct drm_gem_object *
50 intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
51 			      struct intel_initial_plane_config *plane_config)
52 {
53 	struct intel_display *display = to_intel_display(crtc);
54 	struct intel_framebuffer *fb = plane_config->fb;
55 
56 	switch (fb->base.modifier) {
57 	case DRM_FORMAT_MOD_LINEAR:
58 	case I915_FORMAT_MOD_X_TILED:
59 	case I915_FORMAT_MOD_Y_TILED:
60 	case I915_FORMAT_MOD_4_TILED:
61 		break;
62 	default:
63 		drm_dbg_kms(display->drm, "Unsupported modifier for initial FB: 0x%llx\n",
64 			    fb->base.modifier);
65 		return NULL;
66 	}
67 
68 	return display->parent->initial_plane->alloc_obj(&crtc->base, plane_config);
69 }
70 
71 static void
72 intel_find_initial_plane_obj(struct intel_crtc *crtc,
73 			     struct intel_initial_plane_config plane_configs[])
74 {
75 	struct intel_display *display = to_intel_display(crtc);
76 	struct intel_initial_plane_config *plane_config = &plane_configs[crtc->pipe];
77 	struct intel_plane *plane = to_intel_plane(crtc->base.primary);
78 	struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state);
79 	struct drm_framebuffer *fb;
80 	struct i915_vma *vma;
81 	int ret;
82 
83 	/*
84 	 * TODO:
85 	 *   Disable planes if get_initial_plane_config() failed.
86 	 *   Make sure things work if the surface base is not page aligned.
87 	 */
88 	if (!plane_config->fb)
89 		return;
90 
91 	if (intel_alloc_initial_plane_obj(crtc, plane_config)) {
92 		fb = &plane_config->fb->base;
93 		vma = plane_config->vma;
94 	} else {
95 		const struct intel_plane_state *other_plane_state;
96 
97 		other_plane_state = intel_reuse_initial_plane_obj(crtc, plane_configs);
98 		if (!other_plane_state)
99 			goto nofb;
100 
101 		fb = other_plane_state->hw.fb;
102 		vma = other_plane_state->ggtt_vma;
103 	}
104 
105 	plane_state->uapi.rotation = plane_config->rotation;
106 	intel_fb_fill_view(to_intel_framebuffer(fb),
107 			   plane_state->uapi.rotation, &plane_state->view);
108 
109 	ret = display->parent->initial_plane->setup(plane->base.state, plane_config, fb, vma);
110 	if (ret)
111 		goto nofb;
112 
113 	plane_state->uapi.src_x = 0;
114 	plane_state->uapi.src_y = 0;
115 	plane_state->uapi.src_w = fb->width << 16;
116 	plane_state->uapi.src_h = fb->height << 16;
117 
118 	plane_state->uapi.crtc_x = 0;
119 	plane_state->uapi.crtc_y = 0;
120 	plane_state->uapi.crtc_w = fb->width;
121 	plane_state->uapi.crtc_h = fb->height;
122 
123 	plane_state->uapi.fb = fb;
124 	drm_framebuffer_get(fb);
125 
126 	plane_state->uapi.crtc = &crtc->base;
127 	intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
128 
129 	atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
130 
131 	return;
132 
133 nofb:
134 	/*
135 	 * We've failed to reconstruct the BIOS FB.  Current display state
136 	 * indicates that the primary plane is visible, but has a NULL FB,
137 	 * which will lead to problems later if we don't fix it up.  The
138 	 * simplest solution is to just disable the primary plane now and
139 	 * pretend the BIOS never had it enabled.
140 	 */
141 	intel_plane_disable_noatomic(crtc, plane);
142 }
143 
144 static void plane_config_fini(struct intel_display *display,
145 			      struct intel_initial_plane_config *plane_config)
146 {
147 	if (plane_config->fb) {
148 		struct drm_framebuffer *fb = &plane_config->fb->base;
149 
150 		/* We may only have the stub and not a full framebuffer */
151 		if (drm_framebuffer_read_refcount(fb))
152 			drm_framebuffer_put(fb);
153 		else
154 			kfree(fb);
155 	}
156 
157 	display->parent->initial_plane->config_fini(plane_config);
158 }
159 
160 void intel_initial_plane_config(struct intel_display *display)
161 {
162 	struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {};
163 	struct intel_crtc *crtc;
164 
165 	for_each_intel_crtc(display->drm, crtc) {
166 		const struct intel_crtc_state *crtc_state =
167 			to_intel_crtc_state(crtc->base.state);
168 		struct intel_initial_plane_config *plane_config =
169 			&plane_configs[crtc->pipe];
170 
171 		if (!crtc_state->hw.active)
172 			continue;
173 
174 		/*
175 		 * Note that reserving the BIOS fb up front prevents us
176 		 * from stuffing other stolen allocations like the ring
177 		 * on top.  This prevents some ugliness at boot time, and
178 		 * can even allow for smooth boot transitions if the BIOS
179 		 * fb is large enough for the active pipe configuration.
180 		 */
181 		display->funcs.display->get_initial_plane_config(crtc, plane_config);
182 
183 		/*
184 		 * If the fb is shared between multiple heads, we'll
185 		 * just get the first one.
186 		 */
187 		intel_find_initial_plane_obj(crtc, plane_configs);
188 
189 		if (display->funcs.display->fixup_initial_plane_config(crtc, plane_config))
190 			intel_initial_plane_vblank_wait(crtc);
191 
192 		plane_config_fini(display, plane_config);
193 	}
194 }
195