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