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