1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <drm/drm_print.h> 7 #include <drm/intel/display_parent_interface.h> 8 9 #include "display/intel_crtc.h" 10 #include "display/intel_display_types.h" 11 #include "display/intel_fb.h" 12 #include "display/intel_fbdev_fb.h" 13 #include "gem/i915_gem_lmem.h" 14 #include "gem/i915_gem_region.h" 15 16 #include "i915_drv.h" 17 #include "i915_initial_plane.h" 18 19 static void i915_initial_plane_vblank_wait(struct drm_crtc *crtc) 20 { 21 intel_crtc_wait_for_next_vblank(to_intel_crtc(crtc)); 22 } 23 24 static enum intel_memory_type 25 initial_plane_memory_type(struct drm_i915_private *i915) 26 { 27 if (IS_DGFX(i915)) 28 return INTEL_MEMORY_LOCAL; 29 else if (HAS_LMEMBAR_SMEM_STOLEN(i915)) 30 return INTEL_MEMORY_STOLEN_LOCAL; 31 else 32 return INTEL_MEMORY_STOLEN_SYSTEM; 33 } 34 35 static bool 36 initial_plane_phys(struct drm_i915_private *i915, 37 struct intel_initial_plane_config *plane_config) 38 { 39 struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 40 struct intel_memory_region *mem; 41 enum intel_memory_type mem_type; 42 bool is_present, is_local; 43 dma_addr_t dma_addr; 44 u32 base; 45 46 mem_type = initial_plane_memory_type(i915); 47 mem = intel_memory_region_by_type(i915, mem_type); 48 if (!mem) { 49 drm_dbg_kms(&i915->drm, 50 "Initial plane memory region (type %s) not initialized\n", 51 intel_memory_type_str(mem_type)); 52 return false; 53 } 54 55 base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); 56 57 dma_addr = intel_ggtt_read_entry(&ggtt->vm, base, &is_present, &is_local); 58 59 if (!is_present) { 60 drm_err(&i915->drm, "Initial plane FB PTE not present\n"); 61 return false; 62 } 63 64 if (intel_memory_type_is_local(mem->type) != is_local) { 65 drm_err(&i915->drm, "Initial plane FB PTE unsuitable for %s\n", 66 mem->region.name); 67 return false; 68 } 69 70 if (dma_addr < mem->region.start || dma_addr > mem->region.end) { 71 drm_err(&i915->drm, 72 "Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n", 73 &dma_addr, mem->region.name, &mem->region.start, &mem->region.end); 74 return false; 75 } 76 77 drm_dbg(&i915->drm, "Using dma_addr=%pa, based on initial plane programming\n", 78 &dma_addr); 79 80 plane_config->phys_base = dma_addr - mem->region.start; 81 plane_config->mem = mem; 82 83 return true; 84 } 85 86 static struct i915_vma * 87 initial_plane_vma(struct drm_i915_private *i915, 88 struct intel_initial_plane_config *plane_config) 89 { 90 struct intel_memory_region *mem; 91 struct drm_i915_gem_object *obj; 92 struct drm_mm_node orig_mm = {}; 93 struct i915_vma *vma; 94 resource_size_t phys_base; 95 unsigned int tiling; 96 u32 base, size; 97 u64 pinctl; 98 99 if (plane_config->size == 0) 100 return NULL; 101 102 if (!initial_plane_phys(i915, plane_config)) 103 return NULL; 104 105 phys_base = plane_config->phys_base; 106 mem = plane_config->mem; 107 108 base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); 109 size = round_up(plane_config->base + plane_config->size, 110 mem->min_page_size); 111 size -= base; 112 113 /* 114 * If the FB is too big, just don't use it since fbdev is not very 115 * important and we should probably use that space with FBC or other 116 * features. 117 */ 118 if (IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) && 119 IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && 120 mem == i915->mm.stolen_region && 121 !intel_fbdev_fb_prefer_stolen(&i915->drm, size)) { 122 drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); 123 return NULL; 124 } 125 126 obj = i915_gem_object_create_region_at(mem, phys_base, size, 127 I915_BO_ALLOC_USER | 128 I915_BO_PREALLOC); 129 if (IS_ERR(obj)) { 130 drm_dbg_kms(&i915->drm, "Failed to preallocate initial FB in %s\n", 131 mem->region.name); 132 return NULL; 133 } 134 135 /* 136 * Mark it WT ahead of time to avoid changing the 137 * cache_level during fbdev initialization. The 138 * unbind there would get stuck waiting for rcu. 139 */ 140 i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ? 141 I915_CACHE_WT : I915_CACHE_NONE); 142 143 tiling = intel_fb_modifier_to_tiling(plane_config->fb->base.modifier); 144 145 switch (tiling) { 146 case I915_TILING_NONE: 147 break; 148 case I915_TILING_X: 149 case I915_TILING_Y: 150 obj->tiling_and_stride = 151 plane_config->fb->base.pitches[0] | 152 tiling; 153 break; 154 default: 155 MISSING_CASE(tiling); 156 goto err_obj; 157 } 158 159 /* 160 * MTL GOP likes to place the framebuffer high up in ggtt, 161 * which can cause problems for ggtt_reserve_guc_top(). 162 * Try to pin it to a low ggtt address instead to avoid that. 163 */ 164 base = 0; 165 166 if (base != plane_config->base) { 167 struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 168 int ret; 169 170 /* 171 * Make sure the original and new locations 172 * can't overlap. That would corrupt the original 173 * PTEs which are still being used for scanout. 174 */ 175 ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm, 176 size, plane_config->base, 177 I915_COLOR_UNEVICTABLE, PIN_NOEVICT); 178 if (ret) 179 goto err_obj; 180 } 181 182 vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL); 183 if (IS_ERR(vma)) 184 goto err_obj; 185 186 retry: 187 pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base; 188 if (!i915_gem_object_is_lmem(obj)) 189 pinctl |= PIN_MAPPABLE; 190 if (i915_vma_pin(vma, 0, 0, pinctl)) { 191 if (drm_mm_node_allocated(&orig_mm)) { 192 drm_mm_remove_node(&orig_mm); 193 /* 194 * Try again, but this time pin 195 * it to its original location. 196 */ 197 base = plane_config->base; 198 goto retry; 199 } 200 goto err_obj; 201 } 202 203 if (i915_gem_object_is_tiled(obj) && 204 !i915_vma_is_map_and_fenceable(vma)) 205 goto err_obj; 206 207 if (drm_mm_node_allocated(&orig_mm)) 208 drm_mm_remove_node(&orig_mm); 209 210 drm_dbg_kms(&i915->drm, 211 "Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n", 212 i915_ggtt_offset(vma), plane_config->base); 213 214 return vma; 215 216 err_obj: 217 if (drm_mm_node_allocated(&orig_mm)) 218 drm_mm_remove_node(&orig_mm); 219 i915_gem_object_put(obj); 220 return NULL; 221 } 222 223 static struct drm_gem_object * 224 i915_alloc_initial_plane_obj(struct drm_device *drm, 225 struct intel_initial_plane_config *plane_config) 226 { 227 struct drm_i915_private *i915 = to_i915(drm); 228 struct drm_mode_fb_cmd2 mode_cmd = {}; 229 struct drm_framebuffer *fb = &plane_config->fb->base; 230 struct i915_vma *vma; 231 232 vma = initial_plane_vma(i915, plane_config); 233 if (!vma) 234 return NULL; 235 236 mode_cmd.pixel_format = fb->format->format; 237 mode_cmd.width = fb->width; 238 mode_cmd.height = fb->height; 239 mode_cmd.pitches[0] = fb->pitches[0]; 240 mode_cmd.modifier[0] = fb->modifier; 241 mode_cmd.flags = DRM_MODE_FB_MODIFIERS; 242 243 if (intel_framebuffer_init(to_intel_framebuffer(fb), 244 intel_bo_to_drm_bo(vma->obj), 245 fb->format, &mode_cmd)) { 246 drm_dbg_kms(&i915->drm, "intel fb init failed\n"); 247 goto err_vma; 248 } 249 250 plane_config->vma = vma; 251 return intel_bo_to_drm_bo(vma->obj); 252 253 err_vma: 254 i915_vma_put(vma); 255 return NULL; 256 } 257 258 static int 259 i915_initial_plane_setup(struct drm_plane_state *_plane_state, 260 struct intel_initial_plane_config *plane_config, 261 struct drm_framebuffer *fb, 262 struct i915_vma *vma) 263 { 264 struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state); 265 struct drm_i915_private *dev_priv = to_i915(_plane_state->plane->dev); 266 267 __i915_vma_pin(vma); 268 plane_state->ggtt_vma = i915_vma_get(vma); 269 if (intel_plane_uses_fence(plane_state) && 270 i915_vma_pin_fence(vma) == 0 && vma->fence) 271 plane_state->flags |= PLANE_HAS_FENCE; 272 273 plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma); 274 275 if (fb->modifier != DRM_FORMAT_MOD_LINEAR) 276 dev_priv->preserve_bios_swizzle = true; 277 278 return 0; 279 } 280 281 static void i915_plane_config_fini(struct intel_initial_plane_config *plane_config) 282 { 283 if (plane_config->vma) 284 i915_vma_put(plane_config->vma); 285 } 286 287 const struct intel_display_initial_plane_interface i915_display_initial_plane_interface = { 288 .vblank_wait = i915_initial_plane_vblank_wait, 289 .alloc_obj = i915_alloc_initial_plane_obj, 290 .setup = i915_initial_plane_setup, 291 .config_fini = i915_plane_config_fini, 292 }; 293