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