1 // SPDX-License-Identifier: MIT 2 /* Copyright © 2025 Intel Corporation */ 3 4 #include <linux/iopoll.h> 5 6 #include <drm/drm_blend.h> 7 #include <drm/drm_print.h> 8 #include <drm/intel/display_parent_interface.h> 9 10 #include "intel_crtc.h" 11 #include "intel_de.h" 12 #include "intel_display_core.h" 13 #include "intel_display_regs.h" 14 #include "intel_display_types.h" 15 #include "intel_fb.h" 16 #include "intel_frontbuffer.h" 17 #include "intel_initial_plane.h" 18 #include "intel_parent.h" 19 #include "intel_plane.h" 20 21 struct intel_initial_plane_configs { 22 struct intel_initial_plane_config config[I915_MAX_PIPES]; 23 }; 24 25 void intel_initial_plane_vblank_wait(struct intel_crtc *crtc) 26 { 27 struct intel_display *display = to_intel_display(crtc); 28 u32 start_ts, end_ts; 29 int ret; 30 31 /* xe doesn't have interrupts enabled this early */ 32 if (intel_parent_irq_enabled(display)) { 33 intel_crtc_wait_for_next_vblank(crtc); 34 return; 35 } 36 37 start_ts = intel_de_read(display, PIPE_FRMTMSTMP(crtc->pipe)); 38 39 ret = poll_timeout_us(end_ts = intel_de_read(display, PIPE_FRMTMSTMP(crtc->pipe)), 40 end_ts != start_ts, 1000, 1000 * 1000, false); 41 if (ret) 42 drm_warn(display->drm, "[CRTC:%d:%s] early vblank wait timed out\n", 43 crtc->base.base.id, crtc->base.name); 44 } 45 46 static const struct intel_plane_state * 47 intel_reuse_initial_plane_obj(struct intel_crtc *this, 48 const struct intel_initial_plane_configs *all_plane_configs) 49 { 50 struct intel_display *display = to_intel_display(this); 51 struct intel_crtc *crtc; 52 53 for_each_intel_crtc(display, crtc) { 54 struct intel_plane *plane = 55 to_intel_plane(crtc->base.primary); 56 const struct intel_plane_state *plane_state = 57 to_intel_plane_state(plane->base.state); 58 const struct intel_crtc_state *crtc_state = 59 to_intel_crtc_state(crtc->base.state); 60 61 if (!crtc_state->hw.active) 62 continue; 63 64 if (!plane_state->ggtt_vma) 65 continue; 66 67 if (all_plane_configs->config[this->pipe].base == 68 all_plane_configs->config[crtc->pipe].base) 69 return plane_state; 70 } 71 72 return NULL; 73 } 74 75 static struct drm_gem_object * 76 intel_alloc_initial_plane_obj(struct intel_display *display, 77 struct intel_initial_plane_config *plane_config) 78 { 79 struct drm_framebuffer *fb = plane_config->fb; 80 81 switch (fb->modifier) { 82 case DRM_FORMAT_MOD_LINEAR: 83 break; 84 case I915_FORMAT_MOD_X_TILED: 85 case I915_FORMAT_MOD_Y_TILED: 86 /* fenced region needed for linear CPU access to tiled FB */ 87 if (intel_parent_has_fenced_regions(display)) 88 break; 89 fallthrough; 90 default: 91 drm_dbg_kms(display->drm, "Unsupported modifier for initial FB: 0x%llx\n", 92 fb->modifier); 93 return NULL; 94 } 95 96 /* 97 * Would need to preserve the DPT, its GGTT 98 * mapping, and the actual FB memory. 99 */ 100 if (intel_fb_modifier_uses_dpt(display, fb->modifier)) { 101 drm_dbg_kms(display->drm, "DPT not supported for initial FB\n"); 102 return NULL; 103 } 104 105 /* 106 * Would need to preserve the 270 degree rotated 107 * GGTT mapping used by the display hardware. 108 */ 109 if (drm_rotation_90_or_270(plane_config->rotation)) { 110 drm_dbg_kms(display->drm, "90/270 degree rotation not supported for initial FB\n"); 111 return NULL; 112 } 113 114 return display->parent->initial_plane->alloc_obj(display->drm, plane_config); 115 } 116 117 static void 118 intel_find_initial_plane_obj(struct intel_crtc *crtc, 119 struct intel_initial_plane_configs *all_plane_configs) 120 { 121 struct intel_display *display = to_intel_display(crtc); 122 struct intel_initial_plane_config *plane_config = &all_plane_configs->config[crtc->pipe]; 123 struct intel_plane *plane = to_intel_plane(crtc->base.primary); 124 struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); 125 struct drm_framebuffer *fb; 126 struct i915_vma *vma; 127 int ret; 128 129 /* 130 * TODO: 131 * Disable planes if get_initial_plane_config() failed. 132 * Make sure things work if the surface base is not page aligned. 133 */ 134 if (!plane_config->fb) 135 return; 136 137 if (intel_alloc_initial_plane_obj(display, plane_config)) { 138 fb = plane_config->fb; 139 vma = plane_config->vma; 140 } else { 141 const struct intel_plane_state *other_plane_state; 142 143 other_plane_state = intel_reuse_initial_plane_obj(crtc, all_plane_configs); 144 if (!other_plane_state) 145 goto nofb; 146 147 fb = other_plane_state->hw.fb; 148 vma = other_plane_state->ggtt_vma; 149 } 150 151 plane_state->uapi.rotation = plane_config->rotation; 152 intel_fb_fill_view(to_intel_framebuffer(fb), 153 plane_state->uapi.rotation, &plane_state->view); 154 155 ret = display->parent->initial_plane->setup(plane->base.state, plane_config, fb, vma); 156 if (ret) 157 goto nofb; 158 159 plane_state->uapi.src_x = 0; 160 plane_state->uapi.src_y = 0; 161 plane_state->uapi.src_w = fb->width << 16; 162 plane_state->uapi.src_h = fb->height << 16; 163 164 plane_state->uapi.crtc_x = 0; 165 plane_state->uapi.crtc_y = 0; 166 plane_state->uapi.crtc_w = fb->width; 167 plane_state->uapi.crtc_h = fb->height; 168 169 plane_state->uapi.fb = fb; 170 drm_framebuffer_get(fb); 171 172 plane_state->uapi.crtc = &crtc->base; 173 intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc); 174 175 atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits); 176 177 return; 178 179 nofb: 180 /* 181 * We've failed to reconstruct the BIOS FB. Current display state 182 * indicates that the primary plane is visible, but has a NULL FB, 183 * which will lead to problems later if we don't fix it up. The 184 * simplest solution is to just disable the primary plane now and 185 * pretend the BIOS never had it enabled. 186 */ 187 intel_plane_disable_noatomic(crtc, plane); 188 } 189 190 static void plane_config_fini(struct intel_display *display, 191 struct intel_initial_plane_config *plane_config) 192 { 193 if (plane_config->fb) { 194 struct drm_framebuffer *fb = plane_config->fb; 195 196 /* We may only have the stub and not a full framebuffer */ 197 if (drm_framebuffer_read_refcount(fb)) 198 drm_framebuffer_put(fb); 199 else 200 kfree(fb); 201 } 202 203 display->parent->initial_plane->config_fini(plane_config); 204 } 205 206 void intel_initial_plane_config(struct intel_display *display) 207 { 208 struct intel_initial_plane_configs all_plane_configs = {}; 209 struct intel_crtc *crtc; 210 211 for_each_intel_crtc(display, crtc) { 212 const struct intel_crtc_state *crtc_state = 213 to_intel_crtc_state(crtc->base.state); 214 struct intel_initial_plane_config *plane_config = 215 &all_plane_configs.config[crtc->pipe]; 216 217 if (!crtc_state->hw.active) 218 continue; 219 220 /* 221 * Note that reserving the BIOS fb up front prevents us 222 * from stuffing other stolen allocations like the ring 223 * on top. This prevents some ugliness at boot time, and 224 * can even allow for smooth boot transitions if the BIOS 225 * fb is large enough for the active pipe configuration. 226 */ 227 display->modeset.funcs->get_initial_plane_config(crtc, plane_config); 228 229 /* 230 * If the fb is shared between multiple heads, we'll 231 * just get the first one. 232 */ 233 intel_find_initial_plane_obj(crtc, &all_plane_configs); 234 235 if (display->modeset.funcs->fixup_initial_plane_config(crtc, plane_config)) 236 intel_initial_plane_vblank_wait(crtc); 237 238 plane_config_fini(display, plane_config); 239 } 240 } 241