1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include "gem/i915_gem_lmem.h" 7 #include "gem/i915_gem_region.h" 8 #include "i915_drv.h" 9 #include "intel_atomic_plane.h" 10 #include "intel_crtc.h" 11 #include "intel_display.h" 12 #include "intel_display_types.h" 13 #include "intel_fb.h" 14 #include "intel_frontbuffer.h" 15 #include "intel_plane_initial.h" 16 17 static bool 18 intel_reuse_initial_plane_obj(struct intel_crtc *this, 19 const struct intel_initial_plane_config plane_configs[], 20 struct drm_framebuffer **fb, 21 struct i915_vma **vma) 22 { 23 struct drm_i915_private *i915 = to_i915(this->base.dev); 24 struct intel_crtc *crtc; 25 26 for_each_intel_crtc(&i915->drm, crtc) { 27 struct intel_plane *plane = 28 to_intel_plane(crtc->base.primary); 29 const struct intel_plane_state *plane_state = 30 to_intel_plane_state(plane->base.state); 31 const struct intel_crtc_state *crtc_state = 32 to_intel_crtc_state(crtc->base.state); 33 34 if (!crtc_state->uapi.active) 35 continue; 36 37 if (!plane_state->ggtt_vma) 38 continue; 39 40 if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base) { 41 *fb = plane_state->hw.fb; 42 *vma = plane_state->ggtt_vma; 43 return true; 44 } 45 } 46 47 return false; 48 } 49 50 static bool 51 initial_plane_phys_lmem(struct drm_i915_private *i915, 52 struct intel_initial_plane_config *plane_config) 53 { 54 gen8_pte_t __iomem *gte = to_gt(i915)->ggtt->gsm; 55 struct intel_memory_region *mem; 56 dma_addr_t dma_addr; 57 gen8_pte_t pte; 58 u32 base; 59 60 base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); 61 62 gte += base / I915_GTT_PAGE_SIZE; 63 64 pte = ioread64(gte); 65 if (!(pte & GEN12_GGTT_PTE_LM)) { 66 drm_err(&i915->drm, 67 "Initial plane programming missing PTE_LM bit\n"); 68 return false; 69 } 70 71 dma_addr = pte & GEN12_GGTT_PTE_ADDR_MASK; 72 73 if (IS_DGFX(i915)) 74 mem = i915->mm.regions[INTEL_REGION_LMEM_0]; 75 else 76 mem = i915->mm.stolen_region; 77 if (!mem) { 78 drm_dbg_kms(&i915->drm, 79 "Initial plane memory region not initialized\n"); 80 return false; 81 } 82 83 /* 84 * On lmem we don't currently expect this to 85 * ever be placed in the stolen portion. 86 */ 87 if (dma_addr < mem->region.start || dma_addr > mem->region.end) { 88 drm_err(&i915->drm, 89 "Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n", 90 &dma_addr, mem->region.name, &mem->region.start, &mem->region.end); 91 return false; 92 } 93 94 drm_dbg(&i915->drm, 95 "Using dma_addr=%pa, based on initial plane programming\n", 96 &dma_addr); 97 98 plane_config->phys_base = dma_addr - mem->region.start; 99 plane_config->mem = mem; 100 101 return true; 102 } 103 104 static bool 105 initial_plane_phys_smem(struct drm_i915_private *i915, 106 struct intel_initial_plane_config *plane_config) 107 { 108 struct intel_memory_region *mem; 109 u32 base; 110 111 base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); 112 113 mem = i915->mm.stolen_region; 114 if (!mem) { 115 drm_dbg_kms(&i915->drm, 116 "Initial plane memory region not initialized\n"); 117 return false; 118 } 119 120 /* FIXME get and validate the dma_addr from the PTE */ 121 plane_config->phys_base = base; 122 plane_config->mem = mem; 123 124 return true; 125 } 126 127 static bool 128 initial_plane_phys(struct drm_i915_private *i915, 129 struct intel_initial_plane_config *plane_config) 130 { 131 if (IS_DGFX(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915)) 132 return initial_plane_phys_lmem(i915, plane_config); 133 else 134 return initial_plane_phys_smem(i915, plane_config); 135 } 136 137 static struct i915_vma * 138 initial_plane_vma(struct drm_i915_private *i915, 139 struct intel_initial_plane_config *plane_config) 140 { 141 struct intel_memory_region *mem; 142 struct drm_i915_gem_object *obj; 143 struct drm_mm_node orig_mm = {}; 144 struct i915_vma *vma; 145 resource_size_t phys_base; 146 u32 base, size; 147 u64 pinctl; 148 149 if (plane_config->size == 0) 150 return NULL; 151 152 if (!initial_plane_phys(i915, plane_config)) 153 return NULL; 154 155 phys_base = plane_config->phys_base; 156 mem = plane_config->mem; 157 158 base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); 159 size = round_up(plane_config->base + plane_config->size, 160 mem->min_page_size); 161 size -= base; 162 163 /* 164 * If the FB is too big, just don't use it since fbdev is not very 165 * important and we should probably use that space with FBC or other 166 * features. 167 */ 168 if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && 169 mem == i915->mm.stolen_region && 170 size * 2 > i915->dsm.usable_size) { 171 drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); 172 return NULL; 173 } 174 175 obj = i915_gem_object_create_region_at(mem, phys_base, size, 176 I915_BO_ALLOC_USER | 177 I915_BO_PREALLOC); 178 if (IS_ERR(obj)) { 179 drm_dbg_kms(&i915->drm, "Failed to preallocate initial FB in %s\n", 180 mem->region.name); 181 return NULL; 182 } 183 184 /* 185 * Mark it WT ahead of time to avoid changing the 186 * cache_level during fbdev initialization. The 187 * unbind there would get stuck waiting for rcu. 188 */ 189 i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ? 190 I915_CACHE_WT : I915_CACHE_NONE); 191 192 switch (plane_config->tiling) { 193 case I915_TILING_NONE: 194 break; 195 case I915_TILING_X: 196 case I915_TILING_Y: 197 obj->tiling_and_stride = 198 plane_config->fb->base.pitches[0] | 199 plane_config->tiling; 200 break; 201 default: 202 MISSING_CASE(plane_config->tiling); 203 goto err_obj; 204 } 205 206 /* 207 * MTL GOP likes to place the framebuffer high up in ggtt, 208 * which can cause problems for ggtt_reserve_guc_top(). 209 * Try to pin it to a low ggtt address instead to avoid that. 210 */ 211 base = 0; 212 213 if (base != plane_config->base) { 214 struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 215 int ret; 216 217 /* 218 * Make sure the original and new locations 219 * can't overlap. That would corrupt the original 220 * PTEs which are still being used for scanout. 221 */ 222 ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm, 223 size, plane_config->base, 224 I915_COLOR_UNEVICTABLE, PIN_NOEVICT); 225 if (ret) 226 goto err_obj; 227 } 228 229 vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL); 230 if (IS_ERR(vma)) 231 goto err_obj; 232 233 retry: 234 pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base; 235 if (!i915_gem_object_is_lmem(obj)) 236 pinctl |= PIN_MAPPABLE; 237 if (i915_vma_pin(vma, 0, 0, pinctl)) { 238 if (drm_mm_node_allocated(&orig_mm)) { 239 drm_mm_remove_node(&orig_mm); 240 /* 241 * Try again, but this time pin 242 * it to its original location. 243 */ 244 base = plane_config->base; 245 goto retry; 246 } 247 goto err_obj; 248 } 249 250 if (i915_gem_object_is_tiled(obj) && 251 !i915_vma_is_map_and_fenceable(vma)) 252 goto err_obj; 253 254 if (drm_mm_node_allocated(&orig_mm)) 255 drm_mm_remove_node(&orig_mm); 256 257 drm_dbg_kms(&i915->drm, 258 "Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n", 259 i915_ggtt_offset(vma), plane_config->base); 260 261 return vma; 262 263 err_obj: 264 if (drm_mm_node_allocated(&orig_mm)) 265 drm_mm_remove_node(&orig_mm); 266 i915_gem_object_put(obj); 267 return NULL; 268 } 269 270 static bool 271 intel_alloc_initial_plane_obj(struct intel_crtc *crtc, 272 struct intel_initial_plane_config *plane_config) 273 { 274 struct drm_device *dev = crtc->base.dev; 275 struct drm_i915_private *dev_priv = to_i915(dev); 276 struct drm_mode_fb_cmd2 mode_cmd = {}; 277 struct drm_framebuffer *fb = &plane_config->fb->base; 278 struct i915_vma *vma; 279 280 switch (fb->modifier) { 281 case DRM_FORMAT_MOD_LINEAR: 282 case I915_FORMAT_MOD_X_TILED: 283 case I915_FORMAT_MOD_Y_TILED: 284 case I915_FORMAT_MOD_4_TILED: 285 break; 286 default: 287 drm_dbg(&dev_priv->drm, 288 "Unsupported modifier for initial FB: 0x%llx\n", 289 fb->modifier); 290 return false; 291 } 292 293 vma = initial_plane_vma(dev_priv, plane_config); 294 if (!vma) 295 return false; 296 297 mode_cmd.pixel_format = fb->format->format; 298 mode_cmd.width = fb->width; 299 mode_cmd.height = fb->height; 300 mode_cmd.pitches[0] = fb->pitches[0]; 301 mode_cmd.modifier[0] = fb->modifier; 302 mode_cmd.flags = DRM_MODE_FB_MODIFIERS; 303 304 if (intel_framebuffer_init(to_intel_framebuffer(fb), 305 vma->obj, &mode_cmd)) { 306 drm_dbg_kms(&dev_priv->drm, "intel fb init failed\n"); 307 goto err_vma; 308 } 309 310 plane_config->vma = vma; 311 return true; 312 313 err_vma: 314 i915_vma_put(vma); 315 return false; 316 } 317 318 static void 319 intel_find_initial_plane_obj(struct intel_crtc *crtc, 320 struct intel_initial_plane_config plane_configs[]) 321 { 322 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 323 struct intel_initial_plane_config *plane_config = 324 &plane_configs[crtc->pipe]; 325 struct intel_plane *plane = 326 to_intel_plane(crtc->base.primary); 327 struct intel_plane_state *plane_state = 328 to_intel_plane_state(plane->base.state); 329 struct drm_framebuffer *fb; 330 struct i915_vma *vma; 331 332 /* 333 * TODO: 334 * Disable planes if get_initial_plane_config() failed. 335 * Make sure things work if the surface base is not page aligned. 336 */ 337 if (!plane_config->fb) 338 return; 339 340 if (intel_alloc_initial_plane_obj(crtc, plane_config)) { 341 fb = &plane_config->fb->base; 342 vma = plane_config->vma; 343 goto valid_fb; 344 } 345 346 /* 347 * Failed to alloc the obj, check to see if we should share 348 * an fb with another CRTC instead 349 */ 350 if (intel_reuse_initial_plane_obj(crtc, plane_configs, &fb, &vma)) 351 goto valid_fb; 352 353 /* 354 * We've failed to reconstruct the BIOS FB. Current display state 355 * indicates that the primary plane is visible, but has a NULL FB, 356 * which will lead to problems later if we don't fix it up. The 357 * simplest solution is to just disable the primary plane now and 358 * pretend the BIOS never had it enabled. 359 */ 360 intel_plane_disable_noatomic(crtc, plane); 361 362 return; 363 364 valid_fb: 365 plane_state->uapi.rotation = plane_config->rotation; 366 intel_fb_fill_view(to_intel_framebuffer(fb), 367 plane_state->uapi.rotation, &plane_state->view); 368 369 __i915_vma_pin(vma); 370 plane_state->ggtt_vma = i915_vma_get(vma); 371 if (intel_plane_uses_fence(plane_state) && 372 i915_vma_pin_fence(vma) == 0 && vma->fence) 373 plane_state->flags |= PLANE_HAS_FENCE; 374 375 plane_state->uapi.src_x = 0; 376 plane_state->uapi.src_y = 0; 377 plane_state->uapi.src_w = fb->width << 16; 378 plane_state->uapi.src_h = fb->height << 16; 379 380 plane_state->uapi.crtc_x = 0; 381 plane_state->uapi.crtc_y = 0; 382 plane_state->uapi.crtc_w = fb->width; 383 plane_state->uapi.crtc_h = fb->height; 384 385 if (plane_config->tiling) 386 dev_priv->preserve_bios_swizzle = true; 387 388 plane_state->uapi.fb = fb; 389 drm_framebuffer_get(fb); 390 391 plane_state->uapi.crtc = &crtc->base; 392 intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc); 393 394 atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits); 395 } 396 397 static void plane_config_fini(struct intel_initial_plane_config *plane_config) 398 { 399 if (plane_config->fb) { 400 struct drm_framebuffer *fb = &plane_config->fb->base; 401 402 /* We may only have the stub and not a full framebuffer */ 403 if (drm_framebuffer_read_refcount(fb)) 404 drm_framebuffer_put(fb); 405 else 406 kfree(fb); 407 } 408 409 if (plane_config->vma) 410 i915_vma_put(plane_config->vma); 411 } 412 413 void intel_initial_plane_config(struct drm_i915_private *i915) 414 { 415 struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {}; 416 struct intel_crtc *crtc; 417 418 for_each_intel_crtc(&i915->drm, crtc) { 419 struct intel_initial_plane_config *plane_config = 420 &plane_configs[crtc->pipe]; 421 422 if (!to_intel_crtc_state(crtc->base.state)->uapi.active) 423 continue; 424 425 /* 426 * Note that reserving the BIOS fb up front prevents us 427 * from stuffing other stolen allocations like the ring 428 * on top. This prevents some ugliness at boot time, and 429 * can even allow for smooth boot transitions if the BIOS 430 * fb is large enough for the active pipe configuration. 431 */ 432 i915->display.funcs.display->get_initial_plane_config(crtc, plane_config); 433 434 /* 435 * If the fb is shared between multiple heads, we'll 436 * just get the first one. 437 */ 438 intel_find_initial_plane_obj(crtc, plane_configs); 439 440 if (i915->display.funcs.display->fixup_initial_plane_config(crtc, plane_config)) 441 intel_crtc_wait_for_next_vblank(crtc); 442 443 plane_config_fini(plane_config); 444 } 445 } 446