diff options
Diffstat (limited to 'drivers/gpu')
414 files changed, 10427 insertions, 4734 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3c16bd1afd87..d3a9ca4b1cec 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -80,23 +80,6 @@ config DRM_KMS_HELPER help CRTC helpers for KMS drivers. -config DRM_KMS_FB_HELPER - bool - depends on DRM_KMS_HELPER - select FB - select FRAMEBUFFER_CONSOLE if !EXPERT - select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_DEFERRED_IO - help - FBDEV helpers for KMS drivers. - config DRM_DEBUG_DP_MST_TOPOLOGY_REFS bool "Enable refcount backtrace history in the DP MST helpers" depends on STACKTRACE_SUPPORT @@ -117,6 +100,17 @@ config DRM_FBDEV_EMULATION depends on DRM select DRM_KMS_HELPER select DRM_KMS_FB_HELPER + select FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_DEFERRED_IO + select FB_SYS_FOPS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FRAMEBUFFER_CONSOLE if !EXPERT + select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE default y help Choose this option if you have a need for the legacy fbdev diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 5279db4392df..a91cc7684904 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,7 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -drm-y := drm_auth.o drm_cache.o \ +drm-y := drm_aperture.o drm_auth.o drm_cache.o \ drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_drv.o \ drm_sysfs.o drm_hashtab.o drm_mm.o \ @@ -20,15 +20,15 @@ drm-y := drm_auth.o drm_cache.o \ drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \ drm_managed.o drm_vblank_work.o -drm-$(CONFIG_DRM_LEGACY) += drm_bufs.o drm_context.o drm_dma.o drm_legacy_misc.o drm_lock.o \ - drm_memory.o drm_scatter.o drm_vm.o +drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \ + drm_legacy_misc.o drm_lock.o drm_memory.o drm_scatter.o \ + drm_vm.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o -drm-$(CONFIG_AGP) += drm_agpsupport.o drm-$(CONFIG_PCI) += drm_pci.o drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 418e6747b3d5..cc36570b0d2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -58,6 +58,8 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \ amdgpu_fw_attestation.o amdgpu_securedisplay.o amdgpu_hdp.o +amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o + amdgpu-$(CONFIG_PERF_EVENTS) += amdgpu_pmu.o # add asic specific block diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index b6435479cac8..ad5f508924b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -107,6 +107,7 @@ #include "amdgpu_gfxhub.h" #include "amdgpu_df.h" #include "amdgpu_smuio.h" +#include "amdgpu_fdinfo.h" #define MAX_GPU_INSTANCE 16 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 0350205c4897..fc83445fbc40 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -651,3 +651,81 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) idr_destroy(&mgr->ctx_handles); mutex_destroy(&mgr->lock); } + +static void amdgpu_ctx_fence_time(struct amdgpu_ctx *ctx, + struct amdgpu_ctx_entity *centity, ktime_t *total, ktime_t *max) +{ + ktime_t now, t1; + uint32_t i; + + *total = *max = 0; + + now = ktime_get(); + for (i = 0; i < amdgpu_sched_jobs; i++) { + struct dma_fence *fence; + struct drm_sched_fence *s_fence; + + spin_lock(&ctx->ring_lock); + fence = dma_fence_get(centity->fences[i]); + spin_unlock(&ctx->ring_lock); + if (!fence) + continue; + s_fence = to_drm_sched_fence(fence); + if (!dma_fence_is_signaled(&s_fence->scheduled)) { + dma_fence_put(fence); + continue; + } + t1 = s_fence->scheduled.timestamp; + if (!ktime_before(t1, now)) { + dma_fence_put(fence); + continue; + } + if (dma_fence_is_signaled(&s_fence->finished) && + s_fence->finished.timestamp < now) + *total += ktime_sub(s_fence->finished.timestamp, t1); + else + *total += ktime_sub(now, t1); + t1 = ktime_sub(now, t1); + dma_fence_put(fence); + *max = max(t1, *max); + } +} + +ktime_t amdgpu_ctx_mgr_fence_usage(struct amdgpu_ctx_mgr *mgr, uint32_t hwip, + uint32_t idx, uint64_t *elapsed) +{ + struct idr *idp; + struct amdgpu_ctx *ctx; + uint32_t id; + struct amdgpu_ctx_entity *centity; + ktime_t total = 0, max = 0; + + if (idx >= AMDGPU_MAX_ENTITY_NUM) + return 0; + idp = &mgr->ctx_handles; + mutex_lock(&mgr->lock); + idr_for_each_entry(idp, ctx, id) { + ktime_t ttotal, tmax; + + if (!ctx->entities[hwip][idx]) + continue; + + centity = ctx->entities[hwip][idx]; + amdgpu_ctx_fence_time(ctx, centity, &ttotal, &tmax); + + /* Harmonic mean approximation diverges for very small + * values. If ratio < 0.01% ignore + */ + if (AMDGPU_CTX_FENCE_USAGE_MIN_RATIO(tmax, ttotal)) + continue; + + total = ktime_add(total, ttotal); + max = ktime_after(tmax, max) ? tmax : max; + } + + mutex_unlock(&mgr->lock); + if (elapsed) + *elapsed = max; + + return total; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h index f54e10314661..14db16bc3322 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h @@ -30,6 +30,7 @@ struct drm_file; struct amdgpu_fpriv; #define AMDGPU_MAX_ENTITY_NUM 4 +#define AMDGPU_CTX_FENCE_USAGE_MIN_RATIO(max, total) ((max) > 16384ULL*(total)) struct amdgpu_ctx_entity { uint64_t sequence; @@ -87,5 +88,6 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr); void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr); long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout); void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr); - +ktime_t amdgpu_ctx_mgr_fence_usage(struct amdgpu_ctx_mgr *mgr, uint32_t hwip, + uint32_t idx, uint64_t *elapsed); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 410fce097921..1ed9748b9bc7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -23,6 +23,7 @@ */ #include <drm/amdgpu_drm.h> +#include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_gem.h> #include <drm/drm_vblank.h> @@ -42,7 +43,7 @@ #include "amdgpu_irq.h" #include "amdgpu_dma_buf.h" #include "amdgpu_sched.h" - +#include "amdgpu_fdinfo.h" #include "amdgpu_amdkfd.h" #include "amdgpu_ras.h" @@ -1260,7 +1261,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, #endif /* Get rid of things like offb */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); if (ret) return ret; @@ -1694,6 +1695,9 @@ static const struct file_operations amdgpu_driver_kms_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = amdgpu_kms_compat_ioctl, #endif +#ifdef CONFIG_PROC_FS + .show_fdinfo = amdgpu_show_fdinfo +#endif }; int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c new file mode 100644 index 000000000000..dbebbe16e3b3 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +/* Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: David Nieto + * Roy Sun + */ + +#include <linux/debugfs.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/reboot.h> +#include <linux/syscalls.h> + +#include <drm/amdgpu_drm.h> +#include <drm/drm_debugfs.h> + +#include "amdgpu.h" +#include "amdgpu_vm.h" +#include "amdgpu_gem.h" +#include "amdgpu_ctx.h" +#include "amdgpu_fdinfo.h" + + +static const char *amdgpu_ip_name[AMDGPU_HW_IP_NUM] = { + [AMDGPU_HW_IP_GFX] = "gfx", + [AMDGPU_HW_IP_COMPUTE] = "compute", + [AMDGPU_HW_IP_DMA] = "dma", + [AMDGPU_HW_IP_UVD] = "dec", + [AMDGPU_HW_IP_VCE] = "enc", + [AMDGPU_HW_IP_UVD_ENC] = "enc_1", + [AMDGPU_HW_IP_VCN_DEC] = "dec", + [AMDGPU_HW_IP_VCN_ENC] = "enc", + [AMDGPU_HW_IP_VCN_JPEG] = "jpeg", +}; + +void amdgpu_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct amdgpu_fpriv *fpriv; + uint32_t bus, dev, fn, i, domain; + uint64_t vram_mem = 0, gtt_mem = 0, cpu_mem = 0; + struct drm_file *file = f->private_data; + struct amdgpu_device *adev = drm_to_adev(file->minor->dev); + int ret; + + ret = amdgpu_file_to_fpriv(f, &fpriv); + if (ret) + return; + bus = adev->pdev->bus->number; + domain = pci_domain_nr(adev->pdev->bus); + dev = PCI_SLOT(adev->pdev->devfn); + fn = PCI_FUNC(adev->pdev->devfn); + + ret = amdgpu_bo_reserve(fpriv->vm.root.base.bo, false); + if (ret) { + DRM_ERROR("Fail to reserve bo\n"); + return; + } + amdgpu_vm_get_memory(&fpriv->vm, &vram_mem, >t_mem, &cpu_mem); + amdgpu_bo_unreserve(fpriv->vm.root.base.bo); + seq_printf(m, "pdev:\t%04x:%02x:%02x.%d\npasid:\t%u\n", domain, bus, + dev, fn, fpriv->vm.pasid); + seq_printf(m, "vram mem:\t%llu kB\n", vram_mem/1024UL); + seq_printf(m, "gtt mem:\t%llu kB\n", gtt_mem/1024UL); + seq_printf(m, "cpu mem:\t%llu kB\n", cpu_mem/1024UL); + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { + uint32_t count = amdgpu_ctx_num_entities[i]; + int idx = 0; + uint64_t total = 0, min = 0; + uint32_t perc, frac; + + for (idx = 0; idx < count; idx++) { + total = amdgpu_ctx_mgr_fence_usage(&fpriv->ctx_mgr, + i, idx, &min); + if ((total == 0) || (min == 0)) + continue; + + perc = div64_u64(10000 * total, min); + frac = perc % 100; + + seq_printf(m, "%s%d:\t%d.%d%%\n", + amdgpu_ip_name[i], + idx, perc/100, frac); + } + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h new file mode 100644 index 000000000000..41a4c7056729 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: MIT + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: David Nieto + * Roy Sun + */ +#ifndef __AMDGPU_SMI_H__ +#define __AMDGPU_SMI_H__ + +#include <linux/idr.h> +#include <linux/kfifo.h> +#include <linux/rbtree.h> +#include <drm/gpu_scheduler.h> +#include <drm/drm_file.h> +#include <drm/ttm/ttm_bo_driver.h> +#include <linux/sched/mm.h> + +#include "amdgpu_sync.h" +#include "amdgpu_ring.h" +#include "amdgpu_ids.h" + +uint32_t amdgpu_get_ip_count(struct amdgpu_device *adev, int id); +void amdgpu_show_fdinfo(struct seq_file *m, struct file *f); + +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 311bcdc59eda..18974bd081f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -766,7 +766,7 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, void __user *out = u64_to_user_ptr(args->value); info.bo_size = robj->tbo.base.size; - info.alignment = robj->tbo.mem.page_alignment << PAGE_SHIFT; + info.alignment = robj->tbo.page_alignment << PAGE_SHIFT; info.domains = robj->preferred_domains; info.domain_flags = robj->flags; amdgpu_bo_unreserve(robj); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index 8860545344c7..c026972ca9a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -136,7 +136,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, spin_lock(&mgr->lock); r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages, - mem->page_alignment, 0, place->fpfn, + tbo->page_alignment, 0, place->fpfn, place->lpfn, DRM_MM_INSERT_BEST); spin_unlock(&mgr->lock); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index da6d4ee0a132..8714d50c5b20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -52,36 +52,12 @@ * */ -/** - * amdgpu_bo_subtract_pin_size - Remove BO from pin_size accounting - * - * @bo: &amdgpu_bo buffer object - * - * This function is called when a BO stops being pinned, and updates the - * &amdgpu_device pin_size values accordingly. - */ -static void amdgpu_bo_subtract_pin_size(struct amdgpu_bo *bo) -{ - struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); - - if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { - atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); - atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), - &adev->visible_pin_size); - } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { - atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); - } -} - static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo) { struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); struct amdgpu_bo_user *ubo; - if (bo->tbo.pin_count > 0) - amdgpu_bo_subtract_pin_size(bo); - amdgpu_bo_kunmap(bo); if (bo->tbo.base.import_attach) @@ -1002,14 +978,22 @@ int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain) */ void amdgpu_bo_unpin(struct amdgpu_bo *bo) { + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + ttm_bo_unpin(&bo->tbo); if (bo->tbo.pin_count) return; - amdgpu_bo_subtract_pin_size(bo); - if (bo->tbo.base.import_attach) dma_buf_unpin(bo->tbo.base.import_attach); + + if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { + atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); + atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), + &adev->visible_pin_size); + } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { + atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); + } } /** @@ -1269,6 +1253,26 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); } +void amdgpu_bo_get_memory(struct amdgpu_bo *bo, uint64_t *vram_mem, + uint64_t *gtt_mem, uint64_t *cpu_mem) +{ + unsigned int domain; + + domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); + switch (domain) { + case AMDGPU_GEM_DOMAIN_VRAM: + *vram_mem += amdgpu_bo_size(bo); + break; + case AMDGPU_GEM_DOMAIN_GTT: + *gtt_mem += amdgpu_bo_size(bo); + break; + case AMDGPU_GEM_DOMAIN_CPU: + default: + *cpu_mem += amdgpu_bo_size(bo); + break; + } +} + /** * amdgpu_bo_release_notify - notification about a BO being released * @bo: pointer to a buffer object @@ -1327,7 +1331,7 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); - unsigned long offset, size; + unsigned long offset; int r; /* Remember that this BO was accessed by the CPU */ @@ -1336,9 +1340,8 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) if (bo->mem.mem_type != TTM_PL_VRAM) return 0; - size = bo->mem.num_pages << PAGE_SHIFT; offset = bo->mem.start << PAGE_SHIFT; - if ((offset + size) <= adev->gmc.visible_vram_size) + if ((offset + bo->base.size) <= adev->gmc.visible_vram_size) return 0; /* Can't move a pinned BO to visible VRAM */ @@ -1363,7 +1366,7 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) offset = bo->mem.start << PAGE_SHIFT; /* this should never happen */ if (bo->mem.mem_type == TTM_PL_VRAM && - (offset + size) > adev->gmc.visible_vram_size) + (offset + bo->base.size) > adev->gmc.visible_vram_size) return VM_FAULT_SIGBUS; ttm_bo_move_to_lru_tail_unlocked(bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index e0ec48d6a3fd..46d22ab85492 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -195,7 +195,7 @@ static inline unsigned amdgpu_bo_ngpu_pages(struct amdgpu_bo *bo) static inline unsigned amdgpu_bo_gpu_page_alignment(struct amdgpu_bo *bo) { - return (bo->tbo.mem.page_alignment << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE; + return (bo->tbo.page_alignment << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE; } /** @@ -307,6 +307,8 @@ int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr); u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo); u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo); int amdgpu_bo_validate(struct amdgpu_bo *bo); +void amdgpu_bo_get_memory(struct amdgpu_bo *bo, uint64_t *vram_mem, + uint64_t *gtt_mem, uint64_t *cpu_mem); int amdgpu_bo_restore_shadow(struct amdgpu_bo *shadow, struct dma_fence **fence); uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 3251f6b67e23..10391fcff343 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -969,8 +969,6 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) } else { /* allocate GART space */ - tmp = bo->mem; - tmp.mm_node = NULL; placement.num_placement = 1; placement.placement = &placements; placement.num_busy_placement = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 7e1a67295106..edc63d3e087e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -25,6 +25,7 @@ * Alex Deucher * Jerome Glisse */ + #include <linux/dma-fence-array.h> #include <linux/interval_tree_generic.h> #include <linux/idr.h> @@ -1740,6 +1741,50 @@ error_unlock: return r; } +void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem, + uint64_t *gtt_mem, uint64_t *cpu_mem) +{ + struct amdgpu_bo_va *bo_va, *tmp; + + list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) { + if (!bo_va->base.bo) + continue; + amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, + gtt_mem, cpu_mem); + } + list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status) { + if (!bo_va->base.bo) + continue; + amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, + gtt_mem, cpu_mem); + } + list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status) { + if (!bo_va->base.bo) + continue; + amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, + gtt_mem, cpu_mem); + } + list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) { + if (!bo_va->base.bo) + continue; + amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, + gtt_mem, cpu_mem); + } + spin_lock(&vm->invalidated_lock); + list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) { + if (!bo_va->base.bo) + continue; + amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, + gtt_mem, cpu_mem); + } + list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status) { + if (!bo_va->base.bo) + continue; + amdgpu_bo_get_memory(bo_va->base.bo, vram_mem, + gtt_mem, cpu_mem); + } + spin_unlock(&vm->invalidated_lock); +} /** * amdgpu_vm_bo_update - update all BO mappings in the vm page table * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index e5a3f18be2b7..ea60ec122b51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -454,6 +454,8 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm); void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev, struct amdgpu_vm *vm); void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo); +void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem, + uint64_t *gtt_mem, uint64_t *cpu_mem); #if defined(CONFIG_DEBUG_FS) void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index e2cbe19404c0..f78d21910e07 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -394,7 +394,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, pages_per_node = 2UL << (20UL - PAGE_SHIFT); #endif pages_per_node = max_t(uint32_t, pages_per_node, - mem->page_alignment); + tbo->page_alignment); num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node); } @@ -418,7 +418,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, i = 0; spin_lock(&mgr->lock); while (pages_left) { - uint32_t alignment = mem->page_alignment; + uint32_t alignment = tbo->page_alignment; if (pages >= pages_per_node) alignment = pages_per_node; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index a3ba9ca11e98..f327becb022f 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -188,6 +188,8 @@ void amdgpu_atombios_dp_aux_init(struct amdgpu_connector *amdgpu_connector) { amdgpu_connector->ddc_bus->rec.hpd = amdgpu_connector->hpd.hpd; amdgpu_connector->ddc_bus->aux.transfer = amdgpu_atombios_dp_aux_transfer; + amdgpu_connector->ddc_bus->aux.drm_dev = amdgpu_connector->base.dev; + drm_dp_aux_init(&amdgpu_connector->ddc_bus->aux); amdgpu_connector->ddc_bus->has_aux = true; } @@ -610,7 +612,7 @@ amdgpu_atombios_dp_link_train_cr(struct amdgpu_atombios_dp_link_train_info *dp_i dp_info->tries = 0; voltage = 0xff; while (1) { - drm_dp_link_train_clock_recovery_delay(dp_info->dpcd); + drm_dp_link_train_clock_recovery_delay(dp_info->aux, dp_info->dpcd); if (drm_dp_dpcd_read_link_status(dp_info->aux, dp_info->link_status) <= 0) { @@ -675,7 +677,7 @@ amdgpu_atombios_dp_link_train_ce(struct amdgpu_atombios_dp_link_train_info *dp_i dp_info->tries = 0; channel_eq = false; while (1) { - drm_dp_link_train_channel_eq_delay(dp_info->dpcd); + drm_dp_link_train_channel_eq_delay(dp_info->aux, dp_info->dpcd); if (drm_dp_dpcd_read_link_status(dp_info->aux, dp_info->link_status) <= 0) { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index 0cd98fcb1f9f..939bcfa2a4ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -363,6 +363,7 @@ static int uvd_v7_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) error: dma_fence_put(fence); + amdgpu_bo_unpin(bo); amdgpu_bo_unreserve(bo); amdgpu_bo_unref(&bo); return r; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c index 5a1f2433632b..73f2257acc23 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c @@ -333,10 +333,6 @@ int kfd_iommu_resume(struct kfd_dev *kfd) return 0; } -extern bool amd_iommu_pc_supported(void); -extern u8 amd_iommu_pc_get_max_banks(u16 devid); -extern u8 amd_iommu_pc_get_max_counters(u16 devid); - /** kfd_iommu_add_perf_counters - Add IOMMU performance counters to topology */ int kfd_iommu_add_perf_counters(struct kfd_topology_device *kdev) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5df187a6e25f..4823f8a32159 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6399,25 +6399,6 @@ static int fill_hdr_info_packet(const struct drm_connector_state *state, return 0; } -static bool -is_hdr_metadata_different(const struct drm_connector_state *old_state, - const struct drm_connector_state *new_state) -{ - struct drm_property_blob *old_blob = old_state->hdr_output_metadata; - struct drm_property_blob *new_blob = new_state->hdr_output_metadata; - - if (old_blob != new_blob) { - if (old_blob && new_blob && - old_blob->length == new_blob->length) - return memcmp(old_blob->data, new_blob->data, - old_blob->length); - - return true; - } - - return false; -} - static int amdgpu_dm_connector_atomic_check(struct drm_connector *conn, struct drm_atomic_state *state) @@ -6435,7 +6416,7 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, if (!crtc) return 0; - if (is_hdr_metadata_different(old_con_state, new_con_state)) { + if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) { struct dc_info_packet hdr_infopacket; ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket); @@ -7622,9 +7603,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, if (connector_type == DRM_MODE_CONNECTOR_HDMIA || connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector_type == DRM_MODE_CONNECTOR_eDP) { - drm_object_attach_property( - &aconnector->base.base, - dm->ddev->mode_config.hdr_output_metadata_property, 0); + drm_connector_attach_hdr_output_metadata_property(&aconnector->base); if (!aconnector->mst_port) drm_connector_attach_vrr_capable_property(&aconnector->base); @@ -8928,7 +8907,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) dm_old_crtc_state->abm_level; hdr_changed = - is_hdr_metadata_different(old_con_state, new_con_state); + !drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state); if (!scaling_changed && !abm_changed && !hdr_changed) continue; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index d62460b69d95..e6b2eec9fb59 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -437,10 +437,13 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, struct amdgpu_dm_connector *aconnector, int link_index) { + struct dc_link_settings max_link_enc_cap = {0}; + aconnector->dm_dp_aux.aux.name = kasprintf(GFP_KERNEL, "AMDGPU DM aux hw bus %d", link_index); aconnector->dm_dp_aux.aux.transfer = dm_dp_aux_transfer; + aconnector->dm_dp_aux.aux.drm_dev = dm->ddev; aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc; drm_dp_aux_init(&aconnector->dm_dp_aux.aux); @@ -450,6 +453,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_eDP) return; + dc_link_dp_get_max_link_enc_cap(aconnector->dc_link, &max_link_enc_cap); aconnector->mst_mgr.cbs = &dm_mst_cbs; drm_dp_mst_topology_mgr_init( &aconnector->mst_mgr, @@ -457,6 +461,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, &aconnector->dm_dp_aux.aux, 16, 4, + (u8)max_link_enc_cap.lane_count, + (u8)max_link_enc_cap.link_rate, aconnector->connector_id); drm_connector_attach_dp_subconnector_property(&aconnector->base); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 4a08fe095476..ba4883fca616 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -1947,6 +1947,24 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down) return true; } +bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) +{ + if (!max_link_enc_cap) { + DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__); + return false; + } + + if (link->link_enc->funcs->get_max_link_cap) { + link->link_enc->funcs->get_max_link_cap(link->link_enc, max_link_enc_cap); + return true; + } + + DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__); + max_link_enc_cap->lane_count = 1; + max_link_enc_cap->link_rate = 6; + return false; +} + static struct dc_link_settings get_max_link_cap(struct dc_link *link) { struct dc_link_settings max_link_cap = {0}; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 3b57ba5fbb4b..c871923e7db0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -340,6 +340,8 @@ bool dc_link_dp_set_test_pattern( const unsigned char *p_custom_pattern, unsigned int cust_pattern_size); +bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap); + void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); bool dc_link_is_dp_sink_present(struct dc_link *link); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index aeda4e5ec4f4..ff45f23f3d56 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -247,7 +247,6 @@ static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms, config->min_height = 0; config->max_width = 4096; config->max_height = 4096; - config->allow_fb_modifiers = true; config->funcs = &komeda_mode_config_funcs; config->helper_private = &komeda_mode_config_helpers; diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index d83c7366b348..de59f3302516 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -403,7 +403,6 @@ static int malidp_init(struct drm_device *drm) drm->mode_config.max_height = hwdev->max_line_size; drm->mode_config.funcs = &malidp_mode_config_funcs; drm->mode_config.helper_private = &malidp_mode_config_helpers; - drm->mode_config.allow_fb_modifiers = true; ret = malidp_crtc_init(drm); if (ret) diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index ddbba67f0283..8c2ab3d653b7 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -927,6 +927,11 @@ static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = { .atomic_disable = malidp_de_plane_disable, }; +static const uint64_t linear_only_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + int malidp_de_planes_init(struct drm_device *drm) { struct malidp_drm *malidp = drm->dev_private; @@ -990,8 +995,8 @@ int malidp_de_planes_init(struct drm_device *drm) */ ret = drm_universal_plane_init(drm, &plane->base, crtcs, &malidp_de_plane_funcs, formats, n, - (id == DE_SMART) ? NULL : modifiers, plane_type, - NULL); + (id == DE_SMART) ? linear_only_modifiers : modifiers, + plane_type, NULL); if (ret < 0) goto cleanup; diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 44fe9f994fc5..dab0a1f0983b 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -9,6 +9,7 @@ #include <linux/of_graph.h> #include <linux/platform_device.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_ioctl.h> @@ -94,9 +95,7 @@ static int armada_drm_bind(struct device *dev) } /* Remove early framebuffers */ - ret = drm_fb_helper_remove_conflicting_framebuffers(NULL, - "armada-drm-fb", - false); + ret = drm_aperture_remove_framebuffers(false, "armada-drm-fb"); if (ret) { dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n", __func__, ret); diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 88121c0e0d05..cd93c44f2662 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -189,6 +189,9 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size) u32 i, data; u32 boot_address; + if (ast->config_mode != ast_use_p2a) + return false; + data = ast_mindwm(ast, 0x1e6e2100) & 0x01; if (data) { boot_address = get_fw_base(ast); @@ -207,6 +210,9 @@ static bool ast_launch_m68k(struct drm_device *dev) u8 *fw_addr = NULL; u8 jreg; + if (ast->config_mode != ast_use_p2a) + return false; + data = ast_mindwm(ast, 0x1e6e2100) & 0x01; if (!data) { @@ -271,25 +277,55 @@ u8 ast_get_dp501_max_clk(struct drm_device *dev) struct ast_private *ast = to_ast_private(dev); u32 boot_address, offset, data; u8 linkcap[4], linkrate, linklanes, maxclk = 0xff; + u32 *plinkcap; - boot_address = get_fw_base(ast); - - /* validate FW version */ - offset = 0xf000; - data = ast_mindwm(ast, boot_address + offset); - if ((data & 0xf0) != 0x10) /* version: 1x */ - return maxclk; - - /* Read Link Capability */ - offset = 0xf014; - *(u32 *)linkcap = ast_mindwm(ast, boot_address + offset); - if (linkcap[2] == 0) { - linkrate = linkcap[0]; - linklanes = linkcap[1]; - data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes); - if (data > 0xff) - data = 0xff; - maxclk = (u8)data; + if (ast->config_mode == ast_use_p2a) { + boot_address = get_fw_base(ast); + + /* validate FW version */ + offset = AST_DP501_GBL_VERSION; + data = ast_mindwm(ast, boot_address + offset); + if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1) /* version: 1x */ + return maxclk; + + /* Read Link Capability */ + offset = AST_DP501_LINKRATE; + plinkcap = (u32 *)linkcap; + *plinkcap = ast_mindwm(ast, boot_address + offset); + if (linkcap[2] == 0) { + linkrate = linkcap[0]; + linklanes = linkcap[1]; + data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes); + if (data > 0xff) + data = 0xff; + maxclk = (u8)data; + } + } else { + if (!ast->dp501_fw_buf) + return AST_DP501_DEFAULT_DCLK; /* 1024x768 as default */ + + /* dummy read */ + offset = 0x0000; + data = readl(ast->dp501_fw_buf + offset); + + /* validate FW version */ + offset = AST_DP501_GBL_VERSION; + data = readl(ast->dp501_fw_buf + offset); + if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1) /* version: 1x */ + return maxclk; + + /* Read Link Capability */ + offset = AST_DP501_LINKRATE; + plinkcap = (u32 *)linkcap; + *plinkcap = readl(ast->dp501_fw_buf + offset); + if (linkcap[2] == 0) { + linkrate = linkcap[0]; + linklanes = linkcap[1]; + data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes); + if (data > 0xff) + data = 0xff; + maxclk = (u8)data; + } } return maxclk; } @@ -298,26 +334,57 @@ bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) { struct ast_private *ast = to_ast_private(dev); u32 i, boot_address, offset, data; + u32 *pEDIDidx; - boot_address = get_fw_base(ast); - - /* validate FW version */ - offset = 0xf000; - data = ast_mindwm(ast, boot_address + offset); - if ((data & 0xf0) != 0x10) - return false; - - /* validate PnP Monitor */ - offset = 0xf010; - data = ast_mindwm(ast, boot_address + offset); - if (!(data & 0x01)) - return false; + if (ast->config_mode == ast_use_p2a) { + boot_address = get_fw_base(ast); - /* Read EDID */ - offset = 0xf020; - for (i = 0; i < 128; i += 4) { - data = ast_mindwm(ast, boot_address + offset + i); - *(u32 *)(ediddata + i) = data; + /* validate FW version */ + offset = AST_DP501_GBL_VERSION; + data = ast_mindwm(ast, boot_address + offset); + if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1) + return false; + + /* validate PnP Monitor */ + offset = AST_DP501_PNPMONITOR; + data = ast_mindwm(ast, boot_address + offset); + if (!(data & AST_DP501_PNP_CONNECTED)) + return false; + + /* Read EDID */ + offset = AST_DP501_EDID_DATA; + for (i = 0; i < 128; i += 4) { + data = ast_mindwm(ast, boot_address + offset + i); + pEDIDidx = (u32 *)(ediddata + i); + *pEDIDidx = data; + } + } else { + if (!ast->dp501_fw_buf) + return false; + + /* dummy read */ + offset = 0x0000; + data = readl(ast->dp501_fw_buf + offset); + + /* validate FW version */ + offset = AST_DP501_GBL_VERSION; + data = readl(ast->dp501_fw_buf + offset); + if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1) + return false; + + /* validate PnP Monitor */ + offset = AST_DP501_PNPMONITOR; + data = readl(ast->dp501_fw_buf + offset); + if (!(data & AST_DP501_PNP_CONNECTED)) + return false; + + /* Read EDID */ + offset = AST_DP501_EDID_DATA; + for (i = 0; i < 128; i += 4) { + data = readl(ast->dp501_fw_buf + offset + i); + pEDIDidx = (u32 *)(ediddata + i); + *pEDIDidx = data; + } } return true; diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 01837bea18c2..5aa452b4efe6 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -30,10 +30,10 @@ #include <linux/module.h> #include <linux/pci.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_gem_vram_helper.h> #include <drm/drm_probe_helper.h> @@ -89,23 +89,18 @@ static const struct pci_device_id ast_pciidlist[] = { MODULE_DEVICE_TABLE(pci, ast_pciidlist); -static void ast_kick_out_firmware_fb(struct pci_dev *pdev) +static int ast_remove_conflicting_framebuffers(struct pci_dev *pdev) { - struct apertures_struct *ap; bool primary = false; + resource_size_t base, size; - ap = alloc_apertures(1); - if (!ap) - return; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - + base = pci_resource_start(pdev, 0); + size = pci_resource_len(pdev, 0); #ifdef CONFIG_X86 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; #endif - drm_fb_helper_remove_conflicting_framebuffers(ap, "astdrmfb", primary); - kfree(ap); + + return drm_aperture_remove_conflicting_framebuffers(base, size, primary, "astdrmfb"); } static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -114,7 +109,9 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *dev; int ret; - ast_kick_out_firmware_fb(pdev); + ret = ast_remove_conflicting_framebuffers(pdev); + if (ret) + return ret; ret = pcim_enable_device(pdev); if (ret) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index e82ab8628770..911f9f414774 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -150,6 +150,7 @@ struct ast_private { void __iomem *regs; void __iomem *ioregs; + void __iomem *dp501_fw_buf; enum ast_chip chip; bool vga2_clone; @@ -325,6 +326,17 @@ int ast_mode_config_init(struct ast_private *ast); #define AST_MM_ALIGN_SHIFT 4 #define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1) +#define AST_DP501_FW_VERSION_MASK GENMASK(7, 4) +#define AST_DP501_FW_VERSION_1 BIT(4) +#define AST_DP501_PNP_CONNECTED BIT(1) + +#define AST_DP501_DEFAULT_DCLK 65 + +#define AST_DP501_GBL_VERSION 0xf000 +#define AST_DP501_PNPMONITOR 0xf010 +#define AST_DP501_LINKRATE 0xf014 +#define AST_DP501_EDID_DATA 0xf020 + int ast_mm_init(struct ast_private *ast); /* ast post */ diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 0ac3c2039c4b..2aff2e6cf450 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -99,7 +99,7 @@ static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev) if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { /* Double check it's actually working */ data = ast_read32(ast, 0xf004); - if (data != 0xFFFFFFFF) { + if ((data != 0xFFFFFFFF) && (data != 0x00)) { /* P2A works, grab silicon revision */ ast->config_mode = ast_use_p2a; @@ -413,7 +413,7 @@ struct ast_private *ast_device_create(const struct drm_driver *drv, pci_set_drvdata(pdev, dev); - ast->regs = pci_iomap(pdev, 1, 0); + ast->regs = pcim_iomap(pdev, 1, 0); if (!ast->regs) return ERR_PTR(-EIO); @@ -429,7 +429,7 @@ struct ast_private *ast_device_create(const struct drm_driver *drv, /* "map" IO regs if the above hasn't done so already */ if (!ast->ioregs) { - ast->ioregs = pci_iomap(pdev, 2, 0); + ast->ioregs = pcim_iomap(pdev, 2, 0); if (!ast->ioregs) return ERR_PTR(-EIO); } @@ -450,6 +450,14 @@ struct ast_private *ast_device_create(const struct drm_driver *drv, if (ret) return ERR_PTR(ret); + /* map reserved buffer */ + ast->dp501_fw_buf = NULL; + if (dev->vram_mm->vram_size < pci_resource_len(pdev, 0)) { + ast->dp501_fw_buf = pci_iomap_range(pdev, 0, dev->vram_mm->vram_size, 0); + if (!ast->dp501_fw_buf) + drm_info(dev, "failed to map reserved buffer!\n"); + } + ret = ast_mode_config_init(ast); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index e5bd1d517a18..e9645c612aff 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h @@ -78,6 +78,7 @@ struct bochs_device { int bochs_hw_init(struct drm_device *dev); void bochs_hw_fini(struct drm_device *dev); +void bochs_hw_blank(struct bochs_device *bochs, bool blank); void bochs_hw_setmode(struct bochs_device *bochs, struct drm_display_mode *mode); void bochs_hw_setformat(struct bochs_device *bochs, diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index b469624fe40d..c828cadbabff 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -6,6 +6,7 @@ #include <linux/pci.h> #include <drm/drm_drv.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_managed.h> @@ -109,7 +110,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c index 2d7380a9890e..7d3426d8cc69 100644 --- a/drivers/gpu/drm/bochs/bochs_hw.c +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -7,6 +7,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fourcc.h> +#include <video/vga.h> #include "bochs.h" /* ---------------------------------------------------------------------- */ @@ -24,6 +25,19 @@ static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val) } } +static u8 bochs_vga_readb(struct bochs_device *bochs, u16 ioport) +{ + if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df)) + return 0xff; + + if (bochs->mmio) { + int offset = ioport - 0x3c0 + 0x400; + return readb(bochs->mmio + offset); + } else { + return inb(ioport); + } +} + static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg) { u16 ret = 0; @@ -205,6 +219,15 @@ void bochs_hw_fini(struct drm_device *dev) kfree(bochs->edid); } +void bochs_hw_blank(struct bochs_device *bochs, bool blank) +{ + DRM_DEBUG_DRIVER("hw_blank %d\n", blank); + /* discard ar_flip_flop */ + (void)bochs_vga_readb(bochs, VGA_IS1_RC); + /* blank or unblank; we need only update index and set 0x20 */ + bochs_vga_writeb(bochs, VGA_ATT_W, blank ? 0 : 0x20); +} + void bochs_hw_setmode(struct bochs_device *bochs, struct drm_display_mode *mode) { @@ -223,7 +246,7 @@ void bochs_hw_setmode(struct bochs_device *bochs, bochs->xres, bochs->yres, bochs->bpp, bochs->yres_virtual); - bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ + bochs_hw_blank(bochs, false); bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 0); bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 853081d186d5..99410e77d51a 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -57,6 +57,13 @@ static void bochs_pipe_enable(struct drm_simple_display_pipe *pipe, bochs_plane_update(bochs, plane_state); } +static void bochs_pipe_disable(struct drm_simple_display_pipe *pipe) +{ + struct bochs_device *bochs = pipe->crtc.dev->dev_private; + + bochs_hw_blank(bochs, true); +} + static void bochs_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { @@ -67,6 +74,7 @@ static void bochs_pipe_update(struct drm_simple_display_pipe *pipe, static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = { .enable = bochs_pipe_enable, + .disable = bochs_pipe_disable, .update = bochs_pipe_update, .prepare_fb = drm_gem_vram_simple_display_pipe_prepare_fb, .cleanup_fb = drm_gem_vram_simple_display_pipe_cleanup_fb, diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 22a467abd3e9..d25e900f07ef 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -66,7 +66,9 @@ config DRM_LONTIUM_LT8912B depends on OF select DRM_PANEL_BRIDGE select DRM_KMS_HELPER + select DRM_MIPI_DSI select REGMAP_I2C + select VIDEOMODE_HELPERS help Driver for Lontium LT8912B DSI to HDMI bridge chip driver. @@ -81,6 +83,7 @@ config DRM_LONTIUM_LT9611 depends on OF select DRM_PANEL_BRIDGE select DRM_KMS_HELPER + select DRM_MIPI_DSI select REGMAP_I2C help Driver for Lontium LT9611 DSI to HDMI bridge @@ -94,6 +97,7 @@ config DRM_LONTIUM_LT9611UXC depends on OF select DRM_PANEL_BRIDGE select DRM_KMS_HELPER + select DRM_MIPI_DSI select REGMAP_I2C help Driver for Lontium LT9611UXC DSI to HDMI bridge @@ -101,6 +105,14 @@ config DRM_LONTIUM_LT9611UXC HDMI signals Please say Y if you have such hardware. +config DRM_ITE_IT66121 + tristate "ITE IT66121 HDMI bridge" + depends on OF + select DRM_KMS_HELPER + select REGMAP_I2C + help + Support for ITE IT66121 HDMI bridge. + config DRM_LVDS_CODEC tristate "Transparent LVDS encoders and decoders support" depends on OF @@ -169,7 +181,7 @@ config DRM_SIL_SII8620 tristate "Silicon Image SII8620 HDMI/MHL bridge" depends on OF select DRM_KMS_HELPER - imply EXTCON + select EXTCON depends on RC_CORE || !RC_CORE help Silicon Image SII8620 HDMI/MHL bridge chip driver. @@ -267,6 +279,7 @@ config DRM_TI_SN65DSI86 select REGMAP_I2C select DRM_PANEL select DRM_MIPI_DSI + select AUXILIARY_BUS help Texas Instruments SN65DSI86 DSI to eDP Bridge driver diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 5c61b50c1663..965b54dccfe5 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-dsi.o +obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o obj-y += analogix/ obj-y += cadence/ diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index a9bb734366ae..05e3abb5a0c9 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -191,6 +191,7 @@ #define ADV7511_I2S_FORMAT_I2S 0 #define ADV7511_I2S_FORMAT_RIGHT_J 1 #define ADV7511_I2S_FORMAT_LEFT_J 2 +#define ADV7511_I2S_IEC958_DIRECT 3 #define ADV7511_PACKET(p, x) ((p) * 0x20 + (x)) #define ADV7511_PACKET_SDP(x) ADV7511_PACKET(0, x) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c index 45838bd08d37..61f4a38e7d2b 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c @@ -101,6 +101,10 @@ static int adv7511_hdmi_hw_params(struct device *dev, void *data, case 20: len = ADV7511_I2S_SAMPLE_LEN_20; break; + case 32: + if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) + return -EINVAL; + fallthrough; case 24: len = ADV7511_I2S_SAMPLE_LEN_24; break; @@ -112,6 +116,8 @@ static int adv7511_hdmi_hw_params(struct device *dev, void *data, case HDMI_I2S: audio_source = ADV7511_AUDIO_SOURCE_I2S; i2s_format = ADV7511_I2S_FORMAT_I2S; + if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) + i2s_format = ADV7511_I2S_IEC958_DIRECT; break; case HDMI_RIGHT_J: audio_source = ADV7511_AUDIO_SOURCE_I2S; diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig index 024ea2a570e7..2ef6eb2b786c 100644 --- a/drivers/gpu/drm/bridge/analogix/Kconfig +++ b/drivers/gpu/drm/bridge/analogix/Kconfig @@ -6,7 +6,7 @@ config DRM_ANALOGIX_ANX6345 select DRM_KMS_HELPER select REGMAP_I2C help - ANX6345 is an ultra-low Full-HD DisplayPort/eDP + ANX6345 is an ultra-low power Full-HD DisplayPort/eDP transmitter designed for portable devices. The ANX6345 transforms the LVTTL RGB output of an application processor to eDP or DisplayPort. @@ -30,6 +30,7 @@ config DRM_ANALOGIX_ANX7625 tristate "Analogix Anx7625 MIPI to DP interface support" depends on DRM depends on OF + select DRM_MIPI_DSI help ANX7625 is an ultra-low power 4K mobile HD transmitter designed for portable devices. It converts MIPI/DPI to diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index aa6cda458eb9..e33cd077595a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -537,6 +537,7 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, /* Register aux channel */ anx6345->aux.name = "DP-AUX"; anx6345->aux.dev = &anx6345->client->dev; + anx6345->aux.drm_dev = bridge->dev; anx6345->aux.transfer = anx6345_aux_transfer; err = drm_dp_aux_register(&anx6345->aux); diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index f20558618220..5e6a0ed39199 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -905,6 +905,7 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge, /* Register aux channel */ anx78xx->aux.name = "DP-AUX"; anx78xx->aux.dev = &anx78xx->client->dev; + anx78xx->aux.drm_dev = bridge->dev; anx78xx->aux.transfer = anx78xx_aux_transfer; err = drm_dp_aux_register(&anx78xx->aux); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index f115233b1cb9..550814ca2139 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1765,6 +1765,7 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) dp->aux.name = "DP-AUX"; dp->aux.transfer = analogix_dpaux_transfer; dp->aux.dev = dp->dev; + dp->aux.drm_dev = drm_dev; ret = drm_dp_aux_register(&dp->aux); if (ret) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 23283ba0c4f9..b4e349ca38fe 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -893,7 +893,7 @@ static void anx7625_power_on(struct anx7625_data *ctx) usleep_range(2000, 2100); } - usleep_range(4000, 4100); + usleep_range(11000, 12000); /* Power on pin enable */ gpiod_set_value(ctx->pdata.gpio_p_on, 1); diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile index 8f647991b374..4d2db8df1bc6 100644 --- a/drivers/gpu/drm/bridge/cadence/Makefile +++ b/drivers/gpu/drm/bridge/cadence/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o -cdns-mhdp8546-y := cdns-mhdp8546-core.o +cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 989a05bc8197..0cd8f40fb690 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -42,6 +42,7 @@ #include <drm/drm_connector.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_dp_helper.h> +#include <drm/drm_hdcp.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -49,7 +50,7 @@ #include <asm/unaligned.h> #include "cdns-mhdp8546-core.h" - +#include "cdns-mhdp8546-hdcp.h" #include "cdns-mhdp8546-j721e.h" static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) @@ -1614,10 +1615,51 @@ enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn, return MODE_OK; } +static int cdns_mhdp_connector_atomic_check(struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn); + struct drm_connector_state *old_state, *new_state; + struct drm_crtc_state *crtc_state; + u64 old_cp, new_cp; + + if (!mhdp->hdcp_supported) + return 0; + + old_state = drm_atomic_get_old_connector_state(state, conn); + new_state = drm_atomic_get_new_connector_state(state, conn); + old_cp = old_state->content_protection; + new_cp = new_state->content_protection; + + if (old_state->hdcp_content_type != new_state->hdcp_content_type && + new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + goto mode_changed; + } + + if (!new_state->crtc) { + if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + return 0; + } + + if (old_cp == new_cp || + (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED && + new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)) + return 0; + +mode_changed: + crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); + crtc_state->mode_changed = true; + + return 0; +} + static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = { .detect_ctx = cdns_mhdp_connector_detect, .get_modes = cdns_mhdp_get_modes, .mode_valid = cdns_mhdp_mode_valid, + .atomic_check = cdns_mhdp_connector_atomic_check, }; static const struct drm_connector_funcs cdns_mhdp_conn_funcs = { @@ -1662,7 +1704,10 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) return ret; } - return 0; + if (mhdp->hdcp_supported) + ret = drm_connector_attach_content_protection_property(conn, true); + + return ret; } static int cdns_mhdp_attach(struct drm_bridge *bridge, @@ -1674,10 +1719,15 @@ static int cdns_mhdp_attach(struct drm_bridge *bridge, dev_dbg(mhdp->dev, "%s\n", __func__); + mhdp->aux.drm_dev = bridge->dev; + ret = drm_dp_aux_register(&mhdp->aux); + if (ret < 0) + return ret; + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ret = cdns_mhdp_connector_init(mhdp); if (ret) - return ret; + goto aux_unregister; } spin_lock(&mhdp->start_lock); @@ -1693,6 +1743,9 @@ static int cdns_mhdp_attach(struct drm_bridge *bridge, mhdp->regs + CDNS_APB_INT_MASK); return 0; +aux_unregister: + drm_dp_aux_unregister(&mhdp->aux); + return ret; } static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, @@ -1957,6 +2010,15 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, if (WARN_ON(!conn_state)) goto out; + if (mhdp->hdcp_supported && + mhdp->hw_state == MHDP_HW_READY && + conn_state->content_protection == + DRM_MODE_CONTENT_PROTECTION_DESIRED) { + mutex_unlock(&mhdp->link_mutex); + cdns_mhdp_hdcp_enable(mhdp, conn_state->hdcp_content_type); + mutex_lock(&mhdp->link_mutex); + } + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); if (WARN_ON(!crtc_state)) goto out; @@ -2000,6 +2062,9 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, mutex_lock(&mhdp->link_mutex); + if (mhdp->hdcp_supported) + cdns_mhdp_hdcp_disable(mhdp); + mhdp->bridge_enabled = false; cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp); resp &= ~CDNS_DP_FRAMER_EN; @@ -2025,6 +2090,8 @@ static void cdns_mhdp_detach(struct drm_bridge *bridge) dev_dbg(mhdp->dev, "%s\n", __func__); + drm_dp_aux_unregister(&mhdp->aux); + spin_lock(&mhdp->start_lock); mhdp->bridge_attached = false; @@ -2288,7 +2355,6 @@ static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data) struct cdns_mhdp_device *mhdp = data; u32 apb_stat, sw_ev0; bool bridge_attached; - int ret; apb_stat = readl(mhdp->regs + CDNS_APB_INT_STATUS); if (!(apb_stat & CDNS_APB_INT_MASK_SW_EVENT_INT)) @@ -2307,20 +2373,54 @@ static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data) spin_unlock(&mhdp->start_lock); if (bridge_attached && (sw_ev0 & CDNS_DPTX_HPD)) { - ret = cdns_mhdp_update_link_status(mhdp); - if (mhdp->connector.dev) { - if (ret < 0) - schedule_work(&mhdp->modeset_retry_work); - else - drm_kms_helper_hotplug_event(mhdp->bridge.dev); - } else { - drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); - } + schedule_work(&mhdp->hpd_work); + } + + if (sw_ev0 & ~CDNS_DPTX_HPD) { + mhdp->sw_events |= (sw_ev0 & ~CDNS_DPTX_HPD); + wake_up(&mhdp->sw_events_wq); } return IRQ_HANDLED; } +u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, u32 event) +{ + u32 ret; + + ret = wait_event_timeout(mhdp->sw_events_wq, + mhdp->sw_events & event, + msecs_to_jiffies(500)); + if (!ret) { + dev_dbg(mhdp->dev, "SW event 0x%x timeout\n", event); + goto sw_event_out; + } + + ret = mhdp->sw_events; + mhdp->sw_events &= ~event; + +sw_event_out: + return ret; +} + +static void cdns_mhdp_hpd_work(struct work_struct *work) +{ + struct cdns_mhdp_device *mhdp = container_of(work, + struct cdns_mhdp_device, + hpd_work); + int ret; + + ret = cdns_mhdp_update_link_status(mhdp); + if (mhdp->connector.dev) { + if (ret < 0) + schedule_work(&mhdp->modeset_retry_work); + else + drm_kms_helper_hotplug_event(mhdp->bridge.dev); + } else { + drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); + } +} + static int cdns_mhdp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2356,6 +2456,15 @@ static int cdns_mhdp_probe(struct platform_device *pdev) return PTR_ERR(mhdp->regs); } + mhdp->sapb_regs = devm_platform_ioremap_resource_byname(pdev, "mhdptx-sapb"); + if (IS_ERR(mhdp->sapb_regs)) { + mhdp->hdcp_supported = false; + dev_warn(dev, + "Failed to get SAPB memory resource, HDCP not supported\n"); + } else { + mhdp->hdcp_supported = true; + } + mhdp->phy = devm_of_phy_get_by_index(dev, pdev->dev.of_node, 0); if (IS_ERR(mhdp->phy)) { dev_err(dev, "no PHY configured\n"); @@ -2430,13 +2539,18 @@ static int cdns_mhdp_probe(struct platform_device *pdev) /* Initialize the work for modeset in case of link train failure */ INIT_WORK(&mhdp->modeset_retry_work, cdns_mhdp_modeset_retry_fn); + INIT_WORK(&mhdp->hpd_work, cdns_mhdp_hpd_work); init_waitqueue_head(&mhdp->fw_load_wq); + init_waitqueue_head(&mhdp->sw_events_wq); ret = cdns_mhdp_load_firmware(mhdp); if (ret) goto phy_exit; + if (mhdp->hdcp_supported) + cdns_mhdp_hdcp_init(mhdp); + drm_bridge_add(&mhdp->bridge); return 0; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h index 5897a85e3159..c74439d0b1a7 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h @@ -47,6 +47,10 @@ struct phy; #define CDNS_SW_EVENT0 0x00044 #define CDNS_DPTX_HPD BIT(0) +#define CDNS_HDCP_TX_STATUS BIT(4) +#define CDNS_HDCP2_TX_IS_KM_STORED BIT(5) +#define CDNS_HDCP2_TX_STORE_KM BIT(6) +#define CDNS_HDCP_TX_IS_RCVR_ID_VALID BIT(7) #define CDNS_SW_EVENT1 0x00048 #define CDNS_SW_EVENT2 0x0004c @@ -339,8 +343,17 @@ struct cdns_mhdp_platform_info { #define to_cdns_mhdp_bridge_state(s) \ container_of(s, struct cdns_mhdp_bridge_state, base) +struct cdns_mhdp_hdcp { + struct delayed_work check_work; + struct work_struct prop_work; + struct mutex mutex; /* mutex to protect hdcp.value */ + u32 value; + u8 hdcp_content_type; +}; + struct cdns_mhdp_device { void __iomem *regs; + void __iomem *sapb_regs; void __iomem *j721e_regs; struct device *dev; @@ -392,9 +405,18 @@ struct cdns_mhdp_device { /* Work struct to schedule a uevent on link train failure */ struct work_struct modeset_retry_work; + struct work_struct hpd_work; + + wait_queue_head_t sw_events_wq; + u32 sw_events; + + struct cdns_mhdp_hdcp hdcp; + bool hdcp_supported; }; #define connector_to_mhdp(x) container_of(x, struct cdns_mhdp_device, connector) #define bridge_to_mhdp(x) container_of(x, struct cdns_mhdp_device, bridge) +u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, uint32_t event); + #endif diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c new file mode 100644 index 000000000000..fccd6fbcc257 --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence MHDP8546 DP bridge driver. + * + * Copyright (C) 2020 Cadence Design Systems, Inc. + * + */ + +#include <linux/io.h> +#include <linux/iopoll.h> + +#include <asm/unaligned.h> + +#include <drm/drm_hdcp.h> + +#include "cdns-mhdp8546-hdcp.h" + +static int cdns_mhdp_secure_mailbox_read(struct cdns_mhdp_device *mhdp) +{ + int ret, empty; + + WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); + + ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_EMPTY, + empty, !empty, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + return readl(mhdp->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff; +} + +static int cdns_mhdp_secure_mailbox_write(struct cdns_mhdp_device *mhdp, + u8 val) +{ + int ret, full; + + WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); + + ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_FULL, + full, !full, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + writel(val, mhdp->sapb_regs + CDNS_MAILBOX_TX_DATA); + + return 0; +} + +static int cdns_mhdp_secure_mailbox_recv_header(struct cdns_mhdp_device *mhdp, + u8 module_id, + u8 opcode, + u16 req_size) +{ + u32 mbox_size, i; + u8 header[4]; + int ret; + + /* read the header of the message */ + for (i = 0; i < sizeof(header); i++) { + ret = cdns_mhdp_secure_mailbox_read(mhdp); + if (ret < 0) + return ret; + + header[i] = ret; + } + + mbox_size = get_unaligned_be16(header + 2); + + if (opcode != header[0] || module_id != header[1] || + (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) { + for (i = 0; i < mbox_size; i++) + if (cdns_mhdp_secure_mailbox_read(mhdp) < 0) + break; + return -EINVAL; + } + + return 0; +} + +static int cdns_mhdp_secure_mailbox_recv_data(struct cdns_mhdp_device *mhdp, + u8 *buff, u16 buff_size) +{ + int ret; + u32 i; + + for (i = 0; i < buff_size; i++) { + ret = cdns_mhdp_secure_mailbox_read(mhdp); + if (ret < 0) + return ret; + + buff[i] = ret; + } + + return 0; +} + +static int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_device *mhdp, + u8 module_id, + u8 opcode, + u16 size, + u8 *message) +{ + u8 header[4]; + int ret; + u32 i; + + header[0] = opcode; + header[1] = module_id; + put_unaligned_be16(size, header + 2); + + for (i = 0; i < sizeof(header); i++) { + ret = cdns_mhdp_secure_mailbox_write(mhdp, header[i]); + if (ret) + return ret; + } + + for (i = 0; i < size; i++) { + ret = cdns_mhdp_secure_mailbox_write(mhdp, message[i]); + if (ret) + return ret; + } + + return 0; +} + +static int cdns_mhdp_hdcp_get_status(struct cdns_mhdp_device *mhdp, + u16 *hdcp_port_status) +{ + u8 hdcp_status[HDCP_STATUS_SIZE]; + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_STATUS_CHANGE, 0, NULL); + if (ret) + goto err_get_hdcp_status; + + ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_STATUS_CHANGE, + sizeof(hdcp_status)); + if (ret) + goto err_get_hdcp_status; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_status, + sizeof(hdcp_status)); + if (ret) + goto err_get_hdcp_status; + + *hdcp_port_status = ((u16)(hdcp_status[0] << 8) | hdcp_status[1]); + +err_get_hdcp_status: + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static u8 cdns_mhdp_hdcp_handle_status(struct cdns_mhdp_device *mhdp, + u16 status) +{ + u8 err = GET_HDCP_PORT_STS_LAST_ERR(status); + + if (err) + dev_dbg(mhdp->dev, "HDCP Error = %d", err); + + return err; +} + +static int cdns_mhdp_hdcp_rx_id_valid_response(struct cdns_mhdp_device *mhdp, + u8 valid) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_RESPOND_RECEIVER_ID_VALID, + 1, &valid); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_rx_id_valid(struct cdns_mhdp_device *mhdp, + u8 *recv_num, u8 *hdcp_rx_id) +{ + u8 rec_id_hdr[2]; + u8 status; + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_IS_REC_ID_VALID, 0, NULL); + if (ret) + goto err_rx_id_valid; + + ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_IS_REC_ID_VALID, + sizeof(status)); + if (ret) + goto err_rx_id_valid; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, rec_id_hdr, 2); + if (ret) + goto err_rx_id_valid; + + *recv_num = rec_id_hdr[0]; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_rx_id, 5 * *recv_num); + +err_rx_id_valid: + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_km_stored_resp(struct cdns_mhdp_device *mhdp, + u32 size, u8 *km) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_RESPOND_KM, size, km); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_tx_is_km_stored(struct cdns_mhdp_device *mhdp, + u8 *resp, u32 size) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_IS_KM_STORED, 0, NULL); + if (ret) + goto err_is_km_stored; + + ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_IS_KM_STORED, + size); + if (ret) + goto err_is_km_stored; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, resp, size); +err_is_km_stored: + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp, + u8 hdcp_cfg) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_CONFIGURATION, 1, &hdcp_cfg); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_set_config(struct cdns_mhdp_device *mhdp, + u8 hdcp_config, bool enable) +{ + u16 hdcp_port_status; + u32 ret_event; + u8 hdcp_cfg; + int ret; + + hdcp_cfg = hdcp_config | (enable ? 0x04 : 0) | + (HDCP_CONTENT_TYPE_0 << 3); + cdns_mhdp_hdcp_tx_config(mhdp, hdcp_cfg); + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS); + if (!ret_event) + return -1; + + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) + return -1; + + return 0; +} + +static int cdns_mhdp_hdcp_auth_check(struct cdns_mhdp_device *mhdp) +{ + u16 hdcp_port_status; + u32 ret_event; + int ret; + + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS); + if (!ret_event) + return -1; + + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) + return -1; + + if (hdcp_port_status & 1) { + dev_dbg(mhdp->dev, "Authentication completed successfully!\n"); + return 0; + } + + dev_dbg(mhdp->dev, "Authentication failed\n"); + + return -1; +} + +static int cdns_mhdp_hdcp_check_receviers(struct cdns_mhdp_device *mhdp) +{ + u8 hdcp_rec_id[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES]; + u8 hdcp_num_rec; + u32 ret_event; + + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, + CDNS_HDCP_TX_IS_RCVR_ID_VALID); + if (!ret_event) + return -1; + + hdcp_num_rec = 0; + memset(&hdcp_rec_id, 0, sizeof(hdcp_rec_id)); + cdns_mhdp_hdcp_rx_id_valid(mhdp, &hdcp_num_rec, (u8 *)hdcp_rec_id); + cdns_mhdp_hdcp_rx_id_valid_response(mhdp, 1); + + return 0; +} + +static int cdns_mhdp_hdcp_auth_22(struct cdns_mhdp_device *mhdp) +{ + u8 resp[HDCP_STATUS_SIZE]; + u16 hdcp_port_status; + u32 ret_event; + int ret; + + dev_dbg(mhdp->dev, "HDCP: Start 2.2 Authentication\n"); + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, + CDNS_HDCP2_TX_IS_KM_STORED); + if (!ret_event) + return -1; + + if (ret_event & CDNS_HDCP_TX_STATUS) { + mhdp->sw_events &= ~CDNS_HDCP_TX_STATUS; + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) + return -1; + } + + cdns_mhdp_hdcp_tx_is_km_stored(mhdp, resp, sizeof(resp)); + cdns_mhdp_hdcp_km_stored_resp(mhdp, 0, NULL); + + if (cdns_mhdp_hdcp_check_receviers(mhdp)) + return -1; + + return 0; +} + +static inline int cdns_mhdp_hdcp_auth_14(struct cdns_mhdp_device *mhdp) +{ + dev_dbg(mhdp->dev, "HDCP: Starting 1.4 Authentication\n"); + return cdns_mhdp_hdcp_check_receviers(mhdp); +} + +static int cdns_mhdp_hdcp_auth(struct cdns_mhdp_device *mhdp, + u8 hdcp_config) +{ + int ret; + + ret = cdns_mhdp_hdcp_set_config(mhdp, hdcp_config, true); + if (ret) + goto auth_failed; + + if (hdcp_config == HDCP_TX_1) + ret = cdns_mhdp_hdcp_auth_14(mhdp); + else + ret = cdns_mhdp_hdcp_auth_22(mhdp); + + if (ret) + goto auth_failed; + + ret = cdns_mhdp_hdcp_auth_check(mhdp); + if (ret) + ret = cdns_mhdp_hdcp_auth_check(mhdp); + +auth_failed: + return ret; +} + +static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) +{ + int ret; + + dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", + mhdp->connector.name, mhdp->connector.base.id); + + ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); + + return ret; +} + +static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) +{ + int ret, tries = 3; + u32 i; + + for (i = 0; i < tries; i++) { + if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0 || + content_type == DRM_MODE_HDCP_CONTENT_TYPE1) { + ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_2); + if (!ret) + return 0; + _cdns_mhdp_hdcp_disable(mhdp); + } + + if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) { + ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_1); + if (!ret) + return 0; + _cdns_mhdp_hdcp_disable(mhdp); + } + } + + dev_err(mhdp->dev, "HDCP authentication failed (%d tries/%d)\n", + tries, ret); + + return ret; +} + +static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) +{ + u16 hdcp_port_status; + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (!ret && hdcp_port_status & HDCP_PORT_STS_AUTH) + goto out; + + dev_err(mhdp->dev, + "[%s:%d] HDCP link failed, retrying authentication\n", + mhdp->connector.name, mhdp->connector.base.id); + + ret = _cdns_mhdp_hdcp_disable(mhdp); + if (ret) { + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&mhdp->hdcp.prop_work); + goto out; + } + + ret = _cdns_mhdp_hdcp_enable(mhdp, mhdp->hdcp.hdcp_content_type); + if (ret) { + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&mhdp->hdcp.prop_work); + } +out: + mutex_unlock(&mhdp->hdcp.mutex); + return ret; +} + +static void cdns_mhdp_hdcp_check_work(struct work_struct *work) +{ + struct delayed_work *d_work = to_delayed_work(work); + struct cdns_mhdp_hdcp *hdcp = container_of(d_work, + struct cdns_mhdp_hdcp, + check_work); + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); + + if (!cdns_mhdp_hdcp_check_link(mhdp)) + schedule_delayed_work(&hdcp->check_work, + DRM_HDCP_CHECK_PERIOD_MS); +} + +static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) +{ + struct cdns_mhdp_hdcp *hdcp = container_of(work, + struct cdns_mhdp_hdcp, + prop_work); + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); + struct drm_device *dev = mhdp->connector.dev; + struct drm_connector_state *state; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + state = mhdp->connector.state; + state->content_protection = mhdp->hdcp.value; + } + mutex_unlock(&mhdp->hdcp.mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); +} + +int cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_GENERAL, + HDCP_GENERAL_SET_LC_128, + 16, val); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +int +cdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp, + struct cdns_hdcp_tx_public_key_param *val) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_SET_PUBLIC_KEY_PARAMS, + sizeof(*val), (u8 *)val); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +int cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) +{ + int ret; + + mutex_lock(&mhdp->hdcp.mutex); + ret = _cdns_mhdp_hdcp_enable(mhdp, content_type); + if (ret) + goto out; + + mhdp->hdcp.hdcp_content_type = content_type; + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_ENABLED; + schedule_work(&mhdp->hdcp.prop_work); + schedule_delayed_work(&mhdp->hdcp.check_work, + DRM_HDCP_CHECK_PERIOD_MS); +out: + mutex_unlock(&mhdp->hdcp.mutex); + return ret; +} + +int cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) +{ + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + schedule_work(&mhdp->hdcp.prop_work); + ret = _cdns_mhdp_hdcp_disable(mhdp); + } + mutex_unlock(&mhdp->hdcp.mutex); + cancel_delayed_work_sync(&mhdp->hdcp.check_work); + + return ret; +} + +void cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp) +{ + INIT_DELAYED_WORK(&mhdp->hdcp.check_work, cdns_mhdp_hdcp_check_work); + INIT_WORK(&mhdp->hdcp.prop_work, cdns_mhdp_hdcp_prop_work); + mutex_init(&mhdp->hdcp.mutex); +} diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h new file mode 100644 index 000000000000..334c0b8b0d4f --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence MHDP8546 DP bridge driver. + * + * Copyright (C) 2020 Cadence Design Systems, Inc. + * + */ + +#ifndef CDNS_MHDP8546_HDCP_H +#define CDNS_MHDP8546_HDCP_H + +#include "cdns-mhdp8546-core.h" + +#define HDCP_MAX_RECEIVERS 32 +#define HDCP_RECEIVER_ID_SIZE_BYTES 5 +#define HDCP_STATUS_SIZE 0x5 +#define HDCP_PORT_STS_AUTH 0x1 +#define HDCP_PORT_STS_LAST_ERR_SHIFT 0x5 +#define HDCP_PORT_STS_LAST_ERR_MASK (0x0F << 5) +#define GET_HDCP_PORT_STS_LAST_ERR(__sts__) \ + (((__sts__) & HDCP_PORT_STS_LAST_ERR_MASK) >> \ + HDCP_PORT_STS_LAST_ERR_SHIFT) + +#define HDCP_CONFIG_1_4 BIT(0) /* use HDCP 1.4 only */ +#define HDCP_CONFIG_2_2 BIT(1) /* use HDCP 2.2 only */ +/* use All HDCP versions */ +#define HDCP_CONFIG_ALL (BIT(0) | BIT(1)) +#define HDCP_CONFIG_NONE 0 + +enum { + HDCP_GENERAL_SET_LC_128, + HDCP_SET_SEED, +}; + +enum { + HDCP_TRAN_CONFIGURATION, + HDCP2X_TX_SET_PUBLIC_KEY_PARAMS, + HDCP2X_TX_SET_DEBUG_RANDOM_NUMBERS, + HDCP2X_TX_RESPOND_KM, + HDCP1_TX_SEND_KEYS, + HDCP1_TX_SEND_RANDOM_AN, + HDCP_TRAN_STATUS_CHANGE, + HDCP2X_TX_IS_KM_STORED, + HDCP2X_TX_STORE_KM, + HDCP_TRAN_IS_REC_ID_VALID, + HDCP_TRAN_RESPOND_RECEIVER_ID_VALID, + HDCP_TRAN_TEST_KEYS, + HDCP2X_TX_SET_KM_KEY_PARAMS, + HDCP_NUM_OF_SUPPORTED_MESSAGES +}; + +enum { + HDCP_CONTENT_TYPE_0, + HDCP_CONTENT_TYPE_1, +}; + +#define DRM_HDCP_CHECK_PERIOD_MS (128 * 16) + +#define HDCP_PAIRING_R_ID 5 +#define HDCP_PAIRING_M_LEN 16 +#define HDCP_KM_LEN 16 +#define HDCP_PAIRING_M_EKH 16 + +struct cdns_hdcp_pairing_data { + u8 receiver_id[HDCP_PAIRING_R_ID]; + u8 m[HDCP_PAIRING_M_LEN]; + u8 km[HDCP_KM_LEN]; + u8 ekh[HDCP_PAIRING_M_EKH]; +}; + +enum { + HDCP_TX_2, + HDCP_TX_1, + HDCP_TX_BOTH, +}; + +#define DLP_MODULUS_N 384 +#define DLP_E 3 + +struct cdns_hdcp_tx_public_key_param { + u8 N[DLP_MODULUS_N]; + u8 E[DLP_E]; +}; + +int cdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp, + struct cdns_hdcp_tx_public_key_param *val); +int cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val); +int cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type); +int cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp); +void cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp); + +#endif diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c new file mode 100644 index 000000000000..d8a60691fd32 --- /dev/null +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -0,0 +1,1021 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 BayLibre, SAS + * Author: Phong LE <ple@baylibre.com> + * Copyright (C) 2018-2019, Artem Mygaiev + * Copyright (C) 2017, Fresco Logic, Incorporated. + * + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/bitfield.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/of_graph.h> +#include <linux/gpio/consumer.h> +#include <linux/pinctrl/consumer.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modes.h> +#include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> + +#define IT66121_VENDOR_ID0_REG 0x00 +#define IT66121_VENDOR_ID1_REG 0x01 +#define IT66121_DEVICE_ID0_REG 0x02 +#define IT66121_DEVICE_ID1_REG 0x03 + +#define IT66121_VENDOR_ID0 0x54 +#define IT66121_VENDOR_ID1 0x49 +#define IT66121_DEVICE_ID0 0x12 +#define IT66121_DEVICE_ID1 0x06 +#define IT66121_REVISION_MASK GENMASK(7, 4) +#define IT66121_DEVICE_ID1_MASK GENMASK(3, 0) + +#define IT66121_MASTER_SEL_REG 0x10 +#define IT66121_MASTER_SEL_HOST BIT(0) + +#define IT66121_AFE_DRV_REG 0x61 +#define IT66121_AFE_DRV_RST BIT(4) +#define IT66121_AFE_DRV_PWD BIT(5) + +#define IT66121_INPUT_MODE_REG 0x70 +#define IT66121_INPUT_MODE_RGB (0 << 6) +#define IT66121_INPUT_MODE_YUV422 BIT(6) +#define IT66121_INPUT_MODE_YUV444 (2 << 6) +#define IT66121_INPUT_MODE_CCIR656 BIT(4) +#define IT66121_INPUT_MODE_SYNCEMB BIT(3) +#define IT66121_INPUT_MODE_DDR BIT(2) + +#define IT66121_INPUT_CSC_REG 0x72 +#define IT66121_INPUT_CSC_ENDITHER BIT(7) +#define IT66121_INPUT_CSC_ENUDFILTER BIT(6) +#define IT66121_INPUT_CSC_DNFREE_GO BIT(5) +#define IT66121_INPUT_CSC_RGB_TO_YUV 0x02 +#define IT66121_INPUT_CSC_YUV_TO_RGB 0x03 +#define IT66121_INPUT_CSC_NO_CONV 0x00 + +#define IT66121_AFE_XP_REG 0x62 +#define IT66121_AFE_XP_GAINBIT BIT(7) +#define IT66121_AFE_XP_PWDPLL BIT(6) +#define IT66121_AFE_XP_ENI BIT(5) +#define IT66121_AFE_XP_ENO BIT(4) +#define IT66121_AFE_XP_RESETB BIT(3) +#define IT66121_AFE_XP_PWDI BIT(2) + +#define IT66121_AFE_IP_REG 0x64 +#define IT66121_AFE_IP_GAINBIT BIT(7) +#define IT66121_AFE_IP_PWDPLL BIT(6) +#define IT66121_AFE_IP_CKSEL_05 (0 << 4) +#define IT66121_AFE_IP_CKSEL_1 BIT(4) +#define IT66121_AFE_IP_CKSEL_2 (2 << 4) +#define IT66121_AFE_IP_CKSEL_2OR4 (3 << 4) +#define IT66121_AFE_IP_ER0 BIT(3) +#define IT66121_AFE_IP_RESETB BIT(2) +#define IT66121_AFE_IP_ENC BIT(1) +#define IT66121_AFE_IP_EC1 BIT(0) + +#define IT66121_AFE_XP_EC1_REG 0x68 +#define IT66121_AFE_XP_EC1_LOWCLK BIT(4) + +#define IT66121_SW_RST_REG 0x04 +#define IT66121_SW_RST_REF BIT(5) +#define IT66121_SW_RST_AREF BIT(4) +#define IT66121_SW_RST_VID BIT(3) +#define IT66121_SW_RST_AUD BIT(2) +#define IT66121_SW_RST_HDCP BIT(0) + +#define IT66121_DDC_COMMAND_REG 0x15 +#define IT66121_DDC_COMMAND_BURST_READ 0x0 +#define IT66121_DDC_COMMAND_EDID_READ 0x3 +#define IT66121_DDC_COMMAND_FIFO_CLR 0x9 +#define IT66121_DDC_COMMAND_SCL_PULSE 0xA +#define IT66121_DDC_COMMAND_ABORT 0xF + +#define IT66121_HDCP_REG 0x20 +#define IT66121_HDCP_CPDESIRED BIT(0) +#define IT66121_HDCP_EN1P1FEAT BIT(1) + +#define IT66121_INT_STATUS1_REG 0x06 +#define IT66121_INT_STATUS1_AUD_OVF BIT(7) +#define IT66121_INT_STATUS1_DDC_NOACK BIT(5) +#define IT66121_INT_STATUS1_DDC_FIFOERR BIT(4) +#define IT66121_INT_STATUS1_DDC_BUSHANG BIT(2) +#define IT66121_INT_STATUS1_RX_SENS_STATUS BIT(1) +#define IT66121_INT_STATUS1_HPD_STATUS BIT(0) + +#define IT66121_DDC_HEADER_REG 0x11 +#define IT66121_DDC_HEADER_HDCP 0x74 +#define IT66121_DDC_HEADER_EDID 0xA0 + +#define IT66121_DDC_OFFSET_REG 0x12 +#define IT66121_DDC_BYTE_REG 0x13 +#define IT66121_DDC_SEGMENT_REG 0x14 +#define IT66121_DDC_RD_FIFO_REG 0x17 + +#define IT66121_CLK_BANK_REG 0x0F +#define IT66121_CLK_BANK_PWROFF_RCLK BIT(6) +#define IT66121_CLK_BANK_PWROFF_ACLK BIT(5) +#define IT66121_CLK_BANK_PWROFF_TXCLK BIT(4) +#define IT66121_CLK_BANK_PWROFF_CRCLK BIT(3) +#define IT66121_CLK_BANK_0 0 +#define IT66121_CLK_BANK_1 1 + +#define IT66121_INT_REG 0x05 +#define IT66121_INT_ACTIVE_HIGH BIT(7) +#define IT66121_INT_OPEN_DRAIN BIT(6) +#define IT66121_INT_TX_CLK_OFF BIT(0) + +#define IT66121_INT_MASK1_REG 0x09 +#define IT66121_INT_MASK1_AUD_OVF BIT(7) +#define IT66121_INT_MASK1_DDC_NOACK BIT(5) +#define IT66121_INT_MASK1_DDC_FIFOERR BIT(4) +#define IT66121_INT_MASK1_DDC_BUSHANG BIT(2) +#define IT66121_INT_MASK1_RX_SENS BIT(1) +#define IT66121_INT_MASK1_HPD BIT(0) + +#define IT66121_INT_CLR1_REG 0x0C +#define IT66121_INT_CLR1_PKTACP BIT(7) +#define IT66121_INT_CLR1_PKTNULL BIT(6) +#define IT66121_INT_CLR1_PKTGEN BIT(5) +#define IT66121_INT_CLR1_KSVLISTCHK BIT(4) +#define IT66121_INT_CLR1_AUTHDONE BIT(3) +#define IT66121_INT_CLR1_AUTHFAIL BIT(2) +#define IT66121_INT_CLR1_RX_SENS BIT(1) +#define IT66121_INT_CLR1_HPD BIT(0) + +#define IT66121_AV_MUTE_REG 0xC1 +#define IT66121_AV_MUTE_ON BIT(0) +#define IT66121_AV_MUTE_BLUESCR BIT(1) + +#define IT66121_PKT_GEN_CTRL_REG 0xC6 +#define IT66121_PKT_GEN_CTRL_ON BIT(0) +#define IT66121_PKT_GEN_CTRL_RPT BIT(1) + +#define IT66121_AVIINFO_DB1_REG 0x158 +#define IT66121_AVIINFO_DB2_REG 0x159 +#define IT66121_AVIINFO_DB3_REG 0x15A +#define IT66121_AVIINFO_DB4_REG 0x15B +#define IT66121_AVIINFO_DB5_REG 0x15C +#define IT66121_AVIINFO_CSUM_REG 0x15D +#define IT66121_AVIINFO_DB6_REG 0x15E +#define IT66121_AVIINFO_DB7_REG 0x15F +#define IT66121_AVIINFO_DB8_REG 0x160 +#define IT66121_AVIINFO_DB9_REG 0x161 +#define IT66121_AVIINFO_DB10_REG 0x162 +#define IT66121_AVIINFO_DB11_REG 0x163 +#define IT66121_AVIINFO_DB12_REG 0x164 +#define IT66121_AVIINFO_DB13_REG 0x165 + +#define IT66121_AVI_INFO_PKT_REG 0xCD +#define IT66121_AVI_INFO_PKT_ON BIT(0) +#define IT66121_AVI_INFO_PKT_RPT BIT(1) + +#define IT66121_HDMI_MODE_REG 0xC0 +#define IT66121_HDMI_MODE_HDMI BIT(0) + +#define IT66121_SYS_STATUS_REG 0x0E +#define IT66121_SYS_STATUS_ACTIVE_IRQ BIT(7) +#define IT66121_SYS_STATUS_HPDETECT BIT(6) +#define IT66121_SYS_STATUS_SENDECTECT BIT(5) +#define IT66121_SYS_STATUS_VID_STABLE BIT(4) +#define IT66121_SYS_STATUS_AUD_CTS_CLR BIT(1) +#define IT66121_SYS_STATUS_CLEAR_IRQ BIT(0) + +#define IT66121_DDC_STATUS_REG 0x16 +#define IT66121_DDC_STATUS_TX_DONE BIT(7) +#define IT66121_DDC_STATUS_ACTIVE BIT(6) +#define IT66121_DDC_STATUS_NOACK BIT(5) +#define IT66121_DDC_STATUS_WAIT_BUS BIT(4) +#define IT66121_DDC_STATUS_ARBI_LOSE BIT(3) +#define IT66121_DDC_STATUS_FIFO_FULL BIT(2) +#define IT66121_DDC_STATUS_FIFO_EMPTY BIT(1) +#define IT66121_DDC_STATUS_FIFO_VALID BIT(0) + +#define IT66121_EDID_SLEEP_US 20000 +#define IT66121_EDID_TIMEOUT_US 200000 +#define IT66121_EDID_FIFO_SIZE 32 +#define IT66121_AFE_CLK_HIGH 80000 /* Khz */ + +struct it66121_ctx { + struct regmap *regmap; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct drm_connector *connector; + struct device *dev; + struct gpio_desc *gpio_reset; + struct i2c_client *client; + struct regulator_bulk_data supplies[3]; + u32 bus_width; + struct mutex lock; /* Protects fields below and device registers */ + struct hdmi_avi_infoframe hdmi_avi_infoframe; +}; + +static const struct regmap_range_cfg it66121_regmap_banks[] = { + { + .name = "it66121", + .range_min = 0x00, + .range_max = 0x1FF, + .selector_reg = IT66121_CLK_BANK_REG, + .selector_mask = 0x1, + .selector_shift = 0, + .window_start = 0x00, + .window_len = 0x130, + }, +}; + +static const struct regmap_config it66121_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + .max_register = 0x1FF, + .ranges = it66121_regmap_banks, + .num_ranges = ARRAY_SIZE(it66121_regmap_banks), +}; + +static void it66121_hw_reset(struct it66121_ctx *ctx) +{ + gpiod_set_value(ctx->gpio_reset, 1); + msleep(20); + gpiod_set_value(ctx->gpio_reset, 0); +} + +static inline int ite66121_power_on(struct it66121_ctx *ctx) +{ + return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); +} + +static inline int ite66121_power_off(struct it66121_ctx *ctx) +{ + return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); +} + +static inline int it66121_preamble_ddc(struct it66121_ctx *ctx) +{ + return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG, IT66121_MASTER_SEL_HOST); +} + +static inline int it66121_fire_afe(struct it66121_ctx *ctx) +{ + return regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, 0); +} + +/* TOFIX: Handle YCbCr Input & Output */ +static int it66121_configure_input(struct it66121_ctx *ctx) +{ + int ret; + u8 mode = IT66121_INPUT_MODE_RGB; + + if (ctx->bus_width == 12) + mode |= IT66121_INPUT_MODE_DDR; + + ret = regmap_write(ctx->regmap, IT66121_INPUT_MODE_REG, mode); + if (ret) + return ret; + + return regmap_write(ctx->regmap, IT66121_INPUT_CSC_REG, IT66121_INPUT_CSC_NO_CONV); +} + +/** + * it66121_configure_afe() - Configure the analog front end + * @ctx: it66121_ctx object + * @mode: mode to configure + * + * RETURNS: + * zero if success, a negative error code otherwise. + */ +static int it66121_configure_afe(struct it66121_ctx *ctx, + const struct drm_display_mode *mode) +{ + int ret; + + ret = regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, + IT66121_AFE_DRV_RST); + if (ret) + return ret; + + if (mode->clock > IT66121_AFE_CLK_HIGH) { + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, + IT66121_AFE_XP_GAINBIT | + IT66121_AFE_XP_ENO, + IT66121_AFE_XP_GAINBIT); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, + IT66121_AFE_IP_GAINBIT | + IT66121_AFE_IP_ER0 | + IT66121_AFE_IP_EC1, + IT66121_AFE_IP_GAINBIT); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, + IT66121_AFE_XP_EC1_LOWCLK, 0x80); + if (ret) + return ret; + } else { + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, + IT66121_AFE_XP_GAINBIT | + IT66121_AFE_XP_ENO, + IT66121_AFE_XP_ENO); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, + IT66121_AFE_IP_GAINBIT | + IT66121_AFE_IP_ER0 | + IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 | + IT66121_AFE_IP_EC1); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, + IT66121_AFE_XP_EC1_LOWCLK, + IT66121_AFE_XP_EC1_LOWCLK); + if (ret) + return ret; + } + + /* Clear reset flags */ + ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, + IT66121_SW_RST_REF | IT66121_SW_RST_VID, 0); + if (ret) + return ret; + + return it66121_fire_afe(ctx); +} + +static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx) +{ + int ret, val; + u32 busy = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS | + IT66121_DDC_STATUS_ARBI_LOSE; + + ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val, true, + IT66121_EDID_SLEEP_US, IT66121_EDID_TIMEOUT_US); + if (ret) + return ret; + + if (val & busy) + return -EAGAIN; + + return 0; +} + +static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx) +{ + int ret; + + ret = it66121_preamble_ddc(ctx); + if (ret) + return ret; + + return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, + IT66121_DDC_COMMAND_FIFO_CLR); +} + +static int it66121_abort_ddc_ops(struct it66121_ctx *ctx) +{ + int ret; + unsigned int swreset, cpdesire; + + ret = regmap_read(ctx->regmap, IT66121_SW_RST_REG, &swreset); + if (ret) + return ret; + + ret = regmap_read(ctx->regmap, IT66121_HDCP_REG, &cpdesire); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_HDCP_REG, + cpdesire & (~IT66121_HDCP_CPDESIRED & 0xFF)); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_SW_RST_REG, + (swreset | IT66121_SW_RST_HDCP)); + if (ret) + return ret; + + ret = it66121_preamble_ddc(ctx); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, + IT66121_DDC_COMMAND_ABORT); + if (ret) + return ret; + + return it66121_wait_ddc_ready(ctx); +} + +static int it66121_get_edid_block(void *context, u8 *buf, + unsigned int block, size_t len) +{ + struct it66121_ctx *ctx = context; + unsigned int val; + int remain = len; + int offset = 0; + int ret, cnt; + + offset = (block % 2) * len; + block = block / 2; + + ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); + if (ret) + return ret; + + if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { + ret = it66121_abort_ddc_ops(ctx); + if (ret) + return ret; + } + + ret = it66121_clear_ddc_fifo(ctx); + if (ret) + return ret; + + while (remain > 0) { + cnt = (remain > IT66121_EDID_FIFO_SIZE) ? + IT66121_EDID_FIFO_SIZE : remain; + ret = it66121_preamble_ddc(ctx); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, + IT66121_DDC_COMMAND_FIFO_CLR); + if (ret) + return ret; + + ret = it66121_wait_ddc_ready(ctx); + if (ret) + return ret; + + ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); + if (ret) + return ret; + + if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { + ret = it66121_abort_ddc_ops(ctx); + if (ret) + return ret; + } + + ret = it66121_preamble_ddc(ctx); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, + IT66121_DDC_HEADER_EDID); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_BYTE_REG, cnt); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_SEGMENT_REG, block); + if (ret) + return ret; + + ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, + IT66121_DDC_COMMAND_EDID_READ); + if (ret) + return ret; + + offset += cnt; + remain -= cnt; + + /* Per programming manual, sleep here before emptying the FIFO */ + msleep(20); + + ret = it66121_wait_ddc_ready(ctx); + if (ret) + return ret; + + do { + ret = regmap_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG, &val); + if (ret) + return ret; + *(buf++) = val; + cnt--; + } while (cnt > 0); + } + + return 0; +} + +static bool it66121_is_hpd_detect(struct it66121_ctx *ctx) +{ + int val; + + if (regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val)) + return false; + + return val & IT66121_SYS_STATUS_HPDETECT; +} + +static int it66121_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + int ret; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + ret = drm_bridge_attach(bridge->encoder, ctx->next_bridge, bridge, flags); + + ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, + IT66121_CLK_BANK_PWROFF_RCLK, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG, + IT66121_INT_TX_CLK_OFF, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG, + IT66121_AFE_DRV_PWD, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, + IT66121_AFE_XP_PWDI | IT66121_AFE_XP_PWDPLL, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, + IT66121_AFE_IP_PWDPLL, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG, + IT66121_AFE_DRV_RST, 0); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, + IT66121_AFE_XP_RESETB, IT66121_AFE_XP_RESETB); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, + IT66121_AFE_IP_RESETB, IT66121_AFE_IP_RESETB); + if (ret) + return ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, + IT66121_SW_RST_REF, + IT66121_SW_RST_REF); + if (ret) + return ret; + + /* Per programming manual, sleep here for bridge to settle */ + msleep(50); + + /* Start interrupts */ + return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, + IT66121_INT_MASK1_DDC_NOACK | + IT66121_INT_MASK1_DDC_FIFOERR | + IT66121_INT_MASK1_DDC_BUSHANG, 0); +} + +static int it66121_set_mute(struct it66121_ctx *ctx, bool mute) +{ + int ret; + unsigned int val = 0; + + if (mute) + val = IT66121_AV_MUTE_ON; + + ret = regmap_write_bits(ctx->regmap, IT66121_AV_MUTE_REG, IT66121_AV_MUTE_ON, val); + if (ret) + return ret; + + return regmap_write(ctx->regmap, IT66121_PKT_GEN_CTRL_REG, + IT66121_PKT_GEN_CTRL_ON | IT66121_PKT_GEN_CTRL_RPT); +} + +#define MAX_OUTPUT_SEL_FORMATS 1 + +static u32 *it66121_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts) +{ + u32 *output_fmts; + + output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts), + GFP_KERNEL); + if (!output_fmts) + return NULL; + + /* TOFIX handle more than MEDIA_BUS_FMT_RGB888_1X24 as output format */ + output_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + *num_output_fmts = 1; + + return output_fmts; +} + +#define MAX_INPUT_SEL_FORMATS 1 + +static u32 *it66121_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + u32 *input_fmts; + + *num_input_fmts = 0; + + input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), + GFP_KERNEL); + if (!input_fmts) + return NULL; + + if (ctx->bus_width == 12) + /* IT66121FN Datasheet specifies Little-Endian ordering */ + input_fmts[0] = MEDIA_BUS_FMT_RGB888_2X12_LE; + else + /* TOFIX support more input bus formats in 24bit width */ + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + *num_input_fmts = 1; + + return input_fmts; +} + +static void it66121_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + struct drm_atomic_state *state = bridge_state->base.state; + + ctx->connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + + it66121_set_mute(ctx, false); +} + +static void it66121_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + + it66121_set_mute(ctx, true); + + ctx->connector = NULL; +} + +static +void it66121_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + int ret, i; + u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = { + IT66121_AVIINFO_DB1_REG, + IT66121_AVIINFO_DB2_REG, + IT66121_AVIINFO_DB3_REG, + IT66121_AVIINFO_DB4_REG, + IT66121_AVIINFO_DB5_REG, + IT66121_AVIINFO_DB6_REG, + IT66121_AVIINFO_DB7_REG, + IT66121_AVIINFO_DB8_REG, + IT66121_AVIINFO_DB9_REG, + IT66121_AVIINFO_DB10_REG, + IT66121_AVIINFO_DB11_REG, + IT66121_AVIINFO_DB12_REG, + IT66121_AVIINFO_DB13_REG + }; + + mutex_lock(&ctx->lock); + + hdmi_avi_infoframe_init(&ctx->hdmi_avi_infoframe); + + ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe, ctx->connector, + adjusted_mode); + if (ret) { + DRM_ERROR("Failed to setup AVI infoframe: %d\n", ret); + goto unlock; + } + + ret = hdmi_avi_infoframe_pack(&ctx->hdmi_avi_infoframe, buf, sizeof(buf)); + if (ret < 0) { + DRM_ERROR("Failed to pack infoframe: %d\n", ret); + goto unlock; + } + + /* Write new AVI infoframe packet */ + for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) { + if (regmap_write(ctx->regmap, aviinfo_reg[i], buf[i + HDMI_INFOFRAME_HEADER_SIZE])) + goto unlock; + } + if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3])) + goto unlock; + + /* Enable AVI infoframe */ + if (regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG, + IT66121_AVI_INFO_PKT_ON | IT66121_AVI_INFO_PKT_RPT)) + goto unlock; + + /* Set TX mode to HDMI */ + if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, IT66121_HDMI_MODE_HDMI)) + goto unlock; + + if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, + IT66121_CLK_BANK_PWROFF_TXCLK, IT66121_CLK_BANK_PWROFF_TXCLK)) + goto unlock; + + if (it66121_configure_input(ctx)) + goto unlock; + + if (it66121_configure_afe(ctx, adjusted_mode)) + goto unlock; + + regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, IT66121_CLK_BANK_PWROFF_TXCLK, 0); + +unlock: + mutex_unlock(&ctx->lock); +} + +static enum drm_mode_status it66121_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + unsigned long max_clock; + + max_clock = (ctx->bus_width == 12) ? 74250 : 148500; + + if (mode->clock > max_clock) + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static enum drm_connector_status it66121_bridge_detect(struct drm_bridge *bridge) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + + return it66121_is_hpd_detect(ctx) ? connector_status_connected + : connector_status_disconnected; +} + +static void it66121_bridge_hpd_enable(struct drm_bridge *bridge) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + int ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, IT66121_INT_MASK1_HPD, 0); + if (ret) + dev_err(ctx->dev, "failed to enable HPD IRQ\n"); +} + +static void it66121_bridge_hpd_disable(struct drm_bridge *bridge) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + int ret; + + ret = regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, + IT66121_INT_MASK1_HPD, IT66121_INT_MASK1_HPD); + if (ret) + dev_err(ctx->dev, "failed to disable HPD IRQ\n"); +} + +static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); + struct edid *edid; + + mutex_lock(&ctx->lock); + edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx); + mutex_unlock(&ctx->lock); + + return edid; +} + +static const struct drm_bridge_funcs it66121_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .attach = it66121_bridge_attach, + .atomic_get_output_bus_fmts = it66121_bridge_atomic_get_output_bus_fmts, + .atomic_get_input_bus_fmts = it66121_bridge_atomic_get_input_bus_fmts, + .atomic_enable = it66121_bridge_enable, + .atomic_disable = it66121_bridge_disable, + .mode_set = it66121_bridge_mode_set, + .mode_valid = it66121_bridge_mode_valid, + .detect = it66121_bridge_detect, + .get_edid = it66121_bridge_get_edid, + .hpd_enable = it66121_bridge_hpd_enable, + .hpd_disable = it66121_bridge_hpd_disable, +}; + +static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) +{ + int ret; + unsigned int val; + struct it66121_ctx *ctx = dev_id; + struct device *dev = ctx->dev; + enum drm_connector_status status; + bool event = false; + + mutex_lock(&ctx->lock); + + ret = regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val); + if (ret) + goto unlock; + + if (!(val & IT66121_SYS_STATUS_ACTIVE_IRQ)) + goto unlock; + + ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); + if (ret) { + dev_err(dev, "Cannot read STATUS1_REG %d\n", ret); + } else { + if (val & IT66121_INT_STATUS1_DDC_FIFOERR) + it66121_clear_ddc_fifo(ctx); + if (val & (IT66121_INT_STATUS1_DDC_BUSHANG | + IT66121_INT_STATUS1_DDC_NOACK)) + it66121_abort_ddc_ops(ctx); + if (val & IT66121_INT_STATUS1_HPD_STATUS) { + regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG, + IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD); + + status = it66121_is_hpd_detect(ctx) ? connector_status_connected + : connector_status_disconnected; + + event = true; + } + } + + regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG, + IT66121_SYS_STATUS_CLEAR_IRQ, + IT66121_SYS_STATUS_CLEAR_IRQ); + +unlock: + mutex_unlock(&ctx->lock); + + if (event) + drm_bridge_hpd_notify(&ctx->bridge, status); + + return IRQ_HANDLED; +} + +static int it66121_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + u32 vendor_ids[2], device_ids[2], revision_id; + struct device_node *ep; + int ret; + struct it66121_ctx *ctx; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "I2C check functionality failed.\n"); + return -ENXIO; + } + + ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); + if (!ep) + return -EINVAL; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = dev; + ctx->client = client; + + of_property_read_u32(ep, "bus-width", &ctx->bus_width); + of_node_put(ep); + + if (ctx->bus_width != 12 && ctx->bus_width != 24) + return -EINVAL; + + ep = of_graph_get_remote_node(dev->of_node, 1, -1); + if (!ep) + return -EPROBE_DEFER; + + ctx->next_bridge = of_drm_find_bridge(ep); + of_node_put(ep); + + i2c_set_clientdata(client, ctx); + mutex_init(&ctx->lock); + + ctx->supplies[0].supply = "vcn33"; + ctx->supplies[1].supply = "vcn18"; + ctx->supplies[2].supply = "vrf12"; + ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies); + if (ret) { + dev_err(ctx->dev, "regulator_bulk failed\n"); + return ret; + } + + ret = ite66121_power_on(ctx); + if (ret) + return ret; + + it66121_hw_reset(ctx); + + ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config); + if (IS_ERR(ctx->regmap)) { + ite66121_power_off(ctx); + return PTR_ERR(ctx); + } + + regmap_read(ctx->regmap, IT66121_VENDOR_ID0_REG, &vendor_ids[0]); + regmap_read(ctx->regmap, IT66121_VENDOR_ID1_REG, &vendor_ids[1]); + regmap_read(ctx->regmap, IT66121_DEVICE_ID0_REG, &device_ids[0]); + regmap_read(ctx->regmap, IT66121_DEVICE_ID1_REG, &device_ids[1]); + + /* Revision is shared with DEVICE_ID1 */ + revision_id = FIELD_GET(IT66121_REVISION_MASK, device_ids[1]); + device_ids[1] &= IT66121_DEVICE_ID1_MASK; + + if (vendor_ids[0] != IT66121_VENDOR_ID0 || vendor_ids[1] != IT66121_VENDOR_ID1 || + device_ids[0] != IT66121_DEVICE_ID0 || device_ids[1] != IT66121_DEVICE_ID1) { + ite66121_power_off(ctx); + return -ENODEV; + } + + ctx->bridge.funcs = &it66121_bridge_funcs; + ctx->bridge.of_node = dev->of_node; + ctx->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; + + ret = devm_request_threaded_irq(dev, client->irq, NULL, it66121_irq_threaded_handler, + IRQF_ONESHOT, dev_name(dev), ctx); + if (ret < 0) { + dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret); + ite66121_power_off(ctx); + return ret; + } + + drm_bridge_add(&ctx->bridge); + + dev_info(ctx->dev, "IT66121 revision %d probed\n", revision_id); + + return 0; +} + +static int it66121_remove(struct i2c_client *client) +{ + struct it66121_ctx *ctx = i2c_get_clientdata(client); + + ite66121_power_off(ctx); + drm_bridge_remove(&ctx->bridge); + mutex_destroy(&ctx->lock); + + return 0; +} + +static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121" }, + { } +}; +MODULE_DEVICE_TABLE(of, it66121_dt_match); + +static const struct i2c_device_id it66121_id[] = { + { "it66121", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, it66121_id); + +static struct i2c_driver it66121_driver = { + .driver = { + .name = "it66121", + .of_match_table = it66121_dt_match, + }, + .probe = it66121_probe, + .remove = it66121_remove, + .id_table = it66121_id, +}; + +module_i2c_driver(it66121_driver); + +MODULE_AUTHOR("Phong LE"); +MODULE_DESCRIPTION("IT66121 HDMI transmitter driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 4f693123985b..443f1b47e031 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -622,7 +622,8 @@ static int lt8912_parse_dt(struct lt8912 *lt) { struct gpio_desc *gp_reset; struct device *dev = lt->dev; - int ret = 0; + int ret; + int data_lanes; struct device_node *port_node; struct device_node *endpoint; @@ -636,19 +637,21 @@ static int lt8912_parse_dt(struct lt8912 *lt) lt->gp_reset = gp_reset; endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); - if (IS_ERR(endpoint)) { - ret = PTR_ERR(endpoint); - goto end; - } + if (!endpoint) + return -ENODEV; - lt->data_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); + data_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); of_node_put(endpoint); + if (data_lanes < 0) { + dev_err(lt->dev, "%s: Bad data-lanes property\n", __func__); + return data_lanes; + } + lt->data_lanes = data_lanes; lt->host_node = of_graph_get_remote_node(dev->of_node, 0, -1); if (!lt->host_node) { dev_err(lt->dev, "%s: Failed to get remote port\n", __func__); - ret = -ENODEV; - goto end; + return -ENODEV; } port_node = of_graph_get_remote_node(dev->of_node, 1, -1); @@ -659,24 +662,23 @@ static int lt8912_parse_dt(struct lt8912 *lt) } lt->hdmi_port = of_drm_find_bridge(port_node); - if (IS_ERR(lt->hdmi_port)) { + if (!lt->hdmi_port) { dev_err(lt->dev, "%s: Failed to get hdmi port\n", __func__); - ret = PTR_ERR(lt->hdmi_port); - of_node_put(lt->host_node); - goto end; + ret = -ENODEV; + goto err_free_host_node; } if (!of_device_is_compatible(port_node, "hdmi-connector")) { dev_err(lt->dev, "%s: Failed to get hdmi port\n", __func__); ret = -EINVAL; + goto err_free_host_node; } of_node_put(port_node); - -end: - return ret; + return 0; err_free_host_node: + of_node_put(port_node); of_node_put(lt->host_node); return ret; } diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index e8eb8deb444b..29b1ce2140ab 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -1215,6 +1215,7 @@ static struct i2c_device_id lt9611_id[] = { { "lontium,lt9611", 0 }, {} }; +MODULE_DEVICE_TABLE(i2c, lt9611_id); static const struct of_device_id lt9611_match_table[] = { { .compatible = "lontium,lt9611" }, diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index 66b67402f1ac..873995f0a741 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -21,6 +21,7 @@ #include <linux/sys_soc.h> #include <linux/time64.h> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> @@ -661,7 +662,7 @@ static irqreturn_t nwl_dsi_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int nwl_dsi_enable(struct nwl_dsi *dsi) +static int nwl_dsi_mode_set(struct nwl_dsi *dsi) { struct device *dev = dsi->dev; union phy_configure_opts *phy_cfg = &dsi->phy_cfg; @@ -742,7 +743,9 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi) return 0; } -static void nwl_dsi_bridge_disable(struct drm_bridge *bridge) +static void +nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct nwl_dsi *dsi = bridge_to_dsi(bridge); int ret; @@ -803,17 +806,6 @@ static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi, return 0; } -static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - /* At least LCDIF + NWL needs active high sync */ - adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); - adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); - - return true; -} - static enum drm_mode_status nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, @@ -831,6 +823,29 @@ nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } +static int nwl_dsi_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + + /* At least LCDIF + NWL needs active high sync */ + adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); + adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); + + /* + * Do a full modeset if crtc_state->active is changed to be true. + * This ensures our ->mode_set() is called to get the DSI controller + * and the PHY ready to send DCS commands, when only the connector's + * DPMS is brought out of "Off" status. + */ + if (crtc_state->active_changed && crtc_state->active) + crtc_state->mode_changed = true; + + return 0; +} + static void nwl_dsi_bridge_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *mode, @@ -846,13 +861,6 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge, if (ret < 0) return; - /* - * If hs clock is unchanged, we're all good - all parameters are - * derived from it atm. - */ - if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate) - return; - phy_ref_rate = clk_get_rate(dsi->phy_ref_clk); DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate); /* Save the new desired phy config */ @@ -860,14 +868,8 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge, memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode)); drm_mode_debug_printmodeline(adjusted_mode); -} -static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge) -{ - struct nwl_dsi *dsi = bridge_to_dsi(bridge); - int ret; - - pm_runtime_get_sync(dsi->dev); + pm_runtime_get_sync(dev); if (clk_prepare_enable(dsi->lcdif_clk) < 0) return; @@ -877,27 +879,29 @@ static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge) /* Step 1 from DSI reset-out instructions */ ret = reset_control_deassert(dsi->rst_pclk); if (ret < 0) { - DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret); + DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret); return; } /* Step 2 from DSI reset-out instructions */ - nwl_dsi_enable(dsi); + nwl_dsi_mode_set(dsi); /* Step 3 from DSI reset-out instructions */ ret = reset_control_deassert(dsi->rst_esc); if (ret < 0) { - DRM_DEV_ERROR(dsi->dev, "Failed to deassert ESC: %d\n", ret); + DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret); return; } ret = reset_control_deassert(dsi->rst_byte); if (ret < 0) { - DRM_DEV_ERROR(dsi->dev, "Failed to deassert BYTE: %d\n", ret); + DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret); return; } } -static void nwl_dsi_bridge_enable(struct drm_bridge *bridge) +static void +nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct nwl_dsi *dsi = bridge_to_dsi(bridge); int ret; @@ -942,14 +946,16 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge) } static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = { - .pre_enable = nwl_dsi_bridge_pre_enable, - .enable = nwl_dsi_bridge_enable, - .disable = nwl_dsi_bridge_disable, - .mode_fixup = nwl_dsi_bridge_mode_fixup, - .mode_set = nwl_dsi_bridge_mode_set, - .mode_valid = nwl_dsi_bridge_mode_valid, - .attach = nwl_dsi_bridge_attach, - .detach = nwl_dsi_bridge_detach, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_check = nwl_dsi_bridge_atomic_check, + .atomic_enable = nwl_dsi_bridge_atomic_enable, + .atomic_disable = nwl_dsi_bridge_atomic_disable, + .mode_set = nwl_dsi_bridge_mode_set, + .mode_valid = nwl_dsi_bridge_mode_valid, + .attach = nwl_dsi_bridge_attach, + .detach = nwl_dsi_bridge_detach, }; static int nwl_dsi_parse_dt(struct nwl_dsi *dsi) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index dda4fa9a1a08..e7c7c9b9c646 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2395,21 +2395,6 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) return ret; } -static bool hdr_metadata_equal(const struct drm_connector_state *old_state, - const struct drm_connector_state *new_state) -{ - struct drm_property_blob *old_blob = old_state->hdr_output_metadata; - struct drm_property_blob *new_blob = new_state->hdr_output_metadata; - - if (!old_blob || !new_blob) - return old_blob == new_blob; - - if (old_blob->length != new_blob->length) - return false; - - return !memcmp(old_blob->data, new_blob->data, old_blob->length); -} - static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state) { @@ -2423,7 +2408,7 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, if (!crtc) return 0; - if (!hdr_metadata_equal(old_state, new_state)) { + if (!drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); @@ -2492,8 +2477,7 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) drm_connector_attach_max_bpc_property(connector, 8, 16); if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, 0); + drm_connector_attach_hdr_output_metadata_property(connector); drm_connector_attach_encoder(connector, hdmi->bridge.encoder); @@ -3421,7 +3405,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, hdmi->audio = platform_device_register_full(&pdevinfo); } - if (config0 & HDMI_CONFIG0_CEC) { + if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) { cec.hdmi = hdmi; cec.ops = &dw_hdmi_cec_ops; cec.irq = irq; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index da89922721ed..23a6f90b694b 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1414,6 +1414,7 @@ static int tc_bridge_attach(struct drm_bridge *bridge, if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) return 0; + tc->aux.drm_dev = drm; ret = drm_dp_aux_register(&tc->aux); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 88df4dd0f39d..bb0a0e1c6341 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -4,6 +4,7 @@ * datasheet: https://www.ti.com/lit/ds/symlink/sn65dsi86.pdf */ +#include <linux/auxiliary_bus.h> #include <linux/bits.h> #include <linux/clk.h> #include <linux/debugfs.h> @@ -112,13 +113,15 @@ #define SN_LINK_TRAINING_TRIES 10 /** - * struct ti_sn_bridge - Platform data for ti-sn65dsi86 driver. - * @dev: Pointer to our device. + * struct ti_sn65dsi86 - Platform data for ti-sn65dsi86 driver. + * @bridge_aux: AUX-bus sub device for MIPI-to-eDP bridge functionality. + * @gpio_aux: AUX-bus sub device for GPIO controller functionality. + * + * @dev: Pointer to the top level (i2c) device. * @regmap: Regmap for accessing i2c. * @aux: Our aux channel. * @bridge: Our bridge. * @connector: Our connector. - * @debugfs: Used for managing our debugfs. * @host_node: Remote DSI node. * @dsi: Our MIPI DSI source. * @edid: Detected EDID of eDP panel. @@ -129,6 +132,8 @@ * @dp_lanes: Count of dp_lanes we're using. * @ln_assign: Value to program to the LN_ASSIGN register. * @ln_polrs: Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG. + * @comms_enabled: If true then communication over the aux channel is enabled. + * @comms_mutex: Protects modification of comms_enabled. * * @gchip: If we expose our GPIOs, this is used. * @gchip_output: A cache of whether we've set GPIOs to output. This @@ -140,13 +145,15 @@ * lock so concurrent users of our 4 GPIOs don't stomp on * each other's read-modify-write. */ -struct ti_sn_bridge { +struct ti_sn65dsi86 { + struct auxiliary_device bridge_aux; + struct auxiliary_device gpio_aux; + struct device *dev; struct regmap *regmap; struct drm_dp_aux aux; struct drm_bridge bridge; struct drm_connector connector; - struct dentry *debugfs; struct edid *edid; struct device_node *host_node; struct mipi_dsi_device *dsi; @@ -157,6 +164,8 @@ struct ti_sn_bridge { int dp_lanes; u8 ln_assign; u8 ln_polrs; + bool comms_enabled; + struct mutex comms_mutex; #if defined(CONFIG_OF_GPIO) struct gpio_chip gchip; @@ -164,32 +173,131 @@ struct ti_sn_bridge { #endif }; -static const struct regmap_range ti_sn_bridge_volatile_ranges[] = { +static const struct regmap_range ti_sn65dsi86_volatile_ranges[] = { { .range_min = 0, .range_max = 0xFF }, }; static const struct regmap_access_table ti_sn_bridge_volatile_table = { - .yes_ranges = ti_sn_bridge_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(ti_sn_bridge_volatile_ranges), + .yes_ranges = ti_sn65dsi86_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(ti_sn65dsi86_volatile_ranges), }; -static const struct regmap_config ti_sn_bridge_regmap_config = { +static const struct regmap_config ti_sn65dsi86_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_table = &ti_sn_bridge_volatile_table, .cache_type = REGCACHE_NONE, }; -static void ti_sn_bridge_write_u16(struct ti_sn_bridge *pdata, +static void ti_sn65dsi86_write_u16(struct ti_sn65dsi86 *pdata, unsigned int reg, u16 val) { regmap_write(pdata->regmap, reg, val & 0xFF); regmap_write(pdata->regmap, reg + 1, val >> 8); } -static int __maybe_unused ti_sn_bridge_resume(struct device *dev) +static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn65dsi86 *pdata) +{ + u32 bit_rate_khz, clk_freq_khz; + struct drm_display_mode *mode = + &pdata->bridge.encoder->crtc->state->adjusted_mode; + + bit_rate_khz = mode->clock * + mipi_dsi_pixel_format_to_bpp(pdata->dsi->format); + clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2); + + return clk_freq_khz; +} + +/* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */ +static const u32 ti_sn_bridge_refclk_lut[] = { + 12000000, + 19200000, + 26000000, + 27000000, + 38400000, +}; + +/* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */ +static const u32 ti_sn_bridge_dsiclk_lut[] = { + 468000000, + 384000000, + 416000000, + 486000000, + 460800000, +}; + +static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata) +{ + int i; + u32 refclk_rate; + const u32 *refclk_lut; + size_t refclk_lut_size; + + if (pdata->refclk) { + refclk_rate = clk_get_rate(pdata->refclk); + refclk_lut = ti_sn_bridge_refclk_lut; + refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_refclk_lut); + clk_prepare_enable(pdata->refclk); + } else { + refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000; + refclk_lut = ti_sn_bridge_dsiclk_lut; + refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_dsiclk_lut); + } + + /* for i equals to refclk_lut_size means default frequency */ + for (i = 0; i < refclk_lut_size; i++) + if (refclk_lut[i] == refclk_rate) + break; + + regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, REFCLK_FREQ_MASK, + REFCLK_FREQ(i)); +} + +static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata) { - struct ti_sn_bridge *pdata = dev_get_drvdata(dev); + mutex_lock(&pdata->comms_mutex); + + /* configure bridge ref_clk */ + ti_sn_bridge_set_refclk_freq(pdata); + + /* + * HPD on this bridge chip is a bit useless. This is an eDP bridge + * so the HPD is an internal signal that's only there to signal that + * the panel is done powering up. ...but the bridge chip debounces + * this signal by between 100 ms and 400 ms (depending on process, + * voltage, and temperate--I measured it at about 200 ms). One + * particular panel asserted HPD 84 ms after it was powered on meaning + * that we saw HPD 284 ms after power on. ...but the same panel said + * that instead of looking at HPD you could just hardcode a delay of + * 200 ms. We'll assume that the panel driver will have the hardcoded + * delay in its prepare and always disable HPD. + * + * If HPD somehow makes sense on some future panel we'll have to + * change this to be conditional on someone specifying that HPD should + * be used. + */ + regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, + HPD_DISABLE); + + pdata->comms_enabled = true; + + mutex_unlock(&pdata->comms_mutex); +} + +static void ti_sn65dsi86_disable_comms(struct ti_sn65dsi86 *pdata) +{ + mutex_lock(&pdata->comms_mutex); + + pdata->comms_enabled = false; + clk_disable_unprepare(pdata->refclk); + + mutex_unlock(&pdata->comms_mutex); +} + +static int __maybe_unused ti_sn65dsi86_resume(struct device *dev) +{ + struct ti_sn65dsi86 *pdata = dev_get_drvdata(dev); int ret; ret = regulator_bulk_enable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); @@ -200,14 +308,27 @@ static int __maybe_unused ti_sn_bridge_resume(struct device *dev) gpiod_set_value(pdata->enable_gpio, 1); + /* + * If we have a reference clock we can enable communication w/ the + * panel (including the aux channel) w/out any need for an input clock + * so we can do it in resume which lets us read the EDID before + * pre_enable(). Without a reference clock we need the MIPI reference + * clock so reading early doesn't work. + */ + if (pdata->refclk) + ti_sn65dsi86_enable_comms(pdata); + return ret; } -static int __maybe_unused ti_sn_bridge_suspend(struct device *dev) +static int __maybe_unused ti_sn65dsi86_suspend(struct device *dev) { - struct ti_sn_bridge *pdata = dev_get_drvdata(dev); + struct ti_sn65dsi86 *pdata = dev_get_drvdata(dev); int ret; + if (pdata->refclk) + ti_sn65dsi86_disable_comms(pdata); + gpiod_set_value(pdata->enable_gpio, 0); ret = regulator_bulk_disable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); @@ -217,15 +338,15 @@ static int __maybe_unused ti_sn_bridge_suspend(struct device *dev) return ret; } -static const struct dev_pm_ops ti_sn_bridge_pm_ops = { - SET_RUNTIME_PM_OPS(ti_sn_bridge_suspend, ti_sn_bridge_resume, NULL) +static const struct dev_pm_ops ti_sn65dsi86_pm_ops = { + SET_RUNTIME_PM_OPS(ti_sn65dsi86_suspend, ti_sn65dsi86_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static int status_show(struct seq_file *s, void *data) { - struct ti_sn_bridge *pdata = s->private; + struct ti_sn65dsi86 *pdata = s->private; unsigned int reg, val; seq_puts(s, "STATUS REGISTERS:\n"); @@ -238,44 +359,57 @@ static int status_show(struct seq_file *s, void *data) seq_printf(s, "[0x%02x] = 0x%08x\n", reg, val); } - pm_runtime_put(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); return 0; } DEFINE_SHOW_ATTRIBUTE(status); -static void ti_sn_debugfs_init(struct ti_sn_bridge *pdata) +static void ti_sn65dsi86_debugfs_remove(void *data) { - pdata->debugfs = debugfs_create_dir(dev_name(pdata->dev), NULL); - - debugfs_create_file("status", 0600, pdata->debugfs, pdata, - &status_fops); + debugfs_remove_recursive(data); } -static void ti_sn_debugfs_remove(struct ti_sn_bridge *pdata) +static void ti_sn65dsi86_debugfs_init(struct ti_sn65dsi86 *pdata) { - debugfs_remove_recursive(pdata->debugfs); - pdata->debugfs = NULL; + struct device *dev = pdata->dev; + struct dentry *debugfs; + int ret; + + debugfs = debugfs_create_dir(dev_name(dev), NULL); + + /* + * We might get an error back if debugfs wasn't enabled in the kernel + * so let's just silently return upon failure. + */ + if (IS_ERR_OR_NULL(debugfs)) + return; + + ret = devm_add_action_or_reset(dev, ti_sn65dsi86_debugfs_remove, debugfs); + if (ret) + return; + + debugfs_create_file("status", 0600, debugfs, pdata, &status_fops); } /* Connector funcs */ -static struct ti_sn_bridge * -connector_to_ti_sn_bridge(struct drm_connector *connector) +static struct ti_sn65dsi86 * +connector_to_ti_sn65dsi86(struct drm_connector *connector) { - return container_of(connector, struct ti_sn_bridge, connector); + return container_of(connector, struct ti_sn65dsi86, connector); } static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector) { - struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector); + struct ti_sn65dsi86 *pdata = connector_to_ti_sn65dsi86(connector); struct edid *edid = pdata->edid; int num, ret; if (!edid) { pm_runtime_get_sync(pdata->dev); edid = pdata->edid = drm_get_edid(connector, &pdata->aux.ddc); - pm_runtime_put(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); } if (edid && drm_edid_is_valid(edid)) { @@ -306,32 +440,20 @@ static struct drm_connector_helper_funcs ti_sn_bridge_connector_helper_funcs = { .mode_valid = ti_sn_bridge_connector_mode_valid, }; -static enum drm_connector_status -ti_sn_bridge_connector_detect(struct drm_connector *connector, bool force) -{ - /** - * TODO: Currently if drm_panel is present, then always - * return the status as connected. Need to add support to detect - * device state for hot pluggable scenarios. - */ - return connector_status_connected; -} - static const struct drm_connector_funcs ti_sn_bridge_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, - .detect = ti_sn_bridge_connector_detect, .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static struct ti_sn_bridge *bridge_to_ti_sn_bridge(struct drm_bridge *bridge) +static struct ti_sn65dsi86 *bridge_to_ti_sn65dsi86(struct drm_bridge *bridge) { - return container_of(bridge, struct ti_sn_bridge, bridge); + return container_of(bridge, struct ti_sn65dsi86, bridge); } -static int ti_sn_bridge_parse_regulators(struct ti_sn_bridge *pdata) +static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata) { unsigned int i; const char * const ti_sn_bridge_supply_names[] = { @@ -349,7 +471,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { int ret, val; - struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); struct mipi_dsi_host *host; struct mipi_dsi_device *dsi; const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge", @@ -362,6 +484,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, return -EINVAL; } + pdata->aux.drm_dev = bridge->dev; ret = drm_dp_aux_register(&pdata->aux); if (ret < 0) { drm_err(bridge->dev, "Failed to register DP AUX channel: %d\n", ret); @@ -413,7 +536,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, /* check if continuous dsi clock is required or not */ pm_runtime_get_sync(pdata->dev); regmap_read(pdata->regmap, SN_DPPLL_SRC_REG, &val); - pm_runtime_put(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); if (!(val & DPPLL_CLK_SRC_DSICLK)) dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; @@ -437,12 +560,12 @@ err_conn_init: static void ti_sn_bridge_detach(struct drm_bridge *bridge) { - drm_dp_aux_unregister(&bridge_to_ti_sn_bridge(bridge)->aux); + drm_dp_aux_unregister(&bridge_to_ti_sn65dsi86(bridge)->aux); } static void ti_sn_bridge_disable(struct drm_bridge *bridge) { - struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); drm_panel_disable(pdata->panel); @@ -452,69 +575,9 @@ static void ti_sn_bridge_disable(struct drm_bridge *bridge) regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0); /* disable DP PLL */ regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0); - - drm_panel_unprepare(pdata->panel); -} - -static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn_bridge *pdata) -{ - u32 bit_rate_khz, clk_freq_khz; - struct drm_display_mode *mode = - &pdata->bridge.encoder->crtc->state->adjusted_mode; - - bit_rate_khz = mode->clock * - mipi_dsi_pixel_format_to_bpp(pdata->dsi->format); - clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2); - - return clk_freq_khz; -} - -/* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */ -static const u32 ti_sn_bridge_refclk_lut[] = { - 12000000, - 19200000, - 26000000, - 27000000, - 38400000, -}; - -/* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */ -static const u32 ti_sn_bridge_dsiclk_lut[] = { - 468000000, - 384000000, - 416000000, - 486000000, - 460800000, -}; - -static void ti_sn_bridge_set_refclk_freq(struct ti_sn_bridge *pdata) -{ - int i; - u32 refclk_rate; - const u32 *refclk_lut; - size_t refclk_lut_size; - - if (pdata->refclk) { - refclk_rate = clk_get_rate(pdata->refclk); - refclk_lut = ti_sn_bridge_refclk_lut; - refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_refclk_lut); - clk_prepare_enable(pdata->refclk); - } else { - refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000; - refclk_lut = ti_sn_bridge_dsiclk_lut; - refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_dsiclk_lut); - } - - /* for i equals to refclk_lut_size means default frequency */ - for (i = 0; i < refclk_lut_size; i++) - if (refclk_lut[i] == refclk_rate) - break; - - regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, REFCLK_FREQ_MASK, - REFCLK_FREQ(i)); } -static void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata) +static void ti_sn_bridge_set_dsi_rate(struct ti_sn65dsi86 *pdata) { unsigned int bit_rate_mhz, clk_freq_mhz; unsigned int val; @@ -532,7 +595,7 @@ static void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata) regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val); } -static unsigned int ti_sn_bridge_get_bpp(struct ti_sn_bridge *pdata) +static unsigned int ti_sn_bridge_get_bpp(struct ti_sn65dsi86 *pdata) { if (pdata->connector.display_info.bpc <= 6) return 18; @@ -549,7 +612,7 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = { 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400 }; -static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata) +static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata) { unsigned int bit_rate_khz, dp_rate_mhz; unsigned int i; @@ -570,7 +633,7 @@ static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata) return i; } -static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata, +static void ti_sn_bridge_read_valid_rates(struct ti_sn65dsi86 *pdata, bool rate_valid[]) { unsigned int rate_per_200khz; @@ -651,7 +714,7 @@ static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata, } } -static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata) +static void ti_sn_bridge_set_video_timings(struct ti_sn65dsi86 *pdata) { struct drm_display_mode *mode = &pdata->bridge.encoder->crtc->state->adjusted_mode; @@ -662,9 +725,9 @@ static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata) if (mode->flags & DRM_MODE_FLAG_PVSYNC) vsync_polarity = CHA_VSYNC_POLARITY; - ti_sn_bridge_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG, + ti_sn65dsi86_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG, mode->hdisplay); - ti_sn_bridge_write_u16(pdata, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG, + ti_sn65dsi86_write_u16(pdata, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG, mode->vdisplay); regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG, (mode->hsync_end - mode->hsync_start) & 0xFF); @@ -690,7 +753,7 @@ static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata) usleep_range(10000, 10500); /* 10ms delay recommended by spec */ } -static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata) +static unsigned int ti_sn_get_max_lanes(struct ti_sn65dsi86 *pdata) { u8 data; int ret; @@ -705,7 +768,7 @@ static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata) return data & DP_LANE_COUNT_MASK; } -static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx, +static int ti_sn_link_training(struct ti_sn65dsi86 *pdata, int dp_rate_idx, const char **last_err_str) { unsigned int val; @@ -765,7 +828,7 @@ exit: static void ti_sn_bridge_enable(struct drm_bridge *bridge) { - struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); bool rate_valid[ARRAY_SIZE(ti_sn_bridge_dp_rate_lut)] = { }; const char *last_err_str = "No supported DP rate"; int dp_rate_idx; @@ -788,7 +851,7 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge) /* set dsi clk frequency value */ ti_sn_bridge_set_dsi_rate(pdata); - /** + /* * The SN65DSI86 only supports ASSR Display Authentication method and * this method is enabled by default. An eDP panel must support this * authentication method. We need to enable this method in the eDP panel @@ -836,40 +899,24 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge) static void ti_sn_bridge_pre_enable(struct drm_bridge *bridge) { - struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); pm_runtime_get_sync(pdata->dev); - /* configure bridge ref_clk */ - ti_sn_bridge_set_refclk_freq(pdata); - - /* - * HPD on this bridge chip is a bit useless. This is an eDP bridge - * so the HPD is an internal signal that's only there to signal that - * the panel is done powering up. ...but the bridge chip debounces - * this signal by between 100 ms and 400 ms (depending on process, - * voltage, and temperate--I measured it at about 200 ms). One - * particular panel asserted HPD 84 ms after it was powered on meaning - * that we saw HPD 284 ms after power on. ...but the same panel said - * that instead of looking at HPD you could just hardcode a delay of - * 200 ms. We'll assume that the panel driver will have the hardcoded - * delay in its prepare and always disable HPD. - * - * If HPD somehow makes sense on some future panel we'll have to - * change this to be conditional on someone specifying that HPD should - * be used. - */ - regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, - HPD_DISABLE); + if (!pdata->refclk) + ti_sn65dsi86_enable_comms(pdata); drm_panel_prepare(pdata->panel); } static void ti_sn_bridge_post_disable(struct drm_bridge *bridge) { - struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); - clk_disable_unprepare(pdata->refclk); + drm_panel_unprepare(pdata->panel); + + if (!pdata->refclk) + ti_sn65dsi86_disable_comms(pdata); pm_runtime_put_sync(pdata->dev); } @@ -883,15 +930,15 @@ static const struct drm_bridge_funcs ti_sn_bridge_funcs = { .post_disable = ti_sn_bridge_post_disable, }; -static struct ti_sn_bridge *aux_to_ti_sn_bridge(struct drm_dp_aux *aux) +static struct ti_sn65dsi86 *aux_to_ti_sn65dsi86(struct drm_dp_aux *aux) { - return container_of(aux, struct ti_sn_bridge, aux); + return container_of(aux, struct ti_sn65dsi86, aux); } static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { - struct ti_sn_bridge *pdata = aux_to_ti_sn_bridge(aux); + struct ti_sn65dsi86 *pdata = aux_to_ti_sn65dsi86(aux); u32 request = msg->request & ~(DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE); u32 request_val = AUX_CMD_REQ(msg->request); u8 *buf = msg->buffer; @@ -903,6 +950,20 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, if (len > SN_AUX_MAX_PAYLOAD_BYTES) return -EINVAL; + pm_runtime_get_sync(pdata->dev); + mutex_lock(&pdata->comms_mutex); + + /* + * If someone tries to do a DDC over AUX transaction before pre_enable() + * on a device without a dedicated reference clock then we just can't + * do it. Fail right away. This prevents non-refclk users from reading + * the EDID before enabling the panel but such is life. + */ + if (!pdata->comms_enabled) { + ret = -EIO; + goto exit; + } + switch (request) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: @@ -913,7 +974,8 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, msg->reply = 0; break; default: - return -EINVAL; + ret = -EINVAL; + goto exit; } BUILD_BUG_ON(sizeof(addr_len) != sizeof(__be32)); @@ -937,11 +999,11 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, ret = regmap_read_poll_timeout(pdata->regmap, SN_AUX_CMD_REG, val, !(val & AUX_CMD_SEND), 0, 50 * 1000); if (ret) - return ret; + goto exit; ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val); if (ret) - return ret; + goto exit; if (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) { /* @@ -949,13 +1011,14 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, * but it hit a timeout. We ignore defers here because they're * handled in hardware. */ - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto exit; } if (val & AUX_IRQ_STATUS_AUX_SHORT) { ret = regmap_read(pdata->regmap, SN_AUX_LENGTH_REG, &len); if (ret) - return ret; + goto exit; } else if (val & AUX_IRQ_STATUS_NAT_I2C_FAIL) { switch (request) { case DP_AUX_I2C_WRITE: @@ -967,21 +1030,22 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, msg->reply |= DP_AUX_NATIVE_REPLY_NACK; break; } - return 0; + len = 0; + goto exit; } - if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE || - len == 0) - return len; + if (request != DP_AUX_NATIVE_WRITE && request != DP_AUX_I2C_WRITE && len != 0) + ret = regmap_bulk_read(pdata->regmap, SN_AUX_RDATA_REG(0), buf, len); - ret = regmap_bulk_read(pdata->regmap, SN_AUX_RDATA_REG(0), buf, len); - if (ret) - return ret; +exit: + mutex_unlock(&pdata->comms_mutex); + pm_runtime_mark_last_busy(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); - return len; + return ret ? ret : len; } -static int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata) +static int ti_sn_bridge_parse_dsi_host(struct ti_sn65dsi86 *pdata) { struct device_node *np = pdata->dev->of_node; @@ -1016,7 +1080,7 @@ static int tn_sn_bridge_of_xlate(struct gpio_chip *chip, static int ti_sn_bridge_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - struct ti_sn_bridge *pdata = gpiochip_get_data(chip); + struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip); /* * We already have to keep track of the direction because we use @@ -1030,7 +1094,7 @@ static int ti_sn_bridge_gpio_get_direction(struct gpio_chip *chip, static int ti_sn_bridge_gpio_get(struct gpio_chip *chip, unsigned int offset) { - struct ti_sn_bridge *pdata = gpiochip_get_data(chip); + struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip); unsigned int val; int ret; @@ -1044,7 +1108,7 @@ static int ti_sn_bridge_gpio_get(struct gpio_chip *chip, unsigned int offset) */ pm_runtime_get_sync(pdata->dev); ret = regmap_read(pdata->regmap, SN_GPIO_IO_REG, &val); - pm_runtime_put(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); if (ret) return ret; @@ -1055,7 +1119,7 @@ static int ti_sn_bridge_gpio_get(struct gpio_chip *chip, unsigned int offset) static void ti_sn_bridge_gpio_set(struct gpio_chip *chip, unsigned int offset, int val) { - struct ti_sn_bridge *pdata = gpiochip_get_data(chip); + struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip); int ret; if (!test_bit(offset, pdata->gchip_output)) { @@ -1075,7 +1139,7 @@ static void ti_sn_bridge_gpio_set(struct gpio_chip *chip, unsigned int offset, static int ti_sn_bridge_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { - struct ti_sn_bridge *pdata = gpiochip_get_data(chip); + struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip); int shift = offset * 2; int ret; @@ -1095,7 +1159,7 @@ static int ti_sn_bridge_gpio_direction_input(struct gpio_chip *chip, * it off and when it comes back it will have lost all state, but * that's OK because the default is input and we're now an input. */ - pm_runtime_put(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); return 0; } @@ -1103,7 +1167,7 @@ static int ti_sn_bridge_gpio_direction_input(struct gpio_chip *chip, static int ti_sn_bridge_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int val) { - struct ti_sn_bridge *pdata = gpiochip_get_data(chip); + struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip); int shift = offset * 2; int ret; @@ -1121,7 +1185,7 @@ static int ti_sn_bridge_gpio_direction_output(struct gpio_chip *chip, SN_GPIO_MUX_OUTPUT << shift); if (ret) { clear_bit(offset, pdata->gchip_output); - pm_runtime_put(pdata->dev); + pm_runtime_put_autosuspend(pdata->dev); } return ret; @@ -1137,8 +1201,10 @@ static const char * const ti_sn_bridge_gpio_names[SN_NUM_GPIOS] = { "GPIO1", "GPIO2", "GPIO3", "GPIO4" }; -static int ti_sn_setup_gpio_controller(struct ti_sn_bridge *pdata) +static int ti_sn_gpio_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) { + struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent); int ret; /* Only init if someone is going to use us as a GPIO controller */ @@ -1160,23 +1226,44 @@ static int ti_sn_setup_gpio_controller(struct ti_sn_bridge *pdata) pdata->gchip.names = ti_sn_bridge_gpio_names; pdata->gchip.ngpio = SN_NUM_GPIOS; pdata->gchip.base = -1; - ret = devm_gpiochip_add_data(pdata->dev, &pdata->gchip, pdata); + ret = devm_gpiochip_add_data(&adev->dev, &pdata->gchip, pdata); if (ret) dev_err(pdata->dev, "can't add gpio chip\n"); return ret; } -#else +static const struct auxiliary_device_id ti_sn_gpio_id_table[] = { + { .name = "ti_sn65dsi86.gpio", }, + {}, +}; + +MODULE_DEVICE_TABLE(auxiliary, ti_sn_gpio_id_table); + +static struct auxiliary_driver ti_sn_gpio_driver = { + .name = "gpio", + .probe = ti_sn_gpio_probe, + .id_table = ti_sn_gpio_id_table, +}; -static inline int ti_sn_setup_gpio_controller(struct ti_sn_bridge *pdata) +static int __init ti_sn_gpio_register(void) { - return 0; + return auxiliary_driver_register(&ti_sn_gpio_driver); +} + +static void ti_sn_gpio_unregister(void) +{ + auxiliary_driver_unregister(&ti_sn_gpio_driver); } +#else + +static inline int ti_sn_gpio_register(void) { return 0; } +static inline void ti_sn_gpio_unregister(void) {} + #endif -static void ti_sn_bridge_parse_lanes(struct ti_sn_bridge *pdata, +static void ti_sn_bridge_parse_lanes(struct ti_sn65dsi86 *pdata, struct device_node *np) { u32 lane_assignments[SN_MAX_DP_LANES] = { 0, 1, 2, 3 }; @@ -1225,141 +1312,253 @@ static void ti_sn_bridge_parse_lanes(struct ti_sn_bridge *pdata, pdata->ln_polrs = ln_polrs; } -static int ti_sn_bridge_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ti_sn_bridge_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) { - struct ti_sn_bridge *pdata; + struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent); + struct device_node *np = pdata->dev->of_node; int ret; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - DRM_ERROR("device doesn't support I2C\n"); - return -ENODEV; - } - - pdata = devm_kzalloc(&client->dev, sizeof(struct ti_sn_bridge), - GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - pdata->regmap = devm_regmap_init_i2c(client, - &ti_sn_bridge_regmap_config); - if (IS_ERR(pdata->regmap)) { - DRM_ERROR("regmap i2c init failed\n"); - return PTR_ERR(pdata->regmap); - } - - pdata->dev = &client->dev; - - ret = drm_of_find_panel_or_bridge(pdata->dev->of_node, 1, 0, - &pdata->panel, NULL); + ret = drm_of_find_panel_or_bridge(np, 1, 0, &pdata->panel, NULL); if (ret) { DRM_ERROR("could not find any panel node\n"); return ret; } - dev_set_drvdata(&client->dev, pdata); - - pdata->enable_gpio = devm_gpiod_get(pdata->dev, "enable", - GPIOD_OUT_LOW); - if (IS_ERR(pdata->enable_gpio)) { - DRM_ERROR("failed to get enable gpio from DT\n"); - ret = PTR_ERR(pdata->enable_gpio); - return ret; - } - - ti_sn_bridge_parse_lanes(pdata, client->dev.of_node); - - ret = ti_sn_bridge_parse_regulators(pdata); - if (ret) { - DRM_ERROR("failed to parse regulators\n"); - return ret; - } - - pdata->refclk = devm_clk_get(pdata->dev, "refclk"); - if (IS_ERR(pdata->refclk)) { - ret = PTR_ERR(pdata->refclk); - if (ret == -EPROBE_DEFER) - return ret; - DRM_DEBUG_KMS("refclk not found\n"); - pdata->refclk = NULL; - } + ti_sn_bridge_parse_lanes(pdata, np); ret = ti_sn_bridge_parse_dsi_host(pdata); if (ret) return ret; - pm_runtime_enable(pdata->dev); - - ret = ti_sn_setup_gpio_controller(pdata); - if (ret) { - pm_runtime_disable(pdata->dev); - return ret; - } - - i2c_set_clientdata(client, pdata); - pdata->aux.name = "ti-sn65dsi86-aux"; pdata->aux.dev = pdata->dev; pdata->aux.transfer = ti_sn_aux_transfer; drm_dp_aux_init(&pdata->aux); pdata->bridge.funcs = &ti_sn_bridge_funcs; - pdata->bridge.of_node = client->dev.of_node; + pdata->bridge.of_node = np; drm_bridge_add(&pdata->bridge); - ti_sn_debugfs_init(pdata); - return 0; } -static int ti_sn_bridge_remove(struct i2c_client *client) +static void ti_sn_bridge_remove(struct auxiliary_device *adev) { - struct ti_sn_bridge *pdata = i2c_get_clientdata(client); + struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent); if (!pdata) - return -EINVAL; + return; + + if (pdata->dsi) { + mipi_dsi_detach(pdata->dsi); + mipi_dsi_device_unregister(pdata->dsi); + } kfree(pdata->edid); - ti_sn_debugfs_remove(pdata); + + drm_bridge_remove(&pdata->bridge); of_node_put(pdata->host_node); +} - pm_runtime_disable(pdata->dev); +static const struct auxiliary_device_id ti_sn_bridge_id_table[] = { + { .name = "ti_sn65dsi86.bridge", }, + {}, +}; - if (pdata->dsi) { - mipi_dsi_detach(pdata->dsi); - mipi_dsi_device_unregister(pdata->dsi); +static struct auxiliary_driver ti_sn_bridge_driver = { + .name = "bridge", + .probe = ti_sn_bridge_probe, + .remove = ti_sn_bridge_remove, + .id_table = ti_sn_bridge_id_table, +}; + +static void ti_sn65dsi86_runtime_disable(void *data) +{ + pm_runtime_disable(data); +} + +static void ti_sn65dsi86_uninit_aux(void *data) +{ + auxiliary_device_uninit(data); +} + +static void ti_sn65dsi86_delete_aux(void *data) +{ + auxiliary_device_delete(data); +} + +/* + * AUX bus docs say that a non-NULL release is mandatory, but it makes no + * sense for the model used here where all of the aux devices are allocated + * in the single shared structure. We'll use this noop as a workaround. + */ +static void ti_sn65dsi86_noop(struct device *dev) {} + +static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata, + struct auxiliary_device *aux, + const char *name) +{ + struct device *dev = pdata->dev; + int ret; + + /* + * NOTE: It would be nice to set the "of_node" of our children to be + * the same "of_node"" that the top-level component has. That doesn't + * work, though, since pinctrl will try (and fail) to reserve the + * pins again. Until that gets sorted out the children will just need + * to look at the of_node of the main device. + */ + + aux->name = name; + aux->dev.parent = dev; + aux->dev.release = ti_sn65dsi86_noop; + ret = auxiliary_device_init(aux); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux); + if (ret) + return ret; + + ret = auxiliary_device_add(aux); + if (ret) + return ret; + ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux); + + return ret; +} + +static int ti_sn65dsi86_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ti_sn65dsi86 *pdata; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + DRM_ERROR("device doesn't support I2C\n"); + return -ENODEV; } - drm_bridge_remove(&pdata->bridge); + pdata = devm_kzalloc(dev, sizeof(struct ti_sn65dsi86), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + dev_set_drvdata(dev, pdata); + pdata->dev = dev; - return 0; + mutex_init(&pdata->comms_mutex); + + pdata->regmap = devm_regmap_init_i2c(client, + &ti_sn65dsi86_regmap_config); + if (IS_ERR(pdata->regmap)) { + DRM_ERROR("regmap i2c init failed\n"); + return PTR_ERR(pdata->regmap); + } + + pdata->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(pdata->enable_gpio)) { + DRM_ERROR("failed to get enable gpio from DT\n"); + ret = PTR_ERR(pdata->enable_gpio); + return ret; + } + + ret = ti_sn65dsi86_parse_regulators(pdata); + if (ret) { + DRM_ERROR("failed to parse regulators\n"); + return ret; + } + + pdata->refclk = devm_clk_get_optional(dev, "refclk"); + if (IS_ERR(pdata->refclk)) + return PTR_ERR(pdata->refclk); + + pm_runtime_enable(dev); + ret = devm_add_action_or_reset(dev, ti_sn65dsi86_runtime_disable, dev); + if (ret) + return ret; + pm_runtime_set_autosuspend_delay(pdata->dev, 500); + pm_runtime_use_autosuspend(pdata->dev); + + ti_sn65dsi86_debugfs_init(pdata); + + /* + * Break ourselves up into a collection of aux devices. The only real + * motiviation here is to solve the chicken-and-egg problem of probe + * ordering. The bridge wants the panel to be there when it probes. + * The panel wants its HPD GPIO (provided by sn65dsi86 on some boards) + * when it probes. There will soon be other devices (DDC I2C bus, PWM) + * that have the same problem. Having sub-devices allows the some sub + * devices to finish probing even if others return -EPROBE_DEFER and + * gets us around the problems. + */ + + if (IS_ENABLED(CONFIG_OF_GPIO)) { + ret = ti_sn65dsi86_add_aux_device(pdata, &pdata->gpio_aux, "gpio"); + if (ret) + return ret; + } + + return ti_sn65dsi86_add_aux_device(pdata, &pdata->bridge_aux, "bridge"); } -static struct i2c_device_id ti_sn_bridge_id[] = { +static struct i2c_device_id ti_sn65dsi86_id[] = { { "ti,sn65dsi86", 0}, {}, }; -MODULE_DEVICE_TABLE(i2c, ti_sn_bridge_id); +MODULE_DEVICE_TABLE(i2c, ti_sn65dsi86_id); -static const struct of_device_id ti_sn_bridge_match_table[] = { +static const struct of_device_id ti_sn65dsi86_match_table[] = { {.compatible = "ti,sn65dsi86"}, {}, }; -MODULE_DEVICE_TABLE(of, ti_sn_bridge_match_table); +MODULE_DEVICE_TABLE(of, ti_sn65dsi86_match_table); -static struct i2c_driver ti_sn_bridge_driver = { +static struct i2c_driver ti_sn65dsi86_driver = { .driver = { .name = "ti_sn65dsi86", - .of_match_table = ti_sn_bridge_match_table, - .pm = &ti_sn_bridge_pm_ops, + .of_match_table = ti_sn65dsi86_match_table, + .pm = &ti_sn65dsi86_pm_ops, }, - .probe = ti_sn_bridge_probe, - .remove = ti_sn_bridge_remove, - .id_table = ti_sn_bridge_id, + .probe = ti_sn65dsi86_probe, + .id_table = ti_sn65dsi86_id, }; -module_i2c_driver(ti_sn_bridge_driver); + +static int __init ti_sn65dsi86_init(void) +{ + int ret; + + ret = i2c_add_driver(&ti_sn65dsi86_driver); + if (ret) + return ret; + + ret = ti_sn_gpio_register(); + if (ret) + goto err_main_was_registered; + + ret = auxiliary_driver_register(&ti_sn_bridge_driver); + if (ret) + goto err_gpio_was_registered; + + return 0; + +err_gpio_was_registered: + ti_sn_gpio_unregister(); +err_main_was_registered: + i2c_del_driver(&ti_sn65dsi86_driver); + + return ret; +} +module_init(ti_sn65dsi86_init); + +static void __exit ti_sn65dsi86_exit(void) +{ + auxiliary_driver_unregister(&ti_sn_bridge_driver); + ti_sn_gpio_unregister(); + i2c_del_driver(&ti_sn65dsi86_driver); +} +module_exit(ti_sn65dsi86_exit); MODULE_AUTHOR("Sandeep Panda <spanda@codeaurora.org>"); MODULE_DESCRIPTION("sn65dsi86 DSI to eDP bridge driver"); diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 5311d03d49cc..a4ad6fd13abc 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -35,9 +35,10 @@ #include <linux/pci.h> #include <linux/slab.h> +#if IS_ENABLED(CONFIG_AGP) #include <asm/agp.h> +#endif -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -45,6 +46,8 @@ #include "drm_legacy.h" +#if IS_ENABLED(CONFIG_AGP) + /* * Get AGP information. * @@ -53,7 +56,7 @@ * Verifies the AGP device has been initialized and acquired and fills in the * drm_agp_info structure with the information in drm_agp_head::agp_info. */ -int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info) +int drm_legacy_agp_info(struct drm_device *dev, struct drm_agp_info *info) { struct agp_kern_info *kern; @@ -73,15 +76,15 @@ int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info) return 0; } -EXPORT_SYMBOL(drm_agp_info); +EXPORT_SYMBOL(drm_legacy_agp_info); -int drm_agp_info_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_agp_info *info = data; int err; - err = drm_agp_info(dev, info); + err = drm_legacy_agp_info(dev, info); if (err) return err; @@ -97,7 +100,7 @@ int drm_agp_info_ioctl(struct drm_device *dev, void *data, * Verifies the AGP device hasn't been acquired before and calls * \c agp_backend_acquire. */ -int drm_agp_acquire(struct drm_device *dev) +int drm_legacy_agp_acquire(struct drm_device *dev) { struct pci_dev *pdev = to_pci_dev(dev->dev); @@ -111,7 +114,7 @@ int drm_agp_acquire(struct drm_device *dev) dev->agp->acquired = 1; return 0; } -EXPORT_SYMBOL(drm_agp_acquire); +EXPORT_SYMBOL(drm_legacy_agp_acquire); /* * Acquire the AGP device (ioctl). @@ -121,10 +124,10 @@ EXPORT_SYMBOL(drm_agp_acquire); * Verifies the AGP device hasn't been acquired before and calls * \c agp_backend_acquire. */ -int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); + return drm_legacy_agp_acquire((struct drm_device *)file_priv->minor->dev); } /* @@ -135,7 +138,7 @@ int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, * * Verifies the AGP device has been acquired and calls \c agp_backend_release. */ -int drm_agp_release(struct drm_device *dev) +int drm_legacy_agp_release(struct drm_device *dev) { if (!dev->agp || !dev->agp->acquired) return -EINVAL; @@ -143,12 +146,12 @@ int drm_agp_release(struct drm_device *dev) dev->agp->acquired = 0; return 0; } -EXPORT_SYMBOL(drm_agp_release); +EXPORT_SYMBOL(drm_legacy_agp_release); -int drm_agp_release_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - return drm_agp_release(dev); + return drm_legacy_agp_release(dev); } /* @@ -161,7 +164,7 @@ int drm_agp_release_ioctl(struct drm_device *dev, void *data, * Verifies the AGP device has been acquired but not enabled, and calls * \c agp_enable. */ -int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) +int drm_legacy_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) { if (!dev->agp || !dev->agp->acquired) return -EINVAL; @@ -171,14 +174,14 @@ int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) dev->agp->enabled = 1; return 0; } -EXPORT_SYMBOL(drm_agp_enable); +EXPORT_SYMBOL(drm_legacy_agp_enable); -int drm_agp_enable_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_agp_mode *mode = data; - return drm_agp_enable(dev, *mode); + return drm_legacy_agp_enable(dev, *mode); } /* @@ -189,7 +192,7 @@ int drm_agp_enable_ioctl(struct drm_device *dev, void *data, * Verifies the AGP device is present and has been acquired, allocates the * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it. */ -int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) +int drm_legacy_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) { struct drm_agp_mem *entry; struct agp_memory *memory; @@ -221,15 +224,15 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) return 0; } -EXPORT_SYMBOL(drm_agp_alloc); +EXPORT_SYMBOL(drm_legacy_agp_alloc); -int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, +int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_agp_buffer *request = data; - return drm_agp_alloc(dev, request); + return drm_legacy_agp_alloc(dev, request); } /* @@ -241,8 +244,8 @@ int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, * * Walks through drm_agp_head::memory until finding a matching handle. */ -static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device *dev, - unsigned long handle) +static struct drm_agp_mem *drm_legacy_agp_lookup_entry(struct drm_device *dev, + unsigned long handle) { struct drm_agp_mem *entry; @@ -261,14 +264,14 @@ static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device *dev, * Verifies the AGP device is present and acquired, looks-up the AGP memory * entry and passes it to the unbind_agp() function. */ -int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) +int drm_legacy_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) { struct drm_agp_mem *entry; int ret; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - entry = drm_agp_lookup_entry(dev, request->handle); + entry = drm_legacy_agp_lookup_entry(dev, request->handle); if (!entry || !entry->bound) return -EINVAL; ret = agp_unbind_memory(entry->memory); @@ -276,15 +279,15 @@ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) entry->bound = 0; return ret; } -EXPORT_SYMBOL(drm_agp_unbind); +EXPORT_SYMBOL(drm_legacy_agp_unbind); -int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_agp_binding *request = data; - return drm_agp_unbind(dev, request); + return drm_legacy_agp_unbind(dev, request); } /* @@ -296,7 +299,7 @@ int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, * is currently bound into the GATT. Looks-up the AGP memory entry and passes * it to bind_agp() function. */ -int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) +int drm_legacy_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) { struct drm_agp_mem *entry; int retcode; @@ -304,7 +307,7 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) if (!dev->agp || !dev->agp->acquired) return -EINVAL; - entry = drm_agp_lookup_entry(dev, request->handle); + entry = drm_legacy_agp_lookup_entry(dev, request->handle); if (!entry || entry->bound) return -EINVAL; page = DIV_ROUND_UP(request->offset, PAGE_SIZE); @@ -316,15 +319,15 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) dev->agp->base, entry->bound); return 0; } -EXPORT_SYMBOL(drm_agp_bind); +EXPORT_SYMBOL(drm_legacy_agp_bind); -int drm_agp_bind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_agp_binding *request = data; - return drm_agp_bind(dev, request); + return drm_legacy_agp_bind(dev, request); } /* @@ -337,13 +340,13 @@ int drm_agp_bind_ioctl(struct drm_device *dev, void *data, * unbind_agp(). Frees it via free_agp() as well as the entry itself * and unlinks from the doubly linked list it's inserted in. */ -int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) +int drm_legacy_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) { struct drm_agp_mem *entry; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - entry = drm_agp_lookup_entry(dev, request->handle); + entry = drm_legacy_agp_lookup_entry(dev, request->handle); if (!entry) return -EINVAL; if (entry->bound) @@ -355,15 +358,15 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) kfree(entry); return 0; } -EXPORT_SYMBOL(drm_agp_free); +EXPORT_SYMBOL(drm_legacy_agp_free); -int drm_agp_free_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_agp_buffer *request = data; - return drm_agp_free(dev, request); + return drm_legacy_agp_free(dev, request); } /* @@ -378,7 +381,7 @@ int drm_agp_free_ioctl(struct drm_device *dev, void *data, * Note that final cleanup of the kmalloced structure is directly done in * drm_pci_agp_destroy. */ -struct drm_agp_head *drm_agp_init(struct drm_device *dev) +struct drm_agp_head *drm_legacy_agp_init(struct drm_device *dev) { struct pci_dev *pdev = to_pci_dev(dev->dev); struct drm_agp_head *head = NULL; @@ -409,7 +412,7 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev) return head; } /* Only exported for i810.ko */ -EXPORT_SYMBOL(drm_agp_init); +EXPORT_SYMBOL(drm_legacy_agp_init); /** * drm_legacy_agp_clear - Clear AGP resource list @@ -439,8 +442,10 @@ void drm_legacy_agp_clear(struct drm_device *dev) INIT_LIST_HEAD(&dev->agp->memory); if (dev->agp->acquired) - drm_agp_release(dev); + drm_legacy_agp_release(dev); dev->agp->acquired = 0; dev->agp->enabled = 0; } + +#endif diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c new file mode 100644 index 000000000000..9335d9d6cf9a --- /dev/null +++ b/drivers/gpu/drm/drm_aperture.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: MIT + +#include <linux/device.h> +#include <linux/fb.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/platform_device.h> /* for firmware helpers */ +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/vgaarb.h> + +#include <drm/drm_aperture.h> +#include <drm/drm_drv.h> +#include <drm/drm_print.h> + +/** + * DOC: overview + * + * A graphics device might be supported by different drivers, but only one + * driver can be active at any given time. Many systems load a generic + * graphics drivers, such as EFI-GOP or VESA, early during the boot process. + * During later boot stages, they replace the generic driver with a dedicated, + * hardware-specific driver. To take over the device the dedicated driver + * first has to remove the generic driver. DRM aperture functions manage + * ownership of DRM framebuffer memory and hand-over between drivers. + * + * DRM drivers should call drm_aperture_remove_conflicting_framebuffers() + * at the top of their probe function. The function removes any generic + * driver that is currently associated with the given framebuffer memory. + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the + * example given below. + * + * .. code-block:: c + * + * static int remove_conflicting_framebuffers(struct pci_dev *pdev) + * { + * bool primary = false; + * resource_size_t base, size; + * int ret; + * + * base = pci_resource_start(pdev, 0); + * size = pci_resource_len(pdev, 0); + * #ifdef CONFIG_X86 + * primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; + * #endif + * + * return drm_aperture_remove_conflicting_framebuffers(base, size, primary, + * "example driver"); + * } + * + * static int probe(struct pci_dev *pdev) + * { + * int ret; + * + * // Remove any generic drivers... + * ret = remove_conflicting_framebuffers(pdev); + * if (ret) + * return ret; + * + * // ... and initialize the hardware. + * ... + * + * drm_dev_register(); + * + * return 0; + * } + * + * PCI device drivers should call + * drm_aperture_remove_conflicting_pci_framebuffers() and let it detect the + * framebuffer apertures automatically. Device drivers without knowledge of + * the framebuffer's location shall call drm_aperture_remove_framebuffers(), + * which removes all drivers for known framebuffer. + * + * Drivers that are susceptible to being removed by other drivers, such as + * generic EFI or VESA drivers, have to register themselves as owners of their + * given framebuffer memory. Ownership of the framebuffer memory is achived + * by calling devm_aperture_acquire_from_firmware(). On success, the driver + * is the owner of the framebuffer range. The function fails if the + * framebuffer is already by another driver. See below for an example. + * + * .. code-block:: c + * + * static int acquire_framebuffers(struct drm_device *dev, struct platform_device *pdev) + * { + * resource_size_t base, size; + * + * mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + * if (!mem) + * return -EINVAL; + * base = mem->start; + * size = resource_size(mem); + * + * return devm_acquire_aperture_from_firmware(dev, base, size); + * } + * + * static int probe(struct platform_device *pdev) + * { + * struct drm_device *dev; + * int ret; + * + * // ... Initialize the device... + * dev = devm_drm_dev_alloc(); + * ... + * + * // ... and acquire ownership of the framebuffer. + * ret = acquire_framebuffers(dev, pdev); + * if (ret) + * return ret; + * + * drm_dev_register(dev, 0); + * + * return 0; + * } + * + * The generic driver is now subject to forced removal by other drivers. This + * only works for platform drivers that support hot unplug. + * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al + * for the registered framebuffer range, the aperture helpers call + * platform_device_unregister() and the generic driver unloads itself. It + * may not access the device's registers, framebuffer memory, ROM, etc + * afterwards. + */ + +struct drm_aperture { + struct drm_device *dev; + resource_size_t base; + resource_size_t size; + struct list_head lh; + void (*detach)(struct drm_device *dev); +}; + +static LIST_HEAD(drm_apertures); +static DEFINE_MUTEX(drm_apertures_lock); + +static bool overlap(resource_size_t base1, resource_size_t end1, + resource_size_t base2, resource_size_t end2) +{ + return (base1 < end2) && (end1 > base2); +} + +static void devm_aperture_acquire_release(void *data) +{ + struct drm_aperture *ap = data; + bool detached = !ap->dev; + + if (detached) + return; + + mutex_lock(&drm_apertures_lock); + list_del(&ap->lh); + mutex_unlock(&drm_apertures_lock); +} + +static int devm_aperture_acquire(struct drm_device *dev, + resource_size_t base, resource_size_t size, + void (*detach)(struct drm_device *)) +{ + size_t end = base + size; + struct list_head *pos; + struct drm_aperture *ap; + + mutex_lock(&drm_apertures_lock); + + list_for_each(pos, &drm_apertures) { + ap = container_of(pos, struct drm_aperture, lh); + if (overlap(base, end, ap->base, ap->base + ap->size)) { + mutex_unlock(&drm_apertures_lock); + return -EBUSY; + } + } + + ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL); + if (!ap) { + mutex_unlock(&drm_apertures_lock); + return -ENOMEM; + } + + ap->dev = dev; + ap->base = base; + ap->size = size; + ap->detach = detach; + INIT_LIST_HEAD(&ap->lh); + + list_add(&ap->lh, &drm_apertures); + + mutex_unlock(&drm_apertures_lock); + + return devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap); +} + +static void drm_aperture_detach_firmware(struct drm_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev); + + /* + * Remove the device from the device hierarchy. This is the right thing + * to do for firmware-based DRM drivers, such as EFI, VESA or VGA. After + * the new driver takes over the hardware, the firmware device's state + * will be lost. + * + * For non-platform devices, a new callback would be required. + * + * If the aperture helpers ever need to handle native drivers, this call + * would only have to unplug the DRM device, so that the hardware device + * stays around after detachment. + */ + platform_device_unregister(pdev); +} + +/** + * devm_aperture_acquire_from_firmware - Acquires ownership of a firmware framebuffer + * on behalf of a DRM driver. + * @dev: the DRM device to own the framebuffer memory + * @base: the framebuffer's byte offset in physical memory + * @size: the framebuffer size in bytes + * + * Installs the given device as the new owner of the framebuffer. The function + * expects the framebuffer to be provided by a platform device that has been + * set up by firmware. Firmware can be any generic interface, such as EFI, + * VESA, VGA, etc. If the native hardware driver takes over ownership of the + * framebuffer range, the firmware state gets lost. Aperture helpers will then + * unregister the platform device automatically. Acquired apertures are + * released automatically if the underlying device goes away. + * + * The function fails if the framebuffer range, or parts of it, is currently + * owned by another driver. To evict current owners, callers should use + * drm_aperture_remove_conflicting_framebuffers() et al. before calling this + * function. The function also fails if the given device is not a platform + * device. + * + * Returns: + * 0 on success, or a negative errno value otherwise. + */ +int devm_aperture_acquire_from_firmware(struct drm_device *dev, resource_size_t base, + resource_size_t size) +{ + if (drm_WARN_ON(dev, !dev_is_platform(dev->dev))) + return -EINVAL; + + return devm_aperture_acquire(dev, base, size, drm_aperture_detach_firmware); +} +EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); + +static void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size) +{ + resource_size_t end = base + size; + struct list_head *pos, *n; + + mutex_lock(&drm_apertures_lock); + + list_for_each_safe(pos, n, &drm_apertures) { + struct drm_aperture *ap = + container_of(pos, struct drm_aperture, lh); + struct drm_device *dev = ap->dev; + + if (WARN_ON_ONCE(!dev)) + continue; + + if (!overlap(base, end, ap->base, ap->base + ap->size)) + continue; + + ap->dev = NULL; /* detach from device */ + list_del(&ap->lh); + + ap->detach(dev); + } + + mutex_unlock(&drm_apertures_lock); +} + +/** + * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range + * @base: the aperture's base address in physical memory + * @size: aperture size in bytes + * @primary: also kick vga16fb if present + * @name: requesting driver name + * + * This function removes graphics device drivers which use memory range described by + * @base and @size. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, + bool primary, const char *name) +{ +#if IS_REACHABLE(CONFIG_FB) + struct apertures_struct *a; + int ret; + + a = alloc_apertures(1); + if (!a) + return -ENOMEM; + + a->ranges[0].base = base; + a->ranges[0].size = size; + + ret = remove_conflicting_framebuffers(a, name, primary); + kfree(a); + + if (ret) + return ret; +#endif + + drm_aperture_detach_drivers(base, size); + + return 0; +} +EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); + +/** + * drm_aperture_remove_conflicting_pci_framebuffers - remove existing framebuffers for PCI devices + * @pdev: PCI device + * @name: requesting driver name + * + * This function removes graphics device drivers using memory range configured + * for any of @pdev's memory bars. The function assumes that PCI device with + * shadowed ROM drives a primary display and so kicks out vga16fb. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name) +{ + resource_size_t base, size; + int bar, ret = 0; + + for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) { + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) + continue; + base = pci_resource_start(pdev, bar); + size = pci_resource_len(pdev, bar); + drm_aperture_detach_drivers(base, size); + } + + /* + * WARNING: Apparently we must kick fbdev drivers before vgacon, + * otherwise the vga fbdev driver falls over. + */ +#if IS_REACHABLE(CONFIG_FB) + ret = remove_conflicting_pci_framebuffers(pdev, name); +#endif + if (ret == 0) + ret = vga_remove_vgacon(pdev); + return ret; +} +EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index dd9ed000ad4c..a8bbb021684b 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -385,7 +385,8 @@ static int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state, /* The state->enable vs. state->mode_blob checks can be WARN_ON, * as this is a kernel-internal detail that userspace should never - * be able to trigger. */ + * be able to trigger. + */ if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled without mode blob\n", @@ -1302,8 +1303,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) struct drm_crtc_state *new_crtc_state; struct drm_connector *conn; struct drm_connector_state *conn_state; - unsigned requested_crtc = 0; - unsigned affected_crtc = 0; + unsigned int requested_crtc = 0; + unsigned int affected_crtc = 0; int i, ret = 0; DRM_DEBUG_ATOMIC("checking %p\n", state); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f2b3e28d938b..bc3487964fb5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -106,7 +106,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct drm_encoder *encoder; - unsigned encoder_mask = 0; + unsigned int encoder_mask = 0; int i, ret = 0; /* @@ -609,7 +609,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_connector *connector; struct drm_connector_state *old_connector_state, *new_connector_state; int i, ret; - unsigned connectors_mask = 0; + unsigned int connectors_mask = 0; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { bool has_connectors = @@ -1018,8 +1018,10 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) struct drm_encoder *encoder; struct drm_bridge *bridge; - /* Shut down everything that's in the changeset and currently - * still on. So need to check the old, saved state. */ + /* + * Shut down everything that's in the changeset and currently + * still on. So need to check the old, saved state. + */ if (!old_conn_state->crtc) continue; @@ -1409,7 +1411,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); * @dev: DRM device * @state: atomic state object with old state structures * @pre_swap: If true, do an interruptible wait, and @state is the new state. - * Otherwise @state is the old state. + * Otherwise @state is the old state. * * For implicit sync, driver should fish the exclusive fence out from the * incoming fb's and stash it in the drm_plane_state. This is called after @@ -1478,7 +1480,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; int i, ret; - unsigned crtc_mask = 0; + unsigned int crtc_mask = 0; /* * Legacy cursor ioctls are completely unsynced, and userspace @@ -1953,8 +1955,10 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock) list_for_each_entry(commit, &crtc->commit_list, commit_entry) { if (i == 0) { completed = try_wait_for_completion(&commit->flip_done); - /* Userspace is not allowed to get ahead of the previous - * commit with nonblocking ones. */ + /* + * Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. + */ if (!completed && nonblock) { spin_unlock(&crtc->commit_lock); DRM_DEBUG_ATOMIC("[CRTC:%d:%s] busy with a previous commit\n", @@ -2103,9 +2107,11 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, if (ret) return ret; - /* Drivers only send out events when at least either current or + /* + * Drivers only send out events when at least either current or * new CRTC state is active. Complete right away if everything - * stays off. */ + * stays off. + */ if (!old_crtc_state->active && !new_crtc_state->active) { complete_all(&commit->flip_done); continue; @@ -2137,8 +2143,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, } for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { - /* Userspace is not allowed to get ahead of the previous - * commit with nonblocking ones. */ + /* + * Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. + */ if (nonblock && old_conn_state->commit && !try_wait_for_completion(&old_conn_state->commit->flip_done)) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] busy with a previous commit\n", @@ -2156,8 +2164,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, } for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { - /* Userspace is not allowed to get ahead of the previous - * commit with nonblocking ones. */ + /* + * Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. + */ if (nonblock && old_plane_state->commit && !try_wait_for_completion(&old_plane_state->commit->flip_done)) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] busy with a previous commit\n", @@ -2575,7 +2585,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); struct drm_plane *plane; - unsigned plane_mask; + unsigned int plane_mask; plane_mask = old_crtc_state->plane_mask; plane_mask |= new_crtc_state->plane_mask; diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 268bb69c2e2f..438e9585b225 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -78,8 +78,8 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, drm_mode_convert_to_umode(&umode, mode); state->mode_blob = drm_property_create_blob(state->crtc->dev, - sizeof(umode), - &umode); + sizeof(umode), + &umode); if (IS_ERR(state->mode_blob)) return PTR_ERR(state->mode_blob); @@ -114,7 +114,7 @@ EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); * Zero on success, error code on failure. Cannot return -EDEADLK. */ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, - struct drm_property_blob *blob) + struct drm_property_blob *blob) { struct drm_crtc *crtc = state->crtc; diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index f2d46b7ac6f9..f00e5abdbbf4 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -300,7 +300,8 @@ int drm_master_open(struct drm_file *file_priv) int ret = 0; /* if there is no current master make this fd it, but do not create - * any master object for render clients */ + * any master object for render clients + */ mutex_lock(&dev->master_mutex); if (!dev->master) ret = drm_new_set_master(dev, file_priv); diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 26e2f2ffd255..ec37cbfabb50 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -328,8 +328,8 @@ unsigned int drm_rotation_simplify(unsigned int rotation, if (rotation & ~supported_rotations) { rotation ^= DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; rotation = (rotation & DRM_MODE_REFLECT_MASK) | - BIT((ffs(rotation & DRM_MODE_ROTATE_MASK) + 1) - % 4); + BIT((ffs(rotation & DRM_MODE_ROTATE_MASK) + 1) + % 4); } return rotation; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 64f0effb52ac..044acd07c153 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -522,6 +522,9 @@ void drm_bridge_chain_pre_enable(struct drm_bridge *bridge) list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { if (iter->funcs->pre_enable) iter->funcs->pre_enable(iter); + + if (iter == bridge) + break; } } EXPORT_SYMBOL(drm_bridge_chain_pre_enable); diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index e3d77dfefb0a..4805726b34ac 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -40,7 +40,6 @@ #include <asm/shmparam.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -79,7 +78,7 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, return entry; break; default: /* Make gcc happy */ - ; + break; } if (entry->map->offset == map->offset) return entry; @@ -325,7 +324,8 @@ static int drm_addmap_core(struct drm_device *dev, resource_size_t offset, /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, * As we're limiting the address to 2^32-1 (or less), * casting it down to 32 bits is no problem, but we - * need to point to a 64bit variable first. */ + * need to point to a 64bit variable first. + */ map->handle = dma_alloc_coherent(dev->dev, map->size, &map->offset, @@ -674,12 +674,17 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, static void drm_cleanup_buf_error(struct drm_device *dev, struct drm_buf_entry *entry) { + drm_dma_handle_t *dmah; int i; if (entry->seg_count) { for (i = 0; i < entry->seg_count; i++) { if (entry->seglist[i]) { - drm_pci_free(dev, entry->seglist[i]); + dmah = entry->seglist[i]; + dma_free_coherent(dev->dev, + dmah->size, + dmah->vaddr, + dmah->busaddr); } } kfree(entry->seglist); @@ -978,10 +983,18 @@ int drm_legacy_addbufs_pci(struct drm_device *dev, page_count = 0; while (entry->buf_count < count) { + dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); + if (!dmah) + return -ENOMEM; - dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000); + dmah->size = total; + dmah->vaddr = dma_alloc_coherent(dev->dev, + dmah->size, + &dmah->busaddr, + GFP_KERNEL); + if (!dmah->vaddr) { + kfree(dmah); - if (!dmah) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 7631f76e7f34..da39e7ff6965 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -20,6 +20,7 @@ * OF THIS SOFTWARE. */ +#include <drm/drm_auth.h> #include <drm/drm_connector.h> #include <drm/drm_edid.h> #include <drm/drm_encoder.h> @@ -279,7 +280,8 @@ int drm_connector_init(struct drm_device *dev, drm_connector_get_cmdline_mode(connector); /* We should add connectors at the end to avoid upsetting the connector - * index too much. */ + * index too much. + */ spin_lock_irq(&config->connector_list_lock); list_add_tail(&connector->head, &config->connector_list); config->num_connector++; @@ -1958,11 +1960,11 @@ int drm_connector_set_path_property(struct drm_connector *connector, int ret; ret = drm_property_replace_global_blob(dev, - &connector->path_blob_ptr, - strlen(path) + 1, - path, - &connector->base, - dev->mode_config.path_property); + &connector->path_blob_ptr, + strlen(path) + 1, + path, + &connector->base, + dev->mode_config.path_property); return ret; } EXPORT_SYMBOL(drm_connector_set_path_property); @@ -1988,11 +1990,11 @@ int drm_connector_set_tile_property(struct drm_connector *connector) if (!connector->has_tile) { ret = drm_property_replace_global_blob(dev, - &connector->tile_blob_ptr, - 0, - NULL, - &connector->base, - dev->mode_config.tile_property); + &connector->tile_blob_ptr, + 0, + NULL, + &connector->base, + dev->mode_config.tile_property); return ret; } @@ -2003,11 +2005,11 @@ int drm_connector_set_tile_property(struct drm_connector *connector) connector->tile_h_size, connector->tile_v_size); ret = drm_property_replace_global_blob(dev, - &connector->tile_blob_ptr, - strlen(tile) + 1, - tile, - &connector->base, - dev->mode_config.tile_property); + &connector->tile_blob_ptr, + strlen(tile) + 1, + tile, + &connector->base, + dev->mode_config.tile_property); return ret; } EXPORT_SYMBOL(drm_connector_set_tile_property); @@ -2076,10 +2078,10 @@ int drm_connector_update_edid_property(struct drm_connector *connector, ret = drm_property_replace_global_blob(dev, &connector->edid_blob_ptr, - size, - edid, - &connector->base, - dev->mode_config.edid_property); + size, + edid, + &connector->base, + dev->mode_config.edid_property); if (ret) return ret; return drm_connector_set_tile_property(connector); @@ -2151,6 +2153,75 @@ int drm_connector_attach_max_bpc_property(struct drm_connector *connector, EXPORT_SYMBOL(drm_connector_attach_max_bpc_property); /** + * drm_connector_attach_hdr_output_metadata_property - attach "HDR_OUTPUT_METADA" property + * @connector: connector to attach the property on. + * + * This is used to allow the userspace to send HDR Metadata to the + * driver. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_property *prop = dev->mode_config.hdr_output_metadata_property; + + drm_object_attach_property(&connector->base, prop, 0); + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_hdr_output_metadata_property); + +/** + * drm_connector_attach_colorspace_property - attach "Colorspace" property + * @connector: connector to attach the property on. + * + * This is used to allow the userspace to signal the output colorspace + * to the driver. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_colorspace_property(struct drm_connector *connector) +{ + struct drm_property *prop = connector->colorspace_property; + + drm_object_attach_property(&connector->base, prop, DRM_MODE_COLORIMETRY_DEFAULT); + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_colorspace_property); + +/** + * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed + * @old_state: old connector state to compare + * @new_state: new connector state to compare + * + * This is used by HDR-enabled drivers to test whether the HDR metadata + * have changed between two different connector state (and thus probably + * requires a full blown mode change). + * + * Returns: + * True if the metadata are equal, False otherwise + */ +bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, + struct drm_connector_state *new_state) +{ + struct drm_property_blob *old_blob = old_state->hdr_output_metadata; + struct drm_property_blob *new_blob = new_state->hdr_output_metadata; + + if (!old_blob || !new_blob) + return old_blob == new_blob; + + if (old_blob->length != new_blob->length) + return false; + + return !memcmp(old_blob->data, new_blob->data, old_blob->length); +} +EXPORT_SYMBOL(drm_connector_atomic_hdr_metadata_equal); + +/** * drm_connector_set_vrr_capable_property - sets the variable refresh rate * capable property for a connector * @connector: drm connector @@ -2288,7 +2359,8 @@ int drm_connector_property_set_ioctl(struct drm_device *dev, static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) { /* For atomic drivers only state objects are synchronously updated and - * protected by modeset locks, so check those first. */ + * protected by modeset locks, so check those first. + */ if (connector->state) return connector->state->best_encoder; return connector->encoder; @@ -2374,9 +2446,13 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); if (out_resp->count_modes == 0) { - connector->funcs->fill_modes(connector, - dev->mode_config.max_width, - dev->mode_config.max_height); + if (drm_is_current_master(file_priv)) + connector->funcs->fill_modes(connector, + dev->mode_config.max_width, + dev->mode_config.max_height); + else + drm_dbg_kms(dev, "User-space requested a forced probe on [CONNECTOR:%d:%s] but is not the DRM master, demoting to read-only probe", + connector->base.id, connector->name); } out_resp->mm_width = connector->display_info.width_mm; @@ -2450,7 +2526,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out_resp->encoder_id = 0; /* Only grab properties after probing, to make sure EDID and other - * properties reflect the latest status. */ + * properties reflect the latest status. + */ ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic, (uint32_t __user *)(unsigned long)(out_resp->props_ptr), (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index c99be950bf17..c6e6a3e7219a 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -124,7 +124,7 @@ void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev) } /** - * drm_ctxbitmap_flush() - Flush all contexts owned by a file + * drm_legacy_ctxbitmap_flush() - Flush all contexts owned by a file * @dev: DRM device to operate on * @file: Open file to flush contexts for * @@ -312,7 +312,8 @@ static int drm_context_switch_complete(struct drm_device *dev, /* If a context switch is ever initiated when the kernel holds the lock, release - that lock here. */ + that lock here. + */ clear_bit(0, &dev->context_flag); return 0; diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c index d07ba54ec945..eb6b741a6f99 100644 --- a/drivers/gpu/drm/drm_dma.c +++ b/drivers/gpu/drm/drm_dma.c @@ -81,6 +81,7 @@ int drm_legacy_dma_setup(struct drm_device *dev) void drm_legacy_dma_takedown(struct drm_device *dev) { struct drm_device_dma *dma = dev->dma; + drm_dma_handle_t *dmah; int i, j; if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || @@ -100,7 +101,12 @@ void drm_legacy_dma_takedown(struct drm_device *dev) dma->bufs[i].seg_count); for (j = 0; j < dma->bufs[i].seg_count; j++) { if (dma->bufs[i].seglist[j]) { - drm_pci_free(dev, dma->bufs[i].seglist[j]); + dmah = dma->bufs[i].seglist[j]; + dma_free_coherent(dev->dev, + dmah->size, + dmah->vaddr, + dmah->busaddr); + kfree(dmah); } } kfree(dma->bufs[i].seglist); diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c index e25181bf2c48..06b374cae956 100644 --- a/drivers/gpu/drm/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/drm_dp_aux_dev.c @@ -278,6 +278,12 @@ void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) if (!aux_dev) /* attach must have failed */ return; + /* + * As some AUX adapters may exist as platform devices which outlive their respective DRM + * devices, we clear drm_dev to ensure that we never accidentally reference a stale pointer + */ + aux->drm_dev = NULL; + mutex_lock(&aux_idr_mutex); idr_remove(&aux_idr, aux_dev->index); mutex_unlock(&aux_idr_mutex); diff --git a/drivers/gpu/drm/drm_dp_dual_mode_helper.c b/drivers/gpu/drm/drm_dp_dual_mode_helper.c index 1c9ea9f7fdaf..9faf49354cab 100644 --- a/drivers/gpu/drm/drm_dp_dual_mode_helper.c +++ b/drivers/gpu/drm/drm_dp_dual_mode_helper.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/string.h> +#include <drm/drm_device.h> #include <drm/drm_dp_dual_mode_helper.h> #include <drm/drm_print.h> @@ -165,6 +166,7 @@ static bool is_lspcon_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN], /** * drm_dp_dual_mode_detect - Identify the DP dual mode adaptor + * @dev: &drm_device to use * @adapter: I2C adapter for the DDC bus * * Attempt to identify the type of the DP dual mode adaptor used. @@ -178,7 +180,8 @@ static bool is_lspcon_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN], * Returns: * The type of the DP dual mode adaptor used */ -enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter) +enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev, + struct i2c_adapter *adapter) { char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN] = {}; uint8_t adaptor_id = 0x00; @@ -200,8 +203,8 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter) */ ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_HDMI_ID, hdmi_id, sizeof(hdmi_id)); - DRM_DEBUG_KMS("DP dual mode HDMI ID: %*pE (err %zd)\n", - ret ? 0 : (int)sizeof(hdmi_id), hdmi_id, ret); + drm_dbg_kms(dev, "DP dual mode HDMI ID: %*pE (err %zd)\n", + ret ? 0 : (int)sizeof(hdmi_id), hdmi_id, ret); if (ret) return DRM_DP_DUAL_MODE_UNKNOWN; @@ -219,8 +222,7 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter) */ ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID, &adaptor_id, sizeof(adaptor_id)); - DRM_DEBUG_KMS("DP dual mode adaptor ID: %02x (err %zd)\n", - adaptor_id, ret); + drm_dbg_kms(dev, "DP dual mode adaptor ID: %02x (err %zd)\n", adaptor_id, ret); if (ret == 0) { if (is_lspcon_adaptor(hdmi_id, adaptor_id)) return DRM_DP_DUAL_MODE_LSPCON; @@ -236,8 +238,7 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter) * that we may have misdetected the type. */ if (!is_type1_adaptor(adaptor_id) && adaptor_id != hdmi_id[0]) - DRM_ERROR("Unexpected DP dual mode adaptor ID %02x\n", - adaptor_id); + drm_err(dev, "Unexpected DP dual mode adaptor ID %02x\n", adaptor_id); } @@ -250,6 +251,7 @@ EXPORT_SYMBOL(drm_dp_dual_mode_detect); /** * drm_dp_dual_mode_max_tmds_clock - Max TMDS clock for DP dual mode adaptor + * @dev: &drm_device to use * @type: DP dual mode adaptor type * @adapter: I2C adapter for the DDC bus * @@ -263,7 +265,7 @@ EXPORT_SYMBOL(drm_dp_dual_mode_detect); * Returns: * Maximum supported TMDS clock rate for the DP dual mode adaptor in kHz. */ -int drm_dp_dual_mode_max_tmds_clock(enum drm_dp_dual_mode_type type, +int drm_dp_dual_mode_max_tmds_clock(const struct drm_device *dev, enum drm_dp_dual_mode_type type, struct i2c_adapter *adapter) { uint8_t max_tmds_clock; @@ -283,7 +285,7 @@ int drm_dp_dual_mode_max_tmds_clock(enum drm_dp_dual_mode_type type, ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_MAX_TMDS_CLOCK, &max_tmds_clock, sizeof(max_tmds_clock)); if (ret || max_tmds_clock == 0x00 || max_tmds_clock == 0xff) { - DRM_DEBUG_KMS("Failed to query max TMDS clock\n"); + drm_dbg_kms(dev, "Failed to query max TMDS clock\n"); return 165000; } @@ -293,6 +295,7 @@ EXPORT_SYMBOL(drm_dp_dual_mode_max_tmds_clock); /** * drm_dp_dual_mode_get_tmds_output - Get the state of the TMDS output buffers in the DP dual mode adaptor + * @dev: &drm_device to use * @type: DP dual mode adaptor type * @adapter: I2C adapter for the DDC bus * @enabled: current state of the TMDS output buffers @@ -307,8 +310,8 @@ EXPORT_SYMBOL(drm_dp_dual_mode_max_tmds_clock); * Returns: * 0 on success, negative error code on failure */ -int drm_dp_dual_mode_get_tmds_output(enum drm_dp_dual_mode_type type, - struct i2c_adapter *adapter, +int drm_dp_dual_mode_get_tmds_output(const struct drm_device *dev, + enum drm_dp_dual_mode_type type, struct i2c_adapter *adapter, bool *enabled) { uint8_t tmds_oen; @@ -322,7 +325,7 @@ int drm_dp_dual_mode_get_tmds_output(enum drm_dp_dual_mode_type type, ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN, &tmds_oen, sizeof(tmds_oen)); if (ret) { - DRM_DEBUG_KMS("Failed to query state of TMDS output buffers\n"); + drm_dbg_kms(dev, "Failed to query state of TMDS output buffers\n"); return ret; } @@ -334,6 +337,7 @@ EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output); /** * drm_dp_dual_mode_set_tmds_output - Enable/disable TMDS output buffers in the DP dual mode adaptor + * @dev: &drm_device to use * @type: DP dual mode adaptor type * @adapter: I2C adapter for the DDC bus * @enable: enable (as opposed to disable) the TMDS output buffers @@ -347,7 +351,7 @@ EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output); * Returns: * 0 on success, negative error code on failure */ -int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type, +int drm_dp_dual_mode_set_tmds_output(const struct drm_device *dev, enum drm_dp_dual_mode_type type, struct i2c_adapter *adapter, bool enable) { uint8_t tmds_oen = enable ? 0 : DP_DUAL_MODE_TMDS_DISABLE; @@ -367,18 +371,17 @@ int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type, ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN, &tmds_oen, sizeof(tmds_oen)); if (ret) { - DRM_DEBUG_KMS("Failed to %s TMDS output buffers (%d attempts)\n", - enable ? "enable" : "disable", - retry + 1); + drm_dbg_kms(dev, "Failed to %s TMDS output buffers (%d attempts)\n", + enable ? "enable" : "disable", retry + 1); return ret; } ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN, &tmp, sizeof(tmp)); if (ret) { - DRM_DEBUG_KMS("I2C read failed during TMDS output buffer %s (%d attempts)\n", - enable ? "enabling" : "disabling", - retry + 1); + drm_dbg_kms(dev, + "I2C read failed during TMDS output buffer %s (%d attempts)\n", + enable ? "enabling" : "disabling", retry + 1); return ret; } @@ -386,8 +389,8 @@ int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type, return 0; } - DRM_DEBUG_KMS("I2C write value mismatch during TMDS output buffer %s\n", - enable ? "enabling" : "disabling"); + drm_dbg_kms(dev, "I2C write value mismatch during TMDS output buffer %s\n", + enable ? "enabling" : "disabling"); return -EIO; } @@ -425,6 +428,7 @@ EXPORT_SYMBOL(drm_dp_get_dual_mode_type_name); /** * drm_lspcon_get_mode: Get LSPCON's current mode of operation by * reading offset (0x80, 0x41) + * @dev: &drm_device to use * @adapter: I2C-over-aux adapter * @mode: current lspcon mode of operation output variable * @@ -432,7 +436,7 @@ EXPORT_SYMBOL(drm_dp_get_dual_mode_type_name); * 0 on success, sets the current_mode value to appropriate mode * -error on failure */ -int drm_lspcon_get_mode(struct i2c_adapter *adapter, +int drm_lspcon_get_mode(const struct drm_device *dev, struct i2c_adapter *adapter, enum drm_lspcon_mode *mode) { u8 data; @@ -440,7 +444,7 @@ int drm_lspcon_get_mode(struct i2c_adapter *adapter, int retry; if (!mode) { - DRM_ERROR("NULL input\n"); + drm_err(dev, "NULL input\n"); return -EINVAL; } @@ -457,7 +461,7 @@ int drm_lspcon_get_mode(struct i2c_adapter *adapter, } if (ret < 0) { - DRM_DEBUG_KMS("LSPCON read(0x80, 0x41) failed\n"); + drm_dbg_kms(dev, "LSPCON read(0x80, 0x41) failed\n"); return -EFAULT; } @@ -472,13 +476,14 @@ EXPORT_SYMBOL(drm_lspcon_get_mode); /** * drm_lspcon_set_mode: Change LSPCON's mode of operation by * writing offset (0x80, 0x40) + * @dev: &drm_device to use * @adapter: I2C-over-aux adapter * @mode: required mode of operation * * Returns: * 0 on success, -error on failure/timeout */ -int drm_lspcon_set_mode(struct i2c_adapter *adapter, +int drm_lspcon_set_mode(const struct drm_device *dev, struct i2c_adapter *adapter, enum drm_lspcon_mode mode) { u8 data = 0; @@ -493,7 +498,7 @@ int drm_lspcon_set_mode(struct i2c_adapter *adapter, ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_LSPCON_MODE_CHANGE, &data, sizeof(data)); if (ret < 0) { - DRM_ERROR("LSPCON mode change failed\n"); + drm_err(dev, "LSPCON mode change failed\n"); return ret; } @@ -503,24 +508,23 @@ int drm_lspcon_set_mode(struct i2c_adapter *adapter, * so wait and retry until time out or done. */ do { - ret = drm_lspcon_get_mode(adapter, ¤t_mode); + ret = drm_lspcon_get_mode(dev, adapter, ¤t_mode); if (ret) { - DRM_ERROR("can't confirm LSPCON mode change\n"); + drm_err(dev, "can't confirm LSPCON mode change\n"); return ret; } else { if (current_mode != mode) { msleep(10); time_out -= 10; } else { - DRM_DEBUG_KMS("LSPCON mode changed to %s\n", - mode == DRM_LSPCON_MODE_LS ? - "LS" : "PCON"); + drm_dbg_kms(dev, "LSPCON mode changed to %s\n", + mode == DRM_LSPCON_MODE_LS ? "LS" : "PCON"); return 0; } } } while (time_out); - DRM_ERROR("LSPCON mode change timed out\n"); + drm_err(dev, "LSPCON mode change timed out\n"); return -ETIMEDOUT; } EXPORT_SYMBOL(drm_lspcon_set_mode); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index cb2f53e56685..55b53df6ce34 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -132,14 +132,15 @@ u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZ } EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor); -void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { unsigned long rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & DP_TRAINING_AUX_RD_MASK; if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %lu, out of range (max 4)\n", - rd_interval); + drm_dbg_kms(aux->drm_dev, "%s: AUX interval %lu, out of range (max 4)\n", + aux->name, rd_interval); if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) rd_interval = 100; @@ -150,11 +151,12 @@ void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); -static void __drm_dp_link_train_channel_eq_delay(unsigned long rd_interval) +static void __drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + unsigned long rd_interval) { if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %lu, out of range (max 4)\n", - rd_interval); + drm_dbg_kms(aux->drm_dev, "%s: AUX interval %lu, out of range (max 4)\n", + aux->name, rd_interval); if (rd_interval == 0) rd_interval = 400; @@ -164,9 +166,11 @@ static void __drm_dp_link_train_channel_eq_delay(unsigned long rd_interval) usleep_range(rd_interval, rd_interval * 2); } -void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +void drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - __drm_dp_link_train_channel_eq_delay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + __drm_dp_link_train_channel_eq_delay(aux, + dpcd[DP_TRAINING_AUX_RD_INTERVAL] & DP_TRAINING_AUX_RD_MASK); } EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); @@ -182,13 +186,14 @@ static u8 dp_lttpr_phy_cap(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE], int r) return phy_cap[r - DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1]; } -void drm_dp_lttpr_link_train_channel_eq_delay(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE]) +void drm_dp_lttpr_link_train_channel_eq_delay(const struct drm_dp_aux *aux, + const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE]) { u8 interval = dp_lttpr_phy_cap(phy_cap, DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) & DP_TRAINING_AUX_RD_MASK; - __drm_dp_link_train_channel_eq_delay(interval); + __drm_dp_link_train_channel_eq_delay(aux, interval); } EXPORT_SYMBOL(drm_dp_lttpr_link_train_channel_eq_delay); @@ -215,11 +220,11 @@ drm_dp_dump_access(const struct drm_dp_aux *aux, const char *arrow = request == DP_AUX_NATIVE_READ ? "->" : "<-"; if (ret > 0) - DRM_DEBUG_DP("%s: 0x%05x AUX %s (ret=%3d) %*ph\n", - aux->name, offset, arrow, ret, min(ret, 20), buffer); + drm_dbg_dp(aux->drm_dev, "%s: 0x%05x AUX %s (ret=%3d) %*ph\n", + aux->name, offset, arrow, ret, min(ret, 20), buffer); else - DRM_DEBUG_DP("%s: 0x%05x AUX %s (ret=%3d)\n", - aux->name, offset, arrow, ret); + drm_dbg_dp(aux->drm_dev, "%s: 0x%05x AUX %s (ret=%3d)\n", + aux->name, offset, arrow, ret); } /** @@ -282,8 +287,8 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, err = ret; } - DRM_DEBUG_KMS("%s: Too many retries, giving up. First error: %d\n", - aux->name, err); + drm_dbg_kms(aux->drm_dev, "%s: Too many retries, giving up. First error: %d\n", + aux->name, err); ret = err; unlock: @@ -519,44 +524,44 @@ bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, if (drm_dp_dpcd_read(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, &auto_test_req, 1) < 1) { - DRM_ERROR("%s: DPCD failed read at register 0x%x\n", - aux->name, DP_DEVICE_SERVICE_IRQ_VECTOR); + drm_err(aux->drm_dev, "%s: DPCD failed read at register 0x%x\n", + aux->name, DP_DEVICE_SERVICE_IRQ_VECTOR); return false; } auto_test_req &= DP_AUTOMATED_TEST_REQUEST; if (drm_dp_dpcd_read(aux, DP_TEST_REQUEST, &link_edid_read, 1) < 1) { - DRM_ERROR("%s: DPCD failed read at register 0x%x\n", - aux->name, DP_TEST_REQUEST); + drm_err(aux->drm_dev, "%s: DPCD failed read at register 0x%x\n", + aux->name, DP_TEST_REQUEST); return false; } link_edid_read &= DP_TEST_LINK_EDID_READ; if (!auto_test_req || !link_edid_read) { - DRM_DEBUG_KMS("%s: Source DUT does not support TEST_EDID_READ\n", - aux->name); + drm_dbg_kms(aux->drm_dev, "%s: Source DUT does not support TEST_EDID_READ\n", + aux->name); return false; } if (drm_dp_dpcd_write(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, &auto_test_req, 1) < 1) { - DRM_ERROR("%s: DPCD failed write at register 0x%x\n", - aux->name, DP_DEVICE_SERVICE_IRQ_VECTOR); + drm_err(aux->drm_dev, "%s: DPCD failed write at register 0x%x\n", + aux->name, DP_DEVICE_SERVICE_IRQ_VECTOR); return false; } /* send back checksum for the last edid extension block data */ if (drm_dp_dpcd_write(aux, DP_TEST_EDID_CHECKSUM, &real_edid_checksum, 1) < 1) { - DRM_ERROR("%s: DPCD failed write at register 0x%x\n", - aux->name, DP_TEST_EDID_CHECKSUM); + drm_err(aux->drm_dev, "%s: DPCD failed write at register 0x%x\n", + aux->name, DP_TEST_EDID_CHECKSUM); return false; } test_resp |= DP_TEST_EDID_CHECKSUM_WRITE; if (drm_dp_dpcd_write(aux, DP_TEST_RESPONSE, &test_resp, 1) < 1) { - DRM_ERROR("%s: DPCD failed write at register 0x%x\n", - aux->name, DP_TEST_RESPONSE); + drm_err(aux->drm_dev, "%s: DPCD failed write at register 0x%x\n", + aux->name, DP_TEST_RESPONSE); return false; } @@ -599,17 +604,16 @@ static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux, return -EIO; if (dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { - DRM_DEBUG_KMS("%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n", - aux->name, dpcd[DP_DPCD_REV], - dpcd_ext[DP_DPCD_REV]); + drm_dbg_kms(aux->drm_dev, + "%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n", + aux->name, dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]); return 0; } if (!memcmp(dpcd, dpcd_ext, sizeof(dpcd_ext))) return 0; - DRM_DEBUG_KMS("%s: Base DPCD: %*ph\n", - aux->name, DP_RECEIVER_CAP_SIZE, dpcd); + drm_dbg_kms(aux->drm_dev, "%s: Base DPCD: %*ph\n", aux->name, DP_RECEIVER_CAP_SIZE, dpcd); memcpy(dpcd, dpcd_ext, sizeof(dpcd_ext)); @@ -644,8 +648,7 @@ int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux, if (ret < 0) return ret; - DRM_DEBUG_KMS("%s: DPCD: %*ph\n", - aux->name, DP_RECEIVER_CAP_SIZE, dpcd); + drm_dbg_kms(aux->drm_dev, "%s: DPCD: %*ph\n", aux->name, DP_RECEIVER_CAP_SIZE, dpcd); return ret; } @@ -674,12 +677,17 @@ int drm_dp_read_downstream_info(struct drm_dp_aux *aux, memset(downstream_ports, 0, DP_MAX_DOWNSTREAM_PORTS); /* No downstream info to read */ - if (!drm_dp_is_branch(dpcd) || - dpcd[DP_DPCD_REV] < DP_DPCD_REV_10 || - !(dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT)) + if (!drm_dp_is_branch(dpcd) || dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) return 0; + /* Some branches advertise having 0 downstream ports, despite also advertising they have a + * downstream port present. The DP spec isn't clear on if this is allowed or not, but since + * some branches do it we need to handle it regardless. + */ len = drm_dp_downstream_port_count(dpcd); + if (!len) + return 0; + if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) len *= 4; @@ -689,8 +697,7 @@ int drm_dp_read_downstream_info(struct drm_dp_aux *aux, if (ret != len) return -EIO; - DRM_DEBUG_KMS("%s: DPCD DFP: %*ph\n", - aux->name, len, downstream_ports); + drm_dbg_kms(aux->drm_dev, "%s: DPCD DFP: %*ph\n", aux->name, len, downstream_ports); return 0; } @@ -1407,11 +1414,11 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) * Avoid spamming the kernel log with timeout errors. */ if (ret == -ETIMEDOUT) - DRM_DEBUG_KMS_RATELIMITED("%s: transaction timed out\n", - aux->name); + drm_dbg_kms_ratelimited(aux->drm_dev, "%s: transaction timed out\n", + aux->name); else - DRM_DEBUG_KMS("%s: transaction failed: %d\n", - aux->name, ret); + drm_dbg_kms(aux->drm_dev, "%s: transaction failed: %d\n", + aux->name, ret); return ret; } @@ -1425,12 +1432,12 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) break; case DP_AUX_NATIVE_REPLY_NACK: - DRM_DEBUG_KMS("%s: native nack (result=%d, size=%zu)\n", - aux->name, ret, msg->size); + drm_dbg_kms(aux->drm_dev, "%s: native nack (result=%d, size=%zu)\n", + aux->name, ret, msg->size); return -EREMOTEIO; case DP_AUX_NATIVE_REPLY_DEFER: - DRM_DEBUG_KMS("%s: native defer\n", aux->name); + drm_dbg_kms(aux->drm_dev, "%s: native defer\n", aux->name); /* * We could check for I2C bit rate capabilities and if * available adjust this interval. We could also be @@ -1444,8 +1451,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) continue; default: - DRM_ERROR("%s: invalid native reply %#04x\n", - aux->name, msg->reply); + drm_err(aux->drm_dev, "%s: invalid native reply %#04x\n", + aux->name, msg->reply); return -EREMOTEIO; } @@ -1460,13 +1467,13 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return ret; case DP_AUX_I2C_REPLY_NACK: - DRM_DEBUG_KMS("%s: I2C nack (result=%d, size=%zu)\n", - aux->name, ret, msg->size); + drm_dbg_kms(aux->drm_dev, "%s: I2C nack (result=%d, size=%zu)\n", + aux->name, ret, msg->size); aux->i2c_nack_count++; return -EREMOTEIO; case DP_AUX_I2C_REPLY_DEFER: - DRM_DEBUG_KMS("%s: I2C defer\n", aux->name); + drm_dbg_kms(aux->drm_dev, "%s: I2C defer\n", aux->name); /* DP Compliance Test 4.2.2.5 Requirement: * Must have at least 7 retries for I2C defers on the * transaction to pass this test @@ -1480,13 +1487,13 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) continue; default: - DRM_ERROR("%s: invalid I2C reply %#04x\n", - aux->name, msg->reply); + drm_err(aux->drm_dev, "%s: invalid I2C reply %#04x\n", + aux->name, msg->reply); return -EREMOTEIO; } } - DRM_DEBUG_KMS("%s: Too many retries, giving up\n", aux->name); + drm_dbg_kms(aux->drm_dev, "%s: Too many retries, giving up\n", aux->name); return -EREMOTEIO; } @@ -1515,8 +1522,9 @@ static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *o return err == 0 ? -EPROTO : err; if (err < msg.size && err < ret) { - DRM_DEBUG_KMS("%s: Partial I2C reply: requested %zu bytes got %d bytes\n", - aux->name, msg.size, err); + drm_dbg_kms(aux->drm_dev, + "%s: Partial I2C reply: requested %zu bytes got %d bytes\n", + aux->name, msg.size, err); ret = err; } @@ -1695,12 +1703,11 @@ static void drm_dp_aux_crc_work(struct work_struct *work) } if (ret == -EAGAIN) { - DRM_DEBUG_KMS("%s: Get CRC failed after retrying: %d\n", - aux->name, ret); + drm_dbg_kms(aux->drm_dev, "%s: Get CRC failed after retrying: %d\n", + aux->name, ret); continue; } else if (ret) { - DRM_DEBUG_KMS("%s: Failed to get a CRC: %d\n", - aux->name, ret); + drm_dbg_kms(aux->drm_dev, "%s: Failed to get a CRC: %d\n", aux->name, ret); continue; } @@ -1728,10 +1735,18 @@ EXPORT_SYMBOL(drm_dp_remote_aux_init); * drm_dp_aux_init() - minimally initialise an aux channel * @aux: DisplayPort AUX channel * - * If you need to use the drm_dp_aux's i2c adapter prior to registering it - * with the outside world, call drm_dp_aux_init() first. You must still - * call drm_dp_aux_register() once the connector has been registered to - * allow userspace access to the auxiliary DP channel. + * If you need to use the drm_dp_aux's i2c adapter prior to registering it with + * the outside world, call drm_dp_aux_init() first. For drivers which are + * grandparents to their AUX adapters (e.g. the AUX adapter is parented by a + * &drm_connector), you must still call drm_dp_aux_register() once the connector + * has been registered to allow userspace access to the auxiliary DP channel. + * Likewise, for such drivers you should also assign &drm_dp_aux.drm_dev as + * early as possible so that the &drm_device that corresponds to the AUX adapter + * may be mentioned in debugging output from the DRM DP helpers. + * + * For devices which use a separate platform device for their AUX adapters, this + * may be called as early as required by the driver. + * */ void drm_dp_aux_init(struct drm_dp_aux *aux) { @@ -1751,15 +1766,26 @@ EXPORT_SYMBOL(drm_dp_aux_init); * drm_dp_aux_register() - initialise and register aux channel * @aux: DisplayPort AUX channel * - * Automatically calls drm_dp_aux_init() if this hasn't been done yet. - * This should only be called when the underlying &struct drm_connector is - * initialiazed already. Therefore the best place to call this is from - * &drm_connector_funcs.late_register. Not that drivers which don't follow this - * will Oops when CONFIG_DRM_DP_AUX_CHARDEV is enabled. - * - * Drivers which need to use the aux channel before that point (e.g. at driver - * load time, before drm_dev_register() has been called) need to call - * drm_dp_aux_init(). + * Automatically calls drm_dp_aux_init() if this hasn't been done yet. This + * should only be called once the parent of @aux, &drm_dp_aux.dev, is + * initialized. For devices which are grandparents of their AUX channels, + * &drm_dp_aux.dev will typically be the &drm_connector &device which + * corresponds to @aux. For these devices, it's advised to call + * drm_dp_aux_register() in &drm_connector_funcs.late_register, and likewise to + * call drm_dp_aux_unregister() in &drm_connector_funcs.early_unregister. + * Functions which don't follow this will likely Oops when + * %CONFIG_DRM_DP_AUX_CHARDEV is enabled. + * + * For devices where the AUX channel is a device that exists independently of + * the &drm_device that uses it, such as SoCs and bridge devices, it is + * recommended to call drm_dp_aux_register() after a &drm_device has been + * assigned to &drm_dp_aux.drm_dev, and likewise to call + * drm_dp_aux_unregister() once the &drm_device should no longer be associated + * with the AUX channel (e.g. on bridge detach). + * + * Drivers which need to use the aux channel before either of the two points + * mentioned above need to call drm_dp_aux_init() in order to use the AUX + * channel before registration. * * Returns 0 on success or a negative error code on failure. */ @@ -1767,6 +1793,8 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) { int ret; + WARN_ON_ONCE(!aux->drm_dev); + if (!aux->ddc.algo) drm_dp_aux_init(aux); @@ -1983,13 +2011,12 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, dev_id_len = strnlen(ident->device_id, sizeof(ident->device_id)); - DRM_DEBUG_KMS("%s: DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d quirks 0x%04x\n", - aux->name, is_branch ? "branch" : "sink", - (int)sizeof(ident->oui), ident->oui, - dev_id_len, ident->device_id, - ident->hw_rev >> 4, ident->hw_rev & 0xf, - ident->sw_major_rev, ident->sw_minor_rev, - desc->quirks); + drm_dbg_kms(aux->drm_dev, + "%s: DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d quirks 0x%04x\n", + aux->name, is_branch ? "branch" : "sink", + (int)sizeof(ident->oui), ident->oui, dev_id_len, + ident->device_id, ident->hw_rev >> 4, ident->hw_rev & 0xf, + ident->sw_major_rev, ident->sw_minor_rev, desc->quirks); return 0; } @@ -2755,7 +2782,8 @@ int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux) if (ret < 0) return ret; if (!(buf & DP_PCON_ENABLE_SOURCE_CTL_MODE)) { - DRM_DEBUG_KMS("PCON in Autonomous mode, can't enable FRL\n"); + drm_dbg_kms(aux->drm_dev, "%s: PCON in Autonomous mode, can't enable FRL\n", + aux->name); return -EINVAL; } buf |= DP_PCON_ENABLE_HDMI_LINK; @@ -2850,7 +2878,8 @@ void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, num_error = 0; } - DRM_ERROR("More than %d errors since the last read for lane %d", num_error, i); + drm_err(aux->drm_dev, "%s: More than %d errors since the last read for lane %d", + aux->name, num_error, i); } } EXPORT_SYMBOL(drm_dp_pcon_hdmi_frl_link_error_count); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 159014455fab..54604633e65c 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -286,7 +286,8 @@ static void drm_dp_encode_sideband_msg_hdr(struct drm_dp_sideband_msg_hdr *hdr, *len = idx; } -static bool drm_dp_decode_sideband_msg_hdr(struct drm_dp_sideband_msg_hdr *hdr, +static bool drm_dp_decode_sideband_msg_hdr(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_hdr *hdr, u8 *buf, int buflen, u8 *hdrlen) { u8 crc4; @@ -303,7 +304,7 @@ static bool drm_dp_decode_sideband_msg_hdr(struct drm_dp_sideband_msg_hdr *hdr, crc4 = drm_dp_msg_header_crc4(buf, (len * 2) - 1); if ((crc4 & 0xf) != (buf[len - 1] & 0xf)) { - DRM_DEBUG_KMS("crc4 mismatch 0x%x 0x%x\n", crc4, buf[len - 1]); + drm_dbg_kms(mgr->dev, "crc4 mismatch 0x%x 0x%x\n", crc4, buf[len - 1]); return false; } @@ -789,7 +790,8 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg, return true; } -static bool drm_dp_sideband_parse_link_address(struct drm_dp_sideband_msg_rx *raw, +static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; @@ -1014,7 +1016,8 @@ drm_dp_sideband_parse_query_stream_enc_status( return true; } -static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, +static bool drm_dp_sideband_parse_reply(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_reply_body *msg) { memset(msg, 0, sizeof(*msg)); @@ -1030,7 +1033,7 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, switch (msg->req_type) { case DP_LINK_ADDRESS: - return drm_dp_sideband_parse_link_address(raw, msg); + return drm_dp_sideband_parse_link_address(mgr, raw, msg); case DP_QUERY_PAYLOAD: return drm_dp_sideband_parse_query_payload_ack(raw, msg); case DP_REMOTE_DPCD_READ: @@ -1053,14 +1056,16 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, case DP_QUERY_STREAM_ENC_STATUS: return drm_dp_sideband_parse_query_stream_enc_status(raw, msg); default: - DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type, - drm_dp_mst_req_type_str(msg->req_type)); + drm_err(mgr->dev, "Got unknown reply 0x%02x (%s)\n", + msg->req_type, drm_dp_mst_req_type_str(msg->req_type)); return false; } } -static bool drm_dp_sideband_parse_connection_status_notify(struct drm_dp_sideband_msg_rx *raw, - struct drm_dp_sideband_msg_req_body *msg) +static bool +drm_dp_sideband_parse_connection_status_notify(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_rx *raw, + struct drm_dp_sideband_msg_req_body *msg) { int idx = 1; @@ -1082,12 +1087,14 @@ static bool drm_dp_sideband_parse_connection_status_notify(struct drm_dp_sideban idx++; return true; fail_len: - DRM_DEBUG_KMS("connection status reply parse length fail %d %d\n", idx, raw->curlen); + drm_dbg_kms(mgr->dev, "connection status reply parse length fail %d %d\n", + idx, raw->curlen); return false; } -static bool drm_dp_sideband_parse_resource_status_notify(struct drm_dp_sideband_msg_rx *raw, - struct drm_dp_sideband_msg_req_body *msg) +static bool drm_dp_sideband_parse_resource_status_notify(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_rx *raw, + struct drm_dp_sideband_msg_req_body *msg) { int idx = 1; @@ -1105,11 +1112,12 @@ static bool drm_dp_sideband_parse_resource_status_notify(struct drm_dp_sideband_ idx++; return true; fail_len: - DRM_DEBUG_KMS("resource status reply parse length fail %d %d\n", idx, raw->curlen); + drm_dbg_kms(mgr->dev, "resource status reply parse length fail %d %d\n", idx, raw->curlen); return false; } -static bool drm_dp_sideband_parse_req(struct drm_dp_sideband_msg_rx *raw, +static bool drm_dp_sideband_parse_req(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_req_body *msg) { memset(msg, 0, sizeof(*msg)); @@ -1117,12 +1125,12 @@ static bool drm_dp_sideband_parse_req(struct drm_dp_sideband_msg_rx *raw, switch (msg->req_type) { case DP_CONNECTION_STATUS_NOTIFY: - return drm_dp_sideband_parse_connection_status_notify(raw, msg); + return drm_dp_sideband_parse_connection_status_notify(mgr, raw, msg); case DP_RESOURCE_STATUS_NOTIFY: - return drm_dp_sideband_parse_resource_status_notify(raw, msg); + return drm_dp_sideband_parse_resource_status_notify(mgr, raw, msg); default: - DRM_ERROR("Got unknown request 0x%02x (%s)\n", msg->req_type, - drm_dp_mst_req_type_str(msg->req_type)); + drm_err(mgr->dev, "Got unknown request 0x%02x (%s)\n", + msg->req_type, drm_dp_mst_req_type_str(msg->req_type)); return false; } } @@ -1232,14 +1240,14 @@ static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1); if (ret > mgr->max_payloads) { ret = -EINVAL; - DRM_DEBUG_KMS("out of payload ids %d\n", ret); + drm_dbg_kms(mgr->dev, "out of payload ids %d\n", ret); goto out_unlock; } vcpi_ret = find_first_zero_bit(&mgr->vcpi_mask, mgr->max_payloads + 1); if (vcpi_ret > mgr->max_payloads) { ret = -EINVAL; - DRM_DEBUG_KMS("out of vcpi ids %d\n", ret); + drm_dbg_kms(mgr->dev, "out of vcpi ids %d\n", ret); goto out_unlock; } @@ -1261,7 +1269,7 @@ static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr, return; mutex_lock(&mgr->payload_lock); - DRM_DEBUG_KMS("putting payload %d\n", vcpi); + drm_dbg_kms(mgr->dev, "putting payload %d\n", vcpi); clear_bit(vcpi - 1, &mgr->vcpi_mask); for (i = 0; i < mgr->max_payloads; i++) { @@ -1331,7 +1339,8 @@ static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb, goto out; } } else { - DRM_DEBUG_KMS("timedout msg send %p %d %d\n", txmsg, txmsg->state, txmsg->seqno); + drm_dbg_kms(mgr->dev, "timedout msg send %p %d %d\n", + txmsg, txmsg->state, txmsg->seqno); /* dump some state */ ret = -EIO; @@ -1485,7 +1494,7 @@ static void drm_dp_mst_get_mstb_malloc(struct drm_dp_mst_branch *mstb) { kref_get(&mstb->malloc_kref); - DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref)); + drm_dbg(mstb->mgr->dev, "mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref)); } /** @@ -1502,7 +1511,7 @@ drm_dp_mst_get_mstb_malloc(struct drm_dp_mst_branch *mstb) static void drm_dp_mst_put_mstb_malloc(struct drm_dp_mst_branch *mstb) { - DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref) - 1); + drm_dbg(mstb->mgr->dev, "mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref) - 1); kref_put(&mstb->malloc_kref, drm_dp_free_mst_branch_device); } @@ -1536,7 +1545,7 @@ void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port) { kref_get(&port->malloc_kref); - DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->malloc_kref)); + drm_dbg(port->mgr->dev, "port %p (%d)\n", port, kref_read(&port->malloc_kref)); } EXPORT_SYMBOL(drm_dp_mst_get_port_malloc); @@ -1553,7 +1562,7 @@ EXPORT_SYMBOL(drm_dp_mst_get_port_malloc); void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port) { - DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->malloc_kref) - 1); + drm_dbg(port->mgr->dev, "port %p (%d)\n", port, kref_read(&port->malloc_kref) - 1); kref_put(&port->malloc_kref, drm_dp_free_mst_port); } EXPORT_SYMBOL(drm_dp_mst_put_port_malloc); @@ -1778,8 +1787,7 @@ drm_dp_mst_topology_try_get_mstb(struct drm_dp_mst_branch *mstb) topology_ref_history_lock(mstb->mgr); ret = kref_get_unless_zero(&mstb->topology_kref); if (ret) { - DRM_DEBUG("mstb %p (%d)\n", - mstb, kref_read(&mstb->topology_kref)); + drm_dbg(mstb->mgr->dev, "mstb %p (%d)\n", mstb, kref_read(&mstb->topology_kref)); save_mstb_topology_ref(mstb, DRM_DP_MST_TOPOLOGY_REF_GET); } @@ -1809,7 +1817,7 @@ static void drm_dp_mst_topology_get_mstb(struct drm_dp_mst_branch *mstb) save_mstb_topology_ref(mstb, DRM_DP_MST_TOPOLOGY_REF_GET); WARN_ON(kref_read(&mstb->topology_kref) == 0); kref_get(&mstb->topology_kref); - DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->topology_kref)); + drm_dbg(mstb->mgr->dev, "mstb %p (%d)\n", mstb, kref_read(&mstb->topology_kref)); topology_ref_history_unlock(mstb->mgr); } @@ -1831,8 +1839,7 @@ drm_dp_mst_topology_put_mstb(struct drm_dp_mst_branch *mstb) { topology_ref_history_lock(mstb->mgr); - DRM_DEBUG("mstb %p (%d)\n", - mstb, kref_read(&mstb->topology_kref) - 1); + drm_dbg(mstb->mgr->dev, "mstb %p (%d)\n", mstb, kref_read(&mstb->topology_kref) - 1); save_mstb_topology_ref(mstb, DRM_DP_MST_TOPOLOGY_REF_PUT); topology_ref_history_unlock(mstb->mgr); @@ -1895,8 +1902,7 @@ drm_dp_mst_topology_try_get_port(struct drm_dp_mst_port *port) topology_ref_history_lock(port->mgr); ret = kref_get_unless_zero(&port->topology_kref); if (ret) { - DRM_DEBUG("port %p (%d)\n", - port, kref_read(&port->topology_kref)); + drm_dbg(port->mgr->dev, "port %p (%d)\n", port, kref_read(&port->topology_kref)); save_port_topology_ref(port, DRM_DP_MST_TOPOLOGY_REF_GET); } @@ -1923,7 +1929,7 @@ static void drm_dp_mst_topology_get_port(struct drm_dp_mst_port *port) WARN_ON(kref_read(&port->topology_kref) == 0); kref_get(&port->topology_kref); - DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->topology_kref)); + drm_dbg(port->mgr->dev, "port %p (%d)\n", port, kref_read(&port->topology_kref)); save_port_topology_ref(port, DRM_DP_MST_TOPOLOGY_REF_GET); topology_ref_history_unlock(port->mgr); @@ -1944,8 +1950,7 @@ static void drm_dp_mst_topology_put_port(struct drm_dp_mst_port *port) { topology_ref_history_lock(port->mgr); - DRM_DEBUG("port %p (%d)\n", - port, kref_read(&port->topology_kref) - 1); + drm_dbg(port->mgr->dev, "port %p (%d)\n", port, kref_read(&port->topology_kref) - 1); save_port_topology_ref(port, DRM_DP_MST_TOPOLOGY_REF_PUT); topology_ref_history_unlock(port->mgr); @@ -2130,8 +2135,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt, mstb = drm_dp_add_mst_branch_device(lct, rad); if (!mstb) { ret = -ENOMEM; - DRM_ERROR("Failed to create MSTB for port %p", - port); + drm_err(mgr->dev, "Failed to create MSTB for port %p", port); goto out; } @@ -2261,8 +2265,8 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, int drm_dp_mst_connector_late_register(struct drm_connector *connector, struct drm_dp_mst_port *port) { - DRM_DEBUG_KMS("registering %s remote bus for %s\n", - port->aux.name, connector->kdev->kobj.name); + drm_dbg_kms(port->mgr->dev, "registering %s remote bus for %s\n", + port->aux.name, connector->kdev->kobj.name); port->aux.dev = connector->kdev; return drm_dp_aux_register_devnode(&port->aux); @@ -2281,8 +2285,8 @@ EXPORT_SYMBOL(drm_dp_mst_connector_late_register); void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, struct drm_dp_mst_port *port) { - DRM_DEBUG_KMS("unregistering %s remote bus for %s\n", - port->aux.name, connector->kdev->kobj.name); + drm_dbg_kms(port->mgr->dev, "unregistering %s remote bus for %s\n", + port->aux.name, connector->kdev->kobj.name); drm_dp_aux_unregister_devnode(&port->aux); } EXPORT_SYMBOL(drm_dp_mst_connector_early_unregister); @@ -2312,7 +2316,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb, return; error: - DRM_ERROR("Failed to create connector for port %p: %d\n", port, ret); + drm_err(mgr->dev, "Failed to create connector for port %p: %d\n", port, ret); } /* @@ -2350,6 +2354,7 @@ drm_dp_mst_add_port(struct drm_device *dev, port->aux.is_remote = true; /* initialize the MST downstream port's AUX crc work queue */ + port->aux.drm_dev = dev; drm_dp_remote_aux_init(&port->aux); /* @@ -2451,8 +2456,7 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, if (ret == 1) { send_link_addr = true; } else if (ret < 0) { - DRM_ERROR("Failed to change PDT on port %p: %d\n", - port, ret); + drm_err(dev, "Failed to change PDT on port %p: %d\n", port, ret); goto fail; } @@ -2547,8 +2551,7 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb, if (ret == 1) { dowork = true; } else if (ret < 0) { - DRM_ERROR("Failed to change PDT for port %p: %d\n", - port, ret); + drm_err(mgr->dev, "Failed to change PDT for port %p: %d\n", port, ret); dowork = false; } @@ -2607,7 +2610,9 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ if (port->port_num == port_num) { mstb = port->mstb; if (!mstb) { - DRM_ERROR("failed to lookup MSTB with lct %d, rad %02x\n", lct, rad[0]); + drm_err(mgr->dev, + "failed to lookup MSTB with lct %d, rad %02x\n", + lct, rad[0]); goto out; } @@ -2743,7 +2748,7 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work) * things work again. */ if (clear_payload_id_table) { - DRM_DEBUG_KMS("Clearing payload ID table\n"); + drm_dbg_kms(dev, "Clearing payload ID table\n"); drm_dp_send_clear_payload_id_table(mgr, mstb); } @@ -2805,7 +2810,7 @@ retry: retries++; goto retry; } - DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret); + drm_dbg_kms(mgr->dev, "failed to dpcd write %d %d\n", tosend, ret); return -EIO; } @@ -2918,7 +2923,7 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr) struct drm_dp_sideband_msg_tx, next); ret = process_single_tx_qlock(mgr, txmsg, false); if (ret < 0) { - DRM_DEBUG_KMS("failed to send msg in q %d\n", ret); + drm_dbg_kms(mgr->dev, "failed to send msg in q %d\n", ret); list_del(&txmsg->next); txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT; wake_up_all(&mgr->tx_waitq); @@ -2943,24 +2948,26 @@ static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr, } static void -drm_dp_dump_link_address(struct drm_dp_link_address_ack_reply *reply) +drm_dp_dump_link_address(const struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_link_address_ack_reply *reply) { struct drm_dp_link_addr_reply_port *port_reply; int i; for (i = 0; i < reply->nports; i++) { port_reply = &reply->ports[i]; - DRM_DEBUG_KMS("port %d: input %d, pdt: %d, pn: %d, dpcd_rev: %02x, mcs: %d, ddps: %d, ldps %d, sdp %d/%d\n", - i, - port_reply->input_port, - port_reply->peer_device_type, - port_reply->port_number, - port_reply->dpcd_revision, - port_reply->mcs, - port_reply->ddps, - port_reply->legacy_device_plug_status, - port_reply->num_sdp_streams, - port_reply->num_sdp_stream_sinks); + drm_dbg_kms(mgr->dev, + "port %d: input %d, pdt: %d, pn: %d, dpcd_rev: %02x, mcs: %d, ddps: %d, ldps %d, sdp %d/%d\n", + i, + port_reply->input_port, + port_reply->peer_device_type, + port_reply->port_number, + port_reply->dpcd_revision, + port_reply->mcs, + port_reply->ddps, + port_reply->legacy_device_plug_status, + port_reply->num_sdp_streams, + port_reply->num_sdp_stream_sinks); } } @@ -2986,26 +2993,25 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, /* FIXME: Actually do some real error handling here */ ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); if (ret <= 0) { - DRM_ERROR("Sending link address failed with %d\n", ret); + drm_err(mgr->dev, "Sending link address failed with %d\n", ret); goto out; } if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) { - DRM_ERROR("link address NAK received\n"); + drm_err(mgr->dev, "link address NAK received\n"); ret = -EIO; goto out; } reply = &txmsg->reply.u.link_addr; - DRM_DEBUG_KMS("link address reply: %d\n", reply->nports); - drm_dp_dump_link_address(reply); + drm_dbg_kms(mgr->dev, "link address reply: %d\n", reply->nports); + drm_dp_dump_link_address(mgr, reply); ret = drm_dp_check_mstb_guid(mstb, reply->guid); if (ret) { char buf[64]; drm_dp_mst_rad_to_str(mstb->rad, mstb->lct, buf, sizeof(buf)); - DRM_ERROR("GUID check on %s failed: %d\n", - buf, ret); + drm_err(mgr->dev, "GUID check on %s failed: %d\n", buf, ret); goto out; } @@ -3029,8 +3035,8 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, if (port_mask & BIT(port->port_num)) continue; - DRM_DEBUG_KMS("port %d was not in link address, removing\n", - port->port_num); + drm_dbg_kms(mgr->dev, "port %d was not in link address, removing\n", + port->port_num); list_del(&port->next); drm_dp_mst_topology_put_port(port); changed = true; @@ -3062,7 +3068,7 @@ drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); if (ret > 0 && txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) - DRM_DEBUG_KMS("clear payload table id nak received\n"); + drm_dbg_kms(mgr->dev, "clear payload table id nak received\n"); kfree(txmsg); } @@ -3091,15 +3097,15 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, path_res = &txmsg->reply.u.path_resources; if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) { - DRM_DEBUG_KMS("enum path resources nak received\n"); + drm_dbg_kms(mgr->dev, "enum path resources nak received\n"); } else { if (port->port_num != path_res->port_number) DRM_ERROR("got incorrect port in response\n"); - DRM_DEBUG_KMS("enum path resources %d: %d %d\n", - path_res->port_number, - path_res->full_payload_bw_number, - path_res->avail_payload_bw_number); + drm_dbg_kms(mgr->dev, "enum path resources %d: %d %d\n", + path_res->port_number, + path_res->full_payload_bw_number, + path_res->avail_payload_bw_number); /* * If something changed, make sure we send a @@ -3345,7 +3351,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, int id, struct drm_dp_payload *payload) { - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(mgr->dev, "\n"); /* it's okay for these to fail */ if (port) { drm_dp_payload_send_msg(mgr, port, id, 0); @@ -3451,7 +3457,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) continue; } - DRM_DEBUG_KMS("removing payload %d\n", i); + drm_dbg_kms(mgr->dev, "removing payload %d\n", i); for (j = i; j < mgr->max_payloads - 1; j++) { mgr->payloads[j] = mgr->payloads[j + 1]; mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1]; @@ -3498,7 +3504,7 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr) port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi); - DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state); + drm_dbg_kms(mgr->dev, "payload %d %d\n", i, mgr->payloads[i].payload_state); if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) { ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]); } else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) { @@ -3543,8 +3549,8 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, /* DPCD read should never be NACKed */ if (txmsg->reply.reply_type == 1) { - DRM_ERROR("mstb %p port %d: DPCD read on addr 0x%x for %d bytes NAKed\n", - mstb, port->port_num, offset, size); + drm_err(mgr->dev, "mstb %p port %d: DPCD read on addr 0x%x for %d bytes NAKed\n", + mstb, port->port_num, offset, size); ret = -EIO; goto fail_free; } @@ -3637,6 +3643,7 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, /** * drm_dp_get_vc_payload_bw - get the VC payload BW for an MST link + * @mgr: The &drm_dp_mst_topology_mgr to use * @link_rate: link rate in 10kbits/s units * @link_lane_count: lane count * @@ -3645,11 +3652,12 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, * convert the number of PBNs required for a given stream to the number of * timeslots this stream requires in each MTP. */ -int drm_dp_get_vc_payload_bw(int link_rate, int link_lane_count) +int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, + int link_rate, int link_lane_count) { if (link_rate == 0 || link_lane_count == 0) - DRM_DEBUG_KMS("invalid link rate/lane count: (%d / %d)\n", - link_rate, link_lane_count); + drm_dbg_kms(mgr->dev, "invalid link rate/lane count: (%d / %d)\n", + link_rate, link_lane_count); /* See DP v2.0 2.6.4.2, VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */ return link_rate * link_lane_count / 54000; @@ -3700,18 +3708,24 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms /* set the device into MST mode */ if (mst_state) { struct drm_dp_payload reset_pay; + int lane_count; + int link_rate; WARN_ON(mgr->mst_primary); /* get dpcd info */ - ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE); - if (ret != DP_RECEIVER_CAP_SIZE) { - DRM_DEBUG_KMS("failed to read DPCD\n"); + ret = drm_dp_read_dpcd_caps(mgr->aux, mgr->dpcd); + if (ret < 0) { + drm_dbg_kms(mgr->dev, "%s: failed to read DPCD, ret %d\n", + mgr->aux->name, ret); goto out_unlock; } - mgr->pbn_div = drm_dp_get_vc_payload_bw(drm_dp_bw_code_to_link_rate(mgr->dpcd[1]), - mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK); + lane_count = min_t(int, mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK, mgr->max_lane_count); + link_rate = min_t(int, mgr->dpcd[1], mgr->max_link_rate); + mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr, + drm_dp_bw_code_to_link_rate(link_rate), + lane_count); if (mgr->pbn_div == 0) { ret = -EINVAL; goto out_unlock; @@ -3840,7 +3854,7 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE); if (ret != DP_RECEIVER_CAP_SIZE) { - DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); + drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n"); goto out_fail; } @@ -3849,20 +3863,20 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); if (ret < 0) { - DRM_DEBUG_KMS("mst write failed - undocked during suspend?\n"); + drm_dbg_kms(mgr->dev, "mst write failed - undocked during suspend?\n"); goto out_fail; } /* Some hubs forget their guids after they resume */ ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16); if (ret != 16) { - DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); + drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n"); goto out_fail; } ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid); if (ret) { - DRM_DEBUG_KMS("check mstb failed - undocked during suspend?\n"); + drm_dbg_kms(mgr->dev, "check mstb failed - undocked during suspend?\n"); goto out_fail; } @@ -3875,7 +3889,8 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, mutex_unlock(&mgr->lock); if (sync) { - DRM_DEBUG_KMS("Waiting for link probe work to finish re-syncing topology...\n"); + drm_dbg_kms(mgr->dev, + "Waiting for link probe work to finish re-syncing topology...\n"); flush_work(&mgr->work); } @@ -3908,15 +3923,15 @@ drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, len = min(mgr->max_dpcd_transaction_bytes, 16); ret = drm_dp_dpcd_read(mgr->aux, basereg, replyblock, len); if (ret != len) { - DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret); + drm_dbg_kms(mgr->dev, "failed to read DPCD down rep %d %d\n", len, ret); return false; } - ret = drm_dp_decode_sideband_msg_hdr(&hdr, replyblock, len, &hdrlen); + ret = drm_dp_decode_sideband_msg_hdr(mgr, &hdr, replyblock, len, &hdrlen); if (ret == false) { print_hex_dump(KERN_DEBUG, "failed hdr", DUMP_PREFIX_NONE, 16, 1, replyblock, len, false); - DRM_DEBUG_KMS("ERROR: failed header\n"); + drm_dbg_kms(mgr->dev, "ERROR: failed header\n"); return false; } @@ -3924,22 +3939,20 @@ drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, /* Caller is responsible for giving back this reference */ *mstb = drm_dp_get_mst_branch_device(mgr, hdr.lct, hdr.rad); if (!*mstb) { - DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", - hdr.lct); + drm_dbg_kms(mgr->dev, "Got MST reply from unknown device %d\n", hdr.lct); return false; } } if (!drm_dp_sideband_msg_set_header(msg, &hdr, hdrlen)) { - DRM_DEBUG_KMS("sideband msg set header failed %d\n", - replyblock[0]); + drm_dbg_kms(mgr->dev, "sideband msg set header failed %d\n", replyblock[0]); return false; } replylen = min(msg->curchunk_len, (u8)(len - hdrlen)); ret = drm_dp_sideband_append_payload(msg, replyblock + hdrlen, replylen); if (!ret) { - DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]); + drm_dbg_kms(mgr->dev, "sideband msg build failed %d\n", replyblock[0]); return false; } @@ -3950,14 +3963,14 @@ drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, ret = drm_dp_dpcd_read(mgr->aux, basereg + curreply, replyblock, len); if (ret != len) { - DRM_DEBUG_KMS("failed to read a chunk (len %d, ret %d)\n", - len, ret); + drm_dbg_kms(mgr->dev, "failed to read a chunk (len %d, ret %d)\n", + len, ret); return false; } ret = drm_dp_sideband_append_payload(msg, replyblock, len); if (!ret) { - DRM_DEBUG_KMS("failed to build sideband msg\n"); + drm_dbg_kms(mgr->dev, "failed to build sideband msg\n"); return false; } @@ -3991,21 +4004,21 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) struct drm_dp_sideband_msg_hdr *hdr; hdr = &msg->initial_hdr; - DRM_DEBUG_KMS("Got MST reply with no msg %p %d %d %02x %02x\n", - mstb, hdr->seqno, hdr->lct, hdr->rad[0], - msg->msg[0]); + drm_dbg_kms(mgr->dev, "Got MST reply with no msg %p %d %d %02x %02x\n", + mstb, hdr->seqno, hdr->lct, hdr->rad[0], msg->msg[0]); goto out_clear_reply; } - drm_dp_sideband_parse_reply(msg, &txmsg->reply); + drm_dp_sideband_parse_reply(mgr, msg, &txmsg->reply); if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) { - DRM_DEBUG_KMS("Got NAK reply: req 0x%02x (%s), reason 0x%02x (%s), nak data 0x%02x\n", - txmsg->reply.req_type, - drm_dp_mst_req_type_str(txmsg->reply.req_type), - txmsg->reply.u.nak.reason, - drm_dp_mst_nak_reason_str(txmsg->reply.u.nak.reason), - txmsg->reply.u.nak.nak_data); + drm_dbg_kms(mgr->dev, + "Got NAK reply: req 0x%02x (%s), reason 0x%02x (%s), nak data 0x%02x\n", + txmsg->reply.req_type, + drm_dp_mst_req_type_str(txmsg->reply.req_type), + txmsg->reply.u.nak.reason, + drm_dp_mst_nak_reason_str(txmsg->reply.u.nak.reason), + txmsg->reply.u.nak.nak_data); } memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx)); @@ -4053,8 +4066,7 @@ drm_dp_mst_process_up_req(struct drm_dp_mst_topology_mgr *mgr, } if (!mstb) { - DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", - hdr->lct); + drm_dbg_kms(mgr->dev, "Got MST reply from unknown device %d\n", hdr->lct); return false; } @@ -4114,12 +4126,12 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) INIT_LIST_HEAD(&up_req->next); - drm_dp_sideband_parse_req(&mgr->up_req_recv, &up_req->msg); + drm_dp_sideband_parse_req(mgr, &mgr->up_req_recv, &up_req->msg); if (up_req->msg.req_type != DP_CONNECTION_STATUS_NOTIFY && up_req->msg.req_type != DP_RESOURCE_STATUS_NOTIFY) { - DRM_DEBUG_KMS("Received unknown up req type, ignoring: %x\n", - up_req->msg.req_type); + drm_dbg_kms(mgr->dev, "Received unknown up req type, ignoring: %x\n", + up_req->msg.req_type); kfree(up_req); goto out; } @@ -4131,20 +4143,20 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) const struct drm_dp_connection_status_notify *conn_stat = &up_req->msg.u.conn_stat; - DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", - conn_stat->port_number, - conn_stat->legacy_device_plug_status, - conn_stat->displayport_device_plug_status, - conn_stat->message_capability_status, - conn_stat->input_port, - conn_stat->peer_device_type); + drm_dbg_kms(mgr->dev, "Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", + conn_stat->port_number, + conn_stat->legacy_device_plug_status, + conn_stat->displayport_device_plug_status, + conn_stat->message_capability_status, + conn_stat->input_port, + conn_stat->peer_device_type); } else if (up_req->msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { const struct drm_dp_resource_status_notify *res_stat = &up_req->msg.u.resource_stat; - DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", - res_stat->port_number, - res_stat->available_pbn); + drm_dbg_kms(mgr->dev, "Got RSN: pn: %d avail_pbn %d\n", + res_stat->port_number, + res_stat->available_pbn); } up_req->hdr = mgr->up_req_recv.initial_hdr; @@ -4384,8 +4396,9 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, * which is an error */ if (WARN_ON(!prev_slots)) { - DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", - port); + drm_err(mgr->dev, + "cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", + port); return -EINVAL; } @@ -4402,12 +4415,12 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, req_slots = DIV_ROUND_UP(pbn, pbn_div); - DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", - port->connector->base.id, port->connector->name, - port, prev_slots, req_slots); - DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] PBN %d -> %d\n", - port->connector->base.id, port->connector->name, - port, prev_bw, pbn); + drm_dbg_atomic(mgr->dev, "[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", + port->connector->base.id, port->connector->name, + port, prev_slots, req_slots); + drm_dbg_atomic(mgr->dev, "[CONNECTOR:%d:%s] [MST PORT:%p] PBN %d -> %d\n", + port->connector->base.id, port->connector->name, + port, prev_bw, pbn); /* Add the new allocation to the state */ if (!vcpi) { @@ -4471,12 +4484,12 @@ int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, } } if (WARN_ON(!found)) { - DRM_ERROR("no VCPI for [MST PORT:%p] found in mst state %p\n", - port, &topology_state->base); + drm_err(mgr->dev, "no VCPI for [MST PORT:%p] found in mst state %p\n", + port, &topology_state->base); return -EINVAL; } - DRM_DEBUG_ATOMIC("[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); + drm_dbg_atomic(mgr->dev, "[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); if (pos->vcpi) { drm_dp_mst_put_port_malloc(port); pos->vcpi = 0; @@ -4507,8 +4520,9 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, return false; if (port->vcpi.vcpi > 0) { - DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", - port->vcpi.vcpi, port->vcpi.pbn, pbn); + drm_dbg_kms(mgr->dev, + "payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", + port->vcpi.vcpi, port->vcpi.pbn, pbn); if (pbn == port->vcpi.pbn) { drm_dp_mst_topology_put_port(port); return true; @@ -4517,13 +4531,12 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); if (ret) { - DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", - DIV_ROUND_UP(pbn, mgr->pbn_div), ret); + drm_dbg_kms(mgr->dev, "failed to init vcpi slots=%d max=63 ret=%d\n", + DIV_ROUND_UP(pbn, mgr->pbn_div), ret); drm_dp_mst_topology_put_port(port); goto out; } - DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", - pbn, port->vcpi.num_slots); + drm_dbg_kms(mgr->dev, "initing vcpi for pbn=%d slots=%d\n", pbn, port->vcpi.num_slots); /* Keep port allocated until its payload has been removed */ drm_dp_mst_get_port_malloc(port); @@ -4605,14 +4618,14 @@ static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_dpcd_write(mgr->aux, DP_PAYLOAD_ALLOCATE_SET, payload_alloc, 3); if (ret != 3) { - DRM_DEBUG_KMS("failed to write payload allocation %d\n", ret); + drm_dbg_kms(mgr->dev, "failed to write payload allocation %d\n", ret); goto fail; } retry: ret = drm_dp_dpcd_readb(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status); if (ret < 0) { - DRM_DEBUG_KMS("failed to read payload table status %d\n", ret); + drm_dbg_kms(mgr->dev, "failed to read payload table status %d\n", ret); goto fail; } @@ -4622,7 +4635,8 @@ retry: usleep_range(10000, 20000); goto retry; } - DRM_DEBUG_KMS("status not set after read payload table status %d\n", status); + drm_dbg_kms(mgr->dev, "status not set after read payload table status %d\n", + status); ret = -EINVAL; goto fail; } @@ -4669,16 +4683,15 @@ int drm_dp_check_act_status(struct drm_dp_mst_topology_mgr *mgr) status & DP_PAYLOAD_ACT_HANDLED || status < 0, 200, timeout_ms * USEC_PER_MSEC); if (ret < 0 && status >= 0) { - DRM_ERROR("Failed to get ACT after %dms, last status: %02x\n", - timeout_ms, status); + drm_err(mgr->dev, "Failed to get ACT after %dms, last status: %02x\n", + timeout_ms, status); return -EINVAL; } else if (status < 0) { /* * Failure here isn't unexpected - the hub may have * just been unplugged */ - DRM_DEBUG_KMS("Failed to read payload table status: %d\n", - status); + drm_dbg_kms(mgr->dev, "Failed to read payload table status: %d\n", status); return status; } @@ -5118,12 +5131,11 @@ drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, return 0; if (mstb->port_parent) - DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] Checking bandwidth limits on [MSTB:%p]\n", - mstb->port_parent->parent, mstb->port_parent, - mstb); + drm_dbg_atomic(mstb->mgr->dev, + "[MSTB:%p] [MST PORT:%p] Checking bandwidth limits on [MSTB:%p]\n", + mstb->port_parent->parent, mstb->port_parent, mstb); else - DRM_DEBUG_ATOMIC("[MSTB:%p] Checking bandwidth limits\n", - mstb); + drm_dbg_atomic(mstb->mgr->dev, "[MSTB:%p] Checking bandwidth limits\n", mstb); list_for_each_entry(port, &mstb->ports, next) { ret = drm_dp_mst_atomic_check_port_bw_limit(port, state); @@ -5181,14 +5193,14 @@ drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, } if (pbn_used > port->full_pbn) { - DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n", - port->parent, port, pbn_used, - port->full_pbn); + drm_dbg_atomic(port->mgr->dev, + "[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n", + port->parent, port, pbn_used, port->full_pbn); return -ENOSPC; } - DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] uses %d out of %d PBN\n", - port->parent, port, pbn_used, port->full_pbn); + drm_dbg_atomic(port->mgr->dev, "[MSTB:%p] [MST PORT:%p] uses %d out of %d PBN\n", + port->parent, port, pbn_used, port->full_pbn); return pbn_used; } @@ -5203,31 +5215,31 @@ drm_dp_mst_atomic_check_vcpi_alloc_limit(struct drm_dp_mst_topology_mgr *mgr, list_for_each_entry(vcpi, &mst_state->vcpis, next) { /* Releasing VCPI is always OK-even if the port is gone */ if (!vcpi->vcpi) { - DRM_DEBUG_ATOMIC("[MST PORT:%p] releases all VCPI slots\n", - vcpi->port); + drm_dbg_atomic(mgr->dev, "[MST PORT:%p] releases all VCPI slots\n", + vcpi->port); continue; } - DRM_DEBUG_ATOMIC("[MST PORT:%p] requires %d vcpi slots\n", - vcpi->port, vcpi->vcpi); + drm_dbg_atomic(mgr->dev, "[MST PORT:%p] requires %d vcpi slots\n", + vcpi->port, vcpi->vcpi); avail_slots -= vcpi->vcpi; if (avail_slots < 0) { - DRM_DEBUG_ATOMIC("[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", - vcpi->port, mst_state, - avail_slots + vcpi->vcpi); + drm_dbg_atomic(mgr->dev, + "[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", + vcpi->port, mst_state, avail_slots + vcpi->vcpi); return -ENOSPC; } if (++payload_count > mgr->max_payloads) { - DRM_DEBUG_ATOMIC("[MST MGR:%p] state %p has too many payloads (max=%d)\n", - mgr, mst_state, mgr->max_payloads); + drm_dbg_atomic(mgr->dev, + "[MST MGR:%p] state %p has too many payloads (max=%d)\n", + mgr, mst_state, mgr->max_payloads); return -EINVAL; } } - DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", - mgr, mst_state, avail_slots, - 63 - avail_slots); + drm_dbg_atomic(mgr->dev, "[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", + mgr, mst_state, avail_slots, 63 - avail_slots); return 0; } @@ -5284,8 +5296,8 @@ int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, struct drm if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - DRM_DEBUG_ATOMIC("[MST MGR:%p] Setting mode_changed flag on CRTC %p\n", - mgr, crtc); + drm_dbg_atomic(mgr->dev, "[MST MGR:%p] Setting mode_changed flag on CRTC %p\n", + mgr, crtc); crtc_state->mode_changed = true; } @@ -5330,21 +5342,24 @@ int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, } if (!found) { - DRM_DEBUG_ATOMIC("[MST PORT:%p] Couldn't find VCPI allocation in mst state %p\n", - port, mst_state); + drm_dbg_atomic(state->dev, + "[MST PORT:%p] Couldn't find VCPI allocation in mst state %p\n", + port, mst_state); return -EINVAL; } if (pos->dsc_enabled == enable) { - DRM_DEBUG_ATOMIC("[MST PORT:%p] DSC flag is already set to %d, returning %d VCPI slots\n", - port, enable, pos->vcpi); + drm_dbg_atomic(state->dev, + "[MST PORT:%p] DSC flag is already set to %d, returning %d VCPI slots\n", + port, enable, pos->vcpi); vcpi = pos->vcpi; } if (enable) { vcpi = drm_dp_atomic_find_vcpi_slots(state, port->mgr, port, pbn, pbn_div); - DRM_DEBUG_ATOMIC("[MST PORT:%p] Enabling DSC flag, reallocating %d VCPI slots on the port\n", - port, vcpi); + drm_dbg_atomic(state->dev, + "[MST PORT:%p] Enabling DSC flag, reallocating %d VCPI slots on the port\n", + port, vcpi); if (vcpi < 0) return -EINVAL; } @@ -5438,14 +5453,17 @@ EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); * @aux: DP helper aux channel to talk to this device * @max_dpcd_transaction_bytes: hw specific DPCD transaction limit * @max_payloads: maximum number of payloads this GPU can source + * @max_lane_count: maximum number of lanes this GPU supports + * @max_link_rate: maximum link rate this GPU supports, units as in DPCD * @conn_base_id: the connector object ID the MST device is connected to. * * Return 0 for success, or negative error code on failure */ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, struct drm_device *dev, struct drm_dp_aux *aux, - int max_dpcd_transaction_bytes, - int max_payloads, int conn_base_id) + int max_dpcd_transaction_bytes, int max_payloads, + u8 max_lane_count, u8 max_link_rate, + int conn_base_id) { struct drm_dp_mst_topology_state *mst_state; @@ -5480,6 +5498,8 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, mgr->aux = aux; mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; mgr->max_payloads = max_payloads; + mgr->max_lane_count = max_lane_count; + mgr->max_link_rate = max_link_rate; mgr->conn_base_id = conn_base_id; if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 || max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8) @@ -5691,7 +5711,7 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, } else if (remote_i2c_write_ok(msgs, num)) { ret = drm_dp_mst_i2c_write(mstb, port, msgs, num); } else { - DRM_DEBUG_KMS("Unsupported I2C transaction for MST device\n"); + drm_dbg_kms(mgr->dev, "Unsupported I2C transaction for MST device\n"); ret = -EIO; } @@ -5886,14 +5906,13 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && port->parent == port->mgr->mst_primary) { - u8 downstreamport; + u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; - if (drm_dp_dpcd_read(&port->aux, DP_DOWNSTREAMPORT_PRESENT, - &downstreamport, 1) < 0) + if (drm_dp_read_dpcd_caps(port->mgr->aux, dpcd_ext) < 0) return NULL; - if ((downstreamport & DP_DWN_STRM_PORT_PRESENT) && - ((downstreamport & DP_DWN_STRM_PORT_TYPE_MASK) + if ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) && + ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) != DP_DWN_STRM_PORT_TYPE_ANALOG)) return port->mgr->aux; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c2f78dee9f2d..3d8d68a98b95 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -941,9 +941,7 @@ void drm_dev_unregister(struct drm_device *dev) if (dev->driver->unload) dev->driver->unload(dev); - if (dev->agp) - drm_pci_agp_destroy(dev); - + drm_legacy_pci_agp_destroy(dev); drm_legacy_rmmaps(dev); remove_compat_control_link(dev); diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 7efbccffc2ea..d4f0bac6f8f8 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -774,19 +774,7 @@ void drm_event_cancel_free(struct drm_device *dev, } EXPORT_SYMBOL(drm_event_cancel_free); -/** - * drm_send_event_helper - send DRM event to file descriptor - * @dev: DRM device - * @e: DRM event to deliver - * @timestamp: timestamp to set for the fence event in kernel's CLOCK_MONOTONIC - * time domain - * - * This helper function sends the event @e, initialized with - * drm_event_reserve_init(), to its associated userspace DRM file. - * The timestamp variant of dma_fence_signal is used when the caller - * sends a valid timestamp. - */ -void drm_send_event_helper(struct drm_device *dev, +static void drm_send_event_helper(struct drm_device *dev, struct drm_pending_event *e, ktime_t timestamp) { assert_spin_locked(&dev->event_lock); diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index c043ca364c86..0e885cd34107 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL(drm_fb_memcpy); /** * drm_fb_memcpy_dstclip - Copy clip buffer * @dst: Destination buffer (iomem) + * @dst_pitch: Number of bytes between two consecutive scanlines within dst * @vaddr: Source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy @@ -59,12 +60,12 @@ EXPORT_SYMBOL(drm_fb_memcpy); * This function applies clipping on dst, i.e. the destination is a * full (iomem) framebuffer but only the clip rect content is copied over. */ -void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, - struct drm_framebuffer *fb, +void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, + void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip) { unsigned int cpp = fb->format->cpp[0]; - unsigned int offset = clip_offset(clip, fb->pitches[0], cpp); + unsigned int offset = clip_offset(clip, dst_pitch, cpp); size_t len = (clip->x2 - clip->x1) * cpp; unsigned int y, lines = clip->y2 - clip->y1; @@ -73,7 +74,7 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, for (y = 0; y < lines; y++) { memcpy_toio(dst, vaddr, len); vaddr += fb->pitches[0]; - dst += fb->pitches[0]; + dst += dst_pitch; } } EXPORT_SYMBOL(drm_fb_memcpy_dstclip); @@ -343,3 +344,90 @@ void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); +/** + * drm_fb_blit_rect_dstclip - Copy parts of a framebuffer to display memory + * @dst: The display memory to copy to + * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * @dst_format: FOURCC code of the display's color format + * @vmap: The framebuffer memory to copy from + * @fb: The framebuffer to copy from + * @clip: Clip rectangle area to copy + * + * This function copies parts of a framebuffer to display memory. If the + * formats of the display and the framebuffer mismatch, the blit function + * will attempt to convert between them. + * + * Use drm_fb_blit_dstclip() to copy the full framebuffer. + * + * Returns: + * 0 on success, or + * -EINVAL if the color-format conversion failed, or + * a negative error code otherwise. + */ +int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch, + uint32_t dst_format, void *vmap, + struct drm_framebuffer *fb, + struct drm_rect *clip) +{ + uint32_t fb_format = fb->format->format; + + /* treat alpha channel like filler bits */ + if (fb_format == DRM_FORMAT_ARGB8888) + fb_format = DRM_FORMAT_XRGB8888; + if (dst_format == DRM_FORMAT_ARGB8888) + dst_format = DRM_FORMAT_XRGB8888; + + if (dst_format == fb_format) { + drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip); + return 0; + + } else if (dst_format == DRM_FORMAT_RGB565) { + if (fb_format == DRM_FORMAT_XRGB8888) { + drm_fb_xrgb8888_to_rgb565_dstclip(dst, dst_pitch, + vmap, fb, clip, + false); + return 0; + } + } else if (dst_format == DRM_FORMAT_RGB888) { + if (fb_format == DRM_FORMAT_XRGB8888) { + drm_fb_xrgb8888_to_rgb888_dstclip(dst, dst_pitch, + vmap, fb, clip); + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(drm_fb_blit_rect_dstclip); + +/** + * drm_fb_blit_dstclip - Copy framebuffer to display memory + * @dst: The display memory to copy to + * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * @dst_format: FOURCC code of the display's color format + * @vmap: The framebuffer memory to copy from + * @fb: The framebuffer to copy from + * + * This function copies a full framebuffer to display memory. If the formats + * of the display and the framebuffer mismatch, the copy function will + * attempt to convert between them. + * + * See drm_fb_blit_rect_dstclip() for more inforamtion. + * + * Returns: + * 0 on success, or a negative error code otherwise. + */ +int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch, + uint32_t dst_format, void *vmap, + struct drm_framebuffer *fb) +{ + struct drm_rect fullscreen = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; + return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb, + &fullscreen); +} +EXPORT_SYMBOL(drm_fb_blit_dstclip); diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c index de28720757af..b14bed8be771 100644 --- a/drivers/gpu/drm/drm_gem_ttm_helper.c +++ b/drivers/gpu/drm/drm_gem_ttm_helper.c @@ -114,5 +114,38 @@ int drm_gem_ttm_mmap(struct drm_gem_object *gem, } EXPORT_SYMBOL(drm_gem_ttm_mmap); +/** + * drm_gem_ttm_dumb_map_offset() - Implements struct &drm_driver.dumb_map_offset + * @file: DRM file pointer. + * @dev: DRM device. + * @handle: GEM handle + * @offset: Returns the mapping's memory offset on success + * + * Provides an implementation of struct &drm_driver.dumb_map_offset for + * TTM-based GEM drivers. TTM allocates the offset internally and + * drm_gem_ttm_dumb_map_offset() returns it for dumb-buffer implementations. + * + * See struct &drm_driver.dumb_map_offset. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_gem_ttm_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *gem; + + gem = drm_gem_object_lookup(file, handle); + if (!gem) + return -ENOENT; + + *offset = drm_vma_node_offset_addr(&gem->vma_node); + + drm_gem_object_put(gem); + + return 0; +} +EXPORT_SYMBOL(drm_gem_ttm_dumb_map_offset); + MODULE_DESCRIPTION("DRM gem ttm helpers"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 2b7c3a07956d..797200315854 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -245,22 +245,6 @@ void drm_gem_vram_put(struct drm_gem_vram_object *gbo) } EXPORT_SYMBOL(drm_gem_vram_put); -/** - * drm_gem_vram_mmap_offset() - Returns a GEM VRAM object's mmap offset - * @gbo: the GEM VRAM object - * - * See drm_vma_node_offset_addr() for more information. - * - * Returns: - * The buffer object's offset for userspace mappings on success, or - * 0 if no offset is allocated. - */ -u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo) -{ - return drm_vma_node_offset_addr(&gbo->bo.base.vma_node); -} -EXPORT_SYMBOL(drm_gem_vram_mmap_offset); - static u64 drm_gem_vram_pg_offset(struct drm_gem_vram_object *gbo) { /* Keep TTM behavior for now, remove when drivers are audited */ @@ -638,38 +622,6 @@ int drm_gem_vram_driver_dumb_create(struct drm_file *file, } EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); -/** - * drm_gem_vram_driver_dumb_mmap_offset() - \ - Implements &struct drm_driver.dumb_mmap_offset - * @file: DRM file pointer. - * @dev: DRM device. - * @handle: GEM handle - * @offset: Returns the mapping's memory offset on success - * - * Returns: - * 0 on success, or - * a negative errno code otherwise. - */ -int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, uint64_t *offset) -{ - struct drm_gem_object *gem; - struct drm_gem_vram_object *gbo; - - gem = drm_gem_object_lookup(file, handle); - if (!gem) - return -ENOENT; - - gbo = drm_gem_vram_of_gem(gem); - *offset = drm_gem_vram_mmap_offset(gbo); - - drm_gem_object_put(gem); - - return 0; -} -EXPORT_SYMBOL(drm_gem_vram_driver_dumb_mmap_offset); - /* * Helpers for struct drm_plane_helper_funcs */ diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 1265de2b9d90..1dcb5797a3bb 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -56,7 +56,6 @@ void drm_lastclose(struct drm_device *dev); /* drm_pci.c */ int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); -void drm_pci_agp_destroy(struct drm_device *dev); int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); #else @@ -67,10 +66,6 @@ static inline int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, return -EINVAL; } -static inline void drm_pci_agp_destroy(struct drm_device *dev) -{ -} - static inline int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) { diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 33390f02f5eb..d29907955ff7 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -31,7 +31,6 @@ #include <linux/ratelimit.h> #include <linux/export.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_file.h> #include <drm/drm_print.h> @@ -619,6 +618,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd, } #endif +#if IS_ENABLED(CONFIG_DRM_LEGACY) #if IS_ENABLED(CONFIG_AGP) typedef struct drm_agp_mode32 { u32 mode; /**< AGP mode */ @@ -633,7 +633,7 @@ static int compat_drm_agp_enable(struct file *file, unsigned int cmd, if (get_user(mode.mode, &argp->mode)) return -EFAULT; - return drm_ioctl_kernel(file, drm_agp_enable_ioctl, &mode, + return drm_ioctl_kernel(file, drm_legacy_agp_enable_ioctl, &mode, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); } @@ -659,7 +659,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd, struct drm_agp_info info; int err; - err = drm_ioctl_kernel(file, drm_agp_info_ioctl, &info, DRM_AUTH); + err = drm_ioctl_kernel(file, drm_legacy_agp_info_ioctl, &info, DRM_AUTH); if (err) return err; @@ -698,7 +698,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, request.size = req32.size; request.type = req32.type; - err = drm_ioctl_kernel(file, drm_agp_alloc_ioctl, &request, + err = drm_ioctl_kernel(file, drm_legacy_agp_alloc_ioctl, &request, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); if (err) return err; @@ -706,7 +706,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, req32.handle = request.handle; req32.physical = request.physical; if (copy_to_user(argp, &req32, sizeof(req32))) { - drm_ioctl_kernel(file, drm_agp_free_ioctl, &request, + drm_ioctl_kernel(file, drm_legacy_agp_free_ioctl, &request, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); return -EFAULT; } @@ -723,7 +723,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd, if (get_user(request.handle, &argp->handle)) return -EFAULT; - return drm_ioctl_kernel(file, drm_agp_free_ioctl, &request, + return drm_ioctl_kernel(file, drm_legacy_agp_free_ioctl, &request, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); } @@ -744,7 +744,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd, request.handle = req32.handle; request.offset = req32.offset; - return drm_ioctl_kernel(file, drm_agp_bind_ioctl, &request, + return drm_ioctl_kernel(file, drm_legacy_agp_bind_ioctl, &request, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); } @@ -757,12 +757,11 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, if (get_user(request.handle, &argp->handle)) return -EFAULT; - return drm_ioctl_kernel(file, drm_agp_unbind_ioctl, &request, + return drm_ioctl_kernel(file, drm_legacy_agp_unbind_ioctl, &request, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); } #endif /* CONFIG_AGP */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) typedef struct drm_scatter_gather32 { u32 size; /**< In bytes -- will round to page boundary */ u32 handle; /**< Used for mapping / unmapping */ @@ -935,7 +934,6 @@ static struct { DRM_IOCTL32_DEF(DRM_IOCTL_GET_SAREA_CTX, compat_drm_getsareactx), DRM_IOCTL32_DEF(DRM_IOCTL_RES_CTX, compat_drm_resctx), DRM_IOCTL32_DEF(DRM_IOCTL_DMA, compat_drm_dma), -#endif #if IS_ENABLED(CONFIG_AGP) DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ENABLE, compat_drm_agp_enable), DRM_IOCTL32_DEF(DRM_IOCTL_AGP_INFO, compat_drm_agp_info), @@ -944,6 +942,7 @@ static struct { DRM_IOCTL32_DEF(DRM_IOCTL_AGP_BIND, compat_drm_agp_bind), DRM_IOCTL32_DEF(DRM_IOCTL_AGP_UNBIND, compat_drm_agp_unbind), #endif +#endif #if IS_ENABLED(CONFIG_DRM_LEGACY) DRM_IOCTL32_DEF(DRM_IOCTL_SG_ALLOC, compat_drm_sg_alloc), DRM_IOCTL32_DEF(DRM_IOCTL_SG_FREE, compat_drm_sg_free), diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index d273d1a8603a..b0856c139693 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -33,7 +33,6 @@ #include <linux/pci.h> #include <linux/uaccess.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_auth.h> #include <drm/drm_crtc.h> #include <drm/drm_drv.h> @@ -627,14 +626,21 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_legacy_irq_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), #if IS_ENABLED(CONFIG_AGP) - DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_legacy_agp_acquire_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_legacy_agp_release_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_legacy_agp_enable_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_legacy_agp_info_ioctl, DRM_AUTH), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_legacy_agp_alloc_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_legacy_agp_free_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_legacy_agp_bind_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_legacy_agp_unbind_ioctl, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), #endif DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h index f71358f9eac9..7080d2538421 100644 --- a/drivers/gpu/drm/drm_legacy.h +++ b/drivers/gpu/drm/drm_legacy.h @@ -148,6 +148,30 @@ struct drm_agp_mem { struct list_head head; }; +/* drm_agpsupport.c */ +#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_AGP) +void drm_legacy_agp_clear(struct drm_device *dev); + +int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +#else +static inline void drm_legacy_agp_clear(struct drm_device *dev) {} +#endif + /* drm_lock.c */ #if IS_ENABLED(CONFIG_DRM_LEGACY) int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f); @@ -211,4 +235,10 @@ void drm_master_legacy_init(struct drm_master *master); static inline void drm_master_legacy_init(struct drm_master *master) {} #endif +#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_PCI) +void drm_legacy_pci_agp_destroy(struct drm_device *dev); +#else +static inline void drm_legacy_pci_agp_destroy(struct drm_device *dev) {} +#endif + #endif /* __DRM_LEGACY_H__ */ diff --git a/drivers/gpu/drm/drm_legacy_misc.c b/drivers/gpu/drm/drm_legacy_misc.c index 8f54e6a78b6f..83db43b7a25e 100644 --- a/drivers/gpu/drm/drm_legacy_misc.c +++ b/drivers/gpu/drm/drm_legacy_misc.c @@ -33,7 +33,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_irq.h> diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index e4f20a2eb6e7..d2e1dccd8113 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -38,7 +38,6 @@ #include <linux/pci.h> #include <linux/vmalloc.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_cache.h> #include <drm/drm_device.h> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 33a93fa24eb1..ae53ea624c73 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1176,16 +1176,11 @@ enum drm_mode_status drm_mode_validate_ycbcr420(const struct drm_display_mode *mode, struct drm_connector *connector) { - u8 vic = drm_match_cea_mode(mode); - enum drm_mode_status status = MODE_OK; - struct drm_hdmi_info *hdmi = &connector->display_info.hdmi; - - if (test_bit(vic, hdmi->y420_vdb_modes)) { - if (!connector->ycbcr_420_allowed) - status = MODE_NO_420; - } + if (!connector->ycbcr_420_allowed && + drm_mode_is_420_only(&connector->display_info, mode)) + return MODE_NO_420; - return status; + return MODE_OK; } EXPORT_SYMBOL(drm_mode_validate_ycbcr420); @@ -1290,7 +1285,8 @@ EXPORT_SYMBOL(drm_mode_prune_invalid); * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or * positive if @lh_b is better than @lh_a. */ -static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b) +static int drm_mode_compare(void *priv, const struct list_head *lh_a, + const struct list_head *lh_b) { struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 2294a1580d35..38c3cb72e7e6 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -30,7 +30,6 @@ #include <linux/slab.h> #include <drm/drm.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_drv.h> #include <drm/drm_print.h> @@ -41,64 +40,6 @@ /* List of devices hanging off drivers with stealth attach. */ static LIST_HEAD(legacy_dev_list); static DEFINE_MUTEX(legacy_dev_list_lock); - -/** - * drm_pci_alloc - Allocate a PCI consistent memory block, for DMA. - * @dev: DRM device - * @size: size of block to allocate - * @align: alignment of block - * - * FIXME: This is a needless abstraction of the Linux dma-api and should be - * removed. - * - * Return: A handle to the allocated memory block on success or NULL on - * failure. - */ -drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align) -{ - drm_dma_handle_t *dmah; - - /* pci_alloc_consistent only guarantees alignment to the smallest - * PAGE_SIZE order which is greater than or equal to the requested size. - * Return NULL here for now to make sure nobody tries for larger alignment - */ - if (align > size) - return NULL; - - dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); - if (!dmah) - return NULL; - - dmah->size = size; - dmah->vaddr = dma_alloc_coherent(dev->dev, size, - &dmah->busaddr, - GFP_KERNEL); - - if (dmah->vaddr == NULL) { - kfree(dmah); - return NULL; - } - - return dmah; -} -EXPORT_SYMBOL(drm_pci_alloc); - -/** - * drm_pci_free - Free a PCI consistent memory block - * @dev: DRM device - * @dmah: handle to memory block - * - * FIXME: This is a needless abstraction of the Linux dma-api and should be - * removed. - */ -void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) -{ - dma_free_coherent(dev->dev, dmah->size, dmah->vaddr, - dmah->busaddr); - kfree(dmah); -} - -EXPORT_SYMBOL(drm_pci_free); #endif static int drm_get_pci_domain(struct drm_device *dev) @@ -177,7 +118,9 @@ int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, return drm_pci_irq_by_busid(dev, p); } -void drm_pci_agp_destroy(struct drm_device *dev) +#ifdef CONFIG_DRM_LEGACY + +void drm_legacy_pci_agp_destroy(struct drm_device *dev) { if (dev->agp) { arch_phys_wc_del(dev->agp->agp_mtrr); @@ -187,13 +130,11 @@ void drm_pci_agp_destroy(struct drm_device *dev) } } -#ifdef CONFIG_DRM_LEGACY - -static void drm_pci_agp_init(struct drm_device *dev) +static void drm_legacy_pci_agp_init(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { if (pci_find_capability(to_pci_dev(dev->dev), PCI_CAP_ID_AGP)) - dev->agp = drm_agp_init(dev); + dev->agp = drm_legacy_agp_init(dev); if (dev->agp) { dev->agp->agp_mtrr = arch_phys_wc_add( dev->agp->agp_info.aper_base, @@ -203,9 +144,9 @@ static void drm_pci_agp_init(struct drm_device *dev) } } -static int drm_get_pci_dev(struct pci_dev *pdev, - const struct pci_device_id *ent, - const struct drm_driver *driver) +static int drm_legacy_get_pci_dev(struct pci_dev *pdev, + const struct pci_device_id *ent, + const struct drm_driver *driver) { struct drm_device *dev; int ret; @@ -220,7 +161,6 @@ static int drm_get_pci_dev(struct pci_dev *pdev, if (ret) goto err_free; - dev->pdev = pdev; #ifdef __alpha__ dev->hose = pdev->sysdata; #endif @@ -228,7 +168,7 @@ static int drm_get_pci_dev(struct pci_dev *pdev, if (drm_core_check_feature(dev, DRIVER_MODESET)) pci_set_drvdata(pdev, dev); - drm_pci_agp_init(dev); + drm_legacy_pci_agp_init(dev); ret = drm_dev_register(dev, ent->driver_data); if (ret) @@ -243,7 +183,7 @@ static int drm_get_pci_dev(struct pci_dev *pdev, return 0; err_agp: - drm_pci_agp_destroy(dev); + drm_legacy_pci_agp_destroy(dev); pci_disable_device(pdev); err_free: drm_dev_put(dev); @@ -290,7 +230,7 @@ int drm_legacy_pci_init(const struct drm_driver *driver, /* stealth mode requires a manual probe */ pci_dev_get(pdev); - drm_get_pci_dev(pdev, pid, driver); + drm_legacy_get_pci_dev(pdev, pid, driver); } } return 0; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 0dd43882fe7c..b373958ecb30 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -128,6 +128,13 @@ * pairs supported by this plane. The blob is a struct * drm_format_modifier_blob. Without this property the plane doesn't * support buffers with modifiers. Userspace cannot change this property. + * + * Note that userspace can check the &DRM_CAP_ADDFB2_MODIFIERS driver + * capability for general modifier support. If this flag is set then every + * plane will have the IN_FORMATS property, even when it only supports + * DRM_FORMAT_MOD_LINEAR. Before linux kernel release v5.1 there have been + * various bugs in this area with inconsistencies between the capability + * flag and per-plane properties. */ static unsigned int drm_num_planes(struct drm_device *dev) @@ -277,8 +284,14 @@ static int __drm_universal_plane_init(struct drm_device *dev, format_modifier_count++; } - if (format_modifier_count) + /* autoset the cap and check for consistency across all planes */ + if (format_modifier_count) { + drm_WARN_ON(dev, !config->allow_fb_modifiers && + !list_empty(&config->plane_list)); config->allow_fb_modifiers = true; + } else { + drm_WARN_ON(dev, config->allow_fb_modifiers); + } plane->modifier_count = format_modifier_count; plane->modifiers = kmalloc_array(format_modifier_count, @@ -360,6 +373,9 @@ static int __drm_universal_plane_init(struct drm_device *dev, * drm_universal_plane_init() to let the DRM managed resource infrastructure * take care of cleanup and deallocation. * + * Drivers supporting modifiers must set @format_modifiers on all their planes, + * even those that only support DRM_FORMAT_MOD_LINEAR. + * * Returns: * Zero on success, error code on failure. */ diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 9b3b989d7cad..e957d4851dc0 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -45,8 +45,6 @@ #endif #include <linux/mem_encrypt.h> - -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 64370b634cca..79fa3649185c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -177,7 +177,5 @@ void exynos_drm_mode_config_init(struct drm_device *dev) dev->mode_config.funcs = &exynos_drm_mode_config_funcs; dev->mode_config.helper_private = &exynos_drm_mode_config_helpers; - dev->mode_config.allow_fb_modifiers = true; - dev->mode_config.normalize_zpos = true; } diff --git a/drivers/gpu/drm/gma500/backlight.c b/drivers/gpu/drm/gma500/backlight.c index 35600d070cb5..9e90258541a4 100644 --- a/drivers/gpu/drm/gma500/backlight.c +++ b/drivers/gpu/drm/gma500/backlight.c @@ -42,7 +42,7 @@ void gma_backlight_disable(struct drm_device *dev) dev_priv->backlight_device->props.brightness = 0; do_gma_backlight_set(dev); } -#endif +#endif } void gma_backlight_set(struct drm_device *dev, int v) @@ -54,7 +54,7 @@ void gma_backlight_set(struct drm_device *dev, int v) dev_priv->backlight_device->props.brightness = v; do_gma_backlight_set(dev); } -#endif +#endif } int gma_backlight_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 6d3ada39ff86..595b765ecc71 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -245,7 +245,7 @@ i2c_dp_aux_add_bus(struct i2c_adapter *adapter) if (W && !in_dbg_master()) msleep(W); \ } \ ret__; \ -}) +}) #define wait_for(COND, MS) _wait_for(COND, MS, 1) @@ -386,7 +386,7 @@ static void cdv_intel_edp_panel_vdd_on(struct gma_encoder *intel_encoder) if (intel_dp->panel_on) { DRM_DEBUG_KMS("Skip VDD on because of panel on\n"); return; - } + } DRM_DEBUG_KMS("\n"); pp = REG_READ(PP_CONTROL); @@ -433,7 +433,7 @@ static bool cdv_intel_edp_panel_on(struct gma_encoder *intel_encoder) DRM_DEBUG_KMS("Error in Powering up eDP panel, status %x\n", REG_READ(PP_STATUS)); intel_dp->panel_on = false; } else - intel_dp->panel_on = true; + intel_dp->panel_on = true; msleep(intel_dp->panel_power_up_delay); return false; @@ -449,7 +449,7 @@ static void cdv_intel_edp_panel_off (struct gma_encoder *intel_encoder) pp = REG_READ(PP_CONTROL); - if ((pp & POWER_TARGET_ON) == 0) + if ((pp & POWER_TARGET_ON) == 0) return; intel_dp->panel_on = false; @@ -464,7 +464,7 @@ static void cdv_intel_edp_panel_off (struct gma_encoder *intel_encoder) DRM_DEBUG_KMS("PP_STATUS %x\n", REG_READ(PP_STATUS)); if (wait_for((REG_READ(PP_STATUS) & idle_off_mask) == 0, 1000)) { - DRM_DEBUG_KMS("Error in turning off Panel\n"); + DRM_DEBUG_KMS("Error in turning off Panel\n"); } msleep(intel_dp->panel_power_cycle_delay); @@ -535,7 +535,7 @@ cdv_intel_dp_mode_valid(struct drm_connector *connector, if (cdv_intel_dp_link_required(mode->clock, 24) > cdv_intel_dp_max_data_rate(max_link_clock, max_lanes)) return MODE_CLOCK_HIGH; - + } if (mode->clock < 10000) return MODE_CLOCK_LOW; @@ -606,7 +606,7 @@ cdv_intel_dp_aux_ch(struct gma_encoder *encoder, for (i = 0; i < send_bytes; i += 4) REG_WRITE(ch_data + i, pack_aux(send + i, send_bytes - i)); - + /* Send the command and wait for it to complete */ REG_WRITE(ch_ctl, DP_AUX_CH_CTL_SEND_BUSY | @@ -623,7 +623,7 @@ cdv_intel_dp_aux_ch(struct gma_encoder *encoder, break; udelay(100); } - + /* Clear done status and any errors */ REG_WRITE(ch_ctl, status | @@ -659,7 +659,7 @@ cdv_intel_dp_aux_ch(struct gma_encoder *encoder, DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); if (recv_bytes > recv_size) recv_bytes = recv_size; - + for (i = 0; i < recv_bytes; i += 4) unpack_aux(REG_READ(ch_data + i), recv + i, recv_bytes - i); @@ -870,7 +870,7 @@ cdv_intel_dp_i2c_init(struct gma_connector *connector, ret = i2c_dp_aux_add_bus(&intel_dp->adapter); if (is_edp(encoder)) cdv_intel_edp_panel_vdd_off(encoder); - + return ret; } @@ -1291,13 +1291,13 @@ cdv_intel_get_adjust_train(struct gma_encoder *encoder) if (this_p > p) p = this_p; } - + if (v >= CDV_DP_VOLTAGE_MAX) v = CDV_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; if (p == DP_TRAIN_PRE_EMPHASIS_MASK) p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; - + for (lane = 0; lane < 4; lane++) intel_dp->train_set[lane] = v | p; } @@ -1358,7 +1358,6 @@ cdv_intel_dp_set_link_train(struct gma_encoder *encoder, uint32_t dp_reg_value, uint8_t dp_train_pat) { - struct drm_device *dev = encoder->base.dev; int ret; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1384,7 +1383,6 @@ static bool cdv_intel_dplink_set_level(struct gma_encoder *encoder, uint8_t dp_train_pat) { - int ret; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1462,7 +1460,7 @@ cdv_intel_dp_set_vswing_premph(struct gma_encoder *encoder, uint8_t signal_level /* ;gfx_dpio_set_reg(0x8124, 0x00004000) */ index = 2 * premph + 1; cdv_sb_write(dev, ddi_reg->PreEmph2, dp_vswing_premph_table[index]); - return; + return; } @@ -1481,8 +1479,8 @@ cdv_intel_dp_start_link_train(struct gma_encoder *encoder) DP |= DP_PORT_EN; DP &= ~DP_LINK_TRAIN_MASK; - - reg = DP; + + reg = DP; reg |= DP_LINK_TRAIN_PAT_1; /* Enable output, wait for it to become active */ REG_WRITE(intel_dp->output_reg, reg); @@ -1556,7 +1554,7 @@ cdv_intel_dp_start_link_train(struct gma_encoder *encoder) if (!clock_recovery) { DRM_DEBUG_KMS("failure in DP patter 1 training, train set %x\n", intel_dp->train_set[0]); } - + intel_dp->DP = DP; } @@ -1747,7 +1745,7 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector) if (is_edp(intel_encoder)) { struct drm_device *dev = connector->dev; struct drm_psb_private *dev_priv = dev->dev_private; - + cdv_intel_edp_panel_vdd_off(intel_encoder); if (ret) { if (edp && !intel_dp->panel_fixed_mode) { @@ -1942,11 +1940,11 @@ static void cdv_disable_intel_clock_gating(struct drm_device *dev) DPCUNIT_CLOCK_GATE_DISABLE | DPLSUNIT_CLOCK_GATE_DISABLE | DPOUNIT_CLOCK_GATE_DISABLE | - DPIOUNIT_CLOCK_GATE_DISABLE); + DPIOUNIT_CLOCK_GATE_DISABLE); REG_WRITE(DSPCLK_GATE_D, reg_value); - udelay(500); + udelay(500); } void @@ -1990,7 +1988,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev gma_encoder->dev_priv=intel_dp; intel_dp->encoder = gma_encoder; intel_dp->output_reg = output_reg; - + drm_encoder_helper_add(encoder, &cdv_intel_dp_helper_funcs); drm_connector_helper_add(connector, &cdv_intel_dp_connector_helper_funcs); @@ -2027,7 +2025,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev pp_on = REG_READ(PP_CONTROL); pp_on &= ~PANEL_UNLOCK_MASK; pp_on |= PANEL_UNLOCK_REGS; - + REG_WRITE(PP_CONTROL, pp_on); pwm_ctrl = REG_READ(BLC_PWM_CTL2); @@ -2037,7 +2035,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev pp_on = REG_READ(PP_ON_DELAYS); pp_off = REG_READ(PP_OFF_DELAYS); pp_div = REG_READ(PP_DIVISOR); - + /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> PANEL_POWER_UP_DELAY_SHIFT; @@ -2085,9 +2083,9 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev goto err_connector; } else { DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n", - intel_dp->dpcd[0], intel_dp->dpcd[1], + intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); - + } /* The CDV reference driver moves pnale backlight setup into the displays that have a backlight: this is a good idea and one we should probably adopt, however diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 5bff7d9e3aa6..8a2219fcf9b4 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -21,7 +21,7 @@ #include "psb_intel_drv.h" #include "psb_intel_reg.h" -/** +/* * LVDS I2C backlight control macros */ #define BRIGHTNESS_MAX_LEVEL 100 diff --git a/drivers/gpu/drm/gma500/intel_gmbus.c b/drivers/gpu/drm/gma500/intel_gmbus.c index eb0924473a21..c17cbafa468a 100644 --- a/drivers/gpu/drm/gma500/intel_gmbus.c +++ b/drivers/gpu/drm/gma500/intel_gmbus.c @@ -379,7 +379,7 @@ static const struct i2c_algorithm gmbus_algorithm = { }; /** - * intel_gmbus_setup - instantiate all Intel i2c GMBuses + * gma_intel_setup_gmbus() - instantiate all Intel i2c GMBuses * @dev: DRM device */ int gma_intel_setup_gmbus(struct drm_device *dev) diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 49afa577d442..d6e7c2c2c947 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -646,7 +646,7 @@ extern u32 psb_get_vblank_counter(struct drm_crtc *crtc); extern int psbfb_probed(struct drm_device *dev); extern int psbfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -/* accel_2d.c */ +/* psb_drv.c */ extern void psb_spank(struct drm_psb_private *dev_priv); /* psb_reset.c */ diff --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h index de2f2d2dbc60..b65105585578 100644 --- a/drivers/gpu/drm/gud/gud_internal.h +++ b/drivers/gpu/drm/gud/gud_internal.h @@ -86,7 +86,7 @@ static inline u8 gud_from_fourcc(u32 fourcc) return GUD_PIXEL_FORMAT_XRGB8888; case DRM_FORMAT_ARGB8888: return GUD_PIXEL_FORMAT_ARGB8888; - }; + } return 0; } @@ -104,7 +104,7 @@ static inline u32 gud_to_fourcc(u8 format) return DRM_FORMAT_XRGB8888; case GUD_PIXEL_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; - }; + } return 0; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index abd6250d5a14..f4bc5386574a 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/pci.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -60,7 +61,7 @@ static const struct drm_driver hibmc_driver = { .minor = 0, .debugfs_init = drm_vram_mm_debugfs_init, .dumb_create = hibmc_dumb_create, - .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, .gem_prime_mmap = drm_gem_prime_mmap, .irq_handler = hibmc_drm_interrupt, }; @@ -313,8 +314,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev, struct drm_device *dev; int ret; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, - "hibmcdrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "hibmcdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 88250860f8e4..d78c82af367c 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -34,7 +34,6 @@ #include <linux/mman.h> #include <linux/pci.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -220,7 +219,7 @@ static int i810_dma_cleanup(struct drm_device *dev) if (dev_priv->ring.virtual_start) drm_legacy_ioremapfree(&dev_priv->ring.map, dev); if (dev_priv->hw_status_page) { - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_free_coherent(dev->dev, PAGE_SIZE, dev_priv->hw_status_page, dev_priv->dma_status_page); } @@ -398,7 +397,7 @@ static int i810_dma_initialize(struct drm_device *dev, /* Program Hardware Status Page */ dev_priv->hw_status_page = - dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_alloc_coherent(dev->dev, PAGE_SIZE, &dev_priv->dma_status_page, GFP_KERNEL); if (!dev_priv->hw_status_page) { dev->dev_private = (void *)dev_priv; @@ -1197,7 +1196,9 @@ static int i810_flip_bufs(struct drm_device *dev, void *data, int i810_driver_load(struct drm_device *dev, unsigned long flags) { - dev->agp = drm_agp_init(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + + dev->agp = drm_legacy_agp_init(dev); if (dev->agp) { dev->agp->agp_mtrr = arch_phys_wc_add( dev->agp->agp_info.aper_base, @@ -1209,7 +1210,7 @@ int i810_driver_load(struct drm_device *dev, unsigned long flags) if (!dev->agp) return -EINVAL; - pci_set_master(dev->pdev); + pci_set_master(pdev); return 0; } diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 1e1cb245fca7..69f57ca9c68d 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -20,6 +20,7 @@ config DRM_I915 select INPUT if ACPI select ACPI_VIDEO if ACPI select ACPI_BUTTON if ACPI + select IO_MAPPING select SYNC_FILE select IOSF_MBI select CRC32 @@ -101,6 +102,7 @@ config DRM_I915_GVT bool "Enable Intel GVT-g graphics virtualization host support" depends on DRM_I915 depends on 64BIT + depends on VFIO_MDEV=y || VFIO_MDEV=DRM_I915 default n help Choose this option if you want to enable Intel GVT-g graphics diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index dfe3cf328d13..de0f358184aa 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -8,6 +8,7 @@ #include "g4x_dp.h" #include "intel_audio.h" #include "intel_connector.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_link_training.h" diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 78f93506ffaf..be352e9f0afc 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -8,6 +8,7 @@ #include "g4x_hdmi.h" #include "intel_audio.h" #include "intel_connector.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" #include "intel_fifo_underrun.h" diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 456374ddf37a..9643c45a2209 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -10,6 +10,7 @@ #include "intel_atomic.h" #include "intel_atomic_plane.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_sprite.h" @@ -144,7 +145,7 @@ static bool i9xx_plane_has_windowing(struct intel_plane *plane) return i9xx_plane == PLANE_B; else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) return false; - else if (IS_DISPLAY_VER(dev_priv, 4)) + else if (DISPLAY_VER(dev_priv) == 4) return i9xx_plane == PLANE_C; else return i9xx_plane == PLANE_B || @@ -1039,4 +1040,3 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, plane_config->fb = intel_fb; } - diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 9282978060b0..ce544e20f35c 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -31,7 +31,9 @@ #include "intel_atomic.h" #include "intel_combo_phy.h" #include "intel_connector.h" +#include "intel_crtc.h" #include "intel_ddi.h" +#include "intel_de.h" #include "intel_dsi.h" #include "intel_panel.h" #include "intel_vdsc.h" @@ -592,7 +594,7 @@ gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder, * a value '0' inside TA_PARAM_REGISTERS otherwise * leave all fields at HW default values. */ - if (IS_DISPLAY_VER(dev_priv, 11)) { + if (DISPLAY_VER(dev_priv) == 11) { if (afe_clk(encoder, crtc_state) <= 800000) { for_each_dsi_port(port, intel_dsi->ports) { tmp = intel_de_read(dev_priv, @@ -1158,7 +1160,7 @@ gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, gen11_dsi_configure_transcoder(encoder, crtc_state); /* Step 4l: Gate DDI clocks */ - if (IS_DISPLAY_VER(dev_priv, 11)) + if (DISPLAY_VER(dev_priv) == 11) gen11_dsi_gate_clocks(encoder); } diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 4fa389fce8cb..88f424020a5f 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -109,16 +109,6 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector, return -EINVAL; } -static bool blob_equal(const struct drm_property_blob *a, - const struct drm_property_blob *b) -{ - if (a && b) - return a->length == b->length && - !memcmp(a->data, b->data, a->length); - - return !a == !b; -} - int intel_digital_connector_atomic_check(struct drm_connector *conn, struct drm_atomic_state *state) { @@ -149,8 +139,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn, new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio || new_conn_state->base.content_type != old_conn_state->base.content_type || new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode || - !blob_equal(new_conn_state->base.hdr_output_metadata, - old_conn_state->base.hdr_output_metadata)) + !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) crtc_state->mode_changed = true; return 0; @@ -332,7 +321,7 @@ static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_sta plane_state->hw.fb->format->is_yuv && plane_state->hw.fb->format->num_planes > 1) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - if (IS_DISPLAY_VER(dev_priv, 9)) { + if (DISPLAY_VER(dev_priv) == 9) { mode = SKL_PS_SCALER_MODE_NV12; } else if (icl_is_hdr_plane(dev_priv, plane->id)) { /* diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index c3f2962aa1eb..36f52a1d7552 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -102,7 +102,8 @@ intel_plane_duplicate_state(struct drm_plane *plane) __drm_atomic_helper_plane_duplicate_state(plane, &intel_state->uapi); - intel_state->vma = NULL; + intel_state->ggtt_vma = NULL; + intel_state->dpt_vma = NULL; intel_state->flags = 0; /* add reference to fb */ @@ -125,7 +126,9 @@ intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { struct intel_plane_state *plane_state = to_intel_plane_state(state); - drm_WARN_ON(plane->dev, plane_state->vma); + + drm_WARN_ON(plane->dev, plane_state->ggtt_vma); + drm_WARN_ON(plane->dev, plane_state->dpt_vma); __drm_atomic_helper_plane_destroy_state(&plane_state->uapi); if (plane_state->hw.fb) @@ -133,25 +136,45 @@ intel_plane_destroy_state(struct drm_plane *plane, kfree(plane_state); } -unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +unsigned int intel_adjusted_rate(const struct drm_rect *src, + const struct drm_rect *dst, + unsigned int rate) { unsigned int src_w, src_h, dst_w, dst_h; - unsigned int pixel_rate = crtc_state->pixel_rate; - src_w = drm_rect_width(&plane_state->uapi.src) >> 16; - src_h = drm_rect_height(&plane_state->uapi.src) >> 16; - dst_w = drm_rect_width(&plane_state->uapi.dst); - dst_h = drm_rect_height(&plane_state->uapi.dst); + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; + dst_w = drm_rect_width(dst); + dst_h = drm_rect_height(dst); /* Downscaling limits the maximum pixel rate */ dst_w = min(src_w, dst_w); dst_h = min(src_h, dst_h); - return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_rate, src_w * src_h), + return DIV_ROUND_UP_ULL(mul_u32_u32(rate, src_w * src_h), dst_w * dst_h); } +unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + /* + * Note we don't check for plane visibility here as + * we want to use this when calculating the cursor + * watermarks even if the cursor is fully offscreen. + * That depends on the src/dst rectangles being + * correctly populated whenever the watermark code + * considers the cursor to be visible, whether or not + * it is actually visible. + * + * See: intel_wm_plane_visible() and intel_check_cursor() + */ + + return intel_adjusted_rate(&plane_state->uapi.src, + &plane_state->uapi.dst, + crtc_state->pixel_rate); +} + unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_atomic_plane.h index 5c78a087ed86..dc4d05e75e1c 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h @@ -10,6 +10,7 @@ struct drm_plane; struct drm_property; +struct drm_rect; struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; @@ -18,6 +19,9 @@ struct intel_plane_state; extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; +unsigned int intel_adjusted_rate(const struct drm_rect *src, + const struct drm_rect *dst, + unsigned int rate); unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 9671c8f6e892..5f4f316b3ab5 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -31,6 +31,7 @@ #include "intel_atomic.h" #include "intel_audio.h" #include "intel_cdclk.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_lpe_audio.h" @@ -591,40 +592,33 @@ static void enable_audio_dsc_wa(struct intel_encoder *encoder, val = intel_de_read(i915, AUD_CONFIG_BE); - if (IS_DISPLAY_VER(i915, 11)) + if (DISPLAY_VER(i915) == 11) val |= HBLANK_EARLY_ENABLE_ICL(pipe); else if (DISPLAY_VER(i915) >= 12) val |= HBLANK_EARLY_ENABLE_TGL(pipe); if (crtc_state->dsc.compression_enable && - (crtc_state->hw.adjusted_mode.hdisplay >= 3840 && - crtc_state->hw.adjusted_mode.vdisplay >= 2160)) { + crtc_state->hw.adjusted_mode.hdisplay >= 3840 && + crtc_state->hw.adjusted_mode.vdisplay >= 2160) { /* Get hblank early enable value required */ + val &= ~HBLANK_START_COUNT_MASK(pipe); hblank_early_prog = calc_hblank_early_prog(encoder, crtc_state); - if (hblank_early_prog < 32) { - val &= ~HBLANK_START_COUNT_MASK(pipe); + if (hblank_early_prog < 32) val |= HBLANK_START_COUNT(pipe, HBLANK_START_COUNT_32); - } else if (hblank_early_prog < 64) { - val &= ~HBLANK_START_COUNT_MASK(pipe); + else if (hblank_early_prog < 64) val |= HBLANK_START_COUNT(pipe, HBLANK_START_COUNT_64); - } else if (hblank_early_prog < 96) { - val &= ~HBLANK_START_COUNT_MASK(pipe); + else if (hblank_early_prog < 96) val |= HBLANK_START_COUNT(pipe, HBLANK_START_COUNT_96); - } else { - val &= ~HBLANK_START_COUNT_MASK(pipe); + else val |= HBLANK_START_COUNT(pipe, HBLANK_START_COUNT_128); - } /* Get samples room value required */ + val &= ~NUMBER_SAMPLES_PER_LINE_MASK(pipe); samples_room = calc_samples_room(crtc_state); - if (samples_room < 3) { - val &= ~NUMBER_SAMPLES_PER_LINE_MASK(pipe); + if (samples_room < 3) val |= NUMBER_SAMPLES_PER_LINE(pipe, samples_room); - } else { - /* Program 0 i.e "All Samples available in buffer" */ - val &= ~NUMBER_SAMPLES_PER_LINE_MASK(pipe); + else /* Program 0 i.e "All Samples available in buffer" */ val |= NUMBER_SAMPLES_PER_LINE(pipe, 0x0); - } } intel_de_write(i915, AUD_CONFIG_BE, val); @@ -1309,7 +1303,7 @@ static void i915_audio_component_init(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 9) { aud_freq_init = intel_de_read(dev_priv, AUD_FREQ_CNTRL); - if (INTEL_GEN(dev_priv) >= 12) + if (DISPLAY_VER(dev_priv) >= 12) aud_freq = AUD_FREQ_GEN12; else aud_freq = aud_freq_init; diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 3d0c035b5e38..5b6922e28ef2 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -610,7 +610,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *i915) * Only parse SDVO mappings on gens that could have SDVO. This isn't * accurate and doesn't have to be, as long as it's not too strict. */ - if (!IS_DISPLAY_RANGE(i915, 3, 7)) { + if (!IS_DISPLAY_VER(i915, 3, 7)) { drm_dbg_kms(&i915->drm, "Skipping SDVO device mapping\n"); return; } @@ -917,7 +917,7 @@ parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb) * Old decimal value is wake up time in multiples of 100 us. */ if (bdb->version >= 205 && - (IS_GEN9_BC(i915) || DISPLAY_VER(i915) >= 10)) { + (DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) { switch (psr_table->tp1_wakeup_time) { case 0: i915->vbt.psr.tp1_wakeup_time_us = 500; @@ -1651,7 +1651,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) const u8 *ddc_pin_map; int n_entries; - if (HAS_PCH_ADP(i915)) { + if (IS_ALDERLAKE_S(i915)) { ddc_pin_map = adls_ddc_pin_map; n_entries = ARRAY_SIZE(adls_ddc_pin_map); } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { @@ -1659,7 +1659,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) } else if (IS_ROCKETLAKE(i915) && INTEL_PCH_TYPE(i915) == PCH_TGP) { ddc_pin_map = rkl_pch_tgp_ddc_pin_map; n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map); - } else if (HAS_PCH_TGP(i915) && IS_GEN9_BC(i915)) { + } else if (HAS_PCH_TGP(i915) && DISPLAY_VER(i915) == 9) { ddc_pin_map = gen9bc_tgp_ddc_pin_map; n_entries = ARRAY_SIZE(gen9bc_tgp_ddc_pin_map); } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) { @@ -1743,8 +1743,24 @@ static enum port dvo_port_to_port(struct drm_i915_private *i915, [PORT_TC3] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 }, [PORT_TC4] = { DVO_PORT_HDMIE, DVO_PORT_DPE, -1 }, }; + static const int xelpd_port_mapping[][3] = { + [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 }, + [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 }, + [PORT_C] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 }, + [PORT_D_XELPD] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 }, + [PORT_E_XELPD] = { DVO_PORT_HDMIE, DVO_PORT_DPE, -1 }, + [PORT_TC1] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 }, + [PORT_TC2] = { DVO_PORT_HDMIG, DVO_PORT_DPG, -1 }, + [PORT_TC3] = { DVO_PORT_HDMIH, DVO_PORT_DPH, -1 }, + [PORT_TC4] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 }, + }; - if (IS_ALDERLAKE_S(i915)) + if (DISPLAY_VER(i915) == 13) + return __dvo_port_to_port(ARRAY_SIZE(xelpd_port_mapping), + ARRAY_SIZE(xelpd_port_mapping[0]), + xelpd_port_mapping, + dvo_port); + else if (IS_ALDERLAKE_S(i915)) return __dvo_port_to_port(ARRAY_SIZE(adls_port_mapping), ARRAY_SIZE(adls_port_mapping[0]), adls_port_mapping, @@ -1852,6 +1868,19 @@ intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data *devdata) devdata->child.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR; } +static bool is_port_valid(struct drm_i915_private *i915, enum port port) +{ + /* + * On some ICL/CNL SKUs port F is not present, but broken VBTs mark + * the port as present. Only try to initialize port F for the + * SKUs that may actually have it. + */ + if (port == PORT_F && (IS_ICELAKE(i915) || IS_CANNONLAKE(i915))) + return IS_ICL_WITH_PORT_F(i915) || IS_CNL_WITH_PORT_F(i915); + + return true; +} + static void parse_ddi_port(struct drm_i915_private *i915, struct intel_bios_encoder_data *devdata) { @@ -1865,6 +1894,13 @@ static void parse_ddi_port(struct drm_i915_private *i915, if (port == PORT_NONE) return; + if (!is_port_valid(i915, port)) { + drm_dbg_kms(&i915->drm, + "VBT reports port %c as supported, but that can't be true: skipping\n", + port_name(port)); + return; + } + info = &i915->vbt.ddi_port_info[port]; if (info->devdata) { @@ -2770,7 +2806,8 @@ intel_bios_is_port_hpd_inverted(const struct drm_i915_private *i915, const struct intel_bios_encoder_data *devdata = i915->vbt.ddi_port_info[port].devdata; - if (drm_WARN_ON_ONCE(&i915->drm, !IS_GEN9_LP(i915))) + if (drm_WARN_ON_ONCE(&i915->drm, + !IS_GEMINILAKE(i915) && !IS_BROXTON(i915))) return false; return devdata && devdata->child.hpd_invert; @@ -2852,7 +2889,9 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *i915, aux_ch = AUX_CH_C; break; case DP_AUX_D: - if (IS_ALDERLAKE_S(i915)) + if (DISPLAY_VER(i915) == 13) + aux_ch = AUX_CH_D_XELPD; + else if (IS_ALDERLAKE_S(i915)) aux_ch = AUX_CH_USBC3; else if (IS_DG1(i915) || IS_ROCKETLAKE(i915)) aux_ch = AUX_CH_USBC2; @@ -2860,22 +2899,36 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *i915, aux_ch = AUX_CH_D; break; case DP_AUX_E: - if (IS_ALDERLAKE_S(i915)) + if (DISPLAY_VER(i915) == 13) + aux_ch = AUX_CH_E_XELPD; + else if (IS_ALDERLAKE_S(i915)) aux_ch = AUX_CH_USBC4; else aux_ch = AUX_CH_E; break; case DP_AUX_F: - aux_ch = AUX_CH_F; + if (DISPLAY_VER(i915) == 13) + aux_ch = AUX_CH_USBC1; + else + aux_ch = AUX_CH_F; break; case DP_AUX_G: - aux_ch = AUX_CH_G; + if (DISPLAY_VER(i915) == 13) + aux_ch = AUX_CH_USBC2; + else + aux_ch = AUX_CH_G; break; case DP_AUX_H: - aux_ch = AUX_CH_H; + if (DISPLAY_VER(i915) == 13) + aux_ch = AUX_CH_USBC3; + else + aux_ch = AUX_CH_H; break; case DP_AUX_I: - aux_ch = AUX_CH_I; + if (DISPLAY_VER(i915) == 13) + aux_ch = AUX_CH_USBC4; + else + aux_ch = AUX_CH_I; break; default: MISSING_CASE(info->alternate_aux_channel); diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 584ab5ce4106..a35435083b60 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -77,7 +77,7 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv, qi->num_points = dram_info->num_qgv_points; - if (IS_DISPLAY_VER(dev_priv, 12)) + if (DISPLAY_VER(dev_priv) == 12) switch (dram_info->type) { case INTEL_DRAM_DDR4: qi->t_bl = 4; @@ -89,7 +89,7 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv, qi->t_bl = 16; break; } - else if (IS_DISPLAY_VER(dev_priv, 11)) + else if (DISPLAY_VER(dev_priv) == 11) qi->t_bl = dev_priv->dram_info.type == INTEL_DRAM_DDR4 ? 4 : 8; if (drm_WARN_ON(&dev_priv->drm, @@ -271,9 +271,9 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv) icl_get_bw_info(dev_priv, &adls_sa_info); else if (IS_ROCKETLAKE(dev_priv)) icl_get_bw_info(dev_priv, &rkl_sa_info); - else if (IS_DISPLAY_VER(dev_priv, 12)) + else if (DISPLAY_VER(dev_priv) == 12) icl_get_bw_info(dev_priv, &tgl_sa_info); - else if (IS_DISPLAY_VER(dev_priv, 11)) + else if (DISPLAY_VER(dev_priv) == 11) icl_get_bw_info(dev_priv, &icl_sa_info); } @@ -344,6 +344,9 @@ static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, for_each_pipe(dev_priv, pipe) data_rate += bw_state->data_rate[pipe]; + if (DISPLAY_VER(dev_priv) >= 13 && intel_vtd_active()) + data_rate = data_rate * 105 / 100; + return data_rate; } @@ -390,7 +393,6 @@ int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) const struct intel_crtc_state *crtc_state; struct intel_crtc *crtc; int max_bw = 0; - int slice_id; enum pipe pipe; int i; @@ -418,6 +420,7 @@ int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) &crtc_state->wm.skl.plane_ddb_uv[plane_id]; unsigned int data_rate = crtc_state->data_rate[plane_id]; unsigned int dbuf_mask = 0; + enum dbuf_slice slice; dbuf_mask |= skl_ddb_dbuf_slice_mask(dev_priv, plane_alloc); dbuf_mask |= skl_ddb_dbuf_slice_mask(dev_priv, uv_plane_alloc); @@ -435,8 +438,8 @@ int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) * pessimistic, which shouldn't pose any significant * problem anyway. */ - for_each_dbuf_slice_in_mask(slice_id, dbuf_mask) - crtc_bw->used_bw[slice_id] += data_rate; + for_each_dbuf_slice_in_mask(dev_priv, slice, dbuf_mask) + crtc_bw->used_bw[slice] += data_rate; } } @@ -445,10 +448,11 @@ int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) for_each_pipe(dev_priv, pipe) { struct intel_dbuf_bw *crtc_bw; + enum dbuf_slice slice; crtc_bw = &new_bw_state->dbuf_bw[pipe]; - for_each_dbuf_slice(slice_id) { + for_each_dbuf_slice(dev_priv, slice) { /* * Current experimental observations show that contrary * to BSpec we get underruns once we exceed 64 * CDCLK @@ -457,7 +461,7 @@ int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) * bumped up all the time we calculate CDCLK according * to this formula for overall bw consumed by slices. */ - max_bw += crtc_bw->used_bw[slice_id]; + max_bw += crtc_bw->used_bw[slice]; } } diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 3f43ad4d7362..4656a6edc3be 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -26,6 +26,7 @@ #include "intel_atomic.h" #include "intel_bw.h" #include "intel_cdclk.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_sideband.h" @@ -723,12 +724,28 @@ static void bdw_get_cdclk(struct drm_i915_private *dev_priv, bdw_calc_voltage_level(cdclk_config->cdclk); } +static u32 bdw_cdclk_freq_sel(int cdclk) +{ + switch (cdclk) { + default: + MISSING_CASE(cdclk); + fallthrough; + case 337500: + return LCPLL_CLK_FREQ_337_5_BDW; + case 450000: + return LCPLL_CLK_FREQ_450; + case 540000: + return LCPLL_CLK_FREQ_54O_BDW; + case 675000: + return LCPLL_CLK_FREQ_675_BDW; + } +} + static void bdw_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { int cdclk = cdclk_config->cdclk; - u32 val; int ret; if (drm_WARN(&dev_priv->drm, @@ -748,9 +765,8 @@ static void bdw_set_cdclk(struct drm_i915_private *dev_priv, return; } - val = intel_de_read(dev_priv, LCPLL_CTL); - val |= LCPLL_CD_SOURCE_FCLK; - intel_de_write(dev_priv, LCPLL_CTL, val); + intel_de_rmw(dev_priv, LCPLL_CTL, + 0, LCPLL_CD_SOURCE_FCLK); /* * According to the spec, it should be enough to poll for this 1 us. @@ -760,32 +776,11 @@ static void bdw_set_cdclk(struct drm_i915_private *dev_priv, LCPLL_CD_SOURCE_FCLK_DONE, 100)) drm_err(&dev_priv->drm, "Switching to FCLK failed\n"); - val = intel_de_read(dev_priv, LCPLL_CTL); - val &= ~LCPLL_CLK_FREQ_MASK; - - switch (cdclk) { - default: - MISSING_CASE(cdclk); - fallthrough; - case 337500: - val |= LCPLL_CLK_FREQ_337_5_BDW; - break; - case 450000: - val |= LCPLL_CLK_FREQ_450; - break; - case 540000: - val |= LCPLL_CLK_FREQ_54O_BDW; - break; - case 675000: - val |= LCPLL_CLK_FREQ_675_BDW; - break; - } - - intel_de_write(dev_priv, LCPLL_CTL, val); + intel_de_rmw(dev_priv, LCPLL_CTL, + LCPLL_CLK_FREQ_MASK, bdw_cdclk_freq_sel(cdclk)); - val = intel_de_read(dev_priv, LCPLL_CTL); - val &= ~LCPLL_CD_SOURCE_FCLK; - intel_de_write(dev_priv, LCPLL_CTL, val); + intel_de_rmw(dev_priv, LCPLL_CTL, + LCPLL_CD_SOURCE_FCLK, 0); if (wait_for_us((intel_de_read(dev_priv, LCPLL_CTL) & LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) @@ -954,10 +949,8 @@ static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, intel_update_max_cdclk(dev_priv); } -static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) +static u32 skl_dpll0_link_rate(struct drm_i915_private *dev_priv, int vco) { - u32 val; - drm_WARN_ON(&dev_priv->drm, vco != 8100000 && vco != 8640000); /* @@ -969,23 +962,24 @@ static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) * rate later on, with the constraint of choosing a frequency that * works with vco. */ - val = intel_de_read(dev_priv, DPLL_CTRL1); - - val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) | - DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)); - val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0); if (vco == 8640000) - val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, - SKL_DPLL0); + return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0); else - val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, - SKL_DPLL0); + return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0); +} - intel_de_write(dev_priv, DPLL_CTRL1, val); +static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) +{ + intel_de_rmw(dev_priv, DPLL_CTRL1, + DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | + DPLL_CTRL1_SSC(SKL_DPLL0) | + DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0), + DPLL_CTRL1_OVERRIDE(SKL_DPLL0) | + skl_dpll0_link_rate(dev_priv, vco)); intel_de_posting_read(dev_priv, DPLL_CTRL1); - intel_de_write(dev_priv, LCPLL1_CTL, - intel_de_read(dev_priv, LCPLL1_CTL) | LCPLL_PLL_ENABLE); + intel_de_rmw(dev_priv, LCPLL1_CTL, + 0, LCPLL_PLL_ENABLE); if (intel_de_wait_for_set(dev_priv, LCPLL1_CTL, LCPLL_PLL_LOCK, 5)) drm_err(&dev_priv->drm, "DPLL0 not locked\n"); @@ -998,14 +992,38 @@ static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) static void skl_dpll0_disable(struct drm_i915_private *dev_priv) { - intel_de_write(dev_priv, LCPLL1_CTL, - intel_de_read(dev_priv, LCPLL1_CTL) & ~LCPLL_PLL_ENABLE); + intel_de_rmw(dev_priv, LCPLL1_CTL, + LCPLL_PLL_ENABLE, 0); + if (intel_de_wait_for_clear(dev_priv, LCPLL1_CTL, LCPLL_PLL_LOCK, 1)) drm_err(&dev_priv->drm, "Couldn't disable DPLL0\n"); dev_priv->cdclk.hw.vco = 0; } +static u32 skl_cdclk_freq_sel(struct drm_i915_private *dev_priv, + int cdclk, int vco) +{ + switch (cdclk) { + default: + drm_WARN_ON(&dev_priv->drm, + cdclk != dev_priv->cdclk.hw.bypass); + drm_WARN_ON(&dev_priv->drm, vco != 0); + fallthrough; + case 308571: + case 337500: + return CDCLK_FREQ_337_308; + case 450000: + case 432000: + return CDCLK_FREQ_450_432; + case 540000: + return CDCLK_FREQ_540; + case 617143: + case 675000: + return CDCLK_FREQ_675_617; + } +} + static void skl_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) @@ -1036,29 +1054,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, return; } - /* Choose frequency for this cdclk */ - switch (cdclk) { - default: - drm_WARN_ON(&dev_priv->drm, - cdclk != dev_priv->cdclk.hw.bypass); - drm_WARN_ON(&dev_priv->drm, vco != 0); - fallthrough; - case 308571: - case 337500: - freq_select = CDCLK_FREQ_337_308; - break; - case 450000: - case 432000: - freq_select = CDCLK_FREQ_450_432; - break; - case 540000: - freq_select = CDCLK_FREQ_540; - break; - case 617143: - case 675000: - freq_select = CDCLK_FREQ_675_617; - break; - } + freq_select = skl_cdclk_freq_sel(dev_priv, cdclk, vco); if (dev_priv->cdclk.hw.vco != 0 && dev_priv->cdclk.hw.vco != vco) @@ -1257,6 +1253,42 @@ static const struct intel_cdclk_vals rkl_cdclk_table[] = { {} }; +static const struct intel_cdclk_vals adlp_a_step_cdclk_table[] = { + { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, + { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, + { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, + { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, + { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + {} +}; + +static const struct intel_cdclk_vals adlp_cdclk_table[] = { + { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 }, + { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, + { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 }, + { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, + { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, + { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, + { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, + { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + {} +}; + static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk) { const struct intel_cdclk_vals *table = dev_priv->cdclk.table; @@ -1432,18 +1464,12 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, div = 2; break; case BXT_CDCLK_CD2X_DIV_SEL_1_5: - drm_WARN(&dev_priv->drm, - DISPLAY_VER(dev_priv) >= 10, - "Unsupported divider\n"); div = 3; break; case BXT_CDCLK_CD2X_DIV_SEL_2: div = 4; break; case BXT_CDCLK_CD2X_DIV_SEL_4: - drm_WARN(&dev_priv->drm, - DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv), - "Unsupported divider\n"); div = 8; break; default: @@ -1477,12 +1503,9 @@ static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco) { int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk.hw.ref); - u32 val; - val = intel_de_read(dev_priv, BXT_DE_PLL_CTL); - val &= ~BXT_DE_PLL_RATIO_MASK; - val |= BXT_DE_PLL_RATIO(ratio); - intel_de_write(dev_priv, BXT_DE_PLL_CTL, val); + intel_de_rmw(dev_priv, BXT_DE_PLL_CTL, + BXT_DE_PLL_RATIO_MASK, BXT_DE_PLL_RATIO(ratio)); intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE); @@ -1496,16 +1519,12 @@ static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco) static void cnl_cdclk_pll_disable(struct drm_i915_private *dev_priv) { - u32 val; - - val = intel_de_read(dev_priv, BXT_DE_PLL_ENABLE); - val &= ~BXT_DE_PLL_PLL_ENABLE; - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); + intel_de_rmw(dev_priv, BXT_DE_PLL_ENABLE, + BXT_DE_PLL_PLL_ENABLE, 0); /* Timeout 200us */ - if (wait_for((intel_de_read(dev_priv, BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) == 0, 1)) - drm_err(&dev_priv->drm, - "timeout waiting for CDCLK PLL unlock\n"); + if (intel_de_wait_for_clear(dev_priv, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) + drm_err(&dev_priv->drm, "timeout waiting for CDCLK PLL unlock\n"); dev_priv->cdclk.hw.vco = 0; } @@ -1522,9 +1541,8 @@ static void cnl_cdclk_pll_enable(struct drm_i915_private *dev_priv, int vco) intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); /* Timeout 200us */ - if (wait_for((intel_de_read(dev_priv, BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) != 0, 1)) - drm_err(&dev_priv->drm, - "timeout waiting for CDCLK PLL lock\n"); + if (intel_de_wait_for_set(dev_priv, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) + drm_err(&dev_priv->drm, "timeout waiting for CDCLK PLL lock\n"); dev_priv->cdclk.hw.vco = vco; } @@ -1549,13 +1567,34 @@ static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe } } +static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv, + int cdclk, int vco) +{ + /* cdclk = vco / 2 / div{1,1.5,2,4} */ + switch (DIV_ROUND_CLOSEST(vco, cdclk)) { + default: + drm_WARN_ON(&dev_priv->drm, + cdclk != dev_priv->cdclk.hw.bypass); + drm_WARN_ON(&dev_priv->drm, vco != 0); + fallthrough; + case 2: + return BXT_CDCLK_CD2X_DIV_SEL_1; + case 3: + return BXT_CDCLK_CD2X_DIV_SEL_1_5; + case 4: + return BXT_CDCLK_CD2X_DIV_SEL_2; + case 8: + return BXT_CDCLK_CD2X_DIV_SEL_4; + } +} + static void bxt_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; - u32 val, divider; + u32 val; int ret; /* Inform power controller of upcoming frequency change. */ @@ -1580,33 +1619,6 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, return; } - /* cdclk = vco / 2 / div{1,1.5,2,4} */ - switch (DIV_ROUND_CLOSEST(vco, cdclk)) { - default: - drm_WARN_ON(&dev_priv->drm, - cdclk != dev_priv->cdclk.hw.bypass); - drm_WARN_ON(&dev_priv->drm, vco != 0); - fallthrough; - case 2: - divider = BXT_CDCLK_CD2X_DIV_SEL_1; - break; - case 3: - drm_WARN(&dev_priv->drm, - DISPLAY_VER(dev_priv) >= 10, - "Unsupported divider\n"); - divider = BXT_CDCLK_CD2X_DIV_SEL_1_5; - break; - case 4: - divider = BXT_CDCLK_CD2X_DIV_SEL_2; - break; - case 8: - drm_WARN(&dev_priv->drm, - DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv), - "Unsupported divider\n"); - divider = BXT_CDCLK_CD2X_DIV_SEL_4; - break; - } - if (DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) { if (dev_priv->cdclk.hw.vco != 0 && dev_priv->cdclk.hw.vco != vco) @@ -1624,14 +1636,16 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, bxt_de_pll_enable(dev_priv, vco); } - val = divider | skl_cdclk_decimal(cdclk) | - bxt_cdclk_cd2x_pipe(dev_priv, pipe); + val = bxt_cdclk_cd2x_div_sel(dev_priv, cdclk, vco) | + bxt_cdclk_cd2x_pipe(dev_priv, pipe) | + skl_cdclk_decimal(cdclk); /* * Disable SSA Precharge when CD clock frequency < 500 MHz, * enable otherwise. */ - if (IS_GEN9_LP(dev_priv) && cdclk >= 500000) + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + cdclk >= 500000) val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; intel_de_write(dev_priv, CDCLK_CTL, val); @@ -1710,29 +1724,16 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) expected = skl_cdclk_decimal(cdclk); /* Figure out what CD2X divider we should be using for this cdclk */ - switch (DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.vco, - dev_priv->cdclk.hw.cdclk)) { - case 2: - expected |= BXT_CDCLK_CD2X_DIV_SEL_1; - break; - case 3: - expected |= BXT_CDCLK_CD2X_DIV_SEL_1_5; - break; - case 4: - expected |= BXT_CDCLK_CD2X_DIV_SEL_2; - break; - case 8: - expected |= BXT_CDCLK_CD2X_DIV_SEL_4; - break; - default: - goto sanitize; - } + expected |= bxt_cdclk_cd2x_div_sel(dev_priv, + dev_priv->cdclk.hw.cdclk, + dev_priv->cdclk.hw.vco); /* * Disable SSA Precharge when CD clock frequency < 500 MHz, * enable otherwise. */ - if (IS_GEN9_LP(dev_priv) && dev_priv->cdclk.hw.cdclk >= 500000) + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + dev_priv->cdclk.hw.cdclk >= 500000) expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; if (cdctl == expected) @@ -1797,9 +1798,9 @@ static void bxt_cdclk_uninit_hw(struct drm_i915_private *dev_priv) */ void intel_cdclk_init_hw(struct drm_i915_private *i915) { - if (IS_GEN9_LP(i915) || DISPLAY_VER(i915) >= 10) + if (DISPLAY_VER(i915) >= 10 || IS_BROXTON(i915)) bxt_cdclk_init_hw(i915); - else if (IS_GEN9_BC(i915)) + else if (DISPLAY_VER(i915) == 9) skl_cdclk_init_hw(i915); } @@ -1812,9 +1813,9 @@ void intel_cdclk_init_hw(struct drm_i915_private *i915) */ void intel_cdclk_uninit_hw(struct drm_i915_private *i915) { - if (DISPLAY_VER(i915) >= 10 || IS_GEN9_LP(i915)) + if (DISPLAY_VER(i915) >= 10 || IS_BROXTON(i915)) bxt_cdclk_uninit_hw(i915); - else if (IS_GEN9_BC(i915)) + else if (DISPLAY_VER(i915) == 9) skl_cdclk_uninit_hw(i915); } @@ -1852,7 +1853,7 @@ static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *b) { /* Older hw doesn't have the capability */ - if (DISPLAY_VER(dev_priv) < 10 && !IS_GEN9_LP(dev_priv)) + if (DISPLAY_VER(dev_priv) < 10 && !IS_BROXTON(dev_priv)) return false; return a->cdclk != b->cdclk && @@ -2002,7 +2003,7 @@ static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state) if (DISPLAY_VER(dev_priv) >= 10) return DIV_ROUND_UP(pixel_rate, 2); - else if (IS_DISPLAY_VER(dev_priv, 9) || + else if (DISPLAY_VER(dev_priv) == 9 || IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) return pixel_rate; else if (IS_CHERRYVIEW(dev_priv)) @@ -2050,10 +2051,10 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) crtc_state->has_audio && crtc_state->port_clock >= 540000 && crtc_state->lane_count == 4) { - if (IS_DISPLAY_VER(dev_priv, 10)) { + if (DISPLAY_VER(dev_priv) == 10) { /* Display WA #1145: glk,cnl */ min_cdclk = max(316800, min_cdclk); - } else if (IS_DISPLAY_VER(dev_priv, 9) || IS_BROADWELL(dev_priv)) { + } else if (DISPLAY_VER(dev_priv) == 9 || IS_BROADWELL(dev_priv)) { /* Display WA #1144: skl,bxt */ min_cdclk = max(432000, min_cdclk); } @@ -2389,44 +2390,6 @@ static int bxt_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) return 0; } -static int intel_modeset_all_pipes(struct intel_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - struct intel_crtc *crtc; - - /* - * Add all pipes to the state, and force - * a modeset on all the active ones. - */ - for_each_intel_crtc(&dev_priv->drm, crtc) { - struct intel_crtc_state *crtc_state; - int ret; - - crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - if (!crtc_state->hw.active || - drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) - continue; - - crtc_state->uapi.mode_changed = true; - - ret = drm_atomic_add_affected_connectors(&state->base, - &crtc->base); - if (ret) - return ret; - - ret = intel_atomic_add_affected_planes(state, crtc); - if (ret) - return ret; - - crtc_state->update_planes |= crtc_state->active_planes; - } - - return 0; -} - static int fixed_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) { int min_cdclk; @@ -2592,7 +2555,7 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 10) return 2 * max_cdclk_freq; - else if (IS_DISPLAY_VER(dev_priv, 9) || + else if (DISPLAY_VER(dev_priv) == 9 || IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) return max_cdclk_freq; else if (IS_CHERRYVIEW(dev_priv)) @@ -2625,7 +2588,11 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv) dev_priv->max_cdclk_freq = 652800; } else if (IS_CANNONLAKE(dev_priv)) { dev_priv->max_cdclk_freq = 528000; - } else if (IS_GEN9_BC(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv)) { + dev_priv->max_cdclk_freq = 316800; + } else if (IS_BROXTON(dev_priv)) { + dev_priv->max_cdclk_freq = 624000; + } else if (DISPLAY_VER(dev_priv) == 9) { u32 limit = intel_de_read(dev_priv, SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; int max_cdclk, vco; @@ -2647,10 +2614,6 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv) max_cdclk = 308571; dev_priv->max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco); - } else if (IS_GEMINILAKE(dev_priv)) { - dev_priv->max_cdclk_freq = 316800; - } else if (IS_BROXTON(dev_priv)) { - dev_priv->max_cdclk_freq = 624000; } else if (IS_BROADWELL(dev_priv)) { /* * FIXME with extra cooling we can allow @@ -2848,7 +2811,17 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) */ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) { - if (IS_ROCKETLAKE(dev_priv)) { + if (IS_ALDERLAKE_P(dev_priv)) { + dev_priv->display.set_cdclk = bxt_set_cdclk; + dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; + dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; + dev_priv->display.calc_voltage_level = tgl_calc_voltage_level; + /* Wa_22011320316:adlp[a0] */ + if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_A0)) + dev_priv->cdclk.table = adlp_a_step_cdclk_table; + else + dev_priv->cdclk.table = adlp_cdclk_table; + } else if (IS_ROCKETLAKE(dev_priv)) { dev_priv->display.set_cdclk = bxt_set_cdclk; dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; @@ -2878,7 +2851,7 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; dev_priv->display.calc_voltage_level = cnl_calc_voltage_level; dev_priv->cdclk.table = cnl_cdclk_table; - } else if (IS_GEN9_LP(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; dev_priv->display.set_cdclk = bxt_set_cdclk; dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk; @@ -2887,7 +2860,7 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) dev_priv->cdclk.table = glk_cdclk_table; else dev_priv->cdclk.table = bxt_cdclk_table; - } else if (IS_GEN9_BC(dev_priv)) { + } else if (DISPLAY_VER(dev_priv) == 9) { dev_priv->display.bw_calc_min_cdclk = skl_bw_calc_min_cdclk; dev_priv->display.set_cdclk = skl_set_cdclk; dev_priv->display.modeset_calc_cdclk = skl_modeset_calc_cdclk; @@ -2908,9 +2881,9 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) dev_priv->display.modeset_calc_cdclk = fixed_modeset_calc_cdclk; } - if (DISPLAY_VER(dev_priv) >= 10 || IS_GEN9_LP(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 10 || IS_BROXTON(dev_priv)) dev_priv->display.get_cdclk = bxt_get_cdclk; - else if (IS_GEN9_BC(dev_priv)) + else if (DISPLAY_VER(dev_priv) == 9) dev_priv->display.get_cdclk = skl_get_cdclk; else if (IS_BROADWELL(dev_priv)) dev_priv->display.get_cdclk = bdw_get_cdclk; diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index c75d7124d57a..dab892d2251b 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -23,6 +23,7 @@ */ #include "intel_color.h" +#include "intel_de.h" #include "intel_display_types.h" #define CTM_COEFF_SIGN (1ULL << 63) @@ -225,7 +226,7 @@ static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state) */ return crtc_state->limited_color_range && (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) || - IS_DISPLAY_RANGE(dev_priv, 9, 10)); + IS_DISPLAY_VER(dev_priv, 9, 10)); } static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, @@ -1711,7 +1712,7 @@ int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_stat } else { if (DISPLAY_VER(dev_priv) >= 11) return icl_gamma_precision(crtc_state); - else if (IS_DISPLAY_VER(dev_priv, 10)) + else if (DISPLAY_VER(dev_priv) == 10) return glk_gamma_precision(crtc_state); else if (IS_IRONLAKE(dev_priv)) return ilk_gamma_precision(crtc_state); @@ -2136,7 +2137,7 @@ void intel_color_init(struct intel_crtc *crtc) if (DISPLAY_VER(dev_priv) >= 11) { dev_priv->display.load_luts = icl_load_luts; dev_priv->display.read_luts = icl_read_luts; - } else if (IS_DISPLAY_VER(dev_priv, 10)) { + } else if (DISPLAY_VER(dev_priv) == 10) { dev_priv->display.load_luts = glk_load_luts; dev_priv->display.read_luts = glk_read_luts; } else if (DISPLAY_VER(dev_priv) >= 8) { diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index 5df57d16a401..487c54cd5982 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -4,6 +4,7 @@ */ #include "intel_combo_phy.h" +#include "intel_de.h" #include "intel_display_types.h" #define for_each_combo_phy(__dev_priv, __phy) \ diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index d5ceb7bdc14b..9bed1ccecea0 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -282,14 +282,12 @@ void intel_attach_hdmi_colorspace_property(struct drm_connector *connector) { if (!drm_mode_create_hdmi_colorspace_property(connector)) - drm_object_attach_property(&connector->base, - connector->colorspace_property, 0); + drm_connector_attach_colorspace_property(connector); } void intel_attach_dp_colorspace_property(struct drm_connector *connector) { if (!drm_mode_create_dp_colorspace_property(connector)) - drm_object_attach_property(&connector->base, - connector->colorspace_property, 0); + drm_connector_attach_colorspace_property(connector); } diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 580d652c3276..648f1c0d3d39 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -36,7 +36,9 @@ #include "i915_drv.h" #include "intel_connector.h" #include "intel_crt.h" +#include "intel_crtc.h" #include "intel_ddi.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fifo_underrun.h" @@ -356,7 +358,7 @@ intel_crt_mode_valid(struct drm_connector *connector, * DAC limit supposedly 355 MHz. */ max_clock = 270000; - else if (IS_DISPLAY_RANGE(dev_priv, 3, 4)) + else if (IS_DISPLAY_VER(dev_priv, 3, 4)) max_clock = 400000; else max_clock = 350000; @@ -711,7 +713,7 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe) /* Set the border color to purple. */ intel_uncore_write(uncore, bclrpat_reg, 0x500050); - if (!IS_DISPLAY_VER(dev_priv, 2)) { + if (DISPLAY_VER(dev_priv) != 2) { u32 pipeconf = intel_uncore_read(uncore, pipeconf_reg); intel_uncore_write(uncore, pipeconf_reg, @@ -1047,7 +1049,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) else crt->base.pipe_mask = ~0; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) connector->interlace_allowed = 0; else connector->interlace_allowed = 1; diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 39358076c05b..95ff1707b4bd 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -302,11 +302,11 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) if (IS_CHERRYVIEW(dev_priv) || IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv)) funcs = &g4x_crtc_funcs; - else if (IS_DISPLAY_VER(dev_priv, 4)) + else if (DISPLAY_VER(dev_priv) == 4) funcs = &i965_crtc_funcs; else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv)) funcs = &i915gm_crtc_funcs; - else if (IS_DISPLAY_VER(dev_priv, 3)) + else if (DISPLAY_VER(dev_priv) == 3) funcs = &i915_crtc_funcs; else funcs = &i8xx_crtc_funcs; diff --git a/drivers/gpu/drm/i915/display/intel_crtc.h b/drivers/gpu/drm/i915/display/intel_crtc.h index 08112d557411..a5ae997581aa 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.h +++ b/drivers/gpu/drm/i915/display/intel_crtc.h @@ -18,5 +18,8 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe); struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc); void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, struct intel_crtc *crtc); +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc); +void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state); +void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state); #endif diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c index 794efcc3ca08..26a922d34263 100644 --- a/drivers/gpu/drm/i915/display/intel_csr.c +++ b/drivers/gpu/drm/i915/display/intel_csr.c @@ -38,50 +38,56 @@ * low-power state and comes back to normal. */ +#define DMC_PATH(platform, major, minor) \ + "i915/" \ + __stringify(platform) "_dmc_ver" \ + __stringify(major) "_" \ + __stringify(minor) ".bin" + #define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE -#define ADLS_CSR_PATH "i915/adls_dmc_ver2_01.bin" +#define ADLS_CSR_PATH DMC_PATH(adls, 2, 01) #define ADLS_CSR_VERSION_REQUIRED CSR_VERSION(2, 1) MODULE_FIRMWARE(ADLS_CSR_PATH); -#define DG1_CSR_PATH "i915/dg1_dmc_ver2_02.bin" +#define DG1_CSR_PATH DMC_PATH(dg1, 2, 02) #define DG1_CSR_VERSION_REQUIRED CSR_VERSION(2, 2) MODULE_FIRMWARE(DG1_CSR_PATH); -#define RKL_CSR_PATH "i915/rkl_dmc_ver2_02.bin" +#define RKL_CSR_PATH DMC_PATH(rkl, 2, 02) #define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 2) MODULE_FIRMWARE(RKL_CSR_PATH); -#define TGL_CSR_PATH "i915/tgl_dmc_ver2_08.bin" +#define TGL_CSR_PATH DMC_PATH(tgl, 2, 08) #define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 8) MODULE_FIRMWARE(TGL_CSR_PATH); -#define ICL_CSR_PATH "i915/icl_dmc_ver1_09.bin" +#define ICL_CSR_PATH DMC_PATH(icl, 1, 09) #define ICL_CSR_VERSION_REQUIRED CSR_VERSION(1, 9) #define ICL_CSR_MAX_FW_SIZE 0x6000 MODULE_FIRMWARE(ICL_CSR_PATH); -#define CNL_CSR_PATH "i915/cnl_dmc_ver1_07.bin" +#define CNL_CSR_PATH DMC_PATH(cnl, 1, 07) #define CNL_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) #define CNL_CSR_MAX_FW_SIZE GLK_CSR_MAX_FW_SIZE MODULE_FIRMWARE(CNL_CSR_PATH); -#define GLK_CSR_PATH "i915/glk_dmc_ver1_04.bin" +#define GLK_CSR_PATH DMC_PATH(glk, 1, 04) #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) #define GLK_CSR_MAX_FW_SIZE 0x4000 MODULE_FIRMWARE(GLK_CSR_PATH); -#define KBL_CSR_PATH "i915/kbl_dmc_ver1_04.bin" +#define KBL_CSR_PATH DMC_PATH(kbl, 1, 04) #define KBL_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) #define KBL_CSR_MAX_FW_SIZE BXT_CSR_MAX_FW_SIZE MODULE_FIRMWARE(KBL_CSR_PATH); -#define SKL_CSR_PATH "i915/skl_dmc_ver1_27.bin" +#define SKL_CSR_PATH DMC_PATH(skl, 1, 27) #define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 27) #define SKL_CSR_MAX_FW_SIZE BXT_CSR_MAX_FW_SIZE MODULE_FIRMWARE(SKL_CSR_PATH); -#define BXT_CSR_PATH "i915/bxt_dmc_ver1_07.bin" +#define BXT_CSR_PATH DMC_PATH(bxt, 1, 07) #define BXT_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) #define BXT_CSR_MAX_FW_SIZE 0x3000 MODULE_FIRMWARE(BXT_CSR_PATH); @@ -284,7 +290,7 @@ static void gen9_set_dc_state_debugmask(struct drm_i915_private *dev_priv) mask = DC_STATE_DEBUG_MASK_MEMORY_UP; - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) mask |= DC_STATE_DEBUG_MASK_CORES; /* The below bit doesn't need to be cleared ever afterwards */ @@ -709,7 +715,7 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) csr->fw_path = TGL_CSR_PATH; csr->required_version = TGL_CSR_VERSION_REQUIRED; csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE; - } else if (IS_DISPLAY_VER(dev_priv, 11)) { + } else if (DISPLAY_VER(dev_priv) == 11) { csr->fw_path = ICL_CSR_PATH; csr->required_version = ICL_CSR_VERSION_REQUIRED; csr->max_fw_size = ICL_CSR_MAX_FW_SIZE; diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 2345f2efd60b..2ab389b38694 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -13,6 +13,7 @@ #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_cursor.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_display.h" #include "intel_fb.h" diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 953de42e277c..eccbdd42d223 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -31,8 +31,10 @@ #include "intel_audio.h" #include "intel_combo_phy.h" #include "intel_connector.h" +#include "intel_crtc.h" #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_link_training.h" @@ -113,7 +115,8 @@ void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, &n_entries); /* If we're boosting the current, set bit 31 of trans1 */ - if (IS_GEN9_BC(dev_priv) && intel_bios_encoder_dp_boost_level(encoder->devdata)) + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv) && + intel_bios_encoder_dp_boost_level(encoder->devdata)) iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE; for (i = 0; i < n_entries; i++) { @@ -146,7 +149,8 @@ static void intel_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, level = n_entries - 1; /* If we're boosting the current, set bit 31 of trans1 */ - if (IS_GEN9_BC(dev_priv) && intel_bios_encoder_hdmi_boost_level(encoder->devdata)) + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv) && + intel_bios_encoder_hdmi_boost_level(encoder->devdata)) iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE; /* Entry 9 is for HDMI: */ @@ -174,7 +178,7 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv, enum port port) { /* Wait > 518 usecs for DDI_BUF_CTL to be non idle */ - if (DISPLAY_VER(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { + if (DISPLAY_VER(dev_priv) < 10) { usleep_range(518, 1000); return; } @@ -471,7 +475,7 @@ intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, temp |= DDI_PORT_WIDTH(crtc_state->lane_count); } - if (IS_DISPLAY_RANGE(dev_priv, 8, 10) && + if (IS_DISPLAY_VER(dev_priv, 8, 10) && crtc_state->master_transcoder != INVALID_TRANSCODER) { u8 master_select = bdw_trans_port_sync_master_select(crtc_state->master_transcoder); @@ -546,7 +550,7 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state ctl &= ~TRANS_DDI_FUNC_ENABLE; - if (IS_DISPLAY_RANGE(dev_priv, 8, 10)) + if (IS_DISPLAY_VER(dev_priv, 8, 10)) ctl &= ~(TRANS_DDI_PORT_SYNC_ENABLE | TRANS_DDI_PORT_SYNC_MASTER_SELECT_MASK); @@ -759,7 +763,7 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder, *is_dp_mst = mst_pipe_mask; out: - if (*pipe_mask && IS_GEN9_LP(dev_priv)) { + if (*pipe_mask && (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))) { tmp = intel_de_read(dev_priv, BXT_PHY_CTL(port)); if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK | BXT_PHY_LANE_POWERDOWN_ACK | @@ -850,18 +854,19 @@ void intel_ddi_enable_pipe_clock(struct intel_encoder *encoder, { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum port port = encoder->port; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + u32 val; if (cpu_transcoder != TRANSCODER_EDP) { - if (DISPLAY_VER(dev_priv) >= 12) - intel_de_write(dev_priv, - TRANS_CLK_SEL(cpu_transcoder), - TGL_TRANS_CLK_SEL_PORT(port)); + if (DISPLAY_VER(dev_priv) >= 13) + val = TGL_TRANS_CLK_SEL_PORT(phy); + else if (DISPLAY_VER(dev_priv) >= 12) + val = TGL_TRANS_CLK_SEL_PORT(encoder->port); else - intel_de_write(dev_priv, - TRANS_CLK_SEL(cpu_transcoder), - TRANS_CLK_SEL_PORT(port)); + val = TRANS_CLK_SEL_PORT(encoder->port); + + intel_de_write(dev_priv, TRANS_CLK_SEL(cpu_transcoder), val); } } @@ -976,7 +981,7 @@ static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp, tgl_get_combo_buf_trans(encoder, crtc_state, &n_entries); else tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries); - } else if (IS_DISPLAY_VER(dev_priv, 11)) { + } else if (DISPLAY_VER(dev_priv) == 11) { if (IS_PLATFORM(dev_priv, INTEL_JASPERLAKE)) jsl_get_combo_buf_trans(encoder, crtc_state, &n_entries); else if (IS_PLATFORM(dev_priv, INTEL_ELKHARTLAKE)) @@ -987,7 +992,7 @@ static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp, icl_get_mg_buf_trans(encoder, crtc_state, &n_entries); } else if (IS_CANNONLAKE(dev_priv)) { cnl_get_buf_trans(encoder, crtc_state, &n_entries); - } else if (IS_GEN9_LP(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { bxt_get_buf_trans(encoder, crtc_state, &n_entries); } else { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) @@ -1454,6 +1459,14 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, val = intel_de_read(dev_priv, DKL_TX_DPCNTL2(tc_port)); val &= ~DKL_TX_DP20BITMODE; intel_de_write(dev_priv, DKL_TX_DPCNTL2(tc_port), val); + + if ((intel_crtc_has_dp_encoder(crtc_state) && + crtc_state->port_clock == 162000) || + (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) && + crtc_state->port_clock == 594000)) + val |= DKL_TX_LOADGEN_SHARING_PMD_DISABLE; + else + val &= ~DKL_TX_LOADGEN_SHARING_PMD_DISABLE; } } @@ -1555,7 +1568,7 @@ hsw_set_signal_levels(struct intel_dp *intel_dp, intel_dp->DP &= ~DDI_BUF_EMP_MASK; intel_dp->DP |= signal_levels; - if (IS_GEN9_BC(dev_priv)) + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) skl_ddi_set_iboost(encoder, crtc_state, level); intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP); @@ -2332,8 +2345,8 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_DOWNSPREAD_CTRL, enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0) <= 0) drm_dbg_kms(&i915->drm, - "Failed to set MSA_TIMING_PAR_IGNORE %s in the sink\n", - enable ? "enable" : "disable"); + "Failed to %s MSA_TIMING_PAR_IGNORE in the sink\n", + enabledisable(enable)); } static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, @@ -2648,7 +2661,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, icl_ddi_vswing_sequence(encoder, crtc_state, level); else if (IS_CANNONLAKE(dev_priv)) cnl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_ddi_vswing_sequence(encoder, crtc_state, level); else intel_prepare_dp_ddi_buffers(encoder, crtc_state); @@ -3092,20 +3105,20 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) >= 12) tgl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_DISPLAY_VER(dev_priv, 11)) + else if (DISPLAY_VER(dev_priv) == 11) icl_ddi_vswing_sequence(encoder, crtc_state, level); else if (IS_CANNONLAKE(dev_priv)) cnl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_ddi_vswing_sequence(encoder, crtc_state, level); else intel_prepare_hdmi_ddi_buffers(encoder, level); - if (IS_GEN9_BC(dev_priv)) + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) skl_ddi_set_iboost(encoder, crtc_state, level); /* Display WA #1143: skl,kbl,cfl */ - if (IS_GEN9_BC(dev_priv)) { + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) { /* * For some reason these chicken bits have been * stuffed into a transcoder register, event though @@ -3321,7 +3334,7 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state, * Type-C ports. Skip this step for TBT. */ intel_tc_port_set_fia_lane_count(dig_port, crtc_state->lane_count); - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_ddi_phy_set_lane_optim_mask(encoder, crtc_state->lane_lat_optim_mask); } @@ -3679,7 +3692,7 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, if (!pipe_config->bigjoiner_slave) ddi_dotclock_get(pipe_config); - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) pipe_config->lane_lat_optim_mask = bxt_ddi_phy_get_lane_lat_optim_mask(encoder); @@ -3705,6 +3718,8 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, intel_read_dp_sdp(encoder, pipe_config, HDMI_PACKET_TYPE_GAMUT_METADATA); intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC); + + intel_psr_get_config(encoder, pipe_config); } void intel_ddi_get_clock(struct intel_encoder *encoder, @@ -3885,7 +3900,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, pipe_config->pch_pfit.enabled || pipe_config->crc_enabled; - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) pipe_config->lane_lat_optim_mask = bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); @@ -4053,7 +4068,7 @@ intel_ddi_init_dp_connector(struct intel_digital_port *dig_port) dig_port->dp.set_signal_levels = icl_set_signal_levels; else if (IS_CANNONLAKE(dev_priv)) dig_port->dp.set_signal_levels = cnl_set_signal_levels; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) dig_port->dp.set_signal_levels = bxt_set_signal_levels; else dig_port->dp.set_signal_levels = hsw_set_signal_levels; @@ -4296,7 +4311,7 @@ static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dig_port) /* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only * supported configuration */ - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) return true; /* Cannonlake: Most of SKUs don't support DDI_E, and the only @@ -4350,6 +4365,17 @@ static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy) i915->hti_state & HDPORT_DDI_USED(phy); } +static enum hpd_pin xelpd_hpd_pin(struct drm_i915_private *dev_priv, + enum port port) +{ + if (port >= PORT_D_XELPD) + return HPD_PORT_D + port - PORT_D_XELPD; + else if (port >= PORT_TC1) + return HPD_PORT_TC1 + port - PORT_TC1; + else + return HPD_PORT_A + port - PORT_A; +} + static enum hpd_pin dg1_hpd_pin(struct drm_i915_private *dev_priv, enum port port) { @@ -4489,7 +4515,13 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder = &dig_port->base; encoder->devdata = devdata; - if (DISPLAY_VER(dev_priv) >= 12) { + if (DISPLAY_VER(dev_priv) >= 13 && port >= PORT_D_XELPD) { + drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs, + DRM_MODE_ENCODER_TMDS, + "DDI %c/PHY %c", + port_name(port - PORT_D_XELPD + PORT_D), + phy_name(phy)); + } else if (DISPLAY_VER(dev_priv) >= 12) { enum tc_port tc_port = intel_port_to_tc(dev_priv, port); drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs, @@ -4585,10 +4617,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->disable_clock = cnl_ddi_disable_clock; encoder->is_clock_enabled = cnl_ddi_is_clock_enabled; encoder->get_config = cnl_ddi_get_config; - } else if (IS_GEN9_LP(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { /* BXT/GLK have fixed PLL->port mapping */ encoder->get_config = bxt_ddi_get_config; - } else if (IS_GEN9_BC(dev_priv)) { + } else if (DISPLAY_VER(dev_priv) == 9) { encoder->enable_clock = skl_ddi_enable_clock; encoder->disable_clock = skl_ddi_disable_clock; encoder->is_clock_enabled = skl_ddi_is_clock_enabled; @@ -4600,7 +4632,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->get_config = hsw_ddi_get_config; } - if (IS_DG1(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 13) + encoder->hpd_pin = xelpd_hpd_pin(dev_priv, port); + else if (IS_DG1(dev_priv)) encoder->hpd_pin = dg1_hpd_pin(dev_priv, port); else if (IS_ROCKETLAKE(dev_priv)) encoder->hpd_pin = rkl_hpd_pin(dev_priv, port); @@ -4608,11 +4642,11 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->hpd_pin = tgl_hpd_pin(dev_priv, port); else if (IS_JSL_EHL(dev_priv)) encoder->hpd_pin = ehl_hpd_pin(dev_priv, port); - else if (IS_DISPLAY_VER(dev_priv, 11)) + else if (DISPLAY_VER(dev_priv) == 11) encoder->hpd_pin = icl_hpd_pin(dev_priv, port); - else if (IS_DISPLAY_VER(dev_priv, 10)) + else if (IS_CANNONLAKE(dev_priv)) encoder->hpd_pin = cnl_hpd_pin(dev_priv, port); - else if (IS_DISPLAY_VER(dev_priv, 9)) + else if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) encoder->hpd_pin = skl_hpd_pin(dev_priv, port); else encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port); @@ -4672,7 +4706,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) else dig_port->connected = lpt_digital_port_connected; } else if (DISPLAY_VER(dev_priv) >= 8) { - if (port == PORT_A || IS_GEN9_LP(dev_priv)) + if (port == PORT_A || IS_GEMINILAKE(dev_priv) || + IS_BROXTON(dev_priv)) dig_port->connected = bdw_digital_port_connected; else dig_port->connected = lpt_digital_port_connected; diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index 5d9ce6042e87..7bcdd5c12028 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -6,6 +6,7 @@ #include "i915_drv.h" #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" +#include "intel_de.h" #include "intel_display_types.h" /* HDMI/DVI modes ignore everything but the last 2 items. So we share @@ -881,7 +882,7 @@ intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - if (IS_GEN9_BC(dev_priv)) { + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) { const struct ddi_buf_trans *ddi_translations = skl_get_buf_trans_edp(encoder, n_entries); *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); @@ -919,7 +920,7 @@ intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - if (IS_GEN9_BC(dev_priv)) { + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) { return skl_get_buf_trans_hdmi(dev_priv, n_entries); } else if (IS_BROADWELL(dev_priv)) { *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); @@ -1361,7 +1362,7 @@ int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, else tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries); *default_entry = n_entries - 1; - } else if (IS_DISPLAY_VER(dev_priv, 11)) { + } else if (DISPLAY_VER(dev_priv) == 11) { if (intel_phy_is_combo(dev_priv, phy)) icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); else @@ -1370,10 +1371,10 @@ int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, } else if (IS_CANNONLAKE(dev_priv)) { cnl_get_buf_trans_hdmi(encoder, &n_entries); *default_entry = n_entries - 1; - } else if (IS_GEN9_LP(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { bxt_get_buf_trans_hdmi(encoder, &n_entries); *default_entry = n_entries - 1; - } else if (IS_GEN9_BC(dev_priv)) { + } else if (DISPLAY_VER(dev_priv) == 9) { intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); *default_entry = 8; } else if (IS_BROADWELL(dev_priv)) { diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index 00da10bf35f5..9d8c177aa228 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -8,6 +8,7 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "i915_trace.h" #include "intel_uncore.h" static inline u32 @@ -22,26 +23,12 @@ intel_de_posting_read(struct drm_i915_private *i915, i915_reg_t reg) intel_uncore_posting_read(&i915->uncore, reg); } -/* Note: read the warnings for intel_uncore_*_fw() functions! */ -static inline u32 -intel_de_read_fw(struct drm_i915_private *i915, i915_reg_t reg) -{ - return intel_uncore_read_fw(&i915->uncore, reg); -} - static inline void intel_de_write(struct drm_i915_private *i915, i915_reg_t reg, u32 val) { intel_uncore_write(&i915->uncore, reg, val); } -/* Note: read the warnings for intel_uncore_*_fw() functions! */ -static inline void -intel_de_write_fw(struct drm_i915_private *i915, i915_reg_t reg, u32 val) -{ - intel_uncore_write_fw(&i915->uncore, reg, val); -} - static inline void intel_de_rmw(struct drm_i915_private *i915, i915_reg_t reg, u32 clear, u32 set) { @@ -69,4 +56,30 @@ intel_de_wait_for_clear(struct drm_i915_private *i915, i915_reg_t reg, return intel_de_wait_for_register(i915, reg, mask, 0, timeout); } +/* + * Unlocked mmio-accessors, think carefully before using these. + * + * Certain architectures will die if the same cacheline is concurrently accessed + * by different clients (e.g. on Ivybridge). Access to registers should + * therefore generally be serialised, by either the dev_priv->uncore.lock or + * a more localised lock guarding all access to that bank of registers. + */ +static inline u32 +intel_de_read_fw(struct drm_i915_private *i915, i915_reg_t reg) +{ + u32 val; + + val = intel_uncore_read_fw(&i915->uncore, reg); + trace_i915_reg_rw(false, reg, val, sizeof(val), true); + + return val; +} + +static inline void +intel_de_write_fw(struct drm_i915_private *i915, i915_reg_t reg, u32 val) +{ + trace_i915_reg_rw(true, reg, val, sizeof(val), true); + intel_uncore_write_fw(&i915->uncore, reg, val); +} + #endif /* __INTEL_DE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d74b263c5f4e..384ff0bb6e19 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -63,9 +63,11 @@ #include "display/intel_vdsc.h" #include "display/intel_vrr.h" +#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_object.h" #include "gt/intel_rps.h" +#include "gt/gen8_ppgtt.h" #include "g4x_dp.h" #include "g4x_hdmi.h" @@ -78,6 +80,7 @@ #include "intel_color.h" #include "intel_crtc.h" #include "intel_csr.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp_link_training.h" #include "intel_fbc.h" @@ -122,6 +125,182 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +struct i915_dpt { + struct i915_address_space vm; + + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + void __iomem *iomem; +}; + +#define i915_is_dpt(vm) ((vm)->is_dpt) + +static inline struct i915_dpt * +i915_vm_to_dpt(struct i915_address_space *vm) +{ + BUILD_BUG_ON(offsetof(struct i915_dpt, vm)); + GEM_BUG_ON(!i915_is_dpt(vm)); + return container_of(vm, struct i915_dpt, vm); +} + +#define dpt_total_entries(dpt) ((dpt)->vm.total >> PAGE_SHIFT) + +static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) +{ + writeq(pte, addr); +} + +static void dpt_insert_page(struct i915_address_space *vm, + dma_addr_t addr, + u64 offset, + enum i915_cache_level level, + u32 flags) +{ + struct i915_dpt *dpt = i915_vm_to_dpt(vm); + gen8_pte_t __iomem *base = dpt->iomem; + + gen8_set_pte(base + offset / I915_GTT_PAGE_SIZE, + vm->pte_encode(addr, level, flags)); +} + +static void dpt_insert_entries(struct i915_address_space *vm, + struct i915_vma *vma, + enum i915_cache_level level, + u32 flags) +{ + struct i915_dpt *dpt = i915_vm_to_dpt(vm); + gen8_pte_t __iomem *base = dpt->iomem; + const gen8_pte_t pte_encode = vm->pte_encode(0, level, flags); + struct sgt_iter sgt_iter; + dma_addr_t addr; + int i; + + /* + * Note that we ignore PTE_READ_ONLY here. The caller must be careful + * not to allow the user to override access to a read only page. + */ + + i = vma->node.start / I915_GTT_PAGE_SIZE; + for_each_sgt_daddr(addr, sgt_iter, vma->pages) + gen8_set_pte(&base[i++], pte_encode | addr); +} + +static void dpt_clear_range(struct i915_address_space *vm, + u64 start, u64 length) +{ +} + +static void dpt_bind_vma(struct i915_address_space *vm, + struct i915_vm_pt_stash *stash, + struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags) +{ + struct drm_i915_gem_object *obj = vma->obj; + u32 pte_flags; + + /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ + pte_flags = 0; + if (vma->vm->has_read_only && i915_gem_object_is_readonly(obj)) + pte_flags |= PTE_READ_ONLY; + if (i915_gem_object_is_lmem(obj)) + pte_flags |= PTE_LM; + + vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags); + + vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; + + /* + * Without aliasing PPGTT there's no difference between + * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally + * upgrade to both bound if we bind either to avoid double-binding. + */ + atomic_or(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND, &vma->flags); +} + +static void dpt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma) +{ + vm->clear_range(vm, vma->node.start, vma->size); +} + +static void dpt_cleanup(struct i915_address_space *vm) +{ + struct i915_dpt *dpt = i915_vm_to_dpt(vm); + + i915_gem_object_put(dpt->obj); +} + +static struct i915_address_space * +intel_dpt_create(struct intel_framebuffer *fb) +{ + struct drm_gem_object *obj = &intel_fb_obj(&fb->base)->base; + struct drm_i915_private *i915 = to_i915(obj->dev); + struct drm_i915_gem_object *dpt_obj; + struct i915_address_space *vm; + struct i915_dpt *dpt; + size_t size; + int ret; + + if (intel_fb_needs_pot_stride_remap(fb)) + size = intel_remapped_info_size(&fb->remapped_view.gtt.remapped); + else + size = DIV_ROUND_UP_ULL(obj->size, I915_GTT_PAGE_SIZE); + + size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE); + + if (HAS_LMEM(i915)) + dpt_obj = i915_gem_object_create_lmem(i915, size, 0); + else + dpt_obj = i915_gem_object_create_stolen(i915, size); + if (IS_ERR(dpt_obj)) + return ERR_CAST(dpt_obj); + + ret = i915_gem_object_set_cache_level(dpt_obj, I915_CACHE_NONE); + if (ret) { + i915_gem_object_put(dpt_obj); + return ERR_PTR(ret); + } + + dpt = kzalloc(sizeof(*dpt), GFP_KERNEL); + if (!dpt) { + i915_gem_object_put(dpt_obj); + return ERR_PTR(-ENOMEM); + } + + vm = &dpt->vm; + + vm->gt = &i915->gt; + vm->i915 = i915; + vm->dma = i915->drm.dev; + vm->total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; + vm->is_dpt = true; + + i915_address_space_init(vm, VM_CLASS_DPT); + + vm->insert_page = dpt_insert_page; + vm->clear_range = dpt_clear_range; + vm->insert_entries = dpt_insert_entries; + vm->cleanup = dpt_cleanup; + + vm->vma_ops.bind_vma = dpt_bind_vma; + vm->vma_ops.unbind_vma = dpt_unbind_vma; + vm->vma_ops.set_pages = ggtt_set_pages; + vm->vma_ops.clear_pages = clear_pages; + + vm->pte_encode = gen8_ggtt_pte_encode; + + dpt->obj = dpt_obj; + + return &dpt->vm; +} + +static void intel_dpt_destroy(struct i915_address_space *vm) +{ + struct i915_dpt *dpt = i915_vm_to_dpt(vm); + + i915_vm_close(&dpt->vm); +} + /* returns HPLL frequency in kHz */ int vlv_get_hpll_vco(struct drm_i915_private *dev_priv) { @@ -230,7 +409,7 @@ static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv, u32 line1, line2; u32 line_mask; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) line_mask = DSL_LINEMASK_GEN2; else line_mask = DSL_LINEMASK_GEN3; @@ -874,7 +1053,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) case DRM_FORMAT_MOD_LINEAR: return intel_tile_size(dev_priv); case I915_FORMAT_MOD_X_TILED: - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) return 128; else return 512; @@ -889,7 +1068,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) return 64; fallthrough; case I915_FORMAT_MOD_Y_TILED: - if (IS_DISPLAY_VER(dev_priv, 2) || HAS_128_BYTE_Y_TILING(dev_priv)) + if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv)) return 128; else return 512; @@ -972,11 +1151,30 @@ unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, { struct drm_i915_private *dev_priv = to_i915(fb->dev); + if (intel_fb_uses_dpt(fb)) + return 512 * 4096; + /* AUX_DIST needs only 4K alignment */ - if ((DISPLAY_VER(dev_priv) < 12 && is_aux_plane(fb, color_plane)) || - is_ccs_plane(fb, color_plane)) + if (is_ccs_plane(fb, color_plane)) return 4096; + if (is_semiplanar_uv_plane(fb, color_plane)) { + /* + * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes + * alignment for linear UV planes on all platforms. + */ + if (DISPLAY_VER(dev_priv) >= 12) { + if (fb->modifier == DRM_FORMAT_MOD_LINEAR) + return intel_linear_alignment(dev_priv); + + return intel_tile_row_size(fb, color_plane); + } + + return 4096; + } + + drm_WARN_ON(&dev_priv->drm, color_plane != 0); + switch (fb->modifier) { case DRM_FORMAT_MOD_LINEAR: return intel_linear_alignment(dev_priv); @@ -985,19 +1183,12 @@ unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, return 256 * 1024; return 0; case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - if (is_semiplanar_uv_plane(fb, color_plane)) - return intel_tile_row_size(fb, color_plane); - fallthrough; case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: return 16 * 1024; case I915_FORMAT_MOD_Y_TILED_CCS: case I915_FORMAT_MOD_Yf_TILED_CCS: case I915_FORMAT_MOD_Y_TILED: - if (DISPLAY_VER(dev_priv) >= 12 && - is_semiplanar_uv_plane(fb, color_plane)) - return intel_tile_row_size(fb, color_plane); - fallthrough; case I915_FORMAT_MOD_Yf_TILED: return 1 * 1024 * 1024; default: @@ -1016,6 +1207,62 @@ static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) plane_state->view.gtt.type == I915_GGTT_VIEW_NORMAL); } +static struct i915_vma * +intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, + const struct i915_ggtt_view *view, + bool uses_fence, + unsigned long *out_flags, + struct i915_address_space *vm) +{ + struct drm_device *dev = fb->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct i915_vma *vma; + u32 alignment; + int ret; + + if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) + return ERR_PTR(-EINVAL); + + alignment = 4096 * 512; + + atomic_inc(&dev_priv->gpu_error.pending_fb_pin); + + ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + + vma = i915_vma_instance(obj, vm, view); + if (IS_ERR(vma)) + goto err; + + if (i915_vma_misplaced(vma, 0, alignment, 0)) { + ret = i915_vma_unbind(vma); + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + } + + ret = i915_vma_pin(vma, 0, alignment, PIN_GLOBAL); + if (ret) { + vma = ERR_PTR(ret); + goto err; + } + + vma->display_alignment = max_t(u64, vma->display_alignment, alignment); + + i915_gem_object_flush_if_display(obj); + + i915_vma_get(vma); +err: + atomic_dec(&dev_priv->gpu_error.pending_fb_pin); + + return vma; +} + struct i915_vma * intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, bool phys_cursor, @@ -1253,6 +1500,9 @@ static const struct drm_format_info gen12_ccs_formats[] = { { .format = DRM_FORMAT_VYUY, .num_planes = 2, .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_XYUV8888, .num_planes = 2, + .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, + .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_NV12, .num_planes = 4, .char_per_block = { 1, 2, 1, 1 }, .block_w = { 1, 1, 4, 4 }, .block_h = { 1, 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true }, @@ -1335,6 +1585,9 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, struct intel_crtc *crtc; struct intel_plane *plane; + if (!HAS_DISPLAY(dev_priv)) + return 0; + /* * We assume the primary plane for pipe A has * the highest stride limits of them all, @@ -1360,14 +1613,13 @@ u32 intel_fb_max_stride(struct drm_i915_private *dev_priv, * * The new CCS hash mode makes remapping impossible */ - if (!is_ccs_modifier(modifier)) { - if (DISPLAY_VER(dev_priv) >= 7) - return 256*1024; - else if (DISPLAY_VER(dev_priv) >= 4) - return 128*1024; - } - - return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier); + if (DISPLAY_VER(dev_priv) < 4 || is_ccs_modifier(modifier) || + intel_modifier_uses_dpt(dev_priv, modifier)) + return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier); + else if (DISPLAY_VER(dev_priv) >= 7) + return 256 * 1024; + else + return 128 * 1024; } static u32 @@ -1403,7 +1655,8 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) * require the entire fb to accommodate that to avoid * potential runtime errors at plane configuration time. */ - if (IS_DISPLAY_VER(dev_priv, 9) && color_plane == 0 && fb->width > 3840) + if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) && + color_plane == 0 && fb->width > 3840) tile_width *= 4; /* * The main surface pitch must be padded to a multiple of four @@ -1605,13 +1858,56 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc, * Gen2 reports pipe underruns whenever all planes are disabled. * So disable underrun reporting before all the planes get disabled. */ - if (IS_DISPLAY_VER(dev_priv, 2) && !crtc_state->active_planes) + if (DISPLAY_VER(dev_priv) == 2 && !crtc_state->active_planes) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); intel_disable_plane(plane, crtc_state); intel_wait_for_vblank(dev_priv, crtc->pipe); } +static struct i915_vma *intel_dpt_pin(struct i915_address_space *vm) +{ + struct drm_i915_private *i915 = vm->i915; + struct i915_dpt *dpt = i915_vm_to_dpt(vm); + intel_wakeref_t wakeref; + struct i915_vma *vma; + void __iomem *iomem; + + wakeref = intel_runtime_pm_get(&i915->runtime_pm); + atomic_inc(&i915->gpu_error.pending_fb_pin); + + vma = i915_gem_object_ggtt_pin(dpt->obj, NULL, 0, 4096, + HAS_LMEM(i915) ? 0 : PIN_MAPPABLE); + if (IS_ERR(vma)) + goto err; + + iomem = i915_vma_pin_iomap(vma); + i915_vma_unpin(vma); + if (IS_ERR(iomem)) { + vma = iomem; + goto err; + } + + dpt->vma = vma; + dpt->iomem = iomem; + + i915_vma_get(vma); + +err: + atomic_dec(&i915->gpu_error.pending_fb_pin); + intel_runtime_pm_put(&i915->runtime_pm, wakeref); + + return vma; +} + +static void intel_dpt_unpin(struct i915_address_space *vm) +{ + struct i915_dpt *dpt = i915_vm_to_dpt(vm); + + i915_vma_unpin_iomap(dpt->vma); + i915_vma_put(dpt->vma); +} + static void intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, struct intel_initial_plane_config *plane_config) @@ -1657,12 +1953,12 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, continue; state = to_intel_plane_state(c->primary->state); - if (!state->vma) + if (!state->ggtt_vma) continue; if (intel_plane_ggtt_offset(state) == plane_config->base) { fb = state->hw.fb; - vma = state->vma; + vma = state->ggtt_vma; goto valid_fb; } } @@ -1689,7 +1985,7 @@ valid_fb: &intel_state->view); __i915_vma_pin(vma); - intel_state->vma = i915_vma_get(vma); + intel_state->ggtt_vma = i915_vma_get(vma); if (intel_plane_uses_fence(intel_state) && i915_vma_pin_fence(vma) == 0) if (vma->fence) intel_state->flags |= PLANE_HAS_FENCE; @@ -2468,7 +2764,7 @@ static bool needs_nv12_wa(const struct intel_crtc_state *crtc_state) return false; /* WA Display #0827: Gen9:all */ - if (IS_DISPLAY_VER(dev_priv, 9)) + if (DISPLAY_VER(dev_priv) == 9) return true; return false; @@ -2479,7 +2775,7 @@ static bool needs_scalerclk_wa(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); /* Wa_2006604312:icl,ehl */ - if (crtc_state->scaler_state.scaler_users > 0 && IS_DISPLAY_VER(dev_priv, 11)) + if (crtc_state->scaler_state.scaler_users > 0 && DISPLAY_VER(dev_priv) == 11) return true; return false; @@ -2679,7 +2975,7 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, * chance of catching underruns with the intermediate watermarks * vs. the old plane configuration. */ - if (IS_DISPLAY_VER(dev_priv, 2) && planes_disabling(old_crtc_state, new_crtc_state)) + if (DISPLAY_VER(dev_priv) == 2 && planes_disabling(old_crtc_state, new_crtc_state)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); /* @@ -3115,6 +3411,7 @@ static void icl_ddi_bigjoiner_pre_enable(struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state) { struct intel_crtc *master = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(master->base.dev); struct intel_crtc_state *master_crtc_state; struct drm_connector_state *conn_state; struct drm_connector *conn; @@ -3148,6 +3445,9 @@ static void icl_ddi_bigjoiner_pre_enable(struct intel_atomic_state *state, /* and DSC on slave */ intel_dsc_enable(NULL, crtc_state); } + + if (DISPLAY_VER(dev_priv) >= 13) + intel_uncompressed_joiner_enable(crtc_state); } static void hsw_crtc_enable(struct intel_atomic_state *state, @@ -3198,7 +3498,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, crtc->active = true; /* Display WA #1180: WaDisableScalarClockGating: glk, cnl */ - psl_clkgate_wa = IS_DISPLAY_VER(dev_priv, 10) && + psl_clkgate_wa = DISPLAY_VER(dev_priv) == 10 && new_crtc_state->pch_pfit.enabled; if (psl_clkgate_wa) glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true); @@ -3385,7 +3685,11 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port) { - if (IS_ALDERLAKE_S(i915) && port >= PORT_TC1) + if (DISPLAY_VER(i915) >= 13 && port >= PORT_D_XELPD) + return PHY_D + port - PORT_D_XELPD; + else if (DISPLAY_VER(i915) >= 13 && port >= PORT_TC1) + return PHY_F + port - PORT_TC1; + else if (IS_ALDERLAKE_S(i915) && port >= PORT_TC1) return PHY_B + port - PORT_TC1; else if ((IS_DG1(i915) || IS_ROCKETLAKE(i915)) && port >= PORT_TC1) return PHY_C + port - PORT_TC1; @@ -3652,7 +3956,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, crtc->active = true; - if (!IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) != 2) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); intel_encoders_pre_enable(state, crtc); @@ -3677,7 +3981,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, intel_encoders_enable(state, crtc); /* prevents spurious underruns */ - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) intel_wait_for_vblank(dev_priv, pipe); } @@ -3708,7 +4012,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, * On gen2 planes are double buffered but the pipe isn't, so we must * wait for planes to fully turn off before disabling the pipe. */ - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) intel_wait_for_vblank(dev_priv, pipe); intel_encoders_disable(state, crtc); @@ -3732,7 +4036,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, intel_encoders_post_pll_disable(state, crtc); - if (!IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) != 2) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); if (!dev_priv->display.initial_watermarks) @@ -3838,6 +4142,9 @@ int intel_display_suspend(struct drm_device *dev) struct drm_atomic_state *state; int ret; + if (!HAS_DISPLAY(dev_priv)) + return 0; + state = drm_atomic_helper_suspend(dev); ret = PTR_ERR_OR_ZERO(state); if (ret) @@ -3978,7 +4285,7 @@ static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc) static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state) { u32 pixel_rate = crtc_state->hw.pipe_mode.crtc_clock; - unsigned int pipe_w, pipe_h, pfit_w, pfit_h; + struct drm_rect src; /* * We only use IF-ID interlacing. If we ever use @@ -3988,23 +4295,12 @@ static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state) if (!crtc_state->pch_pfit.enabled) return pixel_rate; - pipe_w = crtc_state->pipe_src_w; - pipe_h = crtc_state->pipe_src_h; - - pfit_w = drm_rect_width(&crtc_state->pch_pfit.dst); - pfit_h = drm_rect_height(&crtc_state->pch_pfit.dst); - - if (pipe_w < pfit_w) - pipe_w = pfit_w; - if (pipe_h < pfit_h) - pipe_h = pfit_h; + drm_rect_init(&src, 0, 0, + crtc_state->pipe_src_w << 16, + crtc_state->pipe_src_h << 16); - if (drm_WARN_ON(crtc_state->uapi.crtc->dev, - !pfit_w || !pfit_h)) - return pixel_rate; - - return div_u64(mul_u32_u32(pixel_rate, pipe_w * pipe_h), - pfit_w * pfit_h); + return intel_adjusted_rate(&src, &crtc_state->pch_pfit.dst, + pixel_rate); } static void intel_mode_from_crtc_timings(struct drm_display_mode *mode, @@ -4296,7 +4592,7 @@ static bool transcoder_has_m2_n2(struct drm_i915_private *dev_priv, * Strictly speaking some registers are available before * gen7, but we only support DRRS on gen7+ */ - return IS_DISPLAY_VER(dev_priv, 7) || IS_CHERRYVIEW(dev_priv); + return DISPLAY_VER(dev_priv) == 7 || IS_CHERRYVIEW(dev_priv); } static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state, @@ -4443,7 +4739,7 @@ static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) return false; if (DISPLAY_VER(dev_priv) >= 9 || @@ -5638,7 +5934,7 @@ static void ilk_get_pfit_config(struct intel_crtc_state *crtc_state) * ivb/hsw (since we don't use the higher upscaling modes which * differentiates them) so just WARN about this case for now. */ - drm_WARN_ON(&dev_priv->drm, IS_DISPLAY_VER(dev_priv, 7) && + drm_WARN_ON(&dev_priv->drm, DISPLAY_VER(dev_priv) == 7 && (ctl & PF_PIPE_SEL_MASK_IVB) != PF_PIPE_SEL_IVB(crtc->pipe)); } @@ -5951,13 +6247,15 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, active = hsw_get_transcoder_state(crtc, pipe_config, &power_domain_set); - if (IS_GEN9_LP(dev_priv) && + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && bxt_get_dsi_transcoder_state(crtc, pipe_config, &power_domain_set)) { drm_WARN_ON(&dev_priv->drm, active); active = true; } intel_dsc_get_config(pipe_config); + if (DISPLAY_VER(dev_priv) >= 13 && !pipe_config->dsc.compression_enable) + intel_uncompressed_joiner_get_config(pipe_config); if (!active) { /* bigjoiner slave doesn't enable transcoder */ @@ -6321,7 +6619,7 @@ static int i9xx_pll_refclk(struct drm_device *dev, return dev_priv->vbt.lvds_ssc_freq; else if (HAS_PCH_SPLIT(dev_priv)) return 120000; - else if (!IS_DISPLAY_VER(dev_priv, 2)) + else if (DISPLAY_VER(dev_priv) != 2) return 96000; else return 48000; @@ -6354,7 +6652,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; } - if (!IS_DISPLAY_VER(dev_priv, 2)) { + if (DISPLAY_VER(dev_priv) != 2) { if (IS_PINEVIEW(dev_priv)) clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); @@ -6869,7 +7167,8 @@ static u16 skl_linetime_wm(const struct intel_crtc_state *crtc_state) crtc_state->pixel_rate); /* Display WA #1135: BXT:ALL GLK:ALL */ - if (IS_GEN9_LP(dev_priv) && dev_priv->ipc_enabled) + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + dev_priv->ipc_enabled) linetime_wm /= 2; return min(linetime_wm, 0x1ff); @@ -8342,6 +8641,11 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(vrr.flipline); PIPE_CONF_CHECK_I(vrr.pipeline_full); + PIPE_CONF_CHECK_BOOL(has_psr); + PIPE_CONF_CHECK_BOOL(has_psr2); + PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch); + PIPE_CONF_CHECK_I(dc3co_exitline); + #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_BOOL @@ -8735,6 +9039,44 @@ intel_modeset_verify_disabled(struct drm_i915_private *dev_priv, verify_disabled_dpll_state(dev_priv); } +int intel_modeset_all_pipes(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_crtc *crtc; + + /* + * Add all pipes to the state, and force + * a modeset on all the active ones. + */ + for_each_intel_crtc(&dev_priv->drm, crtc) { + struct intel_crtc_state *crtc_state; + int ret; + + crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->hw.active || + drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) + continue; + + crtc_state->uapi.mode_changed = true; + + ret = drm_atomic_add_affected_connectors(&state->base, + &crtc->base); + if (ret) + return ret; + + ret = intel_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + crtc_state->update_planes |= crtc_state->active_planes; + } + + return 0; +} + static void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state) { @@ -8781,7 +9123,7 @@ intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state) * However if queried just before the start of vblank we'll get an * answer that's slightly in the future. */ - if (IS_DISPLAY_VER(dev_priv, 2)) { + if (DISPLAY_VER(dev_priv) == 2) { int vtotal; vtotal = adjusted_mode.crtc_vtotal; @@ -9658,7 +10000,7 @@ void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - if (!IS_DISPLAY_VER(dev_priv, 2) || crtc_state->active_planes) + if (DISPLAY_VER(dev_priv) != 2 || crtc_state->active_planes) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true); if (crtc_state->has_pch_encoder) { @@ -9687,8 +10029,6 @@ static void intel_pipe_fastset(const struct intel_crtc_state *old_crtc_state, /* on skylake this is done by detaching scalers */ if (DISPLAY_VER(dev_priv) >= 9) { - skl_detach_scalers(new_crtc_state); - if (new_crtc_state->pch_pfit.enabled) skl_pfit_enable(new_crtc_state); } else if (HAS_PCH_SPLIT(dev_priv)) { @@ -9714,8 +10054,8 @@ static void intel_pipe_fastset(const struct intel_crtc_state *old_crtc_state, icl_set_pipe_chicken(crtc); } -static void commit_pipe_config(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static void commit_pipe_pre_planes(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); const struct intel_crtc_state *old_crtc_state = @@ -9733,9 +10073,6 @@ static void commit_pipe_config(struct intel_atomic_state *state, new_crtc_state->update_pipe) intel_color_commit(new_crtc_state); - if (DISPLAY_VER(dev_priv) >= 9) - skl_detach_scalers(new_crtc_state); - if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) bdw_set_pipemisc(new_crtc_state); @@ -9749,6 +10086,23 @@ static void commit_pipe_config(struct intel_atomic_state *state, dev_priv->display.atomic_update_watermarks(state, crtc); } +static void commit_pipe_post_planes(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + + /* + * Disable the scaler(s) after the plane(s) so that we don't + * get a catastrophic underrun even if the two operations + * end up happening in two different frames. + */ + if (DISPLAY_VER(dev_priv) >= 9 && + !intel_crtc_needs_modeset(new_crtc_state)) + skl_detach_scalers(new_crtc_state); +} + static void intel_enable_crtc(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -9800,13 +10154,15 @@ static void intel_update_crtc(struct intel_atomic_state *state, /* Perform vblank evasion around commit operation */ intel_pipe_update_start(new_crtc_state); - commit_pipe_config(state, crtc); + commit_pipe_pre_planes(state, crtc); if (DISPLAY_VER(dev_priv) >= 9) skl_update_planes_on_crtc(state, crtc); else i9xx_update_planes_on_crtc(state, crtc); + commit_pipe_post_planes(state, crtc); + intel_pipe_update_end(new_crtc_state); /* @@ -10276,7 +10632,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) * chance of catching underruns with the intermediate watermarks * vs. the new plane configuration. */ - if (IS_DISPLAY_VER(dev_priv, 2) && planes_enabling(old_crtc_state, new_crtc_state)) + if (DISPLAY_VER(dev_priv) == 2 && planes_enabling(old_crtc_state, new_crtc_state)) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true); if (dev_priv->display.optimize_watermarks) @@ -10540,25 +10896,60 @@ int intel_plane_pin_fb(struct intel_plane_state *plane_state) plane->id == PLANE_CURSOR && INTEL_INFO(dev_priv)->display.cursor_needs_physical; - vma = intel_pin_and_fence_fb_obj(fb, phys_cursor, - &plane_state->view.gtt, - intel_plane_uses_fence(plane_state), - &plane_state->flags); - if (IS_ERR(vma)) - return PTR_ERR(vma); + if (!intel_fb_uses_dpt(fb)) { + vma = intel_pin_and_fence_fb_obj(fb, phys_cursor, + &plane_state->view.gtt, + intel_plane_uses_fence(plane_state), + &plane_state->flags); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + } else { + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + + vma = intel_dpt_pin(intel_fb->dpt_vm); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + + vma = intel_pin_fb_obj_dpt(fb, &plane_state->view.gtt, false, + &plane_state->flags, intel_fb->dpt_vm); + if (IS_ERR(vma)) { + intel_dpt_unpin(intel_fb->dpt_vm); + plane_state->ggtt_vma = NULL; + return PTR_ERR(vma); + } + + plane_state->dpt_vma = vma; - plane_state->vma = vma; + WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma); + } return 0; } void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state) { + struct drm_framebuffer *fb = old_plane_state->hw.fb; struct i915_vma *vma; - vma = fetch_and_zero(&old_plane_state->vma); - if (vma) - intel_unpin_fb_vma(vma, old_plane_state->flags); + if (!intel_fb_uses_dpt(fb)) { + vma = fetch_and_zero(&old_plane_state->ggtt_vma); + if (vma) + intel_unpin_fb_vma(vma, old_plane_state->flags); + } else { + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + + vma = fetch_and_zero(&old_plane_state->dpt_vma); + if (vma) + intel_unpin_fb_vma(vma, old_plane_state->flags); + + vma = fetch_and_zero(&old_plane_state->ggtt_vma); + if (vma) + intel_dpt_unpin(intel_fb->dpt_vm); + } } /** @@ -10855,61 +11246,38 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_ddi_init(dev_priv, PORT_C); intel_ddi_init(dev_priv, PORT_D); icl_dsi_init(dev_priv); - } else if (IS_DISPLAY_VER(dev_priv, 11)) { + } else if (DISPLAY_VER(dev_priv) == 11) { intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); intel_ddi_init(dev_priv, PORT_C); intel_ddi_init(dev_priv, PORT_D); intel_ddi_init(dev_priv, PORT_E); - /* - * On some ICL SKUs port F is not present. No strap bits for - * this, so rely on VBT. - * Work around broken VBTs on SKUs known to have no port F. - */ - if (IS_ICL_WITH_PORT_F(dev_priv) && - intel_bios_is_port_present(dev_priv, PORT_F)) - intel_ddi_init(dev_priv, PORT_F); - + intel_ddi_init(dev_priv, PORT_F); icl_dsi_init(dev_priv); - } else if (IS_GEN9_LP(dev_priv)) { - /* - * FIXME: Broxton doesn't support port detection via the - * DDI_BUF_CTL_A or SFUSE_STRAP registers, find another way to - * detect the ports. - */ + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); intel_ddi_init(dev_priv, PORT_C); - vlv_dsi_init(dev_priv); + } else if (DISPLAY_VER(dev_priv) >= 9) { + intel_ddi_init(dev_priv, PORT_A); + intel_ddi_init(dev_priv, PORT_B); + intel_ddi_init(dev_priv, PORT_C); + intel_ddi_init(dev_priv, PORT_D); + intel_ddi_init(dev_priv, PORT_E); + intel_ddi_init(dev_priv, PORT_F); } else if (HAS_DDI(dev_priv)) { - int found; + u32 found; if (intel_ddi_crt_present(dev_priv)) intel_crt_init(dev_priv); - /* - * Haswell uses DDI functions to detect digital outputs. - * On SKL pre-D0 the strap isn't connected. Later SKUs may or - * may not have it - it was supposed to be fixed by the same - * time we stopped using straps. Assume it's there. - */ + /* Haswell uses DDI functions to detect digital outputs. */ found = intel_de_read(dev_priv, DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED; - /* WaIgnoreDDIAStrap: skl */ - if (found || IS_GEN9_BC(dev_priv)) + if (found) intel_ddi_init(dev_priv, PORT_A); - /* DDI B, C, D, and F detection is indicated by the SFUSE_STRAP - * register */ - if (HAS_PCH_TGP(dev_priv)) { - /* W/A due to lack of STRAP config on TGP PCH*/ - found = (SFUSE_STRAP_DDIB_DETECTED | - SFUSE_STRAP_DDIC_DETECTED | - SFUSE_STRAP_DDID_DETECTED); - } else { - found = intel_de_read(dev_priv, SFUSE_STRAP); - } - + found = intel_de_read(dev_priv, SFUSE_STRAP); if (found & SFUSE_STRAP_DDIB_DETECTED) intel_ddi_init(dev_priv, PORT_B); if (found & SFUSE_STRAP_DDIC_DETECTED) @@ -10918,13 +11286,6 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_ddi_init(dev_priv, PORT_D); if (found & SFUSE_STRAP_DDIF_DETECTED) intel_ddi_init(dev_priv, PORT_F); - /* - * On SKL we don't have a way to detect DDI-E so we rely on VBT. - */ - if (IS_GEN9_BC(dev_priv) && - intel_bios_is_port_present(dev_priv, PORT_E)) - intel_ddi_init(dev_priv, PORT_E); - } else if (HAS_PCH_SPLIT(dev_priv)) { int found; @@ -11012,7 +11373,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) } else if (IS_PINEVIEW(dev_priv)) { intel_lvds_init(dev_priv); intel_crt_init(dev_priv); - } else if (IS_DISPLAY_RANGE(dev_priv, 3, 4)) { + } else if (IS_DISPLAY_VER(dev_priv, 3, 4)) { bool found = false; if (IS_MOBILE(dev_priv)) @@ -11056,7 +11417,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (SUPPORTS_TV(dev_priv)) intel_tv_init(dev_priv); - } else if (IS_DISPLAY_VER(dev_priv, 2)) { + } else if (DISPLAY_VER(dev_priv) == 2) { if (IS_I85X(dev_priv)) intel_lvds_init(dev_priv); @@ -11081,6 +11442,10 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); drm_framebuffer_cleanup(fb); + + if (intel_fb_uses_dpt(fb)) + intel_dpt_destroy(intel_fb->dpt_vm); + intel_frontbuffer_put(intel_fb->frontbuffer); kfree(intel_fb); @@ -11244,13 +11609,36 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, } } + /* TODO: Add POT stride remapping support for CCS formats as well. */ + if (IS_ALDERLAKE_P(dev_priv) && + mode_cmd->modifier[i] != DRM_FORMAT_MOD_LINEAR && + !intel_fb_needs_pot_stride_remap(intel_fb) && + !is_power_of_2(mode_cmd->pitches[i])) { + drm_dbg_kms(&dev_priv->drm, + "plane %d pitch (%d) must be power of two for tiled buffers\n", + i, mode_cmd->pitches[i]); + goto err; + } + fb->obj[i] = &obj->base; } - ret = intel_fill_fb_info(dev_priv, fb); + ret = intel_fill_fb_info(dev_priv, intel_fb); if (ret) goto err; + if (intel_fb_uses_dpt(fb)) { + struct i915_address_space *vm; + + vm = intel_dpt_create(intel_fb); + if (IS_ERR(vm)) { + ret = PTR_ERR(vm); + goto err; + } + + intel_fb->dpt_vm = vm; + } + ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs); if (ret) { drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret); @@ -11428,6 +11816,9 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { */ void intel_init_display_hooks(struct drm_i915_private *dev_priv) { + if (!HAS_DISPLAY(dev_priv)) + return; + intel_init_cdclk_hooks(dev_priv); intel_init_audio_hooks(dev_priv); @@ -11470,8 +11861,12 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) void intel_modeset_init_hw(struct drm_i915_private *i915) { - struct intel_cdclk_state *cdclk_state = - to_intel_cdclk_state(i915->cdclk.obj.state); + struct intel_cdclk_state *cdclk_state; + + if (!HAS_DISPLAY(i915)) + return; + + cdclk_state = to_intel_cdclk_state(i915->cdclk.obj.state); intel_update_cdclk(i915); intel_dump_cdclk_config(&i915->cdclk.hw, "Current CDCLK"); @@ -11704,8 +12099,6 @@ static void intel_mode_config_init(struct drm_i915_private *i915) mode_config->preferred_depth = 24; mode_config->prefer_shadow = 1; - mode_config->allow_fb_modifiers = true; - mode_config->funcs = &intel_mode_funcs; mode_config->async_page_flip = has_async_flips(i915); @@ -11720,7 +12113,7 @@ static void intel_mode_config_init(struct drm_i915_private *i915) } else if (DISPLAY_VER(i915) >= 4) { mode_config->max_width = 8192; mode_config->max_height = 8192; - } else if (IS_DISPLAY_VER(i915, 3)) { + } else if (DISPLAY_VER(i915) == 3) { mode_config->max_width = 4096; mode_config->max_height = 4096; } else { @@ -11787,6 +12180,9 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915) /* FIXME: completely on the wrong abstraction layer */ intel_power_domains_init_hw(i915, false); + if (!HAS_DISPLAY(i915)) + return 0; + intel_csr_ucode_init(i915); i915->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0); @@ -11837,6 +12233,9 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) struct intel_crtc *crtc; int ret; + if (!HAS_DISPLAY(i915)) + return 0; + intel_init_pm(i915); intel_panel_sanitize_ssc(i915); @@ -11849,13 +12248,11 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) INTEL_NUM_PIPES(i915), INTEL_NUM_PIPES(i915) > 1 ? "s" : ""); - if (HAS_DISPLAY(i915)) { - for_each_pipe(i915, pipe) { - ret = intel_crtc_init(i915, pipe); - if (ret) { - intel_mode_config_cleanup(i915); - return ret; - } + for_each_pipe(i915, pipe) { + ret = intel_crtc_init(i915, pipe); + if (ret) { + intel_mode_config_cleanup(i915); + return ret; } } @@ -12609,7 +13006,7 @@ static void intel_early_display_was(struct drm_i915_private *dev_priv) * Display WA #1185 WaDisableDARBFClkGating:cnl,glk,icl,ehl,tgl * Also known as Wa_14010480278. */ - if (IS_DISPLAY_RANGE(dev_priv, 10, 12)) + if (IS_DISPLAY_VER(dev_priv, 10, 12)) intel_de_write(dev_priv, GEN9_CLKGATE_DIS_0, intel_de_read(dev_priv, GEN9_CLKGATE_DIS_0) | DARBF_GATING_DIS); @@ -12790,6 +13187,9 @@ void intel_display_resume(struct drm_device *dev) struct drm_modeset_acquire_ctx ctx; int ret; + if (!HAS_DISPLAY(dev_priv)) + return; + dev_priv->modeset_restore_state = NULL; if (state) state->acquire_ctx = &ctx; @@ -12839,6 +13239,9 @@ static void intel_hpd_poll_fini(struct drm_i915_private *i915) /* part #1: call before irq uninstall */ void intel_modeset_driver_remove(struct drm_i915_private *i915) { + if (!HAS_DISPLAY(i915)) + return; + flush_workqueue(i915->flip_wq); flush_workqueue(i915->modeset_wq); @@ -12849,6 +13252,9 @@ void intel_modeset_driver_remove(struct drm_i915_private *i915) /* part #2: call after irq uninstall */ void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915) { + if (!HAS_DISPLAY(i915)) + return; + /* * Due to the hpd irq storm handling the hotplug work can re-arm the * poll handlers. Hence disable polling after hpd handling is shut down. @@ -12948,207 +13354,3 @@ void intel_display_driver_unregister(struct drm_i915_private *i915) acpi_video_unregister(); intel_opregion_unregister(i915); } - -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) - -struct intel_display_error_state { - - u32 power_well_driver; - - struct intel_cursor_error_state { - u32 control; - u32 position; - u32 base; - u32 size; - } cursor[I915_MAX_PIPES]; - - struct intel_pipe_error_state { - bool power_domain_on; - u32 source; - u32 stat; - } pipe[I915_MAX_PIPES]; - - struct intel_plane_error_state { - u32 control; - u32 stride; - u32 size; - u32 pos; - u32 addr; - u32 surface; - u32 tile_offset; - } plane[I915_MAX_PIPES]; - - struct intel_transcoder_error_state { - bool available; - bool power_domain_on; - enum transcoder cpu_transcoder; - - u32 conf; - - u32 htotal; - u32 hblank; - u32 hsync; - u32 vtotal; - u32 vblank; - u32 vsync; - } transcoder[5]; -}; - -struct intel_display_error_state * -intel_display_capture_error_state(struct drm_i915_private *dev_priv) -{ - struct intel_display_error_state *error; - int transcoders[] = { - TRANSCODER_A, - TRANSCODER_B, - TRANSCODER_C, - TRANSCODER_D, - TRANSCODER_EDP, - }; - int i; - - BUILD_BUG_ON(ARRAY_SIZE(transcoders) != ARRAY_SIZE(error->transcoder)); - - if (!HAS_DISPLAY(dev_priv)) - return NULL; - - error = kzalloc(sizeof(*error), GFP_ATOMIC); - if (error == NULL) - return NULL; - - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) - error->power_well_driver = intel_de_read(dev_priv, - HSW_PWR_WELL_CTL2); - - for_each_pipe(dev_priv, i) { - error->pipe[i].power_domain_on = - __intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_PIPE(i)); - if (!error->pipe[i].power_domain_on) - continue; - - error->cursor[i].control = intel_de_read(dev_priv, CURCNTR(i)); - error->cursor[i].position = intel_de_read(dev_priv, CURPOS(i)); - error->cursor[i].base = intel_de_read(dev_priv, CURBASE(i)); - - error->plane[i].control = intel_de_read(dev_priv, DSPCNTR(i)); - error->plane[i].stride = intel_de_read(dev_priv, DSPSTRIDE(i)); - if (DISPLAY_VER(dev_priv) <= 3) { - error->plane[i].size = intel_de_read(dev_priv, - DSPSIZE(i)); - error->plane[i].pos = intel_de_read(dev_priv, - DSPPOS(i)); - } - if (DISPLAY_VER(dev_priv) <= 7 && !IS_HASWELL(dev_priv)) - error->plane[i].addr = intel_de_read(dev_priv, - DSPADDR(i)); - if (DISPLAY_VER(dev_priv) >= 4) { - error->plane[i].surface = intel_de_read(dev_priv, - DSPSURF(i)); - error->plane[i].tile_offset = intel_de_read(dev_priv, - DSPTILEOFF(i)); - } - - error->pipe[i].source = intel_de_read(dev_priv, PIPESRC(i)); - - if (HAS_GMCH(dev_priv)) - error->pipe[i].stat = intel_de_read(dev_priv, - PIPESTAT(i)); - } - - for (i = 0; i < ARRAY_SIZE(error->transcoder); i++) { - enum transcoder cpu_transcoder = transcoders[i]; - - if (!HAS_TRANSCODER(dev_priv, cpu_transcoder)) - continue; - - error->transcoder[i].available = true; - error->transcoder[i].power_domain_on = - __intel_display_power_is_enabled(dev_priv, - POWER_DOMAIN_TRANSCODER(cpu_transcoder)); - if (!error->transcoder[i].power_domain_on) - continue; - - error->transcoder[i].cpu_transcoder = cpu_transcoder; - - error->transcoder[i].conf = intel_de_read(dev_priv, - PIPECONF(cpu_transcoder)); - error->transcoder[i].htotal = intel_de_read(dev_priv, - HTOTAL(cpu_transcoder)); - error->transcoder[i].hblank = intel_de_read(dev_priv, - HBLANK(cpu_transcoder)); - error->transcoder[i].hsync = intel_de_read(dev_priv, - HSYNC(cpu_transcoder)); - error->transcoder[i].vtotal = intel_de_read(dev_priv, - VTOTAL(cpu_transcoder)); - error->transcoder[i].vblank = intel_de_read(dev_priv, - VBLANK(cpu_transcoder)); - error->transcoder[i].vsync = intel_de_read(dev_priv, - VSYNC(cpu_transcoder)); - } - - return error; -} - -#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) - -void -intel_display_print_error_state(struct drm_i915_error_state_buf *m, - struct intel_display_error_state *error) -{ - struct drm_i915_private *dev_priv = m->i915; - int i; - - if (!error) - return; - - err_printf(m, "Num Pipes: %d\n", INTEL_NUM_PIPES(dev_priv)); - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) - err_printf(m, "PWR_WELL_CTL2: %08x\n", - error->power_well_driver); - for_each_pipe(dev_priv, i) { - err_printf(m, "Pipe [%d]:\n", i); - err_printf(m, " Power: %s\n", - onoff(error->pipe[i].power_domain_on)); - err_printf(m, " SRC: %08x\n", error->pipe[i].source); - err_printf(m, " STAT: %08x\n", error->pipe[i].stat); - - err_printf(m, "Plane [%d]:\n", i); - err_printf(m, " CNTR: %08x\n", error->plane[i].control); - err_printf(m, " STRIDE: %08x\n", error->plane[i].stride); - if (DISPLAY_VER(dev_priv) <= 3) { - err_printf(m, " SIZE: %08x\n", error->plane[i].size); - err_printf(m, " POS: %08x\n", error->plane[i].pos); - } - if (DISPLAY_VER(dev_priv) <= 7 && !IS_HASWELL(dev_priv)) - err_printf(m, " ADDR: %08x\n", error->plane[i].addr); - if (DISPLAY_VER(dev_priv) >= 4) { - err_printf(m, " SURF: %08x\n", error->plane[i].surface); - err_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); - } - - err_printf(m, "Cursor [%d]:\n", i); - err_printf(m, " CNTR: %08x\n", error->cursor[i].control); - err_printf(m, " POS: %08x\n", error->cursor[i].position); - err_printf(m, " BASE: %08x\n", error->cursor[i].base); - } - - for (i = 0; i < ARRAY_SIZE(error->transcoder); i++) { - if (!error->transcoder[i].available) - continue; - - err_printf(m, "CPU transcoder: %s\n", - transcoder_name(error->transcoder[i].cpu_transcoder)); - err_printf(m, " Power: %s\n", - onoff(error->transcoder[i].power_domain_on)); - err_printf(m, " CONF: %08x\n", error->transcoder[i].conf); - err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal); - err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank); - err_printf(m, " HSYNC: %08x\n", error->transcoder[i].hsync); - err_printf(m, " VTOTAL: %08x\n", error->transcoder[i].vtotal); - err_printf(m, " VBLANK: %08x\n", error->transcoder[i].vblank); - err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync); - } -} - -#endif diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 105294ec2dcc..c9dbaf074d77 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -37,13 +37,13 @@ struct drm_encoder; struct drm_file; struct drm_format_info; struct drm_framebuffer; -struct drm_i915_error_state_buf; struct drm_i915_gem_object; struct drm_i915_private; struct drm_mode_fb_cmd2; struct drm_modeset_acquire_ctx; struct drm_plane; struct drm_plane_state; +struct i915_address_space; struct i915_ggtt_view; struct intel_atomic_state; struct intel_crtc; @@ -188,12 +188,13 @@ enum plane_id { for ((__p) = PLANE_PRIMARY; (__p) < I915_MAX_PLANES; (__p)++) \ for_each_if((__crtc)->plane_ids_mask & BIT(__p)) -#define for_each_dbuf_slice_in_mask(__slice, __mask) \ +#define for_each_dbuf_slice(__dev_priv, __slice) \ for ((__slice) = DBUF_S1; (__slice) < I915_MAX_DBUF_SLICES; (__slice)++) \ - for_each_if((BIT(__slice)) & (__mask)) + for_each_if(INTEL_INFO(__dev_priv)->dbuf.slice_mask & BIT(__slice)) -#define for_each_dbuf_slice(__slice) \ - for_each_dbuf_slice_in_mask(__slice, BIT(I915_MAX_DBUF_SLICES) - 1) +#define for_each_dbuf_slice_in_mask(__dev_priv, __slice, __mask) \ + for_each_dbuf_slice((__dev_priv), (__slice)) \ + for_each_if((__mask) & BIT(__slice)) enum port { PORT_NONE = -1, @@ -216,6 +217,10 @@ enum port { PORT_TC5, PORT_TC6, + /* XE_LPD repositions D/E offsets and bitfields */ + PORT_D_XELPD = PORT_TC5, + PORT_E_XELPD, + I915_MAX_PORTS }; @@ -299,6 +304,10 @@ enum aux_ch { AUX_CH_USBC4, AUX_CH_USBC5, AUX_CH_USBC6, + + /* XE_LPD repositions D/E offsets and bitfields */ + AUX_CH_D_XELPD = AUX_CH_USBC5, + AUX_CH_E_XELPD, }; #define aux_ch_name(a) ((a) + 'A') @@ -556,9 +565,6 @@ enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, enum port port); int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc); -void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state); -void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state); int ilk_get_lanes_required(int target_clock, int link_bw, int bpp); void vlv_wait_port_ready(struct drm_i915_private *dev_priv, @@ -597,9 +603,6 @@ void intel_dp_get_m_n(struct intel_crtc *crtc, void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_set m_n); int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n); -bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, - struct dpll *best_clock); -int chv_calc_dpll_params(int refclk, struct dpll *pll_clock); bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state); void hsw_enable_ips(const struct intel_crtc_state *crtc_state); @@ -616,11 +619,6 @@ void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state); int bdw_get_pipemisc_bpp(struct intel_crtc *crtc); unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state); -struct intel_display_error_state * -intel_display_capture_error_state(struct drm_i915_private *dev_priv); -void intel_display_print_error_state(struct drm_i915_error_state_buf *e, - struct intel_display_error_state *error); - bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, u64 modifier); @@ -648,6 +646,7 @@ void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915); void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915); void intel_display_resume(struct drm_device *dev); void intel_init_pch_refclk(struct drm_i915_private *dev_priv); +int intel_modeset_all_pipes(struct intel_atomic_state *state); /* modesetting asserts */ void assert_panel_unlocked(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 564509a4e666..d77a0ab5cacf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -10,6 +10,7 @@ #include "intel_csr.h" #include "intel_display_debugfs.h" #include "intel_display_power.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_fbc.h" @@ -569,7 +570,7 @@ static int i915_dmc_info(struct seq_file *m, void *unused) } else { dc5_reg = IS_BROXTON(dev_priv) ? BXT_CSR_DC3_DC5_COUNT : SKL_CSR_DC3_DC5_COUNT; - if (!IS_GEN9_LP(dev_priv)) + if (!IS_GEMINILAKE(dev_priv) && !IS_BROXTON(dev_priv)) dc6_reg = SKL_CSR_DC5_DC6_COUNT; } @@ -1339,6 +1340,12 @@ static int i915_lpsp_status(struct seq_file *m, void *unused) { struct drm_i915_private *i915 = node_to_i915(m->private); + if (DISPLAY_VER(i915) >= 13) { + LPSP_STATUS(!intel_lpsp_power_well_enabled(i915, + SKL_DISP_PW_2)); + return 0; + } + switch (DISPLAY_VER(i915)) { case 12: case 11: diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 99126caf5747..54c6d65011ee 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -11,6 +11,7 @@ #include "intel_combo_phy.h" #include "intel_csr.h" #include "intel_display_power.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" #include "intel_hotplug.h" @@ -550,7 +551,7 @@ static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv, if (drm_WARN_ON(&dev_priv->drm, !dig_port)) return; - if (IS_DISPLAY_VER(dev_priv, 11) && dig_port->tc_legacy_port) + if (DISPLAY_VER(dev_priv) == 11 && dig_port->tc_legacy_port) return; drm_WARN_ON(&dev_priv->drm, !intel_tc_port_ref_held(dig_port)); @@ -619,7 +620,7 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, * exit sequence. */ timeout_expected = is_tbt; - if (IS_DISPLAY_VER(dev_priv, 11) && dig_port->tc_legacy_port) { + if (DISPLAY_VER(dev_priv) == 11 && dig_port->tc_legacy_port) { icl_tc_cold_exit(dev_priv); timeout_expected = true; } @@ -709,7 +710,7 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv, * BIOS's own request bits, which are forced-on for these power wells * when exiting DC5/6. */ - if (IS_DISPLAY_VER(dev_priv, 9) && !IS_GEN9_LP(dev_priv) && + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv) && (id == SKL_DISP_PW_1 || id == SKL_DISP_PW_MISC_IO)) val |= intel_de_read(dev_priv, regs->bios); @@ -807,9 +808,9 @@ static u32 gen9_dc_mask(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 12) mask |= DC_STATE_EN_DC3CO | DC_STATE_EN_UPTO_DC6 | DC_STATE_EN_DC9; - else if (IS_DISPLAY_VER(dev_priv, 11)) + else if (DISPLAY_VER(dev_priv) == 11) mask |= DC_STATE_EN_UPTO_DC6 | DC_STATE_EN_DC9; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) mask |= DC_STATE_EN_DC9; else mask |= DC_STATE_EN_UPTO_DC6; @@ -821,6 +822,9 @@ static void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv) { u32 val; + if (!HAS_DISPLAY(dev_priv)) + return; + val = intel_de_read(dev_priv, DC_STATE_EN) & gen9_dc_mask(dev_priv); drm_dbg_kms(&dev_priv->drm, @@ -857,6 +861,9 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, u32 state) u32 val; u32 mask; + if (!HAS_DISPLAY(dev_priv)) + return; + if (drm_WARN_ON_ONCE(&dev_priv->drm, state & ~dev_priv->csr.allowed_dc_mask)) state &= dev_priv->csr.allowed_dc_mask; @@ -1035,7 +1042,7 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) enum i915_power_well_id high_pg; /* Power wells at this level and above must be disabled for DC5 entry */ - if (DISPLAY_VER(dev_priv) >= 12) + if (DISPLAY_VER(dev_priv) == 12) high_pg = ICL_DISP_PW_3; else high_pg = SKL_DISP_PW_2; @@ -1060,7 +1067,7 @@ static void gen9_enable_dc5(struct drm_i915_private *dev_priv) drm_dbg_kms(&dev_priv->drm, "Enabling DC5\n"); /* Wa Display #1183: skl,kbl,cfl */ - if (IS_GEN9_BC(dev_priv)) + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) intel_de_write(dev_priv, GEN8_CHICKEN_DCPR_1, intel_de_read(dev_priv, GEN8_CHICKEN_DCPR_1) | SKL_SELECT_ALTERNATE_DC_EXIT); @@ -1087,7 +1094,7 @@ static void skl_enable_dc6(struct drm_i915_private *dev_priv) drm_dbg_kms(&dev_priv->drm, "Enabling DC6\n"); /* Wa Display #1183: skl,kbl,cfl */ - if (IS_GEN9_BC(dev_priv)) + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) intel_de_write(dev_priv, GEN8_CHICKEN_DCPR_1, intel_de_read(dev_priv, GEN8_CHICKEN_DCPR_1) | SKL_SELECT_ALTERNATE_DC_EXIT); @@ -1181,6 +1188,9 @@ static void gen9_disable_dc_states(struct drm_i915_private *dev_priv) gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + if (!HAS_DISPLAY(dev_priv)) + return; + dev_priv->display.get_cdclk(dev_priv, &cdclk_config); /* Can't read out voltage_level so can't use intel_cdclk_changed() */ drm_WARN_ON(&dev_priv->drm, @@ -1189,7 +1199,7 @@ static void gen9_disable_dc_states(struct drm_i915_private *dev_priv) gen9_assert_dbuf_enabled(dev_priv); - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_verify_ddi_phy_power_wells(dev_priv); if (DISPLAY_VER(dev_priv) >= 11) @@ -3012,6 +3022,113 @@ intel_display_power_put_mask_in_set(struct drm_i915_private *i915, BIT_ULL(POWER_DOMAIN_AUX_B) | \ BIT_ULL(POWER_DOMAIN_INIT)) +/* + * XE_LPD Power Domains + * + * Previous platforms required that PG(n-1) be enabled before PG(n). That + * dependency chain turns into a dependency tree on XE_LPD: + * + * PG0 + * | + * --PG1-- + * / \ + * PGA --PG2-- + * / | \ + * PGB PGC PGD + * + * Power wells must be enabled from top to bottom and disabled from bottom + * to top. This allows pipes to be power gated independently. + */ + +#define XELPD_PW_D_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PIPE_D) | \ + BIT_ULL(POWER_DOMAIN_PIPE_D_PANEL_FITTER) | \ + BIT_ULL(POWER_DOMAIN_TRANSCODER_D) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +#define XELPD_PW_C_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PIPE_C) | \ + BIT_ULL(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ + BIT_ULL(POWER_DOMAIN_TRANSCODER_C) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +#define XELPD_PW_B_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PIPE_B) | \ + BIT_ULL(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ + BIT_ULL(POWER_DOMAIN_TRANSCODER_B) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +#define XELPD_PW_A_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PIPE_A) | \ + BIT_ULL(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +#define XELPD_PW_2_POWER_DOMAINS ( \ + XELPD_PW_B_POWER_DOMAINS | \ + XELPD_PW_C_POWER_DOMAINS | \ + XELPD_PW_D_POWER_DOMAINS | \ + BIT_ULL(POWER_DOMAIN_AUDIO) | \ + BIT_ULL(POWER_DOMAIN_VGA) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_D_XELPD) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_E_XELPD) | \ + BIT_ULL(POWER_DOMAIN_AUX_C) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC1) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC2) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC3) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC4) | \ + BIT_ULL(POWER_DOMAIN_AUX_C) | \ + BIT_ULL(POWER_DOMAIN_AUX_D_XELPD) | \ + BIT_ULL(POWER_DOMAIN_AUX_E_XELPD) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC1) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC2) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC3) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC4) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +/* + * XELPD PW_1/PG_1 domains (under HW/DMC control): + * - DBUF function (registers are in PW0) + * - Transcoder A + * - DDI_A and DDI_B + * + * XELPD PW_0/PW_1 domains (under HW/DMC control): + * - PCI + * - Clocks except port PLL + * - Shared functions: + * * interrupts except pipe interrupts + * * MBus except PIPE_MBUS_DBOX_CTL + * * DBUF registers + * - Central power except FBC + * - Top-level GTC (DDI-level GTC is in the well associated with the DDI) + */ + +#define XELPD_DISPLAY_DC_OFF_POWER_DOMAINS ( \ + XELPD_PW_2_POWER_DOMAINS | \ + BIT_ULL(POWER_DOMAIN_MODESET) | \ + BIT_ULL(POWER_DOMAIN_AUX_A) | \ + BIT_ULL(POWER_DOMAIN_AUX_B) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +#define XELPD_AUX_IO_D_XELPD_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_D_XELPD) +#define XELPD_AUX_IO_E_XELPD_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_E_XELPD) +#define XELPD_AUX_IO_USBC1_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC1) +#define XELPD_AUX_IO_USBC2_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC2) +#define XELPD_AUX_IO_USBC3_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC3) +#define XELPD_AUX_IO_USBC4_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC4) + +#define XELPD_AUX_IO_TBT1_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT1) +#define XELPD_AUX_IO_TBT2_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT2) +#define XELPD_AUX_IO_TBT3_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT3) +#define XELPD_AUX_IO_TBT4_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT4) + +#define XELPD_DDI_IO_D_XELPD_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_D_XELPD) +#define XELPD_DDI_IO_E_XELPD_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_E_XELPD) +#define XELPD_DDI_IO_TC1_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC1) +#define XELPD_DDI_IO_TC2_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC2) +#define XELPD_DDI_IO_TC3_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC3) +#define XELPD_DDI_IO_TC4_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC4) + static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_power_well_sync_hw_noop, .enable = i9xx_always_on_power_well_noop, @@ -4516,6 +4633,319 @@ static const struct i915_power_well_desc rkl_power_wells[] = { }, }; +static const struct i915_power_well_desc xelpd_power_wells[] = { + { + .name = "always-on", + .always_on = true, + .domains = POWER_DOMAIN_MASK, + .ops = &i9xx_always_on_power_well_ops, + .id = DISP_PW_ID_NONE, + }, + { + .name = "power well 1", + /* Handled by the DMC firmware */ + .always_on = true, + .domains = 0, + .ops = &hsw_power_well_ops, + .id = SKL_DISP_PW_1, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_PW_1, + .hsw.has_fuses = true, + }, + }, + { + .name = "DC off", + .domains = XELPD_DISPLAY_DC_OFF_POWER_DOMAINS, + .ops = &gen9_dc_off_power_well_ops, + .id = SKL_DISP_DC_OFF, + }, + { + .name = "power well 2", + .domains = XELPD_PW_2_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = SKL_DISP_PW_2, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_PW_2, + .hsw.has_vga = true, + .hsw.has_fuses = true, + }, + }, + { + .name = "power well A", + .domains = XELPD_PW_A_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_PW_A, + .hsw.irq_pipe_mask = BIT(PIPE_A), + .hsw.has_fuses = true, + }, + }, + { + .name = "power well B", + .domains = XELPD_PW_B_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_PW_B, + .hsw.irq_pipe_mask = BIT(PIPE_B), + .hsw.has_fuses = true, + }, + }, + { + .name = "power well C", + .domains = XELPD_PW_C_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_PW_C, + .hsw.irq_pipe_mask = BIT(PIPE_C), + .hsw.has_fuses = true, + }, + }, + { + .name = "power well D", + .domains = XELPD_PW_D_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_PW_D, + .hsw.irq_pipe_mask = BIT(PIPE_D), + .hsw.has_fuses = true, + }, + }, + { + .name = "DDI A IO", + .domains = ICL_DDI_IO_A_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_A, + } + }, + { + .name = "DDI B IO", + .domains = ICL_DDI_IO_B_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_B, + } + }, + { + .name = "DDI C IO", + .domains = ICL_DDI_IO_C_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_C, + } + }, + { + .name = "DDI IO D_XELPD", + .domains = XELPD_DDI_IO_D_XELPD_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_DDI_D, + } + }, + { + .name = "DDI IO E_XELPD", + .domains = XELPD_DDI_IO_E_XELPD_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_DDI_E, + } + }, + { + .name = "DDI IO TC1", + .domains = XELPD_DDI_IO_TC1_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_DDI_TC1, + } + }, + { + .name = "DDI IO TC2", + .domains = XELPD_DDI_IO_TC2_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_DDI_TC2, + } + }, + { + .name = "DDI IO TC3", + .domains = XELPD_DDI_IO_TC3_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_DDI_TC3, + } + }, + { + .name = "DDI IO TC4", + .domains = XELPD_DDI_IO_TC4_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_DDI_TC4, + } + }, + { + .name = "AUX A", + .domains = ICL_AUX_A_IO_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_A, + }, + }, + { + .name = "AUX B", + .domains = ICL_AUX_B_IO_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_B, + }, + }, + { + .name = "AUX C", + .domains = TGL_AUX_C_IO_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_C, + }, + }, + { + .name = "AUX D_XELPD", + .domains = XELPD_AUX_IO_D_XELPD_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_AUX_D, + }, + }, + { + .name = "AUX E_XELPD", + .domains = XELPD_AUX_IO_E_XELPD_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = XELPD_PW_CTL_IDX_AUX_E, + }, + }, + { + .name = "AUX USBC1", + .domains = XELPD_AUX_IO_USBC1_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TC1, + }, + }, + { + .name = "AUX USBC2", + .domains = XELPD_AUX_IO_USBC2_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TC2, + }, + }, + { + .name = "AUX USBC3", + .domains = XELPD_AUX_IO_USBC3_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TC3, + }, + }, + { + .name = "AUX USBC4", + .domains = XELPD_AUX_IO_USBC4_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TC4, + }, + }, + { + .name = "AUX TBT1", + .domains = XELPD_AUX_IO_TBT1_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT1, + .hsw.is_tc_tbt = true, + }, + }, + { + .name = "AUX TBT2", + .domains = XELPD_AUX_IO_TBT2_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT2, + .hsw.is_tc_tbt = true, + }, + }, + { + .name = "AUX TBT3", + .domains = XELPD_AUX_IO_TBT3_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT3, + .hsw.is_tc_tbt = true, + }, + }, + { + .name = "AUX TBT4", + .domains = XELPD_AUX_IO_TBT4_POWER_DOMAINS, + .ops = &icl_aux_power_well_ops, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT4, + .hsw.is_tc_tbt = true, + }, + }, +}; + static int sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv, int disable_power_well) @@ -4533,14 +4963,17 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, int requested_dc; int max_dc; + if (!HAS_DISPLAY(dev_priv)) + return 0; + if (IS_DG1(dev_priv)) max_dc = 3; else if (DISPLAY_VER(dev_priv) >= 12) max_dc = 4; - else if (DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv) || IS_GEN9_BC(dev_priv)) - max_dc = 2; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) max_dc = 1; + else if (DISPLAY_VER(dev_priv) >= 9) + max_dc = 2; else max_dc = 0; @@ -4549,7 +4982,8 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, * not depending on the DMC firmware. It's needed by system * suspend/resume, so allow it unconditionally. */ - mask = IS_GEN9_LP(dev_priv) || DISPLAY_VER(dev_priv) >= 11 ? + mask = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) || + DISPLAY_VER(dev_priv) >= 11 ? DC_STATE_EN_DC9 : 0; if (!dev_priv->params.disable_power_well) @@ -4673,14 +5107,19 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) * The enabling order will be from lower to higher indexed wells, * the disabling order is reversed. */ - if (IS_ALDERLAKE_S(dev_priv) || IS_DG1(dev_priv)) { + if (!HAS_DISPLAY(dev_priv)) { + power_domains->power_well_count = 0; + err = 0; + } else if (DISPLAY_VER(dev_priv) >= 13) { + err = set_power_wells(power_domains, xelpd_power_wells); + } else if (IS_ALDERLAKE_S(dev_priv) || IS_DG1(dev_priv)) { err = set_power_wells_mask(power_domains, tgl_power_wells, BIT_ULL(TGL_DISP_PW_TC_COLD_OFF)); } else if (IS_ROCKETLAKE(dev_priv)) { err = set_power_wells(power_domains, rkl_power_wells); - } else if (IS_DISPLAY_VER(dev_priv, 12)) { + } else if (DISPLAY_VER(dev_priv) == 12) { err = set_power_wells(power_domains, tgl_power_wells); - } else if (IS_DISPLAY_VER(dev_priv, 11)) { + } else if (DISPLAY_VER(dev_priv) == 11) { err = set_power_wells(power_domains, icl_power_wells); } else if (IS_CNL_WITH_PORT_F(dev_priv)) { err = set_power_wells(power_domains, cnl_power_wells); @@ -4692,7 +5131,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) err = set_power_wells(power_domains, glk_power_wells); } else if (IS_BROXTON(dev_priv)) { err = set_power_wells(power_domains, bxt_power_wells); - } else if (IS_GEN9_BC(dev_priv)) { + } else if (DISPLAY_VER(dev_priv) == 9) { err = set_power_wells(power_domains, skl_power_wells); } else if (IS_CHERRYVIEW(dev_priv)) { err = set_power_wells(power_domains, chv_power_wells); @@ -4741,33 +5180,28 @@ static void gen9_dbuf_slice_set(struct drm_i915_private *dev_priv, { i915_reg_t reg = DBUF_CTL_S(slice); bool state; - u32 val; - val = intel_de_read(dev_priv, reg); - if (enable) - val |= DBUF_POWER_REQUEST; - else - val &= ~DBUF_POWER_REQUEST; - intel_de_write(dev_priv, reg, val); + intel_de_rmw(dev_priv, reg, DBUF_POWER_REQUEST, + enable ? DBUF_POWER_REQUEST : 0); intel_de_posting_read(dev_priv, reg); udelay(10); state = intel_de_read(dev_priv, reg) & DBUF_POWER_STATE; drm_WARN(&dev_priv->drm, enable != state, "DBuf slice %d power %s timeout!\n", - slice, enable ? "enable" : "disable"); + slice, enabledisable(enable)); } void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv, u8 req_slices) { - int num_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices; struct i915_power_domains *power_domains = &dev_priv->power_domains; + u8 slice_mask = INTEL_INFO(dev_priv)->dbuf.slice_mask; enum dbuf_slice slice; - drm_WARN(&dev_priv->drm, req_slices & ~(BIT(num_slices) - 1), - "Invalid set of dbuf slices (0x%x) requested (num dbuf slices %d)\n", - req_slices, num_slices); + drm_WARN(&dev_priv->drm, req_slices & ~slice_mask, + "Invalid set of dbuf slices (0x%x) requested (total dbuf slices 0x%x)\n", + req_slices, slice_mask); drm_dbg_kms(&dev_priv->drm, "Updating dbuf slices to 0x%x\n", req_slices); @@ -4781,7 +5215,7 @@ void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv, */ mutex_lock(&power_domains->lock); - for (slice = DBUF_S1; slice < num_slices; slice++) + for_each_dbuf_slice(dev_priv, slice) gen9_dbuf_slice_set(dev_priv, slice, req_slices & BIT(slice)); dev_priv->dbuf.enabled_slices = req_slices; @@ -4809,10 +5243,9 @@ static void gen9_dbuf_disable(struct drm_i915_private *dev_priv) static void gen12_dbuf_slices_config(struct drm_i915_private *dev_priv) { - const int num_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices; enum dbuf_slice slice; - for (slice = DBUF_S1; slice < (DBUF_S1 + num_slices); slice++) + for_each_dbuf_slice(dev_priv, slice) intel_de_rmw(dev_priv, DBUF_CTL_S(slice), DBUF_TRACKER_STATE_SERVICE_MASK, DBUF_TRACKER_STATE_SERVICE(8)); @@ -4837,7 +5270,7 @@ static void icl_mbus_init(struct drm_i915_private *dev_priv) * expect us to program the abox_ctl0 register as well, even though * we don't have to program other instance-0 registers like BW_BUDDY. */ - if (IS_DISPLAY_VER(dev_priv, 12)) + if (DISPLAY_VER(dev_priv) == 12) abox_regs |= BIT(0); for_each_set_bit(i, &abox_regs, sizeof(abox_regs)) @@ -5122,6 +5555,9 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv, /* enable PCH reset handshake */ intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv)); + if (!HAS_DISPLAY(dev_priv)) + return; + /* enable PG1 and Misc I/O */ mutex_lock(&power_domains->lock); @@ -5146,6 +5582,9 @@ static void skl_display_core_uninit(struct drm_i915_private *dev_priv) struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *well; + if (!HAS_DISPLAY(dev_priv)) + return; + gen9_disable_dc_states(dev_priv); gen9_dbuf_disable(dev_priv); @@ -5186,6 +5625,9 @@ static void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume */ intel_pch_reset_handshake(dev_priv, false); + if (!HAS_DISPLAY(dev_priv)) + return; + /* Enable PG1 */ mutex_lock(&power_domains->lock); @@ -5207,6 +5649,9 @@ static void bxt_display_core_uninit(struct drm_i915_private *dev_priv) struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *well; + if (!HAS_DISPLAY(dev_priv)) + return; + gen9_disable_dc_states(dev_priv); gen9_dbuf_disable(dev_priv); @@ -5240,6 +5685,9 @@ static void cnl_display_core_init(struct drm_i915_private *dev_priv, bool resume /* 1. Enable PCH Reset Handshake */ intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv)); + if (!HAS_DISPLAY(dev_priv)) + return; + /* 2-3. */ intel_combo_phy_init(dev_priv); @@ -5267,6 +5715,9 @@ static void cnl_display_core_uninit(struct drm_i915_private *dev_priv) struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *well; + if (!HAS_DISPLAY(dev_priv)) + return; + gen9_disable_dc_states(dev_priv); /* 1. Disable all display engine functions -> aready done */ @@ -5381,6 +5832,9 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, /* 1. Enable PCH reset handshake. */ intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv)); + if (!HAS_DISPLAY(dev_priv)) + return; + /* 2. Initialize all combo phys */ intel_combo_phy_init(dev_priv); @@ -5413,11 +5867,15 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, intel_csr_load_program(dev_priv); /* Wa_14011508470 */ - if (IS_DISPLAY_VER(dev_priv, 12)) { + if (DISPLAY_VER(dev_priv) == 12) { val = DCPR_CLEAR_MEMSTAT_DIS | DCPR_SEND_RESP_IMM | DCPR_MASK_LPMODE | DCPR_MASK_MAXLATENCY_MEMUP_CLR; intel_uncore_rmw(&dev_priv->uncore, GEN11_CHICKEN_DCPR_2, 0, val); } + + /* Wa_14011503030:xelpd */ + if (DISPLAY_VER(dev_priv) >= 13) + intel_de_write(dev_priv, XELPD_DISPLAY_ERR_FATAL_MASK, ~0); } static void icl_display_core_uninit(struct drm_i915_private *dev_priv) @@ -5425,6 +5883,9 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv) struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *well; + if (!HAS_DISPLAY(dev_priv)) + return; + gen9_disable_dc_states(dev_priv); /* 1. Disable all display engine functions -> aready done */ @@ -5623,10 +6084,10 @@ void intel_power_domains_init_hw(struct drm_i915_private *i915, bool resume) icl_display_core_init(i915, resume); } else if (IS_CANNONLAKE(i915)) { cnl_display_core_init(i915, resume); - } else if (IS_GEN9_BC(i915)) { - skl_display_core_init(i915, resume); - } else if (IS_GEN9_LP(i915)) { + } else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) { bxt_display_core_init(i915, resume); + } else if (DISPLAY_VER(i915) == 9) { + skl_display_core_init(i915, resume); } else if (IS_CHERRYVIEW(i915)) { mutex_lock(&power_domains->lock); chv_phy_control_init(i915); @@ -5784,10 +6245,10 @@ void intel_power_domains_suspend(struct drm_i915_private *i915, icl_display_core_uninit(i915); else if (IS_CANNONLAKE(i915)) cnl_display_core_uninit(i915); - else if (IS_GEN9_BC(i915)) - skl_display_core_uninit(i915); - else if (IS_GEN9_LP(i915)) + else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) bxt_display_core_uninit(i915); + else if (DISPLAY_VER(i915) == 9) + skl_display_core_uninit(i915); power_domains->display_core_suspended = true; } @@ -5908,7 +6369,8 @@ static void intel_power_domains_verify_state(struct drm_i915_private *i915) void intel_display_power_suspend_late(struct drm_i915_private *i915) { - if (DISPLAY_VER(i915) >= 11 || IS_GEN9_LP(i915)) { + if (DISPLAY_VER(i915) >= 11 || IS_GEMINILAKE(i915) || + IS_BROXTON(i915)) { bxt_enable_dc9(i915); /* Tweaked Wa_14010685332:icp,jsp,mcc */ if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC) @@ -5921,7 +6383,8 @@ void intel_display_power_suspend_late(struct drm_i915_private *i915) void intel_display_power_resume_early(struct drm_i915_private *i915) { - if (DISPLAY_VER(i915) >= 11 || IS_GEN9_LP(i915)) { + if (DISPLAY_VER(i915) >= 11 || IS_GEMINILAKE(i915) || + IS_BROXTON(i915)) { gen9_sanitize_dc_state(i915); bxt_disable_dc9(i915); /* Tweaked Wa_14010685332:icp,jsp,mcc */ @@ -5938,7 +6401,7 @@ void intel_display_power_suspend(struct drm_i915_private *i915) if (DISPLAY_VER(i915) >= 11) { icl_display_core_uninit(i915); bxt_enable_dc9(i915); - } else if (IS_GEN9_LP(i915)) { + } else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) { bxt_display_core_uninit(i915); bxt_enable_dc9(i915); } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { @@ -5959,7 +6422,7 @@ void intel_display_power_resume(struct drm_i915_private *i915) DC_STATE_EN_UPTO_DC5) gen9_enable_dc5(i915); } - } else if (IS_GEN9_LP(i915)) { + } else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) { bxt_disable_dc9(i915); bxt_display_core_init(i915, true); if (i915->csr.dmc_payload && diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index f3ca5d5c9778..4f0917df4375 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -49,6 +49,9 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_LANES_TC5, POWER_DOMAIN_PORT_DDI_LANES_TC6, + POWER_DOMAIN_PORT_DDI_LANES_D_XELPD = POWER_DOMAIN_PORT_DDI_LANES_TC5, /* XELPD */ + POWER_DOMAIN_PORT_DDI_LANES_E_XELPD, + POWER_DOMAIN_PORT_DDI_A_IO, POWER_DOMAIN_PORT_DDI_B_IO, POWER_DOMAIN_PORT_DDI_C_IO, @@ -66,6 +69,9 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_IO_TC5, POWER_DOMAIN_PORT_DDI_IO_TC6, + POWER_DOMAIN_PORT_DDI_IO_D_XELPD = POWER_DOMAIN_PORT_DDI_IO_TC5, /* XELPD */ + POWER_DOMAIN_PORT_DDI_IO_E_XELPD, + POWER_DOMAIN_PORT_DSI, POWER_DOMAIN_PORT_CRT, POWER_DOMAIN_PORT_OTHER, @@ -88,6 +94,9 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_USBC5, POWER_DOMAIN_AUX_USBC6, + POWER_DOMAIN_AUX_D_XELPD = POWER_DOMAIN_AUX_USBC5, /* XELPD */ + POWER_DOMAIN_AUX_E_XELPD, + POWER_DOMAIN_AUX_IO_A, POWER_DOMAIN_AUX_C_TBT, POWER_DOMAIN_AUX_D_TBT, @@ -380,6 +389,8 @@ intel_display_power_put_all_in_set(struct drm_i915_private *i915, enum dbuf_slice { DBUF_S1, DBUF_S2, + DBUF_S3, + DBUF_S4, I915_MAX_DBUF_SLICES }; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e2e707c4dff5..9c0adfc60c6f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -45,7 +45,6 @@ #include <media/cec-notifier.h> #include "i915_drv.h" -#include "intel_de.h" struct drm_printer; struct __intel_global_objs_state; @@ -127,8 +126,12 @@ struct intel_framebuffer { /* Params to remap the FB pages and program the plane registers in each view. */ struct intel_fb_view normal_view; - struct intel_fb_view rotated_view; - struct intel_fb_view remapped_view; + union { + struct intel_fb_view rotated_view; + struct intel_fb_view remapped_view; + }; + + struct i915_address_space *dpt_vm; }; struct intel_fbdev { @@ -611,7 +614,8 @@ struct intel_plane_state { enum drm_scaling_filter scaling_filter; } hw; - struct i915_vma *vma; + struct i915_vma *ggtt_vma; + struct i915_vma *dpt_vma; unsigned long flags; #define PLANE_HAS_FENCE BIT(0) @@ -1973,9 +1977,19 @@ intel_wait_for_vblank_if_active(struct drm_i915_private *dev_priv, enum pipe pip intel_wait_for_vblank(dev_priv, pipe); } -static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state) +static inline bool intel_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier) +{ + return DISPLAY_VER(i915) >= 13 && modifier != DRM_FORMAT_MOD_LINEAR; +} + +static inline bool intel_fb_uses_dpt(const struct drm_framebuffer *fb) +{ + return fb && intel_modifier_uses_dpt(to_i915(fb->dev), fb->modifier); +} + +static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *plane_state) { - return i915_ggtt_offset(state->vma); + return i915_ggtt_offset(plane_state->ggtt_vma); } static inline struct intel_frontbuffer * diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index a560468765c0..5c9222283044 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -46,13 +46,15 @@ #include "intel_audio.h" #include "intel_connector.h" #include "intel_ddi.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_aux.h" +#include "intel_dp_hdcp.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" -#include "intel_dpll.h" #include "intel_dpio_phy.h" +#include "intel_dpll.h" #include "intel_fifo_underrun.h" #include "intel_hdcp.h" #include "intel_hdmi.h" @@ -107,6 +109,7 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp) } static void intel_dp_unset_edid(struct intel_dp *intel_dp); +static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc); /* update sink rates from dpcd */ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) @@ -215,7 +218,7 @@ bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); return DISPLAY_VER(dev_priv) >= 12 || - (IS_DISPLAY_VER(dev_priv, 11) && + (DISPLAY_VER(dev_priv) == 11 && encoder->port != PORT_A); } @@ -295,16 +298,16 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) { source_rates = cnl_rates; size = ARRAY_SIZE(cnl_rates); - if (IS_DISPLAY_VER(dev_priv, 10)) + if (DISPLAY_VER(dev_priv) == 10) max_rate = cnl_max_source_rate(intel_dp); else if (IS_JSL_EHL(dev_priv)) max_rate = ehl_max_source_rate(intel_dp); else max_rate = icl_max_source_rate(intel_dp); - } else if (IS_GEN9_LP(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { source_rates = bxt_rates; size = ARRAY_SIZE(bxt_rates); - } else if (IS_GEN9_BC(dev_priv)) { + } else if (DISPLAY_VER(dev_priv) == 9) { source_rates = skl_rates; size = ARRAY_SIZE(skl_rates); } else if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) || @@ -492,7 +495,8 @@ small_joiner_ram_size_bits(struct drm_i915_private *i915) static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, u32 link_clock, u32 lane_count, u32 mode_clock, u32 mode_hdisplay, - bool bigjoiner) + bool bigjoiner, + u32 pipe_bpp) { u32 bits_per_pixel, max_bpp_small_joiner_ram; int i; @@ -539,12 +543,17 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, return 0; } - /* Find the nearest match in the array of known BPPs from VESA */ - for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) { - if (bits_per_pixel < valid_dsc_bpp[i + 1]) - break; + /* From XE_LPD onwards we support from bpc upto uncompressed bpp-1 BPPs */ + if (DISPLAY_VER(i915) >= 13) { + bits_per_pixel = min(bits_per_pixel, pipe_bpp - 1); + } else { + /* Find the nearest match in the array of known BPPs from VESA */ + for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) { + if (bits_per_pixel < valid_dsc_bpp[i + 1]) + break; + } + bits_per_pixel = valid_dsc_bpp[i]; } - bits_per_pixel = valid_dsc_bpp[i]; /* * Compressed BPP in U6.4 format so multiply by 16, for Gen 11, @@ -778,6 +787,12 @@ intel_dp_mode_valid(struct drm_connector *connector, */ if (DISPLAY_VER(dev_priv) >= 10 && drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) { + /* + * TBD pass the connector BPC, + * for now U8_MAX so that max BPC on that platform would be picked + */ + int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX); + if (intel_dp_is_edp(intel_dp)) { dsc_max_output_bpp = drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4; @@ -791,7 +806,8 @@ intel_dp_mode_valid(struct drm_connector *connector, max_lanes, target_clock, mode->hdisplay, - bigjoiner) >> 4; + bigjoiner, + pipe_bpp) >> 4; dsc_slice_count = intel_dp_dsc_get_slice_count(intel_dp, target_clock, @@ -802,8 +818,11 @@ intel_dp_mode_valid(struct drm_connector *connector, dsc = dsc_max_output_bpp && dsc_slice_count; } - /* big joiner configuration needs DSC */ - if (bigjoiner && !dsc) + /* + * Big joiner configuration needs DSC for TGL which is not true for + * XE_LPD where uncompressed joiner is supported. + */ + if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc) return MODE_CLOCK_HIGH; if (mode_rate > max_rate && !dsc) @@ -916,7 +935,7 @@ static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp, if (DISPLAY_VER(dev_priv) >= 12) return true; - if (IS_DISPLAY_VER(dev_priv, 11) && pipe_config->cpu_transcoder != TRANSCODER_A) + if (DISPLAY_VER(dev_priv) == 11 && pipe_config->cpu_transcoder != TRANSCODER_A) return true; return false; @@ -1095,48 +1114,18 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, return -EINVAL; } -/* Optimize link config in order: max bpp, min lanes, min clock */ -static int -intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, - struct intel_crtc_state *pipe_config, - const struct link_config_limits *limits) -{ - const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - int bpp, clock, lane_count; - int mode_rate, link_clock, link_avail; - - for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) { - int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp); - - mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock, - output_bpp); - - for (lane_count = limits->min_lane_count; - lane_count <= limits->max_lane_count; - lane_count <<= 1) { - for (clock = limits->min_clock; clock <= limits->max_clock; clock++) { - link_clock = intel_dp->common_rates[clock]; - link_avail = intel_dp_max_data_rate(link_clock, - lane_count); - - if (mode_rate <= link_avail) { - pipe_config->lane_count = lane_count; - pipe_config->pipe_bpp = bpp; - pipe_config->port_clock = link_clock; - - return 0; - } - } - } - } - - return -EINVAL; -} - -static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) +static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 max_req_bpc) { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); int i, num_bpc; u8 dsc_bpc[3] = {0}; + u8 dsc_max_bpc; + + /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ + if (DISPLAY_VER(i915) >= 12) + dsc_max_bpc = min_t(u8, 12, max_req_bpc); + else + dsc_max_bpc = min_t(u8, 10, max_req_bpc); num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, dsc_bpc); @@ -1167,10 +1156,6 @@ static int intel_dp_dsc_compute_params(struct intel_encoder *encoder, */ vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST; - ret = intel_dsc_compute_params(encoder, crtc_state); - if (ret) - return ret; - /* * Slice Height of 8 works for all currently available panels. So start * with that if pic_height is an integral multiple of 8. Eventually add @@ -1183,6 +1168,10 @@ static int intel_dp_dsc_compute_params(struct intel_encoder *encoder, else vdsc_cfg->slice_height = 2; + ret = intel_dsc_compute_params(encoder, crtc_state); + if (ret) + return ret; + vdsc_cfg->dsc_version_major = (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] & DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT; @@ -1224,7 +1213,6 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - u8 dsc_max_bpc; int pipe_bpp; int ret; @@ -1234,14 +1222,7 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, if (!intel_dp_supports_dsc(intel_dp, pipe_config)) return -EINVAL; - /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ - if (DISPLAY_VER(dev_priv) >= 12) - dsc_max_bpc = min_t(u8, 12, conn_state->max_requested_bpc); - else - dsc_max_bpc = min_t(u8, 10, - conn_state->max_requested_bpc); - - pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc); + pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, conn_state->max_requested_bpc); /* Min Input BPC for ICL+ is 8 */ if (pipe_bpp < 8 * 3) { @@ -1276,7 +1257,8 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->lane_count, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, - pipe_config->bigjoiner); + pipe_config->bigjoiner, + pipe_bpp); dsc_dp_slice_count = intel_dp_dsc_get_slice_count(intel_dp, adjusted_mode->crtc_clock, @@ -1382,26 +1364,19 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, intel_dp_can_bigjoiner(intel_dp)) pipe_config->bigjoiner = true; - if (intel_dp_is_edp(intel_dp)) - /* - * Optimize for fast and narrow. eDP 1.3 section 3.3 and eDP 1.4 - * section A.1: "It is recommended that the minimum number of - * lanes be used, using the minimum link rate allowed for that - * lane configuration." - * - * Note that we fall back to the max clock and lane count for eDP - * panels that fail with the fast optimal settings (see - * intel_dp->use_max_params), in which case the fast vs. wide - * choice doesn't matter. - */ - ret = intel_dp_compute_link_config_fast(intel_dp, pipe_config, &limits); - else - /* Optimize for slow and wide. */ - ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits); + /* + * Optimize for slow and wide for everything, because there are some + * eDP 1.3 and 1.4 panels don't work well with fast and narrow. + */ + ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits); - /* enable compression if the mode doesn't fit available BW */ + /* + * Pipe joiner needs compression upto display12 due to BW limitation. DG2 + * onwards pipe joiner can be enabled without compression. + */ drm_dbg_kms(&i915->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en); - if (ret || intel_dp->force_dsc_en || pipe_config->bigjoiner) { + if (ret || intel_dp->force_dsc_en || (DISPLAY_VER(i915) < 13 && + pipe_config->bigjoiner)) { ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, conn_state, &limits); if (ret < 0) @@ -1861,7 +1836,7 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, if (ret < 0) drm_dbg_kms(&i915->drm, "Failed to %s sink decompression state\n", - enable ? "enable" : "disable"); + enabledisable(enable)); } static void @@ -2160,7 +2135,7 @@ void intel_dp_check_frl_training(struct intel_dp *intel_dp) * -PCON supports SRC_CTL_MODE (VESA DP2.0-HDMI2.1 PCON Spec Draft-1 Sec-7) * -sink is HDMI2.1 */ - if (!(intel_dp->dpcd[2] & DP_PCON_SOURCE_CTL_MODE) || + if (!(intel_dp->downstream_ports[2] & DP_PCON_SOURCE_CTL_MODE) || !intel_dp_is_hdmi_2_1_sink(intel_dp) || intel_dp->frl.is_trained) return; @@ -2293,8 +2268,8 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_PROTOCOL_CONVERTER_CONTROL_0, tmp) != 1) - drm_dbg_kms(&i915->drm, "Failed to set protocol converter HDMI mode to %s\n", - enableddisabled(intel_dp->has_hdmi_sink)); + drm_dbg_kms(&i915->drm, "Failed to %s protocol converter HDMI mode\n", + enabledisable(intel_dp->has_hdmi_sink)); tmp = crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 && intel_dp->dfp.ycbcr_444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0; @@ -2302,8 +2277,8 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1) drm_dbg_kms(&i915->drm, - "Failed to set protocol converter YCbCr 4:2:0 conversion mode to %s\n", - enableddisabled(intel_dp->dfp.ycbcr_444_to_420)); + "Failed to %s protocol converter YCbCr 4:2:0 conversion mode\n", + enabledisable(intel_dp->dfp.ycbcr_444_to_420)); tmp = 0; if (intel_dp->dfp.rgb_to_ycbcr) { @@ -2340,8 +2315,8 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0) drm_dbg_kms(&i915->drm, - "Failed to set protocol converter RGB->YCbCr conversion mode to %s\n", - enableddisabled(tmp ? true : false)); + "Failed to %s protocol converter RGB->YCbCr conversion mode\n", + enabledisable(tmp)); } @@ -2861,31 +2836,25 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder, const struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder); u32 dip_enable = VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW | VIDEO_DIP_ENABLE_DRM_GLK; - u32 val = intel_de_read(dev_priv, reg); + u32 val = intel_de_read(dev_priv, reg) & ~dip_enable; /* TODO: Add DSC case (DIP_ENABLE_PPS) */ /* When PSR is enabled, this routine doesn't disable VSC DIP */ - if (intel_psr_enabled(intel_dp)) - val &= ~dip_enable; - else - val &= ~(dip_enable | VIDEO_DIP_ENABLE_VSC_HSW); - - if (!enable) { - intel_de_write(dev_priv, reg, val); - intel_de_posting_read(dev_priv, reg); - return; - } + if (!crtc_state->has_psr) + val &= ~VIDEO_DIP_ENABLE_VSC_HSW; intel_de_write(dev_priv, reg, val); intel_de_posting_read(dev_priv, reg); + if (!enable) + return; + /* When PSR is enabled, VSC SDP is handled by PSR routine */ - if (!intel_psr_enabled(intel_dp)) + if (!crtc_state->has_psr) intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC); intel_write_dp_sdp(encoder, crtc_state, HDMI_PACKET_TYPE_GAMUT_METADATA); @@ -3012,14 +2981,13 @@ static void intel_read_dp_vsc_sdp(struct intel_encoder *encoder, struct drm_dp_vsc_sdp *vsc) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); unsigned int type = DP_SDP_VSC; struct dp_sdp sdp = {}; int ret; /* When PSR is enabled, VSC SDP is handled by PSR routine */ - if (intel_psr_enabled(intel_dp)) + if (crtc_state->has_psr) return; if ((crtc_state->infoframes.enable & @@ -3474,7 +3442,18 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) drm_WARN_ON_ONCE(&i915->drm, intel_dp->active_mst_links < 0); for (;;) { - u8 esi[DP_DPRX_ESI_LEN] = {}; + /* + * The +2 is because DP_DPRX_ESI_LEN is 14, but we then + * pass in "esi+10" to drm_dp_channel_eq_ok(), which + * takes a 6-byte array. So we actually need 16 bytes + * here. + * + * Somebody who knows what the limits actually are + * should check this, but for now this is at least + * harmless and avoids a valid compiler warning about + * using more of the array than we have allocated. + */ + u8 esi[DP_DPRX_ESI_LEN+2] = {}; bool handled; int retry; @@ -5397,7 +5376,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, intel_dp_add_properties(intel_dp, connector); if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) { - int ret = intel_dp_init_hdcp(dig_port, intel_connector); + int ret = intel_dp_hdcp_init(dig_port, intel_connector); if (ret) drm_dbg_kms(&dev_priv->drm, "HDCP init failed, skipping.\n"); @@ -5430,6 +5409,9 @@ void intel_dp_mst_suspend(struct drm_i915_private *dev_priv) { struct intel_encoder *encoder; + if (!HAS_DISPLAY(dev_priv)) + return; + for_each_intel_encoder(&dev_priv->drm, encoder) { struct intel_dp *intel_dp; @@ -5450,6 +5432,9 @@ void intel_dp_mst_resume(struct drm_i915_private *dev_priv) { struct intel_encoder *encoder; + if (!HAS_DISPLAY(dev_priv)) + return; + for_each_intel_encoder(&dev_priv->drm, encoder) { struct intel_dp *intel_dp; int ret; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 8db5062f6c4a..680631b5b437 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -119,9 +119,6 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); -int intel_dp_init_hdcp(struct intel_digital_port *dig_port, - struct intel_connector *intel_connector); - bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state); void intel_dp_sync_state(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 7e83bc2cc34a..7c048d2ecf43 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -126,12 +126,7 @@ static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp, struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - u32 precharge, timeout; - - if (IS_SANDYBRIDGE(dev_priv)) - precharge = 3; - else - precharge = 5; + u32 timeout; /* Max timeout value on G4x-BDW: 1.6ms */ if (IS_BROADWELL(dev_priv)) @@ -146,7 +141,7 @@ static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp, timeout | DP_AUX_CH_CTL_RECEIVE_ERROR | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | - (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | + (3 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT); } @@ -607,8 +602,8 @@ static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - case AUX_CH_USBC5: - case AUX_CH_USBC6: + case AUX_CH_USBC5: /* aka AUX_CH_D_XELPD */ + case AUX_CH_USBC6: /* aka AUX_CH_E_XELPD */ return DP_AUX_CH_CTL(aux_ch); default: MISSING_CASE(aux_ch); @@ -630,8 +625,8 @@ static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - case AUX_CH_USBC5: - case AUX_CH_USBC6: + case AUX_CH_USBC5: /* aka AUX_CH_D_XELPD */ + case AUX_CH_USBC6: /* aka AUX_CH_E_XELPD */ return DP_AUX_CH_DATA(aux_ch, index); default: MISSING_CASE(aux_ch); @@ -682,10 +677,15 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) else intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl; + intel_dp->aux.drm_dev = &dev_priv->drm; drm_dp_aux_init(&intel_dp->aux); /* Failure to allocate our preferred name is not critical */ - if (DISPLAY_VER(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1) + if (DISPLAY_VER(dev_priv) >= 13 && aux_ch >= AUX_CH_D_XELPD) + intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s", + aux_ch_name(aux_ch - AUX_CH_D_XELPD + AUX_CH_D), + encoder->base.name); + else if (DISPLAY_VER(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1) intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s", aux_ch - AUX_CH_USBC1 + '1', encoder->base.name); diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index 651884390137..8e9ac9ba1d38 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -291,7 +291,7 @@ static void set_vesa_backlight_enable(struct intel_dp *intel_dp, bool enable) if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER, reg_val) != 1) { drm_dbg_kms(&i915->drm, "Failed to %s aux backlight\n", - enable ? "enable" : "disable"); + enabledisable(enable)); } } @@ -646,7 +646,6 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) break; case INTEL_BACKLIGHT_DISPLAY_DDI: try_intel_interface = true; - try_vesa_interface = true; break; default: return -ENODEV; diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index 90868e156c69..d697d169e8c1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -11,9 +11,11 @@ #include <drm/drm_hdcp.h> #include <drm/drm_print.h> -#include "intel_display_types.h" #include "intel_ddi.h" +#include "intel_de.h" +#include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dp_hdcp.h" #include "intel_hdcp.h" static unsigned int transcoder_to_stream_enc_status(enum transcoder cpu_transcoder) @@ -532,7 +534,7 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, u8 *byte = buf; ssize_t ret, bytes_to_recv, len; const struct hdcp2_dp_msg_data *hdcp2_msg_data; - ktime_t msg_end; + ktime_t msg_end = ktime_set(0, 0); bool msg_expired; hdcp2_msg_data = get_hdcp2_dp_msg_data(msg_id); @@ -835,7 +837,7 @@ static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = { .protocol = HDCP_PROTOCOL_DP, }; -int intel_dp_init_hdcp(struct intel_digital_port *dig_port, +int intel_dp_hdcp_init(struct intel_digital_port *dig_port, struct intel_connector *intel_connector) { struct drm_device *dev = intel_connector->base.dev; diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.h b/drivers/gpu/drm/i915/display/intel_dp_hdcp.h new file mode 100644 index 000000000000..eff5ec5c5021 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_DP_HDCP___ +#define __INTEL_DP_HDCP___ + +struct intel_connector; +struct intel_digital_port; + +int intel_dp_hdcp_init(struct intel_digital_port *dig_port, + struct intel_connector *intel_connector); + +#endif /* __INTEL_DP_HDCP___ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 5e9c3c74310c..6bf6f1ec13ed 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -37,7 +37,7 @@ intel_dp_dump_link_status(struct drm_device *drm, static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp) { - memset(&intel_dp->lttpr_common_caps, 0, sizeof(intel_dp->lttpr_common_caps)); + memset(intel_dp->lttpr_common_caps, 0, sizeof(intel_dp->lttpr_common_caps)); } static void intel_dp_reset_lttpr_count(struct intel_dp *intel_dp) @@ -96,7 +96,7 @@ static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) * Detecting LTTPRs must be avoided on platforms with an AUX timeout * period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1). */ - if (DISPLAY_VER(i915) < 10) + if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915)) return false; if (drm_dp_read_lttpr_common_caps(&intel_dp->aux, @@ -513,7 +513,7 @@ static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_d enum drm_dp_phy dp_phy) { if (dp_phy == DP_PHY_DPRX) - drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); + drm_dp_link_train_clock_recovery_delay(&intel_dp->aux, intel_dp->dpcd); else drm_dp_lttpr_link_train_clock_recovery_delay(); } @@ -665,11 +665,11 @@ intel_dp_link_training_channel_equalization_delay(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy) { if (dp_phy == DP_PHY_DPRX) { - drm_dp_link_train_channel_eq_delay(intel_dp->dpcd); + drm_dp_link_train_channel_eq_delay(&intel_dp->aux, intel_dp->dpcd); } else { const u8 *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy); - drm_dp_lttpr_link_train_channel_eq_delay(phy_caps); + drm_dp_lttpr_link_train_channel_eq_delay(&intel_dp->aux, phy_caps); } } @@ -882,7 +882,8 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp, int lttpr_count = intel_dp_init_lttpr_and_dprx_caps(intel_dp); if (lttpr_count < 0) - return; + /* Still continue with enabling the port and link training. */ + lttpr_count = 0; if (!intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count)) intel_dp_schedule_fallback_link_training(intel_dp, crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 2daa3f67791e..332d2f9fda5c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -32,13 +32,16 @@ #include "intel_atomic.h" #include "intel_audio.h" #include "intel_connector.h" +#include "intel_crtc.h" #include "intel_ddi.h" +#include "intel_de.h" #include "intel_display_types.h" -#include "intel_hotplug.h" #include "intel_dp.h" +#include "intel_dp_hdcp.h" #include "intel_dp_mst.h" #include "intel_dpio_phy.h" #include "intel_hdcp.h" +#include "intel_hotplug.h" #include "skl_scaler.h" static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, @@ -70,7 +73,8 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, connector->port, crtc_state->pbn, - drm_dp_get_vc_payload_bw(crtc_state->port_clock, + drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, + crtc_state->port_clock, crtc_state->lane_count)); if (slots == -EDEADLK) return slots; @@ -154,7 +158,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->limited_color_range = intel_dp_limited_color_range(pipe_config, conn_state); - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) pipe_config->lane_lat_optim_mask = bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); @@ -832,7 +836,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_attach_broadcast_rgb_property(connector); if (DISPLAY_VER(dev_priv) <= 12) { - ret = intel_dp_init_hdcp(dig_port, intel_connector); + ret = intel_dp_hdcp_init(dig_port, intel_connector); if (ret) drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP MST init failed, skipping.\n", connector->name, connector->base.id); @@ -941,6 +945,8 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) struct intel_dp *intel_dp = &dig_port->dp; enum port port = dig_port->base.port; int ret; + int max_source_rate = + intel_dp->source_rates[intel_dp->num_source_rates - 1]; if (!HAS_DP_MST(i915) || intel_dp_is_edp(intel_dp)) return 0; @@ -956,7 +962,10 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) /* create encoders */ intel_dp_create_fake_mst_encoders(dig_port); ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, &i915->drm, - &intel_dp->aux, 16, 3, conn_base_id); + &intel_dp->aux, 16, 3, + (u8)dig_port->max_lanes, + drm_dp_link_rate_to_bw_code(max_source_rate), + conn_base_id); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 514c4a7adffc..48507ed79950 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -23,6 +23,7 @@ #include "display/intel_dp.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" #include "intel_sideband.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 3e3c5eed1600..89635da9f6f6 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -4,6 +4,7 @@ */ #include <linux/kernel.h> #include "intel_crtc.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_display.h" #include "intel_dpll.h" @@ -366,13 +367,11 @@ static bool intel_pll_is_valid(struct drm_i915_private *dev_priv, if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) return false; - if (!IS_PINEVIEW(dev_priv) && !IS_VALLEYVIEW(dev_priv) && - !IS_CHERRYVIEW(dev_priv) && !IS_GEN9_LP(dev_priv)) + if (!IS_PINEVIEW(dev_priv) && !IS_LP(dev_priv)) if (clock->m1 <= clock->m2) return false; - if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) && - !IS_GEN9_LP(dev_priv)) { + if (!IS_LP(dev_priv)) { if (clock->p < limit->p.min || limit->p.max < clock->p) return false; if (clock->m < limit->m.min || limit->m.max < clock->m) @@ -1358,7 +1357,7 @@ intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv) dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock; else if (IS_PINEVIEW(dev_priv)) dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock; - else if (!IS_DISPLAY_VER(dev_priv, 2)) + else if (DISPLAY_VER(dev_priv) != 2) dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; else dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock; diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index 7ff4b0d29ed1..88247027fd5a 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -6,6 +6,8 @@ #ifndef _INTEL_DPLL_H_ #define _INTEL_DPLL_H_ +#include <linux/types.h> + struct dpll; struct drm_i915_private; struct intel_crtc; @@ -37,5 +39,8 @@ void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); +bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, + struct dpll *best_clock); +int chv_calc_dpll_params(int refclk, struct dpll *pll_clock); #endif diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 1ae158d12c07..18bfe8d09277 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -21,8 +21,10 @@ * DEALINGS IN THE SOFTWARE. */ +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" +#include "intel_dpll.h" #include "intel_dpll_mgr.h" /** @@ -4441,10 +4443,10 @@ void intel_shared_dpll_init(struct drm_device *dev) dpll_mgr = &icl_pll_mgr; else if (IS_CANNONLAKE(dev_priv)) dpll_mgr = &cnl_pll_mgr; - else if (IS_GEN9_BC(dev_priv)) - dpll_mgr = &skl_pll_mgr; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) dpll_mgr = &bxt_pll_mgr; + else if (DISPLAY_VER(dev_priv) == 9) + dpll_mgr = &skl_pll_mgr; else if (HAS_DDI(dev_priv)) dpll_mgr = &hsw_pll_mgr; else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 857126822a88..62a8a69f9f5d 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -5,6 +5,7 @@ */ #include "i915_drv.h" +#include "intel_de.h" #include "intel_display_types.h" #define DSB_BUF_SIZE (2 * PAGE_SIZE) diff --git a/drivers/gpu/drm/i915/display/intel_dsi.h b/drivers/gpu/drm/i915/display/intel_dsi.h index 625f2f1ae061..50d6da0b2419 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.h +++ b/drivers/gpu/drm/i915/display/intel_dsi.h @@ -124,6 +124,7 @@ struct intel_dsi { u16 panel_on_delay; u16 panel_off_delay; u16 panel_pwr_cycle_delay; + ktime_t panel_power_off_time; }; struct intel_dsi_host { diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 090cd76266c6..77419f8c05e9 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -33,6 +33,7 @@ #include "i915_drv.h" #include "intel_connector.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dvo.h" #include "intel_dvo_dev.h" diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index fca41ac5b8e1..a005c68889e7 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -30,14 +30,6 @@ bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) plane == 2; } -bool is_aux_plane(const struct drm_framebuffer *fb, int plane) -{ - if (is_ccs_modifier(fb->modifier)) - return is_ccs_plane(fb, plane); - - return plane == 1; -} - bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane) { return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && @@ -84,7 +76,7 @@ int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) unsigned int intel_tile_size(const struct drm_i915_private *i915) { - return IS_DISPLAY_VER(i915, 2) ? 2048 : 4096; + return DISPLAY_VER(i915) == 2 ? 2048 : 4096; } unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) @@ -171,17 +163,17 @@ void intel_fb_plane_get_subsampling(int *hsub, int *vsub, *vsub = 32; } -static void intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane) +static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h) { - int main_plane = is_ccs_plane(fb, color_plane) ? - skl_ccs_to_main_plane(fb, color_plane) : 0; + int main_plane = is_ccs_plane(&fb->base, color_plane) ? + skl_ccs_to_main_plane(&fb->base, color_plane) : 0; int main_hsub, main_vsub; int hsub, vsub; - intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, main_plane); - intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane); - *w = fb->width / main_hsub / hsub; - *h = fb->height / main_vsub / vsub; + intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane); + intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane); + *w = fb->base.width / main_hsub / hsub; + *h = fb->base.height / main_vsub / vsub; } static u32 intel_adjust_tile_offset(int *x, int *y, @@ -486,9 +478,12 @@ static bool intel_plane_can_remap(const struct intel_plane_state *plane_state) return true; } -static bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) +bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) { - return false; + struct drm_i915_private *i915 = to_i915(fb->base.dev); + + return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR && + !is_ccs_modifier(fb->base.modifier); } static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation) @@ -609,7 +604,11 @@ plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane, unsigned int pitch_tiles) { if (intel_fb_needs_pot_stride_remap(fb)) - return roundup_pow_of_two(pitch_tiles); + /* + * ADL_P, the only platform needing a POT stride has a minimum + * of 8 stride tiles. + */ + return roundup_pow_of_two(max(pitch_tiles, 8u)); else return pitch_tiles; } @@ -743,19 +742,34 @@ static void intel_fb_view_init(struct intel_fb_view *view, enum i915_ggtt_view_t view->gtt.type = view_type; } -int intel_fill_fb_info(struct drm_i915_private *i915, struct drm_framebuffer *fb) +bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb) { - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + if (DISPLAY_VER(to_i915(fb->base.dev)) >= 13) + return false; + + return fb->base.modifier == I915_FORMAT_MOD_Y_TILED || + fb->base.modifier == I915_FORMAT_MOD_Yf_TILED; +} + +int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb) +{ + struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base); u32 gtt_offset_rotated = 0; u32 gtt_offset_remapped = 0; unsigned int max_size = 0; - int i, num_planes = fb->format->num_planes; + int i, num_planes = fb->base.format->num_planes; unsigned int tile_size = intel_tile_size(i915); - intel_fb_view_init(&intel_fb->normal_view, I915_GGTT_VIEW_NORMAL); - intel_fb_view_init(&intel_fb->rotated_view, I915_GGTT_VIEW_ROTATED); - intel_fb_view_init(&intel_fb->remapped_view, I915_GGTT_VIEW_REMAPPED); + intel_fb_view_init(&fb->normal_view, I915_GGTT_VIEW_NORMAL); + + drm_WARN_ON(&i915->drm, + intel_fb_supports_90_270_rotation(fb) && + intel_fb_needs_pot_stride_remap(fb)); + + if (intel_fb_supports_90_270_rotation(fb)) + intel_fb_view_init(&fb->rotated_view, I915_GGTT_VIEW_ROTATED); + if (intel_fb_needs_pot_stride_remap(fb)) + intel_fb_view_init(&fb->remapped_view, I915_GGTT_VIEW_REMAPPED); for (i = 0; i < num_planes; i++) { struct fb_plane_view_dims view_dims; @@ -770,45 +784,43 @@ int intel_fill_fb_info(struct drm_i915_private *i915, struct drm_framebuffer *fb * is consumed by the driver and not passed to DE. Skip the * arithmetic related to alignment and offset calculation. */ - if (is_gen12_ccs_cc_plane(fb, i)) { - if (IS_ALIGNED(fb->offsets[i], PAGE_SIZE)) + if (is_gen12_ccs_cc_plane(&fb->base, i)) { + if (IS_ALIGNED(fb->base.offsets[i], PAGE_SIZE)) continue; else return -EINVAL; } - cpp = fb->format->cpp[i]; - intel_fb_plane_dims(&width, &height, fb, i); + cpp = fb->base.format->cpp[i]; + intel_fb_plane_dims(fb, i, &width, &height); - ret = convert_plane_offset_to_xy(intel_fb, i, width, &x, &y); + ret = convert_plane_offset_to_xy(fb, i, width, &x, &y); if (ret) return ret; - init_plane_view_dims(intel_fb, i, width, height, &view_dims); + init_plane_view_dims(fb, i, width, height, &view_dims); /* * First pixel of the framebuffer from * the start of the normal gtt mapping. */ - intel_fb->normal_view.color_plane[i].x = x; - intel_fb->normal_view.color_plane[i].y = y; - intel_fb->normal_view.color_plane[i].stride = intel_fb->base.pitches[i]; + fb->normal_view.color_plane[i].x = x; + fb->normal_view.color_plane[i].y = y; + fb->normal_view.color_plane[i].stride = fb->base.pitches[i]; - offset = calc_plane_aligned_offset(intel_fb, i, &x, &y); + offset = calc_plane_aligned_offset(fb, i, &x, &y); - /* Y or Yf modifiers required for 90/270 rotation */ - if (fb->modifier == I915_FORMAT_MOD_Y_TILED || - fb->modifier == I915_FORMAT_MOD_Yf_TILED) - gtt_offset_rotated += calc_plane_remap_info(intel_fb, i, &view_dims, + if (intel_fb_supports_90_270_rotation(fb)) + gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims, offset, gtt_offset_rotated, x, y, - &intel_fb->rotated_view); + &fb->rotated_view); - if (intel_fb_needs_pot_stride_remap(intel_fb)) - gtt_offset_remapped += calc_plane_remap_info(intel_fb, i, &view_dims, + if (intel_fb_needs_pot_stride_remap(fb)) + gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims, offset, gtt_offset_remapped, x, y, - &intel_fb->remapped_view); + &fb->remapped_view); - size = calc_plane_normal_size(intel_fb, i, &view_dims, x, y); + size = calc_plane_normal_size(fb, i, &view_dims, x, y); /* how many tiles in total needed in the bo */ max_size = max(max_size, offset + size); } diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index 6acf792a8c44..739d1b91754b 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -19,7 +19,6 @@ struct intel_plane_state; bool is_ccs_plane(const struct drm_framebuffer *fb, int plane); bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane); bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane); -bool is_aux_plane(const struct drm_framebuffer *fb, int plane); bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane); bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane); @@ -46,7 +45,10 @@ u32 intel_plane_compute_aligned_offset(int *x, int *y, const struct intel_plane_state *state, int color_plane); -int intel_fill_fb_info(struct drm_i915_private *i915, struct drm_framebuffer *fb); +bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb); +bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb); + +int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb); void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation, struct intel_fb_view *view); int intel_plane_compute_gtt(struct intel_plane_state *plane_state); diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 986bbbe3b12f..1847a161cb37 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -43,6 +43,7 @@ #include "i915_drv.h" #include "i915_trace.h" #include "i915_vgpu.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fbc.h" #include "intel_frontbuffer.h" @@ -67,7 +68,7 @@ static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv, int lines; intel_fbc_get_plane_source_size(cache, NULL, &lines); - if (IS_DISPLAY_VER(dev_priv, 7)) + if (DISPLAY_VER(dev_priv) == 7) lines = min(lines, 2048); else if (DISPLAY_VER(dev_priv) >= 8) lines = min(lines, 2560); @@ -109,7 +110,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) cfb_pitch = params->fb.stride; /* FBC_CTL wants 32B or 64B units */ - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) cfb_pitch = (cfb_pitch / 32) - 1; else cfb_pitch = (cfb_pitch / 64) - 1; @@ -118,7 +119,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) intel_de_write(dev_priv, FBC_TAG(i), 0); - if (IS_DISPLAY_VER(dev_priv, 4)) { + if (DISPLAY_VER(dev_priv) == 4) { u32 fbc_ctl2; /* Set it up... */ @@ -302,7 +303,7 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) int threshold = dev_priv->fbc.threshold; /* Display WA #0529: skl, kbl, bxt. */ - if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) { + if (DISPLAY_VER(dev_priv) == 9) { u32 val = intel_de_read(dev_priv, CHICKEN_MISC_4); val &= ~(FBC_STRIDE_OVERRIDE | FBC_STRIDE_MASK); @@ -445,7 +446,8 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv, * reserved range size, so it always assumes the maximum (8mb) is used. * If we enable FBC using a CFB on that memory range we'll get FIFO * underruns, even if that range is not reserved by the BIOS. */ - if (IS_BROADWELL(dev_priv) || IS_GEN9_BC(dev_priv)) + if (IS_BROADWELL(dev_priv) || (DISPLAY_VER(dev_priv) == 9 && + !IS_BROXTON(dev_priv))) end = resource_size(&dev_priv->dsm) - 8 * 1024 * 1024; else end = U64_MAX; @@ -590,14 +592,14 @@ static bool stride_is_valid(struct drm_i915_private *dev_priv, if (stride < 512) return false; - if (IS_DISPLAY_VER(dev_priv, 2) || IS_DISPLAY_VER(dev_priv, 3)) + if (DISPLAY_VER(dev_priv) == 2 || DISPLAY_VER(dev_priv) == 3) return stride == 4096 || stride == 8192; - if (IS_DISPLAY_VER(dev_priv, 4) && !IS_G4X(dev_priv) && stride < 2048) + if (DISPLAY_VER(dev_priv) == 4 && !IS_G4X(dev_priv) && stride < 2048) return false; /* Display WA #1105: skl,bxt,kbl,cfl,glk */ - if (IS_DISPLAY_VER(dev_priv, 9) && + if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) && modifier == DRM_FORMAT_MOD_LINEAR && stride & 511) return false; @@ -617,7 +619,7 @@ static bool pixel_format_is_valid(struct drm_i915_private *dev_priv, case DRM_FORMAT_XRGB1555: case DRM_FORMAT_RGB565: /* 16bpp not supported on gen2 */ - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) return false; /* WaFbcOnly1to1Ratio:ctg */ if (IS_G4X(dev_priv)) @@ -735,11 +737,11 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc, cache->fence_y_offset = intel_plane_fence_y_offset(plane_state); drm_WARN_ON(&dev_priv->drm, plane_state->flags & PLANE_HAS_FENCE && - !plane_state->vma->fence); + !plane_state->ggtt_vma->fence); if (plane_state->flags & PLANE_HAS_FENCE && - plane_state->vma->fence) - cache->fence_id = plane_state->vma->fence->id; + plane_state->ggtt_vma->fence) + cache->fence_id = plane_state->ggtt_vma->fence->id; else cache->fence_id = -1; @@ -759,7 +761,7 @@ static u16 intel_fbc_gen9_wa_cfb_stride(struct drm_i915_private *dev_priv) struct intel_fbc *fbc = &dev_priv->fbc; struct intel_fbc_state_cache *cache = &fbc->state_cache; - if ((IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) && + if ((DISPLAY_VER(dev_priv) == 9) && cache->fb.modifier != I915_FORMAT_MOD_X_TILED) return DIV_ROUND_UP(cache->plane.src_w, 32 * fbc->threshold) * 8; else diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index d719cd9c5b73..cef1061fd6cb 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -5,6 +5,7 @@ #include "intel_atomic.h" #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fdi.h" diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c index 9605a1064366..3315aa1d4d5a 100644 --- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c +++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c @@ -27,6 +27,7 @@ #include "i915_drv.h" #include "i915_trace.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fbc.h" #include "intel_fifo_underrun.h" @@ -271,7 +272,7 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); else if (IS_IRONLAKE(dev_priv) || IS_SANDYBRIDGE(dev_priv)) ilk_set_fifo_underrun_reporting(dev, pipe, enable); - else if (IS_DISPLAY_VER(dev_priv, 7)) + else if (DISPLAY_VER(dev_priv) == 7) ivb_set_fifo_underrun_reporting(dev, pipe, enable, old); else if (DISPLAY_VER(dev_priv) >= 8) bdw_set_fifo_underrun_reporting(dev, pipe, enable); @@ -432,7 +433,7 @@ void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv) if (HAS_GMCH(dev_priv)) i9xx_check_fifo_underruns(crtc); - else if (IS_DISPLAY_VER(dev_priv, 7)) + else if (DISPLAY_VER(dev_priv) == 7) ivb_check_fifo_underruns(crtc); } diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index 6fc6965b6133..8161d49e78ba 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -58,6 +58,7 @@ #include "display/intel_dp.h" #include "i915_drv.h" +#include "i915_trace.h" #include "intel_display_types.h" #include "intel_fbc.h" #include "intel_frontbuffer.h" @@ -87,6 +88,8 @@ static void frontbuffer_flush(struct drm_i915_private *i915, if (!frontbuffer_bits) return; + trace_intel_frontbuffer_flush(frontbuffer_bits, origin); + might_sleep(); intel_edp_drrs_flush(i915, frontbuffer_bits); intel_psr_flush(i915, frontbuffer_bits, origin); @@ -173,6 +176,8 @@ void __intel_fb_invalidate(struct intel_frontbuffer *front, spin_unlock(&i915->fb_tracking.lock); } + trace_intel_frontbuffer_invalidate(frontbuffer_bits, origin); + might_sleep(); intel_psr_invalidate(i915, frontbuffer_bits, origin); intel_edp_drrs_invalidate(i915, frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 8ddc20daef64..fcf47f98ea36 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -34,6 +34,7 @@ #include <drm/drm_hdcp.h> #include "i915_drv.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_gmbus.h" @@ -107,9 +108,9 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv, return &gmbus_pins_icp[pin]; else if (HAS_PCH_CNP(dev_priv)) return &gmbus_pins_cnp[pin]; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) return &gmbus_pins_bxt[pin]; - else if (IS_GEN9_BC(dev_priv)) + else if (DISPLAY_VER(dev_priv) == 9) return &gmbus_pins_skl[pin]; else if (IS_BROADWELL(dev_priv)) return &gmbus_pins_bdw[pin]; @@ -128,9 +129,9 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv, size = ARRAY_SIZE(gmbus_pins_icp); else if (HAS_PCH_CNP(dev_priv)) size = ARRAY_SIZE(gmbus_pins_cnp); - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) size = ARRAY_SIZE(gmbus_pins_bxt); - else if (IS_GEN9_BC(dev_priv)) + else if (DISPLAY_VER(dev_priv) == 9) size = ARRAY_SIZE(gmbus_pins_skl); else if (IS_BROADWELL(dev_priv)) size = ARRAY_SIZE(gmbus_pins_bdw); @@ -600,7 +601,7 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, int ret = 0; /* Display WA #0868: skl,bxt,kbl,cfl,glk,cnl */ - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_gmbus_clock_gating(dev_priv, false); else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_CNP(dev_priv)) pch_gmbus_clock_gating(dev_priv, false); @@ -713,7 +714,7 @@ timeout: out: /* Display WA #0868: skl,bxt,kbl,cfl,glk,cnl */ - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_gmbus_clock_gating(dev_priv, true); else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_CNP(dev_priv)) pch_gmbus_clock_gating(dev_priv, true); @@ -845,9 +846,6 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv) unsigned int pin; int ret; - if (!HAS_DISPLAY(dev_priv)) - return 0; - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; else if (!HAS_GMCH(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index d8570e14fe60..ebc2e32aec0b 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -18,6 +18,7 @@ #include "i915_drv.h" #include "i915_reg.h" #include "intel_display_power.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_hdcp.h" #include "intel_sideband.h" @@ -286,11 +287,12 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv) /* * Initiate loading the HDCP key from fuses. * - * BXT+ platforms, HDCP key needs to be loaded by SW. Only Gen 9 - * platforms except BXT and GLK, differ in the key load trigger process - * from other platforms. So GEN9_BC uses the GT Driver Mailbox i/f. + * BXT+ platforms, HDCP key needs to be loaded by SW. Only display + * version 9 platforms (minus BXT) differ in the key load trigger + * process from other platforms. These platforms use the GT Driver + * Mailbox interface. */ - if (IS_GEN9_BC(dev_priv)) { + if (DISPLAY_VER(dev_priv) == 9 && !IS_BROXTON(dev_priv)) { ret = sandybridge_pcode_write(dev_priv, SKL_PCODE_LOAD_HDCP_KEYS, 1); if (ret) { diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index d69f0a6dc26d..4a1b2d863b0c 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -43,6 +43,7 @@ #include "intel_atomic.h" #include "intel_connector.h" #include "intel_ddi.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_gmbus.h" @@ -531,6 +532,11 @@ void hsw_write_infoframe(struct intel_encoder *encoder, hsw_dip_data_reg(dev_priv, cpu_transcoder, type, i >> 2), 0); + /* Wa_14013475917 */ + if (DISPLAY_VER(dev_priv) == 13 && crtc_state->has_psr && + type == DP_SDP_VSC) + return; + val |= hsw_infoframe_enable(type); intel_de_write(dev_priv, ctl_reg, val); intel_de_posting_read(dev_priv, ctl_reg); @@ -542,11 +548,9 @@ void hsw_read_infoframe(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - u32 val, *data = frame; + u32 *data = frame; int i; - val = intel_de_read(dev_priv, HSW_TVIDEO_DIP_CTL(cpu_transcoder)); - for (i = 0; i < len; i += 4) *data++ = intel_de_read(dev_priv, hsw_dip_data_reg(dev_priv, cpu_transcoder, type, i >> 2)); @@ -1251,8 +1255,7 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) drm_dbg_kms(&dev_priv->drm, "%s DP dual mode adaptor TMDS output\n", enable ? "Enabling" : "Disabling"); - drm_dp_dual_mode_set_tmds_output(hdmi->dp_dual_mode.type, - adapter, enable); + drm_dp_dual_mode_set_tmds_output(&dev_priv->drm, hdmi->dp_dual_mode.type, adapter, enable); } static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, @@ -1841,7 +1844,8 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, return MODE_CLOCK_RANGE; /* BXT/GLK DPLL can't generate 223-240 MHz */ - if (IS_GEN9_LP(dev_priv) && clock > 223333 && clock < 240000) + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + clock > 223333 && clock < 240000) return MODE_CLOCK_RANGE; /* CHV DPLL can't generate 216-240 MHz */ @@ -1862,6 +1866,32 @@ static int intel_hdmi_port_clock(int clock, int bpc) } static enum drm_mode_status +intel_hdmi_mode_clock_valid(struct intel_hdmi *hdmi, int clock, bool has_hdmi_sink) +{ + struct drm_device *dev = intel_hdmi_to_dev(hdmi); + struct drm_i915_private *dev_priv = to_i915(dev); + enum drm_mode_status status; + + /* check if we can do 8bpc */ + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 8), + true, has_hdmi_sink); + + if (has_hdmi_sink) { + /* if we can't do 8bpc we may still be able to do 12bpc */ + if (status != MODE_OK && !HAS_GMCH(dev_priv)) + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 12), + true, has_hdmi_sink); + + /* if we can't do 8,12bpc we may still be able to do 10bpc */ + if (status != MODE_OK && DISPLAY_VER(dev_priv) >= 11) + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 10), + true, has_hdmi_sink); + } + + return status; +} + +static enum drm_mode_status intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { @@ -1872,6 +1902,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector, int clock = mode->clock; int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; bool has_hdmi_sink = intel_has_hdmi_sink(hdmi, connector->state); + bool ycbcr_420_only; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -1888,26 +1919,22 @@ intel_hdmi_mode_valid(struct drm_connector *connector, clock *= 2; } - if (drm_mode_is_420_only(&connector->display_info, mode)) + ycbcr_420_only = drm_mode_is_420_only(&connector->display_info, mode); + if (ycbcr_420_only) clock /= 2; - /* check if we can do 8bpc */ - status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 8), - true, has_hdmi_sink); + status = intel_hdmi_mode_clock_valid(hdmi, clock, has_hdmi_sink); + if (status != MODE_OK) { + if (ycbcr_420_only || + !connector->ycbcr_420_allowed || + !drm_mode_is_420_also(&connector->display_info, mode)) + return status; - if (has_hdmi_sink) { - /* if we can't do 8bpc we may still be able to do 12bpc */ - if (status != MODE_OK && !HAS_GMCH(dev_priv)) - status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 12), - true, has_hdmi_sink); - - /* if we can't do 8,12bpc we may still be able to do 10bpc */ - if (status != MODE_OK && DISPLAY_VER(dev_priv) >= 11) - status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 10), - true, has_hdmi_sink); + clock /= 2; + status = intel_hdmi_mode_clock_valid(hdmi, clock, has_hdmi_sink); + if (status != MODE_OK) + return status; } - if (status != MODE_OK) - return status; return intel_mode_valid_max_plane_size(dev_priv, mode, false); } @@ -1977,7 +2004,7 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, /* Display Wa_1405510057:icl,ehl */ if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 && - bpc == 10 && IS_DISPLAY_VER(dev_priv, 11) && + bpc == 10 && DISPLAY_VER(dev_priv) == 11 && (adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start) % 8 == 2) return false; @@ -1988,29 +2015,6 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, INTEL_OUTPUT_FORMAT_YCBCR420); } -static int -intel_hdmi_ycbcr420_config(struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) -{ - struct drm_connector *connector = conn_state->connector; - struct drm_i915_private *i915 = to_i915(connector->dev); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - - if (!drm_mode_is_420_only(&connector->display_info, adjusted_mode)) - return 0; - - if (!connector->ycbcr_420_allowed) { - drm_err(&i915->drm, - "Platform doesn't support YCBCR420 output\n"); - return -EINVAL; - } - - crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420; - - return intel_pch_panel_fitting(crtc_state, conn_state); -} - static int intel_hdmi_compute_bpc(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int clock) @@ -2117,6 +2121,39 @@ static bool intel_hdmi_has_audio(struct intel_encoder *encoder, return intel_conn_state->force_audio == HDMI_AUDIO_ON; } +static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct drm_connector *connector = conn_state->connector; + struct drm_i915_private *i915 = to_i915(connector->dev); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int ret; + bool ycbcr_420_only; + + ycbcr_420_only = drm_mode_is_420_only(&connector->display_info, adjusted_mode); + if (connector->ycbcr_420_allowed && ycbcr_420_only) { + crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420; + } else { + if (!connector->ycbcr_420_allowed && ycbcr_420_only) + drm_dbg_kms(&i915->drm, + "YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n"); + crtc_state->output_format = INTEL_OUTPUT_FORMAT_RGB; + } + + ret = intel_hdmi_compute_clock(encoder, crtc_state); + if (ret) { + if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420 && + connector->ycbcr_420_allowed && + drm_mode_is_420_also(&connector->display_info, adjusted_mode)) { + crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420; + ret = intel_hdmi_compute_clock(encoder, crtc_state); + } + } + + return ret; +} + int intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -2141,23 +2178,25 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) pipe_config->pixel_multiplier = 2; - ret = intel_hdmi_ycbcr420_config(pipe_config, conn_state); - if (ret) - return ret; - - pipe_config->limited_color_range = - intel_hdmi_limited_color_range(pipe_config, conn_state); - if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv)) pipe_config->has_pch_encoder = true; pipe_config->has_audio = intel_hdmi_has_audio(encoder, pipe_config, conn_state); - ret = intel_hdmi_compute_clock(encoder, pipe_config); + ret = intel_hdmi_compute_output_format(encoder, pipe_config, conn_state); if (ret) return ret; + if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { + ret = intel_pch_panel_fitting(pipe_config, conn_state); + if (ret) + return ret; + } + + pipe_config->limited_color_range = + intel_hdmi_limited_color_range(pipe_config, conn_state); + if (conn_state->picture_aspect_ratio) adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; @@ -2223,7 +2262,7 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) enum port port = hdmi_to_dig_port(hdmi)->base.port; struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); - enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(adapter); + enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(&dev_priv->drm, adapter); /* * Type 1 DVI adaptors are not required to implement any @@ -2256,7 +2295,7 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) hdmi->dp_dual_mode.type = type; hdmi->dp_dual_mode.max_tmds_clock = - drm_dp_dual_mode_max_tmds_clock(type, adapter); + drm_dp_dual_mode_max_tmds_clock(&dev_priv->drm, type, adapter); drm_dbg_kms(&dev_priv->drm, "DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n", @@ -2460,8 +2499,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c drm_connector_attach_content_type_property(connector); if (DISPLAY_VER(dev_priv) >= 10) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, 0); + drm_connector_attach_hdr_output_metadata_property(connector); if (!HAS_GMCH(dev_priv)) drm_connector_attach_max_bpc_property(connector, 8, 12); @@ -2708,13 +2746,13 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder) return ddc_pin; } - if (HAS_PCH_ADP(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv)) ddc_pin = adls_port_to_ddc_pin(dev_priv, port); else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) ddc_pin = dg1_port_to_ddc_pin(dev_priv, port); else if (IS_ROCKETLAKE(dev_priv)) ddc_pin = rkl_port_to_ddc_pin(dev_priv, port); - else if (IS_GEN9_BC(dev_priv) && HAS_PCH_TGP(dev_priv)) + else if (DISPLAY_VER(dev_priv) == 9 && HAS_PCH_TGP(dev_priv)) ddc_pin = gen9bc_tgp_port_to_ddc_pin(dev_priv, port); else if (HAS_PCH_MCC(dev_priv)) ddc_pin = mcc_port_to_ddc_pin(dev_priv, port); @@ -2722,7 +2760,7 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder) ddc_pin = icl_port_to_ddc_pin(dev_priv, port); else if (HAS_PCH_CNP(dev_priv)) ddc_pin = cnp_port_to_ddc_pin(dev_priv, port); - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) ddc_pin = bxt_port_to_ddc_pin(dev_priv, port); else if (IS_CHERRYVIEW(dev_priv)) ddc_pin = chv_port_to_ddc_pin(dev_priv, port); diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index f46a1b7190b8..47c85ac97c87 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -595,6 +595,9 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) { int i; + if (!HAS_DISPLAY(dev_priv)) + return; + for_each_hpd_pin(i) { dev_priv->hotplug.stats[i].count = 0; dev_priv->hotplug.stats[i].state = HPD_ENABLED; @@ -670,6 +673,9 @@ static void i915_hpd_poll_init_work(struct work_struct *work) */ void intel_hpd_poll_enable(struct drm_i915_private *dev_priv) { + if (!HAS_DISPLAY(dev_priv)) + return; + WRITE_ONCE(dev_priv->hotplug.poll_enabled, true); /* @@ -702,6 +708,9 @@ void intel_hpd_poll_enable(struct drm_i915_private *dev_priv) */ void intel_hpd_poll_disable(struct drm_i915_private *dev_priv) { + if (!HAS_DISPLAY(dev_priv)) + return; + WRITE_ONCE(dev_priv->hotplug.poll_enabled, false); schedule_work(&dev_priv->hotplug.poll_init_work); } @@ -718,6 +727,9 @@ void intel_hpd_init_work(struct drm_i915_private *dev_priv) void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) { + if (!HAS_DISPLAY(dev_priv)) + return; + spin_lock_irq(&dev_priv->irq_lock); dev_priv->hotplug.long_port_mask = 0; diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c index e4ff533e3a69..05d2d750fa53 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.c +++ b/drivers/gpu/drm/i915/display/intel_lspcon.c @@ -27,6 +27,7 @@ #include <drm/drm_dp_dual_mode_helper.h> #include <drm/drm_edid.h> +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_lspcon.h" @@ -139,10 +140,11 @@ void lspcon_detect_hdr_capability(struct intel_lspcon *lspcon) static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon) { + struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); enum drm_lspcon_mode current_mode; - struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc; + struct i2c_adapter *adapter = &intel_dp->aux.ddc; - if (drm_lspcon_get_mode(adapter, ¤t_mode)) { + if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, ¤t_mode)) { DRM_DEBUG_KMS("Error reading LSPCON mode\n"); return DRM_LSPCON_MODE_INVALID; } @@ -175,11 +177,12 @@ out: static int lspcon_change_mode(struct intel_lspcon *lspcon, enum drm_lspcon_mode mode) { + struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); int err; enum drm_lspcon_mode current_mode; - struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc; + struct i2c_adapter *adapter = &intel_dp->aux.ddc; - err = drm_lspcon_get_mode(adapter, ¤t_mode); + err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, ¤t_mode); if (err) { DRM_ERROR("Error reading LSPCON mode\n"); return err; @@ -190,7 +193,7 @@ static int lspcon_change_mode(struct intel_lspcon *lspcon, return 0; } - err = drm_lspcon_set_mode(adapter, mode); + err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, adapter, mode); if (err < 0) { DRM_ERROR("LSPCON mode change failed\n"); return err; @@ -221,7 +224,8 @@ static bool lspcon_probe(struct intel_lspcon *lspcon) { int retry; enum drm_dp_dual_mode_type adaptor_type; - struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc; + struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); + struct i2c_adapter *adapter = &intel_dp->aux.ddc; enum drm_lspcon_mode expected_mode; expected_mode = lspcon_wake_native_aux_ch(lspcon) ? @@ -232,7 +236,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon) if (retry) usleep_range(500, 1000); - adaptor_type = drm_dp_dual_mode_detect(adapter); + adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, adapter); if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON) break; } diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index f31a368f34c5..7f40e9f60bc2 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -41,6 +41,7 @@ #include "i915_drv.h" #include "intel_atomic.h" #include "intel_connector.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_gmbus.h" #include "intel_lvds.h" @@ -280,7 +281,7 @@ static void intel_pre_enable_lvds(struct intel_atomic_state *state, * special lvds dither control bit on pch-split platforms, dithering is * only controlled through the PIPECONF reg. */ - if (IS_DISPLAY_VER(dev_priv, 4)) { + if (DISPLAY_VER(dev_priv) == 4) { /* * Bspec wording suggests that LVDS port dithering only exists * for 18bpp panels. diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index e477b6114a60..46cba12be888 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -34,6 +34,7 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_frontbuffer.h" #include "intel_overlay.h" @@ -383,7 +384,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay) i830_overlay_clock_gating(dev_priv, true); } -static void +__i915_active_call static void intel_overlay_last_flip_retire(struct i915_active *active) { struct intel_overlay *overlay = @@ -550,7 +551,7 @@ static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 widt { u32 sw; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) sw = ALIGN((offset & 31) + width, 32); else sw = ALIGN((offset & 63) + width, 64); @@ -803,8 +804,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, atomic_inc(&dev_priv->gpu_error.pending_fb_pin); vma = intel_overlay_pin_fb(new_bo); - if (IS_ERR(vma)) + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); goto out_pin_section; + } i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB); @@ -818,7 +821,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, oconfig |= OCONF_CC_OUT_8BIT; if (crtc_state->gamma_enable) oconfig |= OCONF_GAMMA2_ENABLE; - if (IS_DISPLAY_VER(dev_priv, 4)) + if (DISPLAY_VER(dev_priv) == 4) oconfig |= OCONF_CSC_MODE_BT709; oconfig |= pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; @@ -1052,7 +1055,7 @@ static int check_overlay_src(struct drm_i915_private *dev_priv, if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) return -EINVAL; - if (IS_DISPLAY_VER(dev_priv, 4) && rec->stride_Y < 512) + if (DISPLAY_VER(dev_priv) == 4 && rec->stride_Y < 512) return -EINVAL; tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? @@ -1279,7 +1282,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, attrs->contrast = overlay->contrast; attrs->saturation = overlay->saturation; - if (!IS_DISPLAY_VER(dev_priv, 2)) { + if (DISPLAY_VER(dev_priv) != 2) { attrs->gamma0 = intel_de_read(dev_priv, OGAMC0); attrs->gamma1 = intel_de_read(dev_priv, OGAMC1); attrs->gamma2 = intel_de_read(dev_priv, OGAMC2); @@ -1303,7 +1306,7 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, update_reg_attrs(overlay, overlay->regs); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) goto out_unlock; if (overlay->active) { diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 10022d1575e1..7d7a60b4d2de 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -35,6 +35,7 @@ #include <linux/pwm.h> #include "intel_connector.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp_aux_backlight.h" #include "intel_dsi_dcs_backlight.h" @@ -667,7 +668,7 @@ static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc); } - if (IS_DISPLAY_VER(dev_priv, 4)) { + if (DISPLAY_VER(dev_priv) == 4) { mask = BACKLIGHT_DUTY_CYCLE_MASK; } else { level <<= 1; @@ -1040,7 +1041,7 @@ static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state, * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 * that has backlight. */ - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); } @@ -1372,6 +1373,9 @@ int intel_backlight_device_register(struct intel_connector *connector) struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_panel *panel = &connector->panel; struct backlight_properties props; + struct backlight_device *bd; + const char *name; + int ret = 0; if (WARN_ON(panel->backlight.device)) return -ENODEV; @@ -1398,28 +1402,49 @@ int intel_backlight_device_register(struct intel_connector *connector) else props.power = FB_BLANK_POWERDOWN; + name = kstrdup("intel_backlight", GFP_KERNEL); + if (!name) + return -ENOMEM; + + bd = backlight_device_register(name, connector->base.kdev, connector, + &intel_backlight_device_ops, &props); + /* - * Note: using the same name independent of the connector prevents - * registration of multiple backlight devices in the driver. + * Using the same name independent of the drm device or connector + * prevents registration of multiple backlight devices in the + * driver. However, we need to use the default name for backward + * compatibility. Use unique names for subsequent backlight devices as a + * fallback when the default name already exists. */ - panel->backlight.device = - backlight_device_register("intel_backlight", - connector->base.kdev, - connector, - &intel_backlight_device_ops, &props); - - if (IS_ERR(panel->backlight.device)) { - drm_err(&i915->drm, "Failed to register backlight: %ld\n", - PTR_ERR(panel->backlight.device)); - panel->backlight.device = NULL; - return -ENODEV; + if (IS_ERR(bd) && PTR_ERR(bd) == -EEXIST) { + kfree(name); + name = kasprintf(GFP_KERNEL, "card%d-%s-backlight", + i915->drm.primary->index, connector->base.name); + if (!name) + return -ENOMEM; + + bd = backlight_device_register(name, connector->base.kdev, connector, + &intel_backlight_device_ops, &props); } + if (IS_ERR(bd)) { + drm_err(&i915->drm, + "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n", + connector->base.base.id, connector->base.name, name, PTR_ERR(bd)); + ret = PTR_ERR(bd); + goto out; + } + + panel->backlight.device = bd; + drm_dbg_kms(&i915->drm, - "Connector %s backlight sysfs interface registered\n", - connector->base.name); + "[CONNECTOR:%d:%s] backlight device %s registered\n", + connector->base.base.id, connector->base.name, name); - return 0; +out: + kfree(name); + + return ret; } void intel_backlight_device_unregister(struct intel_connector *connector) @@ -1728,7 +1753,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu ctl = intel_de_read(dev_priv, BLC_PWM_CTL); - if (IS_DISPLAY_VER(dev_priv, 2) || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) + if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv)) panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; if (IS_PINEVIEW(dev_priv)) @@ -2161,7 +2186,7 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) intel_dsi_dcs_init_backlight_funcs(connector) == 0) return; - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { panel->backlight.pwm_funcs = &bxt_pwm_funcs; } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) { panel->backlight.pwm_funcs = &cnp_pwm_funcs; @@ -2178,7 +2203,7 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) } else { panel->backlight.pwm_funcs = &vlv_pwm_funcs; } - } else if (IS_DISPLAY_VER(dev_priv, 4)) { + } else if (DISPLAY_VER(dev_priv) == 4) { panel->backlight.pwm_funcs = &i965_pwm_funcs; } else { panel->backlight.pwm_funcs = &i9xx_pwm_funcs; diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c index 7c8e0d76207f..8ac263f471be 100644 --- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c @@ -30,6 +30,7 @@ #include <linux/seq_file.h> #include "intel_atomic.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_pipe_crc.h" @@ -409,7 +410,7 @@ static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv, enum pipe pipe, enum intel_pipe_crc_source *source, u32 *val) { - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) return i8xx_pipe_crc_ctl_reg(source, val); else if (DISPLAY_VER(dev_priv) < 5) return i9xx_pipe_crc_ctl_reg(dev_priv, pipe, source, val); @@ -539,7 +540,7 @@ static int intel_is_valid_crc_source(struct drm_i915_private *dev_priv, const enum intel_pipe_crc_source source) { - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) return i8xx_crc_source_valid(dev_priv, source); else if (DISPLAY_VER(dev_priv) < 5) return i9xx_crc_source_valid(dev_priv, source); @@ -580,13 +581,14 @@ int intel_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, return -EINVAL; } -int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name) +int intel_crtc_set_crc_source(struct drm_crtc *_crtc, const char *source_name) { - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_pipe_crc *pipe_crc = &intel_crtc->pipe_crc; + struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc; enum intel_display_power_domain power_domain; enum intel_pipe_crc_source source; + enum pipe pipe = crtc->pipe; intel_wakeref_t wakeref; u32 val = 0; /* shut up gcc */ int ret = 0; @@ -597,7 +599,7 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name) return -EINVAL; } - power_domain = POWER_DOMAIN_PIPE(crtc->index); + power_domain = POWER_DOMAIN_PIPE(pipe); wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); if (!wakeref) { drm_dbg_kms(&dev_priv->drm, @@ -607,64 +609,64 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name) enable = source != INTEL_PIPE_CRC_SOURCE_NONE; if (enable) - intel_crtc_crc_setup_workarounds(to_intel_crtc(crtc), true); + intel_crtc_crc_setup_workarounds(crtc, true); - ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val); + ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val); if (ret != 0) goto out; pipe_crc->source = source; - intel_de_write(dev_priv, PIPE_CRC_CTL(crtc->index), val); - intel_de_posting_read(dev_priv, PIPE_CRC_CTL(crtc->index)); + intel_de_write(dev_priv, PIPE_CRC_CTL(pipe), val); + intel_de_posting_read(dev_priv, PIPE_CRC_CTL(pipe)); if (!source) { if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - vlv_undo_pipe_scramble_reset(dev_priv, crtc->index); + vlv_undo_pipe_scramble_reset(dev_priv, pipe); } pipe_crc->skipped = 0; out: if (!enable) - intel_crtc_crc_setup_workarounds(to_intel_crtc(crtc), false); + intel_crtc_crc_setup_workarounds(crtc, false); intel_display_power_put(dev_priv, power_domain, wakeref); return ret; } -void intel_crtc_enable_pipe_crc(struct intel_crtc *intel_crtc) +void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc) { - struct drm_crtc *crtc = &intel_crtc->base; - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct intel_pipe_crc *pipe_crc = &intel_crtc->pipe_crc; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc; + enum pipe pipe = crtc->pipe; u32 val = 0; - if (!crtc->crc.opened) + if (!crtc->base.crc.opened) return; - if (get_new_crc_ctl_reg(dev_priv, crtc->index, &pipe_crc->source, &val) < 0) + if (get_new_crc_ctl_reg(dev_priv, pipe, &pipe_crc->source, &val) < 0) return; /* Don't need pipe_crc->lock here, IRQs are not generated. */ pipe_crc->skipped = 0; - intel_de_write(dev_priv, PIPE_CRC_CTL(crtc->index), val); - intel_de_posting_read(dev_priv, PIPE_CRC_CTL(crtc->index)); + intel_de_write(dev_priv, PIPE_CRC_CTL(pipe), val); + intel_de_posting_read(dev_priv, PIPE_CRC_CTL(pipe)); } -void intel_crtc_disable_pipe_crc(struct intel_crtc *intel_crtc) +void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc) { - struct drm_crtc *crtc = &intel_crtc->base; - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct intel_pipe_crc *pipe_crc = &intel_crtc->pipe_crc; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc; + enum pipe pipe = crtc->pipe; /* Swallow crc's until we stop generating them. */ spin_lock_irq(&pipe_crc->lock); pipe_crc->skipped = INT_MIN; spin_unlock_irq(&pipe_crc->lock); - intel_de_write(dev_priv, PIPE_CRC_CTL(crtc->index), 0); - intel_de_posting_read(dev_priv, PIPE_CRC_CTL(crtc->index)); + intel_de_write(dev_priv, PIPE_CRC_CTL(pipe), 0); + intel_de_posting_read(dev_priv, PIPE_CRC_CTL(pipe)); intel_synchronize_irq(dev_priv); } diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index c55da130773b..a36ec4a818ff 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -5,6 +5,7 @@ #include "g4x_dp.h" #include "i915_drv.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dpll.h" @@ -313,10 +314,10 @@ void intel_pps_reset_all(struct drm_i915_private *dev_priv) { struct intel_encoder *encoder; - if (drm_WARN_ON(&dev_priv->drm, - !(IS_VALLEYVIEW(dev_priv) || - IS_CHERRYVIEW(dev_priv) || - IS_GEN9_LP(dev_priv)))) + if (drm_WARN_ON(&dev_priv->drm, !IS_LP(dev_priv))) + return; + + if (!HAS_DISPLAY(dev_priv)) return; /* @@ -338,7 +339,7 @@ void intel_pps_reset_all(struct drm_i915_private *dev_priv) if (encoder->type != INTEL_OUTPUT_EDP) continue; - if (IS_GEN9_LP(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 9) intel_dp->pps.pps_reset = true; else intel_dp->pps.pps_pipe = INVALID_PIPE; @@ -361,7 +362,7 @@ static void intel_pps_get_registers(struct intel_dp *intel_dp, memset(regs, 0, sizeof(*regs)); - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) pps_idx = bxt_power_sequencer_idx(intel_dp); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) pps_idx = vlv_power_sequencer_pipe(intel_dp); @@ -372,7 +373,8 @@ static void intel_pps_get_registers(struct intel_dp *intel_dp, regs->pp_off = PP_OFF_DELAYS(pps_idx); /* Cycle delay moved from PP_DIVISOR to PP_CONTROL */ - if (IS_GEN9_LP(dev_priv) || INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) || + INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) regs->pp_div = INVALID_MMIO_REG; else regs->pp_div = PP_DIVISOR(pps_idx); @@ -1378,7 +1380,7 @@ void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv) int pps_num; int pps_idx; - if (HAS_DDI(dev_priv)) + if (!HAS_DISPLAY(dev_priv) || HAS_DDI(dev_priv)) return; /* * This w/a is needed at least on CPT/PPT, but to be sure apply it @@ -1399,7 +1401,7 @@ void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv) void intel_pps_setup(struct drm_i915_private *i915) { - if (HAS_PCH_SPLIT(i915) || IS_GEN9_LP(i915)) + if (HAS_PCH_SPLIT(i915) || IS_GEMINILAKE(i915) || IS_BROXTON(i915)) i915->pps_mmio_base = PCH_PPS_BASE; else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) i915->pps_mmio_base = VLV_PPS_BASE; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 1d561812fcad..acaf3d459821 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -27,6 +27,7 @@ #include "i915_drv.h" #include "intel_atomic.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dp_aux.h" #include "intel_hdmi.h" @@ -524,7 +525,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val = psr_compute_idle_frames(intel_dp) << EDP_PSR2_IDLE_FRAME_SHIFT; val |= EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE; - if (DISPLAY_VER(dev_priv) >= 10) + if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12) val |= EDP_Y_COORDINATE_ENABLE; val |= EDP_PSR2_FRAME_BEFORE_SU(intel_dp->psr.sink_sync_latency + 1); @@ -655,6 +656,13 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, u32 exit_scanlines; /* + * FIXME: Due to the changed sequence of activating/deactivating DC3CO, + * disable DC3CO until the changed dc3co activating/deactivating sequence + * is applied. B.Specs:49196 + */ + return; + + /* * DMC's DC3CO exit mechanism has an issue with Selective Fecth * TODO: when the issue is addressed, this restriction should be removed. */ @@ -712,6 +720,13 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, } } + /* Wa_14010254185 Wa_14010103792 */ + if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B1)) { + drm_dbg_kms(&dev_priv->drm, + "PSR2 sel fetch not enabled, missing the implementation of WAs\n"); + return false; + } + return crtc_state->enable_psr2_sel_fetch = true; } @@ -732,6 +747,12 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } + /* Wa_16011181250 */ + if (IS_ROCKETLAKE(dev_priv) || IS_ALDERLAKE_S(dev_priv)) { + drm_dbg_kms(&dev_priv->drm, "PSR2 is defeatured for this platform\n"); + return false; + } + if (!transcoder_has_psr2(dev_priv, crtc_state->cpu_transcoder)) { drm_dbg_kms(&dev_priv->drm, "PSR2 not supported in transcoder %s\n", @@ -769,7 +790,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, psr_max_h = 4096; psr_max_v = 2304; max_bpp = 24; - } else if (IS_DISPLAY_VER(dev_priv, 9)) { + } else if (DISPLAY_VER(dev_priv) == 9) { psr_max_h = 3640; psr_max_v = 2304; max_bpp = 24; @@ -804,6 +825,13 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, } } + /* Wa_2209313811 */ + if (!crtc_state->enable_psr2_sel_fetch && + IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B1)) { + drm_dbg_kms(&dev_priv->drm, "PSR2 HW tracking is not supported this Display stepping\n"); + return false; + } + if (!crtc_state->enable_psr2_sel_fetch && (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v)) { drm_dbg_kms(&dev_priv->drm, @@ -873,6 +901,51 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); } +void intel_psr_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + struct intel_dp *intel_dp; + u32 val; + + if (!dig_port) + return; + + intel_dp = &dig_port->dp; + if (!CAN_PSR(intel_dp)) + return; + + mutex_lock(&intel_dp->psr.lock); + if (!intel_dp->psr.enabled) + goto unlock; + + /* + * Not possible to read EDP_PSR/PSR2_CTL registers as it is + * enabled/disabled because of frontbuffer tracking and others. + */ + pipe_config->has_psr = true; + pipe_config->has_psr2 = intel_dp->psr.psr2_enabled; + pipe_config->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); + + if (!intel_dp->psr.psr2_enabled) + goto unlock; + + if (HAS_PSR2_SEL_FETCH(dev_priv)) { + val = intel_de_read(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder)); + if (val & PSR2_MAN_TRK_CTL_ENABLE) + pipe_config->enable_psr2_sel_fetch = true; + } + + if (DISPLAY_VER(dev_priv) >= 12) { + val = intel_de_read(dev_priv, EXITLINE(intel_dp->psr.transcoder)); + val &= EXITLINE_MASK; + pipe_config->dc3co_exitline = val; + } +unlock: + mutex_unlock(&intel_dp->psr.lock); +} + static void intel_psr_activate(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -909,7 +982,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_psr_setup_aux(intel_dp); - if (intel_dp->psr.psr2_enabled && IS_DISPLAY_VER(dev_priv, 9)) { + if (intel_dp->psr.psr2_enabled && DISPLAY_VER(dev_priv) == 9) { i915_reg_t reg = CHICKEN_TRANS(cpu_transcoder); u32 chicken = intel_de_read(dev_priv, reg); @@ -1154,21 +1227,7 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (IS_TIGERLAKE(dev_priv)) - /* - * Writes to CURSURFLIVE in TGL are causing IOMMU errors and - * visual glitches that are often reproduced when executing - * CPU intensive workloads while a eDP 4K panel is attached. - * - * Manually exiting PSR causes the frontbuffer to be updated - * without glitches and the IOMMU errors are also gone but - * this comes at the cost of less time with PSR active. - * - * So using this workaround until this issue is root caused - * and a better fix is found. - */ - intel_psr_exit(intel_dp); - else if (DISPLAY_VER(dev_priv) >= 9) + if (DISPLAY_VER(dev_priv) >= 9) /* * Display WA #0884: skl+ * This documented WA for bxt can be safely applied @@ -1519,8 +1578,7 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) u32 psr_status; mutex_lock(&intel_dp->psr.lock); - if (!intel_dp->psr.enabled || - (intel_dp->psr.enabled && intel_dp->psr.psr2_enabled)) { + if (!intel_dp->psr.enabled || intel_dp->psr.psr2_enabled) { mutex_unlock(&intel_dp->psr.lock); continue; } diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 0491a49ffd50..e3db85e97f4c 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -17,6 +17,7 @@ struct intel_crtc; struct intel_atomic_state; struct intel_plane_state; struct intel_plane; +struct intel_encoder; void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_enable(struct intel_dp *intel_dp, @@ -37,6 +38,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, void intel_psr_init(struct intel_dp *intel_dp); void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state); +void intel_psr_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config); void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index f770d6bcd2c9..e4f91d7a5c60 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -38,6 +38,8 @@ #include "i915_drv.h" #include "intel_atomic.h" #include "intel_connector.h" +#include "intel_crtc.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index acbf4e63b245..4ae9a7455b23 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -43,6 +43,7 @@ #include "i915_trace.h" #include "i915_vgpu.h" #include "intel_atomic_plane.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_frontbuffer.h" #include "intel_sprite.h" diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 71b8edafb1c3..e325463acddd 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -28,7 +28,7 @@ tc_cold_get_power_domain(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - if (IS_DISPLAY_VER(i915, 11)) + if (DISPLAY_VER(i915) == 11) return intel_legacy_aux_to_power_domain(dig_port->aux_ch); else return POWER_DOMAIN_TC_COLD_OFF; @@ -40,7 +40,7 @@ tc_cold_block(struct intel_digital_port *dig_port) struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); enum intel_display_power_domain domain; - if (IS_DISPLAY_VER(i915, 11) && !dig_port->tc_legacy_port) + if (DISPLAY_VER(i915) == 11 && !dig_port->tc_legacy_port) return 0; domain = tc_cold_get_power_domain(dig_port); @@ -71,7 +71,7 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port) struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); bool enabled; - if (IS_DISPLAY_VER(i915, 11) && !dig_port->tc_legacy_port) + if (DISPLAY_VER(i915) == 11 && !dig_port->tc_legacy_port) return; enabled = intel_display_power_is_enabled(i915, @@ -256,8 +256,8 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) return val & DP_PHY_MODE_STATUS_COMPLETED(dig_port->tc_phy_fia_idx); } -static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, - bool enable) +static bool icl_tc_phy_take_ownership(struct intel_digital_port *dig_port, + bool take) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_uncore *uncore = &i915->uncore; @@ -267,20 +267,20 @@ static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia)); if (val == 0xffffffff) { drm_dbg_kms(&i915->drm, - "Port %s: PHY in TCCOLD, can't set safe-mode to %s\n", - dig_port->tc_port_name, enableddisabled(enable)); + "Port %s: PHY in TCCOLD, can't %s ownership\n", + dig_port->tc_port_name, take ? "take" : "release"); return false; } val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx); - if (!enable) + if (take) val |= DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx); intel_uncore_write(uncore, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia), val); - if (enable && wait_for(!icl_tc_phy_status_complete(dig_port), 10)) + if (!take && wait_for(!icl_tc_phy_status_complete(dig_port), 10)) drm_dbg_kms(&i915->drm, "Port %s: PHY complete clear timed out\n", dig_port->tc_port_name); @@ -288,7 +288,7 @@ static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, return true; } -static bool icl_tc_phy_is_in_safe_mode(struct intel_digital_port *dig_port) +static bool icl_tc_phy_is_owned(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_uncore *uncore = &i915->uncore; @@ -303,7 +303,7 @@ static bool icl_tc_phy_is_in_safe_mode(struct intel_digital_port *dig_port) return true; } - return !(val & DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx)); + return val & DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx); } /* @@ -329,7 +329,7 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, goto out_set_tbt_alt_mode; } - if (!icl_tc_phy_set_safe_mode(dig_port, false) && + if (!icl_tc_phy_take_ownership(dig_port, true) && !drm_WARN_ON(&i915->drm, dig_port->tc_legacy_port)) goto out_set_tbt_alt_mode; @@ -348,7 +348,7 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, if (!(tc_port_live_status_mask(dig_port) & BIT(TC_PORT_DP_ALT))) { drm_dbg_kms(&i915->drm, "Port %s: PHY sudden disconnect\n", dig_port->tc_port_name); - goto out_set_safe_mode; + goto out_release_phy; } if (max_lanes < required_lanes) { @@ -356,15 +356,15 @@ static void icl_tc_phy_connect(struct intel_digital_port *dig_port, "Port %s: PHY max lanes %d < required lanes %d\n", dig_port->tc_port_name, max_lanes, required_lanes); - goto out_set_safe_mode; + goto out_release_phy; } dig_port->tc_mode = TC_PORT_DP_ALT; return; -out_set_safe_mode: - icl_tc_phy_set_safe_mode(dig_port, true); +out_release_phy: + icl_tc_phy_take_ownership(dig_port, false); out_set_tbt_alt_mode: dig_port->tc_mode = TC_PORT_TBT_ALT; } @@ -380,7 +380,7 @@ static void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) /* Nothing to do, we never disconnect from legacy mode */ break; case TC_PORT_DP_ALT: - icl_tc_phy_set_safe_mode(dig_port, true); + icl_tc_phy_take_ownership(dig_port, false); dig_port->tc_mode = TC_PORT_TBT_ALT; break; case TC_PORT_TBT_ALT: @@ -401,8 +401,8 @@ static bool icl_tc_phy_is_connected(struct intel_digital_port *dig_port) return dig_port->tc_mode == TC_PORT_TBT_ALT; } - if (icl_tc_phy_is_in_safe_mode(dig_port)) { - drm_dbg_kms(&i915->drm, "Port %s: PHY still in safe mode\n", + if (!icl_tc_phy_is_owned(dig_port)) { + drm_dbg_kms(&i915->drm, "Port %s: PHY not owned\n", dig_port->tc_port_name); return false; @@ -417,10 +417,9 @@ intel_tc_port_get_current_mode(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); u32 live_status_mask = tc_port_live_status_mask(dig_port); - bool in_safe_mode = icl_tc_phy_is_in_safe_mode(dig_port); enum tc_port_mode mode; - if (in_safe_mode || + if (!icl_tc_phy_is_owned(dig_port) || drm_WARN_ON(&i915->drm, !icl_tc_phy_status_complete(dig_port))) return TC_PORT_TBT_ALT; @@ -625,6 +624,10 @@ tc_has_modular_fia(struct drm_i915_private *i915, struct intel_digital_port *dig if (!INTEL_INFO(i915)->display.has_modular_fia) return false; + /* TODO: check if in real HW MODULAR_FIA_MASK is set, if so remove this block */ + if (IS_ALDERLAKE_P(i915)) + return true; + wakeref = tc_cold_block(dig_port); val = intel_uncore_read(&i915->uncore, PORT_TX_DFLEXDPSP(FIA1)); tc_cold_unblock(dig_port, wakeref); diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index e558f121ec4e..ce73ebdfc669 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -36,6 +36,7 @@ #include "i915_drv.h" #include "intel_connector.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_hotplug.h" #include "intel_tv.h" @@ -1165,7 +1166,7 @@ intel_tv_get_config(struct intel_encoder *encoder, static bool intel_tv_source_too_wide(struct drm_i915_private *dev_priv, int hdisplay) { - return IS_DISPLAY_VER(dev_priv, 3) && hdisplay > 1024; + return DISPLAY_VER(dev_priv) == 3 && hdisplay > 1024; } static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode, @@ -1789,7 +1790,7 @@ intel_tv_get_modes(struct drm_connector *connector) continue; /* no vertical scaling with wide sources on gen3 */ - if (IS_DISPLAY_VER(dev_priv, 3) && input->w > 1024 && + if (DISPLAY_VER(dev_priv) == 3 && input->w > 1024 && input->h > intel_tv_mode_vdisplay(tv_mode)) continue; @@ -1978,7 +1979,7 @@ intel_tv_init(struct drm_i915_private *dev_priv) /* Create TV properties then attach current values */ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { /* 1080p50/1080p60 not supported on gen3 */ - if (IS_DISPLAY_VER(dev_priv, 3) && + if (DISPLAY_VER(dev_priv) == 3 && tv_modes[i].oversample == 1) break; diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 3a21c65ffa85..efc3184d8315 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -7,6 +7,7 @@ */ #include "i915_drv.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dsi.h" #include "intel_vdsc.h" @@ -469,13 +470,13 @@ intel_dsc_power_domain(const struct intel_crtc_state *crtc_state) * POWER_DOMAIN_TRANSCODER_VDSC_PW2 power domain in two cases: * * - ICL eDP/DSI transcoder - * - Gen12+ (except RKL) pipe A + * - Display version 12 (except RKL) pipe A * * For any other pipe, VDSC/joining uses the power well associated with * the pipe in use. Hence another reference on the pipe power domain * will suffice. (Except no VDSC/joining on ICL pipe A.) */ - if (DISPLAY_VER(i915) >= 12 && !IS_ROCKETLAKE(i915) && pipe == PIPE_A) + if (DISPLAY_VER(i915) == 12 && !IS_ROCKETLAKE(i915) && pipe == PIPE_A) return POWER_DOMAIN_TRANSCODER_VDSC_PW2; else if (is_pipe_dsc(crtc_state)) return POWER_DOMAIN_PIPE(pipe); @@ -1020,6 +1021,22 @@ static i915_reg_t dss_ctl2_reg(const struct intel_crtc_state *crtc_state) return is_pipe_dsc(crtc_state) ? ICL_PIPE_DSS_CTL2(pipe) : DSS_CTL2; } +void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + u32 dss_ctl1_val = 0; + + if (crtc_state->bigjoiner && !crtc_state->dsc.compression_enable) { + if (crtc_state->bigjoiner_slave) + dss_ctl1_val |= UNCOMPRESSED_JOINER_SLAVE; + else + dss_ctl1_val |= UNCOMPRESSED_JOINER_MASTER; + + intel_de_write(dev_priv, dss_ctl1_reg(crtc_state), dss_ctl1_val); + } +} + void intel_dsc_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1059,13 +1076,35 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - if (!old_crtc_state->dsc.compression_enable) + if (!(old_crtc_state->dsc.compression_enable && + old_crtc_state->bigjoiner)) return; intel_de_write(dev_priv, dss_ctl1_reg(old_crtc_state), 0); intel_de_write(dev_priv, dss_ctl2_reg(old_crtc_state), 0); } +void intel_uncompressed_joiner_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + u32 dss_ctl1; + + dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc_state)); + if (dss_ctl1 & UNCOMPRESSED_JOINER_MASTER) { + crtc_state->bigjoiner = true; + if (!WARN_ON(INTEL_NUM_PIPES(dev_priv) == crtc->pipe + 1)) + crtc_state->bigjoiner_linked_crtc = + intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1); + } else if (dss_ctl1 & UNCOMPRESSED_JOINER_SLAVE) { + crtc_state->bigjoiner = true; + crtc_state->bigjoiner_slave = true; + if (!WARN_ON(crtc->pipe == PIPE_A)) + crtc_state->bigjoiner_linked_crtc = + intel_get_crtc_for_pipe(dev_priv, crtc->pipe - 1); + } +} + void intel_dsc_get_config(struct intel_crtc_state *crtc_state) { struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h index 65d301c23580..fe4d45561253 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc.h @@ -12,11 +12,13 @@ struct intel_encoder; struct intel_crtc_state; bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state); +void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state); void intel_dsc_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_dsc_disable(const struct intel_crtc_state *crtc_state); int intel_dsc_compute_params(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config); +void intel_uncompressed_joiner_get_config(struct intel_crtc_state *crtc_state); void intel_dsc_get_config(struct intel_crtc_state *crtc_state); enum intel_display_power_domain intel_dsc_power_domain(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index a9c2b2fd9252..046210ae1de0 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -5,6 +5,7 @@ */ #include "i915_drv.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_vrr.h" diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 17a98cb627df..394b7bbf48d8 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -2,6 +2,7 @@ /* * Copyright © 2020 Intel Corporation */ +#include "intel_de.h" #include "intel_display_types.h" #include "skl_scaler.h" #include "skl_universal_plane.h" diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 7ffd7b570b54..59e032f3687a 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -10,6 +10,7 @@ #include "i915_drv.h" #include "intel_atomic_plane.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_fb.h" #include "intel_pm.h" @@ -198,6 +199,13 @@ static const u64 gen12_plane_format_modifiers_rc_ccs[] = { DRM_FORMAT_MOD_INVALID }; +static const u64 adlp_step_a_plane_format_modifiers[] = { + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) { switch (format) { @@ -267,7 +275,7 @@ int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915) { - if (HAS_D12_PLANE_MINIMIZATION(i915)) + if (DISPLAY_VER(i915) >= 13 || HAS_D12_PLANE_MINIMIZATION(i915)) return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3); else return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5); @@ -286,40 +294,64 @@ bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) icl_hdr_plane_mask() & BIT(plane_id); } +static int icl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); + + /* two pixels per clock */ + return DIV_ROUND_UP(pixel_rate, 2); +} + static void -skl_plane_ratio(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, +glk_plane_ratio(const struct intel_plane_state *plane_state, unsigned int *num, unsigned int *den) { - struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; if (fb->format->cpp[0] == 8) { - if (DISPLAY_VER(dev_priv) >= 10) { - *num = 10; - *den = 8; - } else { - *num = 9; - *den = 8; - } + *num = 10; + *den = 8; } else { *num = 1; *den = 1; } } -static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, +static int glk_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); - unsigned int num, den; unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); + unsigned int num, den; - skl_plane_ratio(crtc_state, plane_state, &num, &den); + glk_plane_ratio(plane_state, &num, &den); - /* two pixels per clock on glk+ */ - if (DISPLAY_VER(dev_priv) >= 10) - den *= 2; + /* two pixels per clock */ + return DIV_ROUND_UP(pixel_rate * num, 2 * den); +} + +static void +skl_plane_ratio(const struct intel_plane_state *plane_state, + unsigned int *num, unsigned int *den) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + + if (fb->format->cpp[0] == 8) { + *num = 9; + *den = 8; + } else { + *num = 1; + *den = 1; + } +} + +static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); + unsigned int num, den; + + skl_plane_ratio(plane_state, &num, &den); return DIV_ROUND_UP(pixel_rate * num, den); } @@ -457,17 +489,35 @@ skl_plane_max_stride(struct intel_plane *plane, u32 pixel_format, u64 modifier, unsigned int rotation) { + struct drm_i915_private *i915 = to_i915(plane->base.dev); const struct drm_format_info *info = drm_format_info(pixel_format); int cpp = info->cpp[0]; + int max_horizontal_pixels = 8192; + int max_stride_bytes; + + if (DISPLAY_VER(i915) >= 13) { + /* + * The stride in bytes must not exceed of the size + * of 128K bytes. For pixel formats of 64bpp will allow + * for a 16K pixel surface. + */ + max_stride_bytes = 131072; + if (cpp == 8) + max_horizontal_pixels = 16384; + else + max_horizontal_pixels = 65536; + } else { + /* + * "The stride in bytes must not exceed the + * of the size of 8K pixels and 32K bytes." + */ + max_stride_bytes = 32768; + } - /* - * "The stride in bytes must not exceed the - * of the size of 8K pixels and 32K bytes." - */ if (drm_rotation_90_or_270(rotation)) - return min(8192, 32768 / cpp); + return min(max_horizontal_pixels, max_stride_bytes / cpp); else - return min(8192 * cpp, 32768); + return min(max_horizontal_pixels * cpp, max_stride_bytes); } @@ -829,7 +879,7 @@ static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, plane_ctl = PLANE_CTL_ENABLE; - if (DISPLAY_VER(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { + if (DISPLAY_VER(dev_priv) < 10) { plane_ctl |= skl_plane_ctl_alpha(plane_state); plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; @@ -909,6 +959,21 @@ static u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, return plane_color_ctl; } +static u32 skl_surf_address(const struct intel_plane_state *plane_state, + int color_plane) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + u32 offset = plane_state->view.color_plane[color_plane].offset; + + if (intel_fb_uses_dpt(fb)) { + WARN_ON(offset & 0x1fffff); + return offset >> 9; + } else { + WARN_ON(offset & 0xfff); + return offset; + } +} + static void skl_program_plane(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -919,7 +984,7 @@ skl_program_plane(struct intel_plane *plane, enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 surf_addr = plane_state->view.color_plane[color_plane].offset; + u32 surf_addr = skl_surf_address(plane_state, color_plane); u32 stride = skl_plane_stride(plane_state, color_plane); const struct drm_framebuffer *fb = plane_state->hw.fb; int aux_plane = skl_main_to_aux_plane(fb, color_plane); @@ -958,7 +1023,7 @@ skl_program_plane(struct intel_plane *plane, } if (aux_plane) { - aux_dist = plane_state->view.color_plane[aux_plane].offset - surf_addr; + aux_dist = skl_surf_address(plane_state, aux_plane) - surf_addr; if (DISPLAY_VER(dev_priv) < 12) aux_dist |= skl_plane_stride(plane_state, aux_plane); @@ -1008,6 +1073,14 @@ skl_program_plane(struct intel_plane *plane, intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); /* + * Enable the scaler before the plane so that we don't + * get a catastrophic underrun even if the two operations + * end up happening in two different frames. + */ + if (plane_state->scaler_id >= 0) + skl_program_plane_scaler(plane, crtc_state, plane_state); + + /* * The control register self-arms if the plane was previously * disabled. Try to make the plane enable atomic by writing * the control register just before the surface register. @@ -1016,9 +1089,6 @@ skl_program_plane(struct intel_plane *plane, intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), intel_plane_ggtt_offset(plane_state) + surf_addr); - if (plane_state->scaler_id >= 0) - skl_program_plane_scaler(plane, crtc_state, plane_state); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } @@ -1082,7 +1152,6 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, struct drm_i915_private *dev_priv = to_i915(plane->base.dev); const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int rotation = plane_state->hw.rotation; - struct drm_format_name_buf format_name; if (!fb) return 0; @@ -1103,8 +1172,7 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, } if (drm_rotation_90_or_270(rotation)) { - if (fb->modifier != I915_FORMAT_MOD_Y_TILED && - fb->modifier != I915_FORMAT_MOD_Yf_TILED) { + if (!intel_fb_supports_90_270_rotation(to_intel_framebuffer(fb))) { drm_dbg_kms(&dev_priv->drm, "Y/Yf tiling required for 90/270!\n"); return -EINVAL; @@ -1130,9 +1198,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, case DRM_FORMAT_XVYU12_16161616: case DRM_FORMAT_XVYU16161616: drm_dbg_kms(&dev_priv->drm, - "Unsupported pixel format %s for 90/270!\n", - drm_get_format_name(fb->format->format, - &format_name)); + "Unsupported pixel format %p4cc for 90/270!\n", + &fb->format->format); return -EINVAL; default: break; @@ -1184,7 +1251,7 @@ static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_s * than the cursor ending less than 4 pixels from the left edge of the * screen may cause FIFO underflow and display corruption. */ - if (IS_DISPLAY_VER(dev_priv, 10) && + if (DISPLAY_VER(dev_priv) == 10 && (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) { drm_dbg_kms(&dev_priv->drm, "requested plane X %s position %d invalid (valid range %d-%d)\n", @@ -1412,7 +1479,10 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) } } - drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191); + if (DISPLAY_VER(dev_priv) >= 13) + drm_WARN_ON(&dev_priv->drm, x > 65535 || y > 65535); + else + drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191); plane_state->view.color_plane[0].offset = offset; plane_state->view.color_plane[0].x = x; @@ -1486,7 +1556,10 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) } } - drm_WARN_ON(&i915->drm, x > 8191 || y > 8191); + if (DISPLAY_VER(i915) >= 13) + drm_WARN_ON(&i915->drm, x > 65535 || y > 65535); + else + drm_WARN_ON(&i915->drm, x > 8191 || y > 8191); plane_state->view.color_plane[uv_plane].offset = offset; plane_state->view.color_plane[uv_plane].x = x; @@ -1671,7 +1744,7 @@ static bool skl_plane_has_planar(struct drm_i915_private *dev_priv, if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) return false; - if (IS_DISPLAY_VER(dev_priv, 9) && pipe == PIPE_C) + if (DISPLAY_VER(dev_priv) == 9 && pipe == PIPE_C) return false; if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) @@ -1813,6 +1886,10 @@ static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_C0)) return false; + /* Wa_22011186057 */ + if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_A0)) + return false; + return plane_id < PLANE_SPRITE4; } @@ -1830,8 +1907,12 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, case DRM_FORMAT_MOD_LINEAR: case I915_FORMAT_MOD_X_TILED: case I915_FORMAT_MOD_Y_TILED: + break; case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: + /* Wa_22011186057 */ + if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_A0)) + return false; break; default: return false; @@ -1886,7 +1967,10 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, static const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv, enum plane_id plane_id) { - if (gen12_plane_supports_mc_ccs(dev_priv, plane_id)) + /* Wa_22011186057 */ + if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_A0)) + return adlp_step_a_plane_format_modifiers; + else if (gen12_plane_supports_mc_ccs(dev_priv, plane_id)) return gen12_plane_format_modifiers_mc_ccs; else return gen12_plane_format_modifiers_rc_ccs; @@ -1965,12 +2049,15 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv, plane->min_width = icl_plane_min_width; plane->max_width = icl_plane_max_width; plane->max_height = icl_plane_max_height; + plane->min_cdclk = icl_plane_min_cdclk; } else if (DISPLAY_VER(dev_priv) >= 10) { plane->max_width = glk_plane_max_width; plane->max_height = skl_plane_max_height; + plane->min_cdclk = glk_plane_min_cdclk; } else { plane->max_width = skl_plane_max_width; plane->max_height = skl_plane_max_height; + plane->min_cdclk = skl_plane_min_cdclk; } plane->max_stride = skl_plane_max_stride; @@ -1978,11 +2065,10 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv, plane->disable_plane = skl_disable_plane; plane->get_hw_state = skl_plane_get_hw_state; plane->check_plane = skl_plane_check; - plane->min_cdclk = skl_plane_min_cdclk; if (plane_id == PLANE_PRIMARY) { - plane->need_async_flip_disable_wa = IS_DISPLAY_RANGE(dev_priv, - 9, 10); + plane->need_async_flip_disable_wa = IS_DISPLAY_VER(dev_priv, + 9, 10); plane->async_flip = skl_plane_async_flip; plane->enable_flip_done = skl_plane_enable_flip_done; plane->disable_flip_done = skl_plane_disable_flip_done; @@ -2024,9 +2110,12 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv, if (ret) goto fail; - supported_rotations = - DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | - DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; + if (DISPLAY_VER(dev_priv) >= 13) + supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180; + else + supported_rotations = + DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; if (DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) supported_rotations |= DRM_MODE_REFLECT_X; @@ -2197,7 +2286,11 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id)); stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0); - fb->pitches[0] = (val & 0x3ff) * stride_mult; + + if (DISPLAY_VER(dev_priv) >= 13) + fb->pitches[0] = (val & PLANE_STRIDE_MASK_XELPD) * stride_mult; + else + fb->pitches[0] = (val & PLANE_STRIDE_MASK) * stride_mult; aligned_height = intel_fb_align_height(fb, 0, fb->height); @@ -2215,4 +2308,3 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, error: kfree(intel_fb); } - diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 1059a26c1f58..084c9c43b2ed 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -33,6 +33,8 @@ #include "i915_drv.h" #include "intel_atomic.h" #include "intel_connector.h" +#include "intel_crtc.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dsi.h" #include "intel_fifo_underrun.h" @@ -297,7 +299,7 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder, else pipe_config->pipe_bpp = 18; - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { /* Enable Frame time stamp based scanline reporting */ pipe_config->mode_flags |= I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP; @@ -522,7 +524,7 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) if (IS_GEMINILAKE(dev_priv)) glk_dsi_device_ready(encoder); - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_dsi_device_ready(encoder); else vlv_dsi_device_ready(encoder); @@ -601,7 +603,7 @@ static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) drm_dbg_kms(&dev_priv->drm, "\n"); for_each_dsi_port(port, intel_dsi->ports) { /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */ - i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ? + i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A); u32 val; @@ -621,7 +623,7 @@ static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) * On VLV/CHV, wait till Clock lanes are in LP-00 state for MIPI * Port A only. MIPI Port C has no similar bit for checking. */ - if ((IS_GEN9_LP(dev_priv) || port == PORT_A) && + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) || port == PORT_A) && intel_de_wait_for_clear(dev_priv, port_ctrl, AFE_LATCHOUT, 30)) drm_err(&dev_priv->drm, "DSI LP not going Low\n"); @@ -646,7 +648,7 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder, if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { u32 temp; - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { for_each_dsi_port(port, intel_dsi->ports) { temp = intel_de_read(dev_priv, MIPI_CTRL(port)); @@ -666,7 +668,7 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder, } for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ? + i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); u32 temp; @@ -703,7 +705,7 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) enum port port; for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ? + i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); u32 temp; @@ -714,6 +716,19 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) } } +static void intel_dsi_wait_panel_power_cycle(struct intel_dsi *intel_dsi) +{ + ktime_t panel_power_on_time; + s64 panel_power_off_duration; + + panel_power_on_time = ktime_get_boottime(); + panel_power_off_duration = ktime_ms_delta(panel_power_on_time, + intel_dsi->panel_power_off_time); + + if (panel_power_off_duration < (s64)intel_dsi->panel_pwr_cycle_delay) + msleep(intel_dsi->panel_pwr_cycle_delay - panel_power_off_duration); +} + static void intel_dsi_prepare(struct intel_encoder *intel_encoder, const struct intel_crtc_state *pipe_config); static void intel_dsi_unprepare(struct intel_encoder *encoder); @@ -775,13 +790,15 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, drm_dbg_kms(&dev_priv->drm, "\n"); + intel_dsi_wait_panel_power_cycle(intel_dsi); + intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); /* * The BIOS may leave the PLL in a wonky state where it doesn't * lock. It needs to be fully powered down to fix it. */ - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { bxt_dsi_pll_disable(encoder); bxt_dsi_pll_enable(encoder, pipe_config); } else { @@ -846,8 +863,10 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, /* Send initialization commands in LP mode */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); - /* Enable port in pre-enable phase itself because as per hw team - * recommendation, port should be enabled befor plane & pipe */ + /* + * Enable port in pre-enable phase itself because as per hw team + * recommendation, port should be enabled before plane & pipe + */ if (is_cmd_mode(intel_dsi)) { for_each_dsi_port(port, intel_dsi->ports) intel_de_write(dev_priv, @@ -932,7 +951,7 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state, drm_dbg_kms(&dev_priv->drm, "\n"); - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { intel_crtc_vblank_off(old_crtc_state); skl_scaler_disable(old_crtc_state); @@ -971,7 +990,7 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state, val & ~MIPIO_RST_CTRL); } - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { bxt_dsi_pll_disable(encoder); } else { u32 val; @@ -989,18 +1008,14 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state, intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF); - /* - * FIXME As we do with eDP, just make a note of the time here - * and perform the wait before the next panel power on. - */ - intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay); + intel_dsi->panel_power_off_time = ktime_get_boottime(); } static void intel_dsi_shutdown(struct intel_encoder *encoder) { struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); - intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay); + intel_dsi_wait_panel_power_cycle(intel_dsi); } static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, @@ -1024,12 +1039,13 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, * configuration, otherwise accessing DSI registers will hang the * machine. See BSpec North Display Engine registers/MIPI[BXT]. */ - if (IS_GEN9_LP(dev_priv) && !bxt_dsi_pll_is_enabled(dev_priv)) + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + !bxt_dsi_pll_is_enabled(dev_priv)) goto out_put_power; /* XXX: this only works for one DSI output */ for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t ctrl_reg = IS_GEN9_LP(dev_priv) ? + i915_reg_t ctrl_reg = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); bool enabled = intel_de_read(dev_priv, ctrl_reg) & DPI_ENABLE; @@ -1055,7 +1071,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, if (!(intel_de_read(dev_priv, MIPI_DEVICE_READY(port)) & DEVICE_READY)) continue; - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { u32 tmp = intel_de_read(dev_priv, MIPI_CTRL(port)); tmp &= BXT_PIPE_SELECT_MASK; tmp >>= BXT_PIPE_SELECT_SHIFT; @@ -1251,7 +1267,7 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { bxt_dsi_get_pipe_config(encoder, pipe_config); pclk = bxt_dsi_get_pclk(encoder, pipe_config); } else { @@ -1317,7 +1333,7 @@ static void set_dsi_timings(struct drm_encoder *encoder, hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); for_each_dsi_port(port, intel_dsi->ports) { - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { /* * Program hdisplay and vdisplay on MIPI transcoder. * This is different from calculated hactive and @@ -1407,7 +1423,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder, tmp &= ~READ_REQUEST_PRIORITY_MASK; intel_de_write(dev_priv, MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH); - } else if (IS_GEN9_LP(dev_priv)) { + } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { enum pipe pipe = intel_crtc->pipe; tmp = intel_de_read(dev_priv, MIPI_CTRL(port)); @@ -1445,7 +1461,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder, if (intel_dsi->clock_stop) tmp |= CLOCKSTOP; - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { tmp |= BXT_DPHY_DEFEATURE_EN; if (!is_cmd_mode(intel_dsi)) tmp |= BXT_DEFEATURE_DPI_FIFO_CTR; @@ -1492,7 +1508,8 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder, intel_de_write(dev_priv, MIPI_INIT_COUNT(port), txclkesc(intel_dsi->escape_clk_div, 100)); - if (IS_GEN9_LP(dev_priv) && (!intel_dsi->dual_link)) { + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + !intel_dsi->dual_link) { /* * BXT spec says write MIPI_INIT_COUNT for * both the ports, even if only one is @@ -1570,7 +1587,7 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder) /* Panel commands can be sent when clock is in LP11 */ intel_de_write(dev_priv, MIPI_DEVICE_READY(port), 0x0); - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) bxt_dsi_reset_clocks(encoder, port); else vlv_dsi_reset_clocks(encoder, port); @@ -1828,7 +1845,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) if (!intel_bios_is_dsi_present(dev_priv, &port)) return; - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) dev_priv->mipi_mmio_base = BXT_MIPI_BASE; else dev_priv->mipi_mmio_base = VLV_MIPI_BASE; @@ -1854,7 +1871,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) intel_encoder->compute_config = intel_dsi_compute_config; intel_encoder->pre_enable = intel_dsi_pre_enable; - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) intel_encoder->enable = bxt_dsi_enable; intel_encoder->disable = intel_dsi_disable; intel_encoder->post_disable = intel_dsi_post_disable; @@ -1874,13 +1891,15 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) * On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI * port C. BXT isn't limited like this. */ - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) intel_encoder->pipe_mask = ~0; else if (port == PORT_A) intel_encoder->pipe_mask = BIT(PIPE_A); else intel_encoder->pipe_mask = BIT(PIPE_B); + intel_dsi->panel_power_off_time = ktime_get_boottime(); + if (dev_priv->vbt.dsi.config->dual_link) intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C); else diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c index 4070b00c3690..90185b219447 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include "i915_drv.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dsi.h" #include "intel_sideband.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 5964e67c7d36..297143511f99 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -274,7 +274,7 @@ struct i915_execbuffer { struct drm_mm_node node; /** temporary GTT binding */ unsigned long vaddr; /** Current kmap address */ unsigned long page; /** Currently mapped page index */ - unsigned int gen; /** Cached value of INTEL_GEN */ + unsigned int graphics_ver; /** Cached value of GRAPHICS_VER */ bool use_64bit_reloc : 1; bool has_llc : 1; bool has_fence : 1; @@ -1049,10 +1049,10 @@ static void reloc_cache_init(struct reloc_cache *cache, cache->page = -1; cache->vaddr = 0; /* Must be a variable in the struct to allow GCC to unroll. */ - cache->gen = INTEL_GEN(i915); + cache->graphics_ver = GRAPHICS_VER(i915); cache->has_llc = HAS_LLC(i915); cache->use_64bit_reloc = HAS_64BIT_RELOC(i915); - cache->has_fence = cache->gen < 4; + cache->has_fence = cache->graphics_ver < 4; cache->needs_unfenced = INTEL_INFO(i915)->unfenced_needs_alignment; cache->node.flags = 0; reloc_cache_clear(cache); @@ -1402,7 +1402,7 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, err = eb->engine->emit_bb_start(rq, batch->node.start, PAGE_SIZE, - cache->gen > 5 ? 0 : I915_DISPATCH_SECURE); + cache->graphics_ver > 5 ? 0 : I915_DISPATCH_SECURE); if (err) goto skip_request; @@ -1503,14 +1503,14 @@ static int __reloc_entry_gpu(struct i915_execbuffer *eb, u64 offset, u64 target_addr) { - const unsigned int gen = eb->reloc_cache.gen; + const unsigned int ver = eb->reloc_cache.graphics_ver; unsigned int len; u32 *batch; u64 addr; - if (gen >= 8) + if (ver >= 8) len = offset & 7 ? 8 : 5; - else if (gen >= 4) + else if (ver >= 4) len = 4; else len = 3; @@ -1522,7 +1522,7 @@ static int __reloc_entry_gpu(struct i915_execbuffer *eb, return false; addr = gen8_canonical_addr(vma->node.start + offset); - if (gen >= 8) { + if (ver >= 8) { if (offset & 7) { *batch++ = MI_STORE_DWORD_IMM_GEN4; *batch++ = lower_32_bits(addr); @@ -1542,7 +1542,7 @@ static int __reloc_entry_gpu(struct i915_execbuffer *eb, *batch++ = lower_32_bits(target_addr); *batch++ = upper_32_bits(target_addr); } - } else if (gen >= 6) { + } else if (ver >= 6) { *batch++ = MI_STORE_DWORD_IMM_GEN4; *batch++ = 0; *batch++ = addr; @@ -1552,12 +1552,12 @@ static int __reloc_entry_gpu(struct i915_execbuffer *eb, *batch++ = 0; *batch++ = vma_phys_addr(vma, offset); *batch++ = target_addr; - } else if (gen >= 4) { + } else if (ver >= 4) { *batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT; *batch++ = 0; *batch++ = addr; *batch++ = target_addr; - } else if (gen >= 3 && + } else if (ver >= 3 && !(IS_I915G(eb->i915) || IS_I915GM(eb->i915))) { *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; *batch++ = addr; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c index 21cc40897ca8..ce6b664b10aa 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -42,7 +42,7 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) max_order = MAX_ORDER; #ifdef CONFIG_SWIOTLB - if (swiotlb_nr_tbl()) { + if (is_swiotlb_active()) { unsigned int max_segment; max_segment = swiotlb_max_segment(); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 2561a2f1e54f..f6fe5cb01438 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -189,7 +189,7 @@ compute_partial_view(const struct drm_i915_gem_object *obj, struct i915_ggtt_view view; if (i915_gem_object_is_tiled(obj)) - chunk = roundup(chunk, tile_row_pages(obj)); + chunk = roundup(chunk, tile_row_pages(obj) ?: 1); view.type = I915_GGTT_VIEW_PARTIAL; view.partial.offset = rounddown(page_offset, chunk); @@ -367,11 +367,10 @@ retry: goto err_unpin; /* Finally, remap it using the new GTT offset */ - ret = remap_io_mapping(area, - area->vm_start + (vma->ggtt_view.partial.offset << PAGE_SHIFT), - (ggtt->gmadr.start + vma->node.start) >> PAGE_SHIFT, - min_t(u64, vma->size, area->vm_end - area->vm_start), - &ggtt->iomap); + ret = io_mapping_map_user(&ggtt->iomap, area, area->vm_start + + (vma->ggtt_view.partial.offset << PAGE_SHIFT), + (ggtt->gmadr.start + vma->node.start) >> PAGE_SHIFT, + min_t(u64, vma->size, area->vm_end - area->vm_start)); if (ret) goto err_fence; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c index 3e248d3bd869..4f9c8d3021ab 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c @@ -70,6 +70,7 @@ static void try_to_writeback(struct drm_i915_gem_object *obj, /** * i915_gem_shrink - Shrink buffer object caches + * @ww: i915 gem ww acquire ctx, or NULL * @i915: i915 device * @target: amount of memory to make available, in pages * @nr_scanned: optional output for number of pages scanned (incremental) diff --git a/drivers/gpu/drm/i915/gt/gen7_renderclear.c b/drivers/gpu/drm/i915/gt/gen7_renderclear.c index de575fdb033f..21f08e53889c 100644 --- a/drivers/gpu/drm/i915/gt/gen7_renderclear.c +++ b/drivers/gpu/drm/i915/gt/gen7_renderclear.c @@ -397,7 +397,10 @@ static void emit_batch(struct i915_vma * const vma, gen7_emit_pipeline_invalidate(&cmds); batch_add(&cmds, MI_LOAD_REGISTER_IMM(2)); batch_add(&cmds, i915_mmio_reg_offset(CACHE_MODE_0_GEN7)); - batch_add(&cmds, 0xffff0000); + batch_add(&cmds, 0xffff0000 | + ((IS_IVB_GT1(i915) || IS_VALLEYVIEW(i915)) ? + HIZ_RAW_STALL_OPT_DISABLE : + 0)); batch_add(&cmds, i915_mmio_reg_offset(CACHE_MODE_1)); batch_add(&cmds, 0xffff0000 | PIXEL_SUBSPAN_COLLECT_OPT_DISABLE); gen7_emit_pipeline_invalidate(&cmds); diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 176c19633412..74bf6fc8461f 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -641,7 +641,6 @@ static int gen8_preallocate_top_level_pdp(struct i915_ppgtt *ppgtt) err = pin_pt_dma(vm, pde->pt.base); if (err) { - i915_gem_object_put(pde->pt.base); free_pd(vm, pde); return err; } diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.h b/drivers/gpu/drm/i915/gt/gen8_ppgtt.h index 76a08b9c1f5c..b9028c2ad3c7 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.h +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.h @@ -6,8 +6,15 @@ #ifndef __GEN8_PPGTT_H__ #define __GEN8_PPGTT_H__ +#include <linux/kernel.h> + +struct i915_address_space; struct intel_gt; +enum i915_cache_level; struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt); +u64 gen8_ggtt_pte_encode(dma_addr_t addr, + enum i915_cache_level level, + u32 flags); #endif diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index efe935f80c1a..6dbdbde00f14 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -45,9 +45,9 @@ struct engine_info { unsigned int hw_id; u8 class; u8 instance; - /* mmio bases table *must* be sorted in reverse gen order */ + /* mmio bases table *must* be sorted in reverse graphics_ver order */ struct engine_mmio_base { - u32 gen : 8; + u32 graphics_ver : 8; u32 base : 24; } mmio_bases[MAX_MMIO_BASES]; }; @@ -58,7 +58,7 @@ static const struct engine_info intel_engines[] = { .class = RENDER_CLASS, .instance = 0, .mmio_bases = { - { .gen = 1, .base = RENDER_RING_BASE } + { .graphics_ver = 1, .base = RENDER_RING_BASE } }, }, [BCS0] = { @@ -66,7 +66,7 @@ static const struct engine_info intel_engines[] = { .class = COPY_ENGINE_CLASS, .instance = 0, .mmio_bases = { - { .gen = 6, .base = BLT_RING_BASE } + { .graphics_ver = 6, .base = BLT_RING_BASE } }, }, [VCS0] = { @@ -74,9 +74,9 @@ static const struct engine_info intel_engines[] = { .class = VIDEO_DECODE_CLASS, .instance = 0, .mmio_bases = { - { .gen = 11, .base = GEN11_BSD_RING_BASE }, - { .gen = 6, .base = GEN6_BSD_RING_BASE }, - { .gen = 4, .base = BSD_RING_BASE } + { .graphics_ver = 11, .base = GEN11_BSD_RING_BASE }, + { .graphics_ver = 6, .base = GEN6_BSD_RING_BASE }, + { .graphics_ver = 4, .base = BSD_RING_BASE } }, }, [VCS1] = { @@ -84,8 +84,8 @@ static const struct engine_info intel_engines[] = { .class = VIDEO_DECODE_CLASS, .instance = 1, .mmio_bases = { - { .gen = 11, .base = GEN11_BSD2_RING_BASE }, - { .gen = 8, .base = GEN8_BSD2_RING_BASE } + { .graphics_ver = 11, .base = GEN11_BSD2_RING_BASE }, + { .graphics_ver = 8, .base = GEN8_BSD2_RING_BASE } }, }, [VCS2] = { @@ -93,7 +93,7 @@ static const struct engine_info intel_engines[] = { .class = VIDEO_DECODE_CLASS, .instance = 2, .mmio_bases = { - { .gen = 11, .base = GEN11_BSD3_RING_BASE } + { .graphics_ver = 11, .base = GEN11_BSD3_RING_BASE } }, }, [VCS3] = { @@ -101,7 +101,7 @@ static const struct engine_info intel_engines[] = { .class = VIDEO_DECODE_CLASS, .instance = 3, .mmio_bases = { - { .gen = 11, .base = GEN11_BSD4_RING_BASE } + { .graphics_ver = 11, .base = GEN11_BSD4_RING_BASE } }, }, [VECS0] = { @@ -109,8 +109,8 @@ static const struct engine_info intel_engines[] = { .class = VIDEO_ENHANCEMENT_CLASS, .instance = 0, .mmio_bases = { - { .gen = 11, .base = GEN11_VEBOX_RING_BASE }, - { .gen = 7, .base = VEBOX_RING_BASE } + { .graphics_ver = 11, .base = GEN11_VEBOX_RING_BASE }, + { .graphics_ver = 7, .base = VEBOX_RING_BASE } }, }, [VECS1] = { @@ -118,7 +118,7 @@ static const struct engine_info intel_engines[] = { .class = VIDEO_ENHANCEMENT_CLASS, .instance = 1, .mmio_bases = { - { .gen = 11, .base = GEN11_VEBOX2_RING_BASE } + { .graphics_ver = 11, .base = GEN11_VEBOX2_RING_BASE } }, }, }; @@ -146,9 +146,9 @@ u32 intel_engine_context_size(struct intel_gt *gt, u8 class) switch (class) { case RENDER_CLASS: - switch (INTEL_GEN(gt->i915)) { + switch (GRAPHICS_VER(gt->i915)) { default: - MISSING_CASE(INTEL_GEN(gt->i915)); + MISSING_CASE(GRAPHICS_VER(gt->i915)); return DEFAULT_LR_CONTEXT_RENDER_SIZE; case 12: case 11: @@ -184,8 +184,8 @@ u32 intel_engine_context_size(struct intel_gt *gt, u8 class) */ cxt_size = intel_uncore_read(uncore, CXT_SIZE) + 1; drm_dbg(>->i915->drm, - "gen%d CXT_SIZE = %d bytes [0x%08x]\n", - INTEL_GEN(gt->i915), cxt_size * 64, + "graphics_ver = %d CXT_SIZE = %d bytes [0x%08x]\n", + GRAPHICS_VER(gt->i915), cxt_size * 64, cxt_size - 1); return round_up(cxt_size * 64, PAGE_SIZE); case 3: @@ -201,7 +201,7 @@ u32 intel_engine_context_size(struct intel_gt *gt, u8 class) case VIDEO_DECODE_CLASS: case VIDEO_ENHANCEMENT_CLASS: case COPY_ENGINE_CLASS: - if (INTEL_GEN(gt->i915) < 8) + if (GRAPHICS_VER(gt->i915) < 8) return 0; return GEN8_LR_CONTEXT_OTHER_SIZE; } @@ -213,7 +213,7 @@ static u32 __engine_mmio_base(struct drm_i915_private *i915, int i; for (i = 0; i < MAX_MMIO_BASES; i++) - if (INTEL_GEN(i915) >= bases[i].gen) + if (GRAPHICS_VER(i915) >= bases[i].graphics_ver) break; GEM_BUG_ON(i == MAX_MMIO_BASES); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c index 1cbd84eb24e4..3cca7ea2d6ea 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_user.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c @@ -48,7 +48,8 @@ static const u8 uabi_classes[] = { [VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE, }; -static int engine_cmp(void *priv, struct list_head *A, struct list_head *B) +static int engine_cmp(void *priv, const struct list_head *A, + const struct list_head *B) { const struct intel_engine_cs *a = container_of((struct rb_node *)A, typeof(*a), uabi_node); diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 670c1271e7d5..38742bf33fa3 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -18,6 +18,7 @@ #include "i915_vgpu.h" #include "intel_gtt.h" +#include "gen8_ppgtt.h" static int i915_get_ggtt_vma_pages(struct i915_vma *vma); @@ -187,9 +188,9 @@ static void gmch_ggtt_invalidate(struct i915_ggtt *ggtt) intel_gtt_chipset_flush(); } -static u64 gen8_ggtt_pte_encode(dma_addr_t addr, - enum i915_cache_level level, - u32 flags) +u64 gen8_ggtt_pte_encode(dma_addr_t addr, + enum i915_cache_level level, + u32 flags) { gen8_pte_t pte = addr | _PAGE_PRESENT; diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c index e72b7a0dc316..8a322594210c 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c @@ -653,8 +653,8 @@ static void detect_bit_6_swizzle(struct i915_ggtt *ggtt) * banks of memory are paired and unswizzled on the * uneven portion, so leave that as unknown. */ - if (intel_uncore_read(uncore, C0DRB3) == - intel_uncore_read(uncore, C1DRB3)) { + if (intel_uncore_read16(uncore, C0DRB3) == + intel_uncore_read16(uncore, C1DRB3)) { swizzle_x = I915_BIT_6_SWIZZLE_9_10; swizzle_y = I915_BIT_6_SWIZZLE_9; } diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index e67e34e17913..79f565aeb8c0 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -245,6 +245,7 @@ struct i915_address_space { struct dma_resv resv; /* reservation lock for all pd objects, and buffer pool */ #define VM_CLASS_GGTT 0 #define VM_CLASS_PPGTT 1 +#define VM_CLASS_DPT 2 struct drm_i915_gem_object *scratch[4]; /** @@ -255,6 +256,9 @@ struct i915_address_space { /* Global GTT */ bool is_ggtt:1; + /* Display page table */ + bool is_dpt:1; + /* Some systems support read-only mappings for GGTT and/or PPGTT */ bool has_read_only:1; @@ -351,6 +355,7 @@ struct i915_ppgtt { }; #define i915_is_ggtt(vm) ((vm)->is_ggtt) +#define i915_is_dpt(vm) ((vm)->is_dpt) int __must_check i915_vm_lock_objects(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww); diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c index be6f2c8f5184..73fceb0c25fc 100644 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@ -177,7 +177,7 @@ static struct intel_memory_region *setup_lmem(struct intel_gt *gt) { struct drm_i915_private *i915 = gt->i915; struct intel_uncore *uncore = gt->uncore; - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); struct intel_memory_region *mem; resource_size_t io_start; resource_size_t lmem_size; diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c index b32814a1f20b..3453eb77c498 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -376,34 +376,34 @@ static int intel_mmio_bases_check(void *arg) u8 prev = U8_MAX; for (j = 0; j < MAX_MMIO_BASES; j++) { - u8 gen = info->mmio_bases[j].gen; + u8 ver = info->mmio_bases[j].graphics_ver; u32 base = info->mmio_bases[j].base; - if (gen >= prev) { - pr_err("%s(%s, class:%d, instance:%d): mmio base for gen %x is before the one for gen %x\n", + if (ver >= prev) { + pr_err("%s(%s, class:%d, instance:%d): mmio base for graphics ver %u is before the one for ver %u\n", __func__, intel_engine_class_repr(info->class), info->class, info->instance, - prev, gen); + prev, ver); return -EINVAL; } - if (gen == 0) + if (ver == 0) break; if (!base) { - pr_err("%s(%s, class:%d, instance:%d): invalid mmio base (%x) for gen %x at entry %u\n", + pr_err("%s(%s, class:%d, instance:%d): invalid mmio base (%x) for graphics ver %u at entry %u\n", __func__, intel_engine_class_repr(info->class), info->class, info->instance, - base, gen, j); + base, ver, j); return -EINVAL; } - prev = gen; + prev = ver; } - pr_debug("%s: min gen supported for %s%d is %d\n", + pr_debug("%s: min graphics version supported for %s%d is %u\n", __func__, intel_engine_class_repr(info->class), info->instance, diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c b/drivers/gpu/drm/i915/gt/selftest_workarounds.c index 19850489a3fc..64937ec3f2dc 100644 --- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c +++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c @@ -927,7 +927,7 @@ err_batch: struct regmask { i915_reg_t reg; - unsigned long gen_mask; + u8 graphics_ver; }; static bool find_reg(struct drm_i915_private *i915, @@ -938,7 +938,7 @@ static bool find_reg(struct drm_i915_private *i915, u32 offset = i915_mmio_reg_offset(reg); while (count--) { - if (INTEL_INFO(i915)->gen_mask & tbl->gen_mask && + if (GRAPHICS_VER(i915) == tbl->graphics_ver && i915_mmio_reg_offset(tbl->reg) == offset) return true; tbl++; @@ -951,8 +951,8 @@ static bool pardon_reg(struct drm_i915_private *i915, i915_reg_t reg) { /* Alas, we must pardon some whitelists. Mistakes already made */ static const struct regmask pardon[] = { - { GEN9_CTX_PREEMPT_REG, INTEL_GEN_MASK(9, 9) }, - { GEN8_L3SQCREG4, INTEL_GEN_MASK(9, 9) }, + { GEN9_CTX_PREEMPT_REG, 9 }, + { GEN8_L3SQCREG4, 9 }, }; return find_reg(i915, reg, pardon, ARRAY_SIZE(pardon)); @@ -974,7 +974,7 @@ static bool writeonly_reg(struct drm_i915_private *i915, i915_reg_t reg) { /* Some registers do not seem to behave and our writes unreadable */ static const struct regmask wo[] = { - { GEN9_SLICE_COMMON_ECO_CHICKEN1, INTEL_GEN_MASK(9, 9) }, + { GEN9_SLICE_COMMON_ECO_CHICKEN1, 9 }, }; return find_reg(i915, reg, wo, ARRAY_SIZE(wo)); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c index 129e0cf7dfe2..64e0b86bf258 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.c @@ -121,4 +121,3 @@ void intel_guc_log_debugfs_register(struct intel_guc_log *log, intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), log); } - diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index fef1e857cefc..ca9c9e27a43d 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -916,19 +916,26 @@ static int cmd_reg_handler(struct parser_exec_state *s, if (!strncmp(cmd, "srm", 3) || !strncmp(cmd, "lrm", 3)) { - if (offset != i915_mmio_reg_offset(GEN8_L3SQCREG4) && - offset != 0x21f0) { + if (offset == i915_mmio_reg_offset(GEN8_L3SQCREG4) || + offset == 0x21f0 || + (IS_BROADWELL(gvt->gt->i915) && + offset == i915_mmio_reg_offset(INSTPM))) + return 0; + else { gvt_vgpu_err("%s access to register (%x)\n", cmd, offset); return -EPERM; - } else - return 0; + } } if (!strncmp(cmd, "lrr-src", 7) || !strncmp(cmd, "lrr-dst", 7)) { - gvt_vgpu_err("not allowed cmd %s\n", cmd); - return -EPERM; + if (IS_BROADWELL(gvt->gt->i915) && offset == 0x215c) + return 0; + else { + gvt_vgpu_err("not allowed cmd %s reg (%x)\n", cmd, offset); + return -EPERM; + } } if (!strncmp(cmd, "pipe_ctrl", 9)) { @@ -941,11 +948,6 @@ static int cmd_reg_handler(struct parser_exec_state *s, /* below are all lri handlers */ vreg = &vgpu_vreg(s->vgpu, offset); - if (!intel_gvt_mmio_is_cmd_accessible(gvt, offset)) { - gvt_vgpu_err("%s access to non-render register (%x)\n", - cmd, offset); - return -EBADRQC; - } if (is_cmd_update_pdps(offset, s) && cmd_pdp_mmio_update_handler(s, offset, index)) diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c index 62e6a14ad58e..9f1c209d9251 100644 --- a/drivers/gpu/drm/i915/gvt/debugfs.c +++ b/drivers/gpu/drm/i915/gvt/debugfs.c @@ -41,7 +41,7 @@ struct diff_mmio { /* Compare two diff_mmio items. */ static int mmio_offset_compare(void *priv, - struct list_head *a, struct list_head *b) + const struct list_head *a, const struct list_head *b) { struct diff_mmio *ma; struct diff_mmio *mb; diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 67a26923aa0e..9478c132d7b6 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -587,12 +587,6 @@ static void _ppgtt_set_root_entry(struct intel_vgpu_mm *mm, entry, index, false, 0, mm->vgpu); } -static inline void ppgtt_set_guest_root_entry(struct intel_vgpu_mm *mm, - struct intel_gvt_gtt_entry *entry, unsigned long index) -{ - _ppgtt_set_root_entry(mm, entry, index, true); -} - static inline void ppgtt_set_shadow_root_entry(struct intel_vgpu_mm *mm, struct intel_gvt_gtt_entry *entry, unsigned long index) { diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 2ecb8534930b..e7c2babcee8b 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -46,32 +46,23 @@ static const char * const supported_hypervisors[] = { [INTEL_GVT_HYPERVISOR_KVM] = "KVM", }; -static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt, - const char *name) +static struct intel_vgpu_type * +intel_gvt_find_vgpu_type(struct intel_gvt *gvt, unsigned int type_group_id) { - const char *driver_name = - dev_driver_string(gvt->gt->i915->drm.dev); - int i; - - name += strlen(driver_name) + 1; - for (i = 0; i < gvt->num_types; i++) { - struct intel_vgpu_type *t = &gvt->types[i]; - - if (!strncmp(t->name, name, sizeof(t->name))) - return t; - } - - return NULL; + if (WARN_ON(type_group_id >= gvt->num_types)) + return NULL; + return &gvt->types[type_group_id]; } -static ssize_t available_instances_show(struct kobject *kobj, - struct device *dev, char *buf) +static ssize_t available_instances_show(struct mdev_type *mtype, + struct mdev_type_attribute *attr, + char *buf) { struct intel_vgpu_type *type; unsigned int num = 0; - void *gvt = kdev_to_i915(dev)->gvt; + void *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt; - type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); + type = intel_gvt_find_vgpu_type(gvt, mtype_get_type_group_id(mtype)); if (!type) num = 0; else @@ -80,19 +71,19 @@ static ssize_t available_instances_show(struct kobject *kobj, return sprintf(buf, "%u\n", num); } -static ssize_t device_api_show(struct kobject *kobj, struct device *dev, - char *buf) +static ssize_t device_api_show(struct mdev_type *mtype, + struct mdev_type_attribute *attr, char *buf) { return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING); } -static ssize_t description_show(struct kobject *kobj, struct device *dev, - char *buf) +static ssize_t description_show(struct mdev_type *mtype, + struct mdev_type_attribute *attr, char *buf) { struct intel_vgpu_type *type; - void *gvt = kdev_to_i915(dev)->gvt; + void *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt; - type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); + type = intel_gvt_find_vgpu_type(gvt, mtype_get_type_group_id(mtype)); if (!type) return 0; @@ -126,7 +117,7 @@ static bool intel_get_gvt_attrs(struct attribute_group ***intel_vgpu_type_groups return true; } -static bool intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt) +static int intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt) { int i, j; struct intel_vgpu_type *type; @@ -144,7 +135,7 @@ static bool intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt) gvt_vgpu_type_groups[i] = group; } - return true; + return 0; unwind: for (j = 0; j < i; j++) { @@ -152,7 +143,7 @@ unwind: kfree(group); } - return false; + return -ENOMEM; } static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt) @@ -373,7 +364,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915) goto out_clean_thread; ret = intel_gvt_init_vgpu_type_groups(gvt); - if (ret == false) { + if (ret) { gvt_err("failed to init vgpu type groups: %d\n", ret); goto out_clean_types; } diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 8dc8170ba00f..88ab360fcb31 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -574,8 +574,8 @@ struct intel_gvt_ops { void (*vgpu_reset)(struct intel_vgpu *); void (*vgpu_activate)(struct intel_vgpu *); void (*vgpu_deactivate)(struct intel_vgpu *); - struct intel_vgpu_type *(*gvt_find_vgpu_type)(struct intel_gvt *gvt, - const char *name); + struct intel_vgpu_type *(*gvt_find_vgpu_type)( + struct intel_gvt *gvt, unsigned int type_group_id); bool (*get_gvt_attrs)(struct attribute_group ***intel_vgpu_type_groups); int (*vgpu_query_plane)(struct intel_vgpu *vgpu, void *); int (*vgpu_get_dmabuf)(struct intel_vgpu *vgpu, unsigned int); diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 477badfcb258..dda320749c65 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -669,8 +669,8 @@ static void vgpu_update_refresh_rate(struct intel_vgpu *vgpu) link_n = vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)); /* Get H/V total from transcoder timing */ - htotal = (vgpu_vreg_t(vgpu, HTOTAL(TRANSCODER_A)) >> TRANS_HTOTAL_SHIFT) + 1; - vtotal = (vgpu_vreg_t(vgpu, VTOTAL(TRANSCODER_A)) >> TRANS_VTOTAL_SHIFT) + 1; + htotal = (vgpu_vreg_t(vgpu, HTOTAL(TRANSCODER_A)) >> TRANS_HTOTAL_SHIFT); + vtotal = (vgpu_vreg_t(vgpu, VTOTAL(TRANSCODER_A)) >> TRANS_VTOTAL_SHIFT); if (dp_br && link_n && htotal && vtotal) { u64 pixel_clk = 0; @@ -682,7 +682,7 @@ static void vgpu_update_refresh_rate(struct intel_vgpu *vgpu) pixel_clk *= MSEC_PER_SEC; /* Calcuate refresh rate by (pixel_clk / (h_total * v_total)) */ - new_rate = DIV64_U64_ROUND_CLOSEST(pixel_clk, div64_u64(mul_u32_u32(htotal, vtotal), MSEC_PER_SEC)); + new_rate = DIV64_U64_ROUND_CLOSEST(mul_u64_u32_shr(pixel_clk, MSEC_PER_SEC, 0), mul_u32_u32(htotal + 1, vtotal + 1)); if (*old_rate != new_rate) *old_rate = new_rate; diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index d089770795b8..65ff43cfc0f7 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -689,7 +689,7 @@ static void kvmgt_put_vfio_device(void *vgpu) vfio_device_put(vdev->vfio_device); } -static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) +static int intel_vgpu_create(struct mdev_device *mdev) { struct intel_vgpu *vgpu = NULL; struct intel_vgpu_type *type; @@ -700,10 +700,9 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) pdev = mdev_parent_dev(mdev); gvt = kdev_to_i915(pdev)->gvt; - type = intel_gvt_ops->gvt_find_vgpu_type(gvt, kobject_name(kobj)); + type = intel_gvt_ops->gvt_find_vgpu_type(gvt, + mdev_get_type_group_id(mdev)); if (!type) { - gvt_vgpu_err("failed to find type %s to create\n", - kobject_name(kobj)); ret = -EINVAL; goto out; } diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c index cf9a3d384971..aa573b078ae7 100644 --- a/drivers/gpu/drm/i915/i915_active.c +++ b/drivers/gpu/drm/i915/i915_active.c @@ -1156,7 +1156,8 @@ static int auto_active(struct i915_active *ref) return 0; } -static void auto_retire(struct i915_active *ref) +__i915_active_call static void +auto_retire(struct i915_active *ref) { i915_active_put(ref); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c2329bc44f55..db513f93f0f5 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -39,6 +39,7 @@ #include <linux/vga_switcheroo.h> #include <linux/vt.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_irq.h> @@ -553,7 +554,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) if (ret) goto err_perf; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "inteldrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "inteldrmfb"); if (ret) goto err_ggtt; @@ -757,7 +758,6 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) if (IS_ERR(i915)) return i915; - i915->drm.pdev = pdev; pci_set_drvdata(pdev, i915); /* Device parameters start as a copy of module parameters. */ @@ -768,8 +768,6 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(device_info, match_info, sizeof(*device_info)); RUNTIME_INFO(i915)->device_id = pdev->device; - BUG_ON(device_info->gen > BITS_PER_TYPE(device_info->gen_mask)); - return i915; } @@ -796,7 +794,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return PTR_ERR(i915); /* Disable nuclear pageflip by default on pre-ILK */ - if (!i915->params.nuclear_pageflip && match_info->gen < 5) + if (!i915->params.nuclear_pageflip && match_info->graphics_ver < 5) i915->drm.driver_features &= ~DRIVER_ATOMIC; /* @@ -973,8 +971,12 @@ static int i915_driver_open(struct drm_device *dev, struct drm_file *file) */ static void i915_driver_lastclose(struct drm_device *dev) { + struct drm_i915_private *i915 = to_i915(dev); + intel_fbdev_restore_mode(dev); - vga_switcheroo_process_delayed_switch(); + + if (HAS_DISPLAY(i915)) + vga_switcheroo_process_delayed_switch(); } static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) @@ -994,6 +996,9 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv) struct drm_device *dev = &dev_priv->drm; struct intel_encoder *encoder; + if (!HAS_DISPLAY(dev_priv)) + return; + drm_modeset_lock_all(dev); for_each_intel_encoder(dev, encoder) if (encoder->suspend) @@ -1006,6 +1011,9 @@ static void intel_shutdown_encoders(struct drm_i915_private *dev_priv) struct drm_device *dev = &dev_priv->drm; struct intel_encoder *encoder; + if (!HAS_DISPLAY(dev_priv)) + return; + drm_modeset_lock_all(dev); for_each_intel_encoder(dev, encoder) if (encoder->shutdown) @@ -1021,9 +1029,11 @@ void i915_driver_shutdown(struct drm_i915_private *i915) i915_gem_suspend(i915); - drm_kms_helper_poll_disable(&i915->drm); + if (HAS_DISPLAY(i915)) { + drm_kms_helper_poll_disable(&i915->drm); - drm_atomic_helper_shutdown(&i915->drm); + drm_atomic_helper_shutdown(&i915->drm); + } intel_dp_mst_suspend(i915); @@ -1033,10 +1043,18 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_suspend_encoders(i915); intel_shutdown_encoders(i915); + intel_csr_ucode_suspend(i915); + /* * The only requirement is to reboot with display DC states disabled, * for now leaving all display power wells in the INIT power domain - * enabled matching the driver reload sequence. + * enabled. + * + * TODO: + * - unify the pci_driver::shutdown sequence here with the + * pci_driver.driver.pm.poweroff,poweroff_late sequence. + * - unify the driver remove and system/runtime suspend sequences with + * the above unified shutdown/poweroff sequence. */ intel_power_domains_driver_remove(i915); enable_rpm_wakeref_asserts(&i915->runtime_pm); @@ -1079,8 +1097,8 @@ static int i915_drm_suspend(struct drm_device *dev) /* We do a lot of poking in a lot of registers, make sure they work * properly. */ intel_power_domains_disable(dev_priv); - - drm_kms_helper_poll_disable(dev); + if (HAS_DISPLAY(dev_priv)) + drm_kms_helper_poll_disable(dev); pci_save_state(pdev); @@ -1227,7 +1245,8 @@ static int i915_drm_resume(struct drm_device *dev) */ intel_runtime_pm_enable_interrupts(dev_priv); - drm_mode_config_reset(dev); + if (HAS_DISPLAY(dev_priv)) + drm_mode_config_reset(dev); i915_gem_resume(dev_priv); @@ -1240,7 +1259,8 @@ static int i915_drm_resume(struct drm_device *dev) intel_display_resume(dev); intel_hpd_poll_disable(dev_priv); - drm_kms_helper_poll_enable(dev); + if (HAS_DISPLAY(dev_priv)) + drm_kms_helper_poll_enable(dev); intel_opregion_resume(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 69e43bf91a15..374372773b48 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1234,29 +1234,37 @@ static inline struct drm_i915_private *pdev_to_i915(struct pci_dev *pdev) #define RUNTIME_INFO(dev_priv) (&(dev_priv)->__runtime) #define DRIVER_CAPS(dev_priv) (&(dev_priv)->caps) -#define INTEL_GEN(dev_priv) (INTEL_INFO(dev_priv)->gen) #define INTEL_DEVID(dev_priv) (RUNTIME_INFO(dev_priv)->device_id) -#define DISPLAY_VER(i915) (INTEL_INFO(i915)->display.version) -#define IS_DISPLAY_RANGE(i915, from, until) \ - (DISPLAY_VER(i915) >= (from) && DISPLAY_VER(i915) <= (until)) -#define IS_DISPLAY_VER(i915, v) (DISPLAY_VER(i915) == (v)) +/* + * Deprecated: this will be replaced by individual IP checks: + * GRAPHICS_VER(), MEDIA_VER() and DISPLAY_VER() + */ +#define INTEL_GEN(dev_priv) GRAPHICS_VER(dev_priv) +/* + * Deprecated: use IS_GRAPHICS_VER(), IS_MEDIA_VER() and IS_DISPLAY_VER() as + * appropriate. + */ +#define IS_GEN_RANGE(dev_priv, s, e) IS_GRAPHICS_VER(dev_priv, (s), (e)) +/* + * Deprecated: use GRAPHICS_VER(), MEDIA_VER() and DISPLAY_VER() as appropriate. + */ +#define IS_GEN(dev_priv, n) (GRAPHICS_VER(dev_priv) == (n)) -#define REVID_FOREVER 0xff -#define INTEL_REVID(dev_priv) (to_pci_dev((dev_priv)->drm.dev)->revision) +#define GRAPHICS_VER(i915) (INTEL_INFO(i915)->graphics_ver) +#define IS_GRAPHICS_VER(i915, from, until) \ + (GRAPHICS_VER(i915) >= (from) && GRAPHICS_VER(i915) <= (until)) -#define INTEL_GEN_MASK(s, e) ( \ - BUILD_BUG_ON_ZERO(!__builtin_constant_p(s)) + \ - BUILD_BUG_ON_ZERO(!__builtin_constant_p(e)) + \ - GENMASK((e) - 1, (s) - 1)) +#define MEDIA_VER(i915) (INTEL_INFO(i915)->media_ver) +#define IS_MEDIA_VER(i915, from, until) \ + (MEDIA_VER(i915) >= (from) && MEDIA_VER(i915) <= (until)) -/* Returns true if Gen is in inclusive range [Start, End] */ -#define IS_GEN_RANGE(dev_priv, s, e) \ - (!!(INTEL_INFO(dev_priv)->gen_mask & INTEL_GEN_MASK((s), (e)))) +#define DISPLAY_VER(i915) (INTEL_INFO(i915)->display.ver) +#define IS_DISPLAY_VER(i915, from, until) \ + (DISPLAY_VER(i915) >= (from) && DISPLAY_VER(i915) <= (until)) -#define IS_GEN(dev_priv, n) \ - (BUILD_BUG_ON_ZERO(!__builtin_constant_p(n)) + \ - INTEL_INFO(dev_priv)->gen == (n)) +#define REVID_FOREVER 0xff +#define INTEL_REVID(dev_priv) (to_pci_dev((dev_priv)->drm.dev)->revision) #define HAS_DSB(dev_priv) (INTEL_INFO(dev_priv)->display.has_dsb) @@ -1384,6 +1392,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_ROCKETLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ROCKETLAKE) #define IS_DG1(dev_priv) IS_PLATFORM(dev_priv, INTEL_DG1) #define IS_ALDERLAKE_S(dev_priv) IS_PLATFORM(dev_priv, INTEL_ALDERLAKE_S) +#define IS_ALDERLAKE_P(dev_priv) IS_PLATFORM(dev_priv, INTEL_ALDERLAKE_P) #define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev_priv) \ @@ -1534,6 +1543,14 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, (IS_ALDERLAKE_S(__i915) && \ IS_GT_STEP(__i915, since, until)) +#define IS_ADLP_DISPLAY_STEP(__i915, since, until) \ + (IS_ALDERLAKE_P(__i915) && \ + IS_DISPLAY_STEP(__i915, since, until)) + +#define IS_ADLP_GT_STEP(__i915, since, until) \ + (IS_ALDERLAKE_P(__i915) && \ + IS_GT_STEP(__i915, since, until)) + #define IS_LP(dev_priv) (INTEL_INFO(dev_priv)->is_lp) #define IS_GEN9_LP(dev_priv) (IS_GEN(dev_priv, 9) && IS_LP(dev_priv)) #define IS_GEN9_BC(dev_priv) (IS_GEN(dev_priv, 9) && !IS_LP(dev_priv)) @@ -1905,9 +1922,6 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data, struct drm_file *file); /* i915_mm.c */ -int remap_io_mapping(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn, unsigned long size, - struct io_mapping *iomap); int remap_io_sg(struct vm_area_struct *vma, unsigned long addr, unsigned long size, struct scatterlist *sgl, resource_size_t iobase); diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index e622aee6e4be..440c35f1abc9 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -105,7 +105,7 @@ static inline bool tasklet_is_locked(const struct tasklet_struct *t) static inline void __tasklet_disable_sync_once(struct tasklet_struct *t) { if (!atomic_fetch_inc(&t->count)) - tasklet_unlock_wait(t); + tasklet_unlock_spin_wait(t); } static inline bool __tasklet_is_enabled(const struct tasklet_struct *t) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index bb181fe5d47e..99ca242ec13b 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -36,7 +36,6 @@ #include <drm/drm_print.h> -#include "display/intel_atomic.h" #include "display/intel_csr.h" #include "display/intel_overlay.h" @@ -808,9 +807,6 @@ static void __err_print_to_sgl(struct drm_i915_error_state_buf *m, if (error->overlay) intel_overlay_print_error_state(m, error->overlay); - if (error->display) - intel_display_print_error_state(m, error->display); - err_print_capabilities(m, error); err_print_params(m, &error->params); } @@ -974,7 +970,6 @@ void __i915_gpu_coredump_free(struct kref *error_ref) } kfree(error->overlay); - kfree(error->display); cleanup_params(error); @@ -1826,7 +1821,6 @@ i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask) } error->overlay = intel_overlay_capture_error_state(i915); - error->display = intel_display_capture_error_state(i915); return error; } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 16bc42de4b84..eb435f9e0220 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -29,7 +29,6 @@ struct drm_i915_private; struct i915_vma_compress; struct intel_engine_capture_vma; struct intel_overlay_error_state; -struct intel_display_error_state; struct i915_vma_coredump { struct i915_vma_coredump *next; @@ -182,7 +181,6 @@ struct i915_gpu_coredump { struct i915_params params; struct intel_overlay_error_state *overlay; - struct intel_display_error_state *display; struct scatterlist *sgl, *fit; }; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7eefbdec25a2..d4611c643446 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -35,6 +35,7 @@ #include <drm/drm_drv.h> #include <drm/drm_irq.h> +#include "display/intel_de.h" #include "display/intel_display_types.h" #include "display/intel_fifo_underrun.h" #include "display/intel_hotplug.h" @@ -194,7 +195,7 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 11) hpd->hpd = hpd_gen11; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) hpd->hpd = hpd_bxt; else if (DISPLAY_VER(dev_priv) >= 8) hpd->hpd = hpd_bdw; @@ -806,7 +807,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) if (mode->flags & DRM_MODE_FLAG_INTERLACE) vtotal /= 2; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; else position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; @@ -857,7 +858,7 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, int vbl_start, vbl_end, hsync_start, htotal, vtotal; unsigned long irqflags; bool use_scanline_counter = DISPLAY_VER(dev_priv) >= 5 || - IS_G4X(dev_priv) || IS_DISPLAY_VER(dev_priv, 2) || + IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) == 2 || crtc->mode_flags & I915_MODE_FLAG_USE_SCANLINE_COUNTER; if (drm_WARN_ON(&dev_priv->drm, !mode->crtc_clock)) { @@ -2077,7 +2078,7 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, intel_uncore_write(&dev_priv->uncore, SDEIIR, pch_iir); } - if (IS_DISPLAY_VER(dev_priv, 5) && de_iir & DE_PCU_EVENT) + if (DISPLAY_VER(dev_priv) == 5 && de_iir & DE_PCU_EVENT) gen5_rps_irq_handler(&dev_priv->gt.rps); } @@ -2269,7 +2270,17 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) { u32 mask; - if (DISPLAY_VER(dev_priv) >= 12) + if (DISPLAY_VER(dev_priv) >= 13) + return TGL_DE_PORT_AUX_DDIA | + TGL_DE_PORT_AUX_DDIB | + TGL_DE_PORT_AUX_DDIC | + XELPD_DE_PORT_AUX_DDID | + XELPD_DE_PORT_AUX_DDIE | + TGL_DE_PORT_AUX_USBC1 | + TGL_DE_PORT_AUX_USBC2 | + TGL_DE_PORT_AUX_USBC3 | + TGL_DE_PORT_AUX_USBC4; + else if (DISPLAY_VER(dev_priv) >= 12) return TGL_DE_PORT_AUX_DDIA | TGL_DE_PORT_AUX_DDIB | TGL_DE_PORT_AUX_DDIC | @@ -2287,10 +2298,10 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) GEN9_AUX_CHANNEL_C | GEN9_AUX_CHANNEL_D; - if (IS_CNL_WITH_PORT_F(dev_priv) || IS_DISPLAY_VER(dev_priv, 11)) + if (IS_CNL_WITH_PORT_F(dev_priv) || DISPLAY_VER(dev_priv) == 11) mask |= CNL_AUX_CHANNEL_F; - if (IS_DISPLAY_VER(dev_priv, 11)) + if (DISPLAY_VER(dev_priv) == 11) mask |= ICL_AUX_CHANNEL_E; return mask; @@ -2298,7 +2309,7 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) { - if (HAS_D12_PLANE_MINIMIZATION(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) return RKL_DE_PIPE_IRQ_FAULT_ERRORS; else if (DISPLAY_VER(dev_priv) >= 11) return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; @@ -2421,6 +2432,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) u32 iir; enum pipe pipe; + drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DISPLAY(dev_priv)); + if (master_ctl & GEN8_DE_MISC_IRQ) { iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_MISC_IIR); if (iir) { @@ -2458,7 +2471,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) found = true; } - if (IS_GEN9_LP(dev_priv)) { + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK; if (hotplug_trigger) { @@ -2474,7 +2487,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) } } - if (IS_GEN9_LP(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) { + if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && + (iir & BXT_DE_PORT_GMBUS)) { gmbus_irq_handler(dev_priv); found = true; } @@ -3058,14 +3072,13 @@ static void cnp_display_clock_wa(struct drm_i915_private *dev_priv) } } -static void gen8_irq_reset(struct drm_i915_private *dev_priv) +static void gen8_display_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; enum pipe pipe; - gen8_master_intr_disable(dev_priv->uncore.regs); - - gen8_gt_irq_reset(&dev_priv->gt); + if (!HAS_DISPLAY(dev_priv)) + return; intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); @@ -3077,6 +3090,16 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_); GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_); +} + +static void gen8_irq_reset(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + gen8_master_intr_disable(dev_priv->uncore.regs); + + gen8_gt_irq_reset(&dev_priv->gt); + gen8_display_irq_reset(dev_priv); GEN3_IRQ_RESET(uncore, GEN8_PCU_); if (HAS_PCH_SPLIT(dev_priv)) @@ -3092,6 +3115,9 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | BIT(TRANSCODER_C) | BIT(TRANSCODER_D); + if (!HAS_DISPLAY(dev_priv)) + return; + intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0); if (DISPLAY_VER(dev_priv) >= 12) { @@ -3714,10 +3740,13 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) BIT(TRANSCODER_C) | BIT(TRANSCODER_D); enum pipe pipe; + if (!HAS_DISPLAY(dev_priv)) + return; + if (DISPLAY_VER(dev_priv) <= 10) de_misc_masked |= GEN8_DE_MISC_GSE; - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) de_port_masked |= BXT_DE_PORT_GMBUS; if (DISPLAY_VER(dev_priv) >= 11) { @@ -3732,7 +3761,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) gen8_de_pipe_flip_done_mask(dev_priv); de_port_enables = de_port_masked; - if (IS_GEN9_LP(dev_priv)) + if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK; else if (IS_BROADWELL(dev_priv)) de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK; @@ -3797,6 +3826,16 @@ static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) gen8_master_intr_enable(dev_priv->uncore.regs); } +static void gen11_de_irq_postinstall(struct drm_i915_private *dev_priv) +{ + if (!HAS_DISPLAY(dev_priv)) + return; + + gen8_de_irq_postinstall(dev_priv); + + intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, + GEN11_DISPLAY_IRQ_ENABLE); +} static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) { @@ -3807,12 +3846,10 @@ static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) icp_irq_postinstall(dev_priv); gen11_gt_irq_postinstall(&dev_priv->gt); - gen8_de_irq_postinstall(dev_priv); + gen11_de_irq_postinstall(dev_priv); GEN3_IRQ_INIT(uncore, GEN11_GU_MISC_, ~gu_misc_masked, gu_misc_masked); - intel_uncore_write(&dev_priv->uncore, GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE); - if (HAS_MASTER_UNIT_IRQ(dev_priv)) { dg1_master_intr_enable(uncore->regs); intel_uncore_posting_read(&dev_priv->uncore, DG1_MSTR_UNIT_INTR); @@ -4317,7 +4354,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev_priv->display.hpd_irq_setup = dg1_hpd_irq_setup; else if (DISPLAY_VER(dev_priv) >= 11) dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; - else if (IS_GEN9_LP(dev_priv)) + else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) dev_priv->display.hpd_irq_setup = icp_hpd_irq_setup; diff --git a/drivers/gpu/drm/i915/i915_mm.c b/drivers/gpu/drm/i915/i915_mm.c index 666808cb3a32..25576fa73ff0 100644 --- a/drivers/gpu/drm/i915/i915_mm.c +++ b/drivers/gpu/drm/i915/i915_mm.c @@ -28,89 +28,9 @@ #include "i915_drv.h" -struct remap_pfn { - struct mm_struct *mm; - unsigned long pfn; - pgprot_t prot; - - struct sgt_iter sgt; - resource_size_t iobase; -}; - -static int remap_pfn(pte_t *pte, unsigned long addr, void *data) -{ - struct remap_pfn *r = data; - - /* Special PTE are not associated with any struct page */ - set_pte_at(r->mm, addr, pte, pte_mkspecial(pfn_pte(r->pfn, r->prot))); - r->pfn++; - - return 0; -} - -#define use_dma(io) ((io) != -1) - -static inline unsigned long sgt_pfn(const struct remap_pfn *r) -{ - if (use_dma(r->iobase)) - return (r->sgt.dma + r->sgt.curr + r->iobase) >> PAGE_SHIFT; - else - return r->sgt.pfn + (r->sgt.curr >> PAGE_SHIFT); -} - -static int remap_sg(pte_t *pte, unsigned long addr, void *data) -{ - struct remap_pfn *r = data; - - if (GEM_WARN_ON(!r->sgt.sgp)) - return -EINVAL; - - /* Special PTE are not associated with any struct page */ - set_pte_at(r->mm, addr, pte, - pte_mkspecial(pfn_pte(sgt_pfn(r), r->prot))); - r->pfn++; /* track insertions in case we need to unwind later */ - - r->sgt.curr += PAGE_SIZE; - if (r->sgt.curr >= r->sgt.max) - r->sgt = __sgt_iter(__sg_next(r->sgt.sgp), use_dma(r->iobase)); - - return 0; -} - -/** - * remap_io_mapping - remap an IO mapping to userspace - * @vma: user vma to map to - * @addr: target user address to start at - * @pfn: physical address of kernel memory - * @size: size of map area - * @iomap: the source io_mapping - * - * Note: this is only safe if the mm semaphore is held when called. - */ -int remap_io_mapping(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn, unsigned long size, - struct io_mapping *iomap) -{ - struct remap_pfn r; - int err; - #define EXPECTED_FLAGS (VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP) - GEM_BUG_ON((vma->vm_flags & EXPECTED_FLAGS) != EXPECTED_FLAGS); - - /* We rely on prevalidation of the io-mapping to skip track_pfn(). */ - r.mm = vma->vm_mm; - r.pfn = pfn; - r.prot = __pgprot((pgprot_val(iomap->prot) & _PAGE_CACHE_MASK) | - (pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK)); - err = apply_to_page_range(r.mm, addr, size, remap_pfn, &r); - if (unlikely(err)) { - zap_vma_ptes(vma, addr, (r.pfn - pfn) << PAGE_SHIFT); - return err; - } - - return 0; -} +#define use_dma(io) ((io) != -1) /** * remap_io_sg - remap an IO mapping to userspace @@ -126,13 +46,8 @@ int remap_io_sg(struct vm_area_struct *vma, unsigned long addr, unsigned long size, struct scatterlist *sgl, resource_size_t iobase) { - struct remap_pfn r = { - .mm = vma->vm_mm, - .prot = vma->vm_page_prot, - .sgt = __sgt_iter(sgl, use_dma(iobase)), - .iobase = iobase, - }; - int err; + unsigned long pfn, len, remapped = 0; + int err = 0; /* We rely on prevalidation of the io-mapping to skip track_pfn(). */ GEM_BUG_ON((vma->vm_flags & EXPECTED_FLAGS) != EXPECTED_FLAGS); @@ -140,11 +55,25 @@ int remap_io_sg(struct vm_area_struct *vma, if (!use_dma(iobase)) flush_cache_range(vma, addr, size); - err = apply_to_page_range(r.mm, addr, size, remap_sg, &r); - if (unlikely(err)) { - zap_vma_ptes(vma, addr, r.pfn << PAGE_SHIFT); - return err; - } - - return 0; + do { + if (use_dma(iobase)) { + if (!sg_dma_len(sgl)) + break; + pfn = (sg_dma_address(sgl) + iobase) >> PAGE_SHIFT; + len = sg_dma_len(sgl); + } else { + pfn = page_to_pfn(sg_page(sgl)); + len = sgl->length; + } + + err = remap_pfn_range(vma, addr + remapped, pfn, len, + vma->vm_page_prot); + if (err) + break; + remapped += len; + } while ((sgl = __sg_next(sgl))); + + if (err) + zap_vma_ptes(vma, addr, remapped); + return err; } diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 34ebb0662547..14cd64cc61d0 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -97,4 +97,3 @@ void i915_params_copy(struct i915_params *dest, const struct i915_params *src); void i915_params_free(struct i915_params *params); #endif - diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 480553746794..1680062a2149 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -36,7 +36,10 @@ #include "i915_selftest.h" #define PLATFORM(x) .platform = (x) -#define GEN(x) .gen = (x), .gen_mask = BIT((x) - 1), .display.version = (x) +#define GEN(x) \ + .graphics_ver = (x), \ + .media_ver = (x), \ + .display.ver = (x) #define I845_PIPE_OFFSETS \ .pipe_offsets = { \ @@ -644,8 +647,8 @@ static const struct intel_device_info chv_info = { .has_gt_uc = 1, \ .display.has_hdcp = 1, \ .display.has_ipc = 1, \ - .ddb_size = 896, \ - .num_supported_dbuf_slices = 1 + .dbuf.size = 896 - 4, /* 4 blocks for bypass path allocation */ \ + .dbuf.slice_mask = BIT(DBUF_S1) #define SKL_PLATFORM \ GEN9_FEATURES, \ @@ -680,7 +683,7 @@ static const struct intel_device_info skl_gt4_info = { #define GEN9_LP_FEATURES \ GEN(9), \ .is_lp = 1, \ - .num_supported_dbuf_slices = 1, \ + .dbuf.slice_mask = BIT(DBUF_S1), \ .display.has_hotplug = 1, \ .platform_engine_mask = BIT(RCS0) | BIT(VCS0) | BIT(BCS0) | BIT(VECS0), \ .pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), \ @@ -717,14 +720,14 @@ static const struct intel_device_info skl_gt4_info = { static const struct intel_device_info bxt_info = { GEN9_LP_FEATURES, PLATFORM(INTEL_BROXTON), - .ddb_size = 512, + .dbuf.size = 512 - 4, /* 4 blocks for bypass path allocation */ }; static const struct intel_device_info glk_info = { GEN9_LP_FEATURES, PLATFORM(INTEL_GEMINILAKE), - .display.version = 10, - .ddb_size = 1024, + .display.ver = 10, + .dbuf.size = 1024 - 4, /* 4 blocks for bypass path allocation */ GLK_COLORS, }; @@ -787,7 +790,7 @@ static const struct intel_device_info cml_gt2_info = { #define GEN10_FEATURES \ GEN9_FEATURES, \ GEN(10), \ - .ddb_size = 1024, \ + .dbuf.size = 1024 - 4, /* 4 blocks for bypass path allocation */ \ .display.has_dsc = 1, \ .has_coherent_ggtt = false, \ GLK_COLORS @@ -827,8 +830,8 @@ static const struct intel_device_info cnl_info = { [TRANSCODER_DSI_1] = TRANSCODER_DSI1_OFFSET, \ }, \ GEN(11), \ - .ddb_size = 2048, \ - .num_supported_dbuf_slices = 2, \ + .dbuf.size = 2048, \ + .dbuf.slice_mask = BIT(DBUF_S1) | BIT(DBUF_S2), \ .has_logical_ring_elsq = 1, \ .color = { .degamma_lut_size = 33, .gamma_lut_size = 262145 } @@ -904,8 +907,7 @@ static const struct intel_device_info rkl_info = { BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0), }; -#define GEN12_DGFX_FEATURES \ - GEN12_FEATURES, \ +#define DGFX_FEATURES \ .memory_regions = REGION_SMEM | REGION_LMEM, \ .has_master_unit_irq = 1, \ .has_llc = 0, \ @@ -913,7 +915,8 @@ static const struct intel_device_info rkl_info = { .is_dgfx = 1 static const struct intel_device_info dg1_info __maybe_unused = { - GEN12_DGFX_FEATURES, + GEN12_FEATURES, + DGFX_FEATURES, PLATFORM(INTEL_DG1), .pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), .require_force_probe = 1, @@ -936,6 +939,28 @@ static const struct intel_device_info adl_s_info = { .dma_mask_size = 46, }; +#define XE_LPD_FEATURES \ + .display.ver = 13, \ + .display.has_psr_hw_tracking = 0, \ + .abox_mask = GENMASK(1, 0), \ + .pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), \ + .cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | \ + BIT(TRANSCODER_C) | BIT(TRANSCODER_D), \ + .dbuf.size = 4096, \ + .dbuf.slice_mask = BIT(DBUF_S1) | BIT(DBUF_S2) | BIT(DBUF_S3) | BIT(DBUF_S4) + +static const struct intel_device_info adl_p_info = { + GEN12_FEATURES, + XE_LPD_FEATURES, + PLATFORM(INTEL_ALDERLAKE_P), + .require_force_probe = 1, + .display.has_modular_fia = 1, + .platform_engine_mask = + BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0) | BIT(VCS2), + .ppgtt_size = 48, + .dma_mask_size = 39, +}; + #undef GEN #undef PLATFORM @@ -1013,6 +1038,7 @@ static const struct pci_device_id pciidlist[] = { INTEL_TGL_12_IDS(&tgl_info), INTEL_RKL_IDS(&rkl_info), INTEL_ADLS_IDS(&adl_s_info), + INTEL_ADLP_IDS(&adl_p_info), {0, 0, 0} }; MODULE_DEVICE_TABLE(pci, pciidlist); diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 85ad62dbabfa..de8ebc34af0f 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -4318,6 +4318,7 @@ static void oa_init_supported_formats(struct i915_perf *perf) case INTEL_ROCKETLAKE: case INTEL_DG1: case INTEL_ALDERLAKE_S: + case INTEL_ALDERLAKE_P: oa_format_add(perf, I915_OA_FORMAT_A12); oa_format_add(perf, I915_OA_FORMAT_A12_B8_C8); oa_format_add(perf, I915_OA_FORMAT_A32u40_A4u32_B8_C8); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cbf7a60afe54..07cca3b423bc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4170,6 +4170,9 @@ enum { #define GEN9_CLKGATE_DIS_4 _MMIO(0x4653C) #define BXT_GMBUS_GATING_DIS (1 << 14) +#define GEN9_CLKGATE_DIS_5 _MMIO(0x46540) +#define DPCE_GATING_DIS REG_BIT(17) + #define _CLKGATE_DIS_PSL_A 0x46520 #define _CLKGATE_DIS_PSL_B 0x46524 #define _CLKGATE_DIS_PSL_C 0x46528 @@ -4563,8 +4566,7 @@ enum { #define EDP_SU_TRACK_ENABLE (1 << 30) #define TGL_EDP_PSR2_BLOCK_COUNT_NUM_2 (0 << 28) #define TGL_EDP_PSR2_BLOCK_COUNT_NUM_3 (1 << 28) -#define EDP_Y_COORDINATE_VALID (1 << 26) /* GLK and CNL+ */ -#define EDP_Y_COORDINATE_ENABLE (1 << 25) /* GLK and CNL+ */ +#define EDP_Y_COORDINATE_ENABLE REG_BIT(25) /* display 10, 11 and 12 */ #define EDP_MAX_SU_DISABLE_TIME(t) ((t) << 20) #define EDP_MAX_SU_DISABLE_TIME_MASK (0x1f << 20) #define EDP_PSR2_IO_BUFFER_WAKE_MAX_LINES 8 @@ -6430,9 +6432,8 @@ enum { #define _CUR_WM_TRANS_B_0 0x71168 #define PLANE_WM_EN (1 << 31) #define PLANE_WM_IGNORE_LINES (1 << 30) -#define PLANE_WM_LINES_SHIFT 14 -#define PLANE_WM_LINES_MASK 0x1f -#define PLANE_WM_BLOCKS_MASK 0x7ff /* skl+: 10 bits, icl+ 11 bits */ +#define PLANE_WM_LINES_MASK REG_GENMASK(26, 14) +#define PLANE_WM_BLOCKS_MASK REG_GENMASK(11, 0) #define _CUR_WM_0(pipe) _PIPE(pipe, _CUR_WM_A_0, _CUR_WM_B_0) #define CUR_WM(pipe, level) _MMIO(_CUR_WM_0(pipe) + ((4) * (level))) @@ -7207,6 +7208,8 @@ enum { _PIPE(pipe, _PLANE_STRIDE_3_A, _PLANE_STRIDE_3_B) #define PLANE_STRIDE(pipe, plane) \ _MMIO_PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe)) +#define PLANE_STRIDE_MASK REG_GENMASK(10, 0) +#define PLANE_STRIDE_MASK_XELPD REG_GENMASK(11, 0) #define _PLANE_POS_1_B 0x7118c #define _PLANE_POS_2_B 0x7128c @@ -7784,6 +7787,8 @@ enum { #define GEN8_GT_BCS_IRQ (1 << 1) #define GEN8_GT_RCS_IRQ (1 << 0) +#define XELPD_DISPLAY_ERR_FATAL_MASK _MMIO(0x4421c) + #define GEN8_GT_ISR(which) _MMIO(0x44300 + (0x10 * (which))) #define GEN8_GT_IMR(which) _MMIO(0x44304 + (0x10 * (which))) #define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which))) @@ -7866,15 +7871,17 @@ enum { #define BDW_DE_PORT_HOTPLUG_MASK GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) #define BXT_DE_PORT_GMBUS (1 << 1) #define GEN8_AUX_CHANNEL_A (1 << 0) -#define TGL_DE_PORT_AUX_USBC6 (1 << 13) -#define TGL_DE_PORT_AUX_USBC5 (1 << 12) -#define TGL_DE_PORT_AUX_USBC4 (1 << 11) -#define TGL_DE_PORT_AUX_USBC3 (1 << 10) -#define TGL_DE_PORT_AUX_USBC2 (1 << 9) -#define TGL_DE_PORT_AUX_USBC1 (1 << 8) -#define TGL_DE_PORT_AUX_DDIC (1 << 2) -#define TGL_DE_PORT_AUX_DDIB (1 << 1) -#define TGL_DE_PORT_AUX_DDIA (1 << 0) +#define TGL_DE_PORT_AUX_USBC6 REG_BIT(13) +#define XELPD_DE_PORT_AUX_DDIE REG_BIT(13) +#define TGL_DE_PORT_AUX_USBC5 REG_BIT(12) +#define XELPD_DE_PORT_AUX_DDID REG_BIT(12) +#define TGL_DE_PORT_AUX_USBC4 REG_BIT(11) +#define TGL_DE_PORT_AUX_USBC3 REG_BIT(10) +#define TGL_DE_PORT_AUX_USBC2 REG_BIT(9) +#define TGL_DE_PORT_AUX_USBC1 REG_BIT(8) +#define TGL_DE_PORT_AUX_DDIC REG_BIT(2) +#define TGL_DE_PORT_AUX_DDIB REG_BIT(1) +#define TGL_DE_PORT_AUX_DDIA REG_BIT(0) #define GEN8_DE_MISC_ISR _MMIO(0x44460) #define GEN8_DE_MISC_IMR _MMIO(0x44464) @@ -9632,6 +9639,12 @@ enum { #define ICL_PW_CTL_IDX_PW_2 1 #define ICL_PW_CTL_IDX_PW_1 0 +/* XE_LPD - power wells */ +#define XELPD_PW_CTL_IDX_PW_D 8 +#define XELPD_PW_CTL_IDX_PW_C 7 +#define XELPD_PW_CTL_IDX_PW_B 6 +#define XELPD_PW_CTL_IDX_PW_A 5 + #define ICL_PWR_WELL_CTL_AUX1 _MMIO(0x45440) #define ICL_PWR_WELL_CTL_AUX2 _MMIO(0x45444) #define ICL_PWR_WELL_CTL_AUX4 _MMIO(0x4544C) @@ -9646,7 +9659,9 @@ enum { #define TGL_PW_CTL_IDX_AUX_TBT1 9 #define ICL_PW_CTL_IDX_AUX_TBT1 8 #define TGL_PW_CTL_IDX_AUX_TC6 8 +#define XELPD_PW_CTL_IDX_AUX_E 8 #define TGL_PW_CTL_IDX_AUX_TC5 7 +#define XELPD_PW_CTL_IDX_AUX_D 7 #define TGL_PW_CTL_IDX_AUX_TC4 6 #define ICL_PW_CTL_IDX_AUX_F 5 #define TGL_PW_CTL_IDX_AUX_TC3 5 @@ -9661,7 +9676,9 @@ enum { #define ICL_PWR_WELL_CTL_DDI1 _MMIO(0x45450) #define ICL_PWR_WELL_CTL_DDI2 _MMIO(0x45454) #define ICL_PWR_WELL_CTL_DDI4 _MMIO(0x4545C) +#define XELPD_PW_CTL_IDX_DDI_E 8 #define TGL_PW_CTL_IDX_DDI_TC6 8 +#define XELPD_PW_CTL_IDX_DDI_D 7 #define TGL_PW_CTL_IDX_DDI_TC5 7 #define TGL_PW_CTL_IDX_DDI_TC4 6 #define ICL_PW_CTL_IDX_DDI_F 5 @@ -10811,6 +10828,7 @@ enum skl_power_gate { _DKL_TX_DPCNTL1) #define _DKL_TX_DPCNTL2 0x2C8 +#define DKL_TX_LOADGEN_SHARING_PMD_DISABLE REG_BIT(12) #define DKL_TX_DP20BITMODE (1 << 2) #define DKL_TX_DPCNTL2(tc_port) _MMIO(_PORT(tc_port, \ _DKL_PHY1_BASE, \ @@ -11472,6 +11490,8 @@ enum skl_power_gate { #define SPLITTER_CONFIGURATION_MASK REG_GENMASK(26, 25) #define SPLITTER_CONFIGURATION_2_SEGMENT REG_FIELD_PREP(SPLITTER_CONFIGURATION_MASK, 0) #define SPLITTER_CONFIGURATION_4_SEGMENT REG_FIELD_PREP(SPLITTER_CONFIGURATION_MASK, 1) +#define UNCOMPRESSED_JOINER_MASTER (1 << 21) +#define UNCOMPRESSED_JOINER_SLAVE (1 << 20) #define _ICL_PIPE_DSS_CTL2_PB 0x78204 #define _ICL_PIPE_DSS_CTL2_PC 0x78404 @@ -12549,4 +12569,7 @@ enum skl_power_gate { #define TGL_ROOT_DEVICE_SKU_ULX 0x2 #define TGL_ROOT_DEVICE_SKU_ULT 0x4 +#define CLKREQ_POLICY _MMIO(0x101038) +#define CLKREQ_POLICY_MEM_UP_OVRD REG_BIT(1) + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 9165971c3c47..bec9c3652188 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -350,6 +350,8 @@ static void __rq_arm_watchdog(struct i915_request *rq) if (!ce->watchdog.timeout_us) return; + i915_request_get(rq); + hrtimer_init(&wdg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); wdg->timer.function = __rq_watchdog_expired; hrtimer_start_range_ns(&wdg->timer, @@ -357,7 +359,6 @@ static void __rq_arm_watchdog(struct i915_request *rq) NSEC_PER_USEC), NSEC_PER_MSEC, HRTIMER_MODE_REL); - i915_request_get(rq); } static void __rq_cancel_watchdog(struct i915_request *rq) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 0bc7b49f843c..5fcc32821e18 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -87,6 +87,9 @@ void i915_save_display(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + if (!HAS_DISPLAY(dev_priv)) + return; + /* Display arbitration control */ if (INTEL_GEN(dev_priv) <= 4) dev_priv->regfile.saveDSPARB = intel_de_read(dev_priv, DSPARB); @@ -102,6 +105,9 @@ void i915_restore_display(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + if (!HAS_DISPLAY(dev_priv)) + return; + intel_restore_swf(dev_priv); if (IS_GEN(dev_priv, 4)) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 45d32ef42787..4c6b5d52b5ca 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -72,7 +72,7 @@ show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf) if (HAS_RC6pp(dev_priv)) mask |= BIT(2); - return snprintf(buf, PAGE_SIZE, "%x\n", mask); + return sysfs_emit(buf, "%x\n", mask); } static ssize_t @@ -80,7 +80,7 @@ show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); u32 rc6_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6); - return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency); + return sysfs_emit(buf, "%u\n", rc6_residency); } static ssize_t @@ -88,7 +88,7 @@ show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); u32 rc6p_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6p); - return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency); + return sysfs_emit(buf, "%u\n", rc6p_residency); } static ssize_t @@ -96,7 +96,7 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); u32 rc6pp_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6pp); - return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency); + return sysfs_emit(buf, "%u\n", rc6pp_residency); } static ssize_t @@ -104,7 +104,7 @@ show_media_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); u32 rc6_residency = calc_residency(dev_priv, VLV_GT_MEDIA_RC6); - return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency); + return sysfs_emit(buf, "%u\n", rc6_residency); } static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); @@ -263,8 +263,7 @@ static ssize_t gt_act_freq_mhz_show(struct device *kdev, struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); struct intel_rps *rps = &i915->gt.rps; - return snprintf(buf, PAGE_SIZE, "%d\n", - intel_rps_read_actual_frequency(rps)); + return sysfs_emit(buf, "%d\n", intel_rps_read_actual_frequency(rps)); } static ssize_t gt_cur_freq_mhz_show(struct device *kdev, @@ -273,8 +272,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); struct intel_rps *rps = &i915->gt.rps; - return snprintf(buf, PAGE_SIZE, "%d\n", - intel_gpu_freq(rps, rps->cur_freq)); + return sysfs_emit(buf, "%d\n", intel_gpu_freq(rps, rps->cur_freq)); } static ssize_t gt_boost_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) @@ -282,8 +280,7 @@ static ssize_t gt_boost_freq_mhz_show(struct device *kdev, struct device_attribu struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); struct intel_rps *rps = &i915->gt.rps; - return snprintf(buf, PAGE_SIZE, "%d\n", - intel_gpu_freq(rps, rps->boost_freq)); + return sysfs_emit(buf, "%d\n", intel_gpu_freq(rps, rps->boost_freq)); } static ssize_t gt_boost_freq_mhz_store(struct device *kdev, @@ -323,8 +320,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev, struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); struct intel_rps *rps = &dev_priv->gt.rps; - return snprintf(buf, PAGE_SIZE, "%d\n", - intel_gpu_freq(rps, rps->efficient_freq)); + return sysfs_emit(buf, "%d\n", intel_gpu_freq(rps, rps->efficient_freq)); } static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) @@ -332,8 +328,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); struct intel_rps *rps = &dev_priv->gt.rps; - return snprintf(buf, PAGE_SIZE, "%d\n", - intel_gpu_freq(rps, rps->max_freq_softlimit)); + return sysfs_emit(buf, "%d\n", intel_gpu_freq(rps, rps->max_freq_softlimit)); } static ssize_t gt_max_freq_mhz_store(struct device *kdev, @@ -387,8 +382,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); struct intel_rps *rps = &dev_priv->gt.rps; - return snprintf(buf, PAGE_SIZE, "%d\n", - intel_gpu_freq(rps, rps->min_freq_softlimit)); + return sysfs_emit(buf, "%d\n", intel_gpu_freq(rps, rps->min_freq_softlimit)); } static ssize_t gt_min_freq_mhz_store(struct device *kdev, @@ -462,7 +456,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr else BUG(); - return snprintf(buf, PAGE_SIZE, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static const struct attribute * const gen6_attrs[] = { diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index a4addcc64978..6778ad2a14a4 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -8,6 +8,7 @@ #include <drm/drm_drv.h> +#include "display/intel_crtc.h" #include "display/intel_display_types.h" #include "gt/intel_engine.h" @@ -474,6 +475,44 @@ TRACE_EVENT(intel_pipe_update_end, __entry->scanline) ); +/* frontbuffer tracking */ + +TRACE_EVENT(intel_frontbuffer_invalidate, + TP_PROTO(unsigned int frontbuffer_bits, unsigned int origin), + TP_ARGS(frontbuffer_bits, origin), + + TP_STRUCT__entry( + __field(unsigned int, frontbuffer_bits) + __field(unsigned int, origin) + ), + + TP_fast_assign( + __entry->frontbuffer_bits = frontbuffer_bits; + __entry->origin = origin; + ), + + TP_printk("frontbuffer_bits=0x%08x, origin=%u", + __entry->frontbuffer_bits, __entry->origin) +); + +TRACE_EVENT(intel_frontbuffer_flush, + TP_PROTO(unsigned int frontbuffer_bits, unsigned int origin), + TP_ARGS(frontbuffer_bits, origin), + + TP_STRUCT__entry( + __field(unsigned int, frontbuffer_bits) + __field(unsigned int, origin) + ), + + TP_fast_assign( + __entry->frontbuffer_bits = frontbuffer_bits; + __entry->origin = origin; + ), + + TP_printk("frontbuffer_bits=0x%08x, origin=%u", + __entry->frontbuffer_bits, __entry->origin) +); + /* object tracking */ TRACE_EVENT(i915_gem_object_create, diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index abd4dcd9f79c..f02f52ab5070 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -418,6 +418,11 @@ static inline const char *onoff(bool v) return v ? "on" : "off"; } +static inline const char *enabledisable(bool v) +{ + return v ? "enable" : "disable"; +} + static inline const char *enableddisabled(bool v) { return v ? "enabled" : "disabled"; diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h index 6b1bfa230b82..995b502d7e5d 100644 --- a/drivers/gpu/drm/i915/i915_vma_types.h +++ b/drivers/gpu/drm/i915/i915_vma_types.h @@ -286,4 +286,3 @@ struct i915_vma { }; #endif - diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index de02207f6ec6..8cb58a238c68 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -67,6 +67,7 @@ static const char * const platform_names[] = { PLATFORM_NAME(ROCKETLAKE), PLATFORM_NAME(DG1), PLATFORM_NAME(ALDERLAKE_S), + PLATFORM_NAME(ALDERLAKE_P), }; #undef PLATFORM_NAME @@ -95,7 +96,9 @@ static const char *iommu_name(void) void intel_device_info_print_static(const struct intel_device_info *info, struct drm_printer *p) { - drm_printf(p, "gen: %d\n", info->gen); + drm_printf(p, "graphics_ver: %u\n", info->graphics_ver); + drm_printf(p, "media_ver: %u\n", info->media_ver); + drm_printf(p, "display_ver: %u\n", info->display.ver); drm_printf(p, "gt: %d\n", info->gt); drm_printf(p, "iommu: %s\n", iommu_name()); drm_printf(p, "memory-regions: %x\n", info->memory_regions); @@ -265,7 +268,7 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) BUILD_BUG_ON(BITS_PER_TYPE(intel_engine_mask_t) < I915_NUM_ENGINES); - if (HAS_D12_PLANE_MINIMIZATION(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 13 || HAS_D12_PLANE_MINIMIZATION(dev_priv)) for_each_pipe(dev_priv, pipe) runtime->num_sprites[pipe] = 4; else if (INTEL_GEN(dev_priv) >= 11) diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 2f442d418a15..e98b36959736 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -87,6 +87,7 @@ enum intel_platform { INTEL_ROCKETLAKE, INTEL_DG1, INTEL_ALDERLAKE_S, + INTEL_ALDERLAKE_P, INTEL_MAX_PLATFORMS }; @@ -160,9 +161,9 @@ enum intel_ppgtt_type { func(supports_tv); struct intel_device_info { - u16 gen_mask; + u8 graphics_ver; + u8 media_ver; - u8 gen; u8 gt; /* GT number, 0 if undefined */ intel_engine_mask_t platform_engine_mask; /* Engines supported by the HW */ @@ -189,15 +190,17 @@ struct intel_device_info { #undef DEFINE_FLAG struct { - u8 version; + u8 ver; #define DEFINE_FLAG(name) u8 name:1 DEV_INFO_DISPLAY_FOR_EACH_FLAG(DEFINE_FLAG); #undef DEFINE_FLAG } display; - u16 ddb_size; /* in blocks */ - u8 num_supported_dbuf_slices; /* number of DBuf slices */ + struct { + u16 size; /* in blocks */ + u8 slice_mask; + } dbuf; /* Register offsets for the various display pipes and transcoders */ int pipe_offsets[I915_MAX_TRANSCODERS]; diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/intel_pch.c index 7476f0e063c6..98a17dd1bda4 100644 --- a/drivers/gpu/drm/i915/intel_pch.c +++ b/drivers/gpu/drm/i915/intel_pch.c @@ -130,8 +130,10 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv)); return PCH_JSP; case INTEL_PCH_ADP_DEVICE_ID_TYPE: + case INTEL_PCH_ADP2_DEVICE_ID_TYPE: drm_dbg_kms(&dev_priv->drm, "Found Alder Lake PCH\n"); - drm_WARN_ON(&dev_priv->drm, !IS_ALDERLAKE_S(dev_priv)); + drm_WARN_ON(&dev_priv->drm, !IS_ALDERLAKE_S(dev_priv) && + !IS_ALDERLAKE_P(dev_priv)); return PCH_ADP; default: return PCH_NONE; @@ -161,7 +163,7 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv, * make an educated guess as to which PCH is really there. */ - if (IS_ALDERLAKE_S(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) id = INTEL_PCH_ADP_DEVICE_ID_TYPE; else if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) id = INTEL_PCH_TGP_DEVICE_ID_TYPE; diff --git a/drivers/gpu/drm/i915/intel_pch.h b/drivers/gpu/drm/i915/intel_pch.h index 7318377503b0..e2f3f30c6445 100644 --- a/drivers/gpu/drm/i915/intel_pch.h +++ b/drivers/gpu/drm/i915/intel_pch.h @@ -55,6 +55,7 @@ enum intel_pch { #define INTEL_PCH_JSP_DEVICE_ID_TYPE 0x4D80 #define INTEL_PCH_JSP2_DEVICE_ID_TYPE 0x3880 #define INTEL_PCH_ADP_DEVICE_ID_TYPE 0x7A80 +#define INTEL_PCH_ADP2_DEVICE_ID_TYPE 0x5180 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 066abaa73a06..15d9a64e7b4c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -35,6 +35,7 @@ #include "display/intel_atomic.h" #include "display/intel_atomic_plane.h" #include "display/intel_bw.h" +#include "display/intel_de.h" #include "display/intel_display_types.h" #include "display/intel_fbc.h" #include "display/intel_sprite.h" @@ -2339,7 +2340,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) if (IS_I945GM(dev_priv)) wm_info = &i945_wm_info; - else if (!IS_DISPLAY_VER(dev_priv, 2)) + else if (DISPLAY_VER(dev_priv) != 2) wm_info = &i915_wm_info; else wm_info = &i830_a_wm_info; @@ -2353,7 +2354,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) crtc->base.primary->state->fb; int cpp; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) cpp = 4; else cpp = fb->format->cpp[0]; @@ -2368,7 +2369,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) planea_wm = wm_info->max_wm; } - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) wm_info = &i830_bc_wm_info; fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B); @@ -2380,7 +2381,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc) crtc->base.primary->state->fb; int cpp; - if (IS_DISPLAY_VER(dev_priv, 2)) + if (DISPLAY_VER(dev_priv) == 2) cpp = 4; else cpp = fb->format->cpp[0]; @@ -2967,7 +2968,7 @@ static void intel_fixup_spr_wm_latency(struct drm_i915_private *dev_priv, u16 wm[5]) { /* ILK sprite LP0 latency is 1300 ns */ - if (IS_DISPLAY_VER(dev_priv, 5)) + if (DISPLAY_VER(dev_priv) == 5) wm[0] = 13; } @@ -2975,7 +2976,7 @@ static void intel_fixup_cur_wm_latency(struct drm_i915_private *dev_priv, u16 wm[5]) { /* ILK cursor LP0 latency is 1300 ns */ - if (IS_DISPLAY_VER(dev_priv, 5)) + if (DISPLAY_VER(dev_priv) == 5) wm[0] = 13; } @@ -2994,7 +2995,7 @@ int ilk_wm_max_level(const struct drm_i915_private *dev_priv) static void intel_print_wm_latency(struct drm_i915_private *dev_priv, const char *name, - const u16 wm[8]) + const u16 wm[]) { int level, max_level = ilk_wm_max_level(dev_priv); @@ -3105,7 +3106,7 @@ static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency); intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); - if (IS_DISPLAY_VER(dev_priv, 6)) { + if (DISPLAY_VER(dev_priv) == 6) { snb_wm_latency_quirk(dev_priv); snb_wm_lp3_irq_quirk(dev_priv); } @@ -3354,7 +3355,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv, * What we should check here is whether FBC can be * enabled sometime later. */ - if (IS_DISPLAY_VER(dev_priv, 5) && !merged->fbc_wm_enabled && + if (DISPLAY_VER(dev_priv) == 5 && !merged->fbc_wm_enabled && intel_fbc_is_active(dev_priv)) { for (level = 2; level <= max_level; level++) { struct intel_wm_level *wm = &merged->wm[level]; @@ -3636,16 +3637,16 @@ bool ilk_disable_lp_wm(struct drm_i915_private *dev_priv) u8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *dev_priv) { - int i; - int max_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices; - u8 enabled_slices_mask = 0; + u8 enabled_slices = 0; + enum dbuf_slice slice; - for (i = 0; i < max_slices; i++) { - if (intel_uncore_read(&dev_priv->uncore, DBUF_CTL_S(i)) & DBUF_POWER_STATE) - enabled_slices_mask |= BIT(i); + for_each_dbuf_slice(dev_priv, slice) { + if (intel_uncore_read(&dev_priv->uncore, + DBUF_CTL_S(slice)) & DBUF_POWER_STATE) + enabled_slices |= BIT(slice); } - return enabled_slices_mask; + return enabled_slices; } /* @@ -3654,13 +3655,13 @@ u8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *dev_priv) */ static bool skl_needs_memory_bw_wa(struct drm_i915_private *dev_priv) { - return IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv); + return DISPLAY_VER(dev_priv) == 9; } static bool intel_has_sagv(struct drm_i915_private *dev_priv) { - return (IS_GEN9_BC(dev_priv) || DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) && + return DISPLAY_VER(dev_priv) >= 9 && !IS_LP(dev_priv) && dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED; } @@ -3680,13 +3681,13 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) } drm_dbg(&dev_priv->drm, "Couldn't read SAGV block time!\n"); - } else if (IS_DISPLAY_VER(dev_priv, 11)) { + } else if (DISPLAY_VER(dev_priv) == 11) { dev_priv->sagv_block_time_us = 10; return; - } else if (IS_DISPLAY_VER(dev_priv, 10)) { + } else if (DISPLAY_VER(dev_priv) == 10) { dev_priv->sagv_block_time_us = 20; return; - } else if (IS_DISPLAY_VER(dev_priv, 9)) { + } else if (DISPLAY_VER(dev_priv) == 9) { dev_priv->sagv_block_time_us = 30; return; } else { @@ -4028,22 +4029,10 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state) return 0; } -static int intel_dbuf_size(struct drm_i915_private *dev_priv) -{ - int ddb_size = INTEL_INFO(dev_priv)->ddb_size; - - drm_WARN_ON(&dev_priv->drm, ddb_size == 0); - - if (DISPLAY_VER(dev_priv) < 11) - return ddb_size - 4; /* 4 blocks for bypass path allocation */ - - return ddb_size; -} - static int intel_dbuf_slice_size(struct drm_i915_private *dev_priv) { - return intel_dbuf_size(dev_priv) / - INTEL_INFO(dev_priv)->num_supported_dbuf_slices; + return INTEL_INFO(dev_priv)->dbuf.size / + hweight8(INTEL_INFO(dev_priv)->dbuf.slice_mask); } static void @@ -4062,18 +4051,15 @@ skl_ddb_entry_for_slices(struct drm_i915_private *dev_priv, u8 slice_mask, ddb->end = fls(slice_mask) * slice_size; WARN_ON(ddb->start >= ddb->end); - WARN_ON(ddb->end > intel_dbuf_size(dev_priv)); + WARN_ON(ddb->end > INTEL_INFO(dev_priv)->dbuf.size); } u32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv, const struct skl_ddb_entry *entry) { - u32 slice_mask = 0; - u16 ddb_size = intel_dbuf_size(dev_priv); - u16 num_supported_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices; - u16 slice_size = ddb_size / num_supported_slices; - u16 start_slice; - u16 end_slice; + int slice_size = intel_dbuf_slice_size(dev_priv); + enum dbuf_slice start_slice, end_slice; + u8 slice_mask = 0; if (!skl_ddb_entry_size(entry)) return 0; @@ -4613,9 +4599,9 @@ static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - if (IS_DISPLAY_VER(dev_priv, 12)) + if (DISPLAY_VER(dev_priv) == 12) return tgl_compute_dbuf_slices(pipe, active_pipes); - else if (IS_DISPLAY_VER(dev_priv, 11)) + else if (DISPLAY_VER(dev_priv) == 11) return icl_compute_dbuf_slices(pipe, active_pipes); /* * For anything else just return one slice yet. @@ -4986,7 +4972,7 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, * Wa_1408961008:icl, ehl * Underruns with WM1+ disabled */ - if (IS_DISPLAY_VER(dev_priv, 11) && + if (DISPLAY_VER(dev_priv) == 11 && level == 1 && wm->wm[0].enable) { wm->wm[level].blocks = wm->wm[0].blocks; wm->wm[level].lines = wm->wm[0].lines; @@ -5199,6 +5185,14 @@ static bool skl_wm_has_lines(struct drm_i915_private *dev_priv, int level) return level > 0; } +static int skl_wm_max_lines(struct drm_i915_private *dev_priv) +{ + if (DISPLAY_VER(dev_priv) >= 13) + return 255; + else + return 31; +} + static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, int level, unsigned int latency, @@ -5245,7 +5239,7 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, (wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) { selected_result = method2; } else if (latency >= wp->linetime_us) { - if (IS_DISPLAY_VER(dev_priv, 9)) + if (DISPLAY_VER(dev_priv) == 9) selected_result = min_fixed16(method1, method2); else selected_result = method2; @@ -5258,7 +5252,7 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, lines = div_round_up_fixed16(selected_result, wp->plane_blocks_per_line); - if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) { + if (DISPLAY_VER(dev_priv) == 9) { /* Display WA #1125: skl,bxt,kbl */ if (level == 0 && wp->rc_surface) blocks += fixed16_to_u32_round_up(wp->y_tile_minimum); @@ -5303,7 +5297,7 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, if (!skl_wm_has_lines(dev_priv, level)) lines = 0; - if (lines > 31) { + if (lines > skl_wm_max_lines(dev_priv)) { /* reject it */ result->min_ddb_alloc = U16_MAX; return; @@ -5375,7 +5369,7 @@ static void skl_compute_transition_wm(struct drm_i915_private *dev_priv, * WaDisableTWM:skl,kbl,cfl,bxt * Transition WM are not recommended by HW team for GEN9 */ - if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) + if (DISPLAY_VER(dev_priv) == 9) return; if (DISPLAY_VER(dev_priv) >= 11) @@ -5384,7 +5378,7 @@ static void skl_compute_transition_wm(struct drm_i915_private *dev_priv, trans_min = 14; /* Display WA #1140: glk,cnl */ - if (IS_DISPLAY_VER(dev_priv, 10)) + if (DISPLAY_VER(dev_priv) == 10) trans_amount = 0; else trans_amount = 10; /* This is configurable amount */ @@ -5511,12 +5505,12 @@ static int icl_build_plane_wm(struct intel_crtc_state *crtc_state, struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id]; int ret; - memset(wm, 0, sizeof(*wm)); - /* Watermarks calculated in master */ if (plane_state->planar_slave) return 0; + memset(wm, 0, sizeof(*wm)); + if (plane_state->planar_linked_plane) { const struct drm_framebuffer *fb = plane_state->hw.fb; enum plane_id y_plane_id = plane_state->planar_linked_plane->id; @@ -5599,7 +5593,7 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv, if (level->ignore_lines) val |= PLANE_WM_IGNORE_LINES; val |= level->blocks; - val |= level->lines << PLANE_WM_LINES_SHIFT; + val |= REG_FIELD_PREP(PLANE_WM_LINES_MASK, level->lines); intel_de_write_fw(dev_priv, reg, val); } @@ -5825,10 +5819,10 @@ skl_compute_ddb(struct intel_atomic_state *state) return ret; drm_dbg_kms(&dev_priv->drm, - "Enabled dbuf slices 0x%x -> 0x%x (out of %d dbuf slices)\n", + "Enabled dbuf slices 0x%x -> 0x%x (total dbuf slices 0x%x)\n", old_dbuf_state->enabled_slices, new_dbuf_state->enabled_slices, - INTEL_INFO(dev_priv)->num_supported_dbuf_slices); + INTEL_INFO(dev_priv)->dbuf.slice_mask); } for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { @@ -6207,8 +6201,7 @@ static void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level) level->enable = val & PLANE_WM_EN; level->ignore_lines = val & PLANE_WM_IGNORE_LINES; level->blocks = val & PLANE_WM_BLOCKS_MASK; - level->lines = (val >> PLANE_WM_LINES_SHIFT) & - PLANE_WM_LINES_MASK; + level->lines = REG_FIELD_GET(PLANE_WM_LINES_MASK, val); } void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, @@ -7141,6 +7134,19 @@ static void gen12lp_init_clock_gating(struct drm_i915_private *dev_priv) /* Wa_14011059788:tgl,rkl,adl_s,dg1 */ intel_uncore_rmw(&dev_priv->uncore, GEN10_DFR_RATIO_EN_AND_CHICKEN, 0, DFR_DISABLE); + + /* Wa_14013723622:tgl,rkl,dg1,adl-s */ + if (DISPLAY_VER(dev_priv) == 12) + intel_uncore_rmw(&dev_priv->uncore, CLKREQ_POLICY, + CLKREQ_POLICY_MEM_UP_OVRD, 0); +} + +static void adlp_init_clock_gating(struct drm_i915_private *dev_priv) +{ + gen12lp_init_clock_gating(dev_priv); + + /* Wa_22011091694:adlp */ + intel_de_rmw(dev_priv, GEN9_CLKGATE_DIS_5, 0, DPCE_GATING_DIS); } static void dg1_init_clock_gating(struct drm_i915_private *dev_priv) @@ -7620,7 +7626,9 @@ static void nop_init_clock_gating(struct drm_i915_private *dev_priv) */ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) { - if (IS_DG1(dev_priv)) + if (IS_ALDERLAKE_P(dev_priv)) + dev_priv->display.init_clock_gating = adlp_init_clock_gating; + else if (IS_DG1(dev_priv)) dev_priv->display.init_clock_gating = dg1_init_clock_gating; else if (IS_GEN(dev_priv, 12)) dev_priv->display.init_clock_gating = gen12lp_init_clock_gating; @@ -7689,9 +7697,9 @@ void intel_init_pm(struct drm_i915_private *dev_priv) } else if (HAS_PCH_SPLIT(dev_priv)) { ilk_setup_wm_latency(dev_priv); - if ((IS_DISPLAY_VER(dev_priv, 5) && dev_priv->wm.pri_latency[1] && + if ((DISPLAY_VER(dev_priv) == 5 && dev_priv->wm.pri_latency[1] && dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) || - (!IS_DISPLAY_VER(dev_priv, 5) && dev_priv->wm.pri_latency[0] && + (DISPLAY_VER(dev_priv) != 5 && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm; dev_priv->display.compute_intermediate_wm = @@ -7734,12 +7742,12 @@ void intel_init_pm(struct drm_i915_private *dev_priv) dev_priv->display.update_wm = NULL; } else dev_priv->display.update_wm = pnv_update_wm; - } else if (IS_DISPLAY_VER(dev_priv, 4)) { + } else if (DISPLAY_VER(dev_priv) == 4) { dev_priv->display.update_wm = i965_update_wm; - } else if (IS_DISPLAY_VER(dev_priv, 3)) { + } else if (DISPLAY_VER(dev_priv) == 3) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; - } else if (IS_DISPLAY_VER(dev_priv, 2)) { + } else if (DISPLAY_VER(dev_priv) == 2) { if (INTEL_NUM_PIPES(dev_priv) == 1) { dev_priv->display.update_wm = i845_update_wm; dev_priv->display.get_fifo_size = i845_get_fifo_size; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index 1e4ddd11c12b..183ea2b187fe 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -49,7 +49,7 @@ enum i915_drm_suspend_mode { */ struct intel_runtime_pm { atomic_t wakeref_count; - struct device *kdev; /* points to i915->drm.pdev->dev */ + struct device *kdev; /* points to i915->drm.dev */ bool available; bool suspended; bool irqs_enabled; diff --git a/drivers/gpu/drm/i915/intel_step.c b/drivers/gpu/drm/i915/intel_step.c index 4d71547a5b83..ba9479a67521 100644 --- a/drivers/gpu/drm/i915/intel_step.c +++ b/drivers/gpu/drm/i915/intel_step.c @@ -47,6 +47,13 @@ static const struct intel_step_info adls_revid_step_tbl[] = { [0xC] = { .gt_step = STEP_D0, .display_step = STEP_C0 }, }; +static const struct intel_step_info adlp_revid_step_tbl[] = { + [0x0] = { .gt_step = STEP_A0, .display_step = STEP_A0 }, + [0x4] = { .gt_step = STEP_B0, .display_step = STEP_B0 }, + [0x8] = { .gt_step = STEP_C0, .display_step = STEP_C0 }, + [0xC] = { .gt_step = STEP_C0, .display_step = STEP_D0 }, +}; + void intel_step_init(struct drm_i915_private *i915) { const struct intel_step_info *revids = NULL; @@ -54,7 +61,10 @@ void intel_step_init(struct drm_i915_private *i915) int revid = INTEL_REVID(i915); struct intel_step_info step = {}; - if (IS_ALDERLAKE_S(i915)) { + if (IS_ALDERLAKE_P(i915)) { + revids = adlp_revid_step_tbl; + size = ARRAY_SIZE(adlp_revid_step_tbl); + } else if (IS_ALDERLAKE_S(i915)) { revids = adls_revid_step_tbl; size = ARRAY_SIZE(adls_revid_step_tbl); } else if (IS_TGL_U(i915) || IS_TGL_Y(i915)) { diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 661b50191f2b..ed5abe7be498 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -2008,12 +2008,14 @@ void intel_uncore_fini_mmio(struct intel_uncore *uncore) static const struct reg_whitelist { i915_reg_t offset_ldw; i915_reg_t offset_udw; - u16 gen_mask; + u8 min_graphics_ver; + u8 max_graphics_ver; u8 size; } reg_read_whitelist[] = { { .offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE), .offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE), - .gen_mask = INTEL_GEN_MASK(4, 12), + .min_graphics_ver = 4, + .max_graphics_ver = 12, .size = 8 } }; @@ -2038,7 +2040,7 @@ int i915_reg_read_ioctl(struct drm_device *dev, GEM_BUG_ON(entry->size > 8); GEM_BUG_ON(entry_offset & (entry->size - 1)); - if (INTEL_INFO(i915)->gen_mask & entry->gen_mask && + if (IS_GRAPHICS_VER(i915, entry->min_graphics_ver, entry->max_graphics_ver) && entry_offset == (reg->offset & -entry->size)) break; entry++; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 2e4f06eaacc1..45c6c0107c7c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1106,7 +1106,8 @@ static int igt_ppgtt_shrink_boom(void *arg) return exercise_ppgtt(arg, shrink_boom); } -static int sort_holes(void *priv, struct list_head *A, struct list_head *B) +static int sort_holes(void *priv, const struct list_head *A, + const struct list_head *B) { struct drm_mm_node *a = list_entry(A, typeof(*a), hole_stack); struct drm_mm_node *b = list_entry(B, typeof(*b), hole_stack); diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 0e4e6be0101d..f76c9bcec735 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -125,17 +125,19 @@ static int live_forcewake_ops(void *arg) { static const struct reg { const char *name; + u8 min_graphics_ver; + u8 max_graphics_ver; unsigned long platforms; unsigned int offset; } registers[] = { { "RING_START", - INTEL_GEN_MASK(6, 7), + 6, 7, 0x38, }, { "RING_MI_MODE", - INTEL_GEN_MASK(8, BITS_PER_LONG), + 8, U8_MAX, 0x9c, } }; @@ -170,7 +172,7 @@ static int live_forcewake_ops(void *arg) /* We have to pick carefully to get the exact behaviour we need */ for (r = registers; r->name; r++) - if (r->platforms & INTEL_INFO(gt->i915)->gen_mask) + if (IS_GRAPHICS_VER(gt->i915, r->min_graphics_ver, r->max_graphics_ver)) break; if (!r->name) { pr_debug("Forcewaked register not known for %s; skipping\n", diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 0188f877cab2..cf40004bc92a 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -146,7 +146,6 @@ struct drm_i915_private *mock_gem_device(void) } pci_set_drvdata(pdev, i915); - i915->drm.pdev = pdev; dev_pm_domain_set(&pdev->dev, &pm_domain); pm_runtime_enable(&pdev->dev); @@ -162,7 +161,7 @@ struct drm_i915_private *mock_gem_device(void) /* Using the global GTT may ask questions about KMS users, so prepare */ drm_mode_config_init(&i915->drm); - mkwrite_device_info(i915)->gen = -1; + mkwrite_device_info(i915)->graphics_ver = -1; mkwrite_device_info(i915)->page_sizes = I915_GTT_PAGE_SIZE_4K | diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c index b549ce5e7607..37ae68a7fba5 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-kms.c +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c @@ -52,7 +52,6 @@ static void dcss_kms_mode_config_init(struct dcss_kms_dev *kms) config->min_height = 1; config->max_width = 4096; config->max_height = 4096; - config->allow_fb_modifiers = true; config->normalize_zpos = true; config->funcs = &dcss_drm_mode_config_funcs; diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index e6a88c8cbd69..76819a8ac37f 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -81,6 +81,7 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) struct drm_plane_state *old_plane_state, *new_plane_state; bool plane_disabling = false; int i; + bool fence_cookie = dma_fence_begin_signalling(); drm_atomic_helper_commit_modeset_disables(dev, state); @@ -111,6 +112,7 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) } drm_atomic_helper_commit_hw_done(state); + dma_fence_end_signalling(fence_cookie); } static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { @@ -145,9 +147,26 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = { /* none so far */ }; +static int imx_drm_dumb_create(struct drm_file *file_priv, + struct drm_device *drm, + struct drm_mode_create_dumb *args) +{ + u32 width = args->width; + int ret; + + args->width = ALIGN(width, 8); + + ret = drm_gem_cma_dumb_create(file_priv, drm, args); + if (ret) + return ret; + + args->width = width; + return ret; +} + static const struct drm_driver imx_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(imx_drm_dumb_create), .ioctls = imx_drm_ioctls, .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), .fops = &imx_drm_driver_fops, @@ -210,7 +229,6 @@ static int imx_drm_bind(struct device *dev) drm->mode_config.max_height = 4096; drm->mode_config.funcs = &imx_drm_mode_config_funcs; drm->mode_config.helper_private = &imx_drm_mode_config_helpers; - drm->mode_config.allow_fb_modifiers = true; drm->mode_config.normalize_zpos = true; ret = drmm_mode_config_init(drm); diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index ffdc492c5bc5..53132ddf9587 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -274,6 +274,11 @@ imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder, "%s: mode exceeds 85 MHz pixel clock\n", __func__); } + if (!IS_ALIGNED(mode->hdisplay, 8)) { + dev_warn(ldb->dev, + "%s: hdisplay does not align to 8 byte\n", __func__); + } + if (dual) { serial_clk = 3500UL * mode->clock; imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index e6431a227feb..9c8829f945b2 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -305,10 +305,19 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin; drm_display_mode_to_videomode(mode, &sig_cfg.mode); + if (!IS_ALIGNED(sig_cfg.mode.hactive, 8)) { + unsigned int new_hactive = ALIGN(sig_cfg.mode.hactive, 8); + + dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n", + sig_cfg.mode.hactive, new_hactive); + + sig_cfg.mode.hfront_porch = new_hactive - sig_cfg.mode.hactive; + sig_cfg.mode.hactive = new_hactive; + } ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, mode->flags & DRM_MODE_FLAG_INTERLACE, - imx_crtc_state->bus_format, mode->hdisplay); + imx_crtc_state->bus_format, sig_cfg.mode.hactive); ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); } diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index fa5009705365..8710f55d2579 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -30,12 +30,17 @@ to_ipu_plane_state(struct drm_plane_state *p) return container_of(p, struct ipu_plane_state, base); } +static unsigned int ipu_src_rect_width(const struct drm_plane_state *state) +{ + return ALIGN(drm_rect_width(&state->src) >> 16, 8); +} + static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) { return container_of(p, struct ipu_plane, base); } -static const uint32_t ipu_plane_formats[] = { +static const uint32_t ipu_plane_all_formats[] = { DRM_FORMAT_ARGB1555, DRM_FORMAT_XRGB1555, DRM_FORMAT_ABGR1555, @@ -72,6 +77,31 @@ static const uint32_t ipu_plane_formats[] = { DRM_FORMAT_BGRX8888_A8, }; +static const uint32_t ipu_plane_rgb_formats[] = { + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGRA5551, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB565_A8, + DRM_FORMAT_BGR565_A8, + DRM_FORMAT_RGB888_A8, + DRM_FORMAT_BGR888_A8, + DRM_FORMAT_RGBX8888_A8, + DRM_FORMAT_BGRX8888_A8, +}; + static const uint64_t ipu_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID @@ -264,7 +294,6 @@ void ipu_plane_disable_deferred(struct drm_plane *plane) ipu_plane_disable(ipu_plane, false); } } -EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred); static void ipu_plane_state_reset(struct drm_plane *plane) { @@ -284,6 +313,8 @@ static void ipu_plane_state_reset(struct drm_plane *plane) __drm_atomic_helper_plane_reset(plane, &ipu_state->base); ipu_state->base.zpos = zpos; ipu_state->base.normalized_zpos = zpos; + ipu_state->base.color_encoding = DRM_COLOR_YCBCR_BT601; + ipu_state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; } } @@ -320,10 +351,11 @@ static bool ipu_plane_format_mod_supported(struct drm_plane *plane, if (modifier == DRM_FORMAT_MOD_LINEAR) return true; - /* without a PRG there are no supported modifiers */ - if (!ipu_prg_present(ipu)) - return false; - + /* + * Without a PRG the possible modifiers list only includes the linear + * modifier, so we always take the early return from this function and + * only end up here if the PRG is present. + */ return ipu_prg_format_supported(ipu, format, modifier); } @@ -415,6 +447,12 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, if (old_fb && fb->pitches[0] != old_fb->pitches[0]) crtc_state->mode_changed = true; + if (ALIGN(fb->width, 8) * fb->format->cpp[0] > + fb->pitches[0] + fb->offsets[0]) { + dev_warn(dev, "pitch is not big enough for 8 pixels alignment"); + return -EINVAL; + } + switch (fb->format->format) { case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: @@ -590,12 +628,31 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, if (ipu_state->use_pre) { axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, - drm_rect_width(&new_state->src) >> 16, + ipu_src_rect_width(new_state), drm_rect_height(&new_state->src) >> 16, fb->pitches[0], fb->format->format, fb->modifier, &eba); } + if (!old_state->fb || + old_state->fb->format->format != fb->format->format || + old_state->color_encoding != new_state->color_encoding || + old_state->color_range != new_state->color_range) { + ics = ipu_drm_fourcc_to_colorspace(fb->format->format); + switch (ipu_plane->dp_flow) { + case IPU_DP_FLOW_SYNC_BG: + ipu_dp_setup_channel(ipu_plane->dp, new_state->color_encoding, + new_state->color_range, ics, + IPUV3_COLORSPACE_RGB); + break; + case IPU_DP_FLOW_SYNC_FG: + ipu_dp_setup_channel(ipu_plane->dp, new_state->color_encoding, + new_state->color_range, ics, + IPUV3_COLORSPACE_UNKNOWN); + break; + } + } + if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { /* nothing to do if PRE is used */ if (ipu_state->use_pre) @@ -615,17 +672,20 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ics = ipu_drm_fourcc_to_colorspace(fb->format->format); switch (ipu_plane->dp_flow) { case IPU_DP_FLOW_SYNC_BG: - ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB); + ipu_dp_setup_channel(ipu_plane->dp, DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE, ics, + IPUV3_COLORSPACE_RGB); break; case IPU_DP_FLOW_SYNC_FG: - ipu_dp_setup_channel(ipu_plane->dp, ics, - IPUV3_COLORSPACE_UNKNOWN); + ipu_dp_setup_channel(ipu_plane->dp, DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE, ics, + IPUV3_COLORSPACE_UNKNOWN); break; } ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst)); - width = drm_rect_width(&new_state->src) >> 16; + width = ipu_src_rect_width(new_state); height = drm_rect_height(&new_state->src) >> 16; info = drm_format_info(fb->format->format); ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], @@ -690,7 +750,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_zero(ipu_plane->alpha_ch); ipu_cpmem_set_resolution(ipu_plane->alpha_ch, - drm_rect_width(&new_state->src) >> 16, + ipu_src_rect_width(new_state), drm_rect_height(&new_state->src) >> 16); ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8); ipu_cpmem_set_high_priority(ipu_plane->alpha_ch); @@ -821,7 +881,6 @@ int ipu_planes_assign_pre(struct drm_device *dev, return 0; } -EXPORT_SYMBOL_GPL(ipu_planes_assign_pre); struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, int dma, int dp, unsigned int possible_crtcs, @@ -830,16 +889,28 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, struct ipu_plane *ipu_plane; const uint64_t *modifiers = ipu_format_modifiers; unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1; + unsigned int format_count; + const uint32_t *formats; int ret; DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", dma, dp, possible_crtcs); + if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) { + formats = ipu_plane_all_formats; + format_count = ARRAY_SIZE(ipu_plane_all_formats); + } else { + formats = ipu_plane_rgb_formats; + format_count = ARRAY_SIZE(ipu_plane_rgb_formats); + } + + if (ipu_prg_present(ipu)) + modifiers = pre_format_modifiers; + ipu_plane = drmm_universal_plane_alloc(dev, struct ipu_plane, base, possible_crtcs, &ipu_plane_funcs, - ipu_plane_formats, - ARRAY_SIZE(ipu_plane_formats), - modifiers, type, NULL); + formats, format_count, modifiers, + type, NULL); if (IS_ERR(ipu_plane)) { DRM_ERROR("failed to allocate and initialize %s plane\n", zpos ? "overlay" : "primary"); @@ -850,9 +921,6 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - if (ipu_prg_present(ipu)) - modifiers = pre_format_modifiers; - drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) @@ -864,6 +932,15 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, if (ret) return ERR_PTR(ret); + ret = drm_plane_create_color_properties(&ipu_plane->base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return ERR_PTR(ret); + ret = ipu_plane_get_resources(dev, ipu_plane); if (ret) { DRM_ERROR("failed to get %s plane resources: %pe\n", diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 29742ec5ab95..09225b770bb8 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -419,7 +419,7 @@ static void ingenic_drm_plane_enable(struct ingenic_drm *priv, unsigned int en_bit; if (priv->soc_info->has_osd) { - if (plane->type == DRM_PLANE_TYPE_PRIMARY) + if (plane != &priv->f0) en_bit = JZ_LCD_OSDC_F1EN; else en_bit = JZ_LCD_OSDC_F0EN; @@ -434,7 +434,7 @@ void ingenic_drm_plane_disable(struct device *dev, struct drm_plane *plane) unsigned int en_bit; if (priv->soc_info->has_osd) { - if (plane->type == DRM_PLANE_TYPE_PRIMARY) + if (plane != &priv->f0) en_bit = JZ_LCD_OSDC_F1EN; else en_bit = JZ_LCD_OSDC_F0EN; @@ -461,8 +461,7 @@ void ingenic_drm_plane_config(struct device *dev, ingenic_drm_plane_enable(priv, plane); - if (priv->soc_info->has_osd && - plane->type == DRM_PLANE_TYPE_PRIMARY) { + if (priv->soc_info->has_osd && plane != &priv->f0) { switch (fourcc) { case DRM_FORMAT_XRGB1555: ctrl |= JZ_LCD_OSDCTRL_RGB555; @@ -510,7 +509,7 @@ void ingenic_drm_plane_config(struct device *dev, } if (priv->soc_info->has_osd) { - if (plane->type == DRM_PLANE_TYPE_PRIMARY) { + if (plane != &priv->f0) { xy_reg = JZ_REG_LCD_XYP1; size_reg = JZ_REG_LCD_SIZE1; } else { @@ -561,7 +560,7 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, height = newstate->src_h >> 16; cpp = newstate->fb->format->cpp[0]; - if (!priv->soc_info->has_osd || plane->type == DRM_PLANE_TYPE_OVERLAY) + if (!priv->soc_info->has_osd || plane == &priv->f0) hwdesc = &priv->dma_hwdescs->hwdesc_f0; else hwdesc = &priv->dma_hwdescs->hwdesc_f1; diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c index 5ae6adab8306..3b1091e7c0cd 100644 --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c @@ -767,7 +767,7 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d) err = drm_universal_plane_init(drm, plane, 1, &ingenic_ipu_plane_funcs, soc_info->formats, soc_info->num_formats, - NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + NULL, DRM_PLANE_TYPE_OVERLAY, NULL); if (err) { dev_err(dev, "Failed to init plane: %i\n", err); return err; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 4b5d82af84b3..231041b269f5 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -281,7 +281,7 @@ static u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, default: DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL; - }; + } break; case DSI_LP_DT_PPS_YCBCR422_16B: data_type_param.size_constraint_pixels = 2; @@ -301,7 +301,7 @@ static u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, default: DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL; - }; + } break; case DSI_LP_DT_LPPS_YCBCR422_20B: case DSI_LP_DT_PPS_YCBCR422_24B: @@ -318,7 +318,7 @@ static u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, default: DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL; - }; + } break; case DSI_LP_DT_PPS_RGB565_16B: data_type_param.size_constraint_pixels = 1; @@ -337,7 +337,7 @@ static u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, default: DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL; - }; + } break; case DSI_LP_DT_PPS_RGB666_18B: data_type_param.size_constraint_pixels = 4; @@ -361,7 +361,7 @@ static u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, default: DRM_ERROR("DSI: Invalid data_type %d\n", data_type); return -EINVAL; - }; + } *params = data_type_param; return 0; diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c index 4f64940b9055..8989e215dfc9 100644 --- a/drivers/gpu/drm/lima/lima_devfreq.c +++ b/drivers/gpu/drm/lima/lima_devfreq.c @@ -100,20 +100,12 @@ void lima_devfreq_fini(struct lima_device *ldev) devm_devfreq_remove_device(ldev->dev, devfreq->devfreq); devfreq->devfreq = NULL; } - - dev_pm_opp_of_remove_table(ldev->dev); - - dev_pm_opp_put_regulators(devfreq->regulators_opp_table); - dev_pm_opp_put_clkname(devfreq->clkname_opp_table); - devfreq->regulators_opp_table = NULL; - devfreq->clkname_opp_table = NULL; } int lima_devfreq_init(struct lima_device *ldev) { struct thermal_cooling_device *cooling; struct device *dev = ldev->dev; - struct opp_table *opp_table; struct devfreq *devfreq; struct lima_devfreq *ldevfreq = &ldev->devfreq; struct dev_pm_opp *opp; @@ -126,40 +118,28 @@ int lima_devfreq_init(struct lima_device *ldev) spin_lock_init(&ldevfreq->lock); - opp_table = dev_pm_opp_set_clkname(dev, "core"); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); - goto err_fini; - } - - ldevfreq->clkname_opp_table = opp_table; - - opp_table = dev_pm_opp_set_regulators(dev, - (const char *[]){ "mali" }, - 1); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); + ret = devm_pm_opp_set_clkname(dev, "core"); + if (ret) + return ret; + ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1); + if (ret) { /* Continue if the optional regulator is missing */ if (ret != -ENODEV) - goto err_fini; - } else { - ldevfreq->regulators_opp_table = opp_table; + return ret; } - ret = dev_pm_opp_of_add_table(dev); + ret = devm_pm_opp_of_add_table(dev); if (ret) - goto err_fini; + return ret; lima_devfreq_reset(ldevfreq); cur_freq = clk_get_rate(ldev->clk_gpu); opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) { - ret = PTR_ERR(opp); - goto err_fini; - } + if (IS_ERR(opp)) + return PTR_ERR(opp); lima_devfreq_profile.initial_freq = cur_freq; dev_pm_opp_put(opp); @@ -176,8 +156,7 @@ int lima_devfreq_init(struct lima_device *ldev) &ldevfreq->gov_data); if (IS_ERR(devfreq)) { dev_err(dev, "Couldn't initialize GPU devfreq\n"); - ret = PTR_ERR(devfreq); - goto err_fini; + return PTR_ERR(devfreq); } ldevfreq->devfreq = devfreq; @@ -189,10 +168,6 @@ int lima_devfreq_init(struct lima_device *ldev) ldevfreq->cooling = cooling; return 0; - -err_fini: - lima_devfreq_fini(ldev); - return ret; } void lima_devfreq_record_busy(struct lima_devfreq *devfreq) diff --git a/drivers/gpu/drm/lima/lima_devfreq.h b/drivers/gpu/drm/lima/lima_devfreq.h index b0c7c736e81a..b8e50feaeab6 100644 --- a/drivers/gpu/drm/lima/lima_devfreq.h +++ b/drivers/gpu/drm/lima/lima_devfreq.h @@ -9,15 +9,12 @@ #include <linux/ktime.h> struct devfreq; -struct opp_table; struct thermal_cooling_device; struct lima_device; struct lima_devfreq { struct devfreq *devfreq; - struct opp_table *clkname_opp_table; - struct opp_table *regulators_opp_table; struct thermal_cooling_device *cooling; struct devfreq_simple_ondemand_data gov_data; diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 453d8b4c5763..66de3f4f7222 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/soc/amlogic/meson-canvas.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> @@ -156,23 +157,6 @@ static void meson_vpu_init(struct meson_drm *priv) writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } -static void meson_remove_framebuffers(void) -{ - struct apertures_struct *ap; - - ap = alloc_apertures(1); - if (!ap) - return; - - /* The framebuffer can be located anywhere in RAM */ - ap->ranges[0].base = 0; - ap->ranges[0].size = ~0; - - drm_fb_helper_remove_conflicting_framebuffers(ap, "meson-drm-fb", - false); - kfree(ap); -} - struct meson_drm_soc_attr { struct meson_drm_soc_limits limits; const struct soc_device_attribute *attrs; @@ -297,8 +281,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) } } - /* Remove early framebuffers (ie. simplefb) */ - meson_remove_framebuffers(); + /* + * Remove early framebuffers (ie. simplefb). The framebuffer can be + * located anywhere in RAM + */ + ret = drm_aperture_remove_framebuffers(false, "meson-drm-fb"); + if (ret) + goto free_drm; ret = drmm_mode_config_init(drm); if (ret) diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index aad75a22dc33..2ed87cfdd735 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -1103,6 +1103,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, dw_plat_data->phy_data = meson_dw_hdmi; dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; dw_plat_data->ycbcr_420_allowed = true; + dw_plat_data->disable_cec = true; if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index 1cb7d120d18f..403efc1f1a7c 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -389,6 +389,7 @@ int mga_freelist_put(struct drm_device *dev, struct drm_buf *buf) int mga_driver_load(struct drm_device *dev, unsigned long flags) { + struct pci_dev *pdev = to_pci_dev(dev->dev); drm_mga_private_t *dev_priv; int ret; @@ -400,9 +401,9 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags) * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the * device. */ - if ((dev->pdev->device == 0x0525) && dev->pdev->bus->self - && (dev->pdev->bus->self->vendor == 0x3388) - && (dev->pdev->bus->self->device == 0x0021) + if ((pdev->device == 0x0525) && pdev->bus->self + && (pdev->bus->self->vendor == 0x3388) + && (pdev->bus->self->device == 0x0021) && dev->agp) { /* FIXME: This should be quirked in the pci core, but oh well * the hw probably stopped existing. */ @@ -419,10 +420,10 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; dev_priv->chipset = flags; - pci_set_master(dev->pdev); + pci_set_master(pdev); - dev_priv->mmio_base = pci_resource_start(dev->pdev, 1); - dev_priv->mmio_size = pci_resource_len(dev->pdev, 1); + dev_priv->mmio_base = pci_resource_start(pdev, 1); + dev_priv->mmio_size = pci_resource_len(pdev, 1); ret = drm_vblank_init(dev, 1); @@ -468,20 +469,20 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev, struct drm_agp_binding bind_req; /* Acquire AGP. */ - err = drm_agp_acquire(dev); + err = drm_legacy_agp_acquire(dev); if (err) { DRM_ERROR("Unable to acquire AGP: %d\n", err); return err; } - err = drm_agp_info(dev, &info); + err = drm_legacy_agp_info(dev, &info); if (err) { DRM_ERROR("Unable to get AGP info: %d\n", err); return err; } mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode; - err = drm_agp_enable(dev, mode); + err = drm_legacy_agp_enable(dev, mode); if (err) { DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); return err; @@ -501,7 +502,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev, /* Allocate and bind AGP memory. */ agp_req.size = agp_size; agp_req.type = 0; - err = drm_agp_alloc(dev, &agp_req); + err = drm_legacy_agp_alloc(dev, &agp_req); if (err) { dev_priv->agp_size = 0; DRM_ERROR("Unable to allocate %uMB AGP memory\n", @@ -514,7 +515,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev, bind_req.handle = agp_req.handle; bind_req.offset = 0; - err = drm_agp_bind(dev, &bind_req); + err = drm_legacy_agp_bind(dev, &bind_req); if (err) { DRM_ERROR("Unable to bind AGP memory: %d\n", err); return err; @@ -971,10 +972,10 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup) struct drm_agp_buffer free_req; unbind_req.handle = dev_priv->agp_handle; - drm_agp_unbind(dev, &unbind_req); + drm_legacy_agp_unbind(dev, &unbind_req); free_req.handle = dev_priv->agp_handle; - drm_agp_free(dev, &free_req); + drm_legacy_agp_free(dev, &free_req); dev_priv->agp_textures = NULL; dev_priv->agp_size = 0; @@ -982,7 +983,7 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup) } if ((dev->agp != NULL) && dev->agp->acquired) - err = drm_agp_release(dev); + err = drm_legacy_agp_release(dev); #endif } diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index 66df51607896..84395d81ab9b 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h @@ -35,7 +35,6 @@ #include <linux/pci.h> #include <linux/slab.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c index 0dec4062e5a2..5b7247b58451 100644 --- a/drivers/gpu/drm/mga/mga_state.c +++ b/drivers/gpu/drm/mga/mga_state.c @@ -1005,6 +1005,7 @@ int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_getparam_t *param = data; + struct pci_dev *pdev = to_pci_dev(dev->dev); int value; if (!dev_priv) { @@ -1016,7 +1017,7 @@ int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) switch (param->param) { case MGA_PARAM_IRQ_NR: - value = dev->pdev->irq; + value = pdev->irq; break; case MGA_PARAM_CARD_TYPE: value = dev_priv->chipset; diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 4e4c105f9a50..a701d9563257 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -11,6 +11,7 @@ #include <linux/pci.h> #include <linux/vmalloc.h> +#include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> @@ -341,7 +342,9 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *dev; int ret; - drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb"); + if (ret) + return ret; ret = pcim_enable_device(pdev); if (ret) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index cece3e57fb27..9d576240faed 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1554,7 +1554,7 @@ mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, { void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ - drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip); + drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip); /* Always scanout image at VRAM offset 0 */ mgag200_set_startadd(mdev, (u32)0); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index d553f62f4eeb..b4d8e1b01ee4 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1153,10 +1153,6 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, { struct device_node *phandle; - a6xx_gpu->llc_mmio = msm_ioremap(pdev, "cx_mem", "gpu_cx"); - if (IS_ERR(a6xx_gpu->llc_mmio)) - return; - /* * There is a different programming path for targets with an mmu500 * attached, so detect if that is the case @@ -1166,6 +1162,11 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, of_device_is_compatible(phandle, "arm,mmu-500")); of_node_put(phandle); + if (a6xx_gpu->have_mmu500) + a6xx_gpu->llc_mmio = NULL; + else + a6xx_gpu->llc_mmio = msm_ioremap(pdev, "cx_mem", "gpu_cx"); + a6xx_gpu->llc_slice = llcc_slice_getd(LLCC_GPU); a6xx_gpu->htw_llc_slice = llcc_slice_getd(LLCC_GPUHTW); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 6a35a30dd281..cf897297656f 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -188,10 +188,7 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) void adreno_set_llc_attributes(struct iommu_domain *iommu) { - struct io_pgtable_domain_attr pgtbl_cfg; - - pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_ARM_OUTER_WBWA; - iommu_domain_set_attr(iommu, DOMAIN_ATTR_IO_PGTABLE_CFG, &pgtbl_cfg); + iommu_set_pgtable_quirks(iommu, IO_PGTABLE_QUIRK_ARM_OUTER_WBWA); } struct msm_gem_address_space * diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 7c29976be243..18bc76b7f1a3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -648,16 +648,6 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, if (unlikely(!cstate->num_mixers)) return; - /* - * For planes without commit update, drm framework will not add - * those planes to current state since hardware update is not - * required. However, if those planes were power collapsed since - * last commit cycle, driver has to restore the hardware state - * of those planes explicitly here prior to plane flush. - */ - drm_atomic_crtc_for_each_plane(plane, crtc) - dpu_plane_restore(plane, state); - /* update performance setting before crtc kickoff */ dpu_core_perf_crtc_update(crtc, 1, false); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 88e9cc38c13b..93bc3575bf53 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1020,11 +1020,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms->catalog->caps->max_mixer_width * 2; dev->mode_config.max_height = 4096; - /* - * Support format modifiers for compression etc. - */ - dev->mode_config.allow_fb_modifiers = true; - dev->max_vblank_count = 0xffffffff; /* Disable vblank irqs aggressively for power-saving */ dev->vblank_disable_immediate = true; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index df7f3d3afd8b..7a993547eb75 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1258,22 +1258,6 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, } } -void dpu_plane_restore(struct drm_plane *plane, struct drm_atomic_state *state) -{ - struct dpu_plane *pdpu; - - if (!plane || !plane->state) { - DPU_ERROR("invalid plane\n"); - return; - } - - pdpu = to_dpu_plane(plane); - - DPU_DEBUG_PLANE(pdpu, "\n"); - - dpu_plane_atomic_update(plane, state); -} - static void dpu_plane_destroy(struct drm_plane *plane) { struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index 03b6365a750c..34e03ac05f4a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -85,12 +85,6 @@ void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl, u32 *flush_sspp); /** - * dpu_plane_restore - restore hw state if previously power collapsed - * @plane: Pointer to drm plane structure - */ -void dpu_plane_restore(struct drm_plane *plane, struct drm_atomic_state *state); - -/** * dpu_plane_flush - final plane operations before commit flush * @plane: Pointer to drm plane structure */ diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 3d729270bde1..4a5b518288b0 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -88,8 +88,6 @@ static int mdp4_hw_init(struct msm_kms *kms) if (mdp4_kms->rev > 1) mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1); - dev->mode_config.allow_fb_modifiers = true; - out: pm_runtime_put_sync(dev->dev); diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index 9aecca919f24..49bdabea8ed5 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c @@ -349,6 +349,12 @@ enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane) return mdp4_plane->pipe; } +static const uint64_t supported_format_modifiers[] = { + DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + /* initialize plane */ struct drm_plane *mdp4_plane_init(struct drm_device *dev, enum mdp4_pipe pipe_id, bool private_plane) @@ -377,7 +383,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs, mdp4_plane->formats, mdp4_plane->nformats, - NULL, type, NULL); + supported_format_modifiers, type, NULL); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c index 82a8673ab8da..d7e4a39a904e 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.c +++ b/drivers/gpu/drm/msm/dp/dp_audio.c @@ -527,6 +527,7 @@ int dp_audio_hw_params(struct device *dev, dp_audio_setup_acr(audio); dp_audio_safe_to_exit_level(audio); dp_audio_enable(audio, true); + dp_display_signal_audio_start(dp_display); dp_display->audio_enabled = true; end: diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 1390f3547fde..2cebd17a7289 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1103,7 +1103,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, tries = 0; old_v_level = ctrl->link->phy_params.v_level; for (tries = 0; tries < maximum_retries; tries++) { - drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd); + drm_dp_link_train_clock_recovery_delay(ctrl->aux, ctrl->panel->dpcd); ret = dp_ctrl_read_link_status(ctrl, link_status); if (ret) @@ -1184,7 +1184,7 @@ static int dp_ctrl_link_lane_down_shift(struct dp_ctrl_private *ctrl) static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) { dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE); - drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); + drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); } static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, @@ -1215,7 +1215,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); for (tries = 0; tries <= maximum_retries; tries++) { - drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); + drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); ret = dp_ctrl_read_link_status(ctrl, link_status); if (ret) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 5a39da6e1eaf..1784e119269b 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -178,6 +178,15 @@ static int dp_del_event(struct dp_display_private *dp_priv, u32 event) return 0; } +void dp_display_signal_audio_start(struct msm_dp *dp_display) +{ + struct dp_display_private *dp; + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + reinit_completion(&dp->audio_comp); +} + void dp_display_signal_audio_complete(struct msm_dp *dp_display) { struct dp_display_private *dp; @@ -586,10 +595,8 @@ static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) mutex_lock(&dp->event_mutex); state = dp->hpd_state; - if (state == ST_CONNECT_PENDING) { - dp_display_enable(dp, 0); + if (state == ST_CONNECT_PENDING) dp->hpd_state = ST_CONNECTED; - } mutex_unlock(&dp->event_mutex); @@ -651,7 +658,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); /* signal the disconnect event early to ensure proper teardown */ - reinit_completion(&dp->audio_comp); dp_display_handle_plugged_change(g_dp_display, false); dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | @@ -669,10 +675,8 @@ static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data mutex_lock(&dp->event_mutex); state = dp->hpd_state; - if (state == ST_DISCONNECT_PENDING) { - dp_display_disable(dp, 0); + if (state == ST_DISCONNECT_PENDING) dp->hpd_state = ST_DISCONNECTED; - } mutex_unlock(&dp->event_mutex); @@ -898,7 +902,6 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data) /* wait only if audio was enabled */ if (dp_display->audio_enabled) { /* signal the disconnect event */ - reinit_completion(&dp->audio_comp); dp_display_handle_plugged_change(dp_display, false); if (!wait_for_completion_timeout(&dp->audio_comp, HZ * 5)) @@ -1272,7 +1275,12 @@ static int dp_pm_resume(struct device *dev) status = dp_catalog_link_is_connected(dp->catalog); - if (status) + /* + * can not declared display is connected unless + * HDMI cable is plugged in and sink_count of + * dongle become 1 + */ + if (status && dp->link->sink_count) dp->dp_display.is_connected = true; else dp->dp_display.is_connected = false; diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 6092ba1ed85e..5173c89eedf7 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -34,6 +34,7 @@ int dp_display_get_modes(struct msm_dp *dp_display, int dp_display_request_irq(struct msm_dp *dp_display); bool dp_display_check_video_test(struct msm_dp *dp_display); int dp_display_get_test_bpp(struct msm_dp *dp_display); +void dp_display_signal_audio_start(struct msm_dp *dp_display); void dp_display_signal_audio_complete(struct msm_dp *dp_display); #endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index f0a2ddf96a4b..ff7f2ec42030 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -843,7 +843,7 @@ int msm_dsi_phy_get_clk_provider(struct msm_dsi_phy *phy, if (pixel_clk_provider) *pixel_clk_provider = phy->provided_clocks->hws[DSI_PIXEL_PLL_CLK]->clk; - return -EINVAL; + return 0; } void msm_dsi_phy_pll_save_state(struct msm_dsi_phy *phy) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index 582b1428f971..86e40a0d41a3 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -405,6 +405,10 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov if (!vco_name) return -ENOMEM; + parent_name = devm_kzalloc(dev, 32, GFP_KERNEL); + if (!parent_name) + return -ENOMEM; + clk_name = devm_kzalloc(dev, 32, GFP_KERNEL); if (!clk_name) return -ENOMEM; diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h index eb34243dad53..8590f2ce274d 100644 --- a/drivers/gpu/drm/msm/edp/edp.h +++ b/drivers/gpu/drm/msm/edp/edp.h @@ -46,8 +46,7 @@ void edp_bridge_destroy(struct drm_bridge *bridge); struct drm_connector *msm_edp_connector_init(struct msm_edp *edp); /* AUX */ -void *msm_edp_aux_init(struct device *dev, void __iomem *regbase, - struct drm_dp_aux **drm_aux); +void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux); void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux); irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr); void msm_edp_aux_ctrl(struct edp_aux *aux, int enable); diff --git a/drivers/gpu/drm/msm/edp/edp_aux.c b/drivers/gpu/drm/msm/edp/edp_aux.c index df10a0196d94..e3d85c622cfb 100644 --- a/drivers/gpu/drm/msm/edp/edp_aux.c +++ b/drivers/gpu/drm/msm/edp/edp_aux.c @@ -184,9 +184,9 @@ unlock_exit: return ret; } -void *msm_edp_aux_init(struct device *dev, void __iomem *regbase, - struct drm_dp_aux **drm_aux) +void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux) { + struct device *dev = &edp->pdev->dev; struct edp_aux *aux = NULL; int ret; @@ -201,6 +201,7 @@ void *msm_edp_aux_init(struct device *dev, void __iomem *regbase, aux->drm_aux.name = "msm_edp_aux"; aux->drm_aux.dev = dev; + aux->drm_aux.drm_dev = edp->dev; aux->drm_aux.transfer = edp_aux_transfer; ret = drm_dp_aux_register(&aux->drm_aux); if (ret) { diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 0d9657cc70db..4fb397ee7c84 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -608,7 +608,7 @@ static int edp_start_link_train_1(struct edp_ctrl *ctrl) tries = 0; old_v_level = ctrl->v_level; while (1) { - drm_dp_link_train_clock_recovery_delay(ctrl->dpcd); + drm_dp_link_train_clock_recovery_delay(ctrl->drm_aux, ctrl->dpcd); rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); if (rlen < DP_LINK_STATUS_SIZE) { @@ -665,7 +665,7 @@ static int edp_start_link_train_2(struct edp_ctrl *ctrl) return ret; while (1) { - drm_dp_link_train_channel_eq_delay(ctrl->dpcd); + drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); if (rlen < DP_LINK_STATUS_SIZE) { @@ -743,7 +743,7 @@ static int edp_clear_training_pattern(struct edp_ctrl *ctrl) ret = edp_train_pattern_set_write(ctrl, 0); - drm_dp_link_train_channel_eq_delay(ctrl->dpcd); + drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); return ret; } @@ -1153,7 +1153,7 @@ int msm_edp_ctrl_init(struct msm_edp *edp) } /* Init aux and phy */ - ctrl->aux = msm_edp_aux_init(dev, ctrl->base, &ctrl->drm_aux); + ctrl->aux = msm_edp_aux_init(edp, ctrl->base, &ctrl->drm_aux); if (!ctrl->aux || !ctrl->drm_aux) { pr_err("%s:failed to init aux\n", __func__); return -ENOMEM; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e1104d2454e2..fe7d17cd35ec 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -42,7 +42,7 @@ * - 1.7.0 - Add MSM_PARAM_SUSPENDS to access suspend count */ #define MSM_VERSION_MAJOR 1 -#define MSM_VERSION_MINOR 6 +#define MSM_VERSION_MINOR 7 #define MSM_VERSION_PATCHLEVEL 0 static const struct drm_mode_config_funcs mode_config_funcs = { diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 678dba1725a6..227404077e39 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -4,6 +4,7 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <drm/drm_aperture.h> #include <drm/drm_crtc.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> @@ -168,7 +169,9 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) } /* the fw fb could be anywhere in memory */ - drm_fb_helper_remove_conflicting_framebuffers(NULL, "msm", false); + ret = drm_aperture_remove_framebuffers(false, "msm"); + if (ret) + goto fini; ret = drm_fb_helper_initial_config(helper, 32); if (ret) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index b199942266a2..56df86e5f740 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -190,13 +190,25 @@ struct page **msm_gem_get_pages(struct drm_gem_object *obj) } p = get_pages(obj); + + if (!IS_ERR(p)) { + msm_obj->pin_count++; + update_inactive(msm_obj); + } + msm_gem_unlock(obj); return p; } void msm_gem_put_pages(struct drm_gem_object *obj) { - /* when we start tracking the pin count, then do something here */ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + msm_gem_lock(obj); + msm_obj->pin_count--; + GEM_WARN_ON(msm_obj->pin_count < 0); + update_inactive(msm_obj); + msm_gem_unlock(obj); } int msm_gem_mmap_obj(struct drm_gem_object *obj, @@ -646,6 +658,8 @@ static void *get_vaddr(struct drm_gem_object *obj, unsigned madv) ret = -ENOMEM; goto fail; } + + update_inactive(msm_obj); } return msm_obj->vaddr; diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index a6480d2c81b2..03e2cc2a2ce1 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -221,7 +221,7 @@ static inline bool is_active(struct msm_gem_object *msm_obj) /* imported/exported objects are not purgeable: */ static inline bool is_unpurgeable(struct msm_gem_object *msm_obj) { - return msm_obj->base.dma_buf && msm_obj->base.import_attach; + return msm_obj->base.import_attach || msm_obj->pin_count; } static inline bool is_purgeable(struct msm_gem_object *msm_obj) @@ -271,7 +271,7 @@ static inline void mark_unpurgeable(struct msm_gem_object *msm_obj) static inline bool is_unevictable(struct msm_gem_object *msm_obj) { - return is_unpurgeable(msm_obj) || msm_obj->pin_count || msm_obj->vaddr; + return is_unpurgeable(msm_obj) || msm_obj->vaddr; } static inline void mark_evictable(struct msm_gem_object *msm_obj) diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig index 0143d539f8f8..ee22cd25d3e3 100644 --- a/drivers/gpu/drm/mxsfb/Kconfig +++ b/drivers/gpu/drm/mxsfb/Kconfig @@ -10,7 +10,6 @@ config DRM_MXSFB depends on COMMON_CLK select DRM_MXS select DRM_KMS_HELPER - select DRM_KMS_FB_HELPER select DRM_KMS_CMA_HELPER select DRM_PANEL select DRM_PANEL_BRIDGE diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 1c9c0cdf85db..c46d0374b6e6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1617,7 +1617,8 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, mstm->mgr.cbs = &nv50_mstm; ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max, - max_payloads, conn_base_id); + (u8)max_payloads, outp->dcb->dpconf.link_nr, + (u8)outp->dcb->dpconf.link_bw, conn_base_id); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 3e09df0472ce..7a2624c0ba4c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -302,7 +302,6 @@ nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 domain, int type = sg ? ttm_bo_type_sg : ttm_bo_type_device; int ret; - nvbo->bo.mem.num_pages = size >> PAGE_SHIFT; nouveau_bo_placement_set(nvbo, domain, 0); INIT_LIST_HEAD(&nvbo->io_reserve_lru); @@ -364,12 +363,12 @@ static void set_placement_range(struct nouveau_bo *nvbo, uint32_t domain) { struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); - u32 vram_pages = drm->client.device.info.ram_size >> PAGE_SHIFT; + u64 vram_size = drm->client.device.info.ram_size; unsigned i, fpfn, lpfn; if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS && nvbo->mode && (domain & NOUVEAU_GEM_DOMAIN_VRAM) && - nvbo->bo.mem.num_pages < vram_pages / 4) { + nvbo->bo.base.size < vram_size / 4) { /* * Make sure that the color and depth buffers are handled * by independent memory controller units. Up to a 9x @@ -377,11 +376,11 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t domain) * at the same time. */ if (nvbo->zeta) { - fpfn = vram_pages / 2; + fpfn = (vram_size / 2) >> PAGE_SHIFT; lpfn = ~0; } else { fpfn = 0; - lpfn = vram_pages / 2; + lpfn = (vram_size / 2) >> PAGE_SHIFT; } for (i = 0; i < nvbo->placement.num_placement; ++i) { nvbo->placements[i].fpfn = fpfn; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 61e6d7412505..2a298c171d4d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -401,7 +401,6 @@ nouveau_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); if (nv_connector->aux.transfer) { drm_dp_cec_unregister_connector(&nv_connector->aux); - drm_dp_aux_unregister(&nv_connector->aux); kfree(nv_connector->aux.name); } kfree(connector); @@ -461,7 +460,8 @@ nouveau_connector_of_detect(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder; - struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct device_node *cn, *dn = pci_device_to_OF_node(pdev); if (!dn || !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) || @@ -905,13 +905,29 @@ nouveau_connector_late_register(struct drm_connector *connector) int ret; ret = nouveau_backlight_init(connector); + if (ret) + return ret; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || + connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + ret = drm_dp_aux_register(&nouveau_connector(connector)->aux); + if (ret) + goto backlight_fini; + } + + return 0; +backlight_fini: + nouveau_backlight_fini(connector); return ret; } static void nouveau_connector_early_unregister(struct drm_connector *connector) { + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || + connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) + drm_dp_aux_unregister(&nouveau_connector(connector)->aux); + nouveau_backlight_fini(connector); } @@ -1339,18 +1355,19 @@ nouveau_connector_create(struct drm_device *dev, case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: nv_connector->aux.dev = connector->kdev; + nv_connector->aux.drm_dev = dev; nv_connector->aux.transfer = nouveau_connector_aux_xfer; snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL); - ret = drm_dp_aux_register(&nv_connector->aux); + drm_dp_aux_init(&nv_connector->aux); if (ret) { - NV_ERROR(drm, "failed to register aux channel\n"); + NV_ERROR(drm, "Failed to init AUX adapter for sor-%04x-%04x: %d\n", + dcbe->hasht, dcbe->hashm, ret); kfree(nv_connector); return ERR_PTR(ret); } - funcs = &nouveau_connector_funcs; - break; + fallthrough; default: funcs = &nouveau_connector_funcs; break; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index dac02c7be54d..929de41c281f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -697,7 +697,6 @@ nouveau_display_create(struct drm_device *dev) dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; - dev->mode_config.allow_fb_modifiers = true; if (drm->client.device.info.chipset < 0x11) dev->mode_config.async_page_flip = false; @@ -838,21 +837,3 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, drm_gem_object_put(&bo->bo.base); return ret; } - -int -nouveau_display_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle, uint64_t *poffset) -{ - struct drm_gem_object *gem; - - gem = drm_gem_object_lookup(file_priv, handle); - if (gem) { - struct nouveau_bo *bo = nouveau_gem_object(gem); - *poffset = drm_vma_node_offset_addr(&bo->bo.base.vma_node); - drm_gem_object_put(gem); - return 0; - } - - return -ENOENT; -} diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 616c43427059..2ab2ddb1eadf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -58,8 +58,6 @@ bool nouveau_display_scanoutpos(struct drm_crtc *crtc, int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, struct drm_mode_create_dumb *args); -int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, - u32 handle, u64 *offset); void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 885815ea917f..3204fc0a90d2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -30,7 +30,9 @@ #include <linux/vga_switcheroo.h> #include <linux/mmu_notifier.h> +#include <drm/drm_aperture.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_ttm_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_vblank.h> @@ -736,7 +738,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev, nvkm_device_del(&device); /* Remove conflicting drivers (vesafb, efifb etc). */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "nouveaufb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "nouveaufb"); if (ret) return ret; @@ -1212,7 +1214,7 @@ driver_stub = { .gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table, .dumb_create = nouveau_display_dumb_create, - .dumb_map_offset = nouveau_display_dumb_map_offset, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 4fc0fa696461..93ac78bda750 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -379,10 +379,10 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, FBINFO_HWACCEL_IMAGEBLIT; info->fbops = &nouveau_fbcon_sw_ops; info->fix.smem_start = nvbo->bo.mem.bus.offset; - info->fix.smem_len = nvbo->bo.mem.num_pages << PAGE_SHIFT; + info->fix.smem_len = nvbo->bo.base.size; info->screen_base = nvbo_kmap_obj_iovirtual(nvbo); - info->screen_size = nvbo->bo.mem.num_pages << PAGE_SHIFT; + info->screen_size = nvbo->bo.base.size; drm_fb_helper_fill_info(info, &fbcon->helper, sizes); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index c88cbb85f101..a70e82413fa7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -253,7 +253,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, rep->offset = vma->addr; } - rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; + rep->size = nvbo->bo.base.size; rep->map_handle = drm_vma_node_offset_addr(&nvbo->bo.base.vma_node); rep->tile_mode = nvbo->mode; rep->tile_flags = nvbo->contig ? 0 : NOUVEAU_GEM_TILE_NONCONTIG; @@ -638,7 +638,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv; if (unlikely(r->reloc_bo_offset + 4 > - nvbo->bo.mem.num_pages << PAGE_SHIFT)) { + nvbo->bo.base.size)) { NV_PRINTK(err, cli, "reloc outside of bo\n"); ret = -EINVAL; break; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index b81ae90b8449..e8b506a6685b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -321,7 +321,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) } #if IS_ENABLED(CONFIG_SWIOTLB) && IS_ENABLED(CONFIG_X86) - need_swiotlb = !!swiotlb_nr_tbl(); + need_swiotlb = is_swiotlb_active(); #endif ret = ttm_device_init(&drm->ttm.bdev, &nouveau_bo_driver, drm->dev->dev, diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 4894913936e9..ef87d92cdf49 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -80,6 +80,7 @@ config DRM_PANEL_SIMPLE tristate "support for simple panels" depends on OF depends on BACKLIGHT_CLASS_DEVICE + depends on PM select VIDEOMODE_HELPERS help DRM panel driver for dumb panels that need at most a regulator and diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index be312b5c04dd..9be050ab372f 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <video/display_timing.h> @@ -175,6 +176,8 @@ struct panel_simple { bool enabled; bool no_hpd; + bool prepared; + ktime_t prepared_time; ktime_t unprepared_time; @@ -186,6 +189,8 @@ struct panel_simple { struct gpio_desc *enable_gpio; struct gpio_desc *hpd_gpio; + struct edid *edid; + struct drm_display_mode override_mode; enum drm_panel_orientation orientation; @@ -334,25 +339,39 @@ static int panel_simple_disable(struct drm_panel *panel) return 0; } +static int panel_simple_suspend(struct device *dev) +{ + struct panel_simple *p = dev_get_drvdata(dev); + + gpiod_set_value_cansleep(p->enable_gpio, 0); + regulator_disable(p->supply); + p->unprepared_time = ktime_get(); + + kfree(p->edid); + p->edid = NULL; + + return 0; +} + static int panel_simple_unprepare(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); + int ret; - if (p->prepared_time == 0) + /* Unpreparing when already unprepared is a no-op */ + if (!p->prepared) return 0; - gpiod_set_value_cansleep(p->enable_gpio, 0); - - regulator_disable(p->supply); - - p->prepared_time = 0; - p->unprepared_time = ktime_get(); + pm_runtime_mark_last_busy(panel->dev); + ret = pm_runtime_put_autosuspend(panel->dev); + if (ret < 0) + return ret; + p->prepared = false; return 0; } -static int panel_simple_get_hpd_gpio(struct device *dev, - struct panel_simple *p, bool from_probe) +static int panel_simple_get_hpd_gpio(struct device *dev, struct panel_simple *p) { int err; @@ -360,38 +379,28 @@ static int panel_simple_get_hpd_gpio(struct device *dev, if (IS_ERR(p->hpd_gpio)) { err = PTR_ERR(p->hpd_gpio); - /* - * If we're called from probe we won't consider '-EPROBE_DEFER' - * to be an error--we'll leave the error code in "hpd_gpio". - * When we try to use it we'll try again. This allows for - * circular dependencies where the component providing the - * hpd gpio needs the panel to init before probing. - */ - if (err != -EPROBE_DEFER || !from_probe) { + if (err != -EPROBE_DEFER) dev_err(dev, "failed to get 'hpd' GPIO: %d\n", err); - return err; - } + + return err; } return 0; } -static int panel_simple_prepare_once(struct drm_panel *panel) +static int panel_simple_prepare_once(struct panel_simple *p) { - struct panel_simple *p = to_panel_simple(panel); + struct device *dev = p->base.dev; unsigned int delay; int err; int hpd_asserted; unsigned long hpd_wait_us; - if (p->prepared_time != 0) - return 0; - panel_simple_wait(p->unprepared_time, p->desc->delay.unprepare); err = regulator_enable(p->supply); if (err < 0) { - dev_err(panel->dev, "failed to enable supply: %d\n", err); + dev_err(dev, "failed to enable supply: %d\n", err); return err; } @@ -404,12 +413,6 @@ static int panel_simple_prepare_once(struct drm_panel *panel) msleep(delay); if (p->hpd_gpio) { - if (IS_ERR(p->hpd_gpio)) { - err = panel_simple_get_hpd_gpio(panel->dev, p, false); - if (err) - goto error; - } - if (p->desc->delay.hpd_absent_delay) hpd_wait_us = p->desc->delay.hpd_absent_delay * 1000UL; else @@ -423,7 +426,7 @@ static int panel_simple_prepare_once(struct drm_panel *panel) if (err) { if (err != -ETIMEDOUT) - dev_err(panel->dev, + dev_err(dev, "error waiting for hpd GPIO: %d\n", err); goto error; } @@ -447,25 +450,46 @@ error: */ #define MAX_PANEL_PREPARE_TRIES 5 -static int panel_simple_prepare(struct drm_panel *panel) +static int panel_simple_resume(struct device *dev) { + struct panel_simple *p = dev_get_drvdata(dev); int ret; int try; for (try = 0; try < MAX_PANEL_PREPARE_TRIES; try++) { - ret = panel_simple_prepare_once(panel); + ret = panel_simple_prepare_once(p); if (ret != -ETIMEDOUT) break; } if (ret == -ETIMEDOUT) - dev_err(panel->dev, "Prepare timeout after %d tries\n", try); + dev_err(dev, "Prepare timeout after %d tries\n", try); else if (try) - dev_warn(panel->dev, "Prepare needed %d retries\n", try); + dev_warn(dev, "Prepare needed %d retries\n", try); return ret; } +static int panel_simple_prepare(struct drm_panel *panel) +{ + struct panel_simple *p = to_panel_simple(panel); + int ret; + + /* Preparing when already prepared is a no-op */ + if (p->prepared) + return 0; + + ret = pm_runtime_get_sync(panel->dev); + if (ret < 0) { + pm_runtime_put_autosuspend(panel->dev); + return ret; + } + + p->prepared = true; + + return 0; +} + static int panel_simple_enable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); @@ -491,13 +515,16 @@ static int panel_simple_get_modes(struct drm_panel *panel, /* probe EDID if a DDC bus is available */ if (p->ddc) { - struct edid *edid = drm_get_edid(connector, p->ddc); + pm_runtime_get_sync(panel->dev); - drm_connector_update_edid_property(connector, edid); - if (edid) { - num += drm_add_edid_modes(connector, edid); - kfree(edid); - } + if (!p->edid) + p->edid = drm_get_edid(connector, p->ddc); + + if (p->edid) + num += drm_add_edid_modes(connector, p->edid); + + pm_runtime_mark_last_busy(panel->dev); + pm_runtime_put_autosuspend(panel->dev); } /* add hard-coded panel modes */ @@ -649,7 +676,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd"); if (!panel->no_hpd) { - err = panel_simple_get_hpd_gpio(dev, panel, true); + err = panel_simple_get_hpd_gpio(dev, panel); if (err) return err; } @@ -748,18 +775,30 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) break; } + dev_set_drvdata(dev, panel); + + /* + * We use runtime PM for prepare / unprepare since those power the panel + * on and off and those can be very slow operations. This is important + * to optimize powering the panel on briefly to read the EDID before + * fully enabling the panel. + */ + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type); err = drm_panel_of_backlight(&panel->base); if (err) - goto free_ddc; + goto disable_pm_runtime; drm_panel_add(&panel->base); - dev_set_drvdata(dev, panel); - return 0; +disable_pm_runtime: + pm_runtime_disable(dev); free_ddc: if (panel->ddc) put_device(&panel->ddc->dev); @@ -775,6 +814,7 @@ static int panel_simple_remove(struct device *dev) drm_panel_disable(&panel->base); drm_panel_unprepare(&panel->base); + pm_runtime_disable(dev); if (panel->ddc) put_device(&panel->ddc->dev); @@ -4603,10 +4643,17 @@ static void panel_simple_platform_shutdown(struct platform_device *pdev) panel_simple_shutdown(&pdev->dev); } +static const struct dev_pm_ops panel_simple_pm_ops = { + SET_RUNTIME_PM_OPS(panel_simple_suspend, panel_simple_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + static struct platform_driver panel_simple_platform_driver = { .driver = { .name = "panel-simple", .of_match_table = platform_of_match, + .pm = &panel_simple_pm_ops, }, .probe = panel_simple_platform_probe, .remove = panel_simple_platform_remove, @@ -4901,6 +4948,7 @@ static struct mipi_dsi_driver panel_simple_dsi_driver = { .driver = { .name = "panel-simple-dsi", .of_match_table = dsi_of_match, + .pm = &panel_simple_pm_ops, }, .probe = panel_simple_dsi_probe, .remove = panel_simple_dsi_remove, diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 7c5ffc81dce1..3644652f726f 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -89,29 +89,34 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) unsigned long cur_freq; struct device *dev = &pfdev->pdev->dev; struct devfreq *devfreq; - struct opp_table *opp_table; struct thermal_cooling_device *cooling; struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; - opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, - pfdev->comp->num_supplies); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); + if (pfdev->comp->num_supplies > 1) { + /* + * GPUs with more than 1 supply require platform-specific handling: + * continue without devfreq + */ + DRM_DEV_INFO(dev, "More than 1 supply is not supported yet\n"); + return 0; + } + + ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names, + pfdev->comp->num_supplies); + if (ret) { /* Continue if the optional regulator is missing */ if (ret != -ENODEV) { DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); - goto err_fini; + return ret; } - } else { - pfdevfreq->regulators_opp_table = opp_table; } - ret = dev_pm_opp_of_add_table(dev); + ret = devm_pm_opp_of_add_table(dev); if (ret) { /* Optional, continue without devfreq */ if (ret == -ENODEV) ret = 0; - goto err_fini; + return ret; } pfdevfreq->opp_of_table_added = true; @@ -122,10 +127,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) cur_freq = clk_get_rate(pfdev->clock); opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) { - ret = PTR_ERR(opp); - goto err_fini; - } + if (IS_ERR(opp)) + return PTR_ERR(opp); panfrost_devfreq_profile.initial_freq = cur_freq; dev_pm_opp_put(opp); @@ -142,8 +145,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) &pfdevfreq->gov_data); if (IS_ERR(devfreq)) { DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); - ret = PTR_ERR(devfreq); - goto err_fini; + return PTR_ERR(devfreq); } pfdevfreq->devfreq = devfreq; @@ -154,10 +156,6 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) pfdevfreq->cooling = cooling; return 0; - -err_fini: - panfrost_devfreq_fini(pfdev); - return ret; } void panfrost_devfreq_fini(struct panfrost_device *pfdev) @@ -168,14 +166,6 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev) devfreq_cooling_unregister(pfdevfreq->cooling); pfdevfreq->cooling = NULL; } - - if (pfdevfreq->opp_of_table_added) { - dev_pm_opp_of_remove_table(&pfdev->pdev->dev); - pfdevfreq->opp_of_table_added = false; - } - - dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); - pfdevfreq->regulators_opp_table = NULL; } void panfrost_devfreq_resume(struct panfrost_device *pfdev) diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h index 1e2a4de941aa..1514c1f9d91c 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h @@ -9,14 +9,12 @@ #include <linux/ktime.h> struct devfreq; -struct opp_table; struct thermal_cooling_device; struct panfrost_device; struct panfrost_devfreq { struct devfreq *devfreq; - struct opp_table *regulators_opp_table; struct thermal_cooling_device *cooling; struct devfreq_simple_ondemand_data gov_data; bool opp_of_table_added; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index fbcf5edbe367..125ed973feaa 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -238,7 +238,6 @@ int panfrost_device_init(struct panfrost_device *pfdev) res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); if (IS_ERR(pfdev->iomem)) { - dev_err(pfdev->dev, "failed to ioremap iomem\n"); err = PTR_ERR(pfdev->iomem); goto out_pm_domain; } diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 83a461bdeea8..ca07098a6141 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -665,6 +665,15 @@ static const struct panfrost_compatible amlogic_data = { .vendor_quirk = panfrost_gpu_amlogic_quirk, }; +const char * const mediatek_mt8183_supplies[] = { "mali", "sram" }; +const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" }; +static const struct panfrost_compatible mediatek_mt8183_data = { + .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies), + .supply_names = mediatek_mt8183_supplies, + .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains), + .pm_domain_names = mediatek_mt8183_pm_domains, +}; + static const struct of_device_id dt_match[] = { /* Set first to probe before the generic compatibles */ { .compatible = "amlogic,meson-gxm-mali", @@ -681,6 +690,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "arm,mali-t860", .data = &default_data, }, { .compatible = "arm,mali-t880", .data = &default_data, }, { .compatible = "arm,mali-bifrost", .data = &default_data, }, + { .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data }, {} }; MODULE_DEVICE_TABLE(of, dt_match); diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index a7637e79cb42..9e0a1e836011 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -677,10 +677,8 @@ static void qxl_primary_atomic_disable(struct drm_plane *plane, if (bo->shadow) bo = bo->shadow; - if (bo->is_primary) { + if (bo->is_primary) qxl_io_destroy_primary(qdev); - bo->is_primary = false; - } } } @@ -803,6 +801,7 @@ static void qxl_prepare_shadow(struct qxl_device *qdev, struct qxl_bo *user_bo, qdev->dumb_shadow_bo->surf.width != surf.width || qdev->dumb_shadow_bo->surf.height != surf.height) { if (qdev->dumb_shadow_bo) { + qxl_bo_unpin(qdev->dumb_shadow_bo); drm_gem_object_put (&qdev->dumb_shadow_bo->tbo.base); qdev->dumb_shadow_bo = NULL; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 1864467f1063..854e6c5a563f 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -1,4 +1,3 @@ -/* vim: set ts=8 sw=8 tw=78 ai noexpandtab */ /* qxl_drv.c -- QXL driver -*- linux-c -*- * * Copyright 2011 Red Hat, Inc. @@ -29,14 +28,18 @@ */ #include "qxl_drv.h" + #include <linux/console.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/vgaarb.h> #include <drm/drm.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> +#include <drm/drm_gem_ttm_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_prime.h> #include <drm/drm_probe_helper.h> @@ -92,7 +95,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "qxl"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "qxl"); if (ret) goto disable_pci; @@ -271,7 +274,7 @@ static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .dumb_create = qxl_mode_dumb_create, - .dumb_map_offset = qxl_mode_dumb_mmap, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, #if defined(CONFIG_DEBUG_FS) .debugfs_init = qxl_debugfs_init, #endif diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 6dd57cfb2e7c..20a0f3ab84ad 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -330,9 +330,6 @@ void qxl_bo_force_delete(struct qxl_device *qdev); int qxl_mode_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); -int qxl_mode_dumb_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p); /* qxl ttm */ int qxl_ttm_init(struct qxl_device *qdev); diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c index 48a58ba1db96..a635d9fdf8ac 100644 --- a/drivers/gpu/drm/qxl/qxl_dumb.c +++ b/drivers/gpu/drm/qxl/qxl_dumb.c @@ -69,20 +69,3 @@ int qxl_mode_dumb_create(struct drm_file *file_priv, args->handle = handle; return 0; } - -int qxl_mode_dumb_mmap(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p) -{ - struct drm_gem_object *gobj; - struct qxl_bo *qobj; - - BUG_ON(!offset_p); - gobj = drm_gem_object_lookup(file_priv, handle); - if (gobj == NULL) - return -ENOENT; - qobj = gem_to_qxl_bo(gobj); - *offset_p = qxl_bo_mmap_offset(qobj); - drm_gem_object_put(gobj); - return 0; -} diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index b6075f452b9e..38aabcbe2238 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -67,8 +67,8 @@ static int qxl_map_ioctl(struct drm_device *dev, void *data, struct qxl_device *qdev = to_qxl(dev); struct drm_qxl_map *qxl_map = data; - return qxl_mode_dumb_mmap(file_priv, &qdev->ddev, qxl_map->handle, - &qxl_map->offset); + return drm_gem_ttm_dumb_map_offset(file_priv, &qdev->ddev, qxl_map->handle, + &qxl_map->offset); } struct qxl_reloc_info { diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index ee9c29de4d3d..cee4b52b75dd 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -53,11 +53,6 @@ static inline unsigned long qxl_bo_size(struct qxl_bo *bo) return bo->tbo.base.size; } -static inline u64 qxl_bo_mmap_offset(struct qxl_bo *bo) -{ - return drm_vma_node_offset_addr(&bo->tbo.base.vma_node); -} - extern int qxl_bo_create(struct qxl_device *qdev, unsigned long size, bool kernel, bool pinned, u32 domain, diff --git a/drivers/gpu/drm/r128/ati_pcigart.c b/drivers/gpu/drm/r128/ati_pcigart.c index 1234ec60c0af..5d73043446e3 100644 --- a/drivers/gpu/drm/r128/ati_pcigart.c +++ b/drivers/gpu/drm/r128/ati_pcigart.c @@ -45,24 +45,39 @@ static int drm_ati_alloc_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { - gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, - PAGE_SIZE); - if (gart_info->table_handle == NULL) + drm_dma_handle_t *dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); + + if (!dmah) + return -ENOMEM; + + dmah->size = gart_info->table_size; + dmah->vaddr = dma_alloc_coherent(dev->dev, + dmah->size, + &dmah->busaddr, + GFP_KERNEL); + + if (!dmah->vaddr) { + kfree(dmah); return -ENOMEM; + } + gart_info->table_handle = dmah; return 0; } static void drm_ati_free_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { - drm_pci_free(dev, gart_info->table_handle); + drm_dma_handle_t *dmah = gart_info->table_handle; + + dma_free_coherent(dev->dev, dmah->size, dmah->vaddr, dmah->busaddr); gart_info->table_handle = NULL; } int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { struct drm_sg_mem *entry = dev->sg; + struct pci_dev *pdev = to_pci_dev(dev->dev); unsigned long pages; int i; int max_pages; @@ -82,8 +97,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info for (i = 0; i < pages; i++) { if (!entry->busaddr[i]) break; - pci_unmap_page(dev->pdev, entry->busaddr[i], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + pci_unmap_page(pdev, entry->busaddr[i], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); } if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) @@ -102,6 +116,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga { struct drm_local_map *map = &gart_info->mapping; struct drm_sg_mem *entry = dev->sg; + struct pci_dev *pdev = to_pci_dev(dev->dev); void *address = NULL; unsigned long pages; u32 *pci_gart = NULL, page_base, gart_idx; @@ -117,7 +132,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) { + if (pci_set_dma_mask(pdev, gart_info->table_mask)) { DRM_ERROR("fail to set dma mask to 0x%Lx\n", (unsigned long long)gart_info->table_mask); ret = -EFAULT; @@ -156,9 +171,9 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga gart_idx = 0; for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ - entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], + entry->busaddr[i] = pci_map_page(pdev, entry->pagelist[i], 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) { + if (pci_dma_mapping_error(pdev, entry->busaddr[i])) { DRM_ERROR("unable to map PCIGART pages!\n"); drm_ati_pcigart_cleanup(dev, gart_info); address = NULL; diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 138af32480d4..2a2933c16308 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -37,10 +37,10 @@ #include <linux/slab.h> #include <linux/uaccess.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_file.h> #include <drm/drm_irq.h> +#include <drm/drm_legacy.h> #include <drm/drm_print.h> #include <drm/r128_drm.h> diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c index b7a5f162ebae..e35a3a1449bd 100644 --- a/drivers/gpu/drm/r128/r128_drv.c +++ b/drivers/gpu/drm/r128/r128_drv.c @@ -85,7 +85,9 @@ static struct drm_driver driver = { int r128_driver_load(struct drm_device *dev, unsigned long flags) { - pci_set_master(dev->pdev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + + pci_set_master(pdev); return drm_vblank_init(dev, 1); } diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index 9d74c9d914cb..ac13fc2a0214 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -1582,6 +1582,7 @@ int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_getparam_t *param = data; + struct pci_dev *pdev = to_pci_dev(dev->dev); int value; DEV_INIT_TEST_WITH_RETURN(dev_priv); @@ -1590,7 +1591,7 @@ int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv switch (param->param) { case R128_PARAM_IRQ_NR: - value = dev->pdev->irq; + value = pdev->irq; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 15b00a347560..4c1e551d9714 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -232,6 +232,7 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector) radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd; radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; + radeon_connector->ddc_bus->aux.drm_dev = radeon_connector->base.dev; if (ASIC_IS_DCE5(rdev)) { if (radeon_auxch) radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_native; @@ -679,7 +680,7 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info) dp_info->tries = 0; voltage = 0xff; while (1) { - drm_dp_link_train_clock_recovery_delay(dp_info->dpcd); + drm_dp_link_train_clock_recovery_delay(dp_info->aux, dp_info->dpcd); if (drm_dp_dpcd_read_link_status(dp_info->aux, dp_info->link_status) <= 0) { @@ -742,7 +743,7 @@ static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info) dp_info->tries = 0; channel_eq = false; while (1) { - drm_dp_link_train_channel_eq_delay(dp_info->dpcd); + drm_dp_link_train_channel_eq_delay(dp_info->aux, dp_info->dpcd); if (drm_dp_dpcd_read_link_status(dp_info->aux, dp_info->link_status) <= 0) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 56ed5634cebe..65301d6acf13 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -60,6 +60,7 @@ * are considered as fatal) */ +#include <linux/agp_backend.h> #include <linux/atomic.h> #include <linux/wait.h> #include <linux/list.h> @@ -1110,6 +1111,46 @@ typedef int (*radeon_packet0_check_t)(struct radeon_cs_parser *p, /* * AGP */ + +struct radeon_agp_mode { + unsigned long mode; /**< AGP mode */ +}; + +struct radeon_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +}; + +struct radeon_agp_head { + struct agp_kern_info agp_info; + struct list_head memory; + unsigned long mode; + struct agp_bridge_data *bridge; + int enabled; + int acquired; + unsigned long base; + int agp_mtrr; + int cant_use_aperture; + unsigned long page_mask; +}; + +#if IS_ENABLED(CONFIG_AGP) +struct radeon_agp_head *radeon_agp_head_init(struct drm_device *dev); +#else +static inline struct radeon_agp_head *radeon_agp_head_init(struct drm_device *dev) +{ + return NULL; +} +#endif int radeon_agp_init(struct radeon_device *rdev); void radeon_agp_resume(struct radeon_device *rdev); void radeon_agp_suspend(struct radeon_device *rdev); @@ -2303,6 +2344,7 @@ struct radeon_device { #ifdef __alpha__ struct pci_controller *hose; #endif + struct radeon_agp_head *agp; struct rw_semaphore exclusive_lock; /* ASIC */ union radeon_asic_config config; diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 0aca7bdf54c7..d124600b5f58 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -27,7 +27,6 @@ #include <linux/pci.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/radeon_drm.h> @@ -127,38 +126,127 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { PCI_VENDOR_ID_SONY, 0x8175, 1}, { 0, 0, 0, 0, 0, 0, 0 }, }; + +struct radeon_agp_head *radeon_agp_head_init(struct drm_device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct radeon_agp_head *head = NULL; + + head = kzalloc(sizeof(*head), GFP_KERNEL); + if (!head) + return NULL; + head->bridge = agp_find_bridge(pdev); + if (!head->bridge) { + head->bridge = agp_backend_acquire(pdev); + if (!head->bridge) { + kfree(head); + return NULL; + } + agp_copy_info(head->bridge, &head->agp_info); + agp_backend_release(head->bridge); + } else { + agp_copy_info(head->bridge, &head->agp_info); + } + if (head->agp_info.chipset == NOT_SUPPORTED) { + kfree(head); + return NULL; + } + INIT_LIST_HEAD(&head->memory); + head->cant_use_aperture = head->agp_info.cant_use_aperture; + head->page_mask = head->agp_info.page_mask; + head->base = head->agp_info.aper_base; + + return head; +} + +static int radeon_agp_head_acquire(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + + if (!rdev->agp) + return -ENODEV; + if (rdev->agp->acquired) + return -EBUSY; + rdev->agp->bridge = agp_backend_acquire(pdev); + if (!rdev->agp->bridge) + return -ENODEV; + rdev->agp->acquired = 1; + return 0; +} + +static int radeon_agp_head_release(struct radeon_device *rdev) +{ + if (!rdev->agp || !rdev->agp->acquired) + return -EINVAL; + agp_backend_release(rdev->agp->bridge); + rdev->agp->acquired = 0; + return 0; +} + +static int radeon_agp_head_enable(struct radeon_device *rdev, struct radeon_agp_mode mode) +{ + if (!rdev->agp || !rdev->agp->acquired) + return -EINVAL; + + rdev->agp->mode = mode.mode; + agp_enable(rdev->agp->bridge, mode.mode); + rdev->agp->enabled = 1; + return 0; +} + +static int radeon_agp_head_info(struct radeon_device *rdev, struct radeon_agp_info *info) +{ + struct agp_kern_info *kern; + + if (!rdev->agp || !rdev->agp->acquired) + return -EINVAL; + + kern = &rdev->agp->agp_info; + info->agp_version_major = kern->version.major; + info->agp_version_minor = kern->version.minor; + info->mode = kern->mode; + info->aperture_base = kern->aper_base; + info->aperture_size = kern->aper_size * 1024 * 1024; + info->memory_allowed = kern->max_memory << PAGE_SHIFT; + info->memory_used = kern->current_memory << PAGE_SHIFT; + info->id_vendor = kern->device->vendor; + info->id_device = kern->device->device; + + return 0; +} #endif int radeon_agp_init(struct radeon_device *rdev) { #if IS_ENABLED(CONFIG_AGP) struct radeon_agpmode_quirk *p = radeon_agpmode_quirk_list; - struct drm_agp_mode mode; - struct drm_agp_info info; + struct radeon_agp_mode mode; + struct radeon_agp_info info; uint32_t agp_status; int default_mode; bool is_v3; int ret; /* Acquire AGP. */ - ret = drm_agp_acquire(rdev->ddev); + ret = radeon_agp_head_acquire(rdev); if (ret) { DRM_ERROR("Unable to acquire AGP: %d\n", ret); return ret; } - ret = drm_agp_info(rdev->ddev, &info); + ret = radeon_agp_head_info(rdev, &info); if (ret) { - drm_agp_release(rdev->ddev); + radeon_agp_head_release(rdev); DRM_ERROR("Unable to get AGP info: %d\n", ret); return ret; } - if (rdev->ddev->agp->agp_info.aper_size < 32) { - drm_agp_release(rdev->ddev); + if (rdev->agp->agp_info.aper_size < 32) { + radeon_agp_head_release(rdev); dev_warn(rdev->dev, "AGP aperture too small (%zuM) " "need at least 32M, disabling AGP\n", - rdev->ddev->agp->agp_info.aper_size); + rdev->agp->agp_info.aper_size); return -EINVAL; } @@ -239,15 +327,15 @@ int radeon_agp_init(struct radeon_device *rdev) } mode.mode &= ~RADEON_AGP_FW_MODE; /* disable fw */ - ret = drm_agp_enable(rdev->ddev, mode); + ret = radeon_agp_head_enable(rdev, mode); if (ret) { DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); - drm_agp_release(rdev->ddev); + radeon_agp_head_release(rdev); return ret; } - rdev->mc.agp_base = rdev->ddev->agp->agp_info.aper_base; - rdev->mc.gtt_size = rdev->ddev->agp->agp_info.aper_size << 20; + rdev->mc.agp_base = rdev->agp->agp_info.aper_base; + rdev->mc.gtt_size = rdev->agp->agp_info.aper_size << 20; rdev->mc.gtt_start = rdev->mc.agp_base; rdev->mc.gtt_end = rdev->mc.gtt_start + rdev->mc.gtt_size - 1; dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n", @@ -278,8 +366,8 @@ void radeon_agp_resume(struct radeon_device *rdev) void radeon_agp_fini(struct radeon_device *rdev) { #if IS_ENABLED(CONFIG_AGP) - if (rdev->ddev->agp && rdev->ddev->agp->acquired) { - drm_agp_release(rdev->ddev); + if (rdev->agp && rdev->agp->acquired) { + radeon_agp_head_release(rdev); } #endif } diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 059431689c2d..48162501c1ee 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -393,8 +393,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) return 0; } -static int cmp_size_smaller_first(void *priv, struct list_head *a, - struct list_head *b) +static int cmp_size_smaller_first(void *priv, const struct list_head *a, + const struct list_head *b) { struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head); struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head); diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 59cf1d288465..13072c2a6502 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -629,13 +629,20 @@ int radeon_dp_mst_init(struct radeon_connector *radeon_connector) { struct drm_device *dev = radeon_connector->base.dev; + int max_link_rate; if (!radeon_connector->ddc_bus->has_aux) return 0; + if (radeon_connector_is_dp12_capable(&radeon_connector->base)) + max_link_rate = 0x14; + else + max_link_rate = 0x0a; + radeon_connector->mst_mgr.cbs = &mst_cbs; return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev, &radeon_connector->ddc_bus->aux, 16, 6, + 4, (u8)max_link_rate, radeon_connector->base.base.id); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index efeb115ae70e..31d3dd0e5258 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -38,7 +38,7 @@ #include <linux/mmu_notifier.h> #include <linux/pci.h> -#include <drm/drm_agpsupport.h> +#include <drm/drm_aperture.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> @@ -330,7 +330,7 @@ static int radeon_pci_probe(struct pci_dev *pdev, return -EPROBE_DEFER; /* Get rid of things like offb */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "radeondrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "radeondrmfb"); if (ret) return ret; @@ -344,15 +344,6 @@ static int radeon_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, dev); - if (pci_find_capability(pdev, PCI_CAP_ID_AGP)) - dev->agp = drm_agp_init(dev); - if (dev->agp) { - dev->agp->agp_mtrr = arch_phys_wc_add( - dev->agp->agp_info.aper_base, - dev->agp->agp_info.aper_size * - 1024 * 1024); - } - ret = drm_dev_register(dev, ent->driver_data); if (ret) goto err_agp; @@ -360,9 +351,6 @@ static int radeon_pci_probe(struct pci_dev *pdev, return 0; err_agp: - if (dev->agp) - arch_phys_wc_del(dev->agp->agp_mtrr); - kfree(dev->agp); pci_disable_device(pdev); err_free: drm_dev_put(dev); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 58876bb4ef2a..0473583dcdac 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -32,7 +32,6 @@ #include <linux/uaccess.h> #include <linux/vga_switcheroo.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_fb_helper.h> #include <drm/drm_file.h> #include <drm/drm_ioctl.h> @@ -80,10 +79,10 @@ void radeon_driver_unload_kms(struct drm_device *dev) radeon_modeset_fini(rdev); radeon_device_fini(rdev); - if (dev->agp) - arch_phys_wc_del(dev->agp->agp_mtrr); - kfree(dev->agp); - dev->agp = NULL; + if (rdev->agp) + arch_phys_wc_del(rdev->agp->agp_mtrr); + kfree(rdev->agp); + rdev->agp = NULL; done_free: kfree(rdev); @@ -119,6 +118,15 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) rdev->hose = pdev->sysdata; #endif + if (pci_find_capability(pdev, PCI_CAP_ID_AGP)) + rdev->agp = radeon_agp_head_init(rdev->ddev); + if (rdev->agp) { + rdev->agp->agp_mtrr = arch_phys_wc_add( + rdev->agp->agp_info.aper_base, + rdev->agp->agp_info.aper_size * + 1024 * 1024); + } + /* update BUS flag */ if (pci_find_capability(pdev, PCI_CAP_ID_AGP)) { flags |= RADEON_IS_AGP; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 9896d8231fe5..fd4116bdde0f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -119,7 +119,7 @@ static inline unsigned radeon_bo_ngpu_pages(struct radeon_bo *bo) static inline unsigned radeon_bo_gpu_page_alignment(struct radeon_bo *bo) { - return (bo->tbo.mem.page_alignment << PAGE_SHIFT) / RADEON_GPU_PAGE_SIZE; + return (bo->tbo.page_alignment << PAGE_SHIFT) / RADEON_GPU_PAGE_SIZE; } /** diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 380b3007fd0b..3361d11769a2 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -38,7 +38,6 @@ #include <linux/swap.h> #include <linux/swiotlb.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_file.h> #include <drm/drm_prime.h> @@ -291,7 +290,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resourc /* RADEON_IS_AGP is set only if AGP is active */ mem->bus.offset = (mem->start << PAGE_SHIFT) + rdev->mc.agp_base; - mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture; + mem->bus.is_iomem = !rdev->agp->cant_use_aperture; mem->bus.caching = ttm_write_combined; } #endif @@ -513,8 +512,7 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_buffer_object *bo, struct radeon_device *rdev = radeon_get_rdev(bo->bdev); if (rdev->flags & RADEON_IS_AGP) { - return ttm_agp_tt_create(bo, rdev->ddev->agp->bridge, - page_flags); + return ttm_agp_tt_create(bo, rdev->agp->bridge, page_flags); } #endif rbo = container_of(bo, struct radeon_bo, tbo); diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index 606e5b807a6e..e33385dfe3ed 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -547,6 +547,7 @@ static void savage_fake_dma_flush(drm_savage_private_t * dev_priv) int savage_driver_load(struct drm_device *dev, unsigned long chipset) { + struct pci_dev *pdev = to_pci_dev(dev->dev); drm_savage_private_t *dev_priv; dev_priv = kzalloc(sizeof(drm_savage_private_t), GFP_KERNEL); @@ -557,7 +558,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->chipset = (enum savage_family)chipset; - pci_set_master(dev->pdev); + pci_set_master(pdev); return 0; } @@ -572,16 +573,17 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset) int savage_driver_firstopen(struct drm_device *dev) { drm_savage_private_t *dev_priv = dev->dev_private; + struct pci_dev *pdev = to_pci_dev(dev->dev); unsigned long mmio_base, fb_base, fb_size, aperture_base; int ret = 0; if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { - fb_base = pci_resource_start(dev->pdev, 0); + fb_base = pci_resource_start(pdev, 0); fb_size = SAVAGE_FB_SIZE_S3; mmio_base = fb_base + SAVAGE_FB_SIZE_S3; aperture_base = fb_base + SAVAGE_APERTURE_OFFSET; /* this should always be true */ - if (pci_resource_len(dev->pdev, 0) == 0x08000000) { + if (pci_resource_len(pdev, 0) == 0x08000000) { /* Don't make MMIO write-cobining! We need 3 * MTRRs. */ dev_priv->mtrr_handles[0] = @@ -595,16 +597,16 @@ int savage_driver_firstopen(struct drm_device *dev) } else { DRM_ERROR("strange pci_resource_len %08llx\n", (unsigned long long) - pci_resource_len(dev->pdev, 0)); + pci_resource_len(pdev, 0)); } } else if (dev_priv->chipset != S3_SUPERSAVAGE && dev_priv->chipset != S3_SAVAGE2000) { - mmio_base = pci_resource_start(dev->pdev, 0); - fb_base = pci_resource_start(dev->pdev, 1); + mmio_base = pci_resource_start(pdev, 0); + fb_base = pci_resource_start(pdev, 1); fb_size = SAVAGE_FB_SIZE_S4; aperture_base = fb_base + SAVAGE_APERTURE_OFFSET; /* this should always be true */ - if (pci_resource_len(dev->pdev, 1) == 0x08000000) { + if (pci_resource_len(pdev, 1) == 0x08000000) { /* Can use one MTRR to cover both fb and * aperture. */ dev_priv->mtrr_handles[0] = @@ -613,13 +615,13 @@ int savage_driver_firstopen(struct drm_device *dev) } else { DRM_ERROR("strange pci_resource_len %08llx\n", (unsigned long long) - pci_resource_len(dev->pdev, 1)); + pci_resource_len(pdev, 1)); } } else { - mmio_base = pci_resource_start(dev->pdev, 0); - fb_base = pci_resource_start(dev->pdev, 1); - fb_size = pci_resource_len(dev->pdev, 1); - aperture_base = pci_resource_start(dev->pdev, 2); + mmio_base = pci_resource_start(pdev, 0); + fb_base = pci_resource_start(pdev, 1); + fb_size = pci_resource_len(pdev, 1); + aperture_base = pci_resource_start(pdev, 2); /* Automatic MTRR setup will do the right thing. */ } diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index f0790e9471d1..0249c7450188 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -192,7 +192,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) EXPORT_SYMBOL(drm_sched_entity_flush); /** - * drm_sched_entity_kill_jobs - helper for drm_sched_entity_kill_jobs + * drm_sched_entity_kill_jobs_cb - helper for drm_sched_entity_kill_jobs * * @f: signaled fence * @cb: our callback structure @@ -250,7 +250,7 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) } /** - * drm_sched_entity_cleanup - Destroy a context entity + * drm_sched_entity_fini - Destroy a context entity * * @entity: scheduler entity * @@ -295,7 +295,7 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity) EXPORT_SYMBOL(drm_sched_entity_fini); /** - * drm_sched_entity_fini - Destroy a context entity + * drm_sched_entity_destroy - Destroy a context entity * * @entity: scheduler entity * diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 92d8de24d0a1..f4f474944169 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -671,7 +671,7 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) static struct drm_sched_job * drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) { - struct drm_sched_job *job; + struct drm_sched_job *job, *next; /* * Don't destroy jobs while the timeout worker is running OR thread @@ -690,6 +690,13 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) if (job && dma_fence_is_signaled(&job->s_fence->finished)) { /* remove job from pending_list */ list_del_init(&job->list); + /* make the scheduled timestamp more accurate */ + next = list_first_entry_or_null(&sched->pending_list, + typeof(*next), list); + if (next) + next->s_fence->scheduled.timestamp = + job->s_fence->finished.timestamp; + } else { job = NULL; /* queue timeout for next job */ diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 2c54b33abb54..e35e719cf315 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -41,9 +41,10 @@ static struct pci_device_id pciidlist[] = { static int sis_driver_load(struct drm_device *dev, unsigned long chipset) { + struct pci_dev *pdev = to_pci_dev(dev->dev); drm_sis_private_t *dev_priv; - pci_set_master(dev->pdev); + pci_set_master(pdev); dev_priv = kzalloc(sizeof(drm_sis_private_t), GFP_KERNEL); if (dev_priv == NULL) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 65c3c79ad1d5..e99771b947b6 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -1326,8 +1326,6 @@ int ltdc_load(struct drm_device *ddev) goto err; } - ddev->mode_config.allow_fb_modifiers = true; - ret = ltdc_crtc_init(ddev, crtc); if (ret) { DRM_ERROR("Failed to init crtc\n"); diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 91502937f26d..af335f58bdfc 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -13,6 +13,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> @@ -99,7 +100,9 @@ static int sun4i_drv_bind(struct device *dev) drm->irq_enabled = true; /* Remove early framebuffers (ie. simplefb) */ - drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false); + ret = drm_aperture_remove_framebuffers(false, "sun4i-drm-fb"); + if (ret) + goto cleanup_mode_config; sun4i_framebuffer_init(drm); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index c9385cfd0fc1..074563ca586c 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -832,10 +832,14 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, return &plane->base; } -static const u32 tegra_cursor_plane_formats[] = { +static const u32 tegra_legacy_cursor_plane_formats[] = { DRM_FORMAT_RGBA8888, }; +static const u32 tegra_cursor_plane_formats[] = { + DRM_FORMAT_ARGB8888, +}; + static int tegra_cursor_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -875,12 +879,24 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, plane); struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state); struct tegra_dc *dc = to_tegra_dc(new_state->crtc); - u32 value = CURSOR_CLIP_DISPLAY; + struct tegra_drm *tegra = plane->dev->dev_private; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + u64 dma_mask = *dc->dev->dma_mask; +#endif + unsigned int x, y; + u32 value = 0; /* rien ne va plus */ if (!new_state->crtc || !new_state->fb) return; + /* + * Legacy display supports hardware clipping of the cursor, but + * nvdisplay relies on software to clip the cursor to the screen. + */ + if (!dc->soc->has_nvdisplay) + value |= CURSOR_CLIP_DISPLAY; + switch (new_state->crtc_w) { case 32: value |= CURSOR_SIZE_32x32; @@ -908,7 +924,7 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - value = (tegra_plane_state->iova[0] >> 32) & 0x3; + value = (tegra_plane_state->iova[0] >> 32) & (dma_mask >> 32); tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); #endif @@ -920,15 +936,39 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); value &= ~CURSOR_DST_BLEND_MASK; value &= ~CURSOR_SRC_BLEND_MASK; - value |= CURSOR_MODE_NORMAL; + + if (dc->soc->has_nvdisplay) + value &= ~CURSOR_COMPOSITION_MODE_XOR; + else + value |= CURSOR_MODE_NORMAL; + value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; value |= CURSOR_ALPHA; tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); + /* nvdisplay relies on software for clipping */ + if (dc->soc->has_nvdisplay) { + struct drm_rect src; + + x = new_state->dst.x1; + y = new_state->dst.y1; + + drm_rect_fp_to_int(&src, &new_state->src); + + value = (src.y1 & tegra->vmask) << 16 | (src.x1 & tegra->hmask); + tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR); + + value = (drm_rect_height(&src) & tegra->vmask) << 16 | + (drm_rect_width(&src) & tegra->hmask); + tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR); + } else { + x = new_state->crtc_x; + y = new_state->crtc_y; + } + /* position the cursor */ - value = (new_state->crtc_y & 0x3fff) << 16 | - (new_state->crtc_x & 0x3fff); + value = ((y & tegra->vmask) << 16) | (x & tegra->hmask); tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); } @@ -959,6 +999,11 @@ static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = { .atomic_disable = tegra_cursor_atomic_disable, }; +static const uint64_t linear_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, struct tegra_dc *dc) { @@ -982,12 +1027,17 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, plane->index = 6; plane->dc = dc; - num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); - formats = tegra_cursor_plane_formats; + if (!dc->soc->has_nvdisplay) { + num_formats = ARRAY_SIZE(tegra_legacy_cursor_plane_formats); + formats = tegra_legacy_cursor_plane_formats; + } else { + num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); + formats = tegra_cursor_plane_formats; + } err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, + num_formats, linear_modifiers, DRM_PLANE_TYPE_CURSOR, NULL); if (err < 0) { kfree(plane); @@ -1106,7 +1156,8 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, type, NULL); + num_formats, linear_modifiers, + type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -2035,6 +2086,16 @@ static bool tegra_dc_has_window_groups(struct tegra_dc *dc) return false; } +static int tegra_dc_early_init(struct host1x_client *client) +{ + struct drm_device *drm = dev_get_drvdata(client->host); + struct tegra_drm *tegra = drm->dev_private; + + tegra->num_crtcs++; + + return 0; +} + static int tegra_dc_init(struct host1x_client *client) { struct drm_device *drm = dev_get_drvdata(client->host); @@ -2046,6 +2107,12 @@ static int tegra_dc_init(struct host1x_client *client) int err; /* + * DC has been reset by now, so VBLANK syncpoint can be released + * for general use. + */ + host1x_syncpt_release_vblank_reservation(client, 26 + dc->pipe); + + /* * XXX do not register DCs with no window groups because we cannot * assign a primary plane to them, which in turn will cause KMS to * crash. @@ -2111,6 +2178,12 @@ static int tegra_dc_init(struct host1x_client *client) if (dc->soc->pitch_align > tegra->pitch_align) tegra->pitch_align = dc->soc->pitch_align; + /* track maximum resolution */ + if (dc->soc->has_nvdisplay) + drm->mode_config.max_width = drm->mode_config.max_height = 16384; + else + drm->mode_config.max_width = drm->mode_config.max_height = 4096; + err = tegra_dc_rgb_init(drm, dc); if (err < 0 && err != -ENODEV) { dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); @@ -2141,7 +2214,7 @@ cleanup: drm_plane_cleanup(primary); host1x_client_iommu_detach(client); - host1x_syncpt_free(dc->syncpt); + host1x_syncpt_put(dc->syncpt); return err; } @@ -2166,7 +2239,17 @@ static int tegra_dc_exit(struct host1x_client *client) } host1x_client_iommu_detach(client); - host1x_syncpt_free(dc->syncpt); + host1x_syncpt_put(dc->syncpt); + + return 0; +} + +static int tegra_dc_late_exit(struct host1x_client *client) +{ + struct drm_device *drm = dev_get_drvdata(client->host); + struct tegra_drm *tegra = drm->dev_private; + + tegra->num_crtcs--; return 0; } @@ -2235,8 +2318,10 @@ put_rpm: } static const struct host1x_client_ops dc_client_ops = { + .early_init = tegra_dc_early_init, .init = tegra_dc_init, .exit = tegra_dc_exit, + .late_exit = tegra_dc_late_exit, .suspend = tegra_dc_runtime_suspend, .resume = tegra_dc_runtime_resume, }; @@ -2246,6 +2331,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .supports_sector_layout = false, .has_legacy_blending = true, .pitch_align = 8, .has_powergate = false, @@ -2265,6 +2351,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .supports_sector_layout = false, .has_legacy_blending = true, .pitch_align = 8, .has_powergate = false, @@ -2284,6 +2371,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { .supports_interlacing = false, .supports_cursor = false, .supports_block_linear = false, + .supports_sector_layout = false, .has_legacy_blending = true, .pitch_align = 64, .has_powergate = true, @@ -2303,6 +2391,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = false, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = true, @@ -2322,6 +2411,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = false, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = true, @@ -2375,6 +2465,7 @@ static const struct tegra_dc_soc_info tegra186_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = false, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = false, @@ -2423,6 +2514,7 @@ static const struct tegra_dc_soc_info tegra194_dc_soc_info = { .supports_interlacing = true, .supports_cursor = true, .supports_block_linear = true, + .supports_sector_layout = true, .has_legacy_blending = false, .pitch_align = 64, .has_powergate = false, @@ -2532,9 +2624,16 @@ static int tegra_dc_couple(struct tegra_dc *dc) static int tegra_dc_probe(struct platform_device *pdev) { + u64 dma_mask = dma_get_mask(pdev->dev.parent); struct tegra_dc *dc; int err; + err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } + dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); if (!dc) return -ENOMEM; diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 051d03dcb9b0..29f19c3c6149 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -52,6 +52,7 @@ struct tegra_dc_soc_info { bool supports_interlacing; bool supports_cursor; bool supports_block_linear; + bool supports_sector_layout; bool has_legacy_blending; unsigned int pitch_align; bool has_powergate; @@ -511,6 +512,8 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc); #define DC_DISP_CURSOR_START_ADDR_HI 0x4ec #define DC_DISP_BLEND_CURSOR_CONTROL 0x4f1 +#define CURSOR_COMPOSITION_MODE_BLEND (0 << 25) +#define CURSOR_COMPOSITION_MODE_XOR (1 << 25) #define CURSOR_MODE_LEGACY (0 << 24) #define CURSOR_MODE_NORMAL (1 << 24) #define CURSOR_DST_BLEND_ZERO (0 << 16) @@ -705,6 +708,9 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc); #define PROTOCOL_MASK (0xf << 8) #define PROTOCOL_SINGLE_TMDS_A (0x1 << 8) +#define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442 +#define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446 + #define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702 #define OWNER_MASK (0xf << 0) #define OWNER(x) (((x) & 0xf) << 0) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index ea56c6ec25e4..7d7cc90b6fc9 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -719,6 +719,7 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output) unsigned long timeout; int err; + aux->drm_dev = output->connector.dev; err = drm_dp_aux_register(aux); if (err < 0) return err; diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 90709c38c993..f96c237b2242 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_debugfs.h> @@ -174,7 +175,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, struct drm_tegra_syncpt syncpt; struct host1x *host1x = dev_get_drvdata(drm->dev->parent); struct drm_gem_object **refs; - struct host1x_syncpt *sp; + struct host1x_syncpt *sp = NULL; struct host1x_job *job; unsigned int num_refs; int err; @@ -301,8 +302,8 @@ int tegra_drm_submit(struct tegra_drm_context *context, goto fail; } - /* check whether syncpoint ID is valid */ - sp = host1x_syncpt_get(host1x, syncpt.id); + /* Syncpoint ref will be dropped on job release. */ + sp = host1x_syncpt_get_by_id(host1x, syncpt.id); if (!sp) { err = -ENOENT; goto fail; @@ -311,7 +312,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, job->is_addr_reg = context->client->ops->is_addr_reg; job->is_valid_class = context->client->ops->is_valid_class; job->syncpt_incrs = syncpt.incrs; - job->syncpt_id = syncpt.id; + job->syncpt = sp; job->timeout = 10000; if (args->timeout && args->timeout < 10000) @@ -383,7 +384,7 @@ static int tegra_syncpt_read(struct drm_device *drm, void *data, struct drm_tegra_syncpt_read *args = data; struct host1x_syncpt *sp; - sp = host1x_syncpt_get(host, args->id); + sp = host1x_syncpt_get_by_id_noref(host, args->id); if (!sp) return -EINVAL; @@ -398,7 +399,7 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data, struct drm_tegra_syncpt_incr *args = data; struct host1x_syncpt *sp; - sp = host1x_syncpt_get(host1x, args->id); + sp = host1x_syncpt_get_by_id_noref(host1x, args->id); if (!sp) return -EINVAL; @@ -412,7 +413,7 @@ static int tegra_syncpt_wait(struct drm_device *drm, void *data, struct drm_tegra_syncpt_wait *args = data; struct host1x_syncpt *sp; - sp = host1x_syncpt_get(host1x, args->id); + sp = host1x_syncpt_get_by_id_noref(host1x, args->id); if (!sp) return -EINVAL; @@ -1121,11 +1122,8 @@ static int host1x_drm_probe(struct host1x_device *dev) drm->mode_config.min_width = 0; drm->mode_config.min_height = 0; - - drm->mode_config.max_width = 4096; - drm->mode_config.max_height = 4096; - - drm->mode_config.allow_fb_modifiers = true; + drm->mode_config.max_width = 0; + drm->mode_config.max_height = 0; drm->mode_config.normalize_zpos = true; @@ -1142,6 +1140,14 @@ static int host1x_drm_probe(struct host1x_device *dev) if (err < 0) goto fbdev; + /* + * Now that all display controller have been initialized, the maximum + * supported resolution is known and the bitmask for horizontal and + * vertical bitfields can be computed. + */ + tegra->hmask = drm->mode_config.max_width - 1; + tegra->vmask = drm->mode_config.max_height - 1; + if (tegra->use_explicit_iommu) { u64 carveout_start, carveout_end, gem_start, gem_end; u64 dma_mask = dma_get_mask(&dev->dev); @@ -1198,8 +1204,7 @@ static int host1x_drm_probe(struct host1x_device *dev) drm_mode_config_reset(drm); - err = drm_fb_helper_remove_conflicting_framebuffers(NULL, "tegradrmfb", - false); + err = drm_aperture_remove_framebuffers(false, "tegradrmfb"); if (err < 0) goto hub; diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index f38de08e0c95..87df251c1fcf 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -24,6 +24,9 @@ #include "hub.h" #include "trace.h" +/* XXX move to include/uapi/drm/drm_fourcc.h? */ +#define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT(22) + struct reset_control; #ifdef CONFIG_DRM_FBDEV_EMULATION @@ -54,7 +57,9 @@ struct tegra_drm { struct tegra_fbdev *fbdev; #endif + unsigned int hmask, vmask; unsigned int pitch_align; + unsigned int num_crtcs; struct tegra_display_hub *hub; }; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 01939c57fc74..cae8b8cbe9dd 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -44,6 +44,15 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, { uint64_t modifier = framebuffer->modifier; + if ((modifier >> 56) == DRM_FORMAT_MOD_VENDOR_NVIDIA) { + if ((modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) == 0) + tiling->sector_layout = TEGRA_BO_SECTOR_LAYOUT_TEGRA; + else + tiling->sector_layout = TEGRA_BO_SECTOR_LAYOUT_GPU; + + modifier &= ~DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT; + } + switch (modifier) { case DRM_FORMAT_MOD_LINEAR: tiling->mode = TEGRA_BO_TILING_MODE_PITCH; @@ -86,6 +95,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, break; default: + DRM_DEBUG_KMS("unknown format modifier: %llx\n", modifier); return -EINVAL; } diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index fafb5724499b..c15fd99d6cb2 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -21,9 +21,15 @@ enum tegra_bo_tiling_mode { TEGRA_BO_TILING_MODE_BLOCK, }; +enum tegra_bo_sector_layout { + TEGRA_BO_SECTOR_LAYOUT_TEGRA, + TEGRA_BO_SECTOR_LAYOUT_GPU, +}; + struct tegra_bo_tiling { enum tegra_bo_tiling_mode mode; unsigned long value; + enum tegra_bo_sector_layout sector_layout; }; struct tegra_bo { diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index adbe2ddcda19..de288cba3905 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -67,7 +67,7 @@ static int gr2d_init(struct host1x_client *client) detach: host1x_client_iommu_detach(client); free: - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); put: host1x_channel_put(gr2d->channel); return err; @@ -86,7 +86,7 @@ static int gr2d_exit(struct host1x_client *client) return err; host1x_client_iommu_detach(client); - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(gr2d->channel); return 0; diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index b0b8154e8104..24442ade0da3 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -76,7 +76,7 @@ static int gr3d_init(struct host1x_client *client) detach: host1x_client_iommu_detach(client); free: - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); put: host1x_channel_put(gr3d->channel); return err; @@ -94,7 +94,7 @@ static int gr3d_exit(struct host1x_client *client) return err; host1x_client_iommu_detach(client); - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(gr3d->channel); return 0; diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 8e6d329d062b..79bff8b48271 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -55,6 +55,18 @@ static const u64 tegra_shared_plane_modifiers[] = { DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), + /* + * The GPU sector layout is only supported on Tegra194, but these will + * be filtered out later on by ->format_mod_supported() on SoCs where + * it isn't supported. + */ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT, + /* sentinel */ DRM_FORMAT_MOD_INVALID }; @@ -366,6 +378,12 @@ static int tegra_shared_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + if (tiling->sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU && + !dc->soc->supports_sector_layout) { + DRM_ERROR("hardware doesn't support GPU sector layout\n"); + return -EINVAL; + } + /* * Tegra doesn't support different strides for U and V planes so we * error out if the user tries to display a framebuffer with such a @@ -485,6 +503,16 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, base = tegra_plane_state->iova[0] + fb->offsets[0]; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + /* + * Physical address bit 39 in Tegra194 is used as a switch for special + * logic that swizzles the memory using either the legacy Tegra or the + * dGPU sector layout. + */ + if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU) + base |= BIT(39); +#endif + tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH); tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS); @@ -562,9 +590,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; struct tegra_drm *tegra = drm->dev_private; struct tegra_display_hub *hub = tegra->hub; - /* planes can be assigned to arbitrary CRTCs */ - unsigned int possible_crtcs = 0x7; struct tegra_shared_plane *plane; + unsigned int possible_crtcs; unsigned int num_formats; const u64 *modifiers; struct drm_plane *p; @@ -583,6 +610,9 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, p = &plane->base.base; + /* planes can be assigned to arbitrary CRTCs */ + possible_crtcs = BIT(tegra->num_crtcs) - 1; + num_formats = ARRAY_SIZE(tegra_shared_plane_formats); formats = tegra_shared_plane_formats; modifiers = tegra_shared_plane_modifiers; @@ -848,12 +878,19 @@ static const struct host1x_client_ops tegra_display_hub_ops = { static int tegra_display_hub_probe(struct platform_device *pdev) { + u64 dma_mask = dma_get_mask(pdev->dev.parent); struct device_node *child = NULL; struct tegra_display_hub *hub; struct clk *clk; unsigned int i; int err; + err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } + hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL); if (!hub) return -ENOMEM; diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 19e8847a164b..2e11b4b1f702 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -83,6 +83,22 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, kfree(state); } +static bool tegra_plane_supports_sector_layout(struct drm_plane *plane) +{ + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, plane->dev) { + if (plane->possible_crtcs & drm_crtc_mask(crtc)) { + struct tegra_dc *dc = to_tegra_dc(crtc); + + if (!dc->soc->supports_sector_layout) + return false; + } + } + + return true; +} + static bool tegra_plane_format_mod_supported(struct drm_plane *plane, uint32_t format, uint64_t modifier) @@ -92,6 +108,14 @@ static bool tegra_plane_format_mod_supported(struct drm_plane *plane, if (modifier == DRM_FORMAT_MOD_LINEAR) return true; + /* check for the sector layout bit */ + if ((modifier >> 56) == DRM_FORMAT_MOD_VENDOR_NVIDIA) { + if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) { + if (!tegra_plane_supports_sector_layout(plane)) + return false; + } + } + if (info->num_planes == 1) return true; @@ -119,6 +143,14 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) dma_addr_t phys_addr, *phys; struct sg_table *sgt; + /* + * If we're not attached to a domain, we already stored the + * physical address when the buffer was allocated. If we're + * part of a group that's shared between all display + * controllers, we've also already mapped the framebuffer + * through the SMMU. In both cases we can short-circuit the + * code below and retrieve the stored IOV address. + */ if (!domain || dc->client.group) phys = &phys_addr; else diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 77e128832920..72aea1cc0cfa 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -214,7 +214,7 @@ static int vic_init(struct host1x_client *client) return 0; free_syncpt: - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); free_channel: host1x_channel_put(vic->channel); detach: @@ -238,7 +238,7 @@ static int vic_exit(struct host1x_client *client) if (err < 0) return err; - host1x_syncpt_free(client->syncpts[0]); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(vic->channel); host1x_client_iommu_detach(client); diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index 9bbaa1a69050..d46f95d9196d 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -38,6 +38,22 @@ config DRM_GM12U320 This is a KMS driver for projectors which use the GM12U320 chipset for video transfer over USB2/3, such as the Acer C120 mini projector. +config DRM_SIMPLEDRM + tristate "Simple framebuffer driver" + depends on DRM + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help + DRM driver for simple platform-provided framebuffers. + + This driver assumes that the display hardware has been initialized + by the firmware or bootloader before the kernel boots. Scanout + buffer, size, and display format must be provided via device tree, + UEFI, VESA, etc. + + On x86 and compatible, you should also select CONFIG_X86_SYSFB to + use UEFI and VESA framebuffers. + config TINYDRM_HX8357D tristate "DRM support for HX8357D display panels" depends on DRM && SPI diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile index bef6780bdd6f..9cc847e756da 100644 --- a/drivers/gpu/drm/tiny/Makefile +++ b/drivers/gpu/drm/tiny/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o obj-$(CONFIG_DRM_GM12U320) += gm12u320.o +obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index ad922c3ec681..42611dacde88 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -24,6 +24,7 @@ #include <video/cirrus.h> #include <video/vga.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_connector.h> @@ -323,7 +324,7 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_ return -ENODEV; if (cirrus->cpp == fb->format->cpp[0]) - drm_fb_memcpy_dstclip(cirrus->vram, + drm_fb_memcpy_dstclip(cirrus->vram, fb->pitches[0], vmap, fb, rect); else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2) @@ -549,7 +550,7 @@ static int cirrus_pci_probe(struct pci_dev *pdev, struct cirrus_device *cirrus; int ret; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "cirrusdrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "cirrusdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c index 3e2c2868a363..da5df93450de 100644 --- a/drivers/gpu/drm/tiny/hx8357d.c +++ b/drivers/gpu/drm/tiny/hx8357d.c @@ -234,10 +234,8 @@ static int hx8357d_probe(struct spi_device *spi) drm = &dbidev->drm; dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); - if (IS_ERR(dc)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); - return PTR_ERR(dc); - } + if (IS_ERR(dc)) + return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n"); dbidev->backlight = devm_of_find_backlight(dev); if (IS_ERR(dbidev->backlight)) diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c index 6b87df19eec1..69265d8a3beb 100644 --- a/drivers/gpu/drm/tiny/ili9225.c +++ b/drivers/gpu/drm/tiny/ili9225.c @@ -379,16 +379,12 @@ static int ili9225_probe(struct spi_device *spi) drm = &dbidev->drm; dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dbi->reset)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); - return PTR_ERR(dbi->reset); - } + if (IS_ERR(dbi->reset)) + return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n"); rs = devm_gpiod_get(dev, "rs", GPIOD_OUT_LOW); - if (IS_ERR(rs)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'rs'\n"); - return PTR_ERR(rs); - } + if (IS_ERR(rs)) + return dev_err_probe(dev, PTR_ERR(rs), "Failed to get GPIO 'rs'\n"); device_property_read_u32(dev, "rotation", &rotation); diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c index a97f3f70e4a6..ad9ce7b4f76f 100644 --- a/drivers/gpu/drm/tiny/ili9341.c +++ b/drivers/gpu/drm/tiny/ili9341.c @@ -192,16 +192,12 @@ static int ili9341_probe(struct spi_device *spi) drm = &dbidev->drm; dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dbi->reset)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); - return PTR_ERR(dbi->reset); - } + if (IS_ERR(dbi->reset)) + return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n"); dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW); - if (IS_ERR(dc)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); - return PTR_ERR(dc); - } + if (IS_ERR(dc)) + return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n"); dbidev->backlight = devm_of_find_backlight(dev); if (IS_ERR(dbidev->backlight)) diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index 6422a7f67079..75aa1476c66c 100644 --- a/drivers/gpu/drm/tiny/ili9486.c +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -206,16 +206,12 @@ static int ili9486_probe(struct spi_device *spi) drm = &dbidev->drm; dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dbi->reset)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); - return PTR_ERR(dbi->reset); - } + if (IS_ERR(dbi->reset)) + return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n"); dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); - if (IS_ERR(dc)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); - return PTR_ERR(dc); - } + if (IS_ERR(dc)) + return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n"); dbidev->backlight = devm_of_find_backlight(dev); if (IS_ERR(dbidev->backlight)) diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c index dc76fe53aa72..82fd1ad3413f 100644 --- a/drivers/gpu/drm/tiny/mi0283qt.c +++ b/drivers/gpu/drm/tiny/mi0283qt.c @@ -196,16 +196,12 @@ static int mi0283qt_probe(struct spi_device *spi) drm = &dbidev->drm; dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dbi->reset)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); - return PTR_ERR(dbi->reset); - } + if (IS_ERR(dbi->reset)) + return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n"); dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW); - if (IS_ERR(dc)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); - return PTR_ERR(dc); - } + if (IS_ERR(dc)) + return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n"); dbidev->regulator = devm_regulator_get(dev, "power"); if (IS_ERR(dbidev->regulator)) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c new file mode 100644 index 000000000000..4f605c5fe856 --- /dev/null +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -0,0 +1,903 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/clk.h> +#include <linux/of_clk.h> +#include <linux/platform_data/simplefb.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_aperture.h> +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_connector.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_device.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_format_helper.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_gem_shmem_helper.h> +#include <drm/drm_managed.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_simple_kms_helper.h> + +#define DRIVER_NAME "simpledrm" +#define DRIVER_DESC "DRM driver for simple-framebuffer platform devices" +#define DRIVER_DATE "20200625" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +/* + * Assume a monitor resolution of 96 dpi to + * get a somewhat reasonable screen size. + */ +#define RES_MM(d) \ + (((d) * 254ul) / (96ul * 10ul)) + +#define SIMPLEDRM_MODE(hd, vd) \ + DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd)) + +/* + * Helpers for simplefb + */ + +static int +simplefb_get_validated_int(struct drm_device *dev, const char *name, + uint32_t value) +{ + if (value > INT_MAX) { + drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", + name, value); + return -EINVAL; + } + return (int)value; +} + +static int +simplefb_get_validated_int0(struct drm_device *dev, const char *name, + uint32_t value) +{ + if (!value) { + drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", + name, value); + return -EINVAL; + } + return simplefb_get_validated_int(dev, name, value); +} + +static const struct drm_format_info * +simplefb_get_validated_format(struct drm_device *dev, const char *format_name) +{ + static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; + const struct simplefb_format *fmt = formats; + const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); + const struct drm_format_info *info; + + if (!format_name) { + drm_err(dev, "simplefb: missing framebuffer format\n"); + return ERR_PTR(-EINVAL); + } + + while (fmt < end) { + if (!strcmp(format_name, fmt->name)) { + info = drm_format_info(fmt->fourcc); + if (!info) + return ERR_PTR(-EINVAL); + return info; + } + ++fmt; + } + + drm_err(dev, "simplefb: unknown framebuffer format %s\n", + format_name); + + return ERR_PTR(-EINVAL); +} + +static int +simplefb_get_width_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int0(dev, "width", pd->width); +} + +static int +simplefb_get_height_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int0(dev, "height", pd->height); +} + +static int +simplefb_get_stride_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int(dev, "stride", pd->stride); +} + +static const struct drm_format_info * +simplefb_get_format_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_format(dev, pd->format); +} + +static int +simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node, + const char *name, u32 *value) +{ + int ret = of_property_read_u32(of_node, name, value); + + if (ret) + drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", + name, ret); + return ret; +} + +static int +simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node, + const char *name, const char **value) +{ + int ret = of_property_read_string(of_node, name, value); + + if (ret) + drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", + name, ret); + return ret; +} + +static int +simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 width; + int ret = simplefb_read_u32_of(dev, of_node, "width", &width); + + if (ret) + return ret; + return simplefb_get_validated_int0(dev, "width", width); +} + +static int +simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 height; + int ret = simplefb_read_u32_of(dev, of_node, "height", &height); + + if (ret) + return ret; + return simplefb_get_validated_int0(dev, "height", height); +} + +static int +simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 stride; + int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride); + + if (ret) + return ret; + return simplefb_get_validated_int(dev, "stride", stride); +} + +static const struct drm_format_info * +simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) +{ + const char *format; + int ret = simplefb_read_string_of(dev, of_node, "format", &format); + + if (ret) + return ERR_PTR(ret); + return simplefb_get_validated_format(dev, format); +} + +/* + * Simple Framebuffer device + */ + +struct simpledrm_device { + struct drm_device dev; + struct platform_device *pdev; + + /* clocks */ +#if defined CONFIG_OF && defined CONFIG_COMMON_CLK + unsigned int clk_count; + struct clk **clks; +#endif + /* regulators */ +#if defined CONFIG_OF && defined CONFIG_REGULATOR + unsigned int regulator_count; + struct regulator **regulators; +#endif + + /* simplefb settings */ + struct drm_display_mode mode; + const struct drm_format_info *format; + unsigned int pitch; + + /* memory management */ + struct resource *mem; + void __iomem *screen_base; + + /* modesetting */ + uint32_t formats[8]; + size_t nformats; + struct drm_connector connector; + struct drm_simple_display_pipe pipe; +}; + +static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) +{ + return container_of(dev, struct simpledrm_device, dev); +} + +/* + * Hardware + */ + +#if defined CONFIG_OF && defined CONFIG_COMMON_CLK +/* + * Clock handling code. + * + * Here we handle the clocks property of our "simple-framebuffer" dt node. + * This is necessary so that we can make sure that any clocks needed by + * the display engine that the bootloader set up for us (and for which it + * provided a simplefb dt node), stay up, for the life of the simplefb + * driver. + * + * When the driver unloads, we cleanly disable, and then release the clocks. + * + * We only complain about errors here, no action is taken as the most likely + * error can only happen due to a mismatch between the bootloader which set + * up simplefb, and the clock definitions in the device tree. Chances are + * that there are no adverse effects, and if there are, a clean teardown of + * the fb probe will not help us much either. So just complain and carry on, + * and hope that the user actually gets a working fb at the end of things. + */ + +static void simpledrm_device_release_clocks(void *res) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(res); + unsigned int i; + + for (i = 0; i < sdev->clk_count; ++i) { + if (sdev->clks[i]) { + clk_disable_unprepare(sdev->clks[i]); + clk_put(sdev->clks[i]); + } + } +} + +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + struct device_node *of_node = pdev->dev.of_node; + struct clk *clock; + unsigned int i; + int ret; + + if (dev_get_platdata(&pdev->dev) || !of_node) + return 0; + + sdev->clk_count = of_clk_get_parent_count(of_node); + if (!sdev->clk_count) + return 0; + + sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]), + GFP_KERNEL); + if (!sdev->clks) + return -ENOMEM; + + for (i = 0; i < sdev->clk_count; ++i) { + clock = of_clk_get(of_node, i); + if (IS_ERR(clock)) { + ret = PTR_ERR(clock); + if (ret == -EPROBE_DEFER) + goto err; + drm_err(dev, "clock %u not found: %d\n", i, ret); + continue; + } + ret = clk_prepare_enable(clock); + if (ret) { + drm_err(dev, "failed to enable clock %u: %d\n", + i, ret); + clk_put(clock); + continue; + } + sdev->clks[i] = clock; + } + + return devm_add_action_or_reset(&pdev->dev, + simpledrm_device_release_clocks, + sdev); + +err: + while (i) { + --i; + if (sdev->clks[i]) { + clk_disable_unprepare(sdev->clks[i]); + clk_put(sdev->clks[i]); + } + } + return ret; +} +#else +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) +{ + return 0; +} +#endif + +#if defined CONFIG_OF && defined CONFIG_REGULATOR + +#define SUPPLY_SUFFIX "-supply" + +/* + * Regulator handling code. + * + * Here we handle the num-supplies and vin*-supply properties of our + * "simple-framebuffer" dt node. This is necessary so that we can make sure + * that any regulators needed by the display hardware that the bootloader + * set up for us (and for which it provided a simplefb dt node), stay up, + * for the life of the simplefb driver. + * + * When the driver unloads, we cleanly disable, and then release the + * regulators. + * + * We only complain about errors here, no action is taken as the most likely + * error can only happen due to a mismatch between the bootloader which set + * up simplefb, and the regulator definitions in the device tree. Chances are + * that there are no adverse effects, and if there are, a clean teardown of + * the fb probe will not help us much either. So just complain and carry on, + * and hope that the user actually gets a working fb at the end of things. + */ + +static void simpledrm_device_release_regulators(void *res) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(res); + unsigned int i; + + for (i = 0; i < sdev->regulator_count; ++i) { + if (sdev->regulators[i]) { + regulator_disable(sdev->regulators[i]); + regulator_put(sdev->regulators[i]); + } + } +} + +static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + struct device_node *of_node = pdev->dev.of_node; + struct property *prop; + struct regulator *regulator; + const char *p; + unsigned int count = 0, i = 0; + int ret; + + if (dev_get_platdata(&pdev->dev) || !of_node) + return 0; + + /* Count the number of regulator supplies */ + for_each_property_of_node(of_node, prop) { + p = strstr(prop->name, SUPPLY_SUFFIX); + if (p && p != prop->name) + ++count; + } + + if (!count) + return 0; + + sdev->regulators = drmm_kzalloc(dev, + count * sizeof(sdev->regulators[0]), + GFP_KERNEL); + if (!sdev->regulators) + return -ENOMEM; + + for_each_property_of_node(of_node, prop) { + char name[32]; /* 32 is max size of property name */ + size_t len; + + p = strstr(prop->name, SUPPLY_SUFFIX); + if (!p || p == prop->name) + continue; + len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1; + strscpy(name, prop->name, min(sizeof(name), len)); + + regulator = regulator_get_optional(&pdev->dev, name); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); + if (ret == -EPROBE_DEFER) + goto err; + drm_err(dev, "regulator %s not found: %d\n", + name, ret); + continue; + } + + ret = regulator_enable(regulator); + if (ret) { + drm_err(dev, "failed to enable regulator %u: %d\n", + i, ret); + regulator_put(regulator); + continue; + } + + sdev->regulators[i++] = regulator; + } + sdev->regulator_count = i; + + return devm_add_action_or_reset(&pdev->dev, + simpledrm_device_release_regulators, + sdev); + +err: + while (i) { + --i; + if (sdev->regulators[i]) { + regulator_disable(sdev->regulators[i]); + regulator_put(sdev->regulators[i]); + } + } + return ret; +} +#else +static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) +{ + return 0; +} +#endif + +/* + * Simplefb settings + */ + +static struct drm_display_mode simpledrm_mode(unsigned int width, + unsigned int height) +{ + struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) }; + + mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay; + drm_mode_set_name(&mode); + + return mode; +} + +static int simpledrm_device_init_fb(struct simpledrm_device *sdev) +{ + int width, height, stride; + const struct drm_format_info *format; + struct drm_format_name_buf buf; + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev); + struct device_node *of_node = pdev->dev.of_node; + + if (pd) { + width = simplefb_get_width_pd(dev, pd); + if (width < 0) + return width; + height = simplefb_get_height_pd(dev, pd); + if (height < 0) + return height; + stride = simplefb_get_stride_pd(dev, pd); + if (stride < 0) + return stride; + format = simplefb_get_format_pd(dev, pd); + if (IS_ERR(format)) + return PTR_ERR(format); + } else if (of_node) { + width = simplefb_get_width_of(dev, of_node); + if (width < 0) + return width; + height = simplefb_get_height_of(dev, of_node); + if (height < 0) + return height; + stride = simplefb_get_stride_of(dev, of_node); + if (stride < 0) + return stride; + format = simplefb_get_format_of(dev, of_node); + if (IS_ERR(format)) + return PTR_ERR(format); + } else { + drm_err(dev, "no simplefb configuration found\n"); + return -ENODEV; + } + + sdev->mode = simpledrm_mode(width, height); + sdev->format = format; + sdev->pitch = stride; + + drm_dbg_kms(dev, "display mode={" DRM_MODE_FMT "}\n", + DRM_MODE_ARG(&sdev->mode)); + drm_dbg_kms(dev, + "framebuffer format=\"%s\", size=%dx%d, stride=%d byte\n", + drm_get_format_name(format->format, &buf), width, + height, stride); + + return 0; +} + +/* + * Memory management + */ + +static int simpledrm_device_init_mm(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + struct resource *mem; + void __iomem *screen_base; + int ret; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -EINVAL; + + ret = devm_aperture_acquire_from_firmware(dev, mem->start, resource_size(mem)); + if (ret) { + drm_err(dev, "could not acquire memory range %pr: error %d\n", + mem, ret); + return ret; + } + + screen_base = devm_ioremap_wc(&pdev->dev, mem->start, + resource_size(mem)); + if (!screen_base) + return -ENOMEM; + + sdev->mem = mem; + sdev->screen_base = screen_base; + + return 0; +} + +/* + * Modesetting + */ + +/* + * Support all formats of simplefb and maybe more; in order + * of preference. The display's update function will do any + * conversion necessary. + * + * TODO: Add blit helpers for remaining formats and uncomment + * constants. + */ +static const uint32_t simpledrm_default_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB565, + //DRM_FORMAT_XRGB1555, + //DRM_FORMAT_ARGB1555, + DRM_FORMAT_RGB888, + //DRM_FORMAT_XRGB2101010, + //DRM_FORMAT_ARGB2101010, +}; + +static const uint64_t simpledrm_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static int simpledrm_connector_helper_get_modes(struct drm_connector *connector) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &sdev->mode); + if (!mode) + return 0; + + if (mode->name[0] == '\0') + drm_mode_set_name(mode); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + if (mode->width_mm) + connector->display_info.width_mm = mode->width_mm; + if (mode->height_mm) + connector->display_info.height_mm = mode->height_mm; + + return 1; +} + +static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { + .get_modes = simpledrm_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs simpledrm_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int +simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, + const struct drm_display_mode *mode) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + + if (mode->hdisplay != sdev->mode.hdisplay && + mode->vdisplay != sdev->mode.vdisplay) + return MODE_ONE_SIZE; + else if (mode->hdisplay != sdev->mode.hdisplay) + return MODE_ONE_WIDTH; + else if (mode->vdisplay != sdev->mode.vdisplay) + return MODE_ONE_HEIGHT; + + return MODE_OK; +} + +static void +simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */ + struct drm_device *dev = &sdev->dev; + int idx; + + if (!fb) + return; + + if (!drm_dev_enter(dev, &idx)) + return; + + drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch, + sdev->format->format, vmap, fb); + drm_dev_exit(idx); +} + +static void +simpledrm_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_device *dev = &sdev->dev; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; + + /* Clear screen to black if disabled */ + memset_io(sdev->screen_base, 0, sdev->pitch * sdev->mode.vdisplay); + + drm_dev_exit(idx); +} + +static void +simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_plane_state) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_plane_state *plane_state = pipe->plane.state; + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */ + struct drm_framebuffer *fb = plane_state->fb; + struct drm_device *dev = &sdev->dev; + struct drm_rect clip; + int idx; + + if (!fb) + return; + + if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip)) + return; + + if (!drm_dev_enter(dev, &idx)) + return; + + drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch, + sdev->format->format, vmap, fb, &clip); + + drm_dev_exit(idx); +} + +static const struct drm_simple_display_pipe_funcs +simpledrm_simple_display_pipe_funcs = { + .mode_valid = simpledrm_simple_display_pipe_mode_valid, + .enable = simpledrm_simple_display_pipe_enable, + .disable = simpledrm_simple_display_pipe_disable, + .update = simpledrm_simple_display_pipe_update, + DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +}; + +static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev, + size_t *nformats_out) +{ + struct drm_device *dev = &sdev->dev; + size_t i; + + if (sdev->nformats) + goto out; /* don't rebuild list on recurring calls */ + + /* native format goes first */ + sdev->formats[0] = sdev->format->format; + sdev->nformats = 1; + + /* default formats go second */ + for (i = 0; i < ARRAY_SIZE(simpledrm_default_formats); ++i) { + if (simpledrm_default_formats[i] == sdev->format->format) + continue; /* native format already went first */ + sdev->formats[sdev->nformats] = simpledrm_default_formats[i]; + sdev->nformats++; + } + + /* + * TODO: The simpledrm driver converts framebuffers to the native + * format when copying them to device memory. If there are more + * formats listed than supported by the driver, the native format + * is not supported by the conversion helpers. Therefore *only* + * support the native format and add a conversion helper ASAP. + */ + if (drm_WARN_ONCE(dev, i != sdev->nformats, + "format conversion helpers required for %p4cc", + &sdev->format->format)) { + sdev->nformats = 1; + } + +out: + *nformats_out = sdev->nformats; + return sdev->formats; +} + +static int simpledrm_device_init_modeset(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct drm_display_mode *mode = &sdev->mode; + struct drm_connector *connector = &sdev->connector; + struct drm_simple_display_pipe *pipe = &sdev->pipe; + const uint32_t *formats; + size_t nformats; + int ret; + + ret = drmm_mode_config_init(dev); + if (ret) + return ret; + + dev->mode_config.min_width = mode->hdisplay; + dev->mode_config.max_width = mode->hdisplay; + dev->mode_config.min_height = mode->vdisplay; + dev->mode_config.max_height = mode->vdisplay; + dev->mode_config.prefer_shadow_fbdev = true; + dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8; + dev->mode_config.funcs = &simpledrm_mode_config_funcs; + + ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); + if (ret) + return ret; + drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs); + + formats = simpledrm_device_formats(sdev, &nformats); + + ret = drm_simple_display_pipe_init(dev, pipe, &simpledrm_simple_display_pipe_funcs, + formats, nformats, simpledrm_format_modifiers, + connector); + if (ret) + return ret; + + drm_mode_config_reset(dev); + + return 0; +} + +/* + * Init / Cleanup + */ + +static struct simpledrm_device * +simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) +{ + struct simpledrm_device *sdev; + int ret; + + sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, + dev); + if (IS_ERR(sdev)) + return ERR_CAST(sdev); + sdev->pdev = pdev; + platform_set_drvdata(pdev, sdev); + + ret = simpledrm_device_init_clocks(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_regulators(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_fb(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_mm(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_modeset(sdev); + if (ret) + return ERR_PTR(ret); + + return sdev; +} + +/* + * DRM driver + */ + +DEFINE_DRM_GEM_FOPS(simpledrm_fops); + +static struct drm_driver simpledrm_driver = { + DRM_GEM_SHMEM_DRIVER_OPS, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, + .fops = &simpledrm_fops, +}; + +/* + * Platform driver + */ + +static int simpledrm_probe(struct platform_device *pdev) +{ + struct simpledrm_device *sdev; + struct drm_device *dev; + int ret; + + sdev = simpledrm_device_create(&simpledrm_driver, pdev); + if (IS_ERR(sdev)) + return PTR_ERR(sdev); + dev = &sdev->dev; + + ret = drm_dev_register(dev, 0); + if (ret) + return ret; + + drm_fbdev_generic_setup(dev, 0); + + return 0; +} + +static int simpledrm_remove(struct platform_device *pdev) +{ + struct simpledrm_device *sdev = platform_get_drvdata(pdev); + struct drm_device *dev = &sdev->dev; + + drm_dev_unplug(dev); + + return 0; +} + +static const struct of_device_id simpledrm_of_match_table[] = { + { .compatible = "simple-framebuffer", }, + { }, +}; +MODULE_DEVICE_TABLE(of, simpledrm_of_match_table); + +static struct platform_driver simpledrm_platform_driver = { + .driver = { + .name = "simple-framebuffer", /* connect to sysfb */ + .of_match_table = simpledrm_of_match_table, + }, + .probe = simpledrm_probe, + .remove = simpledrm_remove, +}; + +module_platform_driver(simpledrm_platform_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c index 7d216fe9267f..05db980cc047 100644 --- a/drivers/gpu/drm/tiny/st7586.c +++ b/drivers/gpu/drm/tiny/st7586.c @@ -323,16 +323,12 @@ static int st7586_probe(struct spi_device *spi) bufsize = (st7586_mode.vdisplay + 2) / 3 * st7586_mode.hdisplay; dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dbi->reset)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); - return PTR_ERR(dbi->reset); - } + if (IS_ERR(dbi->reset)) + return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n"); a0 = devm_gpiod_get(dev, "a0", GPIOD_OUT_LOW); - if (IS_ERR(a0)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'a0'\n"); - return PTR_ERR(a0); - } + if (IS_ERR(a0)) + return dev_err_probe(dev, PTR_ERR(a0), "Failed to get GPIO 'a0'\n"); device_property_read_u32(dev, "rotation", &rotation); diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c index df8872d62cdd..e8b7815d8cae 100644 --- a/drivers/gpu/drm/tiny/st7735r.c +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -207,16 +207,12 @@ static int st7735r_probe(struct spi_device *spi) drm = &dbidev->drm; dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dbi->reset)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); - return PTR_ERR(dbi->reset); - } + if (IS_ERR(dbi->reset)) + return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n"); dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); - if (IS_ERR(dc)) { - DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); - return PTR_ERR(dc); - } + if (IS_ERR(dc)) + return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n"); dbidev->backlight = devm_of_find_backlight(dev); if (IS_ERR(dbidev->backlight)) diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile index 40e5e9da7953..f906b22959cf 100644 --- a/drivers/gpu/drm/ttm/Makefile +++ b/drivers/gpu/drm/ttm/Makefile @@ -4,7 +4,7 @@ ttm-y := ttm_tt.o ttm_bo.o ttm_bo_util.o ttm_bo_vm.o ttm_module.o \ ttm_execbuf_util.o ttm_range_manager.o ttm_resource.o ttm_pool.o \ - ttm_device.o + ttm_device.o ttm_sys_manager.o ttm-$(CONFIG_AGP) += ttm_agp_backend.o obj-$(CONFIG_DRM_TTM) += ttm.o diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index 0226ae69d3ab..6ddc16f0fe2b 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -32,8 +32,9 @@ #define pr_fmt(fmt) "[TTM] " fmt -#include <drm/ttm/ttm_bo_driver.h> -#include <drm/ttm/ttm_placement.h> +#include <drm/ttm/ttm_device.h> +#include <drm/ttm/ttm_tt.h> +#include <drm/ttm/ttm_resource.h> #include <linux/agp_backend.h> #include <linux/module.h> #include <linux/slab.h> @@ -50,7 +51,6 @@ int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem) { struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm); struct page *dummy_read_page = ttm_glob.dummy_read_page; - struct drm_mm_node *node = bo_mem->mm_node; struct agp_memory *mem; int ret, cached = ttm->caching == ttm_cached; unsigned i; @@ -76,7 +76,7 @@ int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem) mem->is_flushed = 1; mem->type = (cached) ? AGP_USER_CACHED_MEMORY : AGP_USER_MEMORY; - ret = agp_bind_memory(mem, node->start); + ret = agp_bind_memory(mem, bo_mem->start); if (ret) pr_err("AGP Bind memory failed\n"); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index cfd0b9292397..ca1b098b6a56 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -274,7 +274,7 @@ static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo) } /** - * function ttm_bo_cleanup_refs + * ttm_bo_cleanup_refs * If bo idle, remove from lru lists, and unref. * If not idle, block if possible. * @@ -401,6 +401,8 @@ static void ttm_bo_release(struct kref *kref) struct ttm_device *bdev = bo->bdev; int ret; + WARN_ON_ONCE(bo->pin_count); + if (!bo->deleted) { ret = ttm_bo_individualize_resv(bo); if (ret) { @@ -434,7 +436,7 @@ static void ttm_bo_release(struct kref *kref) * FIXME: QXL is triggering this. Can be removed when the * driver is fixed. */ - if (WARN_ON_ONCE(bo->pin_count)) { + if (bo->pin_count) { bo->pin_count = 0; ttm_bo_move_to_lru_tail(bo, &bo->mem, NULL); } @@ -458,8 +460,6 @@ static void ttm_bo_release(struct kref *kref) atomic_dec(&ttm_glob.bo_count); dma_fence_put(bo->moving); - if (!ttm_bo_uses_embedded_gem_object(bo)) - dma_resv_fini(&bo->base._resv); bo->destroy(bo); } @@ -507,11 +507,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, return ttm_tt_create(bo, false); } - evict_mem = bo->mem; - evict_mem.mm_node = NULL; - evict_mem.bus.offset = 0; - evict_mem.bus.addr = NULL; - ret = ttm_bo_mem_space(bo, &placement, &evict_mem, ctx); if (ret) { if (ret != -ERESTARTSYS) { @@ -867,12 +862,8 @@ static int ttm_bo_bounce_temp_buffer(struct ttm_buffer_object *bo, struct ttm_place *hop) { struct ttm_placement hop_placement; + struct ttm_resource hop_mem; int ret; - struct ttm_resource hop_mem = *mem; - - hop_mem.mm_node = NULL; - hop_mem.mem_type = TTM_PL_SYSTEM; - hop_mem.placement = 0; hop_placement.num_placement = hop_placement.num_busy_placement = 1; hop_placement.placement = hop_placement.busy_placement = hop; @@ -894,20 +885,14 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, struct ttm_placement *placement, struct ttm_operation_ctx *ctx) { - int ret = 0; struct ttm_place hop; struct ttm_resource mem; + int ret; dma_resv_assert_held(bo->base.resv); memset(&hop, 0, sizeof(hop)); - mem.num_pages = PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT; - mem.page_alignment = bo->mem.page_alignment; - mem.bus.offset = 0; - mem.bus.addr = NULL; - mem.mm_node = NULL; - /* * Determine where to move the buffer. * @@ -1028,6 +1013,7 @@ int ttm_bo_init_reserved(struct ttm_device *bdev, struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)) { + static const struct ttm_place sys_mem = { .mem_type = TTM_PL_SYSTEM }; bool locked; int ret = 0; @@ -1038,14 +1024,9 @@ int ttm_bo_init_reserved(struct ttm_device *bdev, INIT_LIST_HEAD(&bo->ddestroy); bo->bdev = bdev; bo->type = type; - bo->mem.mem_type = TTM_PL_SYSTEM; - bo->mem.num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - bo->mem.mm_node = NULL; - bo->mem.page_alignment = page_alignment; - bo->mem.bus.offset = 0; - bo->mem.bus.addr = NULL; + bo->page_alignment = page_alignment; + ttm_resource_alloc(bo, &sys_mem, &bo->mem); bo->moving = NULL; - bo->mem.placement = 0; bo->pin_count = 0; bo->sg = sg; if (resv) { @@ -1054,15 +1035,6 @@ int ttm_bo_init_reserved(struct ttm_device *bdev, } else { bo->base.resv = &bo->base._resv; } - if (!ttm_bo_uses_embedded_gem_object(bo)) { - /* - * bo.base is not initialized, so we have to setup the - * struct elements we want use regardless. - */ - bo->base.size = size; - dma_resv_init(&bo->base._resv); - drm_vma_node_reset(&bo->base.vma_node); - } atomic_inc(&ttm_glob.bo_count); /* @@ -1194,14 +1166,16 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, if (bo->mem.mem_type != TTM_PL_SYSTEM) { struct ttm_operation_ctx ctx = { false, false }; struct ttm_resource evict_mem; - struct ttm_place hop; + struct ttm_place place, hop; + memset(&place, 0, sizeof(place)); memset(&hop, 0, sizeof(hop)); - evict_mem = bo->mem; - evict_mem.mm_node = NULL; - evict_mem.placement = 0; - evict_mem.mem_type = TTM_PL_SYSTEM; + place.mem_type = TTM_PL_SYSTEM; + + ret = ttm_resource_alloc(bo, &place, &evict_mem); + if (unlikely(ret)) + goto out; ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, &ctx, &hop); if (unlikely(ret != 0)) { diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index efb7e9c34ab4..ae8b61460724 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -664,6 +664,7 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) { + static const struct ttm_place sys_mem = { .mem_type = TTM_PL_SYSTEM }; struct ttm_buffer_object *ghost; int ret; @@ -676,8 +677,7 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) if (ret) ttm_bo_wait(bo, false, false); - memset(&bo->mem, 0, sizeof(bo->mem)); - bo->mem.mem_type = TTM_PL_SYSTEM; + ttm_resource_alloc(bo, &sys_mem, &bo->mem); bo->ttm = NULL; dma_resv_unlock(&ghost->base._resv); diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index 9b787b3caeb5..460953dcad11 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -36,11 +36,11 @@ #include "ttm_module.h" -/** +/* * ttm_global_mutex - protecting the global state */ -DEFINE_MUTEX(ttm_global_mutex); -unsigned ttm_glob_use_count; +static DEFINE_MUTEX(ttm_global_mutex); +static unsigned ttm_glob_use_count; struct ttm_global ttm_glob; EXPORT_SYMBOL(ttm_glob); @@ -104,7 +104,7 @@ out: return ret; } -/** +/* * A buffer object shrink method that tries to swap out the first * buffer object on the global::swap_lru list. */ @@ -112,7 +112,7 @@ int ttm_global_swapout(struct ttm_operation_ctx *ctx, gfp_t gfp_flags) { struct ttm_global *glob = &ttm_glob; struct ttm_device *bdev; - int ret = -EBUSY; + int ret = 0; mutex_lock(&ttm_global_mutex); list_for_each_entry(bdev, &glob->device_list, device_list) { @@ -165,21 +165,6 @@ int ttm_device_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx, } EXPORT_SYMBOL(ttm_device_swapout); -static void ttm_init_sysman(struct ttm_device *bdev) -{ - struct ttm_resource_manager *man = &bdev->sysman; - - /* - * Initialize the system memory buffer type. - * Other types need to be driver / IOCTL initialized. - */ - man->use_tt = true; - - ttm_resource_manager_init(man, 0); - ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); - ttm_resource_manager_set_used(man, true); -} - static void ttm_device_delayed_workqueue(struct work_struct *work) { struct ttm_device *bdev = @@ -222,7 +207,7 @@ int ttm_device_init(struct ttm_device *bdev, struct ttm_device_funcs *funcs, bdev->funcs = funcs; - ttm_init_sysman(bdev); + ttm_sys_man_init(bdev); ttm_pool_init(&bdev->pool, dev, use_dma_alloc, use_dma32); bdev->vma_manager = vma_manager; diff --git a/drivers/gpu/drm/ttm/ttm_module.h b/drivers/gpu/drm/ttm/ttm_module.h index d7cac5d4b835..767fe22aed48 100644 --- a/drivers/gpu/drm/ttm/ttm_module.h +++ b/drivers/gpu/drm/ttm/ttm_module.h @@ -34,7 +34,10 @@ #define TTM_PFX "[TTM] " struct dentry; +struct ttm_device; extern struct dentry *ttm_debugfs_root; +void ttm_sys_man_init(struct ttm_device *bdev); + #endif /* _TTM_MODULE_H_ */ diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c index 707e5c152896..b9d5da6e6a81 100644 --- a/drivers/gpu/drm/ttm/ttm_range_manager.c +++ b/drivers/gpu/drm/ttm/ttm_range_manager.c @@ -48,7 +48,8 @@ struct ttm_range_manager { spinlock_t lock; }; -static inline struct ttm_range_manager *to_range_manager(struct ttm_resource_manager *man) +static inline struct ttm_range_manager * +to_range_manager(struct ttm_resource_manager *man) { return container_of(man, struct ttm_range_manager, manager); } @@ -78,9 +79,8 @@ static int ttm_range_man_alloc(struct ttm_resource_manager *man, mode = DRM_MM_INSERT_HIGH; spin_lock(&rman->lock); - ret = drm_mm_insert_node_in_range(mm, node, - mem->num_pages, - mem->page_alignment, 0, + ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages, + bo->page_alignment, 0, place->fpfn, lpfn, mode); spin_unlock(&rman->lock); @@ -109,7 +109,21 @@ static void ttm_range_man_free(struct ttm_resource_manager *man, } } -static const struct ttm_resource_manager_func ttm_range_manager_func; +static void ttm_range_man_debug(struct ttm_resource_manager *man, + struct drm_printer *printer) +{ + struct ttm_range_manager *rman = to_range_manager(man); + + spin_lock(&rman->lock); + drm_mm_print(&rman->mm, printer); + spin_unlock(&rman->lock); +} + +static const struct ttm_resource_manager_func ttm_range_manager_func = { + .alloc = ttm_range_man_alloc, + .free = ttm_range_man_free, + .debug = ttm_range_man_debug +}; int ttm_range_man_init(struct ttm_device *bdev, unsigned type, bool use_tt, @@ -163,19 +177,3 @@ int ttm_range_man_fini(struct ttm_device *bdev, return 0; } EXPORT_SYMBOL(ttm_range_man_fini); - -static void ttm_range_man_debug(struct ttm_resource_manager *man, - struct drm_printer *printer) -{ - struct ttm_range_manager *rman = to_range_manager(man); - - spin_lock(&rman->lock); - drm_mm_print(&rman->mm, printer); - spin_unlock(&rman->lock); -} - -static const struct ttm_resource_manager_func ttm_range_manager_func = { - .alloc = ttm_range_man_alloc, - .free = ttm_range_man_free, - .debug = ttm_range_man_debug -}; diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index 04f2eef653ab..59e2b7157e41 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -30,11 +30,17 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo, struct ttm_resource *res) { struct ttm_resource_manager *man = - ttm_manager_type(bo->bdev, res->mem_type); + ttm_manager_type(bo->bdev, place->mem_type); res->mm_node = NULL; - if (!man->func || !man->func->alloc) - return 0; + res->start = 0; + res->num_pages = PFN_UP(bo->base.size); + res->mem_type = place->mem_type; + res->placement = place->flags; + res->bus.addr = NULL; + res->bus.offset = 0; + res->bus.is_iomem = false; + res->bus.caching = ttm_cached; return man->func->alloc(man, bo, place, res); } @@ -44,9 +50,7 @@ void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res) struct ttm_resource_manager *man = ttm_manager_type(bo->bdev, res->mem_type); - if (man->func && man->func->free) - man->func->free(man, res); - + man->func->free(man, res); res->mm_node = NULL; res->mem_type = TTM_PL_SYSTEM; } @@ -139,7 +143,7 @@ void ttm_resource_manager_debug(struct ttm_resource_manager *man, drm_printf(p, " use_type: %d\n", man->use_type); drm_printf(p, " use_tt: %d\n", man->use_tt); drm_printf(p, " size: %llu\n", man->size); - if (man->func && man->func->debug) - (*man->func->debug)(man, p); + if (man->func->debug) + man->func->debug(man, p); } EXPORT_SYMBOL(ttm_resource_manager_debug); diff --git a/drivers/gpu/drm/ttm/ttm_sys_manager.c b/drivers/gpu/drm/ttm/ttm_sys_manager.c new file mode 100644 index 000000000000..474221e863d0 --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_sys_manager.c @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ + +#include <drm/ttm/ttm_resource.h> +#include <drm/ttm/ttm_device.h> +#include <drm/ttm/ttm_placement.h> + +#include "ttm_module.h" + +static int ttm_sys_man_alloc(struct ttm_resource_manager *man, + struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_resource *mem) +{ + return 0; +} + +static void ttm_sys_man_free(struct ttm_resource_manager *man, + struct ttm_resource *mem) +{ +} + +static const struct ttm_resource_manager_func ttm_sys_manager_func = { + .alloc = ttm_sys_man_alloc, + .free = ttm_sys_man_free, +}; + +void ttm_sys_man_init(struct ttm_device *bdev) +{ + struct ttm_resource_manager *man = &bdev->sysman; + + /* + * Initialize the system memory buffer type. + * Other types need to be driver / IOCTL initialized. + */ + man->use_tt = true; + man->func = &ttm_sys_manager_func; + + ttm_resource_manager_init(man, 0); + ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); + ttm_resource_manager_set_used(man, true); +} diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 7dcd3fb69495..539e0232cb3b 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -317,16 +317,21 @@ int ttm_tt_populate(struct ttm_device *bdev, if (ttm_tt_is_populated(ttm)) return 0; - atomic_long_add(ttm->num_pages, &ttm_pages_allocated); - if (bdev->pool.use_dma32) - atomic_long_add(ttm->num_pages, &ttm_dma32_pages_allocated); + if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) { + atomic_long_add(ttm->num_pages, &ttm_pages_allocated); + if (bdev->pool.use_dma32) + atomic_long_add(ttm->num_pages, + &ttm_dma32_pages_allocated); + } while (atomic_long_read(&ttm_pages_allocated) > ttm_pages_limit || atomic_long_read(&ttm_dma32_pages_allocated) > ttm_dma32_pages_limit) { ret = ttm_global_swapout(ctx, GFP_KERNEL); - if (ret) + if (ret == 0) + break; + if (ret < 0) goto error; } @@ -350,9 +355,12 @@ int ttm_tt_populate(struct ttm_device *bdev, return 0; error: - atomic_long_sub(ttm->num_pages, &ttm_pages_allocated); - if (bdev->pool.use_dma32) - atomic_long_sub(ttm->num_pages, &ttm_dma32_pages_allocated); + if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) { + atomic_long_sub(ttm->num_pages, &ttm_pages_allocated); + if (bdev->pool.use_dma32) + atomic_long_sub(ttm->num_pages, + &ttm_dma32_pages_allocated); + } return ret; } EXPORT_SYMBOL(ttm_tt_populate); @@ -382,13 +390,31 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) else ttm_pool_free(&bdev->pool, ttm); - atomic_long_sub(ttm->num_pages, &ttm_pages_allocated); - if (bdev->pool.use_dma32) - atomic_long_sub(ttm->num_pages, &ttm_dma32_pages_allocated); + if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) { + atomic_long_sub(ttm->num_pages, &ttm_pages_allocated); + if (bdev->pool.use_dma32) + atomic_long_sub(ttm->num_pages, + &ttm_dma32_pages_allocated); + } ttm->page_flags &= ~TTM_PAGE_FLAG_PRIV_POPULATED; } +#ifdef CONFIG_DEBUG_FS + +/* Test the shrinker functions and dump the result */ +static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data) +{ + struct ttm_operation_ctx ctx = { false, false }; + + seq_printf(m, "%d\n", ttm_global_swapout(&ctx, GFP_KERNEL)); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ttm_tt_debugfs_shrink); + +#endif + + /** * ttm_tt_mgr_init - register with the MM shrinker * @@ -396,6 +422,11 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) */ void ttm_tt_mgr_init(unsigned long num_pages, unsigned long num_dma32_pages) { +#ifdef CONFIG_DEBUG_FS + debugfs_create_file("tt_shrink", 0400, ttm_debugfs_root, NULL, + &ttm_tt_debugfs_shrink_fops); +#endif + if (!ttm_pages_limit) ttm_pages_limit = num_pages; diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c index e534896b6cfd..6d4b32da9866 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.c +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c @@ -12,6 +12,7 @@ #include <linux/pci.h> #include <linux/vt_kern.h> +#include <drm/drm_aperture.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> @@ -42,7 +43,7 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!vbox_check_supported(VBE_DISPI_ID_HGSMI)) return -ENODEV; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "vboxvideodrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "vboxvideodrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 556ad0f02a0d..9eff45b48869 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> @@ -56,10 +57,8 @@ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index) res = platform_get_resource(dev, IORESOURCE_MEM, index); map = devm_ioremap_resource(&dev->dev, res); - if (IS_ERR(map)) { - DRM_ERROR("Failed to map registers: %ld\n", PTR_ERR(map)); + if (IS_ERR(map)) return map; - } return map; } @@ -266,7 +265,9 @@ static int vc4_drm_bind(struct device *dev) if (ret) goto unbind_all; - drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false); + ret = drm_aperture_remove_framebuffers(false, "vc4drmfb"); + if (ret) + goto unbind_all; ret = vc4_kms_load(drm); if (ret < 0) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index a7500716cf3f..5dceadc61600 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -825,7 +825,7 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc, void vc4_crtc_reset(struct drm_crtc *crtc); void vc4_crtc_handle_vblank(struct vc4_crtc *crtc); void vc4_crtc_get_margins(struct drm_crtc_state *state, - unsigned int *right, unsigned int *left, + unsigned int *left, unsigned int *right, unsigned int *top, unsigned int *bottom); /* vc4_debugfs.c */ diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1fda574579af..c27b287d2053 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -214,6 +214,32 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) return ret; } +static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct drm_connector_state *old_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_connector_state *new_state = + drm_atomic_get_new_connector_state(state, connector); + struct drm_crtc *crtc = new_state->crtc; + + if (!crtc) + return 0; + + if (old_state->colorspace != new_state->colorspace || + !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->mode_changed = true; + } + + return 0; +} + static void vc4_hdmi_connector_reset(struct drm_connector *connector) { struct vc4_hdmi_connector_state *old_state = @@ -263,6 +289,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { .get_modes = vc4_hdmi_connector_get_modes, + .atomic_check = vc4_hdmi_connector_atomic_check, }; static int vc4_hdmi_connector_init(struct drm_device *dev, @@ -290,6 +317,11 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, if (ret) return ret; + ret = drm_mode_create_hdmi_colorspace_property(connector); + if (ret) + return ret; + + drm_connector_attach_colorspace_property(connector); drm_connector_attach_tv_margin_properties(connector); drm_connector_attach_max_bpc_property(connector, 8, 12); @@ -299,6 +331,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, connector->interlace_allowed = 1; connector->doublescan_allowed = 0; + if (vc4_hdmi->variant->supports_hdr) + drm_connector_attach_hdr_output_metadata_property(connector); + drm_connector_attach_encoder(connector, encoder); return 0; @@ -395,7 +430,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) vc4_encoder->limited_rgb_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL); - + drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate); drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); vc4_hdmi_write_infoframe(encoder, &frame); @@ -432,6 +467,25 @@ static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder) vc4_hdmi_write_infoframe(encoder, &frame); } +static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder) +{ + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_connector *connector = &vc4_hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + union hdmi_infoframe frame; + + if (!vc4_hdmi->variant->supports_hdr) + return; + + if (!conn_state->hdr_output_metadata) + return; + + if (drm_hdmi_infoframe_set_hdr_metadata(&frame.drm, conn_state)) + return; + + vc4_hdmi_write_infoframe(encoder, &frame); +} + static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); @@ -444,6 +498,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) */ if (vc4_hdmi->audio.streaming) vc4_hdmi_set_audio_infoframe(encoder); + + vc4_hdmi_set_hdr_infoframe(encoder); } static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, @@ -2102,6 +2158,7 @@ static const struct vc4_hdmi_variant bcm2835_variant = { .phy_rng_enable = vc4_hdmi_phy_rng_enable, .phy_rng_disable = vc4_hdmi_phy_rng_disable, .channel_map = vc4_hdmi_channel_map, + .supports_hdr = false, }; static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { @@ -2129,6 +2186,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { .phy_rng_enable = vc5_hdmi_phy_rng_enable, .phy_rng_disable = vc5_hdmi_phy_rng_disable, .channel_map = vc5_hdmi_channel_map, + .supports_hdr = true, }; static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { @@ -2156,6 +2214,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { .phy_rng_enable = vc5_hdmi_phy_rng_enable, .phy_rng_disable = vc5_hdmi_phy_rng_disable, .channel_map = vc5_hdmi_channel_map, + .supports_hdr = true, }; static const struct of_device_id vc4_hdmi_dt_match[] = { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 3cebd1fd00fc..060bcaefbeb5 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -99,6 +99,9 @@ struct vc4_hdmi_variant { /* Callback to get channel map */ u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask); + + /* Enables HDR metadata */ + bool supports_hdr; }; /* HDMI audio information */ diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index bb5529a7a9c2..f29ac64a5aa5 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -899,7 +899,6 @@ int vc4_kms_load(struct drm_device *dev) dev->mode_config.helper_private = &vc4_mode_config_helpers; dev->mode_config.preferred_depth = 24; dev->mode_config.async_page_flip = true; - dev->mode_config.allow_fb_modifiers = true; ret = vc4_ctm_obj_init(vc4); if (ret) diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index bd5b8eb58b18..090529d0d5dc 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -197,12 +197,6 @@ struct vc4_vec_connector { struct drm_encoder *encoder; }; -static inline struct vc4_vec_connector * -to_vc4_vec_connector(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_vec_connector, base); -} - enum vc4_vec_tv_mode_id { VC4_VEC_TV_MODE_NTSC, VC4_VEC_TV_MODE_NTSC_J, diff --git a/drivers/gpu/drm/via/via_dma.c b/drivers/gpu/drm/via/via_dma.c index cd56ffa3df58..177b0499abf1 100644 --- a/drivers/gpu/drm/via/via_dma.c +++ b/drivers/gpu/drm/via/via_dma.c @@ -38,7 +38,6 @@ #include <linux/uaccess.h> #include <drm/drm.h> -#include <drm/drm_agpsupport.h> #include <drm/drm_device.h> #include <drm/drm_file.h> #include <drm/via_drm.h> diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index 5771bb53ce6a..e016a4d62090 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -494,6 +494,7 @@ via_dmablit_workqueue(struct work_struct *work) { drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); struct drm_device *dev = blitq->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); unsigned long irqsave; drm_via_sg_info_t *cur_sg; int cur_released; @@ -520,7 +521,7 @@ via_dmablit_workqueue(struct work_struct *work) wake_up(&blitq->busy_queue); - via_free_sg_info(dev->pdev, cur_sg); + via_free_sg_info(pdev, cur_sg); kfree(cur_sg); spin_lock_irqsave(&blitq->blit_lock, irqsave); @@ -540,9 +541,10 @@ via_init_dmablit(struct drm_device *dev) { int i, j; drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + struct pci_dev *pdev = to_pci_dev(dev->dev); drm_via_blitq_t *blitq; - pci_set_master(dev->pdev); + pci_set_master(pdev); for (i = 0; i < VIA_NUM_BLIT_ENGINES; ++i) { blitq = dev_priv->blit_queues + i; @@ -573,6 +575,7 @@ via_init_dmablit(struct drm_device *dev) static int via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) { + struct pci_dev *pdev = to_pci_dev(dev->dev); int draw = xfer->to_fb; int ret = 0; @@ -652,17 +655,17 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) { DRM_ERROR("Could not lock DMA pages.\n"); - via_free_sg_info(dev->pdev, vsg); + via_free_sg_info(pdev, vsg); return ret; } - via_map_blit_for_device(dev->pdev, xfer, vsg, 0); + via_map_blit_for_device(pdev, xfer, vsg, 0); if (0 != (ret = via_alloc_desc_pages(vsg))) { DRM_ERROR("Could not allocate DMA descriptor pages.\n"); - via_free_sg_info(dev->pdev, vsg); + via_free_sg_info(pdev, vsg); return ret; } - via_map_blit_for_device(dev->pdev, xfer, vsg, 1); + via_map_blit_for_device(pdev, xfer, vsg, 1); return 0; } diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c index 255c5066a939..a9f6b0c11966 100644 --- a/drivers/gpu/drm/via/via_map.c +++ b/drivers/gpu/drm/via/via_map.c @@ -98,6 +98,7 @@ int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv) int via_driver_load(struct drm_device *dev, unsigned long chipset) { + struct pci_dev *pdev = to_pci_dev(dev->dev); drm_via_private_t *dev_priv; int ret = 0; @@ -110,7 +111,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->chipset = chipset; - pci_set_master(dev->pdev); + pci_set_master(pdev); ret = drm_vblank_init(dev, 1); if (ret) { diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index a21dc3ad6f88..33bf5f53ae31 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -31,6 +31,7 @@ #include <linux/pci.h> #include <drm/drm.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -50,13 +51,16 @@ static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vd const char *pname = dev_name(&pdev->dev); bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; char unique[20]; + int ret; DRM_INFO("pci: %s detected at %s\n", vga ? "virtio-vga" : "virtio-gpu-pci", pname); - if (vga) - drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, - "virtiodrmfb"); + if (vga) { + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "virtiodrmfb"); + if (ret) + return ret; + } /* * Normally the drm_dev_set_unique() call is done by core DRM. diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index 8502400b2f9c..2de61b63ef91 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -64,6 +64,7 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv, { struct drm_gem_object *gobj; struct virtio_gpu_object_params params = { 0 }; + struct virtio_gpu_device *vgdev = dev->dev_private; int ret; uint32_t pitch; @@ -79,6 +80,13 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv, params.height = args->height; params.size = args->size; params.dumb = true; + + if (vgdev->has_resource_blob && !vgdev->has_virgl_3d) { + params.blob_mem = VIRTGPU_BLOB_MEM_GUEST; + params.blob_flags = VIRTGPU_BLOB_FLAG_USE_SHAREABLE; + params.blob = true; + } + ret = virtio_gpu_gem_create(file_priv, dev, ¶ms, &gobj, &args->handle); if (ret) diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 4ff1ec28e630..f648b0e24447 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -254,6 +254,9 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, } if (params->blob) { + if (params->blob_mem == VIRTGPU_BLOB_MEM_GUEST) + bo->guest_blob = true; + virtio_gpu_cmd_resource_create_blob(vgdev, bo, params, ents, nents); } else if (params->virgl) { diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 66c6842d70db..e49523866e1d 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -4,6 +4,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_vblank.h> @@ -64,7 +65,17 @@ static u8 blend_channel(u8 src, u8 dst, u8 alpha) return new_color; } -static void alpha_blending(const u8 *argb_src, u8 *argb_dst) +/** + * alpha_blend - alpha blending equation + * @argb_src: src pixel on premultiplied alpha mode + * @argb_dst: dst pixel completely opaque + * + * blend pixels using premultiplied blend formula. The current DRM assumption + * is that pixel color values have been already pre-multiplied with the alpha + * channel values. See more drm_plane_create_blend_mode_property(). Also, this + * formula assumes a completely opaque background. + */ +static void alpha_blend(const u8 *argb_src, u8 *argb_dst) { u8 alpha; @@ -72,8 +83,16 @@ static void alpha_blending(const u8 *argb_src, u8 *argb_dst) argb_dst[0] = blend_channel(argb_src[0], argb_dst[0], alpha); argb_dst[1] = blend_channel(argb_src[1], argb_dst[1], alpha); argb_dst[2] = blend_channel(argb_src[2], argb_dst[2], alpha); - /* Opaque primary */ - argb_dst[3] = 0xFF; +} + +/** + * x_blend - blending equation that ignores the pixel alpha + * + * overwrites RGB color value from src pixel to dst pixel. + */ +static void x_blend(const u8 *xrgb_src, u8 *xrgb_dst) +{ + memcpy(xrgb_dst, xrgb_src, sizeof(u8) * 3); } /** @@ -82,16 +101,20 @@ static void alpha_blending(const u8 *argb_src, u8 *argb_dst) * @vaddr_src: source address * @dst_composer: destination framebuffer's metadata * @src_composer: source framebuffer's metadata + * @pixel_blend: blending equation based on plane format * - * Blend the vaddr_src value with the vaddr_dst value using the pre-multiplied - * alpha blending equation, since DRM currently assumes that the pixel color - * values have already been pre-multiplied with the alpha channel values. See - * more drm_plane_create_blend_mode_property(). This function uses buffer's - * metadata to locate the new composite values at vaddr_dst. + * Blend the vaddr_src value with the vaddr_dst value using a pixel blend + * equation according to the supported plane formats DRM_FORMAT_(A/XRGB8888) + * and clearing alpha channel to an completely opaque background. This function + * uses buffer's metadata to locate the new composite values at vaddr_dst. + * + * TODO: completely clear the primary plane (a = 0xff) before starting to blend + * pixel color values */ static void blend(void *vaddr_dst, void *vaddr_src, struct vkms_composer *dst_composer, - struct vkms_composer *src_composer) + struct vkms_composer *src_composer, + void (*pixel_blend)(const u8 *, u8 *)) { int i, j, j_dst, i_dst; int offset_src, offset_dst; @@ -119,36 +142,46 @@ static void blend(void *vaddr_dst, void *vaddr_src, pixel_src = (u8 *)(vaddr_src + offset_src); pixel_dst = (u8 *)(vaddr_dst + offset_dst); - alpha_blending(pixel_src, pixel_dst); + pixel_blend(pixel_src, pixel_dst); + /* clearing alpha channel (0xff)*/ + pixel_dst[3] = 0xff; } i_dst++; } } -static void compose_cursor(struct vkms_composer *cursor_composer, - struct vkms_composer *primary_composer, - void *vaddr_out) +static void compose_plane(struct vkms_composer *primary_composer, + struct vkms_composer *plane_composer, + void *vaddr_out) { - struct drm_gem_object *cursor_obj; - struct drm_gem_shmem_object *cursor_shmem_obj; + struct drm_gem_object *plane_obj; + struct drm_gem_shmem_object *plane_shmem_obj; + struct drm_framebuffer *fb = &plane_composer->fb; + void (*pixel_blend)(const u8 *p_src, u8 *p_dst); - cursor_obj = drm_gem_fb_get_obj(&cursor_composer->fb, 0); - cursor_shmem_obj = to_drm_gem_shmem_obj(cursor_obj); + plane_obj = drm_gem_fb_get_obj(&plane_composer->fb, 0); + plane_shmem_obj = to_drm_gem_shmem_obj(plane_obj); - if (WARN_ON(!cursor_shmem_obj->vaddr)) + if (WARN_ON(!plane_shmem_obj->vaddr)) return; - blend(vaddr_out, cursor_shmem_obj->vaddr, - primary_composer, cursor_composer); + if (fb->format->format == DRM_FORMAT_ARGB8888) + pixel_blend = &alpha_blend; + else + pixel_blend = &x_blend; + + blend(vaddr_out, plane_shmem_obj->vaddr, primary_composer, + plane_composer, pixel_blend); } -static int compose_planes(void **vaddr_out, - struct vkms_composer *primary_composer, - struct vkms_composer *cursor_composer) +static int compose_active_planes(void **vaddr_out, + struct vkms_composer *primary_composer, + struct vkms_crtc_state *crtc_state) { struct drm_framebuffer *fb = &primary_composer->fb; struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0); struct drm_gem_shmem_object *shmem_obj = to_drm_gem_shmem_obj(gem_obj); + int i; if (!*vaddr_out) { *vaddr_out = kzalloc(shmem_obj->base.size, GFP_KERNEL); @@ -163,8 +196,14 @@ static int compose_planes(void **vaddr_out, memcpy(*vaddr_out, shmem_obj->vaddr, shmem_obj->base.size); - if (cursor_composer) - compose_cursor(cursor_composer, primary_composer, *vaddr_out); + /* If there are other planes besides primary, we consider the active + * planes should be in z-order and compose them associatively: + * ((primary <- overlay) <- cursor) + */ + for (i = 1; i < crtc_state->num_active_planes; i++) + compose_plane(primary_composer, + crtc_state->active_planes[i]->composer, + *vaddr_out); return 0; } @@ -186,7 +225,7 @@ void vkms_composer_worker(struct work_struct *work) struct drm_crtc *crtc = crtc_state->base.crtc; struct vkms_output *out = drm_crtc_to_vkms_output(crtc); struct vkms_composer *primary_composer = NULL; - struct vkms_composer *cursor_composer = NULL; + struct vkms_plane_state *act_plane = NULL; bool crc_pending, wb_pending; void *vaddr_out = NULL; u32 crc32 = 0; @@ -210,11 +249,11 @@ void vkms_composer_worker(struct work_struct *work) if (!crc_pending) return; - if (crtc_state->num_active_planes >= 1) - primary_composer = crtc_state->active_planes[0]->composer; - - if (crtc_state->num_active_planes == 2) - cursor_composer = crtc_state->active_planes[1]->composer; + if (crtc_state->num_active_planes >= 1) { + act_plane = crtc_state->active_planes[0]; + if (act_plane->base.plane->type == DRM_PLANE_TYPE_PRIMARY) + primary_composer = act_plane->composer; + } if (!primary_composer) return; @@ -222,7 +261,8 @@ void vkms_composer_worker(struct work_struct *work) if (wb_pending) vaddr_out = crtc_state->active_writeback; - ret = compose_planes(&vaddr_out, primary_composer, cursor_composer); + ret = compose_active_planes(&vaddr_out, primary_composer, + crtc_state); if (ret) { if (ret == -EINVAL && !wb_pending) kfree(vaddr_out); diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 2173b82606f6..027ffe759440 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -44,6 +44,10 @@ static bool enable_writeback = true; module_param_named(enable_writeback, enable_writeback, bool, 0444); MODULE_PARM_DESC(enable_writeback, "Enable/Disable writeback connector support"); +static bool enable_overlay; +module_param_named(enable_overlay, enable_overlay, bool, 0444); +MODULE_PARM_DESC(enable_overlay, "Enable/Disable overlay support"); + DEFINE_DRM_GEM_FOPS(vkms_driver_fops); static void vkms_release(struct drm_device *dev) @@ -198,6 +202,7 @@ static int __init vkms_init(void) config->cursor = enable_cursor; config->writeback = enable_writeback; + config->overlay = enable_overlay; return vkms_create(config); } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 35540c7c4416..ac8c9c2fa4ed 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -37,6 +37,10 @@ struct vkms_plane_state { struct vkms_composer *composer; }; +struct vkms_plane { + struct drm_plane base; +}; + /** * vkms_crtc_state - Driver specific CRTC state * @base: base CRTC state @@ -85,6 +89,7 @@ struct vkms_device; struct vkms_config { bool writeback; bool cursor; + bool overlay; /* only set when instantiated */ struct vkms_device *dev; }; @@ -114,8 +119,8 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, int vkms_output_init(struct vkms_device *vkmsdev, int index); -struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type, int index); +struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, + enum drm_plane_type type, int index); /* CRC Support */ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index f5f6f15c362c..04406bd3ff02 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -39,7 +39,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) struct drm_connector *connector = &output->connector; struct drm_encoder *encoder = &output->encoder; struct drm_crtc *crtc = &output->crtc; - struct drm_plane *primary, *cursor = NULL; + struct vkms_plane *primary, *cursor = NULL, *overlay = NULL; int ret; int writeback; @@ -47,17 +47,24 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) if (IS_ERR(primary)) return PTR_ERR(primary); + if (vkmsdev->config->overlay) { + overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); + if (IS_ERR(overlay)) + return PTR_ERR(overlay); + + if (!overlay->base.possible_crtcs) + overlay->base.possible_crtcs = drm_crtc_mask(crtc); + } + if (vkmsdev->config->cursor) { cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); - if (IS_ERR(cursor)) { - ret = PTR_ERR(cursor); - goto err_cursor; - } + if (IS_ERR(cursor)) + return PTR_ERR(cursor); } - ret = vkms_crtc_init(dev, crtc, primary, cursor); + ret = vkms_crtc_init(dev, crtc, &primary->base, &cursor->base); if (ret) - goto err_crtc; + return ret; ret = drm_connector_init(dev, connector, &vkms_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -100,12 +107,5 @@ err_encoder: err_connector: drm_crtc_cleanup(crtc); -err_crtc: - if (vkmsdev->config->cursor) - drm_plane_cleanup(cursor); - -err_cursor: - drm_plane_cleanup(primary); - return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 6d310d31b75d..107521ace597 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -16,8 +16,9 @@ static const u32 vkms_formats[] = { DRM_FORMAT_XRGB8888, }; -static const u32 vkms_cursor_formats[] = { +static const u32 vkms_plane_formats[] = { DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888 }; static struct drm_plane_state * @@ -86,7 +87,6 @@ static void vkms_plane_reset(struct drm_plane *plane) static const struct drm_plane_funcs vkms_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_plane_cleanup, .reset = vkms_plane_reset, .atomic_duplicate_state = vkms_plane_duplicate_state, .atomic_destroy_state = vkms_plane_destroy_state, @@ -133,7 +133,7 @@ static int vkms_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (plane->type == DRM_PLANE_TYPE_CURSOR) + if (plane->type != DRM_PLANE_TYPE_PRIMARY) can_position = true; ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, @@ -191,39 +191,42 @@ static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { .cleanup_fb = vkms_cleanup_fb, }; -struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type, int index) +struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, + enum drm_plane_type type, int index) { struct drm_device *dev = &vkmsdev->drm; const struct drm_plane_helper_funcs *funcs; - struct drm_plane *plane; + struct vkms_plane *plane; const u32 *formats; - int ret, nformats; + int nformats; - plane = kzalloc(sizeof(*plane), GFP_KERNEL); - if (!plane) - return ERR_PTR(-ENOMEM); - - if (type == DRM_PLANE_TYPE_CURSOR) { - formats = vkms_cursor_formats; - nformats = ARRAY_SIZE(vkms_cursor_formats); + switch (type) { + case DRM_PLANE_TYPE_PRIMARY: + formats = vkms_formats; + nformats = ARRAY_SIZE(vkms_formats); funcs = &vkms_primary_helper_funcs; - } else { + break; + case DRM_PLANE_TYPE_CURSOR: + case DRM_PLANE_TYPE_OVERLAY: + formats = vkms_plane_formats; + nformats = ARRAY_SIZE(vkms_plane_formats); + funcs = &vkms_primary_helper_funcs; + break; + default: formats = vkms_formats; nformats = ARRAY_SIZE(vkms_formats); funcs = &vkms_primary_helper_funcs; + break; } - ret = drm_universal_plane_init(dev, plane, 1 << index, - &vkms_plane_funcs, - formats, nformats, - NULL, type, NULL); - if (ret) { - kfree(plane); - return ERR_PTR(ret); - } + plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index, + &vkms_plane_funcs, + formats, nformats, + NULL, type, NULL); + if (IS_ERR(plane)) + return plane; - drm_plane_helper_add(plane, funcs); + drm_plane_helper_add(&plane->base, funcs); return plane; } diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index 15acdf2a7c0f..0060ef842b5a 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig @@ -1,13 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 config DRM_VMWGFX tristate "DRM driver for VMware Virtual GPU" - depends on DRM && PCI && X86 && MMU - select FB_DEFERRED_IO - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + depends on DRM && PCI && MMU + depends on X86 || ARM64 select DRM_TTM - select FB select MAPPING_DIRTY_HELPERS # Only needed for the transitional use of drm_crtc_init - can be removed # again once vmwgfx sets up the primary plane itself. @@ -20,7 +16,7 @@ config DRM_VMWGFX The compiled module will be called "vmwgfx.ko". config DRM_VMWGFX_FBCON - depends on DRM_VMWGFX && FB + depends on DRM_VMWGFX && DRM_FBDEV_EMULATION bool "Enable framebuffer console under vmwgfx by default" help Choose this option if you are shipping a new vmwgfx diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 8c02fa5852e7..09f6dcac768b 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ - vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ + vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \ vmwgfx_bo.o vmwgfx_scrn.o vmwgfx_context.o \ @@ -9,7 +9,9 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \ vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \ - ttm_object.o ttm_lock.o ttm_memory.o + ttm_object.o ttm_memory.o +vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o + obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h index 4db25bd9fa22..127eaf0a0a58 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h @@ -1467,6 +1467,7 @@ struct svga3dsurface_cache { /** * struct svga3dsurface_loc - Surface location + * @sheet: The multisample sheet. * @sub_resource: Surface subresource. Defined as layer * num_mip_levels + * mip_level. * @x: X coordinate. @@ -1474,6 +1475,7 @@ struct svga3dsurface_cache { * @z: Z coordinate. */ struct svga3dsurface_loc { + u32 sheet; u32 sub_resource; u32 x, y, z; }; @@ -1566,8 +1568,8 @@ svga3dsurface_get_loc(const struct svga3dsurface_cache *cache, u32 layer; int i; - if (offset >= cache->sheet_bytes) - offset %= cache->sheet_bytes; + loc->sheet = offset / cache->sheet_bytes; + offset -= loc->sheet * cache->sheet_bytes; layer = offset / cache->mip_chain_bytes; offset -= layer * cache->mip_chain_bytes; @@ -1631,6 +1633,7 @@ svga3dsurface_min_loc(const struct svga3dsurface_cache *cache, u32 sub_resource, struct svga3dsurface_loc *loc) { + loc->sheet = 0; loc->sub_resource = sub_resource; loc->x = loc->y = loc->z = 0; } @@ -1652,6 +1655,7 @@ svga3dsurface_max_loc(const struct svga3dsurface_cache *cache, const struct drm_vmw_size *size; u32 mip; + loc->sheet = 0; loc->sub_resource = sub_resource + 1; mip = sub_resource % cache->num_mip_levels; size = &cache->mip[mip].size; diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index 19fb9e3299e7..193a57f6aae5 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 1998-2015 VMware, Inc. + * Copyright 1998-2021 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -98,6 +98,10 @@ typedef uint32 SVGAMobId; #define SVGA_MAGIC 0x900000UL #define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver)) +/* Version 3 has the control bar instead of the FIFO */ +#define SVGA_VERSION_3 3 +#define SVGA_ID_3 SVGA_MAKE_ID(SVGA_VERSION_3) + /* Version 2 let the address of the frame buffer be unsigned on Win32 */ #define SVGA_VERSION_2 2 #define SVGA_ID_2 SVGA_MAKE_ID(SVGA_VERSION_2) @@ -129,11 +133,12 @@ typedef uint32 SVGAMobId; * Interrupts are only supported when the * SVGA_CAP_IRQMASK capability is present. */ -#define SVGA_IRQFLAG_ANY_FENCE 0x1 /* Any fence was passed */ -#define SVGA_IRQFLAG_FIFO_PROGRESS 0x2 /* Made forward progress in the FIFO */ -#define SVGA_IRQFLAG_FENCE_GOAL 0x4 /* SVGA_FIFO_FENCE_GOAL reached */ -#define SVGA_IRQFLAG_COMMAND_BUFFER 0x8 /* Command buffer completed */ -#define SVGA_IRQFLAG_ERROR 0x10 /* Error while processing commands */ +#define SVGA_IRQFLAG_ANY_FENCE (1 << 0) /* Any fence was passed */ +#define SVGA_IRQFLAG_FIFO_PROGRESS (1 << 1) /* Made forward progress in the FIFO */ +#define SVGA_IRQFLAG_FENCE_GOAL (1 << 2) /* SVGA_FIFO_FENCE_GOAL reached */ +#define SVGA_IRQFLAG_COMMAND_BUFFER (1 << 3) /* Command buffer completed */ +#define SVGA_IRQFLAG_ERROR (1 << 4) /* Error while processing commands */ +#define SVGA_IRQFLAG_MAX (1 << 5) /* * The byte-size is the size of the actual cursor data, @@ -286,7 +291,32 @@ enum { */ SVGA_REG_GBOBJECT_MEM_SIZE_KB = 76, - SVGA_REG_TOP = 77, /* Must be 1 more than the last register */ + /* + + * These registers are for the addresses of the memory BARs for SVGA3 + */ + SVGA_REG_REGS_START_HIGH32 = 77, + SVGA_REG_REGS_START_LOW32 = 78, + SVGA_REG_FB_START_HIGH32 = 79, + SVGA_REG_FB_START_LOW32 = 80, + + /* + * A hint register that recommends which quality level the guest should + * currently use to define multisample surfaces. + * + * If the register is SVGA_REG_MSHINT_DISABLED, + * the guest is only allowed to use SVGA3D_MS_QUALITY_FULL. + * + * Otherwise, this is a live value that can change while the VM is + * powered on with the hint suggestion for which quality level the guest + * should be using. Guests are free to ignore the hint and use either + * RESOLVE or FULL quality. + */ + SVGA_REG_MSHINT = 81, + + SVGA_REG_IRQ_STATUS = 82, + SVGA_REG_DIRTY_TRACKING = 83, + + SVGA_REG_TOP = 84, /* Must be 1 more than the last register */ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */ @@ -310,6 +340,17 @@ typedef enum SVGARegGuestDriverId { SVGA_REG_GUEST_DRIVER_ID_SUBMIT = MAX_UINT32, } SVGARegGuestDriverId; +typedef enum SVGARegMSHint { + SVGA_REG_MSHINT_DISABLED = 0, + SVGA_REG_MSHINT_FULL = 1, + SVGA_REG_MSHINT_RESOLVED = 2, +} SVGARegMSHint; + +typedef enum SVGARegDirtyTracking { + SVGA_REG_DIRTY_TRACKING_PER_IMAGE = 0, + SVGA_REG_DIRTY_TRACKING_PER_SURFACE = 1, +} SVGARegDirtyTracking; + /* * Guest memory regions (GMRs): diff --git a/drivers/gpu/drm/vmwgfx/ttm_lock.c b/drivers/gpu/drm/vmwgfx/ttm_lock.c deleted file mode 100644 index 5971c72e6d10..000000000000 --- a/drivers/gpu/drm/vmwgfx/ttm_lock.c +++ /dev/null @@ -1,194 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -/************************************************************************** - * - * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ -/* - * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> - */ - -#include <linux/atomic.h> -#include <linux/errno.h> -#include <linux/wait.h> -#include <linux/sched/signal.h> -#include "ttm_lock.h" -#include "ttm_object.h" - -#define TTM_WRITE_LOCK_PENDING (1 << 0) -#define TTM_VT_LOCK_PENDING (1 << 1) -#define TTM_SUSPEND_LOCK_PENDING (1 << 2) -#define TTM_VT_LOCK (1 << 3) -#define TTM_SUSPEND_LOCK (1 << 4) - -void ttm_lock_init(struct ttm_lock *lock) -{ - spin_lock_init(&lock->lock); - init_waitqueue_head(&lock->queue); - lock->rw = 0; - lock->flags = 0; -} - -void ttm_read_unlock(struct ttm_lock *lock) -{ - spin_lock(&lock->lock); - if (--lock->rw == 0) - wake_up_all(&lock->queue); - spin_unlock(&lock->lock); -} - -static bool __ttm_read_lock(struct ttm_lock *lock) -{ - bool locked = false; - - spin_lock(&lock->lock); - if (lock->rw >= 0 && lock->flags == 0) { - ++lock->rw; - locked = true; - } - spin_unlock(&lock->lock); - return locked; -} - -int ttm_read_lock(struct ttm_lock *lock, bool interruptible) -{ - int ret = 0; - - if (interruptible) - ret = wait_event_interruptible(lock->queue, - __ttm_read_lock(lock)); - else - wait_event(lock->queue, __ttm_read_lock(lock)); - return ret; -} - -static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked) -{ - bool block = true; - - *locked = false; - - spin_lock(&lock->lock); - if (lock->rw >= 0 && lock->flags == 0) { - ++lock->rw; - block = false; - *locked = true; - } else if (lock->flags == 0) { - block = false; - } - spin_unlock(&lock->lock); - - return !block; -} - -int ttm_read_trylock(struct ttm_lock *lock, bool interruptible) -{ - int ret = 0; - bool locked; - - if (interruptible) - ret = wait_event_interruptible - (lock->queue, __ttm_read_trylock(lock, &locked)); - else - wait_event(lock->queue, __ttm_read_trylock(lock, &locked)); - - if (unlikely(ret != 0)) { - BUG_ON(locked); - return ret; - } - - return (locked) ? 0 : -EBUSY; -} - -void ttm_write_unlock(struct ttm_lock *lock) -{ - spin_lock(&lock->lock); - lock->rw = 0; - wake_up_all(&lock->queue); - spin_unlock(&lock->lock); -} - -static bool __ttm_write_lock(struct ttm_lock *lock) -{ - bool locked = false; - - spin_lock(&lock->lock); - if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) { - lock->rw = -1; - lock->flags &= ~TTM_WRITE_LOCK_PENDING; - locked = true; - } else { - lock->flags |= TTM_WRITE_LOCK_PENDING; - } - spin_unlock(&lock->lock); - return locked; -} - -int ttm_write_lock(struct ttm_lock *lock, bool interruptible) -{ - int ret = 0; - - if (interruptible) { - ret = wait_event_interruptible(lock->queue, - __ttm_write_lock(lock)); - if (unlikely(ret != 0)) { - spin_lock(&lock->lock); - lock->flags &= ~TTM_WRITE_LOCK_PENDING; - wake_up_all(&lock->queue); - spin_unlock(&lock->lock); - } - } else - wait_event(lock->queue, __ttm_write_lock(lock)); - - return ret; -} - -void ttm_suspend_unlock(struct ttm_lock *lock) -{ - spin_lock(&lock->lock); - lock->flags &= ~TTM_SUSPEND_LOCK; - wake_up_all(&lock->queue); - spin_unlock(&lock->lock); -} - -static bool __ttm_suspend_lock(struct ttm_lock *lock) -{ - bool locked = false; - - spin_lock(&lock->lock); - if (lock->rw == 0) { - lock->flags &= ~TTM_SUSPEND_LOCK_PENDING; - lock->flags |= TTM_SUSPEND_LOCK; - locked = true; - } else { - lock->flags |= TTM_SUSPEND_LOCK_PENDING; - } - spin_unlock(&lock->lock); - return locked; -} - -void ttm_suspend_lock(struct ttm_lock *lock) -{ - wait_event(lock->queue, __ttm_suspend_lock(lock)); -} diff --git a/drivers/gpu/drm/vmwgfx/ttm_lock.h b/drivers/gpu/drm/vmwgfx/ttm_lock.h deleted file mode 100644 index af8b28ca546f..000000000000 --- a/drivers/gpu/drm/vmwgfx/ttm_lock.h +++ /dev/null @@ -1,218 +0,0 @@ -/************************************************************************** - * - * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ -/* - * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> - */ - -/** @file ttm_lock.h - * This file implements a simple replacement for the buffer manager use - * of the DRM heavyweight hardware lock. - * The lock is a read-write lock. Taking it in read mode and write mode - * is relatively fast, and intended for in-kernel use only. - * - * The vt mode is used only when there is a need to block all - * user-space processes from validating buffers. - * It's allowed to leave kernel space with the vt lock held. - * If a user-space process dies while having the vt-lock, - * it will be released during the file descriptor release. The vt lock - * excludes write lock and read lock. - * - * The suspend mode is used to lock out all TTM users when preparing for - * and executing suspend operations. - * - */ - -#ifndef _TTM_LOCK_H_ -#define _TTM_LOCK_H_ - -#include <linux/atomic.h> -#include <linux/wait.h> - -#include "ttm_object.h" - -/** - * struct ttm_lock - * - * @base: ttm base object used solely to release the lock if the client - * holding the lock dies. - * @queue: Queue for processes waiting for lock change-of-status. - * @lock: Spinlock protecting some lock members. - * @rw: Read-write lock counter. Protected by @lock. - * @flags: Lock state. Protected by @lock. - */ - -struct ttm_lock { - struct ttm_base_object base; - wait_queue_head_t queue; - spinlock_t lock; - int32_t rw; - uint32_t flags; -}; - - -/** - * ttm_lock_init - * - * @lock: Pointer to a struct ttm_lock - * Initializes the lock. - */ -extern void ttm_lock_init(struct ttm_lock *lock); - -/** - * ttm_read_unlock - * - * @lock: Pointer to a struct ttm_lock - * - * Releases a read lock. - */ -extern void ttm_read_unlock(struct ttm_lock *lock); - -/** - * ttm_read_lock - * - * @lock: Pointer to a struct ttm_lock - * @interruptible: Interruptible sleeping while waiting for a lock. - * - * Takes the lock in read mode. - * Returns: - * -ERESTARTSYS If interrupted by a signal and interruptible is true. - */ -extern int ttm_read_lock(struct ttm_lock *lock, bool interruptible); - -/** - * ttm_read_trylock - * - * @lock: Pointer to a struct ttm_lock - * @interruptible: Interruptible sleeping while waiting for a lock. - * - * Tries to take the lock in read mode. If the lock is already held - * in write mode, the function will return -EBUSY. If the lock is held - * in vt or suspend mode, the function will sleep until these modes - * are unlocked. - * - * Returns: - * -EBUSY The lock was already held in write mode. - * -ERESTARTSYS If interrupted by a signal and interruptible is true. - */ -extern int ttm_read_trylock(struct ttm_lock *lock, bool interruptible); - -/** - * ttm_write_unlock - * - * @lock: Pointer to a struct ttm_lock - * - * Releases a write lock. - */ -extern void ttm_write_unlock(struct ttm_lock *lock); - -/** - * ttm_write_lock - * - * @lock: Pointer to a struct ttm_lock - * @interruptible: Interruptible sleeping while waiting for a lock. - * - * Takes the lock in write mode. - * Returns: - * -ERESTARTSYS If interrupted by a signal and interruptible is true. - */ -extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible); - -/** - * ttm_lock_downgrade - * - * @lock: Pointer to a struct ttm_lock - * - * Downgrades a write lock to a read lock. - */ -extern void ttm_lock_downgrade(struct ttm_lock *lock); - -/** - * ttm_suspend_lock - * - * @lock: Pointer to a struct ttm_lock - * - * Takes the lock in suspend mode. Excludes read and write mode. - */ -extern void ttm_suspend_lock(struct ttm_lock *lock); - -/** - * ttm_suspend_unlock - * - * @lock: Pointer to a struct ttm_lock - * - * Releases a suspend lock - */ -extern void ttm_suspend_unlock(struct ttm_lock *lock); - -/** - * ttm_vt_lock - * - * @lock: Pointer to a struct ttm_lock - * @interruptible: Interruptible sleeping while waiting for a lock. - * @tfile: Pointer to a struct ttm_object_file to register the lock with. - * - * Takes the lock in vt mode. - * Returns: - * -ERESTARTSYS If interrupted by a signal and interruptible is true. - * -ENOMEM: Out of memory when locking. - */ -extern int ttm_vt_lock(struct ttm_lock *lock, bool interruptible, - struct ttm_object_file *tfile); - -/** - * ttm_vt_unlock - * - * @lock: Pointer to a struct ttm_lock - * - * Releases a vt lock. - * Returns: - * -EINVAL If the lock was not held. - */ -extern int ttm_vt_unlock(struct ttm_lock *lock); - -/** - * ttm_write_unlock - * - * @lock: Pointer to a struct ttm_lock - * - * Releases a write lock. - */ -extern void ttm_write_unlock(struct ttm_lock *lock); - -/** - * ttm_write_lock - * - * @lock: Pointer to a struct ttm_lock - * @interruptible: Interruptible sleeping while waiting for a lock. - * - * Takes the lock in write mode. - * Returns: - * -ERESTARTSYS If interrupted by a signal and interruptible is true. - */ -extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible); - -#endif diff --git a/drivers/gpu/drm/vmwgfx/ttm_memory.c b/drivers/gpu/drm/vmwgfx/ttm_memory.c index 104b95a8c7a2..aeb0a22a2c34 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_memory.c +++ b/drivers/gpu/drm/vmwgfx/ttm_memory.c @@ -280,7 +280,7 @@ static void ttm_shrink(struct ttm_mem_global *glob, bool from_wq, spin_unlock(&glob->lock); ret = ttm_global_swapout(ctx, GFP_KERNEL); spin_lock(&glob->lock); - if (unlikely(ret < 0)) + if (unlikely(ret <= 0)) break; } diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c index 112394dd0ab6..04789b2bb2a2 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.c +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c @@ -540,7 +540,7 @@ ttm_object_device_init(struct ttm_mem_global *mem_glob, if (ret != 0) goto out_no_object_hash; - idr_init(&tdev->idr); + idr_init_base(&tdev->idr, 1); tdev->ops = *ops; tdev->dmabuf_release = tdev->ops.release; tdev->ops.release = ttm_prime_dmabuf_release; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c b/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c index 81f525a82b77..05b324825900 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c @@ -788,7 +788,7 @@ static void vmw_collect_dirty_view_ids(struct vmw_ctx_binding_state *cbs, } /** - * vmw_binding_emit_set_sr - Issue delayed DX shader resource binding commands + * vmw_emit_set_sr - Issue delayed DX shader resource binding commands * * @cbs: Pointer to the context's struct vmw_ctx_binding_state * @shader_slot: The shader slot of the binding. @@ -832,7 +832,7 @@ static int vmw_emit_set_sr(struct vmw_ctx_binding_state *cbs, } /** - * vmw_binding_emit_set_rt - Issue delayed DX rendertarget binding commands + * vmw_emit_set_rt - Issue delayed DX rendertarget binding commands * * @cbs: Pointer to the context's struct vmw_ctx_binding_state */ @@ -1024,7 +1024,7 @@ static void vmw_collect_dirty_vbs(struct vmw_ctx_binding_state *cbs, } /** - * vmw_binding_emit_set_vb - Issue delayed vertex buffer binding commands + * vmw_emit_set_vb - Issue delayed vertex buffer binding commands * * @cbs: Pointer to the context's struct vmw_ctx_binding_state * @@ -1394,7 +1394,7 @@ struct list_head *vmw_binding_state_list(struct vmw_ctx_binding_state *cbs) } /** - * vmwgfx_binding_state_reset - clear a struct vmw_ctx_binding_state + * vmw_binding_state_reset - clear a struct vmw_ctx_binding_state * * @cbs: Pointer to the struct vmw_ctx_binding_state to be cleared * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c index 3a438ae4d3f4..cdbd5a870711 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c @@ -421,7 +421,7 @@ static int vmw_bo_cpu_blit_line(struct vmw_bo_blit_line_data *d, } /** - * ttm_bo_cpu_blit - in-kernel cpu blit. + * vmw_bo_cpu_blit - in-kernel cpu blit. * * @dst: Destination buffer object. * @dst_offset: Destination offset of blit start in bytes. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 50e529a01677..04dd49c4c257 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -96,10 +96,6 @@ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, int ret; uint32_t new_flags; - ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, NULL); @@ -116,9 +112,7 @@ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, vmw_bo_pin_reserved(buf, true); ttm_bo_unreserve(bo); - err: - ttm_write_unlock(&dev_priv->reservation_sem); return ret; } @@ -144,10 +138,6 @@ int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, int ret; uint32_t new_flags; - ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, NULL); @@ -172,7 +162,6 @@ out_unreserve: ttm_bo_unreserve(bo); err: - ttm_write_unlock(&dev_priv->reservation_sem); return ret; } @@ -228,10 +217,6 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, placement.num_busy_placement = 1; placement.busy_placement = &place; - ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, NULL); if (unlikely(ret != 0)) @@ -263,7 +248,6 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, ttm_bo_unreserve(bo); err_unlock: - ttm_write_unlock(&dev_priv->reservation_sem); return ret; } @@ -287,10 +271,6 @@ int vmw_bo_unpin(struct vmw_private *dev_priv, struct ttm_buffer_object *bo = &buf->base; int ret; - ret = ttm_read_lock(&dev_priv->reservation_sem, interruptible); - if (unlikely(ret != 0)) - return ret; - ret = ttm_bo_reserve(bo, interruptible, false, NULL); if (unlikely(ret != 0)) goto err; @@ -300,7 +280,6 @@ int vmw_bo_unpin(struct vmw_private *dev_priv, ttm_bo_unreserve(bo); err: - ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -460,6 +439,7 @@ void vmw_bo_bo_free(struct ttm_buffer_object *bo) WARN_ON(vmw_bo->dirty); WARN_ON(!RB_EMPTY_ROOT(&vmw_bo->res_tree)); vmw_bo_unmap(vmw_bo); + dma_resv_fini(&bo->base._resv); kfree(vmw_bo); } @@ -512,6 +492,11 @@ int vmw_bo_create_kernel(struct vmw_private *dev_priv, unsigned long size, if (unlikely(ret)) goto error_free; + + bo->base.size = size; + dma_resv_init(&bo->base._resv); + drm_vma_node_reset(&bo->base.vma_node); + ret = ttm_bo_init_reserved(&dev_priv->bdev, bo, size, ttm_bo_type_device, placement, 0, &ctx, NULL, NULL, NULL); @@ -570,6 +555,10 @@ int vmw_bo_init(struct vmw_private *dev_priv, if (unlikely(ret)) return ret; + vmw_bo->base.base.size = size; + dma_resv_init(&vmw_bo->base.base._resv); + drm_vma_node_reset(&vmw_bo->base.base.vma_node); + ret = ttm_bo_init_reserved(bdev, &vmw_bo->base, size, ttm_bo_type_device, placement, 0, &ctx, NULL, NULL, bo_free); @@ -611,7 +600,7 @@ static void vmw_user_bo_release(struct ttm_base_object **p_base) /** - * vmw_user_bo_ref_obj-release - TTM synccpu reference object release callback + * vmw_user_bo_ref_obj_release - TTM synccpu reference object release callback * for vmw user buffer objects * * @base: Pointer to the TTM base object @@ -896,10 +885,6 @@ int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, uint32_t handle; int ret; - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, req->size, false, &handle, &vbo, NULL); @@ -914,7 +899,6 @@ int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, vmw_bo_unreference(&vbo); out_no_bo: - ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -1109,10 +1093,6 @@ int vmw_dumb_create(struct drm_file *file_priv, args->pitch = args->width * ((args->bpp + 7) / 8); args->size = args->pitch * args->height; - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, args->size, false, &args->handle, &vbo, NULL); @@ -1121,7 +1101,6 @@ int vmw_dumb_create(struct drm_file *file_priv, vmw_bo_unreference(&vbo); out_no_bo: - ttm_read_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c index 20246a7c97c9..9c89189a226d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c @@ -31,15 +31,10 @@ #include "vmwgfx_drv.h" -struct vmw_temp_set_context { - SVGA3dCmdHeader header; - SVGA3dCmdDXTempSetContext body; -}; - bool vmw_supports_3d(struct vmw_private *dev_priv) { uint32_t fifo_min, hwversion; - const struct vmw_fifo_state *fifo = &dev_priv->fifo; + const struct vmw_fifo_state *fifo = dev_priv->fifo; if (!(dev_priv->capabilities & SVGA_CAP_3D)) return false; @@ -61,6 +56,8 @@ bool vmw_supports_3d(struct vmw_private *dev_priv) if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) return false; + BUG_ON(vmw_is_svga_v3(dev_priv)); + fifo_min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN); if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) return false; @@ -98,16 +95,24 @@ bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) return false; } -int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) +struct vmw_fifo_state *vmw_fifo_create(struct vmw_private *dev_priv) { + struct vmw_fifo_state *fifo; uint32_t max; uint32_t min; - fifo->dx = false; + if (!dev_priv->fifo_mem) + return NULL; + + fifo = kzalloc(sizeof(*fifo), GFP_KERNEL); + if (!fifo) + return ERR_PTR(-ENOMEM); fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE; fifo->static_buffer = vmalloc(fifo->static_buffer_size); - if (unlikely(fifo->static_buffer == NULL)) - return -ENOMEM; + if (unlikely(fifo->static_buffer == NULL)) { + kfree(fifo); + return ERR_PTR(-ENOMEM); + } fifo->dynamic_buffer = NULL; fifo->reserved_size = 0; @@ -115,20 +120,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) mutex_init(&fifo->fifo_mutex); init_rwsem(&fifo->rwsem); - - DRM_INFO("width %d\n", vmw_read(dev_priv, SVGA_REG_WIDTH)); - DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT)); - DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL)); - - dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); - dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); - dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); - - vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE | - SVGA_REG_ENABLE_HIDE); - - vmw_write(dev_priv, SVGA_REG_TRACES, 0); - min = 4; if (dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO) min = vmw_read(dev_priv, SVGA_REG_MEM_REGS); @@ -155,35 +146,23 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) (unsigned int) max, (unsigned int) min, (unsigned int) fifo->capabilities); - - atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_FENCE, dev_priv->last_read_seqno); - - return 0; + return fifo; } void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) { u32 *fifo_mem = dev_priv->fifo_mem; - - if (cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0) + if (fifo_mem && cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0) vmw_write(dev_priv, SVGA_REG_SYNC, reason); + } -void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) +void vmw_fifo_destroy(struct vmw_private *dev_priv) { - vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); - while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0) - ; - - dev_priv->last_read_seqno = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_FENCE); + struct vmw_fifo_state *fifo = dev_priv->fifo; - vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, - dev_priv->config_done_state); - vmw_write(dev_priv, SVGA_REG_ENABLE, - dev_priv->enable_state); - vmw_write(dev_priv, SVGA_REG_TRACES, - dev_priv->traces_state); + if (!fifo) + return; if (likely(fifo->static_buffer != NULL)) { vfree(fifo->static_buffer); @@ -194,6 +173,8 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) vfree(fifo->dynamic_buffer); fifo->dynamic_buffer = NULL; } + kfree(fifo); + dev_priv->fifo = NULL; } static bool vmw_fifo_is_full(struct vmw_private *dev_priv, uint32_t bytes) @@ -289,7 +270,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) { - struct vmw_fifo_state *fifo_state = &dev_priv->fifo; + struct vmw_fifo_state *fifo_state = dev_priv->fifo; u32 *fifo_mem = dev_priv->fifo_mem; uint32_t max; uint32_t min; @@ -438,16 +419,12 @@ static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state, static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) { - struct vmw_fifo_state *fifo_state = &dev_priv->fifo; + struct vmw_fifo_state *fifo_state = dev_priv->fifo; uint32_t next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD); uint32_t max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX); uint32_t min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN); bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; - if (fifo_state->dx) - bytes += sizeof(struct vmw_temp_set_context); - - fifo_state->dx = false; BUG_ON((bytes & 3) != 0); BUG_ON(bytes > fifo_state->reserved_size); @@ -495,7 +472,7 @@ void vmw_cmd_commit(struct vmw_private *dev_priv, uint32_t bytes) /** - * vmw_fifo_commit_flush - Commit fifo space and flush any buffered commands. + * vmw_cmd_commit_flush - Commit fifo space and flush any buffered commands. * * @dev_priv: Pointer to device private structure. * @bytes: Number of bytes to commit. @@ -509,7 +486,7 @@ void vmw_cmd_commit_flush(struct vmw_private *dev_priv, uint32_t bytes) } /** - * vmw_fifo_flush - Flush any buffered commands and make sure command processing + * vmw_cmd_flush - Flush any buffered commands and make sure command processing * starts. * * @dev_priv: Pointer to device private structure. @@ -527,7 +504,6 @@ int vmw_cmd_flush(struct vmw_private *dev_priv, bool interruptible) int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) { - struct vmw_fifo_state *fifo_state = &dev_priv->fifo; struct svga_fifo_cmd_fence *cmd_fence; u32 *fm; int ret = 0; @@ -546,7 +522,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) *seqno = atomic_add_return(1, &dev_priv->marker_seq); } while (*seqno == 0); - if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) { + if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) { /* * Don't request hardware to send a fence. The @@ -561,22 +537,22 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) cmd_fence = (struct svga_fifo_cmd_fence *) fm; cmd_fence->fence = *seqno; vmw_cmd_commit_flush(dev_priv, bytes); - vmw_update_seqno(dev_priv, fifo_state); + vmw_update_seqno(dev_priv); out_err: return ret; } /** - * vmw_fifo_emit_dummy_legacy_query - emits a dummy query to the fifo using + * vmw_cmd_emit_dummy_legacy_query - emits a dummy query to the fifo using * legacy query commands. * * @dev_priv: The device private structure. * @cid: The hardware context id used for the query. * - * See the vmw_fifo_emit_dummy_query documentation. + * See the vmw_cmd_emit_dummy_query documentation. */ -static int vmw_fifo_emit_dummy_legacy_query(struct vmw_private *dev_priv, +static int vmw_cmd_emit_dummy_legacy_query(struct vmw_private *dev_priv, uint32_t cid) { /* @@ -614,16 +590,16 @@ static int vmw_fifo_emit_dummy_legacy_query(struct vmw_private *dev_priv, } /** - * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using + * vmw_cmd_emit_dummy_gb_query - emits a dummy query to the fifo using * guest-backed resource query commands. * * @dev_priv: The device private structure. * @cid: The hardware context id used for the query. * - * See the vmw_fifo_emit_dummy_query documentation. + * See the vmw_cmd_emit_dummy_query documentation. */ -static int vmw_fifo_emit_dummy_gb_query(struct vmw_private *dev_priv, - uint32_t cid) +static int vmw_cmd_emit_dummy_gb_query(struct vmw_private *dev_priv, + uint32_t cid) { /* * A query wait without a preceding query end will @@ -656,7 +632,7 @@ static int vmw_fifo_emit_dummy_gb_query(struct vmw_private *dev_priv, /** - * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using + * vmw_cmd_emit_dummy_query - emits a dummy query to the fifo using * appropriate resource query commands. * * @dev_priv: The device private structure. @@ -677,7 +653,27 @@ int vmw_cmd_emit_dummy_query(struct vmw_private *dev_priv, uint32_t cid) { if (dev_priv->has_mob) - return vmw_fifo_emit_dummy_gb_query(dev_priv, cid); + return vmw_cmd_emit_dummy_gb_query(dev_priv, cid); - return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid); + return vmw_cmd_emit_dummy_legacy_query(dev_priv, cid); +} + + +/** + * vmw_cmd_supported - returns true if the given device supports + * command queues. + * + * @vmw: The device private structure. + * + * Returns true if we can issue commands. + */ +bool vmw_cmd_supported(struct vmw_private *vmw) +{ + if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS | + SVGA_CAP_CMD_BUFFERS_2)) != 0) + return true; + /* + * We have FIFO cmd's + */ + return vmw->fifo_mem != NULL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 2e23e537cdf5..05ca310ed61a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -295,7 +295,7 @@ void vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header) /** - * vmw_cmbuf_header_submit: Submit a command buffer to hardware. + * vmw_cmdbuf_header_submit: Submit a command buffer to hardware. * * @header: The header of the buffer to submit. */ @@ -620,7 +620,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) } /** - * vmw_cmdbuf_man idle - Check whether the command buffer manager is idle. + * vmw_cmdbuf_man_idle - Check whether the command buffer manager is idle. * * @man: The command buffer manager. * @check_preempted: Check also the preempted queue for pending command buffers. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 4a5a3e246216..3ed9914cb994 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -748,10 +748,6 @@ static int vmw_context_define(struct drm_device *dev, void *data, ((dev_priv->has_mob) ? vmw_cmdbuf_res_man_size() : 0) + + VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_user_context_size, &ttm_opt_ctx); @@ -759,7 +755,7 @@ static int vmw_context_define(struct drm_device *dev, void *data, if (ret != -ERESTARTSYS) DRM_ERROR("Out of graphics memory for context" " creation.\n"); - goto out_unlock; + goto out_ret; } ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -767,7 +763,7 @@ static int vmw_context_define(struct drm_device *dev, void *data, ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_user_context_size); ret = -ENOMEM; - goto out_unlock; + goto out_ret; } res = &ctx->res; @@ -780,7 +776,7 @@ static int vmw_context_define(struct drm_device *dev, void *data, ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx); if (unlikely(ret != 0)) - goto out_unlock; + goto out_ret; tmp = vmw_resource_reference(&ctx->res); ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT, @@ -794,8 +790,7 @@ static int vmw_context_define(struct drm_device *dev, void *data, arg->cid = ctx->base.handle; out_err: vmw_resource_unreference(&res); -out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); +out_ret: return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index 42321b9c8129..b40aa002bf2b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -482,11 +482,15 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) vmw_bo_unreference(&old_buf); res->id = vcotbl->type; + /* Release the pin acquired in vmw_bo_init */ + ttm_bo_unpin(bo); + return 0; out_map_new: ttm_bo_kunmap(&old_map); out_wait: + ttm_bo_unpin(bo); ttm_bo_unreserve(bo); vmw_bo_unreference(&buf); @@ -649,7 +653,7 @@ int vmw_cotable_notify(struct vmw_resource *res, int id) } /** - * vmw_cotable_add_view - add a view to the cotable's list of active views. + * vmw_cotable_add_resource - add a view to the cotable's list of active views. * * @res: pointer struct vmw_resource representing the cotable. * @head: pointer to the struct list_head member of the resource, dedicated diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4e41d8221f06..6f5ea00973e0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -31,12 +31,13 @@ #include <linux/pci.h> #include <linux/mem_encrypt.h> +#include <drm/drm_aperture.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_sysfs.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_placement.h> +#include <generated/utsrelease.h> #include "ttm_object.h" #include "vmwgfx_binding.h" @@ -50,7 +51,7 @@ #define VMWGFX_VALIDATION_MEM_GRAN (16*PAGE_SIZE) -/** +/* * Fully encoded drm commands. Might move to vmw_drm.h */ @@ -246,6 +247,7 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { static const struct pci_device_id vmw_pci_id_list[] = { { PCI_DEVICE(0x15ad, VMWGFX_PCI_ID_SVGA2) }, + { PCI_DEVICE(0x15ad, VMWGFX_PCI_ID_SVGA3) }, { } }; MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); @@ -393,6 +395,60 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) return ret; } +static int vmw_device_init(struct vmw_private *dev_priv) +{ + bool uses_fb_traces = false; + + DRM_INFO("width %d\n", vmw_read(dev_priv, SVGA_REG_WIDTH)); + DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT)); + DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL)); + + dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); + dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); + dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); + + vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE | + SVGA_REG_ENABLE_HIDE); + + uses_fb_traces = !vmw_cmd_supported(dev_priv) && + (dev_priv->capabilities & SVGA_CAP_TRACES) != 0; + + vmw_write(dev_priv, SVGA_REG_TRACES, uses_fb_traces); + dev_priv->fifo = vmw_fifo_create(dev_priv); + if (IS_ERR(dev_priv->fifo)) { + int err = PTR_ERR(dev_priv->fifo); + dev_priv->fifo = NULL; + return err; + } else if (!dev_priv->fifo) { + vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1); + } + + dev_priv->last_read_seqno = vmw_fence_read(dev_priv); + atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); + return 0; +} + +static void vmw_device_fini(struct vmw_private *vmw) +{ + /* + * Legacy sync + */ + vmw_write(vmw, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); + while (vmw_read(vmw, SVGA_REG_BUSY) != 0) + ; + + vmw->last_read_seqno = vmw_fence_read(vmw); + + vmw_write(vmw, SVGA_REG_CONFIG_DONE, + vmw->config_done_state); + vmw_write(vmw, SVGA_REG_ENABLE, + vmw->enable_state); + vmw_write(vmw, SVGA_REG_TRACES, + vmw->traces_state); + + vmw_fifo_destroy(vmw); +} + /** * vmw_request_device_late - Perform late device setup * @@ -433,9 +489,9 @@ static int vmw_request_device(struct vmw_private *dev_priv) { int ret; - ret = vmw_fifo_init(dev_priv, &dev_priv->fifo); + ret = vmw_device_init(dev_priv); if (unlikely(ret != 0)) { - DRM_ERROR("Unable to initialize FIFO.\n"); + DRM_ERROR("Unable to initialize the device.\n"); return ret; } vmw_fence_fifo_up(dev_priv->fman); @@ -469,7 +525,7 @@ out_no_query_bo: vmw_cmdbuf_man_destroy(dev_priv->cman); out_no_mob: vmw_fence_fifo_down(dev_priv->fman); - vmw_fifo_release(dev_priv, &dev_priv->fifo); + vmw_device_fini(dev_priv); return ret; } @@ -517,7 +573,7 @@ static void vmw_release_device_late(struct vmw_private *dev_priv) if (dev_priv->cman) vmw_cmdbuf_man_destroy(dev_priv->cman); - vmw_fifo_release(dev_priv, &dev_priv->fifo); + vmw_device_fini(dev_priv); } /* @@ -638,6 +694,8 @@ static void vmw_vram_manager_fini(struct vmw_private *dev_priv) static int vmw_setup_pci_resources(struct vmw_private *dev, unsigned long pci_id) { + resource_size_t rmmio_start; + resource_size_t rmmio_size; resource_size_t fifo_start; resource_size_t fifo_size; int ret; @@ -649,23 +707,45 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, if (ret) return ret; - dev->io_start = pci_resource_start(pdev, 0); - dev->vram_start = pci_resource_start(pdev, 1); - dev->vram_size = pci_resource_len(pdev, 1); - fifo_start = pci_resource_start(pdev, 2); - fifo_size = pci_resource_len(pdev, 2); - - DRM_INFO("FIFO at %pa size is %llu kiB\n", - &fifo_start, (uint64_t)fifo_size / 1024); - dev->fifo_mem = devm_memremap(dev->drm.dev, - fifo_start, - fifo_size, - MEMREMAP_WB); - - if (IS_ERR(dev->fifo_mem)) { - DRM_ERROR("Failed mapping FIFO memory.\n"); + dev->pci_id = pci_id; + if (pci_id == VMWGFX_PCI_ID_SVGA3) { + rmmio_start = pci_resource_start(pdev, 0); + rmmio_size = pci_resource_len(pdev, 0); + dev->vram_start = pci_resource_start(pdev, 2); + dev->vram_size = pci_resource_len(pdev, 2); + + DRM_INFO("Register MMIO at 0x%pa size is %llu kiB\n", + &rmmio_start, (uint64_t)rmmio_size / 1024); + dev->rmmio = devm_ioremap(dev->drm.dev, + rmmio_start, + rmmio_size); + if (!dev->rmmio) { + DRM_ERROR("Failed mapping registers mmio memory.\n"); + pci_release_regions(pdev); + return -ENOMEM; + } + } else if (pci_id == VMWGFX_PCI_ID_SVGA2) { + dev->io_start = pci_resource_start(pdev, 0); + dev->vram_start = pci_resource_start(pdev, 1); + dev->vram_size = pci_resource_len(pdev, 1); + fifo_start = pci_resource_start(pdev, 2); + fifo_size = pci_resource_len(pdev, 2); + + DRM_INFO("FIFO at %pa size is %llu kiB\n", + &fifo_start, (uint64_t)fifo_size / 1024); + dev->fifo_mem = devm_memremap(dev->drm.dev, + fifo_start, + fifo_size, + MEMREMAP_WB); + + if (IS_ERR(dev->fifo_mem)) { + DRM_ERROR("Failed mapping FIFO memory.\n"); + pci_release_regions(pdev); + return PTR_ERR(dev->fifo_mem); + } + } else { pci_release_regions(pdev); - return PTR_ERR(dev->fifo_mem); + return -EINVAL; } /* @@ -684,13 +764,16 @@ static int vmw_detect_version(struct vmw_private *dev) { uint32_t svga_id; - vmw_write(dev, SVGA_REG_ID, SVGA_ID_2); + vmw_write(dev, SVGA_REG_ID, vmw_is_svga_v3(dev) ? + SVGA_ID_3 : SVGA_ID_2); svga_id = vmw_read(dev, SVGA_REG_ID); - if (svga_id != SVGA_ID_2) { + if (svga_id != SVGA_ID_2 && svga_id != SVGA_ID_3) { DRM_ERROR("Unsupported SVGA ID 0x%x on chipset 0x%x\n", svga_id, dev->vmw_chipset); return -ENOSYS; } + BUG_ON(vmw_is_svga_v3(dev) && (svga_id != SVGA_ID_3)); + DRM_INFO("Running on SVGA version %d.\n", (svga_id & 0xff)); return 0; } @@ -699,33 +782,29 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) int ret; enum vmw_res_type i; bool refuse_dma = false; - char host_log[100] = {0}; struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); dev_priv->vmw_chipset = pci_id; - dev_priv->last_read_seqno = (uint32_t) -100; dev_priv->drm.dev_private = dev_priv; - ret = vmw_setup_pci_resources(dev_priv, pci_id); - if (ret) - return ret; - ret = vmw_detect_version(dev_priv); - if (ret) - goto out_no_pci_or_version; - mutex_init(&dev_priv->cmdbuf_mutex); - mutex_init(&dev_priv->release_mutex); mutex_init(&dev_priv->binding_mutex); - mutex_init(&dev_priv->global_kms_state_mutex); - ttm_lock_init(&dev_priv->reservation_sem); spin_lock_init(&dev_priv->resource_lock); spin_lock_init(&dev_priv->hw_lock); spin_lock_init(&dev_priv->waiter_lock); spin_lock_init(&dev_priv->cap_lock); spin_lock_init(&dev_priv->cursor_lock); + ret = vmw_setup_pci_resources(dev_priv, pci_id); + if (ret) + return ret; + ret = vmw_detect_version(dev_priv); + if (ret) + goto out_no_pci_or_version; + + for (i = vmw_res_context; i < vmw_res_max; ++i) { - idr_init(&dev_priv->res_idr[i]); + idr_init_base(&dev_priv->res_idr[i], 1); INIT_LIST_HEAD(&dev_priv->res_lru[i]); } @@ -826,6 +905,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) vmw_print_capabilities(dev_priv->capabilities); if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) vmw_print_capabilities2(dev_priv->capabilities2); + DRM_INFO("Supports command queues = %d\n", + vmw_cmd_supported((dev_priv))); ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) @@ -967,11 +1048,11 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) DRM_INFO("SM4_1 support available.\n"); if (dev_priv->sm_type == VMW_SM_4) DRM_INFO("SM4 support available.\n"); + DRM_INFO("Running without reservation semaphore\n"); - snprintf(host_log, sizeof(host_log), "vmwgfx: Module Version: %d.%d.%d", - VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, - VMWGFX_DRIVER_PATCHLEVEL); - vmw_host_log(host_log); + vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", + VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, + VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); if (dev_priv->enable_fb) { vmw_fifo_resource_inc(dev_priv); @@ -1180,7 +1261,7 @@ static void __vmw_svga_enable(struct vmw_private *dev_priv) struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); if (!ttm_resource_manager_used(man)) { - vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE); + vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE); ttm_resource_manager_set_used(man, true); } } @@ -1192,9 +1273,7 @@ static void __vmw_svga_enable(struct vmw_private *dev_priv) */ void vmw_svga_enable(struct vmw_private *dev_priv) { - (void) ttm_read_lock(&dev_priv->reservation_sem, false); __vmw_svga_enable(dev_priv); - ttm_read_unlock(&dev_priv->reservation_sem); } /** @@ -1239,7 +1318,6 @@ void vmw_svga_disable(struct vmw_private *dev_priv) * */ vmw_kms_lost_device(&dev_priv->drm); - ttm_write_lock(&dev_priv->reservation_sem, false); if (ttm_resource_manager_used(man)) { if (ttm_resource_manager_evict_all(&dev_priv->bdev, man)) DRM_ERROR("Failed evicting VRAM buffers.\n"); @@ -1248,7 +1326,6 @@ void vmw_svga_disable(struct vmw_private *dev_priv) SVGA_REG_ENABLE_HIDE | SVGA_REG_ENABLE_ENABLE); } - ttm_write_unlock(&dev_priv->reservation_sem); } static void vmw_remove(struct pci_dev *pdev) @@ -1288,14 +1365,12 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, * Once user-space processes have been frozen, we can release * the lock again. */ - ttm_suspend_lock(&dev_priv->reservation_sem); dev_priv->suspend_locked = true; break; case PM_POST_HIBERNATION: case PM_POST_RESTORE: if (READ_ONCE(dev_priv->suspend_locked)) { dev_priv->suspend_locked = false; - ttm_suspend_unlock(&dev_priv->reservation_sem); } break; default: @@ -1354,20 +1429,16 @@ static int vmw_pm_freeze(struct device *kdev) int ret; /* - * Unlock for vmw_kms_suspend. * No user-space processes should be running now. */ - ttm_suspend_unlock(&dev_priv->reservation_sem); ret = vmw_kms_suspend(&dev_priv->drm); if (ret) { - ttm_suspend_lock(&dev_priv->reservation_sem); DRM_ERROR("Failed to freeze modesetting.\n"); return ret; } if (dev_priv->enable_fb) vmw_fb_off(dev_priv); - ttm_suspend_lock(&dev_priv->reservation_sem); vmw_execbuf_release_pinned_bo(dev_priv); vmw_resource_evict_all(dev_priv); vmw_release_device_early(dev_priv); @@ -1380,7 +1451,6 @@ static int vmw_pm_freeze(struct device *kdev) vmw_fifo_resource_inc(dev_priv); WARN_ON(vmw_request_device_late(dev_priv)); dev_priv->suspend_locked = false; - ttm_suspend_unlock(&dev_priv->reservation_sem); if (dev_priv->suspend_state) vmw_kms_resume(dev); if (dev_priv->enable_fb) @@ -1402,8 +1472,7 @@ static int vmw_pm_restore(struct device *kdev) struct vmw_private *dev_priv = vmw_priv(dev); int ret; - vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); - (void) vmw_read(dev_priv, SVGA_REG_ID); + vmw_detect_version(dev_priv); if (dev_priv->enable_fb) vmw_fifo_resource_inc(dev_priv); @@ -1417,7 +1486,6 @@ static int vmw_pm_restore(struct device *kdev) vmw_fence_fifo_up(dev_priv->fman); dev_priv->suspend_locked = false; - ttm_suspend_unlock(&dev_priv->reservation_sem); if (dev_priv->suspend_state) vmw_kms_resume(&dev_priv->drm); @@ -1441,8 +1509,8 @@ static const struct file_operations vmwgfx_driver_fops = { .release = drm_release, .unlocked_ioctl = vmw_unlocked_ioctl, .mmap = vmw_mmap, - .poll = vmw_fops_poll, - .read = vmw_fops_read, + .poll = drm_poll, + .read = drm_read, #if defined(CONFIG_COMPAT) .compat_ioctl = vmw_compat_ioctl, #endif @@ -1491,7 +1559,7 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct vmw_private *vmw; int ret; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "svgadrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "svgadrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7e6518709e14..d1cef3b69e9d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,7 +40,6 @@ #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_execbuf_util.h> -#include "ttm_lock.h" #include "ttm_object.h" #include "vmwgfx_fence.h" @@ -67,6 +66,7 @@ #define VMWGFX_ENABLE_SCREEN_TARGET_OTABLE 1 #define VMWGFX_PCI_ID_SVGA2 0x0405 +#define VMWGFX_PCI_ID_SVGA3 0x0406 /* * Perhaps we should have sysfs entries for these. @@ -285,7 +285,6 @@ struct vmw_fifo_state { uint32_t capabilities; struct mutex fifo_mutex; struct rw_semaphore rwsem; - bool dx; }; /** @@ -486,14 +485,14 @@ struct vmw_private { struct drm_device drm; struct ttm_device bdev; - struct vmw_fifo_state fifo; - struct drm_vma_offset_manager vma_manager; + unsigned long pci_id; u32 vmw_chipset; resource_size_t io_start; resource_size_t vram_start; resource_size_t vram_size; resource_size_t prim_bb_mem; + void __iomem *rmmio; u32 *fifo_mem; resource_size_t fifo_mem_size; uint32_t fb_max_width; @@ -529,7 +528,6 @@ struct vmw_private { struct vmw_overlay *overlay_priv; struct drm_property *hotplug_mode_update_property; struct drm_property *implicit_placement_property; - struct mutex global_kms_state_mutex; spinlock_t cursor_lock; struct drm_atomic_state *suspend_state; @@ -592,15 +590,9 @@ struct vmw_private { bool refuse_hibernation; bool suspend_locked; - struct mutex release_mutex; atomic_t num_fifo_resources; /* - * Replace this with an rwsem as soon as we have down_xx_interruptible() - */ - struct ttm_lock reservation_sem; - - /* * Query processing. These members * are protected by the cmdbuf mutex. */ @@ -631,6 +623,7 @@ struct vmw_private { */ struct vmw_otable_batch otable_batch; + struct vmw_fifo_state *fifo; struct vmw_cmdbuf_man *cman; DECLARE_BITMAP(irqthread_pending, VMW_IRQTHREAD_MAX); @@ -654,6 +647,14 @@ static inline struct vmw_fpriv *vmw_fpriv(struct drm_file *file_priv) } /* + * SVGA v3 has mmio register access and lacks fifo cmds + */ +static inline bool vmw_is_svga_v3(const struct vmw_private *dev) +{ + return dev->pci_id == VMWGFX_PCI_ID_SVGA3; +} + +/* * The locking here is fine-grained, so that it is performed once * for every read- and write operation. This is of course costly, but we * don't perform much register access in the timing critical paths anyway. @@ -663,10 +664,14 @@ static inline struct vmw_fpriv *vmw_fpriv(struct drm_file *file_priv) static inline void vmw_write(struct vmw_private *dev_priv, unsigned int offset, uint32_t value) { - spin_lock(&dev_priv->hw_lock); - outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT); - outl(value, dev_priv->io_start + VMWGFX_VALUE_PORT); - spin_unlock(&dev_priv->hw_lock); + if (vmw_is_svga_v3(dev_priv)) { + iowrite32(value, dev_priv->rmmio + offset); + } else { + spin_lock(&dev_priv->hw_lock); + outl(offset, dev_priv->io_start + SVGA_INDEX_PORT); + outl(value, dev_priv->io_start + SVGA_VALUE_PORT); + spin_unlock(&dev_priv->hw_lock); + } } static inline uint32_t vmw_read(struct vmw_private *dev_priv, @@ -674,10 +679,14 @@ static inline uint32_t vmw_read(struct vmw_private *dev_priv, { u32 val; - spin_lock(&dev_priv->hw_lock); - outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT); - val = inl(dev_priv->io_start + VMWGFX_VALUE_PORT); - spin_unlock(&dev_priv->hw_lock); + if (vmw_is_svga_v3(dev_priv)) { + val = ioread32(dev_priv->rmmio + offset); + } else { + spin_lock(&dev_priv->hw_lock); + outl(offset, dev_priv->io_start + SVGA_INDEX_PORT); + val = inl(dev_priv->io_start + SVGA_VALUE_PORT); + spin_unlock(&dev_priv->hw_lock); + } return val; } @@ -940,19 +949,14 @@ extern int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern __poll_t vmw_fops_poll(struct file *filp, - struct poll_table_struct *wait); -extern ssize_t vmw_fops_read(struct file *filp, char __user *buffer, - size_t count, loff_t *offset); /** * Fifo utilities - vmwgfx_fifo.c */ -extern int vmw_fifo_init(struct vmw_private *dev_priv, - struct vmw_fifo_state *fifo); -extern void vmw_fifo_release(struct vmw_private *dev_priv, - struct vmw_fifo_state *fifo); +extern struct vmw_fifo_state *vmw_fifo_create(struct vmw_private *dev_priv); +extern void vmw_fifo_destroy(struct vmw_private *dev_priv); +extern bool vmw_cmd_supported(struct vmw_private *vmw); extern void * vmw_cmd_ctx_reserve(struct vmw_private *dev_priv, uint32_t bytes, int ctx_id); extern void vmw_cmd_commit(struct vmw_private *dev_priv, uint32_t bytes); @@ -978,6 +982,31 @@ extern int vmw_cmd_flush(struct vmw_private *dev_priv, #define VMW_CMD_RESERVE(__priv, __bytes) \ VMW_CMD_CTX_RESERVE(__priv, __bytes, SVGA3D_INVALID_ID) + +/** + * vmw_fifo_caps - Returns the capabilities of the FIFO command + * queue or 0 if fifo memory isn't present. + * @dev_priv: The device private context + */ +static inline uint32_t vmw_fifo_caps(const struct vmw_private *dev_priv) +{ + if (!dev_priv->fifo_mem || !dev_priv->fifo) + return 0; + return dev_priv->fifo->capabilities; +} + + +/** + * vmw_is_cursor_bypass3_enabled - Returns TRUE iff Cursor Bypass 3 + * is enabled in the FIFO. + * @dev_priv: The device private context + */ +static inline bool +vmw_is_cursor_bypass3_enabled(const struct vmw_private *dev_priv) +{ + return (vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_CURSOR_BYPASS_3) != 0; +} + /** * TTM glue - vmwgfx_ttm_glue.c */ @@ -1087,9 +1116,6 @@ bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd); * IRQs and wating - vmwgfx_irq.c */ -extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy, - uint32_t seqno, bool interruptible, - unsigned long timeout); extern int vmw_irq_install(struct drm_device *dev, int irq); extern void vmw_irq_uninstall(struct drm_device *dev); extern bool vmw_seqno_passed(struct vmw_private *dev_priv, @@ -1100,8 +1126,7 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv, uint32_t seqno, bool interruptible, unsigned long timeout); -extern void vmw_update_seqno(struct vmw_private *dev_priv, - struct vmw_fifo_state *fifo_state); +extern void vmw_update_seqno(struct vmw_private *dev_priv); extern void vmw_seqno_waiter_add(struct vmw_private *dev_priv); extern void vmw_seqno_waiter_remove(struct vmw_private *dev_priv); extern void vmw_goal_waiter_add(struct vmw_private *dev_priv); @@ -1116,10 +1141,29 @@ extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, * Kernel framebuffer - vmwgfx_fb.c */ +#ifdef CONFIG_DRM_FBDEV_EMULATION int vmw_fb_init(struct vmw_private *vmw_priv); int vmw_fb_close(struct vmw_private *dev_priv); int vmw_fb_off(struct vmw_private *vmw_priv); int vmw_fb_on(struct vmw_private *vmw_priv); +#else +static inline int vmw_fb_init(struct vmw_private *vmw_priv) +{ + return 0; +} +static inline int vmw_fb_close(struct vmw_private *dev_priv) +{ + return 0; +} +static inline int vmw_fb_off(struct vmw_private *vmw_priv) +{ + return 0; +} +static inline int vmw_fb_on(struct vmw_private *vmw_priv) +{ + return 0; +} +#endif /** * Kernel modesetting - vmwgfx_kms.c @@ -1454,7 +1498,7 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, /* Host messaging -vmwgfx_msg.c: */ int vmw_host_get_guestinfo(const char *guest_info_param, char *buffer, size_t *length); -int vmw_host_log(const char *log); +__printf(1, 2) int vmw_host_printf(const char *fmt, ...); int vmw_msg_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -1525,11 +1569,8 @@ static inline void vmw_bo_unreference(struct vmw_buffer_object **buf) struct vmw_buffer_object *tmp_buf = *buf; *buf = NULL; - if (tmp_buf != NULL) { - if (tmp_buf->base.pin_count > 0) - ttm_bo_unpin(&tmp_buf->base); + if (tmp_buf != NULL) ttm_bo_put(&tmp_buf->base); - } } static inline struct vmw_buffer_object * @@ -1564,6 +1605,7 @@ static inline void vmw_fifo_resource_dec(struct vmw_private *dev_priv) */ static inline u32 vmw_fifo_mem_read(struct vmw_private *vmw, uint32 fifo_reg) { + BUG_ON(vmw_is_svga_v3(vmw)); return READ_ONCE(*(vmw->fifo_mem + fifo_reg)); } @@ -1578,6 +1620,44 @@ static inline u32 vmw_fifo_mem_read(struct vmw_private *vmw, uint32 fifo_reg) static inline void vmw_fifo_mem_write(struct vmw_private *vmw, u32 fifo_reg, u32 value) { + BUG_ON(vmw_is_svga_v3(vmw)); WRITE_ONCE(*(vmw->fifo_mem + fifo_reg), value); } + +static inline u32 vmw_fence_read(struct vmw_private *dev_priv) +{ + u32 fence; + if (vmw_is_svga_v3(dev_priv)) + fence = vmw_read(dev_priv, SVGA_REG_FENCE); + else + fence = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_FENCE); + return fence; +} + +static inline void vmw_fence_write(struct vmw_private *dev_priv, + u32 fence) +{ + BUG_ON(vmw_is_svga_v3(dev_priv)); + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_FENCE, fence); +} + +static inline u32 vmw_irq_status_read(struct vmw_private *vmw) +{ + u32 status; + if (vmw_is_svga_v3(vmw)) + status = vmw_read(vmw, SVGA_REG_IRQ_STATUS); + else + status = inl(vmw->io_start + SVGA_IRQSTATUS_PORT); + return status; +} + +static inline void vmw_irq_status_write(struct vmw_private *vmw, + uint32 status) +{ + if (vmw_is_svga_v3(vmw)) + vmw_write(vmw, SVGA_REG_IRQ_STATUS, status); + else + outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT); +} + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 7a24196f92c3..32a84dff3fbf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -711,7 +711,7 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, } /** - * vmw_rebind_dx_query - Rebind DX query associated with the context + * vmw_rebind_all_dx_query - Rebind DX query associated with the context * * @ctx_res: context the query belongs to * @@ -1140,7 +1140,7 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, } /** - * vmw_translate_mob_pointer - Prepare to translate a user-space buffer handle + * vmw_translate_mob_ptr - Prepare to translate a user-space buffer handle * to a MOB id. * * @dev_priv: Pointer to a device private structure. @@ -1195,7 +1195,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, } /** - * vmw_translate_guest_pointer - Prepare to translate a user-space buffer handle + * vmw_translate_guest_ptr - Prepare to translate a user-space buffer handle * to a valid SVGAGuestPtr * * @dev_priv: Pointer to a device private structure. @@ -2308,7 +2308,7 @@ static int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv, } /** - * vmw_cmd_dx_ia_set_vertex_buffers - Validate + * vmw_cmd_dx_set_index_buffer - Validate * SVGA_3D_CMD_DX_IA_SET_INDEX_BUFFER command. * * @dev_priv: Pointer to a device private struct. @@ -2347,7 +2347,7 @@ static int vmw_cmd_dx_set_index_buffer(struct vmw_private *dev_priv, } /** - * vmw_cmd_dx_set_rendertarget - Validate SVGA_3D_CMD_DX_SET_RENDERTARGETS + * vmw_cmd_dx_set_rendertargets - Validate SVGA_3D_CMD_DX_SET_RENDERTARGETS * command * * @dev_priv: Pointer to a device private struct. @@ -2402,7 +2402,7 @@ static int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv, } /** - * vmw_cmd_dx_clear_rendertarget_view - Validate + * vmw_cmd_dx_clear_depthstencil_view - Validate * SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW command * * @dev_priv: Pointer to a device private struct. @@ -2513,7 +2513,7 @@ static int vmw_cmd_dx_set_so_targets(struct vmw_private *dev_priv, binding.bi.ctx = ctx_node->ctx; binding.bi.res = res; - binding.bi.bt = vmw_ctx_binding_so_target, + binding.bi.bt = vmw_ctx_binding_so_target; binding.offset = cmd->targets[i].offset; binding.size = cmd->targets[i].sizeInBytes; binding.slot = i; @@ -2763,12 +2763,24 @@ static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv, { VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXGenMips) = container_of(header, typeof(*cmd), header); - struct vmw_resource *ret; + struct vmw_resource *view; + struct vmw_res_cache_entry *rcache; - ret = vmw_view_id_val_add(sw_context, vmw_view_sr, - cmd->body.shaderResourceViewId); + view = vmw_view_id_val_add(sw_context, vmw_view_sr, + cmd->body.shaderResourceViewId); + if (IS_ERR(view)) + return PTR_ERR(view); - return PTR_ERR_OR_ZERO(ret); + /* + * Normally the shader-resource view is not gpu-dirtying, but for + * this particular command it is... + * So mark the last looked-up surface, which is the surface + * the view points to, gpu-dirty. + */ + rcache = &sw_context->res_cache[vmw_res_surface]; + vmw_validation_res_set_dirty(sw_context->ctx, rcache->private, + VMW_RES_DIRTY_SET); + return 0; } /** @@ -3829,7 +3841,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, fence_rep.handle = fence_handle; fence_rep.seqno = fence->base.seqno; - vmw_update_seqno(dev_priv, &dev_priv->fifo); + vmw_update_seqno(dev_priv); fence_rep.passed_seqno = dev_priv->last_read_seqno; } @@ -4431,10 +4443,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, goto out; } - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - ret = vmw_execbuf_process(file_priv, dev_priv, (void __user *)(unsigned long)arg->commands, NULL, arg->command_size, arg->throttle_us, @@ -4442,7 +4450,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, (void __user *)(unsigned long)arg->fence_rep, NULL, arg->flags); - ttm_read_unlock(&dev_priv->reservation_sem); if (unlikely(ret != 0)) goto out; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 33f07abfc3ae..d18c6a56e3dc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -195,7 +195,6 @@ static void vmw_fb_dirty_flush(struct work_struct *work) if (!cur_fb) goto out_unlock; - (void) ttm_read_lock(&vmw_priv->reservation_sem, false); (void) ttm_bo_reserve(&vbo->base, false, false, NULL); virtual = vmw_bo_map_and_cache(vbo); if (!virtual) @@ -254,7 +253,6 @@ static void vmw_fb_dirty_flush(struct work_struct *work) out_unreserve: ttm_bo_unreserve(&vbo->base); - ttm_read_unlock(&vmw_priv->reservation_sem); if (w && h) { WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, &clip, 1)); @@ -396,8 +394,6 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, struct vmw_buffer_object *vmw_bo; int ret; - (void) ttm_write_lock(&vmw_priv->reservation_sem, false); - vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL); if (!vmw_bo) { ret = -ENOMEM; @@ -412,12 +408,8 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, goto err_unlock; /* init frees the buffer on failure */ *out = vmw_bo; - ttm_write_unlock(&vmw_priv->reservation_sem); - - return 0; err_unlock: - ttm_write_unlock(&vmw_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 23523eb3cac2..9fe12329a4d5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -139,12 +139,10 @@ static bool vmw_fence_enable_signaling(struct dma_fence *f) struct vmw_fence_manager *fman = fman_from_fence(fence); struct vmw_private *dev_priv = fman->dev_priv; - u32 seqno = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_FENCE); + u32 seqno = vmw_fence_read(dev_priv); if (seqno - fence->base.seqno < VMW_FENCE_WRAP) return false; - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); - return true; } @@ -177,7 +175,6 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) if (likely(vmw_fence_obj_signaled(fence))) return timeout; - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); vmw_seqno_waiter_add(dev_priv); spin_lock(f->lock); @@ -464,7 +461,7 @@ static void __vmw_fences_update(struct vmw_fence_manager *fman) bool needs_rerun; uint32_t seqno, new_seqno; - seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE); + seqno = vmw_fence_read(fman->dev_priv); rerun: list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) { if (seqno - fence->base.seqno < VMW_FENCE_WRAP) { @@ -486,7 +483,7 @@ rerun: needs_rerun = vmw_fence_goal_new_locked(fman, seqno); if (unlikely(needs_rerun)) { - new_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE); + new_seqno = vmw_fence_read(fman->dev_priv); if (new_seqno != seqno) { seqno = new_seqno; goto rerun; @@ -529,13 +526,6 @@ int vmw_fence_obj_wait(struct vmw_fence_obj *fence, bool lazy, return ret; } -void vmw_fence_obj_flush(struct vmw_fence_obj *fence) -{ - struct vmw_private *dev_priv = fman_from_fence(fence)->dev_priv; - - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); -} - static void vmw_fence_destroy(struct vmw_fence_obj *fence) { dma_fence_free(&fence->base); @@ -992,7 +982,7 @@ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence, } /** - * vmw_event_fence_action_create - Post an event for sending when a fence + * vmw_event_fence_action_queue - Post an event for sending when a fence * object seqno has passed. * * @file_priv: The file connection on which the event should be posted. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h index 50e9fdd7acf1..079ab4f3ba51 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h @@ -94,8 +94,6 @@ extern int vmw_fence_obj_wait(struct vmw_fence_obj *fence, bool lazy, bool interruptible, unsigned long timeout); -extern void vmw_fence_obj_flush(struct vmw_fence_obj *fence); - extern int vmw_fence_create(struct vmw_fence_manager *fman, uint32_t seqno, struct vmw_fence_obj **p_fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 964ddf1ca57a..c482e5298e11 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -72,7 +72,7 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv, SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32; while (num_pages > 0) { - unsigned long nr = min(num_pages, (unsigned long)VMW_PPN_PER_REMAP); + unsigned long nr = min_t(unsigned long, num_pages, VMW_PPN_PER_REMAP); remap_cmd.offsetPages = remap_pos; remap_cmd.numPages = nr; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index b36032964b2f..4fdacf9924e6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -60,15 +60,13 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, param->value = dev_priv->capabilities2; break; case DRM_VMW_PARAM_FIFO_CAPS: - param->value = dev_priv->fifo.capabilities; + param->value = vmw_fifo_caps(dev_priv); break; case DRM_VMW_PARAM_MAX_FB_SIZE: param->value = dev_priv->prim_bb_mem; break; case DRM_VMW_PARAM_FIFO_HW_VERSION: { - const struct vmw_fifo_state *fifo = &dev_priv->fifo; - if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) { param->value = SVGA3D_HWVERSION_WS8_B1; break; @@ -76,7 +74,7 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, param->value = vmw_fifo_mem_read(dev_priv, - ((fifo->capabilities & + ((vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? SVGA_FIFO_3D_HWVERSION_REVISED : SVGA_FIFO_3D_HWVERSION)); @@ -302,10 +300,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, } vfb = vmw_framebuffer_to_vfb(fb); - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - goto out_no_ttm_lock; - ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid, user_surface_converter, &res); @@ -322,8 +316,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, vmw_surface_unreference(&surface); out_no_surface: - ttm_read_unlock(&dev_priv->reservation_sem); -out_no_ttm_lock: drm_framebuffer_put(fb); out_no_fb: drm_modeset_unlock_all(dev); @@ -391,15 +383,10 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, goto out_no_ttm_lock; } - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - goto out_no_ttm_lock; - ret = vmw_kms_readback(dev_priv, file_priv, vfb, user_fence_rep, clips, num_clips); - ttm_read_unlock(&dev_priv->reservation_sem); out_no_ttm_lock: drm_framebuffer_put(fb); out_no_fb: @@ -409,46 +396,3 @@ out_no_copy: out_clips: return ret; } - - -/** - * vmw_fops_poll - wrapper around the drm_poll function - * - * @filp: See the linux fops poll documentation. - * @wait: See the linux fops poll documentation. - * - * Wrapper around the drm_poll function that makes sure the device is - * processing the fifo if drm_poll decides to wait. - */ -__poll_t vmw_fops_poll(struct file *filp, struct poll_table_struct *wait) -{ - struct drm_file *file_priv = filp->private_data; - struct vmw_private *dev_priv = - vmw_priv(file_priv->minor->dev); - - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); - return drm_poll(filp, wait); -} - - -/** - * vmw_fops_read - wrapper around the drm_read function - * - * @filp: See the linux fops read documentation. - * @buffer: See the linux fops read documentation. - * @count: See the linux fops read documentation. - * @offset: See the linux fops read documentation. - * - * Wrapper around the drm_read function that makes sure the device is - * processing the fifo if drm_read decides to wait. - */ -ssize_t vmw_fops_read(struct file *filp, char __user *buffer, - size_t count, loff_t *offset) -{ - struct drm_file *file_priv = filp->private_data; - struct vmw_private *dev_priv = - vmw_priv(file_priv->minor->dev); - - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); - return drm_read(filp, buffer, count, offset); -} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 6c2a569f1fcb..b9a9b7ddadbd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -65,7 +65,7 @@ static irqreturn_t vmw_thread_fn(int irq, void *arg) } /** - * vmw_irq_handler irq handler + * vmw_irq_handler: irq handler * * @irq: irq number * @arg: Closure argument. Pointer to a struct drm_device cast to void * @@ -82,11 +82,11 @@ static irqreturn_t vmw_irq_handler(int irq, void *arg) uint32_t status, masked_status; irqreturn_t ret = IRQ_HANDLED; - status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); + status = vmw_irq_status_read(dev_priv); masked_status = status & READ_ONCE(dev_priv->irq_mask); if (likely(status)) - outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); + vmw_irq_status_write(dev_priv, status); if (!status) return IRQ_NONE; @@ -114,10 +114,9 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno) return (vmw_read(dev_priv, SVGA_REG_BUSY) == 0); } -void vmw_update_seqno(struct vmw_private *dev_priv, - struct vmw_fifo_state *fifo_state) +void vmw_update_seqno(struct vmw_private *dev_priv) { - uint32_t seqno = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_FENCE); + uint32_t seqno = vmw_fence_read(dev_priv); if (dev_priv->last_read_seqno != seqno) { dev_priv->last_read_seqno = seqno; @@ -128,18 +127,16 @@ void vmw_update_seqno(struct vmw_private *dev_priv, bool vmw_seqno_passed(struct vmw_private *dev_priv, uint32_t seqno) { - struct vmw_fifo_state *fifo_state; bool ret; if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return true; - fifo_state = &dev_priv->fifo; - vmw_update_seqno(dev_priv, fifo_state); + vmw_update_seqno(dev_priv); if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return true; - if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && + if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) && vmw_fifo_idle(dev_priv, seqno)) return true; @@ -161,7 +158,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, bool interruptible, unsigned long timeout) { - struct vmw_fifo_state *fifo_state = &dev_priv->fifo; + struct vmw_fifo_state *fifo_state = dev_priv->fifo; uint32_t count = 0; uint32_t signal_seq; @@ -221,7 +218,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, } finish_wait(&dev_priv->fence_queue, &__wait); if (ret == 0 && fifo_idle) - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_FENCE, signal_seq); + vmw_fence_write(dev_priv, signal_seq); wake_up_all(&dev_priv->fence_queue); out_err: @@ -236,7 +233,7 @@ void vmw_generic_waiter_add(struct vmw_private *dev_priv, { spin_lock_bh(&dev_priv->waiter_lock); if ((*waiter_count)++ == 0) { - outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); + vmw_irq_status_write(dev_priv, flag); dev_priv->irq_mask |= flag; vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); } @@ -278,59 +275,13 @@ void vmw_goal_waiter_remove(struct vmw_private *dev_priv) &dev_priv->goal_queue_waiters); } -int vmw_wait_seqno(struct vmw_private *dev_priv, - bool lazy, uint32_t seqno, - bool interruptible, unsigned long timeout) -{ - long ret; - struct vmw_fifo_state *fifo = &dev_priv->fifo; - - if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) - return 0; - - if (likely(vmw_seqno_passed(dev_priv, seqno))) - return 0; - - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); - - if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) - return vmw_fallback_wait(dev_priv, lazy, true, seqno, - interruptible, timeout); - - if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) - return vmw_fallback_wait(dev_priv, lazy, false, seqno, - interruptible, timeout); - - vmw_seqno_waiter_add(dev_priv); - - if (interruptible) - ret = wait_event_interruptible_timeout - (dev_priv->fence_queue, - vmw_seqno_passed(dev_priv, seqno), - timeout); - else - ret = wait_event_timeout - (dev_priv->fence_queue, - vmw_seqno_passed(dev_priv, seqno), - timeout); - - vmw_seqno_waiter_remove(dev_priv); - - if (unlikely(ret == 0)) - ret = -EBUSY; - else if (likely(ret > 0)) - ret = 0; - - return ret; -} - static void vmw_irq_preinstall(struct drm_device *dev) { struct vmw_private *dev_priv = vmw_priv(dev); uint32_t status; - status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); - outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); + status = vmw_irq_status_read(dev_priv); + vmw_irq_status_write(dev_priv, status); } void vmw_irq_uninstall(struct drm_device *dev) @@ -346,8 +297,8 @@ void vmw_irq_uninstall(struct drm_device *dev) vmw_write(dev_priv, SVGA_REG_IRQMASK, 0); - status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); - outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); + status = vmw_irq_status_read(dev_priv); + vmw_irq_status_write(dev_priv, status); dev->irq_enabled = false; free_irq(dev->irq, dev); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index abbca8b0b3c5..220f9fd0d420 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -38,8 +38,10 @@ void vmw_du_cleanup(struct vmw_display_unit *du) { + struct vmw_private *dev_priv = vmw_priv(du->primary.dev); drm_plane_cleanup(&du->primary); - drm_plane_cleanup(&du->cursor); + if (vmw_cmd_supported(dev_priv)) + drm_plane_cleanup(&du->cursor); drm_connector_unregister(&du->connector); drm_crtc_cleanup(&du->crtc); @@ -128,11 +130,17 @@ static void vmw_cursor_update_position(struct vmw_private *dev_priv, uint32_t count; spin_lock(&dev_priv->cursor_lock); - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, show ? 1 : 0); - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x); - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y); - count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT); - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_COUNT, ++count); + if (vmw_is_cursor_bypass3_enabled(dev_priv)) { + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, show ? 1 : 0); + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x); + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y); + count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT); + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_COUNT, ++count); + } else { + vmw_write(dev_priv, SVGA_REG_CURSOR_X, x); + vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y); + vmw_write(dev_priv, SVGA_REG_CURSOR_ON, show ? 1 : 0); + } spin_unlock(&dev_priv->cursor_lock); } @@ -289,7 +297,7 @@ void vmw_du_primary_plane_destroy(struct drm_plane *plane) /** - * vmw_du_vps_unpin_surf - unpins resource associated with a framebuffer surface + * vmw_du_plane_unpin_surf - unpins resource associated with a framebuffer surface * * @vps: plane state associated with the display surface * @unreference: true if we also want to unreference the display. @@ -474,7 +482,7 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, * vmw_du_cursor_plane_atomic_check - check if the new state is okay * * @plane: cursor plane - * @new_state: info on the new plane state + * @state: info on the new plane state * * This is a chance to fail if the new cursor state does not fit * our requirements. @@ -1008,12 +1016,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, drm_modeset_lock_all(&dev_priv->drm); - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) { - drm_modeset_unlock_all(&dev_priv->drm); - return ret; - } - if (!num_clips) { num_clips = 1; clips = &norect; @@ -1037,7 +1039,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, } vmw_cmd_flush(dev_priv, false); - ttm_read_unlock(&dev_priv->reservation_sem); drm_modeset_unlock_all(&dev_priv->drm); @@ -1052,7 +1053,8 @@ static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer, { struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - if (dev_priv->active_display_unit == vmw_du_legacy) + if (dev_priv->active_display_unit == vmw_du_legacy && + vmw_cmd_supported(dev_priv)) return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags, color, clips, num_clips); @@ -2640,7 +2642,7 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, } /** - * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement + * vmw_kms_create_implicit_placement_property - Set up the implicit placement * property. * * @dev_priv: Pointer to a device private struct. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 87e0b303d900..d85c7eab9469 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -404,19 +404,24 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) drm_plane_helper_add(primary, &vmw_ldu_primary_plane_helper_funcs); - /* Initialize cursor plane */ - ret = drm_universal_plane_init(dev, &ldu->base.cursor, - 0, &vmw_ldu_cursor_funcs, - vmw_cursor_plane_formats, - ARRAY_SIZE(vmw_cursor_plane_formats), - NULL, DRM_PLANE_TYPE_CURSOR, NULL); - if (ret) { - DRM_ERROR("Failed to initialize cursor plane"); - drm_plane_cleanup(&ldu->base.primary); - goto err_free; - } + /* + * We're going to be using traces and software cursors + */ + if (vmw_cmd_supported(dev_priv)) { + /* Initialize cursor plane */ + ret = drm_universal_plane_init(dev, &ldu->base.cursor, + 0, &vmw_ldu_cursor_funcs, + vmw_cursor_plane_formats, + ARRAY_SIZE(vmw_cursor_plane_formats), + NULL, DRM_PLANE_TYPE_CURSOR, NULL); + if (ret) { + DRM_ERROR("Failed to initialize cursor plane"); + drm_plane_cleanup(&ldu->base.primary); + goto err_free; + } - drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); + drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); + } ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -445,9 +450,10 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_encoder; } - ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, - &ldu->base.cursor, - &vmw_legacy_crtc_funcs, NULL); + ret = drm_crtc_init_with_planes( + dev, crtc, &ldu->base.primary, + vmw_cmd_supported(dev_priv) ? &ldu->base.cursor : NULL, + &vmw_legacy_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n"); goto err_free_unregister; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index a0b53141dded..5648664f71bc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -94,6 +94,16 @@ static void vmw_mob_pt_setup(struct vmw_mob *mob, struct vmw_piter data_iter, unsigned long num_data_pages); + +static inline void vmw_bo_unpin_unlocked(struct ttm_buffer_object *bo) +{ + int ret = ttm_bo_reserve(bo, false, true, NULL); + BUG_ON(ret != 0); + ttm_bo_unpin(bo); + ttm_bo_unreserve(bo); +} + + /* * vmw_setup_otable_base - Issue an object table base setup command to * the device @@ -277,7 +287,7 @@ out_no_setup: &batch->otables[i]); } - ttm_bo_unpin(batch->otable_bo); + vmw_bo_unpin_unlocked(batch->otable_bo); ttm_bo_put(batch->otable_bo); batch->otable_bo = NULL; return ret; @@ -341,6 +351,7 @@ static void vmw_otable_batch_takedown(struct vmw_private *dev_priv, BUG_ON(ret != 0); vmw_bo_fence_single(bo, NULL); + ttm_bo_unpin(bo); ttm_bo_unreserve(bo); ttm_bo_unpin(batch->otable_bo); @@ -530,7 +541,7 @@ static void vmw_mob_pt_setup(struct vmw_mob *mob, void vmw_mob_destroy(struct vmw_mob *mob) { if (mob->pt_bo) { - ttm_bo_unpin(mob->pt_bo); + vmw_bo_unpin_unlocked(mob->pt_bo); ttm_bo_put(mob->pt_bo); mob->pt_bo = NULL; } @@ -646,7 +657,7 @@ int vmw_mob_bind(struct vmw_private *dev_priv, out_no_cmd_space: vmw_fifo_resource_dec(dev_priv); if (pt_set_up) { - ttm_bo_unpin(mob->pt_bo); + vmw_bo_unpin_unlocked(mob->pt_bo); ttm_bo_put(mob->pt_bo); mob->pt_bo = NULL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 609269625468..3d08f5700bdb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -33,7 +33,8 @@ #include <asm/hypervisor.h> #include "vmwgfx_drv.h" -#include "vmwgfx_msg.h" +#include "vmwgfx_msg_x86.h" +#include "vmwgfx_msg_arm64.h" #define MESSAGE_STATUS_SUCCESS 0x0001 #define MESSAGE_STATUS_DORECV 0x0002 @@ -473,30 +474,40 @@ out_open: } - /** - * vmw_host_log: Sends a log message to the host + * vmw_host_printf: Sends a log message to the host * - * @log: NULL terminated string + * @fmt: Regular printf format string and arguments * * Returns: 0 on success */ -int vmw_host_log(const char *log) +__printf(1, 2) +int vmw_host_printf(const char *fmt, ...) { + va_list ap; struct rpc_channel channel; char *msg; + char *log; int ret = 0; - if (!vmw_msg_enabled) return -ENODEV; - if (!log) + if (!fmt) return ret; + va_start(ap, fmt); + log = kvasprintf(GFP_KERNEL, fmt, ap); + va_end(ap); + if (!log) { + DRM_ERROR("Cannot allocate memory for the log message.\n"); + return -ENOMEM; + } + msg = kasprintf(GFP_KERNEL, "log %s", log); if (!msg) { DRM_ERROR("Cannot allocate memory for host log message.\n"); + kfree(log); return -ENOMEM; } @@ -508,6 +519,7 @@ int vmw_host_log(const char *log) vmw_close_channel(&channel); kfree(msg); + kfree(log); return 0; @@ -515,6 +527,7 @@ out_msg: vmw_close_channel(&channel); out_open: kfree(msg); + kfree(log); DRM_ERROR("Failed to send host log message.\n"); return -EINVAL; @@ -537,7 +550,7 @@ int vmw_msg_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_vmw_msg_arg *arg = - (struct drm_vmw_msg_arg *) data; + (struct drm_vmw_msg_arg *)data; struct rpc_channel channel; char *msg; int length; @@ -577,7 +590,7 @@ int vmw_msg_ioctl(struct drm_device *dev, void *data, } if (reply && reply_len > 0) { if (copy_to_user((void __user *)((unsigned long)arg->receive), - reply, reply_len)) { + reply, reply_len)) { DRM_ERROR("Failed to copy message to userspace.\n"); kfree(reply); goto out_msg; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h deleted file mode 100644 index f685c7071dec..000000000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +++ /dev/null @@ -1,214 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ OR MIT */ -/************************************************************************** - * - * Copyright 2016 VMware, Inc., Palo Alto, CA., USA - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - ************************************************************************** - * - * Based on code from vmware.c and vmmouse.c. - * Author: - * Sinclair Yeh <syeh@vmware.com> - */ -#ifndef _VMWGFX_MSG_H -#define _VMWGFX_MSG_H - -#include <asm/vmware.h> - -/** - * Hypervisor-specific bi-directional communication channel. Should never - * execute on bare metal hardware. The caller must make sure to check for - * supported hypervisor before using these macros. - * - * The last two parameters are both input and output and must be initialized. - * - * @cmd: [IN] Message Cmd - * @in_ebx: [IN] Message Len, through EBX - * @in_si: [IN] Input argument through SI, set to 0 if not used - * @in_di: [IN] Input argument through DI, set ot 0 if not used - * @flags: [IN] hypercall flags + [channel id] - * @magic: [IN] hypervisor magic value - * @eax: [OUT] value of EAX register - * @ebx: [OUT] e.g. status from an HB message status command - * @ecx: [OUT] e.g. status from a non-HB message status command - * @edx: [OUT] e.g. channel id - * @si: [OUT] - * @di: [OUT] - */ -#define VMW_PORT(cmd, in_ebx, in_si, in_di, \ - flags, magic, \ - eax, ebx, ecx, edx, si, di) \ -({ \ - asm volatile (VMWARE_HYPERCALL : \ - "=a"(eax), \ - "=b"(ebx), \ - "=c"(ecx), \ - "=d"(edx), \ - "=S"(si), \ - "=D"(di) : \ - "a"(magic), \ - "b"(in_ebx), \ - "c"(cmd), \ - "d"(flags), \ - "S"(in_si), \ - "D"(in_di) : \ - "memory"); \ -}) - - -/** - * Hypervisor-specific bi-directional communication channel. Should never - * execute on bare metal hardware. The caller must make sure to check for - * supported hypervisor before using these macros. - * - * The last 3 parameters are both input and output and must be initialized. - * - * @cmd: [IN] Message Cmd - * @in_ecx: [IN] Message Len, through ECX - * @in_si: [IN] Input argument through SI, set to 0 if not used - * @in_di: [IN] Input argument through DI, set to 0 if not used - * @flags: [IN] hypercall flags + [channel id] - * @magic: [IN] hypervisor magic value - * @bp: [IN] - * @eax: [OUT] value of EAX register - * @ebx: [OUT] e.g. status from an HB message status command - * @ecx: [OUT] e.g. status from a non-HB message status command - * @edx: [OUT] e.g. channel id - * @si: [OUT] - * @di: [OUT] - */ -#ifdef __x86_64__ - -#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ - flags, magic, bp, \ - eax, ebx, ecx, edx, si, di) \ -({ \ - asm volatile ("push %%rbp;" \ - "mov %12, %%rbp;" \ - VMWARE_HYPERCALL_HB_OUT \ - "pop %%rbp;" : \ - "=a"(eax), \ - "=b"(ebx), \ - "=c"(ecx), \ - "=d"(edx), \ - "=S"(si), \ - "=D"(di) : \ - "a"(magic), \ - "b"(cmd), \ - "c"(in_ecx), \ - "d"(flags), \ - "S"(in_si), \ - "D"(in_di), \ - "r"(bp) : \ - "memory", "cc"); \ -}) - - -#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ - flags, magic, bp, \ - eax, ebx, ecx, edx, si, di) \ -({ \ - asm volatile ("push %%rbp;" \ - "mov %12, %%rbp;" \ - VMWARE_HYPERCALL_HB_IN \ - "pop %%rbp" : \ - "=a"(eax), \ - "=b"(ebx), \ - "=c"(ecx), \ - "=d"(edx), \ - "=S"(si), \ - "=D"(di) : \ - "a"(magic), \ - "b"(cmd), \ - "c"(in_ecx), \ - "d"(flags), \ - "S"(in_si), \ - "D"(in_di), \ - "r"(bp) : \ - "memory", "cc"); \ -}) - -#else - -/* - * In the 32-bit version of this macro, we store bp in a memory location - * because we've ran out of registers. - * Now we can't reference that memory location while we've modified - * %esp or %ebp, so we first push it on the stack, just before we push - * %ebp, and then when we need it we read it from the stack where we - * just pushed it. - */ -#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ - flags, magic, bp, \ - eax, ebx, ecx, edx, si, di) \ -({ \ - asm volatile ("push %12;" \ - "push %%ebp;" \ - "mov 0x04(%%esp), %%ebp;" \ - VMWARE_HYPERCALL_HB_OUT \ - "pop %%ebp;" \ - "add $0x04, %%esp;" : \ - "=a"(eax), \ - "=b"(ebx), \ - "=c"(ecx), \ - "=d"(edx), \ - "=S"(si), \ - "=D"(di) : \ - "a"(magic), \ - "b"(cmd), \ - "c"(in_ecx), \ - "d"(flags), \ - "S"(in_si), \ - "D"(in_di), \ - "m"(bp) : \ - "memory", "cc"); \ -}) - - -#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ - flags, magic, bp, \ - eax, ebx, ecx, edx, si, di) \ -({ \ - asm volatile ("push %12;" \ - "push %%ebp;" \ - "mov 0x04(%%esp), %%ebp;" \ - VMWARE_HYPERCALL_HB_IN \ - "pop %%ebp;" \ - "add $0x04, %%esp;" : \ - "=a"(eax), \ - "=b"(ebx), \ - "=c"(ecx), \ - "=d"(edx), \ - "=S"(si), \ - "=D"(di) : \ - "a"(magic), \ - "b"(cmd), \ - "c"(in_ecx), \ - "d"(flags), \ - "S"(in_si), \ - "D"(in_di), \ - "m"(bp) : \ - "memory", "cc"); \ -}) -#endif /* #if __x86_64__ */ - -#endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h new file mode 100755 index 000000000000..4f40167ad61f --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Copyright 2021 VMware, Inc., Palo Alto, CA., USA + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef _VMWGFX_MSG_ARM64_H +#define _VMWGFX_MSG_ARM64_H + +#if defined(__aarch64__) + +#define VMWARE_HYPERVISOR_PORT 0x5658 +#define VMWARE_HYPERVISOR_PORT_HB 0x5659 + +#define VMWARE_HYPERVISOR_HB BIT(0) +#define VMWARE_HYPERVISOR_OUT BIT(1) + +#define X86_IO_MAGIC 0x86 + +#define X86_IO_W7_SIZE_SHIFT 0 +#define X86_IO_W7_SIZE_MASK (0x3 << X86_IO_W7_SIZE_SHIFT) +#define X86_IO_W7_DIR (1 << 2) +#define X86_IO_W7_WITH (1 << 3) +#define X86_IO_W7_STR (1 << 4) +#define X86_IO_W7_DF (1 << 5) +#define X86_IO_W7_IMM_SHIFT 5 +#define X86_IO_W7_IMM_MASK (0xff << X86_IO_W7_IMM_SHIFT) + +static inline void vmw_port(unsigned long cmd, unsigned long in_ebx, + unsigned long in_si, unsigned long in_di, + unsigned long flags, unsigned long magic, + unsigned long *eax, unsigned long *ebx, + unsigned long *ecx, unsigned long *edx, + unsigned long *si, unsigned long *di) +{ + register u64 x0 asm("x0") = magic; + register u64 x1 asm("x1") = in_ebx; + register u64 x2 asm("x2") = cmd; + register u64 x3 asm("x3") = flags | VMWARE_HYPERVISOR_PORT; + register u64 x4 asm("x4") = in_si; + register u64 x5 asm("x5") = in_di; + + register u64 x7 asm("x7") = ((u64)X86_IO_MAGIC << 32) | + X86_IO_W7_WITH | + X86_IO_W7_DIR | + (2 << X86_IO_W7_SIZE_SHIFT); + + asm volatile("mrs xzr, mdccsr_el0 \n\t" + : "+r"(x0), "+r"(x1), "+r"(x2), + "+r"(x3), "+r"(x4), "+r"(x5) + : "r"(x7) + :); + *eax = x0; + *ebx = x1; + *ecx = x2; + *edx = x3; + *si = x4; + *di = x5; +} + +static inline void vmw_port_hb(unsigned long cmd, unsigned long in_ecx, + unsigned long in_si, unsigned long in_di, + unsigned long flags, unsigned long magic, + unsigned long bp, u32 w7dir, + unsigned long *eax, unsigned long *ebx, + unsigned long *ecx, unsigned long *edx, + unsigned long *si, unsigned long *di) +{ + register u64 x0 asm("x0") = magic; + register u64 x1 asm("x1") = cmd; + register u64 x2 asm("x2") = in_ecx; + register u64 x3 asm("x3") = flags | VMWARE_HYPERVISOR_PORT_HB; + register u64 x4 asm("x4") = in_si; + register u64 x5 asm("x5") = in_di; + register u64 x6 asm("x6") = bp; + register u64 x7 asm("x7") = ((u64)X86_IO_MAGIC << 32) | + X86_IO_W7_STR | + X86_IO_W7_WITH | + w7dir; + + asm volatile("mrs xzr, mdccsr_el0 \n\t" + : "+r"(x0), "+r"(x1), "+r"(x2), + "+r"(x3), "+r"(x4), "+r"(x5) + : "r"(x6), "r"(x7) + :); + *eax = x0; + *ebx = x1; + *ecx = x2; + *edx = x3; + *si = x4; + *di = x5; +} + +#define VMW_PORT(cmd, in_ebx, in_si, in_di, flags, magic, eax, ebx, ecx, edx, \ + si, di) \ + vmw_port(cmd, in_ebx, in_si, in_di, flags, magic, &eax, &ebx, &ecx, \ + &edx, &si, &di) + +#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, flags, magic, bp, eax, ebx, \ + ecx, edx, si, di) \ + vmw_port_hb(cmd, in_ecx, in_si, in_di, flags, magic, bp, \ + 0, &eax, &ebx, &ecx, &edx, &si, &di) + +#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, flags, magic, bp, eax, ebx, \ + ecx, edx, si, di) \ + vmw_port_hb(cmd, in_ecx, in_si, in_di, flags, magic, bp, \ + X86_IO_W7_DIR, &eax, &ebx, &ecx, &edx, &si, &di) + +#endif + +#endif /* _VMWGFX_MSG_ARM64_H */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg_x86.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg_x86.h new file mode 100644 index 000000000000..0b74ca2dfb7b --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg_x86.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR MIT */ +/************************************************************************** + * + * Copyright 2016-2021 VMware, Inc., Palo Alto, CA., USA + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + ************************************************************************** + * + * Based on code from vmware.c and vmmouse.c. + * Author: + * Sinclair Yeh <syeh@vmware.com> + */ +#ifndef _VMWGFX_MSG_X86_H +#define _VMWGFX_MSG_X86_H + + +#if defined(__i386__) || defined(__x86_64__) + +#include <asm/vmware.h> + +/** + * Hypervisor-specific bi-directional communication channel. Should never + * execute on bare metal hardware. The caller must make sure to check for + * supported hypervisor before using these macros. + * + * The last two parameters are both input and output and must be initialized. + * + * @cmd: [IN] Message Cmd + * @in_ebx: [IN] Message Len, through EBX + * @in_si: [IN] Input argument through SI, set to 0 if not used + * @in_di: [IN] Input argument through DI, set ot 0 if not used + * @flags: [IN] hypercall flags + [channel id] + * @magic: [IN] hypervisor magic value + * @eax: [OUT] value of EAX register + * @ebx: [OUT] e.g. status from an HB message status command + * @ecx: [OUT] e.g. status from a non-HB message status command + * @edx: [OUT] e.g. channel id + * @si: [OUT] + * @di: [OUT] + */ +#define VMW_PORT(cmd, in_ebx, in_si, in_di, \ + flags, magic, \ + eax, ebx, ecx, edx, si, di) \ +({ \ + asm volatile (VMWARE_HYPERCALL : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ + "=d"(edx), \ + "=S"(si), \ + "=D"(di) : \ + "a"(magic), \ + "b"(in_ebx), \ + "c"(cmd), \ + "d"(flags), \ + "S"(in_si), \ + "D"(in_di) : \ + "memory"); \ +}) + + +/** + * Hypervisor-specific bi-directional communication channel. Should never + * execute on bare metal hardware. The caller must make sure to check for + * supported hypervisor before using these macros. + * + * The last 3 parameters are both input and output and must be initialized. + * + * @cmd: [IN] Message Cmd + * @in_ecx: [IN] Message Len, through ECX + * @in_si: [IN] Input argument through SI, set to 0 if not used + * @in_di: [IN] Input argument through DI, set to 0 if not used + * @flags: [IN] hypercall flags + [channel id] + * @magic: [IN] hypervisor magic value + * @bp: [IN] + * @eax: [OUT] value of EAX register + * @ebx: [OUT] e.g. status from an HB message status command + * @ecx: [OUT] e.g. status from a non-HB message status command + * @edx: [OUT] e.g. channel id + * @si: [OUT] + * @di: [OUT] + */ +#ifdef __x86_64__ + +#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ + flags, magic, bp, \ + eax, ebx, ecx, edx, si, di) \ +({ \ + asm volatile ("push %%rbp;" \ + "mov %12, %%rbp;" \ + VMWARE_HYPERCALL_HB_OUT \ + "pop %%rbp;" : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ + "=d"(edx), \ + "=S"(si), \ + "=D"(di) : \ + "a"(magic), \ + "b"(cmd), \ + "c"(in_ecx), \ + "d"(flags), \ + "S"(in_si), \ + "D"(in_di), \ + "r"(bp) : \ + "memory", "cc"); \ +}) + + +#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ + flags, magic, bp, \ + eax, ebx, ecx, edx, si, di) \ +({ \ + asm volatile ("push %%rbp;" \ + "mov %12, %%rbp;" \ + VMWARE_HYPERCALL_HB_IN \ + "pop %%rbp" : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ + "=d"(edx), \ + "=S"(si), \ + "=D"(di) : \ + "a"(magic), \ + "b"(cmd), \ + "c"(in_ecx), \ + "d"(flags), \ + "S"(in_si), \ + "D"(in_di), \ + "r"(bp) : \ + "memory", "cc"); \ +}) + +#elif defined(__i386__) + +/* + * In the 32-bit version of this macro, we store bp in a memory location + * because we've ran out of registers. + * Now we can't reference that memory location while we've modified + * %esp or %ebp, so we first push it on the stack, just before we push + * %ebp, and then when we need it we read it from the stack where we + * just pushed it. + */ +#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ + flags, magic, bp, \ + eax, ebx, ecx, edx, si, di) \ +({ \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ + VMWARE_HYPERCALL_HB_OUT \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ + "=d"(edx), \ + "=S"(si), \ + "=D"(di) : \ + "a"(magic), \ + "b"(cmd), \ + "c"(in_ecx), \ + "d"(flags), \ + "S"(in_si), \ + "D"(in_di), \ + "m"(bp) : \ + "memory", "cc"); \ +}) + + +#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \ + flags, magic, bp, \ + eax, ebx, ecx, edx, si, di) \ +({ \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ + VMWARE_HYPERCALL_HB_IN \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ + "=d"(edx), \ + "=S"(si), \ + "=D"(di) : \ + "a"(magic), \ + "b"(cmd), \ + "c"(in_ecx), \ + "d"(flags), \ + "S"(in_si), \ + "D"(in_di), \ + "m"(bp) : \ + "memory", "cc"); \ +}) +#endif /* defined(__i386__) */ + +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#endif /* _VMWGFX_MSG_X86_H */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index ac4a9b722279..54c5d16eb3b7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -421,7 +421,7 @@ int vmw_overlay_pause_all(struct vmw_private *dev_priv) static bool vmw_overlay_available(const struct vmw_private *dev_priv) { return (dev_priv->overlay_priv != NULL && - ((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) == + ((vmw_fifo_caps(dev_priv) & VMW_OVERLAY_CAP_MASK) == VMW_OVERLAY_CAP_MASK)); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h index e99f6cdbb091..cf585dfe5669 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h @@ -34,10 +34,6 @@ #include <linux/types.h> -#define VMWGFX_INDEX_PORT 0x0 -#define VMWGFX_VALUE_PORT 0x1 -#define VMWGFX_IRQSTATUS_PORT 0x8 - struct svga_guest_mem_descriptor { u32 ppn; u32 num_pages; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 35f02958ee2c..62ea920addc3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -280,7 +280,7 @@ out_bad_resource: } /** - * vmw_user_resource_lookup_handle - lookup a struct resource from a + * vmw_user_resource_noref_lookup_handle - lookup a struct resource from a * TTM user-space handle and perform basic type checks * * @dev_priv: Pointer to a device private struct @@ -990,7 +990,6 @@ int vmw_resource_pin(struct vmw_resource *res, bool interruptible) struct vmw_private *dev_priv = res->dev_priv; int ret; - ttm_write_lock(&dev_priv->reservation_sem, interruptible); mutex_lock(&dev_priv->cmdbuf_mutex); ret = vmw_resource_reserve(res, interruptible, false); if (ret) @@ -1029,7 +1028,6 @@ out_no_validate: vmw_resource_unreserve(res, false, false, false, NULL, 0UL); out_no_reserve: mutex_unlock(&dev_priv->cmdbuf_mutex); - ttm_write_unlock(&dev_priv->reservation_sem); return ret; } @@ -1047,7 +1045,6 @@ void vmw_resource_unpin(struct vmw_resource *res) struct vmw_private *dev_priv = res->dev_priv; int ret; - (void) ttm_read_lock(&dev_priv->reservation_sem, false); mutex_lock(&dev_priv->cmdbuf_mutex); ret = vmw_resource_reserve(res, false, true); @@ -1065,7 +1062,6 @@ void vmw_resource_unpin(struct vmw_resource *res) vmw_resource_unreserve(res, false, false, false, NULL, 0UL); mutex_unlock(&dev_priv->cmdbuf_mutex); - ttm_read_unlock(&dev_priv->reservation_sem); } /** @@ -1079,7 +1075,7 @@ enum vmw_res_type vmw_res_type(const struct vmw_resource *res) } /** - * vmw_resource_update_dirty - Update a resource's dirty tracker with a + * vmw_resource_dirty_update - Update a resource's dirty tracker with a * sequential range of touched backing store memory. * @res: The resource. * @start: The first page touched. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 9bc9a0714664..145430d14219 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -1222,7 +1222,7 @@ static void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_kms_do_bo_dirty - Dirty part of a buffer-object backed framebuffer + * vmw_kms_sou_do_bo_dirty - Dirty part of a buffer-object backed framebuffer * * @dev_priv: Pointer to the device private structure. * @framebuffer: Pointer to the buffer-object backed framebuffer. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index a0db06564013..b391975871a5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -876,15 +876,9 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, goto out_bad_arg; } - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - goto out_bad_arg; - ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset, shader_type, num_input_sig, num_output_sig, tfile, shader_handle); - - ttm_read_unlock(&dev_priv->reservation_sem); out_bad_arg: vmw_bo_unreference(&buffer); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c index 73e9a487e659..33b69a70cfe3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c @@ -162,13 +162,8 @@ vmw_simple_resource_create_ioctl(struct drm_device *dev, void *data, account_size = ttm_round_pot(alloc_size) + VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (ret) - return ret; - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), account_size, &ctx); - ttm_read_unlock(&dev_priv->reservation_sem); if (ret) { if (ret != -ERESTARTSYS) DRM_ERROR("Out of graphics memory for %s" diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_so.c b/drivers/gpu/drm/vmwgfx/vmwgfx_so.c index 2877c7b43bd7..c3a8d6e8380e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_so.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_so.c @@ -33,7 +33,7 @@ * The currently only reason we need to keep track of views is that if we * destroy a hardware surface, all views pointing to it must also be destroyed, * otherwise the device will error. - * So in particuar if a surface is evicted, we must destroy all views pointing + * So in particular if a surface is evicted, we must destroy all views pointing * to it, and all context bindings of that view. Similarly we must restore * the view bindings, views and surfaces pointed to by the views when a * context is referenced in the command stream. @@ -90,7 +90,7 @@ static const struct vmw_res_func vmw_view_func = { }; /** - * struct vmw_view - view define command body stub + * struct vmw_view_define - view define command body stub * * @view_id: The device id of the view being defined * @sid: The surface id of the view being defined diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 7b11f0285786..9e236f9f8a8a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -742,7 +742,7 @@ out_unref: } /** - * vmw_stdu_surface_clip - Callback to encode a surface copy command cliprect + * vmw_kms_stdu_surface_clip - Callback to encode a surface copy command cliprect * * @dirty: The closure structure. * @@ -780,7 +780,7 @@ static void vmw_kms_stdu_surface_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_stdu_surface_fifo_commit - Callback to fill in and submit a surface + * vmw_kms_stdu_surface_fifo_commit - Callback to fill in and submit a surface * copy command. * * @dirty: The closure structure. @@ -1571,7 +1571,7 @@ static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, /** * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane * @plane: display plane - * @old_state: Only used to get crtc info + * @state: Only used to get crtc info * * Formally update stdu->display_srf to the new plane, and bind the new * plane STDU. This function is called during the commit phase when diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index c3e55c1376eb..8ead06574850 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -680,7 +680,7 @@ static void vmw_user_surface_free(struct vmw_resource *res) } /** - * vmw_user_surface_free - User visible surface TTM base object destructor + * vmw_user_surface_base_release - User visible surface TTM base object destructor * * @p_base: Pointer to a pointer to a TTM base object * embedded in a struct vmw_user_surface. @@ -702,7 +702,7 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base) } /** - * vmw_user_surface_destroy_ioctl - Ioctl function implementing + * vmw_surface_destroy_ioctl - Ioctl function implementing * the user surface destroy functionality. * * @dev: Pointer to a struct drm_device. @@ -719,7 +719,7 @@ int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, } /** - * vmw_user_surface_define_ioctl - Ioctl function implementing + * vmw_surface_define_ioctl - Ioctl function implementing * the user surface define functionality. * * @dev: Pointer to a struct drm_device. @@ -779,10 +779,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), size, &ctx); if (unlikely(ret != 0)) { @@ -913,7 +909,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, rep->sid = user_srf->prime.base.handle; vmw_resource_unreference(&res); - ttm_read_unlock(&dev_priv->reservation_sem); return 0; out_no_copy: kfree(srf->offsets); @@ -924,7 +919,6 @@ out_no_sizes: out_no_user_srf: ttm_mem_global_free(vmw_mem_glob(dev_priv), size); out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -1007,7 +1001,7 @@ out_no_lookup: } /** - * vmw_user_surface_define_ioctl - Ioctl function implementing + * vmw_surface_reference_ioctl - Ioctl function implementing * the user surface reference functionality. * * @dev: Pointer to a struct drm_device. @@ -1061,7 +1055,7 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, } /** - * vmw_surface_define_encode - Encode a surface_define command. + * vmw_gb_surface_create - Encode a surface_define command. * * @res: Pointer to a struct vmw_resource embedded in a struct * vmw_surface. @@ -1542,10 +1536,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev, if (drm_is_primary_client(file_priv)) user_srf->master = drm_master_get(file_priv->master); - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - res = &user_srf->srf.res; if (req->base.buffer_handle != SVGA3D_INVALID_ID) { @@ -1627,7 +1617,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev, vmw_resource_unreference(&res); out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -1804,6 +1793,19 @@ static void vmw_surface_tex_dirty_range_add(struct vmw_resource *res, svga3dsurface_get_loc(cache, &loc2, end - 1); svga3dsurface_inc_loc(cache, &loc2); + if (loc1.sheet != loc2.sheet) { + u32 sub_res; + + /* + * Multiple multisample sheets. To do this in an optimized + * fashion, compute the dirty region for each sheet and the + * resulting union. Since this is not a common case, just dirty + * the whole surface. + */ + for (sub_res = 0; sub_res < dirty->num_subres; ++sub_res) + vmw_subres_dirty_full(dirty, sub_res); + return; + } if (loc1.sub_resource + 1 == loc2.sub_resource) { /* Dirty range covers a single sub-resource */ vmw_subres_dirty_add(dirty, &loc1, &loc2); @@ -2112,10 +2114,6 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, if (req->sizes != NULL) return -EINVAL; - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), user_accounting_size, &ctx); if (ret != 0) { @@ -2179,13 +2177,11 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, */ ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); - ttm_read_unlock(&dev_priv->reservation_sem); return ret; out_no_user_srf: ttm_mem_global_free(vmw_mem_glob(dev_priv), user_accounting_size); out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c index eb63cbe64909..5ccc35b3194c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c @@ -28,15 +28,16 @@ static struct vmw_thp_manager *to_thp_manager(struct ttm_resource_manager *man) static const struct ttm_resource_manager_func vmw_thp_func; -static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node, +static int vmw_thp_insert_aligned(struct ttm_buffer_object *bo, + struct drm_mm *mm, struct drm_mm_node *node, unsigned long align_pages, const struct ttm_place *place, struct ttm_resource *mem, unsigned long lpfn, enum drm_mm_insert_mode mode) { - if (align_pages >= mem->page_alignment && - (!mem->page_alignment || align_pages % mem->page_alignment == 0)) { + if (align_pages >= bo->page_alignment && + (!bo->page_alignment || align_pages % bo->page_alignment == 0)) { return drm_mm_insert_node_in_range(mm, node, mem->num_pages, align_pages, 0, @@ -75,7 +76,7 @@ static int vmw_thp_get_node(struct ttm_resource_manager *man, if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)) { align_pages = (HPAGE_PUD_SIZE >> PAGE_SHIFT); if (mem->num_pages >= align_pages) { - ret = vmw_thp_insert_aligned(mm, node, align_pages, + ret = vmw_thp_insert_aligned(bo, mm, node, align_pages, place, mem, lpfn, mode); if (!ret) goto found_unlock; @@ -84,14 +85,14 @@ static int vmw_thp_get_node(struct ttm_resource_manager *man, align_pages = (HPAGE_PMD_SIZE >> PAGE_SHIFT); if (mem->num_pages >= align_pages) { - ret = vmw_thp_insert_aligned(mm, node, align_pages, place, mem, - lpfn, mode); + ret = vmw_thp_insert_aligned(bo, mm, node, align_pages, place, + mem, lpfn, mode); if (!ret) goto found_unlock; } ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages, - mem->page_alignment, 0, + bo->page_alignment, 0, place->fpfn, lpfn, mode); found_unlock: spin_unlock(&rman->lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 2dc031fe4a90..7bfe83c936ff 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -200,7 +200,8 @@ struct vmw_ttm_tt { const size_t vmw_tt_size = sizeof(struct vmw_ttm_tt); /** - * Helper functions to advance a struct vmw_piter iterator. + * __vmw_piter_non_sg_next: Helper functions to advance + * a struct vmw_piter iterator. * * @viter: Pointer to the iterator. * @@ -222,7 +223,8 @@ static bool __vmw_piter_sg_next(struct vmw_piter *viter) /** - * Helper functions to return a pointer to the current page. + * __vmw_piter_non_sg_page: Helper functions to return a pointer + * to the current page. * * @viter: Pointer to the iterator * @@ -236,7 +238,8 @@ static struct page *__vmw_piter_non_sg_page(struct vmw_piter *viter) } /** - * Helper functions to return the DMA address of the current page. + * __vmw_piter_phys_addr: Helper functions to return the DMA + * address of the current page. * * @viter: Pointer to the iterator * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c index e7570f422400..8338b1d20f2a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c @@ -82,7 +82,7 @@ struct vmw_validation_res_node { u32 reserved : 1; u32 dirty : 1; u32 dirty_set : 1; - unsigned long private[0]; + unsigned long private[]; }; /** @@ -809,7 +809,7 @@ void vmw_validation_revert(struct vmw_validation_context *ctx) } /** - * vmw_validation_cone - Commit validation actions after command submission + * vmw_validation_done - Commit validation actions after command submission * success. * @ctx: The validation context. * @fence: Fence with which to fence all buffer objects taking part in the diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 59d1fb017da0..82430ca9b913 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -713,7 +713,7 @@ static int zynqmp_dp_link_train_cr(struct zynqmp_dp *dp) if (ret) return ret; - drm_dp_link_train_clock_recovery_delay(dp->dpcd); + drm_dp_link_train_clock_recovery_delay(&dp->aux, dp->dpcd); ret = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (ret < 0) return ret; @@ -778,7 +778,7 @@ static int zynqmp_dp_link_train_ce(struct zynqmp_dp *dp) if (ret) return ret; - drm_dp_link_train_channel_eq_delay(dp->dpcd); + drm_dp_link_train_channel_eq_delay(&dp->aux, dp->dpcd); ret = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (ret < 0) return ret; @@ -1069,6 +1069,7 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp) dp->aux.name = "ZynqMP DP AUX"; dp->aux.dev = dp->dev; + dp->aux.drm_dev = dp->drm; dp->aux.transfer = zynqmp_dp_aux_transfer; return drm_dp_aux_register(&dp->aux); diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig index 90ebaedc11fd..aa8594190b50 100644 --- a/drivers/gpu/drm/zte/Kconfig +++ b/drivers/gpu/drm/zte/Kconfig @@ -3,7 +3,6 @@ config DRM_ZTE tristate "DRM Support for ZTE SoCs" depends on DRM && ARCH_ZX select DRM_KMS_CMA_HELPER - select DRM_KMS_FB_HELPER select DRM_KMS_HELPER select SND_SOC_HDMI_CODEC if SND_SOC select VIDEOMODE_HELPERS diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 68a766ff0e9d..46f69c532b6b 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -197,6 +197,17 @@ int host1x_device_init(struct host1x_device *device) mutex_lock(&device->clients_lock); list_for_each_entry(client, &device->clients, list) { + if (client->ops && client->ops->early_init) { + err = client->ops->early_init(client); + if (err < 0) { + dev_err(&device->dev, "failed to early initialize %s: %d\n", + dev_name(client->dev), err); + goto teardown_late; + } + } + } + + list_for_each_entry(client, &device->clients, list) { if (client->ops && client->ops->init) { err = client->ops->init(client); if (err < 0) { @@ -217,6 +228,14 @@ teardown: if (client->ops->exit) client->ops->exit(client); + /* reset client to end of list for late teardown */ + client = list_entry(&device->clients, struct host1x_client, list); + +teardown_late: + list_for_each_entry_continue_reverse(client, &device->clients, list) + if (client->ops->late_exit) + client->ops->late_exit(client); + mutex_unlock(&device->clients_lock); return err; } @@ -251,6 +270,18 @@ int host1x_device_exit(struct host1x_device *device) } } + list_for_each_entry_reverse(client, &device->clients, list) { + if (client->ops && client->ops->late_exit) { + err = client->ops->late_exit(client); + if (err < 0) { + dev_err(&device->dev, "failed to late cleanup %s: %d\n", + dev_name(client->dev), err); + mutex_unlock(&device->clients_lock); + return err; + } + } + } + mutex_unlock(&device->clients_lock); return 0; diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c index e8d3fda91d8a..6e6ca774f68d 100644 --- a/drivers/gpu/host1x/cdma.c +++ b/drivers/gpu/host1x/cdma.c @@ -273,15 +273,13 @@ static int host1x_cdma_wait_pushbuffer_space(struct host1x *host1x, static void cdma_start_timer_locked(struct host1x_cdma *cdma, struct host1x_job *job) { - struct host1x *host = cdma_to_host1x(cdma); - if (cdma->timeout.client) { /* timer already started */ return; } cdma->timeout.client = job->client; - cdma->timeout.syncpt = host1x_syncpt_get(host, job->syncpt_id); + cdma->timeout.syncpt = job->syncpt; cdma->timeout.syncpt_val = job->syncpt_end; cdma->timeout.start_ktime = ktime_get(); @@ -312,7 +310,6 @@ static void stop_cdma_timer_locked(struct host1x_cdma *cdma) static void update_cdma_locked(struct host1x_cdma *cdma) { bool signal = false; - struct host1x *host1x = cdma_to_host1x(cdma); struct host1x_job *job, *n; /* If CDMA is stopped, queue is cleared and we can return */ @@ -324,8 +321,7 @@ static void update_cdma_locked(struct host1x_cdma *cdma) * to consume as many sync queue entries as possible without blocking */ list_for_each_entry_safe(job, n, &cdma->sync_queue, list) { - struct host1x_syncpt *sp = - host1x_syncpt_get(host1x, job->syncpt_id); + struct host1x_syncpt *sp = job->syncpt; /* Check whether this syncpt has completed, and bail if not */ if (!host1x_syncpt_is_expired(sp, job->syncpt_end)) { @@ -499,8 +495,7 @@ int host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job) if (!cdma->timeout.initialized) { int err; - err = host1x_hw_cdma_timeout_init(host1x, cdma, - job->syncpt_id); + err = host1x_hw_cdma_timeout_init(host1x, cdma); if (err) { mutex_unlock(&cdma->lock); return err; diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index 1b4997bda1c7..8a14880c61bb 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c @@ -69,6 +69,7 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) static void show_syncpts(struct host1x *m, struct output *o) { + struct list_head *pos; unsigned int i; host1x_debug_output(o, "---- syncpts ----\n"); @@ -76,12 +77,19 @@ static void show_syncpts(struct host1x *m, struct output *o) for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { u32 max = host1x_syncpt_read_max(m->syncpt + i); u32 min = host1x_syncpt_load(m->syncpt + i); + unsigned int waiters = 0; - if (!min && !max) + spin_lock(&m->syncpt[i].intr.lock); + list_for_each(pos, &m->syncpt[i].intr.wait_head) + waiters++; + spin_unlock(&m->syncpt[i].intr.lock); + + if (!min && !max && !waiters) continue; - host1x_debug_output(o, "id %u (%s) min %d max %d\n", - i, m->syncpt[i].name, min, max); + host1x_debug_output(o, + "id %u (%s) min %d max %d (%d waiters)\n", + i, m->syncpt[i].name, min, max, waiters); } for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index d0ebb70e2fdd..fbb6447b8659 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -77,6 +77,7 @@ static const struct host1x_info host1x01_info = { .has_hypervisor = false, .num_sid_entries = 0, .sid_table = NULL, + .reserve_vblank_syncpts = true, }; static const struct host1x_info host1x02_info = { @@ -91,6 +92,7 @@ static const struct host1x_info host1x02_info = { .has_hypervisor = false, .num_sid_entries = 0, .sid_table = NULL, + .reserve_vblank_syncpts = true, }; static const struct host1x_info host1x04_info = { @@ -105,6 +107,7 @@ static const struct host1x_info host1x04_info = { .has_hypervisor = false, .num_sid_entries = 0, .sid_table = NULL, + .reserve_vblank_syncpts = false, }; static const struct host1x_info host1x05_info = { @@ -119,6 +122,7 @@ static const struct host1x_info host1x05_info = { .has_hypervisor = false, .num_sid_entries = 0, .sid_table = NULL, + .reserve_vblank_syncpts = false, }; static const struct host1x_sid_entry tegra186_sid_table[] = { @@ -142,6 +146,7 @@ static const struct host1x_info host1x06_info = { .has_hypervisor = true, .num_sid_entries = ARRAY_SIZE(tegra186_sid_table), .sid_table = tegra186_sid_table, + .reserve_vblank_syncpts = false, }; static const struct host1x_sid_entry tegra194_sid_table[] = { @@ -165,6 +170,7 @@ static const struct host1x_info host1x07_info = { .has_hypervisor = true, .num_sid_entries = ARRAY_SIZE(tegra194_sid_table), .sid_table = tegra194_sid_table, + .reserve_vblank_syncpts = false, }; static const struct of_device_id host1x_of_match[] = { diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index f781a9b0f39d..fa6d4bc46e98 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -37,7 +37,7 @@ struct host1x_cdma_ops { void (*start)(struct host1x_cdma *cdma); void (*stop)(struct host1x_cdma *cdma); void (*flush)(struct host1x_cdma *cdma); - int (*timeout_init)(struct host1x_cdma *cdma, unsigned int syncpt); + int (*timeout_init)(struct host1x_cdma *cdma); void (*timeout_destroy)(struct host1x_cdma *cdma); void (*freeze)(struct host1x_cdma *cdma); void (*resume)(struct host1x_cdma *cdma, u32 getptr); @@ -101,6 +101,12 @@ struct host1x_info { bool has_hypervisor; /* has hypervisor registers */ unsigned int num_sid_entries; const struct host1x_sid_entry *sid_table; + /* + * On T20-T148, the boot chain may setup DC to increment syncpoints + * 26/27 on VBLANK. As such we cannot use these syncpoints until + * the display driver disables VBLANK increments. + */ + bool reserve_vblank_syncpts; }; struct host1x { @@ -261,10 +267,9 @@ static inline void host1x_hw_cdma_flush(struct host1x *host, } static inline int host1x_hw_cdma_timeout_init(struct host1x *host, - struct host1x_cdma *cdma, - unsigned int syncpt) + struct host1x_cdma *cdma) { - return host->cdma_op->timeout_init(cdma, syncpt); + return host->cdma_op->timeout_init(cdma); } static inline void host1x_hw_cdma_timeout_destroy(struct host1x *host, diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 2f3bf94cf365..e49cd5b8f735 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c @@ -295,7 +295,7 @@ static void cdma_timeout_handler(struct work_struct *work) /* * Init timeout resources */ -static int cdma_timeout_init(struct host1x_cdma *cdma, unsigned int syncpt) +static int cdma_timeout_init(struct host1x_cdma *cdma) { INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler); cdma->timeout.initialized = true; diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 5eaa29d171c9..d4c28faf27d1 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c @@ -86,8 +86,7 @@ static void submit_gathers(struct host1x_job *job) static inline void synchronize_syncpt_base(struct host1x_job *job) { - struct host1x *host = dev_get_drvdata(job->channel->dev->parent); - struct host1x_syncpt *sp = host->syncpt + job->syncpt_id; + struct host1x_syncpt *sp = job->syncpt; unsigned int id; u32 value; @@ -118,7 +117,7 @@ static void host1x_channel_set_streamid(struct host1x_channel *channel) static int channel_submit(struct host1x_job *job) { struct host1x_channel *ch = job->channel; - struct host1x_syncpt *sp; + struct host1x_syncpt *sp = job->syncpt; u32 user_syncpt_incrs = job->syncpt_incrs; u32 prev_max = 0; u32 syncval; @@ -126,10 +125,9 @@ static int channel_submit(struct host1x_job *job) struct host1x_waitlist *completed_waiter = NULL; struct host1x *host = dev_get_drvdata(ch->dev->parent); - sp = host->syncpt + job->syncpt_id; trace_host1x_channel_submit(dev_name(ch->dev), job->num_gathers, job->num_relocs, - job->syncpt_id, job->syncpt_incrs); + job->syncpt->id, job->syncpt_incrs); /* before error checks, return current max */ prev_max = job->syncpt_end = host1x_syncpt_read_max(sp); @@ -163,7 +161,7 @@ static int channel_submit(struct host1x_job *job) host1x_cdma_push(&ch->cdma, host1x_opcode_setclass(HOST1X_CLASS_HOST1X, host1x_uclass_wait_syncpt_r(), 1), - host1x_class_host_wait_syncpt(job->syncpt_id, + host1x_class_host_wait_syncpt(job->syncpt->id, host1x_syncpt_read_max(sp))); } diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index f31bcfa1b837..ceb48229d14b 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c @@ -204,7 +204,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) unsigned int i; host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", - job, job->syncpt_id, job->syncpt_end, + job, job->syncpt->id, job->syncpt_end, job->first_get, job->timeout, job->num_slots, job->num_unpins); diff --git a/drivers/gpu/host1x/hw/hw_host1x07_vm.h b/drivers/gpu/host1x/hw/hw_host1x07_vm.h index 3058b3c9a91d..b766851d5b83 100644 --- a/drivers/gpu/host1x/hw/hw_host1x07_vm.h +++ b/drivers/gpu/host1x/hw/hw_host1x07_vm.h @@ -29,6 +29,6 @@ #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(x) (0x652c + 4 * (x)) #define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(x) (0x6590 + 4 * (x)) #define HOST1X_SYNC_SYNCPT(x) (0x8080 + 4 * (x)) -#define HOST1X_SYNC_SYNCPT_INT_THRESH(x) (0x8d00 + 4 * (x)) +#define HOST1X_SYNC_SYNCPT_INT_THRESH(x) (0x9980 + 4 * (x)) #define HOST1X_SYNC_SYNCPT_CH_APP(x) (0xa604 + 4 * (x)) #define HOST1X_SYNC_SYNCPT_CH_APP_CH(v) (((v) & 0x3f) << 8) diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c index 9245add23b5d..6d1f3c0fdbe7 100644 --- a/drivers/gpu/host1x/intr.c +++ b/drivers/gpu/host1x/intr.c @@ -235,25 +235,37 @@ int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt, host1x_hw_intr_enable_syncpt_intr(host, syncpt->id); } - spin_unlock(&syncpt->intr.lock); - if (ref) *ref = waiter; + + spin_unlock(&syncpt->intr.lock); + return 0; } -void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref) +void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref, + bool flush) { struct host1x_waitlist *waiter = ref; struct host1x_syncpt *syncpt; - while (atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED) == - WLS_REMOVED) - schedule(); + atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED); syncpt = host->syncpt + id; - (void)process_wait_list(host, syncpt, - host1x_syncpt_load(host->syncpt + id)); + + spin_lock(&syncpt->intr.lock); + if (atomic_cmpxchg(&waiter->state, WLS_CANCELLED, WLS_HANDLED) == + WLS_CANCELLED) { + list_del(&waiter->list); + kref_put(&waiter->refcount, waiter_release); + } + spin_unlock(&syncpt->intr.lock); + + if (flush) { + /* Wait until any concurrently executing handler has finished. */ + while (atomic_read(&waiter->state) != WLS_HANDLED) + schedule(); + } kref_put(&waiter->refcount, waiter_release); } diff --git a/drivers/gpu/host1x/intr.h b/drivers/gpu/host1x/intr.h index aac38194398f..6ea55e615e3a 100644 --- a/drivers/gpu/host1x/intr.h +++ b/drivers/gpu/host1x/intr.h @@ -74,8 +74,10 @@ int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt, * Unreference an action submitted to host1x_intr_add_action(). * You must call this if you passed non-NULL as ref. * @ref the ref returned from host1x_intr_add_action() + * @flush wait until any pending handlers have completed before returning. */ -void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref); +void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref, + bool flush); /* Initialize host1x sync point interrupt */ int host1x_intr_init(struct host1x *host, unsigned int irq_sync); diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index 82d0a60ba3f7..adbdc225de8d 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -79,6 +79,9 @@ static void job_free(struct kref *ref) { struct host1x_job *job = container_of(ref, struct host1x_job, ref); + if (job->syncpt) + host1x_syncpt_put(job->syncpt); + kfree(job); } @@ -674,7 +677,7 @@ EXPORT_SYMBOL(host1x_job_unpin); */ void host1x_job_dump(struct device *dev, struct host1x_job *job) { - dev_dbg(dev, " SYNCPT_ID %d\n", job->syncpt_id); + dev_dbg(dev, " SYNCPT_ID %d\n", job->syncpt->id); dev_dbg(dev, " SYNCPT_VAL %d\n", job->syncpt_end); dev_dbg(dev, " FIRST_GET 0x%x\n", job->first_get); dev_dbg(dev, " TIMEOUT %d\n", job->timeout); diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index fce7892d5137..e648ebbb2027 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -42,17 +42,32 @@ static void host1x_syncpt_base_free(struct host1x_syncpt_base *base) base->requested = false; } -static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, - struct host1x_client *client, - unsigned long flags) +/** + * host1x_syncpt_alloc() - allocate a syncpoint + * @host: host1x device data + * @flags: bitfield of HOST1X_SYNCPT_* flags + * @name: name for the syncpoint for use in debug prints + * + * Allocates a hardware syncpoint for the caller's use. The caller then has + * the sole authority to mutate the syncpoint's value until it is freed again. + * + * If no free syncpoints are available, or a NULL name was specified, returns + * NULL. + */ +struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, + unsigned long flags, + const char *name) { struct host1x_syncpt *sp = host->syncpt; + char *full_name; unsigned int i; - char *name; + + if (!name) + return NULL; mutex_lock(&host->syncpt_mutex); - for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++) + for (i = 0; i < host->info->nb_pts && kref_read(&sp->ref); i++, sp++) ; if (i >= host->info->nb_pts) @@ -64,19 +79,19 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, goto unlock; } - name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id, - client ? dev_name(client->dev) : NULL); - if (!name) + full_name = kasprintf(GFP_KERNEL, "%u-%s", sp->id, name); + if (!full_name) goto free_base; - sp->client = client; - sp->name = name; + sp->name = full_name; if (flags & HOST1X_SYNCPT_CLIENT_MANAGED) sp->client_managed = true; else sp->client_managed = false; + kref_init(&sp->ref); + mutex_unlock(&host->syncpt_mutex); return sp; @@ -87,6 +102,7 @@ unlock: mutex_unlock(&host->syncpt_mutex); return NULL; } +EXPORT_SYMBOL(host1x_syncpt_alloc); /** * host1x_syncpt_id() - retrieve syncpoint ID @@ -294,7 +310,7 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, } } - host1x_intr_put_ref(sp->host, sp->id, ref); + host1x_intr_put_ref(sp->host, sp->id, ref, true); done: return err; @@ -307,59 +323,12 @@ EXPORT_SYMBOL(host1x_syncpt_wait); bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh) { u32 current_val; - u32 future_val; smp_rmb(); current_val = (u32)atomic_read(&sp->min_val); - future_val = (u32)atomic_read(&sp->max_val); - - /* Note the use of unsigned arithmetic here (mod 1<<32). - * - * c = current_val = min_val = the current value of the syncpoint. - * t = thresh = the value we are checking - * f = future_val = max_val = the value c will reach when all - * outstanding increments have completed. - * - * Note that c always chases f until it reaches f. - * - * Dtf = (f - t) - * Dtc = (c - t) - * - * Consider all cases: - * - * A) .....c..t..f..... Dtf < Dtc need to wait - * B) .....c.....f..t.. Dtf > Dtc expired - * C) ..t..c.....f..... Dtf > Dtc expired (Dct very large) - * - * Any case where f==c: always expired (for any t). Dtf == Dcf - * Any case where t==c: always expired (for any f). Dtf >= Dtc (because Dtc==0) - * Any case where t==f!=c: always wait. Dtf < Dtc (because Dtf==0, - * Dtc!=0) - * - * Other cases: - * - * A) .....t..f..c..... Dtf < Dtc need to wait - * A) .....f..c..t..... Dtf < Dtc need to wait - * A) .....f..t..c..... Dtf > Dtc expired - * - * So: - * Dtf >= Dtc implies EXPIRED (return true) - * Dtf < Dtc implies WAIT (return false) - * - * Note: If t is expired then we *cannot* wait on it. We would wait - * forever (hang the system). - * - * Note: do NOT get clever and remove the -thresh from both sides. It - * is NOT the same. - * - * If future valueis zero, we have a client managed sync point. In that - * case we do a direct comparison. - */ - if (!host1x_syncpt_client_managed(sp)) - return future_val - thresh >= current_val - thresh; - else - return (s32)(current_val - thresh) >= 0; + + return ((current_val - thresh) & 0x80000000U) == 0U; } int host1x_syncpt_init(struct host1x *host) @@ -401,10 +370,15 @@ int host1x_syncpt_init(struct host1x *host) host1x_hw_syncpt_enable_protection(host); /* Allocate sync point to use for clearing waits for expired fences */ - host->nop_sp = host1x_syncpt_alloc(host, NULL, 0); + host->nop_sp = host1x_syncpt_alloc(host, 0, "reserved-nop"); if (!host->nop_sp) return -ENOMEM; + if (host->info->reserve_vblank_syncpts) { + kref_init(&host->syncpt[26].ref); + kref_init(&host->syncpt[27].ref); + } + return 0; } @@ -416,44 +390,50 @@ int host1x_syncpt_init(struct host1x *host) * host1x client drivers can use this function to allocate a syncpoint for * subsequent use. A syncpoint returned by this function will be reserved for * use by the client exclusively. When no longer using a syncpoint, a host1x - * client driver needs to release it using host1x_syncpt_free(). + * client driver needs to release it using host1x_syncpt_put(). */ struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client, unsigned long flags) { struct host1x *host = dev_get_drvdata(client->host->parent); - return host1x_syncpt_alloc(host, client, flags); + return host1x_syncpt_alloc(host, flags, dev_name(client->dev)); } EXPORT_SYMBOL(host1x_syncpt_request); -/** - * host1x_syncpt_free() - free a requested syncpoint - * @sp: host1x syncpoint - * - * Release a syncpoint previously allocated using host1x_syncpt_request(). A - * host1x client driver should call this when the syncpoint is no longer in - * use. Note that client drivers must ensure that the syncpoint doesn't remain - * under the control of hardware after calling this function, otherwise two - * clients may end up trying to access the same syncpoint concurrently. - */ -void host1x_syncpt_free(struct host1x_syncpt *sp) +static void syncpt_release(struct kref *ref) { - if (!sp) - return; + struct host1x_syncpt *sp = container_of(ref, struct host1x_syncpt, ref); + + atomic_set(&sp->max_val, host1x_syncpt_read(sp)); mutex_lock(&sp->host->syncpt_mutex); host1x_syncpt_base_free(sp->base); kfree(sp->name); sp->base = NULL; - sp->client = NULL; sp->name = NULL; sp->client_managed = false; mutex_unlock(&sp->host->syncpt_mutex); } -EXPORT_SYMBOL(host1x_syncpt_free); + +/** + * host1x_syncpt_put() - free a requested syncpoint + * @sp: host1x syncpoint + * + * Release a syncpoint previously allocated using host1x_syncpt_request(). A + * host1x client driver should call this when the syncpoint is no longer in + * use. + */ +void host1x_syncpt_put(struct host1x_syncpt *sp) +{ + if (!sp) + return; + + kref_put(&sp->ref, syncpt_release); +} +EXPORT_SYMBOL(host1x_syncpt_put); void host1x_syncpt_deinit(struct host1x *host) { @@ -520,16 +500,48 @@ unsigned int host1x_syncpt_nb_mlocks(struct host1x *host) } /** - * host1x_syncpt_get() - obtain a syncpoint by ID + * host1x_syncpt_get_by_id() - obtain a syncpoint by ID * @host: host1x controller * @id: syncpoint ID */ -struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id) +struct host1x_syncpt *host1x_syncpt_get_by_id(struct host1x *host, + unsigned int id) { if (id >= host->info->nb_pts) return NULL; - return host->syncpt + id; + if (kref_get_unless_zero(&host->syncpt[id].ref)) + return &host->syncpt[id]; + else + return NULL; +} +EXPORT_SYMBOL(host1x_syncpt_get_by_id); + +/** + * host1x_syncpt_get_by_id_noref() - obtain a syncpoint by ID but don't + * increase the refcount. + * @host: host1x controller + * @id: syncpoint ID + */ +struct host1x_syncpt *host1x_syncpt_get_by_id_noref(struct host1x *host, + unsigned int id) +{ + if (id >= host->info->nb_pts) + return NULL; + + return &host->syncpt[id]; +} +EXPORT_SYMBOL(host1x_syncpt_get_by_id_noref); + +/** + * host1x_syncpt_get() - increment syncpoint refcount + * @sp: syncpoint + */ +struct host1x_syncpt *host1x_syncpt_get(struct host1x_syncpt *sp) +{ + kref_get(&sp->ref); + + return sp; } EXPORT_SYMBOL(host1x_syncpt_get); @@ -552,3 +564,31 @@ u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base) return base->id; } EXPORT_SYMBOL(host1x_syncpt_base_id); + +static void do_nothing(struct kref *ref) +{ +} + +/** + * host1x_syncpt_release_vblank_reservation() - Make VBLANK syncpoint + * available for allocation + * + * @client: host1x bus client + * @syncpt_id: syncpoint ID to make available + * + * Makes VBLANK<i> syncpoint available for allocatation if it was + * reserved at initialization time. This should be called by the display + * driver after it has ensured that any VBLANK increment programming configured + * by the boot chain has been disabled. + */ +void host1x_syncpt_release_vblank_reservation(struct host1x_client *client, + u32 syncpt_id) +{ + struct host1x *host = dev_get_drvdata(client->host->parent); + + if (!host->info->reserve_vblank_syncpts) + return; + + kref_put(&host->syncpt[syncpt_id].ref, do_nothing); +} +EXPORT_SYMBOL(host1x_syncpt_release_vblank_reservation); diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h index 8e1d04dacaa0..a6766f8d55ee 100644 --- a/drivers/gpu/host1x/syncpt.h +++ b/drivers/gpu/host1x/syncpt.h @@ -11,6 +11,7 @@ #include <linux/atomic.h> #include <linux/host1x.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/sched.h> #include "intr.h" @@ -26,6 +27,8 @@ struct host1x_syncpt_base { }; struct host1x_syncpt { + struct kref ref; + unsigned int id; atomic_t min_val; atomic_t max_val; @@ -33,7 +36,6 @@ struct host1x_syncpt { const char *name; bool client_managed; struct host1x *host; - struct host1x_client *client; struct host1x_syncpt_base *base; /* interrupt data */ diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 34b4075a6a8e..ca96b235491a 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -167,6 +167,11 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, dc->di = ipu_di_get_num(di); + if (!IS_ALIGNED(width, 8)) { + dev_warn(priv->dev, + "%s: hactive does not align to 8 byte\n", __func__); + } + map = ipu_bus_format_to_map(bus_format); /* diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index e617f60afeea..666223c6bec4 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -506,6 +506,13 @@ int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode) { u32 diff; + if (!IS_ALIGNED(mode->hactive, 8) && + mode->hfront_porch < ALIGN(mode->hactive, 8) - mode->hactive) { + dev_err(di->ipu->dev, "hactive %d is not aligned to 8 and front porch is too small to compensate\n", + mode->hactive); + return -EINVAL; + } + if (mode->vfront_porch >= 2) return 0; diff --git a/drivers/gpu/ipu-v3/ipu-dp.c b/drivers/gpu/ipu-v3/ipu-dp.c index 8f67e985f26a..6a558205db96 100644 --- a/drivers/gpu/ipu-v3/ipu-dp.c +++ b/drivers/gpu/ipu-v3/ipu-dp.c @@ -10,6 +10,7 @@ #include <linux/io.h> #include <linux/err.h> +#include <drm/drm_color_mgmt.h> #include <video/imx-ipu-v3.h> #include "ipu-prv.h" @@ -125,6 +126,8 @@ int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos) EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos); static void ipu_dp_csc_init(struct ipu_flow *flow, + enum drm_color_encoding ycbcr_enc, + enum drm_color_range range, enum ipu_color_space in, enum ipu_color_space out, u32 place) @@ -148,7 +151,18 @@ static void ipu_dp_csc_init(struct ipu_flow *flow, flow->base + DP_CSC_0); writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30), flow->base + DP_CSC_1); + } else if (ycbcr_enc == DRM_COLOR_YCBCR_BT709) { + /* Rec.709 limited range */ + writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0); + writel(0x0e5 | (0x095 << 16), flow->base + DP_CSC_A_1); + writel(0x3e5 | (0x3bc << 16), flow->base + DP_CSC_A_2); + writel(0x095 | (0x10e << 16), flow->base + DP_CSC_A_3); + writel(0x000 | (0x3e10 << 16) | (1 << 30), + flow->base + DP_CSC_0); + writel(0x09a | (1 << 14) | (0x3dbe << 16) | (1 << 30), + flow->base + DP_CSC_1); } else { + /* BT.601 limited range */ writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0); writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1); writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2); @@ -165,6 +179,8 @@ static void ipu_dp_csc_init(struct ipu_flow *flow, } int ipu_dp_setup_channel(struct ipu_dp *dp, + enum drm_color_encoding ycbcr_enc, + enum drm_color_range range, enum ipu_color_space in, enum ipu_color_space out) { @@ -183,7 +199,8 @@ int ipu_dp_setup_channel(struct ipu_dp *dp, * foreground and background are of same colorspace, put * colorspace converter after combining unit. */ - ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs, + ipu_dp_csc_init(flow, ycbcr_enc, range, + flow->foreground.in_cs, flow->out_cs, DP_COM_CONF_CSC_DEF_BOTH); } else { if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN || @@ -192,10 +209,12 @@ int ipu_dp_setup_channel(struct ipu_dp *dp, * foreground identical to output, apply color * conversion on background */ - ipu_dp_csc_init(flow, flow->background.in_cs, + ipu_dp_csc_init(flow, ycbcr_enc, range, + flow->background.in_cs, flow->out_cs, DP_COM_CONF_CSC_DEF_BG); else - ipu_dp_csc_init(flow, flow->foreground.in_cs, + ipu_dp_csc_init(flow, ycbcr_enc, range, + flow->foreground.in_cs, flow->out_cs, DP_COM_CONF_CSC_DEF_FG); } |