1 /* SPDX-License-Identifier: MIT */ 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/fb.h> 7 8 #include <drm/drm_print.h> 9 10 #include "gem/i915_gem_lmem.h" 11 12 #include "i915_drv.h" 13 #include "intel_fbdev_fb.h" 14 15 u32 intel_fbdev_fb_pitch_align(u32 stride) 16 { 17 return ALIGN(stride, 64); 18 } 19 20 struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) 21 { 22 struct drm_i915_private *dev_priv = to_i915(drm); 23 struct drm_i915_gem_object *obj; 24 25 obj = ERR_PTR(-ENODEV); 26 if (HAS_LMEM(dev_priv)) { 27 obj = i915_gem_object_create_lmem(dev_priv, size, 28 I915_BO_ALLOC_CONTIGUOUS | 29 I915_BO_ALLOC_USER); 30 } else { 31 /* 32 * If the FB is too big, just don't use it since fbdev is not very 33 * important and we should probably use that space with FBC or other 34 * features. 35 * 36 * Also skip stolen on MTL as Wa_22018444074 mitigation. 37 */ 38 if (!IS_METEORLAKE(dev_priv) && size * 2 < dev_priv->dsm.usable_size) 39 obj = i915_gem_object_create_stolen(dev_priv, size); 40 if (IS_ERR(obj)) 41 obj = i915_gem_object_create_shmem(dev_priv, size); 42 } 43 44 if (IS_ERR(obj)) { 45 drm_err(drm, "failed to allocate framebuffer (%pe)\n", obj); 46 return ERR_PTR(-ENOMEM); 47 } 48 49 return &obj->base; 50 } 51 52 void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) 53 { 54 drm_gem_object_put(obj); 55 } 56 57 int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, 58 struct drm_gem_object *_obj, struct i915_vma *vma) 59 { 60 struct drm_i915_private *i915 = to_i915(drm); 61 struct drm_i915_gem_object *obj = to_intel_bo(_obj); 62 struct i915_gem_ww_ctx ww; 63 void __iomem *vaddr; 64 int ret; 65 66 if (i915_gem_object_is_lmem(obj)) { 67 struct intel_memory_region *mem = obj->mm.region; 68 69 /* Use fbdev's framebuffer from lmem for discrete */ 70 info->fix.smem_start = 71 (unsigned long)(mem->io.start + 72 i915_gem_object_get_dma_address(obj, 0) - 73 mem->region.start); 74 info->fix.smem_len = obj->base.size; 75 } else { 76 struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 77 78 /* Our framebuffer is the entirety of fbdev's system memory */ 79 info->fix.smem_start = 80 (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); 81 info->fix.smem_len = vma->size; 82 } 83 84 for_i915_gem_ww(&ww, ret, false) { 85 ret = i915_gem_object_lock(vma->obj, &ww); 86 87 if (ret) 88 continue; 89 90 vaddr = i915_vma_pin_iomap(vma); 91 if (IS_ERR(vaddr)) { 92 drm_err(drm, 93 "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); 94 ret = PTR_ERR(vaddr); 95 continue; 96 } 97 } 98 99 if (ret) 100 return ret; 101 102 info->screen_base = vaddr; 103 info->screen_size = intel_bo_to_drm_bo(obj)->size; 104 105 return 0; 106 } 107