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_FRAMEBUFFER_CONSOLE) && 119 mem == i915->mm.stolen_region && 120 !intel_fbdev_fb_prefer_stolen(&i915->drm, size)) { 121 drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); 122 return NULL; 123 } 124 125 obj = i915_gem_object_create_region_at(mem, phys_base, size, 126 I915_BO_ALLOC_USER | 127 I915_BO_PREALLOC); 128 if (IS_ERR(obj)) { 129 drm_dbg_kms(&i915->drm, "Failed to preallocate initial FB in %s\n", 130 mem->region.name); 131 return NULL; 132 } 133 134 /* 135 * Mark it WT ahead of time to avoid changing the 136 * cache_level during fbdev initialization. The 137 * unbind there would get stuck waiting for rcu. 138 */ 139 i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ? 140 I915_CACHE_WT : I915_CACHE_NONE); 141 142 tiling = intel_fb_modifier_to_tiling(plane_config->fb->base.modifier); 143 144 switch (tiling) { 145 case I915_TILING_NONE: 146 break; 147 case I915_TILING_X: 148 case I915_TILING_Y: 149 obj->tiling_and_stride = 150 plane_config->fb->base.pitches[0] | 151 tiling; 152 break; 153 default: 154 MISSING_CASE(tiling); 155 goto err_obj; 156 } 157 158 /* 159 * MTL GOP likes to place the framebuffer high up in ggtt, 160 * which can cause problems for ggtt_reserve_guc_top(). 161 * Try to pin it to a low ggtt address instead to avoid that. 162 */ 163 base = 0; 164 165 if (base != plane_config->base) { 166 struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 167 int ret; 168 169 /* 170 * Make sure the original and new locations 171 * can't overlap. That would corrupt the original 172 * PTEs which are still being used for scanout. 173 */ 174 ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm, 175 size, plane_config->base, 176 I915_COLOR_UNEVICTABLE, PIN_NOEVICT); 177 if (ret) 178 goto err_obj; 179 } 180 181 vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL); 182 if (IS_ERR(vma)) 183 goto err_obj; 184 185 retry: 186 pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base; 187 if (!i915_gem_object_is_lmem(obj)) 188 pinctl |= PIN_MAPPABLE; 189 if (i915_vma_pin(vma, 0, 0, pinctl)) { 190 if (drm_mm_node_allocated(&orig_mm)) { 191 drm_mm_remove_node(&orig_mm); 192 /* 193 * Try again, but this time pin 194 * it to its original location. 195 */ 196 base = plane_config->base; 197 goto retry; 198 } 199 goto err_obj; 200 } 201 202 if (i915_gem_object_is_tiled(obj) && 203 !i915_vma_is_map_and_fenceable(vma)) 204 goto err_obj; 205 206 if (drm_mm_node_allocated(&orig_mm)) 207 drm_mm_remove_node(&orig_mm); 208 209 drm_dbg_kms(&i915->drm, 210 "Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n", 211 i915_ggtt_offset(vma), plane_config->base); 212 213 return vma; 214 215 err_obj: 216 if (drm_mm_node_allocated(&orig_mm)) 217 drm_mm_remove_node(&orig_mm); 218 i915_gem_object_put(obj); 219 return NULL; 220 } 221 222 static struct drm_gem_object * 223 i915_alloc_initial_plane_obj(struct drm_device *drm, 224 struct intel_initial_plane_config *plane_config) 225 { 226 struct drm_i915_private *i915 = to_i915(drm); 227 struct drm_mode_fb_cmd2 mode_cmd = {}; 228 struct drm_framebuffer *fb = &plane_config->fb->base; 229 struct i915_vma *vma; 230 231 vma = initial_plane_vma(i915, plane_config); 232 if (!vma) 233 return NULL; 234 235 mode_cmd.pixel_format = fb->format->format; 236 mode_cmd.width = fb->width; 237 mode_cmd.height = fb->height; 238 mode_cmd.pitches[0] = fb->pitches[0]; 239 mode_cmd.modifier[0] = fb->modifier; 240 mode_cmd.flags = DRM_MODE_FB_MODIFIERS; 241 242 if (intel_framebuffer_init(to_intel_framebuffer(fb), 243 intel_bo_to_drm_bo(vma->obj), 244 fb->format, &mode_cmd)) { 245 drm_dbg_kms(&i915->drm, "intel fb init failed\n"); 246 goto err_vma; 247 } 248 249 plane_config->vma = vma; 250 return intel_bo_to_drm_bo(vma->obj); 251 252 err_vma: 253 i915_vma_put(vma); 254 return NULL; 255 } 256 257 static int 258 i915_initial_plane_setup(struct drm_plane_state *_plane_state, 259 struct intel_initial_plane_config *plane_config, 260 struct drm_framebuffer *fb, 261 struct i915_vma *vma) 262 { 263 struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state); 264 struct drm_i915_private *dev_priv = to_i915(_plane_state->plane->dev); 265 266 __i915_vma_pin(vma); 267 plane_state->ggtt_vma = i915_vma_get(vma); 268 if (intel_plane_uses_fence(plane_state) && 269 i915_vma_pin_fence(vma) == 0 && vma->fence) 270 plane_state->flags |= PLANE_HAS_FENCE; 271 272 plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma); 273 274 if (fb->modifier != DRM_FORMAT_MOD_LINEAR) 275 dev_priv->preserve_bios_swizzle = true; 276 277 return 0; 278 } 279 280 static void i915_plane_config_fini(struct intel_initial_plane_config *plane_config) 281 { 282 if (plane_config->vma) 283 i915_vma_put(plane_config->vma); 284 } 285 286 const struct intel_display_initial_plane_interface i915_display_initial_plane_interface = { 287 .vblank_wait = i915_initial_plane_vblank_wait, 288 .alloc_obj = i915_alloc_initial_plane_obj, 289 .setup = i915_initial_plane_setup, 290 .config_fini = i915_plane_config_fini, 291 }; 292