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(&crtc->base, 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