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