16a3e94ffSJani Nikula // SPDX-License-Identifier: MIT 26a3e94ffSJani Nikula /* 36a3e94ffSJani Nikula * Copyright © 2021 Intel Corporation 46a3e94ffSJani Nikula */ 56a3e94ffSJani Nikula 66a3e94ffSJani Nikula /* for ioread64 */ 76a3e94ffSJani Nikula #include <linux/io-64-nonatomic-lo-hi.h> 86a3e94ffSJani Nikula 99dacae14SJani Nikula #include <drm/intel/display_parent_interface.h> 109dacae14SJani Nikula 116a3e94ffSJani Nikula #include "regs/xe_gtt_defs.h" 126a3e94ffSJani Nikula #include "xe_ggtt.h" 136a3e94ffSJani Nikula #include "xe_mmio.h" 146a3e94ffSJani Nikula 156a3e94ffSJani Nikula #include "i915_vma.h" 166a3e94ffSJani Nikula #include "intel_crtc.h" 176a3e94ffSJani Nikula #include "intel_display_regs.h" 186a3e94ffSJani Nikula #include "intel_display_types.h" 196a3e94ffSJani Nikula #include "intel_fb.h" 206a3e94ffSJani Nikula #include "intel_fb_pin.h" 216a3e94ffSJani Nikula #include "xe_bo.h" 226a3e94ffSJani Nikula #include "xe_vram_types.h" 236a3e94ffSJani Nikula #include "xe_wa.h" 246a3e94ffSJani Nikula 256a3e94ffSJani Nikula #include <generated/xe_device_wa_oob.h> 266a3e94ffSJani Nikula 276a3e94ffSJani Nikula /* Early xe has no irq */ 289dacae14SJani Nikula static void xe_initial_plane_vblank_wait(struct drm_crtc *_crtc) 299dacae14SJani Nikula { 309dacae14SJani Nikula struct intel_crtc *crtc = to_intel_crtc(_crtc); 316a3e94ffSJani Nikula struct xe_device *xe = to_xe_device(crtc->base.dev); 326a3e94ffSJani Nikula struct xe_reg pipe_frmtmstmp = XE_REG(i915_mmio_reg_offset(PIPE_FRMTMSTMP(crtc->pipe))); 336a3e94ffSJani Nikula u32 timestamp; 346a3e94ffSJani Nikula int ret; 356a3e94ffSJani Nikula 366a3e94ffSJani Nikula timestamp = xe_mmio_read32(xe_root_tile_mmio(xe), pipe_frmtmstmp); 376a3e94ffSJani Nikula 386a3e94ffSJani Nikula ret = xe_mmio_wait32_not(xe_root_tile_mmio(xe), pipe_frmtmstmp, ~0U, timestamp, 40000U, ×tamp, false); 396a3e94ffSJani Nikula if (ret < 0) 406a3e94ffSJani Nikula drm_warn(&xe->drm, "waiting for early vblank failed with %i\n", ret); 416a3e94ffSJani Nikula } 426a3e94ffSJani Nikula 436a3e94ffSJani Nikula static struct xe_bo * 446a3e94ffSJani Nikula initial_plane_bo(struct xe_device *xe, 456a3e94ffSJani Nikula struct intel_initial_plane_config *plane_config) 466a3e94ffSJani Nikula { 476a3e94ffSJani Nikula struct xe_tile *tile0 = xe_device_get_root_tile(xe); 486a3e94ffSJani Nikula struct xe_bo *bo; 496a3e94ffSJani Nikula resource_size_t phys_base; 506a3e94ffSJani Nikula u32 base, size, flags; 516a3e94ffSJani Nikula u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K; 526a3e94ffSJani Nikula 536a3e94ffSJani Nikula if (plane_config->size == 0) 546a3e94ffSJani Nikula return NULL; 556a3e94ffSJani Nikula 566a3e94ffSJani Nikula flags = XE_BO_FLAG_SCANOUT | XE_BO_FLAG_GGTT; 576a3e94ffSJani Nikula 586a3e94ffSJani Nikula base = round_down(plane_config->base, page_size); 596a3e94ffSJani Nikula if (IS_DGFX(xe)) { 606a3e94ffSJani Nikula u64 pte = xe_ggtt_read_pte(tile0->mem.ggtt, base); 616a3e94ffSJani Nikula 626a3e94ffSJani Nikula if (!(pte & XE_GGTT_PTE_DM)) { 636a3e94ffSJani Nikula drm_err(&xe->drm, 646a3e94ffSJani Nikula "Initial plane programming missing DM bit\n"); 656a3e94ffSJani Nikula return NULL; 666a3e94ffSJani Nikula } 676a3e94ffSJani Nikula 686a3e94ffSJani Nikula phys_base = pte & ~(page_size - 1); 696a3e94ffSJani Nikula flags |= XE_BO_FLAG_VRAM0; 706a3e94ffSJani Nikula 716a3e94ffSJani Nikula /* 726a3e94ffSJani Nikula * We don't currently expect this to ever be placed in the 736a3e94ffSJani Nikula * stolen portion. 746a3e94ffSJani Nikula */ 756a3e94ffSJani Nikula if (phys_base >= xe_vram_region_usable_size(tile0->mem.vram)) { 766a3e94ffSJani Nikula drm_err(&xe->drm, 776a3e94ffSJani Nikula "Initial plane programming using invalid range, phys_base=%pa\n", 786a3e94ffSJani Nikula &phys_base); 796a3e94ffSJani Nikula return NULL; 806a3e94ffSJani Nikula } 816a3e94ffSJani Nikula 826a3e94ffSJani Nikula drm_dbg(&xe->drm, 836a3e94ffSJani Nikula "Using phys_base=%pa, based on initial plane programming\n", 846a3e94ffSJani Nikula &phys_base); 856a3e94ffSJani Nikula } else { 866a3e94ffSJani Nikula struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN); 876a3e94ffSJani Nikula 886a3e94ffSJani Nikula if (!stolen) 896a3e94ffSJani Nikula return NULL; 906a3e94ffSJani Nikula phys_base = base; 916a3e94ffSJani Nikula flags |= XE_BO_FLAG_STOLEN; 926a3e94ffSJani Nikula 936a3e94ffSJani Nikula if (XE_DEVICE_WA(xe, 22019338487_display)) 946a3e94ffSJani Nikula return NULL; 956a3e94ffSJani Nikula 966a3e94ffSJani Nikula /* 976a3e94ffSJani Nikula * If the FB is too big, just don't use it since fbdev is not very 986a3e94ffSJani Nikula * important and we should probably use that space with FBC or other 996a3e94ffSJani Nikula * features. 1006a3e94ffSJani Nikula */ 1016a3e94ffSJani Nikula if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && 1026a3e94ffSJani Nikula plane_config->size * 2 >> PAGE_SHIFT >= stolen->size) 1036a3e94ffSJani Nikula return NULL; 1046a3e94ffSJani Nikula } 1056a3e94ffSJani Nikula 1066a3e94ffSJani Nikula size = round_up(plane_config->base + plane_config->size, 1076a3e94ffSJani Nikula page_size); 1086a3e94ffSJani Nikula size -= base; 1096a3e94ffSJani Nikula 1106a3e94ffSJani Nikula bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base, 1116a3e94ffSJani Nikula ttm_bo_type_kernel, flags, 0, false); 1126a3e94ffSJani Nikula if (IS_ERR(bo)) { 1136a3e94ffSJani Nikula drm_dbg(&xe->drm, 1146a3e94ffSJani Nikula "Failed to create bo phys_base=%pa size %u with flags %x: %li\n", 1156a3e94ffSJani Nikula &phys_base, size, flags, PTR_ERR(bo)); 1166a3e94ffSJani Nikula return NULL; 1176a3e94ffSJani Nikula } 1186a3e94ffSJani Nikula 1196a3e94ffSJani Nikula return bo; 1206a3e94ffSJani Nikula } 1216a3e94ffSJani Nikula 122adf7968eSJani Nikula static struct drm_gem_object * 123*82eaf345SJani Nikula xe_alloc_initial_plane_obj(struct drm_device *drm, 1246a3e94ffSJani Nikula struct intel_initial_plane_config *plane_config) 1256a3e94ffSJani Nikula { 126*82eaf345SJani Nikula struct xe_device *xe = to_xe_device(drm); 1276a3e94ffSJani Nikula struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 1286a3e94ffSJani Nikula struct drm_framebuffer *fb = &plane_config->fb->base; 1296a3e94ffSJani Nikula struct xe_bo *bo; 1306a3e94ffSJani Nikula 1316a3e94ffSJani Nikula mode_cmd.pixel_format = fb->format->format; 1326a3e94ffSJani Nikula mode_cmd.width = fb->width; 1336a3e94ffSJani Nikula mode_cmd.height = fb->height; 1346a3e94ffSJani Nikula mode_cmd.pitches[0] = fb->pitches[0]; 1356a3e94ffSJani Nikula mode_cmd.modifier[0] = fb->modifier; 1366a3e94ffSJani Nikula mode_cmd.flags = DRM_MODE_FB_MODIFIERS; 1376a3e94ffSJani Nikula 1386a3e94ffSJani Nikula bo = initial_plane_bo(xe, plane_config); 1396a3e94ffSJani Nikula if (!bo) 140adf7968eSJani Nikula return NULL; 1416a3e94ffSJani Nikula 1426a3e94ffSJani Nikula if (intel_framebuffer_init(to_intel_framebuffer(fb), 1436a3e94ffSJani Nikula &bo->ttm.base, fb->format, &mode_cmd)) { 1446a3e94ffSJani Nikula drm_dbg_kms(&xe->drm, "intel fb init failed\n"); 1456a3e94ffSJani Nikula goto err_bo; 1466a3e94ffSJani Nikula } 1476a3e94ffSJani Nikula /* Reference handed over to fb */ 1486a3e94ffSJani Nikula xe_bo_put(bo); 1496a3e94ffSJani Nikula 150adf7968eSJani Nikula return &bo->ttm.base; 1516a3e94ffSJani Nikula 1526a3e94ffSJani Nikula err_bo: 1536a3e94ffSJani Nikula xe_bo_unpin_map_no_vm(bo); 154adf7968eSJani Nikula return NULL; 1556a3e94ffSJani Nikula } 1566a3e94ffSJani Nikula 1571b3cc68dSJani Nikula static int 1585bad0037SJani Nikula xe_initial_plane_setup(struct drm_plane_state *_plane_state, 159adf7968eSJani Nikula struct intel_initial_plane_config *plane_config, 160adf7968eSJani Nikula struct drm_framebuffer *fb, 161adf7968eSJani Nikula struct i915_vma *_unused) 1626a3e94ffSJani Nikula { 1635bad0037SJani Nikula struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state); 1646a3e94ffSJani Nikula struct i915_vma *vma; 1656a3e94ffSJani Nikula 1666a3e94ffSJani Nikula vma = intel_fb_pin_to_ggtt(fb, &plane_state->view.gtt, 1676a3e94ffSJani Nikula 0, 0, 0, false, &plane_state->flags); 1686a3e94ffSJani Nikula if (IS_ERR(vma)) 1691b3cc68dSJani Nikula return PTR_ERR(vma); 1706a3e94ffSJani Nikula 1716a3e94ffSJani Nikula plane_state->ggtt_vma = vma; 1726a3e94ffSJani Nikula 1736a3e94ffSJani Nikula plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma); 1746a3e94ffSJani Nikula 1756a3e94ffSJani Nikula plane_config->vma = vma; 1766a3e94ffSJani Nikula 1771b3cc68dSJani Nikula return 0; 1786a3e94ffSJani Nikula } 1796a3e94ffSJani Nikula 180a13f152aSJani Nikula static void xe_plane_config_fini(struct intel_initial_plane_config *plane_config) 1816a3e94ffSJani Nikula { 1826a3e94ffSJani Nikula } 1836a3e94ffSJani Nikula 1849dacae14SJani Nikula const struct intel_display_initial_plane_interface xe_display_initial_plane_interface = { 1859dacae14SJani Nikula .vblank_wait = xe_initial_plane_vblank_wait, 186adf7968eSJani Nikula .alloc_obj = xe_alloc_initial_plane_obj, 187adf7968eSJani Nikula .setup = xe_initial_plane_setup, 188a13f152aSJani Nikula .config_fini = xe_plane_config_fini, 1899dacae14SJani Nikula }; 190