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