diff options
Diffstat (limited to 'drivers/gpu/drm/amd')
303 files changed, 11833 insertions, 9894 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 5fcd510f1abb..5341b6b242c3 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -13,6 +13,8 @@ config DRM_AMDGPU select DRM_TTM_HELPER select POWER_SUPPLY select HWMON + select I2C + select I2C_ALGOBIT select BACKLIGHT_CLASS_DEVICE select INTERVAL_TREE select DRM_BUDDY diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 798d0e9a60b7..5df603192cdc 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -81,7 +81,8 @@ amdgpu-y += \ # add DF block amdgpu-y += \ df_v1_7.o \ - df_v3_6.o + df_v3_6.o \ + df_v4_3.o # add GMC block amdgpu-y += \ @@ -136,6 +137,7 @@ amdgpu-y += \ gfx_v10_0.o \ imu_v11_0.o \ gfx_v11_0.o \ + gfx_v11_0_3.o \ imu_v11_0_3.o # add async DMA block diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 6b74df446694..4e4efd10cb89 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -52,8 +52,7 @@ #include <linux/pci.h> #include <linux/aer.h> -#include <drm/ttm/ttm_bo_api.h> -#include <drm/ttm/ttm_bo_driver.h> +#include <drm/ttm/ttm_bo.h> #include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_execbuf_util.h> @@ -150,7 +149,7 @@ struct amdgpu_watchdog_timer * Modules parameters. */ extern int amdgpu_modeset; -extern int amdgpu_vram_limit; +extern unsigned int amdgpu_vram_limit; extern int amdgpu_vis_vram_limit; extern int amdgpu_gart_size; extern int amdgpu_gtt_size; @@ -195,6 +194,7 @@ extern int amdgpu_emu_mode; extern uint amdgpu_smu_memory_pool_size; extern int amdgpu_smu_pptable_id; extern uint amdgpu_dc_feature_mask; +extern uint amdgpu_freesync_vid_mode; extern uint amdgpu_dc_debug_mask; extern uint amdgpu_dc_visual_confirm; extern uint amdgpu_dm_abm_level; @@ -608,7 +608,7 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); /* VRAM scratch page for HDP bug, default vram page */ -struct amdgpu_vram_scratch { +struct amdgpu_mem_scratch { struct amdgpu_bo *robj; volatile uint32_t *ptr; u64 gpu_addr; @@ -755,6 +755,11 @@ struct amdgpu_mqd { #define AMDGPU_PRODUCT_NAME_LEN 64 struct amdgpu_reset_domain; +/* + * Non-zero (true) if the GPU has VRAM. Zero (false) otherwise. + */ +#define AMDGPU_HAS_VRAM(_adev) ((_adev)->gmc.real_vram_size) + struct amdgpu_device { struct device *dev; struct pci_dev *pdev; @@ -848,7 +853,7 @@ struct amdgpu_device { /* memory management */ struct amdgpu_mman mman; - struct amdgpu_vram_scratch vram_scratch; + struct amdgpu_mem_scratch mem_scratch; struct amdgpu_wb wb; atomic64_t num_bytes_moved; atomic64_t num_evictions; @@ -870,7 +875,7 @@ struct amdgpu_device { struct amdgpu_vkms_output *amdgpu_vkms_output; struct amdgpu_mode_info mode_info; /* For pre-DCE11. DCE11 and later are in "struct amdgpu_device->dm" */ - struct work_struct hotplug_work; + struct delayed_work hotplug_work; struct amdgpu_irq_src crtc_irq; struct amdgpu_irq_src vline0_irq; struct amdgpu_irq_src vupdate_irq; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 57b5e11446c6..f29c1d0ad4c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -24,6 +24,7 @@ #include <linux/pci.h> #include <linux/acpi.h> +#include <linux/backlight.h> #include <linux/slab.h> #include <linux/power_supply.h> #include <linux/pm_runtime.h> @@ -31,7 +32,6 @@ #include <acpi/video.h> #include <acpi/actbl.h> -#include <drm/drm_crtc_helper.h> #include "amdgpu.h" #include "amdgpu_pm.h" #include "amdgpu_display.h" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 0040deaf8a83..333780491867 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -97,7 +97,7 @@ struct amdgpu_amdkfd_fence { struct amdgpu_kfd_dev { struct kfd_dev *dev; - uint64_t vram_used; + int64_t vram_used; uint64_t vram_used_aligned; bool init_complete; struct work_struct reset_work; @@ -271,9 +271,9 @@ int amdgpu_amdkfd_get_pcie_bandwidth_mbytes(struct amdgpu_device *adev, bool is_ ((struct drm_file *)(drm_priv))->driver_priv)->vm) int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev, - struct file *filp, u32 pasid); + struct amdgpu_vm *avm, u32 pasid); int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev, - struct file *filp, + struct amdgpu_vm *avm, void **process_info, struct dma_fence **ef); void amdgpu_amdkfd_gpuvm_release_process_vm(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index b15091d8310d..d6320c836251 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -25,6 +25,7 @@ #include <linux/pagemap.h> #include <linux/sched/mm.h> #include <linux/sched/task.h> +#include <drm/ttm/ttm_tt.h> #include "amdgpu_object.h" #include "amdgpu_gem.h" @@ -1430,18 +1431,11 @@ static void amdgpu_amdkfd_gpuvm_unpin_bo(struct amdgpu_bo *bo) } int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev, - struct file *filp, u32 pasid) + struct amdgpu_vm *avm, u32 pasid) { - struct amdgpu_fpriv *drv_priv; - struct amdgpu_vm *avm; int ret; - ret = amdgpu_file_to_fpriv(filp, &drv_priv); - if (ret) - return ret; - avm = &drv_priv->vm; - /* Free the original amdgpu allocated pasid, * will be replaced with kfd allocated pasid. */ @@ -1458,19 +1452,12 @@ int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev, } int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev, - struct file *filp, + struct amdgpu_vm *avm, void **process_info, struct dma_fence **ef) { - struct amdgpu_fpriv *drv_priv; - struct amdgpu_vm *avm; int ret; - ret = amdgpu_file_to_fpriv(filp, &drv_priv); - if (ret) - return ret; - avm = &drv_priv->vm; - /* Already a compute VM? */ if (avm->process_info) return -EINVAL; @@ -1612,6 +1599,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( struct amdgpu_bo *bo; struct drm_gem_object *gobj = NULL; u32 domain, alloc_domain; + uint64_t aligned_size; u64 alloc_flags; int ret; @@ -1667,22 +1655,23 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( * the memory. */ if ((*mem)->aql_queue) - size = size >> 1; + size >>= 1; + aligned_size = PAGE_ALIGN(size); (*mem)->alloc_flags = flags; amdgpu_sync_create(&(*mem)->sync); - ret = amdgpu_amdkfd_reserve_mem_limit(adev, size, flags); + ret = amdgpu_amdkfd_reserve_mem_limit(adev, aligned_size, flags); if (ret) { pr_debug("Insufficient memory\n"); goto err_reserve_limit; } pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n", - va, size, domain_string(alloc_domain)); + va, (*mem)->aql_queue ? size << 1 : size, domain_string(alloc_domain)); - ret = amdgpu_gem_object_create(adev, size, 1, alloc_domain, alloc_flags, + ret = amdgpu_gem_object_create(adev, aligned_size, 1, alloc_domain, alloc_flags, bo_type, NULL, &gobj); if (ret) { pr_debug("Failed to create BO on domain %s. ret %d\n", @@ -1739,7 +1728,7 @@ err_node_allow: /* Don't unreserve system mem limit twice */ goto err_reserve_limit; err_bo_create: - amdgpu_amdkfd_unreserve_mem_limit(adev, size, flags); + amdgpu_amdkfd_unreserve_mem_limit(adev, aligned_size, flags); err_reserve_limit: mutex_destroy(&(*mem)->lock); if (gobj) @@ -2099,7 +2088,7 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_device *adev, struct amdgpu_b } amdgpu_amdkfd_remove_eviction_fence( - bo, bo->kfd_bo->process_info->eviction_fence); + bo, bo->vm_bo->vm->process_info->eviction_fence); amdgpu_bo_unreserve(bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index e4d78491bcc7..ededdc01ca28 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -28,6 +28,8 @@ struct hmm_range; +struct drm_file; + struct amdgpu_device; struct amdgpu_bo; struct amdgpu_bo_va; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index f1a050379190..456e385333b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -411,17 +411,10 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, return -EINVAL; } - err = request_firmware(&adev->pm.fw, fw_name, adev->dev); - if (err) { - DRM_ERROR("Failed to request firmware\n"); - return err; - } - - err = amdgpu_ucode_validate(adev->pm.fw); + err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name); if (err) { DRM_ERROR("Failed to load firmware \"%s\"", fw_name); - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; + amdgpu_ucode_release(&adev->pm.fw); return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 2ebbc6382a06..6be30dcb029d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -25,7 +25,9 @@ */ #include <drm/display/drm_dp_helper.h> +#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_probe_helper.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" @@ -996,13 +998,33 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) } } + if (amdgpu_connector->detected_hpd_without_ddc) { + force = true; + amdgpu_connector->detected_hpd_without_ddc = false; + } + if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { ret = connector->status; goto exit; } - if (amdgpu_connector->ddc_bus) + if (amdgpu_connector->ddc_bus) { dret = amdgpu_display_ddc_probe(amdgpu_connector, false); + + /* Sometimes the pins required for the DDC probe on DVI + * connectors don't make contact at the same time that the ones + * for HPD do. If the DDC probe fails even though we had an HPD + * signal, try again later + */ + if (!dret && !force && + amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { + DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n"); + amdgpu_connector->detected_hpd_without_ddc = true; + schedule_delayed_work(&adev->hotplug_work, + msecs_to_jiffies(1000)); + goto exit; + } + } if (dret) { amdgpu_connector->detected_by_load = false; amdgpu_connector_free_edid(connector); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 8516c814bc9b..8b7a09b392ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -32,6 +32,8 @@ #include <drm/amdgpu_drm.h> #include <drm/drm_syncobj.h> +#include <drm/ttm/ttm_tt.h> + #include "amdgpu_cs.h" #include "amdgpu.h" #include "amdgpu_trace.h" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h index 113f39510a72..fb3e3d56d427 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h @@ -23,6 +23,8 @@ #ifndef __AMDGPU_CS_H__ #define __AMDGPU_CS_H__ +#include <linux/ww_mutex.h> + #include "amdgpu_job.h" #include "amdgpu_bo_list.h" #include "amdgpu_ring.h" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 0f16d3c09309..f60753f97ac5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1717,7 +1717,7 @@ no_preempt: static int amdgpu_debugfs_ib_preempt(void *data, u64 val) { - int r, resched, length; + int r, length; struct amdgpu_ring *ring; struct dma_fence **fences = NULL; struct amdgpu_device *adev = (struct amdgpu_device *)data; @@ -1747,8 +1747,6 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) /* stop the scheduler */ kthread_park(ring->sched.thread); - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); - /* preempt the IB */ r = amdgpu_ring_preempt_ib(ring); if (r) { @@ -1785,8 +1783,6 @@ failure: up_read(&adev->reset_domain->sem); - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); - pro_end: kfree(fences); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index afe6af9c0138..1257745fb202 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -36,7 +36,9 @@ #include <generated/utsrelease.h> #include <linux/pci-p2pdma.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_probe_helper.h> #include <drm/amdgpu_drm.h> @@ -90,6 +92,8 @@ MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); #define AMDGPU_MAX_RETRY_LIMIT 2 #define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL) +static const struct drm_driver amdgpu_kms_driver; + const char *amdgpu_asic_name[] = { "TAHITI", "PITCAIRN", @@ -924,32 +928,33 @@ static int amdgpu_device_asic_init(struct amdgpu_device *adev) } /** - * amdgpu_device_vram_scratch_init - allocate the VRAM scratch page + * amdgpu_device_mem_scratch_init - allocate the VRAM scratch page * * @adev: amdgpu_device pointer * * Allocates a scratch page of VRAM for use by various things in the * driver. */ -static int amdgpu_device_vram_scratch_init(struct amdgpu_device *adev) +static int amdgpu_device_mem_scratch_init(struct amdgpu_device *adev) { - return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE, - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &adev->vram_scratch.robj, - &adev->vram_scratch.gpu_addr, - (void **)&adev->vram_scratch.ptr); + return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->mem_scratch.robj, + &adev->mem_scratch.gpu_addr, + (void **)&adev->mem_scratch.ptr); } /** - * amdgpu_device_vram_scratch_fini - Free the VRAM scratch page + * amdgpu_device_mem_scratch_fini - Free the VRAM scratch page * * @adev: amdgpu_device pointer * * Frees the VRAM scratch page. */ -static void amdgpu_device_vram_scratch_fini(struct amdgpu_device *adev) +static void amdgpu_device_mem_scratch_fini(struct amdgpu_device *adev) { - amdgpu_bo_free_kernel(&adev->vram_scratch.robj, NULL, NULL); + amdgpu_bo_free_kernel(&adev->mem_scratch.robj, NULL, NULL); } /** @@ -1981,17 +1986,10 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name); - err = request_firmware(&adev->firmware.gpu_info_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->firmware.gpu_info_fw, fw_name); if (err) { dev_err(adev->dev, - "Failed to load gpu_info firmware \"%s\"\n", - fw_name); - goto out; - } - err = amdgpu_ucode_validate(adev->firmware.gpu_info_fw); - if (err) { - dev_err(adev->dev, - "Failed to validate gpu_info firmware \"%s\"\n", + "Failed to get gpu_info firmware \"%s\"\n", fw_name); goto out; } @@ -2078,6 +2076,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) struct drm_device *dev = adev_to_drm(adev); struct pci_dev *parent; int i, r; + bool total; amdgpu_device_enable_virtual_display(adev); @@ -2161,6 +2160,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID) adev->pm.pp_feature &= ~PP_OVERDRIVE_MASK; + total = true; for (i = 0; i < adev->num_ip_blocks; i++) { if ((amdgpu_ip_block_mask & (1 << i)) == 0) { DRM_ERROR("disabled ip block: %d <%s>\n", @@ -2174,7 +2174,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) } else if (r) { DRM_ERROR("early_init of IP block <%s> failed %d\n", adev->ip_blocks[i].version->funcs->name, r); - return r; + total = false; } else { adev->ip_blocks[i].status.valid = true; } @@ -2205,6 +2205,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) } } + if (!total) + return -ENODEV; adev->cg_flags &= amdgpu_cg_mask; adev->pg_flags &= amdgpu_pg_mask; @@ -2390,9 +2392,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) amdgpu_virt_exchange_data(adev); - r = amdgpu_device_vram_scratch_init(adev); + r = amdgpu_device_mem_scratch_init(adev); if (r) { - DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r); + DRM_ERROR("amdgpu_mem_scratch_init failed %d\n", r); goto init_failed; } r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev); @@ -2410,8 +2412,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) /* right after GMC hw init, we create CSA */ if (amdgpu_mcbp) { r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj, - AMDGPU_GEM_DOMAIN_VRAM, - AMDGPU_CSA_SIZE); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_CSA_SIZE); if (r) { DRM_ERROR("allocate CSA failed %d\n", r); goto init_failed; @@ -2581,9 +2584,10 @@ int amdgpu_device_set_cg_state(struct amdgpu_device *adev, i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1; if (!adev->ip_blocks[i].status.late_initialized) continue; - /* skip CG for GFX on S0ix */ + /* skip CG for GFX, SDMA on S0ix */ if (adev->in_s0ix && - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX) + (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX || + adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && @@ -2617,9 +2621,10 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev, i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1; if (!adev->ip_blocks[i].status.late_initialized) continue; - /* skip PG for GFX on S0ix */ + /* skip PG for GFX, SDMA on S0ix */ if (adev->in_s0ix && - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX) + (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX || + adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && @@ -2871,7 +2876,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) amdgpu_ucode_free_bo(adev); amdgpu_free_static_csa(&adev->virt.csa_obj); amdgpu_device_wb_fini(adev); - amdgpu_device_vram_scratch_fini(adev); + amdgpu_device_mem_scratch_fini(adev); amdgpu_ib_pool_fini(adev); } @@ -3027,6 +3032,12 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev) adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_MES)) continue; + /* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */ + if (adev->in_s0ix && + (adev->ip_versions[SDMA0_HWIP][0] >= IP_VERSION(5, 0, 0)) && + (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) + continue; + /* XXX handle errors */ r = adev->ip_blocks[i].version->funcs->suspend(adev); /* XXX handle errors */ @@ -3227,15 +3238,6 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev) return r; } adev->ip_blocks[i].status.hw = true; - - if (adev->in_s0ix && adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { - /* disable gfxoff for IP resume. The gfxoff will be re-enabled in - * amdgpu_device_resume() after IP resume. - */ - amdgpu_gfx_off_ctrl(adev, false); - DRM_DEBUG("will disable gfxoff for re-initializing other blocks\n"); - } - } return 0; @@ -3687,6 +3689,11 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (r) return r; + /* Get rid of things like offb */ + r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver); + if (r) + return r; + /* Enable TMZ based on IP_VERSION */ amdgpu_gmc_tmz_set(adev); @@ -3989,10 +3996,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) } amdgpu_fence_driver_hw_fini(adev); - if (adev->mman.initialized) { - flush_delayed_work(&adev->mman.bdev.wq); - ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); - } + if (adev->mman.initialized) + drain_workqueue(adev->mman.bdev.wq); if (adev->pm_sysfs_en) amdgpu_pm_sysfs_fini(adev); @@ -4024,8 +4029,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) amdgpu_fence_driver_sw_fini(adev); amdgpu_device_ip_fini(adev); - release_firmware(adev->firmware.gpu_info_fw); - adev->firmware.gpu_info_fw = NULL; + amdgpu_ucode_release(&adev->firmware.gpu_info_fw); adev->accel_working = false; dma_fence_put(rcu_dereference_protected(adev->gang_submit, true)); @@ -4223,13 +4227,6 @@ exit: /* Make sure IB tests flushed */ flush_delayed_work(&adev->delayed_init_work); - if (adev->in_s0ix) { - /* re-enable gfxoff after IP resume. This re-enables gfxoff after - * it was disabled for IP resume in amdgpu_device_ip_resume_phase2(). - */ - amdgpu_gfx_off_ctrl(adev, true); - DRM_DEBUG("will enable gfxoff for the mission mode\n"); - } if (fbcon) drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, false); @@ -4610,11 +4607,6 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) if (!amdgpu_ras_is_poison_mode_supported(adev)) return true; - if (!amdgpu_device_ip_check_soft_reset(adev)) { - dev_info(adev->dev,"Timeout, but no hardware hang detected.\n"); - return false; - } - if (amdgpu_sriov_vf(adev)) return true; @@ -4739,7 +4731,8 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, if (!need_full_reset) need_full_reset = amdgpu_device_ip_need_full_reset(adev); - if (!need_full_reset && amdgpu_gpu_recovery) { + if (!need_full_reset && amdgpu_gpu_recovery && + amdgpu_device_ip_check_soft_reset(adev)) { amdgpu_device_ip_pre_soft_reset(adev); r = amdgpu_device_ip_soft_reset(adev); amdgpu_device_ip_post_soft_reset(adev); @@ -5865,8 +5858,8 @@ void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev, int amdgpu_in_reset(struct amdgpu_device *adev) { return atomic_read(&adev->reset_domain->in_gpu_reset); - } - +} + /** * amdgpu_device_halt() - bring hardware to some kind of halt state * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 1bbd56029a4f..b719852daa07 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -33,6 +33,7 @@ #include "gmc_v9_0.h" #include "df_v1_7.h" #include "df_v3_6.h" +#include "df_v4_3.h" #include "nbio_v6_1.h" #include "nbio_v7_0.h" #include "nbio_v7_4.h" @@ -2329,6 +2330,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(3, 5, 2): adev->df.funcs = &df_v1_7_funcs; break; + case IP_VERSION(4, 3, 0): + adev->df.funcs = &df_v4_3_funcs; + break; default: break; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index b22471b3bd63..503f89a766c3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -42,6 +42,7 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_vblank.h> /** @@ -63,7 +64,7 @@ void amdgpu_display_hotplug_work_func(struct work_struct *work) { struct amdgpu_device *adev = container_of(work, struct amdgpu_device, - hotplug_work); + hotplug_work.work); struct drm_device *dev = adev_to_drm(adev); struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 271e30e34d93..0c001bb8fc2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -37,6 +37,7 @@ #include "amdgpu_dma_buf.h" #include "amdgpu_xgmi.h" #include <drm/amdgpu_drm.h> +#include <drm/ttm/ttm_tt.h> #include <linux/dma-buf.h> #include <linux/dma-fence-array.h> #include <linux/pci-p2pdma.h> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b4f2d61ea0d5..7bb12a76631f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -23,7 +23,6 @@ */ #include <drm/amdgpu_drm.h> -#include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_generic.h> #include <drm/drm_gem.h> @@ -39,7 +38,6 @@ #include <linux/mmu_notifier.h> #include <linux/suspend.h> #include <linux/cc_platform.h> -#include <linux/fb.h> #include <linux/dynamic_debug.h> #include "amdgpu.h" @@ -105,13 +103,16 @@ * - 3.46.0 - To enable hot plug amdgpu tests in libdrm * - 3.47.0 - Add AMDGPU_GEM_CREATE_DISCARDABLE and AMDGPU_VM_NOALLOC flags * - 3.48.0 - Add IP discovery version info to HW INFO - * 3.49.0 - Add gang submit into CS IOCTL + * - 3.49.0 - Add gang submit into CS IOCTL + * - 3.50.0 - Update AMDGPU_INFO_DEV_INFO IOCTL for minimum engine and memory clock + * Update AMDGPU_INFO_SENSOR IOCTL for PEAK_PSTATE engine and memory clock + * 3.51.0 - Return the PCIe gen and lanes from the INFO ioctl */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 49 +#define KMS_DRIVER_MINOR 51 #define KMS_DRIVER_PATCHLEVEL 0 -int amdgpu_vram_limit; +unsigned int amdgpu_vram_limit = UINT_MAX; int amdgpu_vis_vram_limit; int amdgpu_gart_size = -1; /* auto */ int amdgpu_gtt_size = -1; /* auto */ @@ -181,6 +182,7 @@ int amdgpu_mes_kiq; int amdgpu_noretry = -1; int amdgpu_force_asic_type = -1; int amdgpu_tmz = -1; /* auto */ +uint amdgpu_freesync_vid_mode; int amdgpu_reset_method = -1; /* auto */ int amdgpu_num_kcq = -1; int amdgpu_smartshift_bias; @@ -880,6 +882,32 @@ MODULE_PARM_DESC(tmz, "Enable TMZ feature (-1 = auto (default), 0 = off, 1 = on) module_param_named(tmz, amdgpu_tmz, int, 0444); /** + * DOC: freesync_video (uint) + * Enable the optimization to adjust front porch timing to achieve seamless + * mode change experience when setting a freesync supported mode for which full + * modeset is not needed. + * + * The Display Core will add a set of modes derived from the base FreeSync + * video mode into the corresponding connector's mode list based on commonly + * used refresh rates and VRR range of the connected display, when users enable + * this feature. From the userspace perspective, they can see a seamless mode + * change experience when the change between different refresh rates under the + * same resolution. Additionally, userspace applications such as Video playback + * can read this modeset list and change the refresh rate based on the video + * frame rate. Finally, the userspace can also derive an appropriate mode for a + * particular refresh rate based on the FreeSync Mode and add it to the + * connector's mode list. + * + * Note: This is an experimental feature. + * + * The default value: 0 (off). + */ +MODULE_PARM_DESC( + freesync_video, + "Enable freesync modesetting optimization feature (0 = off (default), 1 = on)"); +module_param_named(freesync_video, amdgpu_freesync_vid_mode, uint, 0444); + +/** * DOC: reset_method (int) * GPU reset method (-1 = auto (default), 0 = legacy, 1 = mode0, 2 = mode1, 3 = mode2, 4 = baco) */ @@ -2095,11 +2123,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, } #endif - /* Get rid of things like offb */ - ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver); - if (ret) - return ret; - adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev); if (IS_ERR(adev)) return PTR_ERR(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c index c96e458ed088..27a782a9dc72 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c @@ -24,7 +24,6 @@ * Alex Deucher */ -#include <drm/drm_crtc_helper.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" #include "amdgpu_connectors.h" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h index 41a4c7056729..e86834bfea1d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h @@ -30,7 +30,6 @@ #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" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index bb7350ea1d75..ed1164a87fce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -34,6 +34,7 @@ #include <drm/amdgpu_drm.h> #include <drm/drm_drv.h> #include <drm/drm_gem_ttm_helper.h> +#include <drm/ttm/ttm_tt.h> #include "amdgpu.h" #include "amdgpu_display.h" @@ -61,10 +62,10 @@ static vm_fault_t amdgpu_gem_fault(struct vm_fault *vmf) goto unlock; } - ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, - TTM_BO_VM_NUM_PREFAULT); + ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, + TTM_BO_VM_NUM_PREFAULT); - drm_dev_exit(idx); + drm_dev_exit(idx); } else { ret = ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 23692e5d4d13..35ed46b9249c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -156,6 +156,9 @@ static bool amdgpu_gfx_is_compute_multipipe_capable(struct amdgpu_device *adev) return amdgpu_compute_multipipe == 1; } + if (adev->ip_versions[GC_HWIP][0] > IP_VERSION(9, 0, 0)) + return true; + /* FIXME: spreading the queues across pipes causes perf regressions * on POLARIS11 compute workloads */ if (adev->asic_type == CHIP_POLARIS11) @@ -372,8 +375,11 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, * KIQ MQD no matter SRIOV or Bare-metal */ r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &ring->mqd_obj, - &ring->mqd_gpu_addr, &ring->mqd_ptr); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &ring->mqd_obj, + &ring->mqd_gpu_addr, + &ring->mqd_ptr); if (r) { dev_warn(adev->dev, "failed to create ring mqd ob (%d)", r); return r; @@ -693,6 +699,50 @@ late_fini: return r; } +int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev) +{ + int err = 0; + struct amdgpu_gfx_ras *ras = NULL; + + /* adev->gfx.ras is NULL, which means gfx does not + * support ras function, then do nothing here. + */ + if (!adev->gfx.ras) + return 0; + + ras = adev->gfx.ras; + + err = amdgpu_ras_register_ras_block(adev, &ras->ras_block); + if (err) { + dev_err(adev->dev, "Failed to register gfx ras block!\n"); + return err; + } + + strcpy(ras->ras_block.ras_comm.name, "gfx"); + ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__GFX; + ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; + adev->gfx.ras_if = &ras->ras_block.ras_comm; + + /* If not define special ras_late_init function, use gfx default ras_late_init */ + if (!ras->ras_block.ras_late_init) + ras->ras_block.ras_late_init = amdgpu_ras_block_late_init; + + /* If not defined special ras_cb function, use default ras_cb */ + if (!ras->ras_block.ras_cb) + ras->ras_block.ras_cb = amdgpu_gfx_process_ras_data_cb; + + return 0; +} + +int amdgpu_gfx_poison_consumption_handler(struct amdgpu_device *adev, + struct amdgpu_iv_entry *entry) +{ + if (adev->gfx.ras && adev->gfx.ras->poison_consumption_handler) + return adev->gfx.ras->poison_consumption_handler(adev, entry); + + return 0; +} + int amdgpu_gfx_process_ras_data_cb(struct amdgpu_device *adev, void *err_data, struct amdgpu_iv_entry *entry) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index b3df4787877e..86ec9d0d12c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -210,6 +210,11 @@ struct amdgpu_gfx_ras { struct amdgpu_ras_block_object ras_block; void (*enable_watchdog_timer)(struct amdgpu_device *adev); bool (*query_utcl2_poison_status)(struct amdgpu_device *adev); + int (*rlc_gc_fed_irq)(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry); + int (*poison_consumption_handler)(struct amdgpu_device *adev, + struct amdgpu_iv_entry *entry); }; struct amdgpu_gfx_funcs { @@ -323,6 +328,7 @@ struct amdgpu_gfx { struct amdgpu_irq_src priv_inst_irq; struct amdgpu_irq_src cp_ecc_error_irq; struct amdgpu_irq_src sq_irq; + struct amdgpu_irq_src rlc_gc_fed_irq; struct sq_work sq_work; /* gfx status */ @@ -432,4 +438,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v); int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev); void amdgpu_gfx_cp_init_microcode(struct amdgpu_device *adev, uint32_t ucode_id); +int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev); +int amdgpu_gfx_poison_consumption_handler(struct amdgpu_device *adev, + struct amdgpu_iv_entry *entry); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 02a4c93673ce..94f10ac0eef7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -35,6 +35,7 @@ #include "amdgpu_xgmi.h" #include <drm/drm_drv.h> +#include <drm/ttm/ttm_tt.h> /** * amdgpu_gmc_pdb0_alloc - allocate vram for pdb0 @@ -201,13 +202,20 @@ uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo) void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, u64 base) { + uint64_t vis_limit = (uint64_t)amdgpu_vis_vram_limit << 20; uint64_t limit = (uint64_t)amdgpu_vram_limit << 20; mc->vram_start = base; mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; - if (limit && limit < mc->real_vram_size) + if (limit < mc->real_vram_size) mc->real_vram_size = limit; + if (vis_limit && vis_limit < mc->visible_vram_size) + mc->visible_vram_size = vis_limit; + + if (mc->real_vram_size < mc->visible_vram_size) + mc->visible_vram_size = mc->real_vram_size; + if (mc->xgmi.num_physical_nodes == 0) { mc->fb_start = mc->vram_start; mc->fb_end = mc->vram_end; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index fcb711a11a5b..3f07b1a2ce47 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -497,6 +497,7 @@ void amdgpu_vmid_free_reserved(struct amdgpu_device *adev, !--id_mgr->reserved_use_count) { /* give the reserved ID back to normal round robin */ list_add(&id_mgr->reserved->list, &id_mgr->ids_lru); + id_mgr->reserved = NULL; } vm->reserved_vmid[vmhub] = false; mutex_unlock(&id_mgr->lock); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index a6aef488a822..d0a1cc88832c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -45,7 +45,6 @@ #include <linux/irq.h> #include <linux/pci.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_vblank.h> #include <drm/amdgpu_drm.h> #include <drm/drm_drv.h> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 9e549923622b..c3d9d75143f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -161,8 +161,14 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) struct dma_fence *f; unsigned i; - /* use sched fence if available */ - f = job->base.s_fence ? &job->base.s_fence->finished : &job->hw_fence; + /* Check if any fences where initialized */ + if (job->base.s_fence && job->base.s_fence->finished.ops) + f = &job->base.s_fence->finished; + else if (job->hw_fence.ops) + f = &job->hw_fence; + else + f = NULL; + for (i = 0; i < job->num_ibs; ++i) amdgpu_ib_free(ring->adev, &job->ibs[i], f); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 7aa7e52ca784..ca945055e683 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -43,6 +43,7 @@ #include "amdgpu_gem.h" #include "amdgpu_display.h" #include "amdgpu_ras.h" +#include "amd_pcie.h" void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev) { @@ -767,6 +768,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case AMDGPU_INFO_DEV_INFO: { struct drm_amdgpu_info_device *dev_info; uint64_t vm_size; + uint32_t pcie_gen_mask; int ret; dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); @@ -785,15 +787,20 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (adev->pm.dpm_enabled) { dev_info->max_engine_clock = amdgpu_dpm_get_sclk(adev, false) * 10; dev_info->max_memory_clock = amdgpu_dpm_get_mclk(adev, false) * 10; + dev_info->min_engine_clock = amdgpu_dpm_get_sclk(adev, true) * 10; + dev_info->min_memory_clock = amdgpu_dpm_get_mclk(adev, true) * 10; } else { - dev_info->max_engine_clock = adev->clock.default_sclk * 10; - dev_info->max_memory_clock = adev->clock.default_mclk * 10; + dev_info->max_engine_clock = + dev_info->min_engine_clock = + adev->clock.default_sclk * 10; + dev_info->max_memory_clock = + dev_info->min_memory_clock = + adev->clock.default_mclk * 10; } dev_info->enabled_rb_pipes_mask = adev->gfx.config.backend_enable_mask; dev_info->num_rb_pipes = adev->gfx.config.max_backends_per_se * adev->gfx.config.max_shader_engines; dev_info->num_hw_gfx_contexts = adev->gfx.config.max_hw_contexts; - dev_info->_pad = 0; dev_info->ids_flags = 0; if (adev->flags & AMD_IS_APU) dev_info->ids_flags |= AMDGPU_IDS_FLAGS_FUSION; @@ -847,6 +854,17 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) dev_info->tcc_disabled_mask = adev->gfx.config.tcc_disabled_mask; + /* Combine the chip gen mask with the platform (CPU/mobo) mask. */ + pcie_gen_mask = adev->pm.pcie_gen_mask & (adev->pm.pcie_gen_mask >> 16); + dev_info->pcie_gen = fls(pcie_gen_mask); + dev_info->pcie_num_lanes = + adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 ? 32 : + adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 ? 16 : + adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 ? 12 : + adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 ? 8 : + adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 ? 4 : + adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 ? 2 : 1; + ret = copy_to_user(out, dev_info, min((size_t)size, sizeof(*dev_info))) ? -EFAULT : 0; kfree(dev_info); @@ -1014,6 +1032,24 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } ui32 /= 100; break; + case AMDGPU_INFO_SENSOR_PEAK_PSTATE_GFX_SCLK: + /* get peak pstate sclk in Mhz */ + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK, + (void *)&ui32, &ui32_size)) { + return -EINVAL; + } + ui32 /= 100; + break; + case AMDGPU_INFO_SENSOR_PEAK_PSTATE_GFX_MCLK: + /* get peak pstate mclk in Mhz */ + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK, + (void *)&ui32, &ui32_size)) { + return -EINVAL; + } + ui32 /= 100; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->sensor_info.type); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 0c546245793b..82e27bd4f038 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -21,6 +21,8 @@ * */ +#include <linux/firmware.h> + #include "amdgpu_mes.h" #include "amdgpu.h" #include "soc15_common.h" @@ -1423,3 +1425,60 @@ error_pasid: kfree(vm); return 0; } + +int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe) +{ + const struct mes_firmware_header_v1_0 *mes_hdr; + struct amdgpu_firmware_info *info; + char ucode_prefix[30]; + char fw_name[40]; + int r; + + amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin", + ucode_prefix, + pipe == AMDGPU_MES_SCHED_PIPE ? "" : "1"); + r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], fw_name); + if (r) + goto out; + + mes_hdr = (const struct mes_firmware_header_v1_0 *) + adev->mes.fw[pipe]->data; + adev->mes.uc_start_addr[pipe] = + le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | + ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); + adev->mes.data_start_addr[pipe] = + le32_to_cpu(mes_hdr->mes_data_start_addr_lo) | + ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + int ucode, ucode_data; + + if (pipe == AMDGPU_MES_SCHED_PIPE) { + ucode = AMDGPU_UCODE_ID_CP_MES; + ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA; + } else { + ucode = AMDGPU_UCODE_ID_CP_MES1; + ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA; + } + + info = &adev->firmware.ucode[ucode]; + info->ucode_id = ucode; + info->fw = adev->mes.fw[pipe]; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes), + PAGE_SIZE); + + info = &adev->firmware.ucode[ucode_data]; + info->ucode_id = ucode_data; + info->fw = adev->mes.fw[pipe]; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes), + PAGE_SIZE); + } + + return 0; +out: + amdgpu_ucode_release(&adev->mes.fw[pipe]); + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 97c05d08a551..547ec35691fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -306,6 +306,7 @@ struct amdgpu_mes_funcs { int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs); +int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe); int amdgpu_mes_init(struct amdgpu_device *adev); void amdgpu_mes_fini(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 8a39300b1a84..44c57f4a84c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -35,7 +35,6 @@ #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_fixed.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_probe_helper.h> #include <linux/i2c.h> @@ -534,6 +533,7 @@ struct amdgpu_connector { void *con_priv; bool dac_load_detect; bool detected_by_load; /* if the connection status was determined by load */ + bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */ uint16_t connector_object_id; struct amdgpu_hpd hpd; struct amdgpu_router router; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 4e684c2afc70..981010de0a28 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -470,8 +470,9 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, return true; fail: - DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size, - man->size); + if (man) + DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size, + man->size); return false; } @@ -1573,9 +1574,9 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m) attachment = READ_ONCE(bo->tbo.base.import_attach); if (attachment) - seq_printf(m, " imported from %p", dma_buf); + seq_printf(m, " imported from ino:%lu", file_inode(dma_buf->file)->i_ino); else if (dma_buf) - seq_printf(m, " exported as %p", dma_buf); + seq_printf(m, " exported as ino:%lu", file_inode(dma_buf->file)->i_ino); amdgpu_bo_print_flag(m, bo, CPU_ACCESS_REQUIRED); amdgpu_bo_print_flag(m, bo, NO_CPU_ACCESS); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 7a2fc920739b..a8391f269cd0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -66,7 +66,8 @@ static int psp_ring_init(struct psp_context *psp, /* allocate 4k Page of Local Frame Buffer memory for ring */ ring->ring_size = 0x1000; ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->firmware.rbuf, &ring->ring_mem_mc_addr, (void **)&ring->ring_mem); @@ -122,6 +123,38 @@ static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp } } +static int psp_init_sriov_microcode(struct psp_context *psp) +{ + struct amdgpu_device *adev = psp->adev; + char ucode_prefix[30]; + int ret = 0; + + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); + + switch (adev->ip_versions[MP0_HWIP][0]) { + case IP_VERSION(9, 0, 0): + case IP_VERSION(11, 0, 7): + case IP_VERSION(11, 0, 9): + adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; + ret = psp_init_cap_microcode(psp, ucode_prefix); + break; + case IP_VERSION(13, 0, 2): + adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; + ret = psp_init_cap_microcode(psp, ucode_prefix); + ret &= psp_init_ta_microcode(psp, ucode_prefix); + break; + case IP_VERSION(13, 0, 0): + adev->virt.autoload_ucode_id = 0; + break; + case IP_VERSION(13, 0, 10): + adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA; + break; + default: + return -EINVAL; + } + return ret; +} + static int psp_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -192,7 +225,10 @@ static int psp_early_init(void *handle) psp_check_pmfw_centralized_cstate_management(psp); - return 0; + if (amdgpu_sriov_vf(adev)) + return psp_init_sriov_microcode(psp); + else + return psp_init_microcode(psp); } void psp_ta_free_shared_buf(struct ta_mem_context *mem_ctx) @@ -300,7 +336,7 @@ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) { /* runtime db doesn't exist, exit */ - dev_warn(adev->dev, "PSP runtime database doesn't exist\n"); + dev_dbg(adev->dev, "PSP runtime database doesn't exist\n"); return false; } @@ -350,42 +386,6 @@ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, return ret; } -static int psp_init_sriov_microcode(struct psp_context *psp) -{ - struct amdgpu_device *adev = psp->adev; - int ret = 0; - - switch (adev->ip_versions[MP0_HWIP][0]) { - case IP_VERSION(9, 0, 0): - adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; - ret = psp_init_cap_microcode(psp, "vega10"); - break; - case IP_VERSION(11, 0, 9): - adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; - ret = psp_init_cap_microcode(psp, "navi12"); - break; - case IP_VERSION(11, 0, 7): - adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; - ret = psp_init_cap_microcode(psp, "sienna_cichlid"); - break; - case IP_VERSION(13, 0, 2): - adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; - ret = psp_init_cap_microcode(psp, "aldebaran"); - ret &= psp_init_ta_microcode(psp, "aldebaran"); - break; - case IP_VERSION(13, 0, 0): - adev->virt.autoload_ucode_id = 0; - break; - case IP_VERSION(13, 0, 10): - adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA; - break; - default: - BUG(); - break; - } - return ret; -} - static int psp_sw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -401,15 +401,6 @@ static int psp_sw_init(void *handle) ret = -ENOMEM; } - if (amdgpu_sriov_vf(adev)) - ret = psp_init_sriov_microcode(psp); - else - ret = psp_init_microcode(psp); - if (ret) { - DRM_ERROR("Failed to load psp firmware!\n"); - return ret; - } - adev->psp.xgmi_context.supports_extended_data = !adev->gmc.xgmi.connected_to_cpu && adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 2); @@ -514,20 +505,11 @@ static int psp_sw_fini(void *handle) psp_memory_training_fini(psp); - release_firmware(psp->sos_fw); - psp->sos_fw = NULL; - - release_firmware(psp->asd_fw); - psp->asd_fw = NULL; - - release_firmware(psp->ta_fw); - psp->ta_fw = NULL; - - release_firmware(psp->cap_fw); - psp->cap_fw = NULL; - - release_firmware(psp->toc_fw); - psp->toc_fw = NULL; + amdgpu_ucode_release(&psp->sos_fw); + amdgpu_ucode_release(&psp->asd_fw); + amdgpu_ucode_release(&psp->ta_fw); + amdgpu_ucode_release(&psp->cap_fw); + amdgpu_ucode_release(&psp->toc_fw); if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 0) || adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 7)) @@ -797,9 +779,13 @@ static int psp_tmr_init(struct psp_context *psp) if (!psp->tmr_bo) { pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; - ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_ALIGNMENT, - AMDGPU_GEM_DOMAIN_VRAM, - &psp->tmr_bo, &psp->tmr_mc_addr, pptr); + ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, + PSP_TMR_ALIGNMENT, + AMDGPU_HAS_VRAM(psp->adev) ? + AMDGPU_GEM_DOMAIN_VRAM : + AMDGPU_GEM_DOMAIN_GTT, + &psp->tmr_bo, &psp->tmr_mc_addr, + pptr); } return ret; @@ -1092,7 +1078,8 @@ int psp_ta_init_shared_buf(struct psp_context *psp, * physical) for ta to host memory */ return amdgpu_bo_create_kernel(psp->adev, mem_ctx->shared_mem_size, - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &mem_ctx->shared_bo, &mem_ctx->shared_mc_addr, &mem_ctx->shared_buf); @@ -1901,7 +1888,7 @@ out_unlock: static int psp_securedisplay_initialize(struct psp_context *psp) { int ret; - struct securedisplay_cmd *securedisplay_cmd; + struct ta_securedisplay_cmd *securedisplay_cmd; /* * TODO: bypass the initialize in sriov for now @@ -2908,25 +2895,15 @@ int psp_ring_cmd_submit(struct psp_context *psp, return 0; } -int psp_init_asd_microcode(struct psp_context *psp, - const char *chip_name) +int psp_init_asd_microcode(struct psp_context *psp, const char *chip_name) { struct amdgpu_device *adev = psp->adev; char fw_name[PSP_FW_NAME_LEN]; const struct psp_firmware_header_v1_0 *asd_hdr; int err = 0; - if (!chip_name) { - dev_err(adev->dev, "invalid chip name for asd microcode\n"); - return -EINVAL; - } - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name); - err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev); - if (err) - goto out; - - err = amdgpu_ucode_validate(adev->psp.asd_fw); + err = amdgpu_ucode_request(adev, &adev->psp.asd_fw, fw_name); if (err) goto out; @@ -2938,31 +2915,19 @@ int psp_init_asd_microcode(struct psp_context *psp, le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes); return 0; out: - dev_err(adev->dev, "fail to initialize asd microcode\n"); - release_firmware(adev->psp.asd_fw); - adev->psp.asd_fw = NULL; + amdgpu_ucode_release(&adev->psp.asd_fw); return err; } -int psp_init_toc_microcode(struct psp_context *psp, - const char *chip_name) +int psp_init_toc_microcode(struct psp_context *psp, const char *chip_name) { struct amdgpu_device *adev = psp->adev; char fw_name[PSP_FW_NAME_LEN]; const struct psp_firmware_header_v1_0 *toc_hdr; int err = 0; - if (!chip_name) { - dev_err(adev->dev, "invalid chip name for toc microcode\n"); - return -EINVAL; - } - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", chip_name); - err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev); - if (err) - goto out; - - err = amdgpu_ucode_validate(adev->psp.toc_fw); + err = amdgpu_ucode_request(adev, &adev->psp.toc_fw, fw_name); if (err) goto out; @@ -2974,9 +2939,7 @@ int psp_init_toc_microcode(struct psp_context *psp, le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes); return 0; out: - dev_err(adev->dev, "fail to request/validate toc microcode\n"); - release_firmware(adev->psp.toc_fw); - adev->psp.toc_fw = NULL; + amdgpu_ucode_release(&adev->psp.toc_fw); return err; } @@ -3107,8 +3070,7 @@ static int psp_init_sos_base_fw(struct amdgpu_device *adev) return 0; } -int psp_init_sos_microcode(struct psp_context *psp, - const char *chip_name) +int psp_init_sos_microcode(struct psp_context *psp, const char *chip_name) { struct amdgpu_device *adev = psp->adev; char fw_name[PSP_FW_NAME_LEN]; @@ -3121,17 +3083,8 @@ int psp_init_sos_microcode(struct psp_context *psp, uint8_t *ucode_array_start_addr; int fw_index = 0; - if (!chip_name) { - dev_err(adev->dev, "invalid chip name for sos microcode\n"); - return -EINVAL; - } - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name); - err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev); - if (err) - goto out; - - err = amdgpu_ucode_validate(adev->psp.sos_fw); + err = amdgpu_ucode_request(adev, &adev->psp.sos_fw, fw_name); if (err) goto out; @@ -3203,10 +3156,7 @@ int psp_init_sos_microcode(struct psp_context *psp, return 0; out: - dev_err(adev->dev, - "failed to init sos firmware\n"); - release_firmware(adev->psp.sos_fw); - adev->psp.sos_fw = NULL; + amdgpu_ucode_release(&adev->psp.sos_fw); return err; } @@ -3272,41 +3222,76 @@ static int parse_ta_bin_descriptor(struct psp_context *psp, return 0; } -int psp_init_ta_microcode(struct psp_context *psp, - const char *chip_name) +static int parse_ta_v1_microcode(struct psp_context *psp) { + const struct ta_firmware_header_v1_0 *ta_hdr; struct amdgpu_device *adev = psp->adev; - char fw_name[PSP_FW_NAME_LEN]; - const struct ta_firmware_header_v2_0 *ta_hdr; - int err = 0; - int ta_index = 0; - if (!chip_name) { - dev_err(adev->dev, "invalid chip name for ta microcode\n"); + ta_hdr = (const struct ta_firmware_header_v1_0 *) adev->psp.ta_fw->data; + + if (le16_to_cpu(ta_hdr->header.header_version_major) != 1) return -EINVAL; - } - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); - err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); - if (err) - goto out; + adev->psp.xgmi_context.context.bin_desc.fw_version = + le32_to_cpu(ta_hdr->xgmi.fw_version); + adev->psp.xgmi_context.context.bin_desc.size_bytes = + le32_to_cpu(ta_hdr->xgmi.size_bytes); + adev->psp.xgmi_context.context.bin_desc.start_addr = + (uint8_t *)ta_hdr + + le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); + + adev->psp.ras_context.context.bin_desc.fw_version = + le32_to_cpu(ta_hdr->ras.fw_version); + adev->psp.ras_context.context.bin_desc.size_bytes = + le32_to_cpu(ta_hdr->ras.size_bytes); + adev->psp.ras_context.context.bin_desc.start_addr = + (uint8_t *)adev->psp.xgmi_context.context.bin_desc.start_addr + + le32_to_cpu(ta_hdr->ras.offset_bytes); + + adev->psp.hdcp_context.context.bin_desc.fw_version = + le32_to_cpu(ta_hdr->hdcp.fw_version); + adev->psp.hdcp_context.context.bin_desc.size_bytes = + le32_to_cpu(ta_hdr->hdcp.size_bytes); + adev->psp.hdcp_context.context.bin_desc.start_addr = + (uint8_t *)ta_hdr + + le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); + + adev->psp.dtm_context.context.bin_desc.fw_version = + le32_to_cpu(ta_hdr->dtm.fw_version); + adev->psp.dtm_context.context.bin_desc.size_bytes = + le32_to_cpu(ta_hdr->dtm.size_bytes); + adev->psp.dtm_context.context.bin_desc.start_addr = + (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + + le32_to_cpu(ta_hdr->dtm.offset_bytes); + + adev->psp.securedisplay_context.context.bin_desc.fw_version = + le32_to_cpu(ta_hdr->securedisplay.fw_version); + adev->psp.securedisplay_context.context.bin_desc.size_bytes = + le32_to_cpu(ta_hdr->securedisplay.size_bytes); + adev->psp.securedisplay_context.context.bin_desc.start_addr = + (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + + le32_to_cpu(ta_hdr->securedisplay.offset_bytes); + + adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - err = amdgpu_ucode_validate(adev->psp.ta_fw); - if (err) - goto out; + return 0; +} + +static int parse_ta_v2_microcode(struct psp_context *psp) +{ + const struct ta_firmware_header_v2_0 *ta_hdr; + struct amdgpu_device *adev = psp->adev; + int err = 0; + int ta_index = 0; ta_hdr = (const struct ta_firmware_header_v2_0 *)adev->psp.ta_fw->data; - if (le16_to_cpu(ta_hdr->header.header_version_major) != 2) { - dev_err(adev->dev, "unsupported TA header version\n"); - err = -EINVAL; - goto out; - } + if (le16_to_cpu(ta_hdr->header.header_version_major) != 2) + return -EINVAL; if (le32_to_cpu(ta_hdr->ta_fw_bin_count) >= UCODE_MAX_PSP_PACKAGING) { dev_err(adev->dev, "packed TA count exceeds maximum limit\n"); - err = -EINVAL; - goto out; + return -EINVAL; } for (ta_index = 0; ta_index < le32_to_cpu(ta_hdr->ta_fw_bin_count); ta_index++) { @@ -3314,19 +3299,44 @@ int psp_init_ta_microcode(struct psp_context *psp, &ta_hdr->ta_fw_bin[ta_index], ta_hdr); if (err) - goto out; + return err; } return 0; -out: - dev_err(adev->dev, "fail to initialize ta microcode\n"); - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; +} + +int psp_init_ta_microcode(struct psp_context *psp, const char *chip_name) +{ + const struct common_firmware_header *hdr; + struct amdgpu_device *adev = psp->adev; + char fw_name[PSP_FW_NAME_LEN]; + int err; + + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); + err = amdgpu_ucode_request(adev, &adev->psp.ta_fw, fw_name); + if (err) + return err; + + hdr = (const struct common_firmware_header *)adev->psp.ta_fw->data; + switch (le16_to_cpu(hdr->header_version_major)) { + case 1: + err = parse_ta_v1_microcode(psp); + break; + case 2: + err = parse_ta_v2_microcode(psp); + break; + default: + dev_err(adev->dev, "unsupported TA header version\n"); + err = -EINVAL; + } + + if (err) + amdgpu_ucode_release(&adev->psp.ta_fw); + return err; } -int psp_init_cap_microcode(struct psp_context *psp, - const char *chip_name) +int psp_init_cap_microcode(struct psp_context *psp, const char *chip_name) { struct amdgpu_device *adev = psp->adev; char fw_name[PSP_FW_NAME_LEN]; @@ -3334,28 +3344,20 @@ int psp_init_cap_microcode(struct psp_context *psp, struct amdgpu_firmware_info *info = NULL; int err = 0; - if (!chip_name) { - dev_err(adev->dev, "invalid chip name for cap microcode\n"); - return -EINVAL; - } - if (!amdgpu_sriov_vf(adev)) { dev_err(adev->dev, "cap microcode should only be loaded under SRIOV\n"); return -EINVAL; } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_cap.bin", chip_name); - err = request_firmware(&adev->psp.cap_fw, fw_name, adev->dev); - if (err) { - dev_warn(adev->dev, "cap microcode does not exist, skip\n"); - err = 0; - goto out; - } - - err = amdgpu_ucode_validate(adev->psp.cap_fw); + err = amdgpu_ucode_request(adev, &adev->psp.cap_fw, fw_name); if (err) { + if (err == -ENODEV) { + dev_warn(adev->dev, "cap microcode does not exist, skip\n"); + err = 0; + goto out; + } dev_err(adev->dev, "fail to initialize cap microcode\n"); - goto out; } info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CAP]; @@ -3372,8 +3374,7 @@ int psp_init_cap_microcode(struct psp_context *psp, return 0; out: - release_firmware(adev->psp.cap_fw); - adev->psp.cap_fw = NULL; + amdgpu_ucode_release(&adev->psp.cap_fw); return err; } @@ -3444,10 +3445,10 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, /* LFB address which is aligned to 1MB boundary per PSP request */ ret = amdgpu_bo_create_kernel(adev, usbc_pd_fw->size, 0x100000, - AMDGPU_GEM_DOMAIN_VRAM, - &fw_buf_bo, - &fw_pri_mc_addr, - &fw_pri_cpu_addr); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &fw_buf_bo, &fw_pri_mc_addr, + &fw_pri_cpu_addr); if (ret) goto rel_buf; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index ad490c1e2f57..6e543558386d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -706,13 +706,23 @@ static int __amdgpu_ras_feature_enable(struct amdgpu_device *adev, return 0; } +static int amdgpu_ras_check_feature_allowed(struct amdgpu_device *adev, + struct ras_common_if *head) +{ + if (amdgpu_ras_is_feature_allowed(adev, head) || + amdgpu_ras_is_poison_mode_supported(adev)) + return 1; + else + return 0; +} + /* wrapper of psp_ras_enable_features */ int amdgpu_ras_feature_enable(struct amdgpu_device *adev, struct ras_common_if *head, bool enable) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); union ta_ras_cmd_input *info; - int ret; + int ret = 0; if (!con) return -EINVAL; @@ -736,7 +746,8 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev, } /* Do not enable if it is not allowed. */ - WARN_ON(enable && !amdgpu_ras_is_feature_allowed(adev, head)); + if (enable && !amdgpu_ras_check_feature_allowed(adev, head)) + goto out; /* Only enable ras feature operation handle on host side */ if (head->block == AMDGPU_RAS_BLOCK__GFX && @@ -754,7 +765,6 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev, /* setup the obj */ __amdgpu_ras_feature_enable(adev, head, enable); - ret = 0; out: if (head->block == AMDGPU_RAS_BLOCK__GFX) kfree(info); @@ -910,9 +920,6 @@ static struct amdgpu_ras_block_object *amdgpu_ras_get_ras_block(struct amdgpu_de if (block >= AMDGPU_RAS_BLOCK__LAST) return NULL; - if (!amdgpu_ras_is_supported(adev, block)) - return NULL; - list_for_each_entry_safe(node, tmp, &adev->ras_list, node) { if (!node->ras_obj) { dev_warn(adev->dev, "Warning: abnormal ras list node.\n"); @@ -1087,6 +1094,10 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev, info->head.block, info->head.sub_block_index); + /* inject on guest isn't allowed, return success directly */ + if (amdgpu_sriov_vf(adev)) + return 0; + if (!obj) return -EINVAL; @@ -1122,11 +1133,54 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev, } /** - * amdgpu_ras_query_error_count -- Get error counts of all IPs + * amdgpu_ras_query_error_count_helper -- Get error counter for specific IP + * @adev: pointer to AMD GPU device + * @ce_count: pointer to an integer to be set to the count of correctible errors. + * @ue_count: pointer to an integer to be set to the count of uncorrectible errors. + * @query_info: pointer to ras_query_if + * + * Return 0 for query success or do nothing, otherwise return an error + * on failures + */ +static int amdgpu_ras_query_error_count_helper(struct amdgpu_device *adev, + unsigned long *ce_count, + unsigned long *ue_count, + struct ras_query_if *query_info) +{ + int ret; + + if (!query_info) + /* do nothing if query_info is not specified */ + return 0; + + ret = amdgpu_ras_query_error_status(adev, query_info); + if (ret) + return ret; + + *ce_count += query_info->ce_count; + *ue_count += query_info->ue_count; + + /* some hardware/IP supports read to clear + * no need to explictly reset the err status after the query call */ + if (adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 2) && + adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 4)) { + if (amdgpu_ras_reset_error_status(adev, query_info->head.block)) + dev_warn(adev->dev, + "Failed to reset error counter and error status\n"); + } + + return 0; +} + +/** + * amdgpu_ras_query_error_count -- Get error counts of all IPs or specific IP * @adev: pointer to AMD GPU device * @ce_count: pointer to an integer to be set to the count of correctible errors. * @ue_count: pointer to an integer to be set to the count of uncorrectible * errors. + * @query_info: pointer to ras_query_if if the query request is only for + * specific ip block; if info is NULL, then the qurey request is for + * all the ip blocks that support query ras error counters/status * * If set, @ce_count or @ue_count, count and return the corresponding * error counts in those integer pointers. Return 0 if the device @@ -1134,11 +1188,13 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev, */ int amdgpu_ras_query_error_count(struct amdgpu_device *adev, unsigned long *ce_count, - unsigned long *ue_count) + unsigned long *ue_count, + struct ras_query_if *query_info) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_manager *obj; unsigned long ce, ue; + int ret; if (!adev->ras_enabled || !con) return -EOPNOTSUPP; @@ -1150,26 +1206,23 @@ int amdgpu_ras_query_error_count(struct amdgpu_device *adev, ce = 0; ue = 0; - list_for_each_entry(obj, &con->head, node) { - struct ras_query_if info = { - .head = obj->head, - }; - int res; - - res = amdgpu_ras_query_error_status(adev, &info); - if (res) - return res; + if (!query_info) { + /* query all the ip blocks that support ras query interface */ + list_for_each_entry(obj, &con->head, node) { + struct ras_query_if info = { + .head = obj->head, + }; - if (adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 2) && - adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 4)) { - if (amdgpu_ras_reset_error_status(adev, info.head.block)) - dev_warn(adev->dev, "Failed to reset error counter and error status"); + ret = amdgpu_ras_query_error_count_helper(adev, &ce, &ue, &info); } - - ce += info.ce_count; - ue += info.ue_count; + } else { + /* query specific ip block */ + ret = amdgpu_ras_query_error_count_helper(adev, &ce, &ue, query_info); } + if (ret) + return ret; + if (ce_count) *ce_count = ce; @@ -1564,14 +1617,14 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager * struct amdgpu_ras_block_object *block_obj = amdgpu_ras_get_ras_block(adev, obj->head.block, 0); - if (!block_obj || !block_obj->hw_ops) + if (!block_obj) return; /* both query_poison_status and handle_poison_consumption are optional, * but at least one of them should be implemented if we need poison * consumption handler */ - if (block_obj->hw_ops->query_poison_status) { + if (block_obj->hw_ops && block_obj->hw_ops->query_poison_status) { poison_stat = block_obj->hw_ops->query_poison_status(adev); if (!poison_stat) { /* Not poison consumption interrupt, no need to handle it */ @@ -1585,7 +1638,7 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager * if (!adev->gmc.xgmi.connected_to_cpu) amdgpu_umc_poison_handler(adev, false); - if (block_obj->hw_ops->handle_poison_consumption) + if (block_obj->hw_ops && block_obj->hw_ops->handle_poison_consumption) poison_stat = block_obj->hw_ops->handle_poison_consumption(adev); /* gpu reset is fallback for failed and default cases */ @@ -1593,6 +1646,8 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager * dev_info(adev->dev, "GPU reset for %s RAS poison consumption is issued!\n", block_obj->ras_comm.name); amdgpu_ras_reset_gpu(adev); + } else { + amdgpu_gfx_poison_consumption_handler(adev, entry); } } @@ -2344,22 +2399,24 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) if (amdgpu_atomfirmware_sram_ecc_supported(adev)) { dev_info(adev->dev, "SRAM ECC is active.\n"); - if (!amdgpu_sriov_vf(adev)) { + if (!amdgpu_sriov_vf(adev)) adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC | 1 << AMDGPU_RAS_BLOCK__DF); - - if (adev->ip_versions[VCN_HWIP][0] == IP_VERSION(2, 6, 0) || - adev->ip_versions[VCN_HWIP][0] == IP_VERSION(4, 0, 0)) - adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN | - 1 << AMDGPU_RAS_BLOCK__JPEG); - else - adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN | - 1 << AMDGPU_RAS_BLOCK__JPEG); - } else { + else adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__PCIE_BIF | 1 << AMDGPU_RAS_BLOCK__SDMA | 1 << AMDGPU_RAS_BLOCK__GFX); - } + + /* VCN/JPEG RAS can be supported on both bare metal and + * SRIOV environment + */ + if (adev->ip_versions[VCN_HWIP][0] == IP_VERSION(2, 6, 0) || + adev->ip_versions[VCN_HWIP][0] == IP_VERSION(4, 0, 0)) + adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN | + 1 << AMDGPU_RAS_BLOCK__JPEG); + else + adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN | + 1 << AMDGPU_RAS_BLOCK__JPEG); } else { dev_info(adev->dev, "SRAM ECC is not presented.\n"); } @@ -2395,7 +2452,7 @@ static void amdgpu_ras_counte_dw(struct work_struct *work) /* Cache new values. */ - if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count) == 0) { + if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count, NULL) == 0) { atomic_set(&con->ras_ce_count, ce_count); atomic_set(&con->ras_ue_count, ue_count); } @@ -2405,11 +2462,42 @@ Out: pm_runtime_put_autosuspend(dev->dev); } +static void amdgpu_ras_query_poison_mode(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + bool df_poison, umc_poison; + + /* poison setting is useless on SRIOV guest */ + if (amdgpu_sriov_vf(adev) || !con) + return; + + /* Init poison supported flag, the default value is false */ + if (adev->gmc.xgmi.connected_to_cpu) { + /* enabled by default when GPU is connected to CPU */ + con->poison_supported = true; + } else if (adev->df.funcs && + adev->df.funcs->query_ras_poison_mode && + adev->umc.ras && + adev->umc.ras->query_ras_poison_mode) { + df_poison = + adev->df.funcs->query_ras_poison_mode(adev); + umc_poison = + adev->umc.ras->query_ras_poison_mode(adev); + + /* Only poison is set in both DF and UMC, we can support it */ + if (df_poison && umc_poison) + con->poison_supported = true; + else if (df_poison != umc_poison) + dev_warn(adev->dev, + "Poison setting is inconsistent in DF/UMC(%d:%d)!\n", + df_poison, umc_poison); + } +} + int amdgpu_ras_init(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); int r; - bool df_poison, umc_poison; if (con) return 0; @@ -2484,26 +2572,7 @@ int amdgpu_ras_init(struct amdgpu_device *adev) goto release_con; } - /* Init poison supported flag, the default value is false */ - if (adev->gmc.xgmi.connected_to_cpu) { - /* enabled by default when GPU is connected to CPU */ - con->poison_supported = true; - } - else if (adev->df.funcs && - adev->df.funcs->query_ras_poison_mode && - adev->umc.ras && - adev->umc.ras->query_ras_poison_mode) { - df_poison = - adev->df.funcs->query_ras_poison_mode(adev); - umc_poison = - adev->umc.ras->query_ras_poison_mode(adev); - /* Only poison is set in both DF and UMC, we can support it */ - if (df_poison && umc_poison) - con->poison_supported = true; - else if (df_poison != umc_poison) - dev_warn(adev->dev, "Poison setting is inconsistent in DF/UMC(%d:%d)!\n", - df_poison, umc_poison); - } + amdgpu_ras_query_poison_mode(adev); if (amdgpu_ras_fs_init(adev)) { r = -EINVAL; @@ -2564,6 +2633,7 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev, { struct amdgpu_ras_block_object *ras_obj = NULL; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + struct ras_query_if *query_info; unsigned long ue_count, ce_count; int r; @@ -2605,11 +2675,17 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev, /* Those are the cached values at init. */ - if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count) == 0) { + query_info = kzalloc(sizeof(struct ras_query_if), GFP_KERNEL); + if (!query_info) + return -ENOMEM; + memcpy(&query_info->head, ras_block, sizeof(struct ras_common_if)); + + if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count, query_info) == 0) { atomic_set(&con->ras_ce_count, ce_count); atomic_set(&con->ras_ue_count, ue_count); } + kfree(query_info); return 0; interrupt: @@ -2946,11 +3022,26 @@ int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_co int amdgpu_ras_is_supported(struct amdgpu_device *adev, unsigned int block) { + int ret = 0; struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); if (block >= AMDGPU_RAS_BLOCK_COUNT) return 0; - return ras && (adev->ras_enabled & (1 << block)); + + ret = ras && (adev->ras_enabled & (1 << block)); + + /* For the special asic with mem ecc enabled but sram ecc + * not enabled, even if the ras block is not supported on + * .ras_enabled, if the asic supports poison mode and the + * ras block has ras configuration, it can be considered + * that the ras block supports ras function. + */ + if (!ret && + amdgpu_ras_is_poison_mode_supported(adev) && + amdgpu_ras_get_ras_block(adev, block, 0)) + ret = 1; + + return ret; } int amdgpu_ras_reset_gpu(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index bf5a95104ec1..f2ad999993f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -540,7 +540,8 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev); int amdgpu_ras_query_error_count(struct amdgpu_device *adev, unsigned long *ce_count, - unsigned long *ue_count); + unsigned long *ue_count, + struct ras_query_if *query_info); /* error handling functions */ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c index 012b72d00e04..85fb730d9fc8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c @@ -93,7 +93,8 @@ int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws) /* allocate save restore block */ r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.rlc.save_restore_obj, &adev->gfx.rlc.save_restore_gpu_addr, (void **)&adev->gfx.rlc.sr_ptr); @@ -130,7 +131,8 @@ int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev) /* allocate clear state block */ adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev); r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.rlc.clear_state_obj, &adev->gfx.rlc.clear_state_gpu_addr, (void **)&adev->gfx.rlc.cs_ptr); @@ -156,7 +158,8 @@ int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev) int r; r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size, - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.rlc.cp_table_obj, &adev->gfx.rlc.cp_table_gpu_addr, (void **)&adev->gfx.rlc.cp_table_ptr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c index ea5278f094c0..231ca06bc9c7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c @@ -154,16 +154,11 @@ int amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev, static int amdgpu_sdma_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst) { - int err = 0; uint16_t version_major; const struct common_firmware_header *header = NULL; const struct sdma_firmware_header_v1_0 *hdr; const struct sdma_firmware_header_v2_0 *hdr_v2; - err = amdgpu_ucode_validate(sdma_inst->fw); - if (err) - return err; - header = (const struct common_firmware_header *) sdma_inst->fw->data; version_major = le16_to_cpu(header->header_version_major); @@ -195,7 +190,7 @@ void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev, int i; for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); + amdgpu_ucode_release(&adev->sdma.instance[i].fw); if (duplicate) break; } @@ -205,16 +200,22 @@ void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev, } int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, - char *fw_name, u32 instance, - bool duplicate) + u32 instance, bool duplicate) { struct amdgpu_firmware_info *info = NULL; const struct common_firmware_header *header = NULL; - int err = 0, i; + int err, i; const struct sdma_firmware_header_v2_0 *sdma_hdr; uint16_t version_major; - - err = request_firmware(&adev->sdma.instance[instance].fw, fw_name, adev->dev); + char ucode_prefix[30]; + char fw_name[40]; + + amdgpu_ucode_ip_version_decode(adev, SDMA0_HWIP, ucode_prefix, sizeof(ucode_prefix)); + if (instance == 0) + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); + else + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s%d.bin", ucode_prefix, instance); + err = amdgpu_ucode_request(adev, &adev->sdma.instance[instance].fw, fw_name); if (err) goto out; @@ -279,10 +280,8 @@ int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, } out: - if (err) { - DRM_ERROR("SDMA: Failed to init firmware \"%s\"\n", fw_name); + if (err) amdgpu_sdma_destroy_inst_ctx(adev, duplicate); - } return err; } @@ -306,3 +305,38 @@ void amdgpu_sdma_unset_buffer_funcs_helper(struct amdgpu_device *adev) } } } + +int amdgpu_sdma_ras_sw_init(struct amdgpu_device *adev) +{ + int err = 0; + struct amdgpu_sdma_ras *ras = NULL; + + /* adev->sdma.ras is NULL, which means sdma does not + * support ras function, then do nothing here. + */ + if (!adev->sdma.ras) + return 0; + + ras = adev->sdma.ras; + + err = amdgpu_ras_register_ras_block(adev, &ras->ras_block); + if (err) { + dev_err(adev->dev, "Failed to register sdma ras block!\n"); + return err; + } + + strcpy(ras->ras_block.ras_comm.name, "sdma"); + ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__SDMA; + ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; + adev->sdma.ras_if = &ras->ras_block.ras_comm; + + /* If not define special ras_late_init function, use default ras_late_init */ + if (!ras->ras_block.ras_late_init) + ras->ras_block.ras_late_init = amdgpu_sdma_ras_late_init; + + /* If not defined special ras_cb function, use default ras_cb */ + if (!ras->ras_block.ras_cb) + ras->ras_block.ras_cb = amdgpu_sdma_process_ras_data_cb; + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h index 7d99205c2e01..fc8528812598 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h @@ -124,10 +124,11 @@ int amdgpu_sdma_process_ras_data_cb(struct amdgpu_device *adev, int amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); -int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, - char *fw_name, u32 instance, bool duplicate); +int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, u32 instance, + bool duplicate); void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev, bool duplicate); void amdgpu_sdma_unset_buffer_funcs_helper(struct amdgpu_device *adev); +int amdgpu_sdma_ras_sw_init(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c index 2c1d82fc4c34..8ed0e073656f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c @@ -77,11 +77,11 @@ void psp_securedisplay_parse_resp_status(struct psp_context *psp, } } -void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct securedisplay_cmd **cmd, +void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct ta_securedisplay_cmd **cmd, enum ta_securedisplay_command command_id) { - *cmd = (struct securedisplay_cmd *)psp->securedisplay_context.context.mem_context.shared_buf; - memset(*cmd, 0, sizeof(struct securedisplay_cmd)); + *cmd = (struct ta_securedisplay_cmd *)psp->securedisplay_context.context.mem_context.shared_buf; + memset(*cmd, 0, sizeof(struct ta_securedisplay_cmd)); (*cmd)->status = TA_SECUREDISPLAY_STATUS__GENERIC_FAILURE; (*cmd)->cmd_id = command_id; } @@ -93,7 +93,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u { struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; struct psp_context *psp = &adev->psp; - struct securedisplay_cmd *securedisplay_cmd; + struct ta_securedisplay_cmd *securedisplay_cmd; struct drm_device *dev = adev_to_drm(adev); uint32_t phy_id; uint32_t op; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h index fe98574748f4..456ad68ed4b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h @@ -30,7 +30,7 @@ void amdgpu_securedisplay_debugfs_init(struct amdgpu_device *adev); void psp_securedisplay_parse_resp_status(struct psp_context *psp, enum ta_securedisplay_status status); -void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct securedisplay_cmd **cmd, +void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct ta_securedisplay_cmd **cmd, enum ta_securedisplay_command command_id); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 677ad2016976..98d91ebf5c26 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -153,10 +153,10 @@ TRACE_EVENT(amdgpu_cs, TP_fast_assign( __entry->bo_list = p->bo_list; - __entry->ring = to_amdgpu_ring(job->base.sched)->idx; + __entry->ring = to_amdgpu_ring(job->base.entity->rq->sched)->idx; __entry->dw = ib->length_dw; __entry->fences = amdgpu_fence_count_emitted( - to_amdgpu_ring(job->base.sched)); + to_amdgpu_ring(job->base.entity->rq->sched)); ), TP_printk("bo_list=%p, ring=%u, dw=%u, fences=%u", __entry->bo_list, __entry->ring, __entry->dw, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 55e0284b2bdd..c5ef7f7bdc15 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -44,10 +44,10 @@ #include <linux/module.h> #include <drm/drm_drv.h> -#include <drm/ttm/ttm_bo_api.h> -#include <drm/ttm/ttm_bo_driver.h> +#include <drm/ttm/ttm_bo.h> #include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_range_manager.h> +#include <drm/ttm/ttm_tt.h> #include <drm/amdgpu_drm.h> #include <drm/drm_drv.h> @@ -1679,10 +1679,10 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) /* reserve vram for mem train according to TMR location */ amdgpu_ttm_training_data_block_init(adev); ret = amdgpu_bo_create_kernel_at(adev, - ctx->c2p_train_data_offset, - ctx->train_data_size, - &ctx->c2p_bo, - NULL); + ctx->c2p_train_data_offset, + ctx->train_data_size, + &ctx->c2p_bo, + NULL); if (ret) { DRM_ERROR("alloc c2p_bo failed(%d)!\n", ret); amdgpu_ttm_training_reserve_vram_fini(adev); @@ -1692,10 +1692,10 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) } ret = amdgpu_bo_create_kernel_at(adev, - adev->gmc.real_vram_size - adev->mman.discovery_tmr_size, - adev->mman.discovery_tmr_size, - &adev->mman.discovery_memory, - NULL); + adev->gmc.real_vram_size - adev->mman.discovery_tmr_size, + adev->mman.discovery_tmr_size, + &adev->mman.discovery_memory, + NULL); if (ret) { DRM_ERROR("alloc tmr failed(%d)!\n", ret); amdgpu_bo_free_kernel(&adev->mman.discovery_memory, NULL, NULL); @@ -1718,7 +1718,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) { uint64_t gtt_size; int r; - u64 vis_vram_limit; mutex_init(&adev->mman.gtt_window_lock); @@ -1741,12 +1740,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } - /* Reduce size of CPU-visible VRAM if requested */ - vis_vram_limit = (u64)amdgpu_vis_vram_limit * 1024 * 1024; - if (amdgpu_vis_vram_limit > 0 && - vis_vram_limit <= adev->gmc.visible_vram_size) - adev->gmc.visible_vram_size = vis_vram_limit; - /* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_set_buffer_funcs_status(adev, false); #ifdef CONFIG_64BIT diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 5cb62e6249c2..380b89114341 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -504,7 +504,7 @@ void amdgpu_ucode_print_gpu_info_hdr(const struct common_firmware_header *hdr) } } -int amdgpu_ucode_validate(const struct firmware *fw) +static int amdgpu_ucode_validate(const struct firmware *fw) { const struct common_firmware_header *hdr = (const struct common_firmware_header *)fw->data; @@ -1059,12 +1059,229 @@ int amdgpu_ucode_init_bo(struct amdgpu_device *adev) return 0; } +static const char *amdgpu_ucode_legacy_naming(struct amdgpu_device *adev, int block_type) +{ + if (block_type == MP0_HWIP) { + switch (adev->ip_versions[MP0_HWIP][0]) { + case IP_VERSION(9, 0, 0): + switch (adev->asic_type) { + case CHIP_VEGA10: + return "vega10"; + case CHIP_VEGA12: + return "vega12"; + default: + return NULL; + } + case IP_VERSION(10, 0, 0): + case IP_VERSION(10, 0, 1): + if (adev->asic_type == CHIP_RAVEN) { + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + return "raven2"; + else if (adev->apu_flags & AMD_APU_IS_PICASSO) + return "picasso"; + return "raven"; + } + break; + case IP_VERSION(11, 0, 0): + return "navi10"; + case IP_VERSION(11, 0, 2): + return "vega20"; + case IP_VERSION(11, 0, 3): + return "renoir"; + case IP_VERSION(11, 0, 4): + return "arcturus"; + case IP_VERSION(11, 0, 5): + return "navi14"; + case IP_VERSION(11, 0, 7): + return "sienna_cichlid"; + case IP_VERSION(11, 0, 9): + return "navi12"; + case IP_VERSION(11, 0, 11): + return "navy_flounder"; + case IP_VERSION(11, 0, 12): + return "dimgrey_cavefish"; + case IP_VERSION(11, 0, 13): + return "beige_goby"; + case IP_VERSION(11, 5, 0): + return "vangogh"; + case IP_VERSION(12, 0, 1): + return "green_sardine"; + case IP_VERSION(13, 0, 2): + return "aldebaran"; + case IP_VERSION(13, 0, 1): + case IP_VERSION(13, 0, 3): + return "yellow_carp"; + } + } else if (block_type == MP1_HWIP) { + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(9, 0, 0): + case IP_VERSION(10, 0, 0): + case IP_VERSION(10, 0, 1): + case IP_VERSION(11, 0, 2): + if (adev->asic_type == CHIP_ARCTURUS) + return "arcturus_smc"; + return NULL; + case IP_VERSION(11, 0, 0): + return "navi10_smc"; + case IP_VERSION(11, 0, 5): + return "navi14_smc"; + case IP_VERSION(11, 0, 9): + return "navi12_smc"; + case IP_VERSION(11, 0, 7): + return "sienna_cichlid_smc"; + case IP_VERSION(11, 0, 11): + return "navy_flounder_smc"; + case IP_VERSION(11, 0, 12): + return "dimgrey_cavefish_smc"; + case IP_VERSION(11, 0, 13): + return "beige_goby_smc"; + case IP_VERSION(13, 0, 2): + return "aldebaran_smc"; + } + } else if (block_type == SDMA0_HWIP) { + switch (adev->ip_versions[SDMA0_HWIP][0]) { + case IP_VERSION(4, 0, 0): + return "vega10_sdma"; + case IP_VERSION(4, 0, 1): + return "vega12_sdma"; + case IP_VERSION(4, 1, 0): + case IP_VERSION(4, 1, 1): + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + return "raven2_sdma"; + else if (adev->apu_flags & AMD_APU_IS_PICASSO) + return "picasso_sdma"; + return "raven_sdma"; + case IP_VERSION(4, 1, 2): + if (adev->apu_flags & AMD_APU_IS_RENOIR) + return "renoir_sdma"; + return "green_sardine_sdma"; + case IP_VERSION(4, 2, 0): + return "vega20_sdma"; + case IP_VERSION(4, 2, 2): + return "arcturus_sdma"; + case IP_VERSION(4, 4, 0): + return "aldebaran_sdma"; + case IP_VERSION(5, 0, 0): + return "navi10_sdma"; + case IP_VERSION(5, 0, 1): + return "cyan_skillfish2_sdma"; + case IP_VERSION(5, 0, 2): + return "navi14_sdma"; + case IP_VERSION(5, 0, 5): + return "navi12_sdma"; + case IP_VERSION(5, 2, 0): + return "sienna_cichlid_sdma"; + case IP_VERSION(5, 2, 2): + return "navy_flounder_sdma"; + case IP_VERSION(5, 2, 4): + return "dimgrey_cavefish_sdma"; + case IP_VERSION(5, 2, 5): + return "beige_goby_sdma"; + case IP_VERSION(5, 2, 3): + return "yellow_carp_sdma"; + case IP_VERSION(5, 2, 1): + return "vangogh_sdma"; + } + } else if (block_type == UVD_HWIP) { + switch (adev->ip_versions[UVD_HWIP][0]) { + case IP_VERSION(1, 0, 0): + case IP_VERSION(1, 0, 1): + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + return "raven2_vcn"; + else if (adev->apu_flags & AMD_APU_IS_PICASSO) + return "picasso_vcn"; + return "raven_vcn"; + case IP_VERSION(2, 5, 0): + return "arcturus_vcn"; + case IP_VERSION(2, 2, 0): + if (adev->apu_flags & AMD_APU_IS_RENOIR) + return "renoir_vcn"; + return "green_sardine_vcn"; + case IP_VERSION(2, 6, 0): + return "aldebaran_vcn"; + case IP_VERSION(2, 0, 0): + return "navi10_vcn"; + case IP_VERSION(2, 0, 2): + if (adev->asic_type == CHIP_NAVI12) + return "navi12_vcn"; + return "navi14_vcn"; + case IP_VERSION(3, 0, 0): + case IP_VERSION(3, 0, 64): + case IP_VERSION(3, 0, 192): + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0)) + return "sienna_cichlid_vcn"; + return "navy_flounder_vcn"; + case IP_VERSION(3, 0, 2): + return "vangogh_vcn"; + case IP_VERSION(3, 0, 16): + return "dimgrey_cavefish_vcn"; + case IP_VERSION(3, 0, 33): + return "beige_goby_vcn"; + case IP_VERSION(3, 1, 1): + return "yellow_carp_vcn"; + } + } else if (block_type == GC_HWIP) { + switch (adev->ip_versions[GC_HWIP][0]) { + case IP_VERSION(9, 0, 1): + return "vega10"; + case IP_VERSION(9, 2, 1): + return "vega12"; + case IP_VERSION(9, 4, 0): + return "vega20"; + case IP_VERSION(9, 2, 2): + case IP_VERSION(9, 1, 0): + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + return "raven2"; + else if (adev->apu_flags & AMD_APU_IS_PICASSO) + return "picasso"; + return "raven"; + case IP_VERSION(9, 4, 1): + return "arcturus"; + case IP_VERSION(9, 3, 0): + if (adev->apu_flags & AMD_APU_IS_RENOIR) + return "renoir"; + return "green_sardine"; + case IP_VERSION(9, 4, 2): + return "aldebaran"; + case IP_VERSION(10, 1, 10): + return "navi10"; + case IP_VERSION(10, 1, 1): + return "navi14"; + case IP_VERSION(10, 1, 2): + return "navi12"; + case IP_VERSION(10, 3, 0): + return "sienna_cichlid"; + case IP_VERSION(10, 3, 2): + return "navy_flounder"; + case IP_VERSION(10, 3, 1): + return "vangogh"; + case IP_VERSION(10, 3, 4): + return "dimgrey_cavefish"; + case IP_VERSION(10, 3, 5): + return "beige_goby"; + case IP_VERSION(10, 3, 3): + return "yellow_carp"; + case IP_VERSION(10, 1, 3): + case IP_VERSION(10, 1, 4): + return "cyan_skillfish2"; + } + } + return NULL; +} + void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type, char *ucode_prefix, int len) { int maj, min, rev; char *ip_name; + const char *legacy; uint32_t version = adev->ip_versions[block_type][0]; + legacy = amdgpu_ucode_legacy_naming(adev, block_type); + if (legacy) { + snprintf(ucode_prefix, len, "%s", legacy); + return; + } + switch (block_type) { case GC_HWIP: ip_name = "gc"; @@ -1091,3 +1308,39 @@ void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type, snprintf(ucode_prefix, len, "%s_%d_%d_%d", ip_name, maj, min, rev); } + +/* + * amdgpu_ucode_request - Fetch and validate amdgpu microcode + * + * @adev: amdgpu device + * @fw: pointer to load firmware to + * @fw_name: firmware to load + * + * This is a helper that will use request_firmware and amdgpu_ucode_validate + * to load and run basic validation on firmware. If the load fails, remap + * the error code to -ENODEV, so that early_init functions will fail to load. + */ +int amdgpu_ucode_request(struct amdgpu_device *adev, const struct firmware **fw, + const char *fw_name) +{ + int err = request_firmware(fw, fw_name, adev->dev); + + if (err) + return -ENODEV; + err = amdgpu_ucode_validate(*fw); + if (err) + dev_dbg(adev->dev, "\"%s\" failed to validate\n", fw_name); + + return err; +} + +/* + * amdgpu_ucode_release - Release firmware microcode + * + * @fw: pointer to firmware to release + */ +void amdgpu_ucode_release(const struct firmware **fw) +{ + release_firmware(*fw); + *fw = NULL; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 552e06929229..bee93ab4298f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -543,7 +543,9 @@ void amdgpu_ucode_print_rlc_hdr(const struct common_firmware_header *hdr); void amdgpu_ucode_print_sdma_hdr(const struct common_firmware_header *hdr); void amdgpu_ucode_print_psp_hdr(const struct common_firmware_header *hdr); void amdgpu_ucode_print_gpu_info_hdr(const struct common_firmware_header *hdr); -int amdgpu_ucode_validate(const struct firmware *fw); +int amdgpu_ucode_request(struct amdgpu_device *adev, const struct firmware **fw, + const char *fw_name); +void amdgpu_ucode_release(const struct firmware **fw); bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr, uint16_t hdr_major, uint16_t hdr_minor); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index f76c19fc0392..1c7fcb4f2380 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -169,25 +169,33 @@ int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset) { int ret = AMDGPU_RAS_SUCCESS; - if (!adev->gmc.xgmi.connected_to_cpu) { - struct ras_err_data err_data = {0, 0, 0, NULL}; - struct ras_common_if head = { - .block = AMDGPU_RAS_BLOCK__UMC, - }; - struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); - - ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset); - - if (ret == AMDGPU_RAS_SUCCESS && obj) { - obj->err_data.ue_count += err_data.ue_count; - obj->err_data.ce_count += err_data.ce_count; + if (!amdgpu_sriov_vf(adev)) { + if (!adev->gmc.xgmi.connected_to_cpu) { + struct ras_err_data err_data = {0, 0, 0, NULL}; + struct ras_common_if head = { + .block = AMDGPU_RAS_BLOCK__UMC, + }; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); + + ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset); + + if (ret == AMDGPU_RAS_SUCCESS && obj) { + obj->err_data.ue_count += err_data.ue_count; + obj->err_data.ce_count += err_data.ce_count; + } + } else if (reset) { + /* MCA poison handler is only responsible for GPU reset, + * let MCA notifier do page retirement. + */ + kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); + amdgpu_ras_reset_gpu(adev); } - } else if (reset) { - /* MCA poison handler is only responsible for GPU reset, - * let MCA notifier do page retirement. - */ - kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); - amdgpu_ras_reset_gpu(adev); + } else { + if (adev->virt.ops && adev->virt.ops->ras_poison_handler) + adev->virt.ops->ras_poison_handler(adev); + else + dev_warn(adev->dev, + "No ras_poison_handler interface in SRIOV!\n"); } return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index e00bb654e24b..632a6ded5735 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -260,19 +260,11 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) return -EINVAL; } - r = request_firmware(&adev->uvd.fw, fw_name, adev->dev); - if (r) { - dev_err(adev->dev, "amdgpu_uvd: Can't load firmware \"%s\"\n", - fw_name); - return r; - } - - r = amdgpu_ucode_validate(adev->uvd.fw); + r = amdgpu_ucode_request(adev, &adev->uvd.fw, fw_name); if (r) { dev_err(adev->dev, "amdgpu_uvd: Can't validate firmware \"%s\"\n", fw_name); - release_firmware(adev->uvd.fw); - adev->uvd.fw = NULL; + amdgpu_ucode_release(&adev->uvd.fw); return r; } @@ -331,8 +323,11 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) if (adev->uvd.harvest_config & (1 << j)) continue; r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.inst[j].vcpu_bo, - &adev->uvd.inst[j].gpu_addr, &adev->uvd.inst[j].cpu_addr); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->uvd.inst[j].vcpu_bo, + &adev->uvd.inst[j].gpu_addr, + &adev->uvd.inst[j].cpu_addr); if (r) { dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r); return r; @@ -394,7 +389,7 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]); } amdgpu_bo_free_kernel(&adev->uvd.ib_bo, NULL, &addr); - release_firmware(adev->uvd.fw); + amdgpu_ucode_release(&adev->uvd.fw); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index b239e874f2d5..2fb61410b1c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -158,19 +158,11 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) return -EINVAL; } - r = request_firmware(&adev->vce.fw, fw_name, adev->dev); - if (r) { - dev_err(adev->dev, "amdgpu_vce: Can't load firmware \"%s\"\n", - fw_name); - return r; - } - - r = amdgpu_ucode_validate(adev->vce.fw); + r = amdgpu_ucode_request(adev, &adev->vce.fw, fw_name); if (r) { dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n", fw_name); - release_firmware(adev->vce.fw); - adev->vce.fw = NULL; + amdgpu_ucode_release(&adev->vce.fw); return r; } @@ -186,7 +178,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) (binary_id << 8)); r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &adev->vce.vcpu_bo, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->vce.vcpu_bo, &adev->vce.gpu_addr, &adev->vce.cpu_addr); if (r) { dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r); @@ -226,7 +220,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) for (i = 0; i < adev->vce.num_rings; i++) amdgpu_ring_fini(&adev->vce.ring[i]); - release_firmware(adev->vce.fw); + amdgpu_ucode_release(&adev->vce.fw); mutex_destroy(&adev->vce.idle_mutex); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index b1622ac9949f..25217b05c0ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -36,26 +36,26 @@ #include "soc15d.h" /* Firmware Names */ -#define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin" -#define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin" -#define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin" -#define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin" -#define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin" -#define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin" -#define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin" -#define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin" -#define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin" -#define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin" -#define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin" -#define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin" +#define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin" +#define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin" +#define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin" +#define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin" +#define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin" +#define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin" +#define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin" +#define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin" +#define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin" +#define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin" +#define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin" +#define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin" #define FIRMWARE_DIMGREY_CAVEFISH "amdgpu/dimgrey_cavefish_vcn.bin" -#define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin" -#define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin" -#define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin" -#define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin" -#define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin" -#define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin" -#define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin" +#define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin" +#define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin" +#define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin" +#define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin" +#define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin" +#define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin" +#define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN); MODULE_FIRMWARE(FIRMWARE_PICASSO); @@ -80,10 +80,24 @@ MODULE_FIRMWARE(FIRMWARE_VCN4_0_4); static void amdgpu_vcn_idle_work_handler(struct work_struct *work); +int amdgpu_vcn_early_init(struct amdgpu_device *adev) +{ + char ucode_prefix[30]; + char fw_name[40]; + int r; + + amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix)); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); + r = amdgpu_ucode_request(adev, &adev->vcn.fw, fw_name); + if (r) + amdgpu_ucode_release(&adev->vcn.fw); + + return r; +} + int amdgpu_vcn_sw_init(struct amdgpu_device *adev) { unsigned long bo_size; - const char *fw_name; const struct common_firmware_header *hdr; unsigned char fw_check; unsigned int fw_shared_size, log_offset; @@ -96,131 +110,9 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) for (i = 0; i < adev->vcn.num_vcn_inst; i++) atomic_set(&adev->vcn.inst[i].dpg_enc_submission_cnt, 0); - switch (adev->ip_versions[UVD_HWIP][0]) { - case IP_VERSION(1, 0, 0): - case IP_VERSION(1, 0, 1): - if (adev->apu_flags & AMD_APU_IS_RAVEN2) - fw_name = FIRMWARE_RAVEN2; - else if (adev->apu_flags & AMD_APU_IS_PICASSO) - fw_name = FIRMWARE_PICASSO; - else - fw_name = FIRMWARE_RAVEN; - break; - case IP_VERSION(2, 5, 0): - fw_name = FIRMWARE_ARCTURUS; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(2, 2, 0): - if (adev->apu_flags & AMD_APU_IS_RENOIR) - fw_name = FIRMWARE_RENOIR; - else - fw_name = FIRMWARE_GREEN_SARDINE; - - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(2, 6, 0): - fw_name = FIRMWARE_ALDEBARAN; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(2, 0, 0): - fw_name = FIRMWARE_NAVI10; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(2, 0, 2): - if (adev->asic_type == CHIP_NAVI12) - fw_name = FIRMWARE_NAVI12; - else - fw_name = FIRMWARE_NAVI14; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(3, 0, 0): - case IP_VERSION(3, 0, 64): - case IP_VERSION(3, 0, 192): - if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0)) - fw_name = FIRMWARE_SIENNA_CICHLID; - else - fw_name = FIRMWARE_NAVY_FLOUNDER; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(3, 0, 2): - fw_name = FIRMWARE_VANGOGH; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(3, 0, 16): - fw_name = FIRMWARE_DIMGREY_CAVEFISH; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(3, 0, 33): - fw_name = FIRMWARE_BEIGE_GOBY; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(3, 1, 1): - fw_name = FIRMWARE_YELLOW_CARP; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(3, 1, 2): - fw_name = FIRMWARE_VCN_3_1_2; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(4, 0, 0): - fw_name = FIRMWARE_VCN4_0_0; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(4, 0, 2): - fw_name = FIRMWARE_VCN4_0_2; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - case IP_VERSION(4, 0, 4): - fw_name = FIRMWARE_VCN4_0_4; - if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && - (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) - adev->vcn.indirect_sram = true; - break; - default: - return -EINVAL; - } - - r = request_firmware(&adev->vcn.fw, fw_name, adev->dev); - if (r) { - dev_err(adev->dev, "amdgpu_vcn: Can't load firmware \"%s\"\n", - fw_name); - return r; - } - - r = amdgpu_ucode_validate(adev->vcn.fw); - if (r) { - dev_err(adev->dev, "amdgpu_vcn: Can't validate firmware \"%s\"\n", - fw_name); - release_firmware(adev->vcn.fw); - adev->vcn.fw = NULL; - return r; - } + if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) && + (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)) + adev->vcn.indirect_sram = true; hdr = (const struct common_firmware_header *)adev->vcn.fw->data; adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version); @@ -274,8 +166,11 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) continue; r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &adev->vcn.inst[i].vcpu_bo, - &adev->vcn.inst[i].gpu_addr, &adev->vcn.inst[i].cpu_addr); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->vcn.inst[i].vcpu_bo, + &adev->vcn.inst[i].gpu_addr, + &adev->vcn.inst[i].cpu_addr); if (r) { dev_err(adev->dev, "(%d) failed to allocate vcn bo\n", r); return r; @@ -296,8 +191,11 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) if (adev->vcn.indirect_sram) { r = amdgpu_bo_create_kernel(adev, 64 * 2 * 4, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &adev->vcn.inst[i].dpg_sram_bo, - &adev->vcn.inst[i].dpg_sram_gpu_addr, &adev->vcn.inst[i].dpg_sram_cpu_addr); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->vcn.inst[i].dpg_sram_bo, + &adev->vcn.inst[i].dpg_sram_gpu_addr, + &adev->vcn.inst[i].dpg_sram_cpu_addr); if (r) { dev_err(adev->dev, "VCN %d (%d) failed to allocate DPG bo\n", i, r); return r; @@ -333,7 +231,7 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) amdgpu_ring_fini(&adev->vcn.inst[j].ring_enc[i]); } - release_firmware(adev->vcn.fw); + amdgpu_ucode_release(&adev->vcn.fw); mutex_destroy(&adev->vcn.vcn1_jpeg1_workaround); mutex_destroy(&adev->vcn.vcn_pg_lock); @@ -1250,8 +1148,16 @@ int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev, if (!ras_if) return 0; - ih_data.head = *ras_if; - amdgpu_ras_interrupt_dispatch(adev, &ih_data); + if (!amdgpu_sriov_vf(adev)) { + ih_data.head = *ras_if; + amdgpu_ras_interrupt_dispatch(adev, &ih_data); + } else { + if (adev->virt.ops && adev->virt.ops->ras_poison_handler) + adev->virt.ops->ras_poison_handler(adev); + else + dev_warn(adev->dev, + "No ras_poison_handler interface in SRIOV for VCN!\n"); + } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index dbb8d68a30c6..d3e2af902907 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -369,6 +369,7 @@ enum vcn_ring_type { VCN_UNIFIED_RING, }; +int amdgpu_vcn_early_init(struct amdgpu_device *adev); int amdgpu_vcn_sw_init(struct amdgpu_device *adev); int amdgpu_vcn_sw_fini(struct amdgpu_device *adev); int amdgpu_vcn_suspend(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 2994b9db196f..f39391e03d46 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -232,7 +232,8 @@ int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev) return 0; r = amdgpu_bo_create_kernel(adev, PAGE_SIZE, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->virt.mm_table.bo, &adev->virt.mm_table.gpu_addr, (void *)&adev->virt.mm_table.cpu_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index 2b9d806e23af..b9e9480448af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -88,6 +88,7 @@ struct amdgpu_virt_ops { int (*wait_reset)(struct amdgpu_device *adev); void (*trans_msg)(struct amdgpu_device *adev, enum idh_request req, u32 data1, u32 data2, u32 data3); + void (*ras_poison_handler)(struct amdgpu_device *adev); }; /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index dc379dc22c77..b9441ab457ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -33,6 +33,7 @@ #include <drm/amdgpu_drm.h> #include <drm/drm_drv.h> +#include <drm/ttm/ttm_tt.h> #include "amdgpu.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 094bb4807303..856a64bc7a89 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -29,7 +29,7 @@ #include <linux/rbtree.h> #include <drm/gpu_scheduler.h> #include <drm/drm_file.h> -#include <drm/ttm/ttm_bo_driver.h> +#include <drm/ttm/ttm_bo.h> #include <linux/sched/mm.h> #include "amdgpu_sync.h" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index faa12146635c..9fa1d814508a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -882,7 +882,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) kfree(rsv); list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) { - drm_buddy_free_list(&mgr->mm, &rsv->blocks); + drm_buddy_free_list(&mgr->mm, &rsv->allocated); kfree(rsv); } drm_buddy_fini(&mgr->mm); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 4b9e7b050ccd..4340d08f7607 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -29,13 +29,16 @@ #include "df/df_3_6_offset.h" #include "xgmi/xgmi_4_0_0_smn.h" #include "xgmi/xgmi_4_0_0_sh_mask.h" +#include "xgmi/xgmi_6_1_0_sh_mask.h" #include "wafl/wafl2_4_0_0_smn.h" #include "wafl/wafl2_4_0_0_sh_mask.h" #include "amdgpu_reset.h" #define smnPCS_XGMI3X16_PCS_ERROR_STATUS 0x11a0020c +#define smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK 0x11a00218 #define smnPCS_GOPX1_PCS_ERROR_STATUS 0x12200210 +#define smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK 0x12200218 static DEFINE_MUTEX(xgmi_mutex); @@ -79,11 +82,27 @@ static const int xgmi3x16_pcs_err_status_reg_aldebaran[] = { smnPCS_XGMI3X16_PCS_ERROR_STATUS + 0x700000 }; +static const int xgmi3x16_pcs_err_noncorrectable_mask_reg_aldebaran[] = { + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x200000, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x300000, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x400000, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x500000, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x600000, + smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x700000 +}; + static const int walf_pcs_err_status_reg_aldebaran[] = { smnPCS_GOPX1_PCS_ERROR_STATUS, smnPCS_GOPX1_PCS_ERROR_STATUS + 0x100000 }; +static const int walf_pcs_err_noncorrectable_mask_reg_aldebaran[] = { + smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK, + smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000 +}; + static const struct amdgpu_pcs_ras_field xgmi_pcs_ras_fields[] = { {"XGMI PCS DataLossErr", SOC15_REG_FIELD(XGMI0_PCS_GOPX16_PCS_ERROR_STATUS, DataLossErr)}, @@ -162,6 +181,67 @@ static const struct amdgpu_pcs_ras_field wafl_pcs_ras_fields[] = { SOC15_REG_FIELD(PCS_GOPX1_0_PCS_GOPX1_PCS_ERROR_STATUS, RecoveryRelockAttemptErr)}, }; +static const struct amdgpu_pcs_ras_field xgmi3x16_pcs_ras_fields[] = { + {"XGMI3X16 PCS DataLossErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DataLossErr)}, + {"XGMI3X16 PCS TrainingErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, TrainingErr)}, + {"XGMI3X16 PCS FlowCtrlAckErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, FlowCtrlAckErr)}, + {"XGMI3X16 PCS RxFifoUnderflowErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxFifoUnderflowErr)}, + {"XGMI3X16 PCS RxFifoOverflowErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxFifoOverflowErr)}, + {"XGMI3X16 PCS CRCErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, CRCErr)}, + {"XGMI3X16 PCS BERExceededErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, BERExceededErr)}, + {"XGMI3X16 PCS TxVcidDataErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, TxVcidDataErr)}, + {"XGMI3X16 PCS ReplayBufParityErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayBufParityErr)}, + {"XGMI3X16 PCS DataParityErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DataParityErr)}, + {"XGMI3X16 PCS ReplayFifoOverflowErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayFifoOverflowErr)}, + {"XGMI3X16 PCS ReplayFifoUnderflowErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayFifoUnderflowErr)}, + {"XGMI3X16 PCS ElasticFifoOverflowErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ElasticFifoOverflowErr)}, + {"XGMI3X16 PCS DeskewErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DeskewErr)}, + {"XGMI3X16 PCS FlowCtrlCRCErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, FlowCtrlCRCErr)}, + {"XGMI3X16 PCS DataStartupLimitErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DataStartupLimitErr)}, + {"XGMI3X16 PCS FCInitTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, FCInitTimeoutErr)}, + {"XGMI3X16 PCS RecoveryTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RecoveryTimeoutErr)}, + {"XGMI3X16 PCS ReadySerialTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReadySerialTimeoutErr)}, + {"XGMI3X16 PCS ReadySerialAttemptErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReadySerialAttemptErr)}, + {"XGMI3X16 PCS RecoveryAttemptErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RecoveryAttemptErr)}, + {"XGMI3X16 PCS RecoveryRelockAttemptErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RecoveryRelockAttemptErr)}, + {"XGMI3X16 PCS ReplayAttemptErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayAttemptErr)}, + {"XGMI3X16 PCS SyncHdrErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, SyncHdrErr)}, + {"XGMI3X16 PCS TxReplayTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, TxReplayTimeoutErr)}, + {"XGMI3X16 PCS RxReplayTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxReplayTimeoutErr)}, + {"XGMI3X16 PCS LinkSubTxTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, LinkSubTxTimeoutErr)}, + {"XGMI3X16 PCS LinkSubRxTimeoutErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, LinkSubRxTimeoutErr)}, + {"XGMI3X16 PCS RxCMDPktErr", + SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxCMDPktErr)}, +}; + /** * DOC: AMDGPU XGMI Support * @@ -809,39 +889,47 @@ static void amdgpu_xgmi_reset_ras_error_count(struct amdgpu_device *adev) static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev, uint32_t value, + uint32_t mask_value, uint32_t *ue_count, uint32_t *ce_count, - bool is_xgmi_pcs) + bool is_xgmi_pcs, + bool check_mask) { int i; - int ue_cnt; + int ue_cnt = 0; + const struct amdgpu_pcs_ras_field *pcs_ras_fields = NULL; + uint32_t field_array_size = 0; if (is_xgmi_pcs) { - /* query xgmi pcs error status, - * only ue is supported */ - for (i = 0; i < ARRAY_SIZE(xgmi_pcs_ras_fields); i ++) { - ue_cnt = (value & - xgmi_pcs_ras_fields[i].pcs_err_mask) >> - xgmi_pcs_ras_fields[i].pcs_err_shift; - if (ue_cnt) { - dev_info(adev->dev, "%s detected\n", - xgmi_pcs_ras_fields[i].err_name); - *ue_count += ue_cnt; - } + if (adev->ip_versions[XGMI_HWIP][0] == IP_VERSION(6, 1, 0)) { + pcs_ras_fields = &xgmi3x16_pcs_ras_fields[0]; + field_array_size = ARRAY_SIZE(xgmi3x16_pcs_ras_fields); + } else { + pcs_ras_fields = &xgmi_pcs_ras_fields[0]; + field_array_size = ARRAY_SIZE(xgmi_pcs_ras_fields); } } else { - /* query wafl pcs error status, - * only ue is supported */ - for (i = 0; i < ARRAY_SIZE(wafl_pcs_ras_fields); i++) { - ue_cnt = (value & - wafl_pcs_ras_fields[i].pcs_err_mask) >> - wafl_pcs_ras_fields[i].pcs_err_shift; - if (ue_cnt) { - dev_info(adev->dev, "%s detected\n", - wafl_pcs_ras_fields[i].err_name); - *ue_count += ue_cnt; - } + pcs_ras_fields = &wafl_pcs_ras_fields[0]; + field_array_size = ARRAY_SIZE(wafl_pcs_ras_fields); + } + + if (check_mask) + value = value & ~mask_value; + + /* query xgmi/walf pcs error status, + * only ue is supported */ + for (i = 0; value && i < field_array_size; i++) { + ue_cnt = (value & + pcs_ras_fields[i].pcs_err_mask) >> + pcs_ras_fields[i].pcs_err_shift; + if (ue_cnt) { + dev_info(adev->dev, "%s detected\n", + pcs_ras_fields[i].err_name); + *ue_count += ue_cnt; } + + /* reset bit value if the bit is checked */ + value &= ~(pcs_ras_fields[i].pcs_err_mask); } return 0; @@ -852,7 +940,7 @@ static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev, { struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; int i; - uint32_t data; + uint32_t data, mask_data = 0; uint32_t ue_cnt = 0, ce_cnt = 0; if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL)) @@ -867,15 +955,15 @@ static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev, for (i = 0; i < ARRAY_SIZE(xgmi_pcs_err_status_reg_arct); i++) { data = RREG32_PCIE(xgmi_pcs_err_status_reg_arct[i]); if (data) - amdgpu_xgmi_query_pcs_error_status(adev, - data, &ue_cnt, &ce_cnt, true); + amdgpu_xgmi_query_pcs_error_status(adev, data, + mask_data, &ue_cnt, &ce_cnt, true, false); } /* check wafl pcs error */ for (i = 0; i < ARRAY_SIZE(wafl_pcs_err_status_reg_arct); i++) { data = RREG32_PCIE(wafl_pcs_err_status_reg_arct[i]); if (data) - amdgpu_xgmi_query_pcs_error_status(adev, - data, &ue_cnt, &ce_cnt, false); + amdgpu_xgmi_query_pcs_error_status(adev, data, + mask_data, &ue_cnt, &ce_cnt, false, false); } break; case CHIP_VEGA20: @@ -883,31 +971,35 @@ static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev, for (i = 0; i < ARRAY_SIZE(xgmi_pcs_err_status_reg_vg20); i++) { data = RREG32_PCIE(xgmi_pcs_err_status_reg_vg20[i]); if (data) - amdgpu_xgmi_query_pcs_error_status(adev, - data, &ue_cnt, &ce_cnt, true); + amdgpu_xgmi_query_pcs_error_status(adev, data, + mask_data, &ue_cnt, &ce_cnt, true, false); } /* check wafl pcs error */ for (i = 0; i < ARRAY_SIZE(wafl_pcs_err_status_reg_vg20); i++) { data = RREG32_PCIE(wafl_pcs_err_status_reg_vg20[i]); if (data) - amdgpu_xgmi_query_pcs_error_status(adev, - data, &ue_cnt, &ce_cnt, false); + amdgpu_xgmi_query_pcs_error_status(adev, data, + mask_data, &ue_cnt, &ce_cnt, false, false); } break; case CHIP_ALDEBARAN: /* check xgmi3x16 pcs error */ for (i = 0; i < ARRAY_SIZE(xgmi3x16_pcs_err_status_reg_aldebaran); i++) { data = RREG32_PCIE(xgmi3x16_pcs_err_status_reg_aldebaran[i]); + mask_data = + RREG32_PCIE(xgmi3x16_pcs_err_noncorrectable_mask_reg_aldebaran[i]); if (data) - amdgpu_xgmi_query_pcs_error_status(adev, - data, &ue_cnt, &ce_cnt, true); + amdgpu_xgmi_query_pcs_error_status(adev, data, + mask_data, &ue_cnt, &ce_cnt, true, true); } /* check wafl pcs error */ for (i = 0; i < ARRAY_SIZE(walf_pcs_err_status_reg_aldebaran); i++) { data = RREG32_PCIE(walf_pcs_err_status_reg_aldebaran[i]); + mask_data = + RREG32_PCIE(walf_pcs_err_noncorrectable_mask_reg_aldebaran[i]); if (data) - amdgpu_xgmi_query_pcs_error_status(adev, - data, &ue_cnt, &ce_cnt, false); + amdgpu_xgmi_query_pcs_error_status(adev, data, + mask_data, &ue_cnt, &ce_cnt, false, true); } break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c index afad094f84c2..10098fdd33fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c @@ -24,7 +24,6 @@ * Alex Deucher */ -#include <drm/drm_crtc_helper.h> #include <drm/amdgpu_drm.h> #include <drm/drm_fixed.h> #include "amdgpu.h" diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index 18ae9433e463..d95b2dc78063 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -28,7 +28,6 @@ #include <acpi/video.h> -#include <drm/drm_crtc_helper.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" #include "amdgpu_connectors.h" diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index cbca9866645c..67d16236b216 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -73,10 +73,9 @@ u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev); static void cik_sdma_free_microcode(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ucode_release(&adev->sdma.instance[i].fw); } /* @@ -137,18 +136,15 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->sdma.instance[i].fw, fw_name); if (err) goto out; - err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); } out: if (err) { pr_err("cik_sdma: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ucode_release(&adev->sdma.instance[i].fw); } return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 248f1a4e915f..9a24ed463abd 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -21,8 +21,9 @@ * */ -#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_modeset_helper.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_vblank.h> #include "amdgpu.h" @@ -2837,7 +2838,7 @@ static int dce_v10_0_sw_init(void *handle) if (r) return r; - INIT_WORK(&adev->hotplug_work, + INIT_DELAYED_WORK(&adev->hotplug_work, amdgpu_display_hotplug_work_func); drm_kms_helper_poll_init(adev_to_drm(adev)); @@ -2902,7 +2903,7 @@ static int dce_v10_0_hw_fini(void *handle) dce_v10_0_pageflip_interrupt_fini(adev); - flush_work(&adev->hotplug_work); + flush_delayed_work(&adev->hotplug_work); return 0; } @@ -3302,7 +3303,7 @@ static int dce_v10_0_hpd_irq(struct amdgpu_device *adev, if (disp_int & mask) { dce_v10_0_hpd_int_ack(adev, hpd); - schedule_work(&adev->hotplug_work); + schedule_delayed_work(&adev->hotplug_work, 0); DRM_DEBUG("IH: HPD%d\n", hpd + 1); } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index cd9c19060d89..c14b70350a51 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -21,8 +21,9 @@ * */ -#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_modeset_helper.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_vblank.h> #include "amdgpu.h" @@ -2956,7 +2957,7 @@ static int dce_v11_0_sw_init(void *handle) if (r) return r; - INIT_WORK(&adev->hotplug_work, + INIT_DELAYED_WORK(&adev->hotplug_work, amdgpu_display_hotplug_work_func); drm_kms_helper_poll_init(adev_to_drm(adev)); @@ -3032,7 +3033,7 @@ static int dce_v11_0_hw_fini(void *handle) dce_v11_0_pageflip_interrupt_fini(adev); - flush_work(&adev->hotplug_work); + flush_delayed_work(&adev->hotplug_work); return 0; } @@ -3426,7 +3427,7 @@ static int dce_v11_0_hpd_irq(struct amdgpu_device *adev, if (disp_int & mask) { dce_v11_0_hpd_int_ack(adev, hpd); - schedule_work(&adev->hotplug_work); + schedule_delayed_work(&adev->hotplug_work, 0); DRM_DEBUG("IH: HPD%d\n", hpd + 1); } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 76323deecc58..7f85ba5b726f 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -23,8 +23,9 @@ #include <linux/pci.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_modeset_helper.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_vblank.h> #include "amdgpu.h" @@ -2715,7 +2716,7 @@ static int dce_v6_0_sw_init(void *handle) return r; /* Pre-DCE11 */ - INIT_WORK(&adev->hotplug_work, + INIT_DELAYED_WORK(&adev->hotplug_work, amdgpu_display_hotplug_work_func); drm_kms_helper_poll_init(adev_to_drm(adev)); @@ -2776,7 +2777,7 @@ static int dce_v6_0_hw_fini(void *handle) dce_v6_0_pageflip_interrupt_fini(adev); - flush_work(&adev->hotplug_work); + flush_delayed_work(&adev->hotplug_work); return 0; } @@ -3103,7 +3104,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]); tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); - schedule_work(&adev->hotplug_work); + schedule_delayed_work(&adev->hotplug_work, 0); DRM_DEBUG("IH: HPD%d\n", hpd + 1); } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 01cf3ab111cb..d421a268c9ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -21,8 +21,9 @@ * */ -#include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_modeset_helper.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_vblank.h> #include "amdgpu.h" @@ -2739,7 +2740,7 @@ static int dce_v8_0_sw_init(void *handle) return r; /* Pre-DCE11 */ - INIT_WORK(&adev->hotplug_work, + INIT_DELAYED_WORK(&adev->hotplug_work, amdgpu_display_hotplug_work_func); drm_kms_helper_poll_init(adev_to_drm(adev)); @@ -2802,7 +2803,7 @@ static int dce_v8_0_hw_fini(void *handle) dce_v8_0_pageflip_interrupt_fini(adev); - flush_work(&adev->hotplug_work); + flush_delayed_work(&adev->hotplug_work); return 0; } @@ -3195,7 +3196,7 @@ static int dce_v8_0_hpd_irq(struct amdgpu_device *adev, tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]); tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); - schedule_work(&adev->hotplug_work); + schedule_delayed_work(&adev->hotplug_work, 0); DRM_DEBUG("IH: HPD%d\n", hpd + 1); } diff --git a/drivers/gpu/drm/amd/amdgpu/df_v4_3.c b/drivers/gpu/drm/amd/amdgpu/df_v4_3.c new file mode 100644 index 000000000000..e8b9e19ede2e --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/df_v4_3.c @@ -0,0 +1,61 @@ +/* + * Copyright 2022 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. + * + */ +#include "amdgpu.h" +#include "df_v4_3.h" + +#include "df/df_4_3_offset.h" +#include "df/df_4_3_sh_mask.h" + +static bool df_v4_3_query_ras_poison_mode(struct amdgpu_device *adev) +{ + uint32_t hw_assert_msklo, hw_assert_mskhi; + uint32_t v0, v1, v28, v31; + + hw_assert_msklo = RREG32_SOC15(DF, 0, + regDF_CS_UMC_AON0_HardwareAssertMaskLow); + hw_assert_mskhi = RREG32_SOC15(DF, 0, + regDF_NCS_PG0_HardwareAssertMaskHigh); + + v0 = REG_GET_FIELD(hw_assert_msklo, + DF_CS_UMC_AON0_HardwareAssertMaskLow, HWAssertMsk0); + v1 = REG_GET_FIELD(hw_assert_msklo, + DF_CS_UMC_AON0_HardwareAssertMaskLow, HWAssertMsk1); + v28 = REG_GET_FIELD(hw_assert_mskhi, + DF_NCS_PG0_HardwareAssertMaskHigh, HWAssertMsk28); + v31 = REG_GET_FIELD(hw_assert_mskhi, + DF_NCS_PG0_HardwareAssertMaskHigh, HWAssertMsk31); + + if (v0 && v1 && v28 && v31) + return true; + else if (!v0 && !v1 && !v28 && !v31) + return false; + else { + dev_warn(adev->dev, "DF poison setting is inconsistent(%d:%d:%d:%d)!\n", + v0, v1, v28, v31); + return false; + } +} + +const struct amdgpu_df_funcs df_v4_3_funcs = { + .query_ras_poison_mode = df_v4_3_query_ras_poison_mode, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/df_v4_3.h b/drivers/gpu/drm/amd/amdgpu/df_v4_3.h new file mode 100644 index 000000000000..06ef0724edd3 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/df_v4_3.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022 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. + * + */ + +#ifndef __DF_V4_3_H__ +#define __DF_V4_3_H__ + +#include "soc15_common.h" + +extern const struct amdgpu_df_funcs df_v4_3_funcs; + +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 49d34c7bbf20..6983acc456b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3891,18 +3891,12 @@ err1: static void gfx_v10_0_free_microcode(struct amdgpu_device *adev) { - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); + amdgpu_ucode_release(&adev->gfx.mec2_fw); kfree(adev->gfx.rlc.register_list_format); } @@ -3974,9 +3968,9 @@ static void gfx_v10_0_check_gfxoff_flag(struct amdgpu_device *adev) static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) { - const char *chip_name; char fw_name[40]; - char *wks = ""; + char ucode_prefix[30]; + const char *wks = ""; int err; const struct rlc_firmware_header_v2_0 *rlc_hdr; uint16_t version_major; @@ -3984,90 +3978,40 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) DRM_DEBUG("\n"); - switch (adev->ip_versions[GC_HWIP][0]) { - case IP_VERSION(10, 1, 10): - chip_name = "navi10"; - break; - case IP_VERSION(10, 1, 1): - chip_name = "navi14"; - if (!(adev->pdev->device == 0x7340 && - adev->pdev->revision != 0x00)) - wks = "_wks"; - break; - case IP_VERSION(10, 1, 2): - chip_name = "navi12"; - break; - case IP_VERSION(10, 3, 0): - chip_name = "sienna_cichlid"; - break; - case IP_VERSION(10, 3, 2): - chip_name = "navy_flounder"; - break; - case IP_VERSION(10, 3, 1): - chip_name = "vangogh"; - break; - case IP_VERSION(10, 3, 4): - chip_name = "dimgrey_cavefish"; - break; - case IP_VERSION(10, 3, 5): - chip_name = "beige_goby"; - break; - case IP_VERSION(10, 3, 3): - chip_name = "yellow_carp"; - break; - case IP_VERSION(10, 3, 6): - chip_name = "gc_10_3_6"; - break; - case IP_VERSION(10, 1, 3): - case IP_VERSION(10, 1, 4): - chip_name = "cyan_skillfish2"; - break; - case IP_VERSION(10, 3, 7): - chip_name = "gc_10_3_7"; - break; - default: - BUG(); - } + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 1) && + (!(adev->pdev->device == 0x7340 && adev->pdev->revision != 0x00))) + wks = "_wks"; + amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp%s.bin", chip_name, wks); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.pfp_fw); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp%s.bin", ucode_prefix, wks); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me%s.bin", chip_name, wks); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.me_fw); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me%s.bin", ucode_prefix, wks); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce%s.bin", chip_name, wks); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.ce_fw); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce%s.bin", ucode_prefix, wks); + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE); if (!amdgpu_sriov_vf(adev)) { - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); - err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); - if (err) - goto out; + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix); + err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); /* don't check this. There are apparently firmwares in the wild with * incorrect size in the header */ - err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + if (err == -ENODEV) + goto out; if (err) dev_dbg(adev->dev, - "gfx10: amdgpu_ucode_validate() failed \"%s\"\n", + "gfx10: amdgpu_ucode_request() failed \"%s\"\n", fw_name); rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; version_major = le16_to_cpu(rlc_hdr->header.header_version_major); @@ -4077,47 +4021,34 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) goto out; } - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec%s.bin", chip_name, wks); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.mec_fw); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec%s.bin", ucode_prefix, wks); + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2%s.bin", chip_name, wks); - err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2%s.bin", ucode_prefix, wks); + err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name); if (!err) { - err = amdgpu_ucode_validate(adev->gfx.mec2_fw); - if (err) - goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); } else { err = 0; adev->gfx.mec2_fw = NULL; } + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); + amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); gfx_v10_0_check_fw_write_wait(adev); out: if (err) { - dev_err(adev->dev, - "gfx10: Failed to init firmware \"%s\"\n", - fw_name); - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); + amdgpu_ucode_release(&adev->gfx.mec2_fw); } gfx_v10_0_check_gfxoff_flag(adev); @@ -4270,19 +4201,11 @@ static void gfx_v10_0_mec_fini(struct amdgpu_device *adev) amdgpu_bo_free_kernel(&adev->gfx.mec.mec_fw_obj, NULL, NULL); } -static int gfx_v10_0_me_init(struct amdgpu_device *adev) +static void gfx_v10_0_me_init(struct amdgpu_device *adev) { - int r; - bitmap_zero(adev->gfx.me.queue_bitmap, AMDGPU_MAX_GFX_QUEUES); amdgpu_gfx_graphics_queue_acquire(adev); - - r = gfx_v10_0_init_microcode(adev); - if (r) - DRM_ERROR("Failed to load gfx firmware!\n"); - - return r; } static int gfx_v10_0_mec_init(struct amdgpu_device *adev) @@ -4650,9 +4573,7 @@ static int gfx_v10_0_sw_init(void *handle) adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; - r = gfx_v10_0_me_init(adev); - if (r) - return r; + gfx_v10_0_me_init(adev); if (adev->gfx.rlc.funcs) { if (adev->gfx.rlc.funcs->init) { @@ -7630,7 +7551,7 @@ static int gfx_v10_0_early_init(void *handle) /* init rlcg reg access ctrl */ gfx_v10_0_init_rlcg_reg_access_ctrl(adev); - return 0; + return gfx_v10_0_init_microcode(adev); } static int gfx_v10_0_late_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index a56c6e106d00..c621b2ad7ba3 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -46,6 +46,7 @@ #include "clearstate_gfx11.h" #include "v11_structs.h" #include "gfx_v11_0.h" +#include "gfx_v11_0_3.h" #include "nbio_v4_3.h" #include "mes_v11_0.h" @@ -431,18 +432,37 @@ err1: static void gfx_v11_0_free_microcode(struct amdgpu_device *adev) { - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); kfree(adev->gfx.rlc.register_list_format); } +static int gfx_v11_0_init_toc_microcode(struct amdgpu_device *adev, const char *ucode_prefix) +{ + const struct psp_firmware_header_v1_0 *toc_hdr; + int err = 0; + char fw_name[40]; + + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", ucode_prefix); + err = amdgpu_ucode_request(adev, &adev->psp.toc_fw, fw_name); + if (err) + goto out; + + toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data; + adev->psp.toc.fw_version = le32_to_cpu(toc_hdr->header.ucode_version); + adev->psp.toc.feature_version = le32_to_cpu(toc_hdr->sos.fw_version); + adev->psp.toc.size_bytes = le32_to_cpu(toc_hdr->header.ucode_size_bytes); + adev->psp.toc.start_addr = (uint8_t *)toc_hdr + + le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes); + return 0; +out: + amdgpu_ucode_release(&adev->psp.toc_fw); + return err; +} + static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) { char fw_name[40]; @@ -457,10 +477,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", ucode_prefix); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.pfp_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); if (err) goto out; /* check pfp fw hdr version to decide if enable rs64 for gfx11.*/ @@ -477,10 +494,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", ucode_prefix); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.me_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); if (err) goto out; if (adev->gfx.rs64_enable) { @@ -493,10 +507,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) if (!amdgpu_sriov_vf(adev)) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix); - err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; @@ -508,10 +519,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", ucode_prefix); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.mec_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); if (err) goto out; if (adev->gfx.rs64_enable) { @@ -525,59 +533,23 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev) amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT); } + if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) + err = gfx_v11_0_init_toc_microcode(adev, ucode_prefix); + /* only one MEC for gfx 11.0.0. */ adev->gfx.mec2_fw = NULL; out: if (err) { - dev_err(adev->dev, - "gfx11: Failed to init firmware \"%s\"\n", - fw_name); - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); } return err; } -static int gfx_v11_0_init_toc_microcode(struct amdgpu_device *adev) -{ - const struct psp_firmware_header_v1_0 *toc_hdr; - int err = 0; - char fw_name[40]; - char ucode_prefix[30]; - - amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); - - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", ucode_prefix); - err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev); - if (err) - goto out; - - err = amdgpu_ucode_validate(adev->psp.toc_fw); - if (err) - goto out; - - toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data; - adev->psp.toc.fw_version = le32_to_cpu(toc_hdr->header.ucode_version); - adev->psp.toc.feature_version = le32_to_cpu(toc_hdr->sos.fw_version); - adev->psp.toc.size_bytes = le32_to_cpu(toc_hdr->header.ucode_size_bytes); - adev->psp.toc.start_addr = (uint8_t *)toc_hdr + - le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes); - return 0; -out: - dev_err(adev->dev, "Failed to load TOC microcode\n"); - release_firmware(adev->psp.toc_fw); - adev->psp.toc_fw = NULL; - return err; -} - static u32 gfx_v11_0_get_csb_size(struct amdgpu_device *adev) { u32 count = 0; @@ -714,19 +686,11 @@ static void gfx_v11_0_mec_fini(struct amdgpu_device *adev) amdgpu_bo_free_kernel(&adev->gfx.mec.mec_fw_data_obj, NULL, NULL); } -static int gfx_v11_0_me_init(struct amdgpu_device *adev) +static void gfx_v11_0_me_init(struct amdgpu_device *adev) { - int r; - bitmap_zero(adev->gfx.me.queue_bitmap, AMDGPU_MAX_GFX_QUEUES); amdgpu_gfx_graphics_queue_acquire(adev); - - r = gfx_v11_0_init_microcode(adev); - if (r) - DRM_ERROR("Failed to load gfx firmware!\n"); - - return r; } static int gfx_v11_0_mec_init(struct amdgpu_device *adev) @@ -852,7 +816,14 @@ static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev) switch (adev->ip_versions[GC_HWIP][0]) { case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 2): + adev->gfx.config.max_hw_contexts = 8; + adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; + adev->gfx.config.sc_prim_fifo_size_backend = 0x100; + adev->gfx.config.sc_hiz_tile_fifo_size = 0; + adev->gfx.config.sc_earlyz_tile_fifo_size = 0x4C0; + break; case IP_VERSION(11, 0, 3): + adev->gfx.ras = &gfx_v11_0_3_ras; adev->gfx.config.max_hw_contexts = 8; adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; adev->gfx.config.sc_prim_fifo_size_backend = 0x100; @@ -987,10 +958,11 @@ static int gfx_v11_0_rlc_autoload_buffer_init(struct amdgpu_device *adev) total_size = gfx_v11_0_calc_toc_total_size(adev); r = amdgpu_bo_create_reserved(adev, total_size, 64 * 1024, - AMDGPU_GEM_DOMAIN_VRAM, - &adev->gfx.rlc.rlc_autoload_bo, - &adev->gfx.rlc.rlc_autoload_gpu_addr, - (void **)&adev->gfx.rlc.rlc_autoload_ptr); + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->gfx.rlc.rlc_autoload_bo, + &adev->gfx.rlc.rlc_autoload_gpu_addr, + (void **)&adev->gfx.rlc.rlc_autoload_ptr); if (r) { dev_err(adev->dev, "(%d) failed to create fw autoload bo\n", r); @@ -1287,10 +1259,8 @@ static int gfx_v11_0_sw_init(void *handle) switch (adev->ip_versions[GC_HWIP][0]) { case IP_VERSION(11, 0, 0): - case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 2): case IP_VERSION(11, 0, 3): - case IP_VERSION(11, 0, 4): adev->gfx.me.num_me = 1; adev->gfx.me.num_pipe_per_me = 1; adev->gfx.me.num_queue_per_pipe = 1; @@ -1298,6 +1268,15 @@ static int gfx_v11_0_sw_init(void *handle) adev->gfx.mec.num_pipe_per_mec = 4; adev->gfx.mec.num_queue_per_pipe = 4; break; + case IP_VERSION(11, 0, 1): + case IP_VERSION(11, 0, 4): + adev->gfx.me.num_me = 1; + adev->gfx.me.num_pipe_per_me = 1; + adev->gfx.me.num_queue_per_pipe = 1; + adev->gfx.mec.num_mec = 1; + adev->gfx.mec.num_pipe_per_mec = 4; + adev->gfx.mec.num_queue_per_pipe = 4; + break; default: adev->gfx.me.num_me = 1; adev->gfx.me.num_pipe_per_me = 1; @@ -1329,6 +1308,20 @@ static int gfx_v11_0_sw_init(void *handle) if (r) return r; + /* ECC error */ + r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, + GFX_11_0_0__SRCID__CP_ECC_ERROR, + &adev->gfx.cp_ecc_error_irq); + if (r) + return r; + + /* FED error */ + r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, + GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT, + &adev->gfx.rlc_gc_fed_irq); + if (r) + return r; + adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; if (adev->gfx.imu.funcs) { @@ -1339,9 +1332,7 @@ static int gfx_v11_0_sw_init(void *handle) } } - r = gfx_v11_0_me_init(adev); - if (r) - return r; + gfx_v11_0_me_init(adev); r = gfx_v11_0_rlc_init(adev); if (r) { @@ -1409,9 +1400,6 @@ static int gfx_v11_0_sw_init(void *handle) /* allocate visible FB for rlc auto-loading fw */ if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) { - r = gfx_v11_0_init_toc_microcode(adev); - if (r) - dev_err(adev->dev, "Failed to load toc firmware!\n"); r = gfx_v11_0_rlc_autoload_buffer_init(adev); if (r) return r; @@ -1421,6 +1409,11 @@ static int gfx_v11_0_sw_init(void *handle) if (r) return r; + if (amdgpu_gfx_ras_sw_init(adev)) { + dev_err(adev->dev, "Failed to initialize gfx ras block!\n"); + return -EINVAL; + } + return 0; } @@ -2649,7 +2642,9 @@ static int gfx_v11_0_cp_gfx_load_pfp_microcode_rs64(struct amdgpu_device *adev) /* 64kb align */ r = amdgpu_bo_create_reserved(adev, fw_ucode_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.pfp.pfp_fw_obj, &adev->gfx.pfp.pfp_fw_gpu_addr, (void **)&adev->gfx.pfp.pfp_fw_ptr); @@ -2660,7 +2655,9 @@ static int gfx_v11_0_cp_gfx_load_pfp_microcode_rs64(struct amdgpu_device *adev) } r = amdgpu_bo_create_reserved(adev, fw_data_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.pfp.pfp_fw_data_obj, &adev->gfx.pfp.pfp_fw_data_gpu_addr, (void **)&adev->gfx.pfp.pfp_fw_data_ptr); @@ -2863,7 +2860,9 @@ static int gfx_v11_0_cp_gfx_load_me_microcode_rs64(struct amdgpu_device *adev) /* 64kb align*/ r = amdgpu_bo_create_reserved(adev, fw_ucode_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.me.me_fw_obj, &adev->gfx.me.me_fw_gpu_addr, (void **)&adev->gfx.me.me_fw_ptr); @@ -2874,7 +2873,9 @@ static int gfx_v11_0_cp_gfx_load_me_microcode_rs64(struct amdgpu_device *adev) } r = amdgpu_bo_create_reserved(adev, fw_data_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.me.me_fw_data_obj, &adev->gfx.me.me_fw_data_gpu_addr, (void **)&adev->gfx.me.me_fw_data_ptr); @@ -3380,7 +3381,9 @@ static int gfx_v11_0_cp_compute_load_microcode_rs64(struct amdgpu_device *adev) fw_data_size = le32_to_cpu(mec_hdr->data_size_bytes); r = amdgpu_bo_create_reserved(adev, fw_ucode_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.mec.mec_fw_obj, &adev->gfx.mec.mec_fw_gpu_addr, (void **)&fw_ucode_ptr); @@ -3391,7 +3394,9 @@ static int gfx_v11_0_cp_compute_load_microcode_rs64(struct amdgpu_device *adev) } r = amdgpu_bo_create_reserved(adev, fw_data_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.mec.mec_fw_data_obj, &adev->gfx.mec.mec_fw_data_gpu_addr, (void **)&fw_data_ptr); @@ -4401,6 +4406,7 @@ static int gfx_v11_0_hw_fini(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; + amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4680,7 +4686,7 @@ static int gfx_v11_0_early_init(void *handle) gfx_v11_0_init_rlcg_reg_access_ctrl(adev); - return 0; + return gfx_v11_0_init_microcode(adev); } static int gfx_v11_0_ras_late_init(void *handle) @@ -5832,6 +5838,36 @@ static void gfx_v11_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev } } +#define CP_ME1_PIPE_INST_ADDR_INTERVAL 0x1 +#define SET_ECC_ME_PIPE_STATE(reg_addr, state) \ + do { \ + uint32_t tmp = RREG32_SOC15_IP(GC, reg_addr); \ + tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, state); \ + WREG32_SOC15_IP(GC, reg_addr, tmp); \ + } while (0) + +static int gfx_v11_0_set_cp_ecc_error_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) +{ + uint32_t ecc_irq_state = 0; + uint32_t pipe0_int_cntl_addr = 0; + int i = 0; + + ecc_irq_state = (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0; + + pipe0_int_cntl_addr = SOC15_REG_OFFSET(GC, 0, regCP_ME1_PIPE0_INT_CNTL); + + WREG32_FIELD15_PREREG(GC, 0, CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, ecc_irq_state); + + for (i = 0; i < adev->gfx.mec.num_pipe_per_mec; i++) + SET_ECC_ME_PIPE_STATE(pipe0_int_cntl_addr + i * CP_ME1_PIPE_INST_ADDR_INTERVAL, + ecc_irq_state); + + return 0; +} + static int gfx_v11_0_set_eop_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, @@ -6008,6 +6044,16 @@ static int gfx_v11_0_priv_inst_irq(struct amdgpu_device *adev, return 0; } +static int gfx_v11_0_rlc_gc_fed_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + if (adev->gfx.ras && adev->gfx.ras->rlc_gc_fed_irq) + return adev->gfx.ras->rlc_gc_fed_irq(adev, source, entry); + + return 0; +} + #if 0 static int gfx_v11_0_kiq_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, @@ -6238,6 +6284,15 @@ static const struct amdgpu_irq_src_funcs gfx_v11_0_priv_inst_irq_funcs = { .process = gfx_v11_0_priv_inst_irq, }; +static const struct amdgpu_irq_src_funcs gfx_v11_0_cp_ecc_error_irq_funcs = { + .set = gfx_v11_0_set_cp_ecc_error_state, + .process = amdgpu_gfx_cp_ecc_error_irq, +}; + +static const struct amdgpu_irq_src_funcs gfx_v11_0_rlc_gc_fed_irq_funcs = { + .process = gfx_v11_0_rlc_gc_fed_irq, +}; + static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev) { adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST; @@ -6248,6 +6303,13 @@ static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.priv_inst_irq.num_types = 1; adev->gfx.priv_inst_irq.funcs = &gfx_v11_0_priv_inst_irq_funcs; + + adev->gfx.cp_ecc_error_irq.num_types = 1; /* CP ECC error */ + adev->gfx.cp_ecc_error_irq.funcs = &gfx_v11_0_cp_ecc_error_irq_funcs; + + adev->gfx.rlc_gc_fed_irq.num_types = 1; /* 0x80 FED error */ + adev->gfx.rlc_gc_fed_irq.funcs = &gfx_v11_0_rlc_gc_fed_irq_funcs; + } static void gfx_v11_0_set_imu_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c new file mode 100644 index 000000000000..b07a72ca25d9 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c @@ -0,0 +1,88 @@ +/* + * Copyright 2023 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. + * + */ + +#include "amdgpu.h" +#include "soc21.h" +#include "gc/gc_11_0_3_offset.h" +#include "gc/gc_11_0_3_sh_mask.h" +#include "ivsrcid/gfx/irqsrcs_gfx_11_0_0.h" +#include "soc15.h" +#include "soc15d.h" +#include "gfx_v11_0.h" + + +static int gfx_v11_0_3_rlc_gc_fed_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + uint32_t rlc_status0 = 0, rlc_status1 = 0; + struct ras_common_if *ras_if = NULL; + struct ras_dispatch_if ih_data = { + .entry = entry, + }; + + rlc_status0 = RREG32(SOC15_REG_OFFSET(GC, 0, regRLC_RLCS_FED_STATUS_0)); + rlc_status1 = RREG32(SOC15_REG_OFFSET(GC, 0, regRLC_RLCS_FED_STATUS_1)); + + if (!rlc_status0 && !rlc_status1) { + dev_warn(adev->dev, "RLC_GC_FED irq is generated, but rlc_status0 and rlc_status1 are empty!\n"); + return 0; + } + + /* Use RLC_RLCS_FED_STATUS_0/1 to distinguish FED error block. */ + if (REG_GET_FIELD(rlc_status0, RLC_RLCS_FED_STATUS_0, SDMA0_FED_ERR) || + REG_GET_FIELD(rlc_status0, RLC_RLCS_FED_STATUS_0, SDMA1_FED_ERR)) + ras_if = adev->sdma.ras_if; + else + ras_if = adev->gfx.ras_if; + + if (!ras_if) { + dev_err(adev->dev, "Gfx or sdma ras block not initialized, rlc_status0:0x%x.\n", + rlc_status0); + return -EINVAL; + } + + ih_data.head = *ras_if; + + dev_warn(adev->dev, "RLC %s FED IRQ\n", ras_if->name); + amdgpu_ras_interrupt_dispatch(adev, &ih_data); + + return 0; +} + +static int gfx_v11_0_3_poison_consumption_handler(struct amdgpu_device *adev, + struct amdgpu_iv_entry *entry) +{ + /* Workaround: when vmid and pasid are both zero, trigger gpu reset in KGD. */ + if (entry && (entry->client_id == SOC21_IH_CLIENTID_GFX) && + (entry->src_id == GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT) && + !entry->vmid && !entry->pasid) + amdgpu_ras_reset_gpu(adev); + + return 0; +} + +struct amdgpu_gfx_ras gfx_v11_0_3_ras = { + .rlc_gc_fed_irq = gfx_v11_0_3_rlc_gc_fed_irq, + .poison_consumption_handler = gfx_v11_0_3_poison_consumption_handler, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h new file mode 100644 index 000000000000..672c7920b3d0 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 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. + * + */ + +#ifndef __GFX_V11_0_3_H__ +#define __GFX_V11_0_3_H__ + +extern struct amdgpu_gfx_ras gfx_v11_0_3_ras; + +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 204b246f0e3f..c41219e23151 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -338,10 +338,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.pfp_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); if (err) goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; @@ -349,10 +346,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.me_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); if (err) goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; @@ -360,10 +354,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.ce_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); if (err) goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; @@ -371,10 +362,9 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); - err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.rlc_fw); rlc_hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data; adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); @@ -382,14 +372,10 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) out: if (err) { pr_err("gfx6: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); } return err; } @@ -2375,7 +2361,8 @@ static int gfx_v6_0_rlc_init(struct amdgpu_device *adev) dws = adev->gfx.rlc.clear_state_size + (256 / 4); r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.rlc.clear_state_obj, &adev->gfx.rlc.clear_state_gpu_addr, (void **)&adev->gfx.rlc.cs_ptr); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 0f2976507e48..9d5c1e29b4a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -887,6 +887,16 @@ static void gfx_v7_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *bu static void gfx_v7_0_init_pg(struct amdgpu_device *adev); static void gfx_v7_0_get_cu_info(struct amdgpu_device *adev); +static void gfx_v7_0_free_microcode(struct amdgpu_device *adev) +{ + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); + amdgpu_ucode_release(&adev->gfx.mec2_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); +} + /* * Core functions */ @@ -927,88 +937,44 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.pfp_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); if (err) goto out; snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.me_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); if (err) goto out; snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.ce_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); if (err) goto out; snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.mec_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); if (err) goto out; if (adev->asic_type == CHIP_KAVERI) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); - err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.mec2_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name); if (err) goto out; } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); - err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.rlc_fw); - out: if (err) { pr_err("gfx7: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; + gfx_v7_0_free_microcode(adev); } return err; } -static void gfx_v7_0_free_microcode(struct amdgpu_device *adev) -{ - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; -} - /** * gfx_v7_0_tiling_mode_table_init - init the hw tiling table * @@ -2772,7 +2738,8 @@ static int gfx_v7_0_mec_init(struct amdgpu_device *adev) * GFX7_MEC_HPD_SIZE * 2; r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.mec.hpd_eop_obj, &adev->gfx.mec.hpd_eop_gpu_addr, (void **)&hpd); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index d47135606e3e..b1f2684d854a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -924,20 +924,14 @@ err1: static void gfx_v8_0_free_microcode(struct amdgpu_device *adev) { - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); if ((adev->asic_type != CHIP_STONEY) && (adev->asic_type != CHIP_TOPAZ)) - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; + amdgpu_ucode_release(&adev->gfx.mec2_fw); kfree(adev->gfx.rlc.register_list_format); } @@ -989,40 +983,34 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp_2.bin", chip_name); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); - if (err == -ENOENT) { + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); + if (err == -ENODEV) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); } } else { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); } if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.pfp_fw); - if (err) - goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me_2.bin", chip_name); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); - if (err == -ENOENT) { + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); + if (err == -ENODEV) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); } } else { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); } if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.me_fw); - if (err) - goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); @@ -1030,20 +1018,17 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce_2.bin", chip_name); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); - if (err == -ENOENT) { + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); + if (err == -ENODEV) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); } } else { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); } if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.ce_fw); - if (err) - goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); @@ -1060,10 +1045,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) adev->virt.chained_ib_support = false; snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); - err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.rlc_fw); rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version); adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version); @@ -1110,20 +1094,17 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec_2.bin", chip_name); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); - if (err == -ENOENT) { + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); + if (err == -ENODEV) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); } } else { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); } if (err) goto out; - err = amdgpu_ucode_validate(adev->gfx.mec_fw); - if (err) - goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); @@ -1132,19 +1113,16 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) (adev->asic_type != CHIP_TOPAZ)) { if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2_2.bin", chip_name); - err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); - if (err == -ENOENT) { + err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name); + if (err == -ENODEV) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); - err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name); } } else { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); - err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); + err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name); } if (!err) { - err = amdgpu_ucode_validate(adev->gfx.mec2_fw); - if (err) - goto out; cp_hdr = (const struct gfx_firmware_header_v1_0 *) adev->gfx.mec2_fw->data; adev->gfx.mec2_fw_version = @@ -1219,18 +1197,12 @@ out: dev_err(adev->dev, "gfx8: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); + amdgpu_ucode_release(&adev->gfx.mec2_fw); } return err; } @@ -1340,7 +1312,8 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev) mec_hpd_size = adev->gfx.num_compute_rings * GFX8_MEC_HPD_SIZE; if (mec_hpd_size) { r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.mec.hpd_eop_obj, &adev->gfx.mec.hpd_eop_gpu_addr, (void **)&hpd); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index f202b45c413c..8ad5c03506f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1078,18 +1078,12 @@ err1: static void gfx_v9_0_free_microcode(struct amdgpu_device *adev) { - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); + amdgpu_ucode_release(&adev->gfx.mec_fw); + amdgpu_ucode_release(&adev->gfx.mec2_fw); kfree(adev->gfx.rlc.register_list_format); } @@ -1251,55 +1245,40 @@ static void gfx_v9_0_check_if_need_gfxoff(struct amdgpu_device *adev) } static int gfx_v9_0_init_cp_gfx_microcode(struct amdgpu_device *adev, - const char *chip_name) + char *chip_name) { char fw_name[30]; int err; snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); - err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.pfp_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); - err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.me_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); - err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.ce_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE); out: if (err) { - dev_err(adev->dev, - "gfx9: Failed to init firmware \"%s\"\n", - fw_name); - release_firmware(adev->gfx.pfp_fw); - adev->gfx.pfp_fw = NULL; - release_firmware(adev->gfx.me_fw); - adev->gfx.me_fw = NULL; - release_firmware(adev->gfx.ce_fw); - adev->gfx.ce_fw = NULL; + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); } return err; } static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev, - const char *chip_name) + char *chip_name) { char fw_name[30]; int err; @@ -1328,10 +1307,7 @@ static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev, snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_kicker_rlc.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); - err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; @@ -1340,13 +1316,9 @@ static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev, version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor); err = amdgpu_gfx_rlc_init_microcode(adev, version_major, version_minor); out: - if (err) { - dev_err(adev->dev, - "gfx9: Failed to init firmware \"%s\"\n", - fw_name); - release_firmware(adev->gfx.rlc_fw); - adev->gfx.rlc_fw = NULL; - } + if (err) + amdgpu_ucode_release(&adev->gfx.rlc_fw); + return err; } @@ -1361,7 +1333,7 @@ static bool gfx_v9_0_load_mec2_fw_bin_support(struct amdgpu_device *adev) } static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, - const char *chip_name) + char *chip_name) { char fw_name[30]; int err; @@ -1371,10 +1343,7 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); - err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.mec_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); @@ -1386,91 +1355,49 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev, else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); - err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); + /* ignore failures to load */ + err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name); if (!err) { - err = amdgpu_ucode_validate(adev->gfx.mec2_fw); - if (err) - goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); } else { err = 0; - adev->gfx.mec2_fw = NULL; + amdgpu_ucode_release(&adev->gfx.mec2_fw); } } else { adev->gfx.mec2_fw_version = adev->gfx.mec_fw_version; adev->gfx.mec2_feature_version = adev->gfx.mec_feature_version; } -out: gfx_v9_0_check_if_need_gfxoff(adev); gfx_v9_0_check_fw_write_wait(adev); - if (err) { - dev_err(adev->dev, - "gfx9: Failed to init firmware \"%s\"\n", - fw_name); - release_firmware(adev->gfx.mec_fw); - adev->gfx.mec_fw = NULL; - release_firmware(adev->gfx.mec2_fw); - adev->gfx.mec2_fw = NULL; - } + +out: + if (err) + amdgpu_ucode_release(&adev->gfx.mec_fw); return err; } static int gfx_v9_0_init_microcode(struct amdgpu_device *adev) { - const char *chip_name; + char ucode_prefix[30]; int r; DRM_DEBUG("\n"); - - switch (adev->ip_versions[GC_HWIP][0]) { - case IP_VERSION(9, 0, 1): - chip_name = "vega10"; - break; - case IP_VERSION(9, 2, 1): - chip_name = "vega12"; - break; - case IP_VERSION(9, 4, 0): - chip_name = "vega20"; - break; - case IP_VERSION(9, 2, 2): - case IP_VERSION(9, 1, 0): - if (adev->apu_flags & AMD_APU_IS_RAVEN2) - chip_name = "raven2"; - else if (adev->apu_flags & AMD_APU_IS_PICASSO) - chip_name = "picasso"; - else - chip_name = "raven"; - break; - case IP_VERSION(9, 4, 1): - chip_name = "arcturus"; - break; - case IP_VERSION(9, 3, 0): - if (adev->apu_flags & AMD_APU_IS_RENOIR) - chip_name = "renoir"; - else - chip_name = "green_sardine"; - break; - case IP_VERSION(9, 4, 2): - chip_name = "aldebaran"; - break; - default: - BUG(); - } + amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); /* No CPG in Arcturus */ if (adev->gfx.num_gfx_rings) { - r = gfx_v9_0_init_cp_gfx_microcode(adev, chip_name); + r = gfx_v9_0_init_cp_gfx_microcode(adev, ucode_prefix); if (r) return r; } - r = gfx_v9_0_init_rlc_microcode(adev, chip_name); + r = gfx_v9_0_init_rlc_microcode(adev, ucode_prefix); if (r) return r; - r = gfx_v9_0_init_cp_compute_microcode(adev, chip_name); + r = gfx_v9_0_init_cp_compute_microcode(adev, ucode_prefix); if (r) return r; @@ -1783,7 +1710,8 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev) mec_hpd_size = adev->gfx.num_compute_rings * GFX9_MEC_HPD_SIZE; if (mec_hpd_size) { r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->gfx.mec.hpd_eop_obj, &adev->gfx.mec.hpd_eop_gpu_addr, (void **)&hpd); @@ -2008,27 +1936,6 @@ static int gfx_v9_0_gpu_early_init(struct amdgpu_device *adev) break; } - if (adev->gfx.ras) { - err = amdgpu_ras_register_ras_block(adev, &adev->gfx.ras->ras_block); - if (err) { - DRM_ERROR("Failed to register gfx ras block!\n"); - return err; - } - - strcpy(adev->gfx.ras->ras_block.ras_comm.name, "gfx"); - adev->gfx.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__GFX; - adev->gfx.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; - adev->gfx.ras_if = &adev->gfx.ras->ras_block.ras_comm; - - /* If not define special ras_late_init function, use gfx default ras_late_init */ - if (!adev->gfx.ras->ras_block.ras_late_init) - adev->gfx.ras->ras_block.ras_late_init = amdgpu_gfx_ras_late_init; - - /* If not defined special ras_cb function, use default ras_cb */ - if (!adev->gfx.ras->ras_block.ras_cb) - adev->gfx.ras->ras_block.ras_cb = amdgpu_gfx_process_ras_data_cb; - } - adev->gfx.config.gb_addr_config = gb_addr_config; adev->gfx.config.gb_addr_config_fields.num_pipes = 1 << @@ -2158,12 +2065,6 @@ static int gfx_v9_0_sw_init(void *handle) adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; - r = gfx_v9_0_init_microcode(adev); - if (r) { - DRM_ERROR("Failed to load gfx firmware!\n"); - return r; - } - if (adev->gfx.rlc.funcs) { if (adev->gfx.rlc.funcs->init) { r = adev->gfx.rlc.funcs->init(adev); @@ -2276,6 +2177,11 @@ static int gfx_v9_0_sw_init(void *handle) if (r) return r; + if (amdgpu_gfx_ras_sw_init(adev)) { + dev_err(adev->dev, "Failed to initialize gfx ras block!\n"); + return -EINVAL; + } + return 0; } @@ -4605,7 +4511,7 @@ static int gfx_v9_0_early_init(void *handle) /* init rlcg reg access ctrl */ gfx_v9_0_init_rlcg_reg_access_ctrl(adev); - return 0; + return gfx_v9_0_init_microcode(adev); } static int gfx_v9_0_ecc_late_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c index ec4d5e15b766..ab2325f6c7ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c @@ -120,7 +120,7 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18); /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c index 34513e8e1519..9b3a02527318 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c @@ -165,7 +165,7 @@ static void gfxhub_v2_0_init_system_aperture_regs(struct amdgpu_device *adev) max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18); /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c index 3f8676d23a5e..4aacbbec31e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c @@ -167,7 +167,7 @@ static void gfxhub_v2_1_init_system_aperture_regs(struct amdgpu_device *adev) max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18); /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c index 0e13370c2057..fa42d1907dfa 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c @@ -163,7 +163,7 @@ static void gfxhub_v3_0_init_system_aperture_regs(struct amdgpu_device *adev) adev->gmc.vram_end >> 18); /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c index 080ff11ca305..3dc17a3deedb 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c @@ -169,7 +169,7 @@ static void gfxhub_v3_0_3_init_system_aperture_regs(struct amdgpu_device *adev) adev->gmc.vram_end >> 18); /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 21e46817d82d..7db1f1a7e33c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -78,13 +78,25 @@ gmc_v10_0_vm_fault_interrupt_state(struct amdgpu_device *adev, /* MM HUB */ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, false); /* GFX HUB */ - amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false); + /* This works because this interrupt is only + * enabled at init/resume and disabled in + * fini/suspend, so the overall state doesn't + * change over the course of suspend/resume. + */ + if (!adev->in_s0ix) + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false); break; case AMDGPU_IRQ_STATE_ENABLE: /* MM HUB */ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, true); /* GFX HUB */ - amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true); + /* This works because this interrupt is only + * enabled at init/resume and disabled in + * fini/suspend, so the overall state doesn't + * change over the course of suspend/resume. + */ + if (!adev->in_s0ix) + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true); break; default: break; @@ -835,10 +847,7 @@ static int gmc_v10_0_mc_init(struct amdgpu_device *adev) } #endif - /* In case the PCI BAR is larger than the actual amount of vram */ adev->gmc.visible_vram_size = adev->gmc.aper_size; - if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) - adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { @@ -1061,9 +1070,12 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev) } amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); - r = adev->gfxhub.funcs->gart_enable(adev); - if (r) - return r; + + if (!adev->in_s0ix) { + r = adev->gfxhub.funcs->gart_enable(adev); + if (r) + return r; + } r = adev->mmhub.funcs->gart_enable(adev); if (r) @@ -1077,10 +1089,12 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev) value = (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) ? false : true; - adev->gfxhub.funcs->set_fault_enable_default(adev, value); + if (!adev->in_s0ix) + adev->gfxhub.funcs->set_fault_enable_default(adev, value); adev->mmhub.funcs->set_fault_enable_default(adev, value); gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_MMHUB_0, 0); - gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_GFXHUB_0, 0); + if (!adev->in_s0ix) + gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_GFXHUB_0, 0); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", (unsigned)(adev->gmc.gart_size >> 20), @@ -1101,7 +1115,7 @@ static int gmc_v10_0_hw_init(void *handle) * harvestable groups in gc_utcl2 need to be programmed before any GFX block * register setup within GMC, or else system hang when harvesting SA. */ - if (adev->gfxhub.funcs && adev->gfxhub.funcs->utcl2_harvest) + if (!adev->in_s0ix && adev->gfxhub.funcs && adev->gfxhub.funcs->utcl2_harvest) adev->gfxhub.funcs->utcl2_harvest(adev); r = gmc_v10_0_gart_enable(adev); @@ -1129,7 +1143,8 @@ static int gmc_v10_0_hw_init(void *handle) */ static void gmc_v10_0_gart_disable(struct amdgpu_device *adev) { - adev->gfxhub.funcs->gart_disable(adev); + if (!adev->in_s0ix) + adev->gfxhub.funcs->gart_disable(adev); adev->mmhub.funcs->gart_disable(adev); } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 4326078689cd..5e0018fe7e7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -64,13 +64,25 @@ gmc_v11_0_vm_fault_interrupt_state(struct amdgpu_device *adev, /* MM HUB */ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, false); /* GFX HUB */ - amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false); + /* This works because this interrupt is only + * enabled at init/resume and disabled in + * fini/suspend, so the overall state doesn't + * change over the course of suspend/resume. + */ + if (!adev->in_s0ix) + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false); break; case AMDGPU_IRQ_STATE_ENABLE: /* MM HUB */ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, true); /* GFX HUB */ - amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true); + /* This works because this interrupt is only + * enabled at init/resume and disabled in + * fini/suspend, so the overall state doesn't + * change over the course of suspend/resume. + */ + if (!adev->in_s0ix) + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true); break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index ec291d28edff..b7dad4e67813 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -131,19 +131,12 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/si58_mc.bin"); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); - err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); - if (err) - goto out; - - err = amdgpu_ucode_validate(adev->gmc.fw); - -out: + err = amdgpu_ucode_request(adev, &adev->gmc.fw, fw_name); if (err) { dev_err(adev->dev, "si_mc: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gmc.fw); - adev->gmc.fw = NULL; + amdgpu_ucode_release(&adev->gmc.fw); } return err; } @@ -258,7 +251,7 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev) WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, adev->gmc.vram_end >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, - adev->vram_scratch.gpu_addr >> 12); + adev->mem_scratch.gpu_addr >> 12); WREG32(mmMC_VM_AGP_BASE, 0); WREG32(mmMC_VM_AGP_TOP, 0x0FFFFFFF); WREG32(mmMC_VM_AGP_BOT, 0x0FFFFFFF); @@ -894,8 +887,7 @@ static int gmc_v6_0_sw_fini(void *handle) amdgpu_vm_manager_fini(adev); amdgpu_gart_table_vram_free(adev); amdgpu_bo_fini(adev); - release_firmware(adev->gmc.fw); - adev->gmc.fw = NULL; + amdgpu_ucode_release(&adev->gmc.fw); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 979da6f510e8..402960b0174e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -156,16 +156,10 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); - err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gmc.fw); - -out: + err = amdgpu_ucode_request(adev, &adev->gmc.fw, fw_name); if (err) { pr_err("cik_mc: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gmc.fw); - adev->gmc.fw = NULL; + amdgpu_ucode_release(&adev->gmc.fw); } return err; } @@ -292,7 +286,7 @@ static void gmc_v7_0_mc_program(struct amdgpu_device *adev) WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, adev->gmc.vram_end >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, - adev->vram_scratch.gpu_addr >> 12); + adev->mem_scratch.gpu_addr >> 12); WREG32(mmMC_VM_AGP_BASE, 0); WREG32(mmMC_VM_AGP_TOP, 0x0FFFFFFF); WREG32(mmMC_VM_AGP_BOT, 0x0FFFFFFF); @@ -389,10 +383,7 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) } #endif - /* In case the PCI BAR is larger than the actual amount of vram */ adev->gmc.visible_vram_size = adev->gmc.aper_size; - if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) - adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { @@ -1081,8 +1072,7 @@ static int gmc_v7_0_sw_fini(void *handle) kfree(adev->gmc.vm_fault_info); amdgpu_gart_table_vram_free(adev); amdgpu_bo_fini(adev); - release_firmware(adev->gmc.fw); - adev->gmc.fw = NULL; + amdgpu_ucode_release(&adev->gmc.fw); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 382dde1ce74c..504c1b34dab7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -264,16 +264,10 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); - err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gmc.fw); - -out: + err = amdgpu_ucode_request(adev, &adev->gmc.fw, fw_name); if (err) { pr_err("mc: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gmc.fw); - adev->gmc.fw = NULL; + amdgpu_ucode_release(&adev->gmc.fw); } return err; } @@ -474,7 +468,7 @@ static void gmc_v8_0_mc_program(struct amdgpu_device *adev) WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, adev->gmc.vram_end >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, - adev->vram_scratch.gpu_addr >> 12); + adev->mem_scratch.gpu_addr >> 12); if (amdgpu_sriov_vf(adev)) { tmp = ((adev->gmc.vram_end >> 24) & 0xFFFF) << 16; @@ -587,10 +581,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) } #endif - /* In case the PCI BAR is larger than the actual amount of vram */ adev->gmc.visible_vram_size = adev->gmc.aper_size; - if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) - adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { @@ -1203,8 +1194,7 @@ static int gmc_v8_0_sw_fini(void *handle) kfree(adev->gmc.vm_fault_info); amdgpu_gart_table_vram_free(adev); amdgpu_bo_fini(adev); - release_firmware(adev->gmc.fw); - adev->gmc.fw = NULL; + amdgpu_ucode_release(&adev->gmc.fw); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 08d6cf79fb15..d65c6cea3445 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -484,6 +484,14 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev, for (i = 0; i < 16; i++) { reg = hub->vm_context0_cntl + i; + /* This works because this interrupt is only + * enabled at init/resume and disabled in + * fini/suspend, so the overall state doesn't + * change over the course of suspend/resume. + */ + if (adev->in_s0ix && (j == AMDGPU_GFXHUB_0)) + continue; + if (j == AMDGPU_GFXHUB_0) tmp = RREG32_SOC15_IP(GC, reg); else @@ -504,6 +512,14 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev, for (i = 0; i < 16; i++) { reg = hub->vm_context0_cntl + i; + /* This works because this interrupt is only + * enabled at init/resume and disabled in + * fini/suspend, so the overall state doesn't + * change over the course of suspend/resume. + */ + if (adev->in_s0ix && (j == AMDGPU_GFXHUB_0)) + continue; + if (j == AMDGPU_GFXHUB_0) tmp = RREG32_SOC15_IP(GC, reg); else @@ -1536,10 +1552,7 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) } #endif - /* In case the PCI BAR is larger than the actual amount of vram */ adev->gmc.visible_vram_size = adev->gmc.aper_size; - if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) - adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { @@ -1862,9 +1875,12 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev) } amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); - r = adev->gfxhub.funcs->gart_enable(adev); - if (r) - return r; + + if (!adev->in_s0ix) { + r = adev->gfxhub.funcs->gart_enable(adev); + if (r) + return r; + } r = adev->mmhub.funcs->gart_enable(adev); if (r) @@ -1911,11 +1927,15 @@ static int gmc_v9_0_hw_init(void *handle) value = true; if (!amdgpu_sriov_vf(adev)) { - adev->gfxhub.funcs->set_fault_enable_default(adev, value); + if (!adev->in_s0ix) + adev->gfxhub.funcs->set_fault_enable_default(adev, value); adev->mmhub.funcs->set_fault_enable_default(adev, value); } - for (i = 0; i < adev->num_vmhubs; ++i) + for (i = 0; i < adev->num_vmhubs; ++i) { + if (adev->in_s0ix && (i == AMDGPU_GFXHUB_0)) + continue; gmc_v9_0_flush_gpu_tlb(adev, 0, i, 0); + } if (adev->umc.funcs && adev->umc.funcs->init_registers) adev->umc.funcs->init_registers(adev); @@ -1939,7 +1959,8 @@ static int gmc_v9_0_hw_init(void *handle) */ static void gmc_v9_0_gart_disable(struct amdgpu_device *adev) { - adev->gfxhub.funcs->gart_disable(adev); + if (!adev->in_s0ix) + adev->gfxhub.funcs->gart_disable(adev); adev->mmhub.funcs->gart_disable(adev); } diff --git a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c index 95548c512f4f..ed0d368149aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c @@ -49,10 +49,7 @@ static int imu_v11_0_init_microcode(struct amdgpu_device *adev) amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_imu.bin", ucode_prefix); - err = request_firmware(&adev->gfx.imu_fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->gfx.imu_fw); + err = amdgpu_ucode_request(adev, &adev->gfx.imu_fw, fw_name); if (err) goto out; imu_hdr = (const struct imu_firmware_header_v1_0 *)adev->gfx.imu_fw->data; @@ -77,7 +74,7 @@ out: dev_err(adev->dev, "gfx11: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->gfx.imu_fw); + amdgpu_ucode_release(&adev->gfx.imu_fw); } return err; diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c index 614394118a53..2e2062636d5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c @@ -379,89 +379,6 @@ static const struct amdgpu_mes_funcs mes_v10_1_funcs = { .resume_gang = mes_v10_1_resume_gang, }; -static int mes_v10_1_init_microcode(struct amdgpu_device *adev, - enum admgpu_mes_pipe pipe) -{ - const char *chip_name; - char fw_name[30]; - int err; - const struct mes_firmware_header_v1_0 *mes_hdr; - struct amdgpu_firmware_info *info; - - switch (adev->ip_versions[GC_HWIP][0]) { - case IP_VERSION(10, 1, 10): - chip_name = "navi10"; - break; - case IP_VERSION(10, 3, 0): - chip_name = "sienna_cichlid"; - break; - default: - BUG(); - } - - if (pipe == AMDGPU_MES_SCHED_PIPE) - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin", - chip_name); - else - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes1.bin", - chip_name); - - err = request_firmware(&adev->mes.fw[pipe], fw_name, adev->dev); - if (err) - return err; - - err = amdgpu_ucode_validate(adev->mes.fw[pipe]); - if (err) { - release_firmware(adev->mes.fw[pipe]); - adev->mes.fw[pipe] = NULL; - return err; - } - - mes_hdr = (const struct mes_firmware_header_v1_0 *) - adev->mes.fw[pipe]->data; - adev->mes.uc_start_addr[pipe] = - le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | - ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); - adev->mes.data_start_addr[pipe] = - le32_to_cpu(mes_hdr->mes_data_start_addr_lo) | - ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - int ucode, ucode_data; - - if (pipe == AMDGPU_MES_SCHED_PIPE) { - ucode = AMDGPU_UCODE_ID_CP_MES; - ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA; - } else { - ucode = AMDGPU_UCODE_ID_CP_MES1; - ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA; - } - - info = &adev->firmware.ucode[ucode]; - info->ucode_id = ucode; - info->fw = adev->mes.fw[pipe]; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes), - PAGE_SIZE); - - info = &adev->firmware.ucode[ucode_data]; - info->ucode_id = ucode_data; - info->fw = adev->mes.fw[pipe]; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes), - PAGE_SIZE); - } - - return 0; -} - -static void mes_v10_1_free_microcode(struct amdgpu_device *adev, - enum admgpu_mes_pipe pipe) -{ - release_firmware(adev->mes.fw[pipe]); - adev->mes.fw[pipe] = NULL; -} - static int mes_v10_1_allocate_ucode_buffer(struct amdgpu_device *adev, enum admgpu_mes_pipe pipe) { @@ -1007,7 +924,6 @@ static int mes_v10_1_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int pipe, r; - adev->mes.adev = adev; adev->mes.funcs = &mes_v10_1_funcs; adev->mes.kiq_hw_init = &mes_v10_1_kiq_hw_init; @@ -1019,10 +935,6 @@ static int mes_v10_1_sw_init(void *handle) if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE) continue; - r = mes_v10_1_init_microcode(adev, pipe); - if (r) - return r; - r = mes_v10_1_allocate_eop_buf(adev, pipe); if (r) return r; @@ -1059,8 +971,7 @@ static int mes_v10_1_sw_fini(void *handle) amdgpu_bo_free_kernel(&adev->mes.eop_gpu_obj[pipe], &adev->mes.eop_gpu_addr[pipe], NULL); - - mes_v10_1_free_microcode(adev, pipe); + amdgpu_ucode_release(&adev->mes.fw[pipe]); } amdgpu_bo_free_kernel(&adev->gfx.kiq.ring.mqd_obj, @@ -1229,6 +1140,22 @@ static int mes_v10_1_resume(void *handle) return amdgpu_mes_resume(adev); } +static int mes_v10_0_early_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int pipe, r; + + for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { + if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE) + continue; + r = amdgpu_mes_init_microcode(adev, pipe); + if (r) + return r; + } + + return 0; +} + static int mes_v10_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1241,6 +1168,7 @@ static int mes_v10_0_late_init(void *handle) static const struct amd_ip_funcs mes_v10_1_ip_funcs = { .name = "mes_v10_1", + .early_init = mes_v10_0_early_init, .late_init = mes_v10_0_late_init, .sw_init = mes_v10_1_sw_init, .sw_fini = mes_v10_1_sw_fini, diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 970b066b37bb..bfa305079bfc 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -459,80 +459,6 @@ static const struct amdgpu_mes_funcs mes_v11_0_funcs = { .misc_op = mes_v11_0_misc_op, }; -static int mes_v11_0_init_microcode(struct amdgpu_device *adev, - enum admgpu_mes_pipe pipe) -{ - char fw_name[30]; - char ucode_prefix[30]; - int err; - const struct mes_firmware_header_v1_0 *mes_hdr; - struct amdgpu_firmware_info *info; - - amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); - - if (pipe == AMDGPU_MES_SCHED_PIPE) - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin", - ucode_prefix); - else - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes1.bin", - ucode_prefix); - - err = request_firmware(&adev->mes.fw[pipe], fw_name, adev->dev); - if (err) - return err; - - err = amdgpu_ucode_validate(adev->mes.fw[pipe]); - if (err) { - release_firmware(adev->mes.fw[pipe]); - adev->mes.fw[pipe] = NULL; - return err; - } - - mes_hdr = (const struct mes_firmware_header_v1_0 *) - adev->mes.fw[pipe]->data; - adev->mes.uc_start_addr[pipe] = - le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | - ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); - adev->mes.data_start_addr[pipe] = - le32_to_cpu(mes_hdr->mes_data_start_addr_lo) | - ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - int ucode, ucode_data; - - if (pipe == AMDGPU_MES_SCHED_PIPE) { - ucode = AMDGPU_UCODE_ID_CP_MES; - ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA; - } else { - ucode = AMDGPU_UCODE_ID_CP_MES1; - ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA; - } - - info = &adev->firmware.ucode[ucode]; - info->ucode_id = ucode; - info->fw = adev->mes.fw[pipe]; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes), - PAGE_SIZE); - - info = &adev->firmware.ucode[ucode_data]; - info->ucode_id = ucode_data; - info->fw = adev->mes.fw[pipe]; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes), - PAGE_SIZE); - } - - return 0; -} - -static void mes_v11_0_free_microcode(struct amdgpu_device *adev, - enum admgpu_mes_pipe pipe) -{ - release_firmware(adev->mes.fw[pipe]); - adev->mes.fw[pipe] = NULL; -} - static int mes_v11_0_allocate_ucode_buffer(struct amdgpu_device *adev, enum admgpu_mes_pipe pipe) { @@ -549,7 +475,9 @@ static int mes_v11_0_allocate_ucode_buffer(struct amdgpu_device *adev, fw_size = le32_to_cpu(mes_hdr->mes_ucode_size_bytes); r = amdgpu_bo_create_reserved(adev, fw_size, - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->mes.ucode_fw_obj[pipe], &adev->mes.ucode_fw_gpu_addr[pipe], (void **)&adev->mes.ucode_fw_ptr[pipe]); @@ -582,7 +510,9 @@ static int mes_v11_0_allocate_ucode_data_buffer(struct amdgpu_device *adev, fw_size = le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes); r = amdgpu_bo_create_reserved(adev, fw_size, - 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM, + 64 * 1024, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, &adev->mes.data_fw_obj[pipe], &adev->mes.data_fw_gpu_addr[pipe], (void **)&adev->mes.data_fw_ptr[pipe]); @@ -1087,7 +1017,6 @@ static int mes_v11_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int pipe, r; - adev->mes.adev = adev; adev->mes.funcs = &mes_v11_0_funcs; adev->mes.kiq_hw_init = &mes_v11_0_kiq_hw_init; adev->mes.kiq_hw_fini = &mes_v11_0_kiq_hw_fini; @@ -1100,10 +1029,6 @@ static int mes_v11_0_sw_init(void *handle) if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE) continue; - r = mes_v11_0_init_microcode(adev, pipe); - if (r) - return r; - r = mes_v11_0_allocate_eop_buf(adev, pipe); if (r) return r; @@ -1140,8 +1065,7 @@ static int mes_v11_0_sw_fini(void *handle) amdgpu_bo_free_kernel(&adev->mes.eop_gpu_obj[pipe], &adev->mes.eop_gpu_addr[pipe], NULL); - - mes_v11_0_free_microcode(adev, pipe); + amdgpu_ucode_release(&adev->mes.fw[pipe]); } amdgpu_bo_free_kernel(&adev->gfx.kiq.ring.mqd_obj, @@ -1338,6 +1262,22 @@ static int mes_v11_0_resume(void *handle) return amdgpu_mes_resume(adev); } +static int mes_v11_0_early_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int pipe, r; + + for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { + if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE) + continue; + r = amdgpu_mes_init_microcode(adev, pipe); + if (r) + return r; + } + + return 0; +} + static int mes_v11_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1352,6 +1292,7 @@ static int mes_v11_0_late_init(void *handle) static const struct amd_ip_funcs mes_v11_0_ip_funcs = { .name = "mes_v11_0", + .early_init = mes_v11_0_early_init, .late_init = mes_v11_0_late_init, .sw_init = mes_v11_0_sw_init, .sw_fini = mes_v11_0_sw_fini, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index 3e51e773f92b..15e7cbeae75b 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -114,7 +114,7 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) return; /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c index 6fa7090bc6cb..73afbf2facc9 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c @@ -134,7 +134,7 @@ static void mmhub_v1_7_init_system_aperture_regs(struct amdgpu_device *adev) } /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(MMHUB, 0, regMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(MMHUB, 0, regMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c index 0e664d0cc8d5..278e32db878d 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c @@ -234,7 +234,7 @@ static void mmhub_v2_0_init_system_aperture_regs(struct amdgpu_device *adev) } /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c index 4638ea7c2eec..fcf2813e70db 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c @@ -164,7 +164,7 @@ static void mmhub_v2_3_init_system_aperture_regs(struct amdgpu_device *adev) max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18); /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c index 16cc82215e2e..ae9cd1a4cfee 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c @@ -169,26 +169,26 @@ static void mmhub_v3_0_init_system_aperture_regs(struct amdgpu_device *adev) uint64_t value; uint32_t tmp; - if (!amdgpu_sriov_vf(adev)) { - /* - * the new L1 policy will block SRIOV guest from writing - * these regs, and they will be programed at host. - * so skip programing these regs. - */ - /* Disable AGP. */ - WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BASE, 0); - WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_TOP, 0); - WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BOT, 0x00FFFFFF); - - /* Program the system aperture low logical page number. */ - WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR, - adev->gmc.vram_start >> 18); - WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR, - adev->gmc.vram_end >> 18); - } + if (amdgpu_sriov_vf(adev)) + return; + + /* + * the new L1 policy will block SRIOV guest from writing + * these regs, and they will be programed at host. + * so skip programing these regs. + */ + /* Disable AGP. */ + WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BASE, 0); + WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_TOP, 0); + WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BOT, 0x00FFFFFF); + /* Program the system aperture low logical page number. */ + WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR, + adev->gmc.vram_start >> 18); + WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR, + adev->gmc.vram_end >> 18); /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + + value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c index 6bdf2ef0298d..c8d478f2afdc 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c @@ -188,7 +188,7 @@ static void mmhub_v3_0_1_init_system_aperture_regs(struct amdgpu_device *adev) adev->gmc.vram_end >> 18); /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + + value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c index 45465acaa943..c30e40e52fb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c @@ -181,7 +181,7 @@ static void mmhub_v3_0_2_init_system_aperture_regs(struct amdgpu_device *adev) } /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + + value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c index 445cb06b9d26..72083e96222f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c @@ -136,7 +136,7 @@ static void mmhub_v9_4_init_system_aperture_regs(struct amdgpu_device *adev, max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18); /* Set default page address. */ - value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr); + value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr); WREG32_SOC15_OFFSET( MMHUB, 0, mmVMSHAREDPF0_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index 12906ba74462..63725b2ebc03 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -404,6 +404,11 @@ static int xgpu_ai_request_init_data(struct amdgpu_device *adev) return xgpu_ai_send_access_requests(adev, IDH_REQ_GPU_INIT_DATA); } +static void xgpu_ai_ras_poison_handler(struct amdgpu_device *adev) +{ + xgpu_ai_send_access_requests(adev, IDH_RAS_POISON); +} + const struct amdgpu_virt_ops xgpu_ai_virt_ops = { .req_full_gpu = xgpu_ai_request_full_gpu_access, .rel_full_gpu = xgpu_ai_release_full_gpu_access, @@ -411,4 +416,5 @@ const struct amdgpu_virt_ops xgpu_ai_virt_ops = { .wait_reset = NULL, .trans_msg = xgpu_ai_mailbox_trans_msg, .req_init_data = xgpu_ai_request_init_data, + .ras_poison_handler = xgpu_ai_ras_poison_handler, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h index fa7e13e0459e..af1a784696bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h @@ -39,6 +39,7 @@ enum idh_request { IDH_LOG_VF_ERROR = 200, IDH_READY_TO_RESET = 201, + IDH_RAS_POISON = 202, }; enum idh_event { diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index e07757eea7ad..cae1aaa4ddb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -426,6 +426,11 @@ void xgpu_nv_mailbox_put_irq(struct amdgpu_device *adev) amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0); } +static void xgpu_nv_ras_poison_handler(struct amdgpu_device *adev) +{ + xgpu_nv_send_access_requests(adev, IDH_RAS_POISON); +} + const struct amdgpu_virt_ops xgpu_nv_virt_ops = { .req_full_gpu = xgpu_nv_request_full_gpu_access, .rel_full_gpu = xgpu_nv_release_full_gpu_access, @@ -433,4 +438,5 @@ const struct amdgpu_virt_ops xgpu_nv_virt_ops = { .reset_gpu = xgpu_nv_request_reset, .wait_reset = NULL, .trans_msg = xgpu_nv_mailbox_trans_msg, + .ras_poison_handler = xgpu_nv_ras_poison_handler, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h index 73887b0aa1d6..d0221ce08769 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h @@ -39,6 +39,7 @@ enum idh_request { IDH_LOG_VF_ERROR = 200, IDH_READY_TO_RESET = 201, + IDH_RAS_POISON = 202, }; enum idh_event { diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 6853b93ac82e..d972025f0d20 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -98,7 +98,7 @@ static const struct amdgpu_video_codecs nv_video_codecs_decode = }; /* Sienna Cichlid */ -static const struct amdgpu_video_codec_info sc_video_codecs_decode_array[] = +static const struct amdgpu_video_codec_info sc_video_codecs_decode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, @@ -110,10 +110,27 @@ static const struct amdgpu_video_codec_info sc_video_codecs_decode_array[] = {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, }; -static const struct amdgpu_video_codecs sc_video_codecs_decode = +static const struct amdgpu_video_codec_info sc_video_codecs_decode_array_vcn1[] = { - .codec_count = ARRAY_SIZE(sc_video_codecs_decode_array), - .codec_array = sc_video_codecs_decode_array, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, +}; + +static const struct amdgpu_video_codecs sc_video_codecs_decode_vcn0 = +{ + .codec_count = ARRAY_SIZE(sc_video_codecs_decode_array_vcn0), + .codec_array = sc_video_codecs_decode_array_vcn0, +}; + +static const struct amdgpu_video_codecs sc_video_codecs_decode_vcn1 = +{ + .codec_count = ARRAY_SIZE(sc_video_codecs_decode_array_vcn1), + .codec_array = sc_video_codecs_decode_array_vcn1, }; /* SRIOV Sienna Cichlid, not const since data is controlled by host */ @@ -123,7 +140,7 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] = {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, }; -static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array[] = +static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, @@ -135,16 +152,33 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array[] = {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, }; +static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn1[] = +{ + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, +}; + static struct amdgpu_video_codecs sriov_sc_video_codecs_encode = { .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_encode_array), .codec_array = sriov_sc_video_codecs_encode_array, }; -static struct amdgpu_video_codecs sriov_sc_video_codecs_decode = +static struct amdgpu_video_codecs sriov_sc_video_codecs_decode_vcn0 = { - .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_decode_array), - .codec_array = sriov_sc_video_codecs_decode_array, + .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn0), + .codec_array = sriov_sc_video_codecs_decode_array_vcn0, +}; + +static struct amdgpu_video_codecs sriov_sc_video_codecs_decode_vcn1 = +{ + .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn1), + .codec_array = sriov_sc_video_codecs_decode_array_vcn1, }; /* Beige Goby*/ @@ -181,20 +215,37 @@ static const struct amdgpu_video_codecs yc_video_codecs_decode = { static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, const struct amdgpu_video_codecs **codecs) { + if (adev->vcn.num_vcn_inst == hweight8(adev->vcn.harvest_config)) + return -EINVAL; + switch (adev->ip_versions[UVD_HWIP][0]) { case IP_VERSION(3, 0, 0): case IP_VERSION(3, 0, 64): case IP_VERSION(3, 0, 192): if (amdgpu_sriov_vf(adev)) { - if (encode) - *codecs = &sriov_sc_video_codecs_encode; - else - *codecs = &sriov_sc_video_codecs_decode; + if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) { + if (encode) + *codecs = &sriov_sc_video_codecs_encode; + else + *codecs = &sriov_sc_video_codecs_decode_vcn1; + } else { + if (encode) + *codecs = &sriov_sc_video_codecs_encode; + else + *codecs = &sriov_sc_video_codecs_decode_vcn0; + } } else { - if (encode) - *codecs = &nv_video_codecs_encode; - else - *codecs = &sc_video_codecs_decode; + if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) { + if (encode) + *codecs = &nv_video_codecs_encode; + else + *codecs = &sc_video_codecs_decode_vcn1; + } else { + if (encode) + *codecs = &nv_video_codecs_encode; + else + *codecs = &sc_video_codecs_decode_vcn0; + } } return 0; case IP_VERSION(3, 0, 16): @@ -202,7 +253,7 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, if (encode) *codecs = &nv_video_codecs_encode; else - *codecs = &sc_video_codecs_decode; + *codecs = &sc_video_codecs_decode_vcn0; return 0; case IP_VERSION(3, 1, 1): case IP_VERSION(3, 1, 2): @@ -993,9 +1044,19 @@ static int nv_common_late_init(void *handle) if (amdgpu_sriov_vf(adev)) { xgpu_nv_mailbox_get_irq(adev); - amdgpu_virt_update_sriov_video_codec(adev, - sriov_sc_video_codecs_encode_array, ARRAY_SIZE(sriov_sc_video_codecs_encode_array), - sriov_sc_video_codecs_decode_array, ARRAY_SIZE(sriov_sc_video_codecs_decode_array)); + if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) { + amdgpu_virt_update_sriov_video_codec(adev, + sriov_sc_video_codecs_encode_array, + ARRAY_SIZE(sriov_sc_video_codecs_encode_array), + sriov_sc_video_codecs_decode_array_vcn1, + ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn1)); + } else { + amdgpu_virt_update_sriov_video_codec(adev, + sriov_sc_video_codecs_encode_array, + ARRAY_SIZE(sriov_sc_video_codecs_encode_array), + sriov_sc_video_codecs_decode_array_vcn1, + ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn1)); + } } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index 9de46fa8f46c..e1b7fca09666 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -47,83 +47,17 @@ MODULE_FIRMWARE("amdgpu/raven_ta.bin"); static int psp_v10_0_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - const char *chip_name; - char fw_name[30]; + char ucode_prefix[30]; int err = 0; - const struct ta_firmware_header_v1_0 *ta_hdr; DRM_DEBUG("\n"); - switch (adev->asic_type) { - case CHIP_RAVEN: - if (adev->apu_flags & AMD_APU_IS_RAVEN2) - chip_name = "raven2"; - else if (adev->apu_flags & AMD_APU_IS_PICASSO) - chip_name = "picasso"; - else - chip_name = "raven"; - break; - default: BUG(); - } - - err = psp_init_asd_microcode(psp, chip_name); + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); + + err = psp_init_asd_microcode(psp, ucode_prefix); if (err) - goto out; - - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); - err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); - if (err) { - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; - dev_info(adev->dev, - "psp v10.0: Failed to load firmware \"%s\"\n", - fw_name); - } else { - err = amdgpu_ucode_validate(adev->psp.ta_fw); - if (err) - goto out2; - - ta_hdr = (const struct ta_firmware_header_v1_0 *) - adev->psp.ta_fw->data; - adev->psp.hdcp_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->hdcp.fw_version); - adev->psp.hdcp_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->hdcp.size_bytes); - adev->psp.hdcp_context.context.bin_desc.start_addr = - (uint8_t *)ta_hdr + - le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); - - adev->psp.dtm_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->dtm.fw_version); - adev->psp.dtm_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->dtm.size_bytes); - adev->psp.dtm_context.context.bin_desc.start_addr = - (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + - le32_to_cpu(ta_hdr->dtm.offset_bytes); - - adev->psp.securedisplay_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->securedisplay.fw_version); - adev->psp.securedisplay_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->securedisplay.size_bytes); - adev->psp.securedisplay_context.context.bin_desc.start_addr = - (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + - le32_to_cpu(ta_hdr->securedisplay.offset_bytes); - - adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - } - - return 0; - -out2: - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; -out: - if (err) { - dev_err(adev->dev, - "psp v10.0: Failed to load firmware \"%s\"\n", - fw_name); - } - - return err; + return err; + + return psp_init_ta_microcode(psp, ucode_prefix); } static int psp_v10_0_ring_create(struct psp_context *psp, diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index bd3e3e23a939..8f84fe40abbb 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -88,159 +88,56 @@ MODULE_FIRMWARE("amdgpu/beige_goby_ta.bin"); static int psp_v11_0_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - const char *chip_name; - char fw_name[PSP_FW_NAME_LEN]; + char ucode_prefix[30]; int err = 0; - const struct ta_firmware_header_v1_0 *ta_hdr; DRM_DEBUG("\n"); - switch (adev->ip_versions[MP0_HWIP][0]) { - case IP_VERSION(11, 0, 2): - chip_name = "vega20"; - break; - case IP_VERSION(11, 0, 0): - chip_name = "navi10"; - break; - case IP_VERSION(11, 0, 5): - chip_name = "navi14"; - break; - case IP_VERSION(11, 0, 9): - chip_name = "navi12"; - break; - case IP_VERSION(11, 0, 4): - chip_name = "arcturus"; - break; - case IP_VERSION(11, 0, 7): - chip_name = "sienna_cichlid"; - break; - case IP_VERSION(11, 0, 11): - chip_name = "navy_flounder"; - break; - case IP_VERSION(11, 5, 0): - chip_name = "vangogh"; - break; - case IP_VERSION(11, 0, 12): - chip_name = "dimgrey_cavefish"; - break; - case IP_VERSION(11, 0, 13): - chip_name = "beige_goby"; - break; - default: - BUG(); - } - + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); switch (adev->ip_versions[MP0_HWIP][0]) { case IP_VERSION(11, 0, 2): case IP_VERSION(11, 0, 4): - err = psp_init_sos_microcode(psp, chip_name); + err = psp_init_sos_microcode(psp, ucode_prefix); if (err) return err; - err = psp_init_asd_microcode(psp, chip_name); + err = psp_init_asd_microcode(psp, ucode_prefix); if (err) return err; - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); - err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); - if (err) { - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; - dev_info(adev->dev, - "psp v11.0: Failed to load firmware \"%s\"\n", fw_name); - } else { - err = amdgpu_ucode_validate(adev->psp.ta_fw); - if (err) - goto out2; - - ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data; - adev->psp.xgmi_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->xgmi.fw_version); - adev->psp.xgmi_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->xgmi.size_bytes); - adev->psp.xgmi_context.context.bin_desc.start_addr = - (uint8_t *)ta_hdr + - le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); - adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - adev->psp.ras_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->ras.fw_version); - adev->psp.ras_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->ras.size_bytes); - adev->psp.ras_context.context.bin_desc.start_addr = - (uint8_t *)adev->psp.xgmi_context.context.bin_desc.start_addr + - le32_to_cpu(ta_hdr->ras.offset_bytes); - } + err = psp_init_ta_microcode(psp, ucode_prefix); + adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0; break; case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 5): case IP_VERSION(11, 0, 9): - err = psp_init_sos_microcode(psp, chip_name); + err = psp_init_sos_microcode(psp, ucode_prefix); if (err) return err; - err = psp_init_asd_microcode(psp, chip_name); + err = psp_init_asd_microcode(psp, ucode_prefix); if (err) return err; - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); - err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); - if (err) { - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; - dev_info(adev->dev, - "psp v11.0: Failed to load firmware \"%s\"\n", fw_name); - } else { - err = amdgpu_ucode_validate(adev->psp.ta_fw); - if (err) - goto out2; - - ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data; - adev->psp.hdcp_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->hdcp.fw_version); - adev->psp.hdcp_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->hdcp.size_bytes); - adev->psp.hdcp_context.context.bin_desc.start_addr = - (uint8_t *)ta_hdr + - le32_to_cpu( - ta_hdr->header.ucode_array_offset_bytes); - - adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - - adev->psp.dtm_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->dtm.fw_version); - adev->psp.dtm_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->dtm.size_bytes); - adev->psp.dtm_context.context.bin_desc.start_addr = - (uint8_t *)adev->psp.hdcp_context.context - .bin_desc.start_addr + - le32_to_cpu(ta_hdr->dtm.offset_bytes); - } + err = psp_init_ta_microcode(psp, ucode_prefix); + adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0; break; case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): - err = psp_init_sos_microcode(psp, chip_name); - if (err) - return err; - err = psp_init_ta_microcode(psp, chip_name); + err = psp_init_sos_microcode(psp, ucode_prefix); if (err) return err; + err = psp_init_ta_microcode(psp, ucode_prefix); break; case IP_VERSION(11, 5, 0): - err = psp_init_asd_microcode(psp, chip_name); - if (err) - return err; - err = psp_init_toc_microcode(psp, chip_name); + err = psp_init_asd_microcode(psp, ucode_prefix); if (err) return err; + err = psp_init_toc_microcode(psp, ucode_prefix); break; default: BUG(); } - return 0; - -out2: - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c index 8ed2281b6557..fcd708eae75c 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c @@ -48,83 +48,25 @@ MODULE_FIRMWARE("amdgpu/green_sardine_ta.bin"); static int psp_v12_0_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - const char *chip_name; - char fw_name[30]; + char ucode_prefix[30]; int err = 0; - const struct ta_firmware_header_v1_0 *ta_hdr; DRM_DEBUG("\n"); - switch (adev->asic_type) { - case CHIP_RENOIR: - if (adev->apu_flags & AMD_APU_IS_RENOIR) - chip_name = "renoir"; - else - chip_name = "green_sardine"; - break; - default: - BUG(); - } + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); - err = psp_init_asd_microcode(psp, chip_name); + err = psp_init_asd_microcode(psp, ucode_prefix); if (err) return err; - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); - err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); - if (err) { - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; - dev_info(adev->dev, - "psp v12.0: Failed to load firmware \"%s\"\n", - fw_name); - } else { - err = amdgpu_ucode_validate(adev->psp.ta_fw); - if (err) - goto out; - - ta_hdr = (const struct ta_firmware_header_v1_0 *) - adev->psp.ta_fw->data; - adev->psp.hdcp_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->hdcp.fw_version); - adev->psp.hdcp_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->hdcp.size_bytes); - adev->psp.hdcp_context.context.bin_desc.start_addr = - (uint8_t *)ta_hdr + - le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); - - adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); - - adev->psp.dtm_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->dtm.fw_version); - adev->psp.dtm_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->dtm.size_bytes); - adev->psp.dtm_context.context.bin_desc.start_addr = - (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + - le32_to_cpu(ta_hdr->dtm.offset_bytes); - - if (adev->apu_flags & AMD_APU_IS_RENOIR) { - adev->psp.securedisplay_context.context.bin_desc.fw_version = - le32_to_cpu(ta_hdr->securedisplay.fw_version); - adev->psp.securedisplay_context.context.bin_desc.size_bytes = - le32_to_cpu(ta_hdr->securedisplay.size_bytes); - adev->psp.securedisplay_context.context.bin_desc.start_addr = - (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr + - le32_to_cpu(ta_hdr->securedisplay.offset_bytes); - } - } - - return 0; + err = psp_init_ta_microcode(psp, ucode_prefix); + if (err) + return err; -out: - release_firmware(adev->psp.ta_fw); - adev->psp.ta_fw = NULL; - if (err) { - dev_err(adev->dev, - "psp v12.0: Failed to load firmware \"%s\"\n", - fw_name); - } + /* only supported on renoir */ + if (!(adev->apu_flags & AMD_APU_IS_RENOIR)) + adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0; - return err; + return 0; } static int psp_v12_0_bootloader_load_sysdrv(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index e6a26a7e5e5e..d62fcc77af95 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -70,32 +70,19 @@ MODULE_FIRMWARE("amdgpu/psp_13_0_11_ta.bin"); static int psp_v13_0_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - const char *chip_name; char ucode_prefix[30]; int err = 0; - switch (adev->ip_versions[MP0_HWIP][0]) { - case IP_VERSION(13, 0, 2): - chip_name = "aldebaran"; - break; - case IP_VERSION(13, 0, 1): - case IP_VERSION(13, 0, 3): - chip_name = "yellow_carp"; - break; - default: - amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); - chip_name = ucode_prefix; - break; - } + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); switch (adev->ip_versions[MP0_HWIP][0]) { case IP_VERSION(13, 0, 2): - err = psp_init_sos_microcode(psp, chip_name); + err = psp_init_sos_microcode(psp, ucode_prefix); if (err) return err; /* It's not necessary to load ras ta on Guest side */ if (!amdgpu_sriov_vf(adev)) { - err = psp_init_ta_microcode(&adev->psp, chip_name); + err = psp_init_ta_microcode(psp, ucode_prefix); if (err) return err; } @@ -105,21 +92,21 @@ static int psp_v13_0_init_microcode(struct psp_context *psp) case IP_VERSION(13, 0, 5): case IP_VERSION(13, 0, 8): case IP_VERSION(13, 0, 11): - err = psp_init_toc_microcode(psp, chip_name); + err = psp_init_toc_microcode(psp, ucode_prefix); if (err) return err; - err = psp_init_ta_microcode(psp, chip_name); + err = psp_init_ta_microcode(psp, ucode_prefix); if (err) return err; break; case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 7): case IP_VERSION(13, 0, 10): - err = psp_init_sos_microcode(psp, chip_name); + err = psp_init_sos_microcode(psp, ucode_prefix); if (err) return err; /* It's not necessary to load ras ta on Guest side */ - err = psp_init_ta_microcode(psp, chip_name); + err = psp_init_ta_microcode(psp, ucode_prefix); if (err) return err; break; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c index 9d4e24e518e8..d5ba58eba3e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c @@ -35,25 +35,17 @@ MODULE_FIRMWARE("amdgpu/psp_13_0_4_ta.bin"); static int psp_v13_0_4_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - const char *chip_name; char ucode_prefix[30]; int err = 0; - switch (adev->ip_versions[MP0_HWIP][0]) { - case IP_VERSION(13, 0, 4): - amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); - chip_name = ucode_prefix; - break; - default: - BUG(); - } + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); switch (adev->ip_versions[MP0_HWIP][0]) { case IP_VERSION(13, 0, 4): - err = psp_init_toc_microcode(psp, chip_name); + err = psp_init_toc_microcode(psp, ucode_prefix); if (err) return err; - err = psp_init_ta_microcode(psp, chip_name); + err = psp_init_ta_microcode(psp, ucode_prefix); if (err) return err; break; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index 157147c6c94e..f6b75e3e47ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c @@ -57,26 +57,18 @@ static int psp_v3_1_ring_stop(struct psp_context *psp, static int psp_v3_1_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - const char *chip_name; + char ucode_prefix[30]; int err = 0; DRM_DEBUG("\n"); - switch (adev->asic_type) { - case CHIP_VEGA10: - chip_name = "vega10"; - break; - case CHIP_VEGA12: - chip_name = "vega12"; - break; - default: BUG(); - } + amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); - err = psp_init_sos_microcode(psp, chip_name); + err = psp_init_sos_microcode(psp, ucode_prefix); if (err) return err; - err = psp_init_asd_microcode(psp, chip_name); + err = psp_init_asd_microcode(psp, ucode_prefix); if (err) return err; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index c52d246a1d96..fd2a7b66ac56 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -113,10 +113,9 @@ static void sdma_v2_4_init_golden_registers(struct amdgpu_device *adev) static void sdma_v2_4_free_microcode(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ucode_release(&adev->sdma.instance[i].fw); } /** @@ -151,10 +150,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); + err = amdgpu_ucode_request(adev, &adev->sdma.instance[i].fw, fw_name); if (err) goto out; hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; @@ -176,10 +172,8 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) out: if (err) { pr_err("sdma_v2_4: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ucode_release(&adev->sdma.instance[i].fw); } return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 486d9b5c1b9e..e572389089d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -250,10 +250,9 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev) static void sdma_v3_0_free_microcode(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ucode_release(&adev->sdma.instance[i].fw); } /** @@ -309,10 +308,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); + err = amdgpu_ucode_request(adev, &adev->sdma.instance[i].fw, fw_name); if (err) goto out; hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; @@ -332,10 +328,8 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) out: if (err) { pr_err("sdma_v3_0: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < adev->sdma.num_instances; i++) { - release_firmware(adev->sdma.instance[i].fw); - adev->sdma.instance[i].fw = NULL; - } + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ucode_release(&adev->sdma.instance[i].fw); } return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 4d780e4430e7..b5affba22156 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -575,60 +575,17 @@ static void sdma_v4_0_setup_ulv(struct amdgpu_device *adev) // vega10 real chip need to use PSP to load firmware static int sdma_v4_0_init_microcode(struct amdgpu_device *adev) { - const char *chip_name; - char fw_name[30]; int ret, i; - DRM_DEBUG("\n"); - - switch (adev->ip_versions[SDMA0_HWIP][0]) { - case IP_VERSION(4, 0, 0): - chip_name = "vega10"; - break; - case IP_VERSION(4, 0, 1): - chip_name = "vega12"; - break; - case IP_VERSION(4, 2, 0): - chip_name = "vega20"; - break; - case IP_VERSION(4, 1, 0): - case IP_VERSION(4, 1, 1): - if (adev->apu_flags & AMD_APU_IS_RAVEN2) - chip_name = "raven2"; - else if (adev->apu_flags & AMD_APU_IS_PICASSO) - chip_name = "picasso"; - else - chip_name = "raven"; - break; - case IP_VERSION(4, 2, 2): - chip_name = "arcturus"; - break; - case IP_VERSION(4, 1, 2): - if (adev->apu_flags & AMD_APU_IS_RENOIR) - chip_name = "renoir"; - else - chip_name = "green_sardine"; - break; - case IP_VERSION(4, 4, 0): - chip_name = "aldebaran"; - break; - default: - BUG(); - } - for (i = 0; i < adev->sdma.num_instances; i++) { - if (i == 0) - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); - else - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma%d.bin", chip_name, i); if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) || adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) { /* Acturus & Aldebaran will leverage the same FW memory for every SDMA instance */ - ret = amdgpu_sdma_init_microcode(adev, fw_name, 0, true); + ret = amdgpu_sdma_init_microcode(adev, 0, true); break; } else { - ret = amdgpu_sdma_init_microcode(adev, fw_name, i, false); + ret = amdgpu_sdma_init_microcode(adev, i, false); if (ret) return ret; } @@ -1894,6 +1851,11 @@ static int sdma_v4_0_sw_init(void *handle) } } + if (amdgpu_sdma_ras_sw_init(adev)) { + dev_err(adev->dev, "Failed to initialize sdma ras block!\n"); + return -EINVAL; + } + return r; } @@ -2731,22 +2693,6 @@ static void sdma_v4_0_set_ras_funcs(struct amdgpu_device *adev) break; } - if (adev->sdma.ras) { - amdgpu_ras_register_ras_block(adev, &adev->sdma.ras->ras_block); - - strcpy(adev->sdma.ras->ras_block.ras_comm.name, "sdma"); - adev->sdma.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__SDMA; - adev->sdma.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; - adev->sdma.ras_if = &adev->sdma.ras->ras_block.ras_comm; - - /* If don't define special ras_late_init function, use default ras_late_init */ - if (!adev->sdma.ras->ras_block.ras_late_init) - adev->sdma.ras->ras_block.ras_late_init = amdgpu_sdma_ras_late_init; - - /* If not defined special ras_cb function, use default ras_cb */ - if (!adev->sdma.ras->ras_block.ras_cb) - adev->sdma.ras->ras_block.ras_cb = amdgpu_sdma_process_ras_data_cb; - } } const struct amdgpu_ip_block_version sdma_v4_0_ip_block = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c index d4d9f196db83..1941b3b7c5d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c @@ -237,39 +237,13 @@ static void sdma_v5_0_init_golden_registers(struct amdgpu_device *adev) // emulation only, won't work on real chip // navi10 real chip need to use PSP to load firmware static int sdma_v5_0_init_microcode(struct amdgpu_device *adev) -{ - const char *chip_name; - char fw_name[40]; - int ret, i; +{ int ret, i; if (amdgpu_sriov_vf(adev) && (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(5, 0, 5))) return 0; - DRM_DEBUG("\n"); - - switch (adev->ip_versions[SDMA0_HWIP][0]) { - case IP_VERSION(5, 0, 0): - chip_name = "navi10"; - break; - case IP_VERSION(5, 0, 2): - chip_name = "navi14"; - break; - case IP_VERSION(5, 0, 5): - chip_name = "navi12"; - break; - case IP_VERSION(5, 0, 1): - chip_name = "cyan_skillfish2"; - break; - default: - BUG(); - } - for (i = 0; i < adev->sdma.num_instances; i++) { - if (i == 0) - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); - else - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - ret = amdgpu_sdma_init_microcode(adev, fw_name, i, false); + ret = amdgpu_sdma_init_microcode(adev, i, false); if (ret) return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index 809eca54fc61..8e445eb9dd49 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -89,59 +89,6 @@ static u32 sdma_v5_2_get_reg_offset(struct amdgpu_device *adev, u32 instance, u3 return base + internal_offset; } -/** - * sdma_v5_2_init_microcode - load ucode images from disk - * - * @adev: amdgpu_device pointer - * - * Use the firmware interface to load the ucode images into - * the driver (not loaded into hw). - * Returns 0 on success, error on failure. - */ - -// emulation only, won't work on real chip -// navi10 real chip need to use PSP to load firmware -static int sdma_v5_2_init_microcode(struct amdgpu_device *adev) -{ - const char *chip_name; - char fw_name[40]; - - DRM_DEBUG("\n"); - - switch (adev->ip_versions[SDMA0_HWIP][0]) { - case IP_VERSION(5, 2, 0): - chip_name = "sienna_cichlid_sdma"; - break; - case IP_VERSION(5, 2, 2): - chip_name = "navy_flounder_sdma"; - break; - case IP_VERSION(5, 2, 1): - chip_name = "vangogh_sdma"; - break; - case IP_VERSION(5, 2, 4): - chip_name = "dimgrey_cavefish_sdma"; - break; - case IP_VERSION(5, 2, 5): - chip_name = "beige_goby_sdma"; - break; - case IP_VERSION(5, 2, 3): - chip_name = "yellow_carp_sdma"; - break; - case IP_VERSION(5, 2, 6): - chip_name = "sdma_5_2_6"; - break; - case IP_VERSION(5, 2, 7): - chip_name = "sdma_5_2_7"; - break; - default: - BUG(); - } - - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", chip_name); - - return amdgpu_sdma_init_microcode(adev, fw_name, 0, true); -} - static unsigned sdma_v5_2_ring_init_cond_exec(struct amdgpu_ring *ring) { unsigned ret; @@ -809,12 +756,6 @@ static int sdma_v5_2_start(struct amdgpu_device *adev) msleep(1000); } - /* TODO: check whether can submit a doorbell request to raise - * a doorbell fence to exit gfxoff. - */ - if (adev->in_s0ix) - amdgpu_gfx_off_ctrl(adev, false); - sdma_v5_2_soft_reset(adev); /* unhalt the MEs */ sdma_v5_2_enable(adev, true); @@ -823,8 +764,6 @@ static int sdma_v5_2_start(struct amdgpu_device *adev) /* start the gfx rings and rlc compute queues */ r = sdma_v5_2_gfx_resume(adev); - if (adev->in_s0ix) - amdgpu_gfx_off_ctrl(adev, true); if (r) return r; r = sdma_v5_2_rlc_resume(adev); @@ -1296,7 +1235,7 @@ static int sdma_v5_2_sw_init(void *handle) return r; } - r = sdma_v5_2_init_microcode(adev); + r = amdgpu_sdma_init_microcode(adev, 0, true); if (r) { DRM_ERROR("Failed to load sdma firmware!\n"); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index 049c26a45d85..3d36329be384 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -78,29 +78,6 @@ static u32 sdma_v6_0_get_reg_offset(struct amdgpu_device *adev, u32 instance, u3 return base + internal_offset; } -/** - * sdma_v6_0_init_microcode - load ucode images from disk - * - * @adev: amdgpu_device pointer - * - * Use the firmware interface to load the ucode images into - * the driver (not loaded into hw). - * Returns 0 on success, error on failure. - */ -static int sdma_v6_0_init_microcode(struct amdgpu_device *adev) -{ - char fw_name[30]; - char ucode_prefix[30]; - - DRM_DEBUG("\n"); - - amdgpu_ucode_ip_version_decode(adev, SDMA0_HWIP, ucode_prefix, sizeof(ucode_prefix)); - - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); - - return amdgpu_sdma_init_microcode(adev, fw_name, 0, true); -} - static unsigned sdma_v6_0_ring_init_cond_exec(struct amdgpu_ring *ring) { unsigned ret; @@ -1234,6 +1211,24 @@ static void sdma_v6_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); } +static struct amdgpu_sdma_ras sdma_v6_0_3_ras = { + .ras_block = { + .ras_late_init = amdgpu_ras_block_late_init, + }, +}; + +static void sdma_v6_0_set_ras_funcs(struct amdgpu_device *adev) +{ + switch (adev->ip_versions[SDMA0_HWIP][0]) { + case IP_VERSION(6, 0, 3): + adev->sdma.ras = &sdma_v6_0_3_ras; + break; + default: + break; + } + +} + static int sdma_v6_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1243,6 +1238,7 @@ static int sdma_v6_0_early_init(void *handle) sdma_v6_0_set_vm_pte_funcs(adev); sdma_v6_0_set_irq_funcs(adev); sdma_v6_0_set_mqd_funcs(adev); + sdma_v6_0_set_ras_funcs(adev); return 0; } @@ -1260,7 +1256,7 @@ static int sdma_v6_0_sw_init(void *handle) if (r) return r; - r = sdma_v6_0_init_microcode(adev); + r = amdgpu_sdma_init_microcode(adev, 0, true); if (r) { DRM_ERROR("Failed to load sdma firmware!\n"); return r; @@ -1287,6 +1283,11 @@ static int sdma_v6_0_sw_init(void *handle) return r; } + if (amdgpu_sdma_ras_sw_init(adev)) { + dev_err(adev->dev, "Failed to initialize sdma ras block!\n"); + return -EINVAL; + } + return r; } @@ -1426,10 +1427,12 @@ static int sdma_v6_0_set_trap_irq_state(struct amdgpu_device *adev, u32 reg_offset = sdma_v6_0_get_reg_offset(adev, type, regSDMA0_CNTL); - sdma_cntl = RREG32(reg_offset); - sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE, - state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); - WREG32(reg_offset, sdma_cntl); + if (!amdgpu_sriov_vf(adev)) { + sdma_cntl = RREG32(reg_offset); + sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE, + state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); + WREG32(reg_offset, sdma_cntl); + } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 5562670b7b52..9c4a29d50f1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -48,19 +48,31 @@ static const struct amd_ip_funcs soc21_common_ip_funcs; /* SOC21 */ -static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array[] = +static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, }; -static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode = +static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] = { - .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_encode_array), - .codec_array = vcn_4_0_0_video_codecs_encode_array, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, +}; + +static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn0 = +{ + .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_encode_array_vcn0), + .codec_array = vcn_4_0_0_video_codecs_encode_array_vcn0, }; -static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array[] = +static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn1 = +{ + .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_encode_array_vcn1), + .codec_array = vcn_4_0_0_video_codecs_encode_array_vcn1, +}; + +static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, @@ -69,23 +81,46 @@ static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array[ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, }; -static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_decode = +static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array_vcn1[] = +{ + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, +}; + +static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_decode_vcn0 = { - .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_decode_array), - .codec_array = vcn_4_0_0_video_codecs_decode_array, + .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_decode_array_vcn0), + .codec_array = vcn_4_0_0_video_codecs_decode_array_vcn0, +}; + +static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_decode_vcn1 = +{ + .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_decode_array_vcn1), + .codec_array = vcn_4_0_0_video_codecs_decode_array_vcn1, }; static int soc21_query_video_codecs(struct amdgpu_device *adev, bool encode, const struct amdgpu_video_codecs **codecs) { - switch (adev->ip_versions[UVD_HWIP][0]) { + if (adev->vcn.num_vcn_inst == hweight8(adev->vcn.harvest_config)) + return -EINVAL; + switch (adev->ip_versions[UVD_HWIP][0]) { case IP_VERSION(4, 0, 0): case IP_VERSION(4, 0, 2): - if (encode) - *codecs = &vcn_4_0_0_video_codecs_encode; - else - *codecs = &vcn_4_0_0_video_codecs_decode; + if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) { + if (encode) + *codecs = &vcn_4_0_0_video_codecs_encode_vcn1; + else + *codecs = &vcn_4_0_0_video_codecs_decode_vcn1; + } else { + if (encode) + *codecs = &vcn_4_0_0_video_codecs_encode_vcn0; + else + *codecs = &vcn_4_0_0_video_codecs_decode_vcn0; + } return 0; default: return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h b/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h index cf8ff064dc72..00d8bdb8254f 100644 --- a/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h +++ b/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h @@ -55,10 +55,10 @@ enum ta_securedisplay_status { TA_SECUREDISPLAY_STATUS__MAX = 0x7FFFFFFF,/* Maximum Value for status*/ }; -/** @enum ta_securedisplay_max_phy +/** @enum ta_securedisplay_phy_ID * Physical ID number to use for reading corresponding DIO Scratch register for ROI */ -enum ta_securedisplay_max_phy { +enum ta_securedisplay_phy_ID { TA_SECUREDISPLAY_PHY0 = 0, TA_SECUREDISPLAY_PHY1 = 1, TA_SECUREDISPLAY_PHY2 = 2, @@ -139,16 +139,16 @@ union ta_securedisplay_cmd_output { uint32_t reserved[4]; }; -/** @struct securedisplay_cmd - * Secure Display Command which is shared buffer memory - */ -struct securedisplay_cmd { - uint32_t cmd_id; /* +0 Bytes Command ID */ - enum ta_securedisplay_status status; /* +4 Bytes Status of Secure Display TA */ - uint32_t reserved[2]; /* +8 Bytes Reserved */ - union ta_securedisplay_cmd_input securedisplay_in_message; /* +16 Bytes Input Buffer */ - union ta_securedisplay_cmd_output securedisplay_out_message;/* +32 Bytes Output Buffer */ - /**@note Total 48 Bytes */ +/** @struct ta_securedisplay_cmd +* Secure display command which is shared buffer memory +*/ +struct ta_securedisplay_cmd { + uint32_t cmd_id; /**< +0 Bytes Command ID */ + enum ta_securedisplay_status status; /**< +4 Bytes Status code returned by the secure display TA */ + uint32_t reserved[2]; /**< +8 Bytes Reserved */ + union ta_securedisplay_cmd_input securedisplay_in_message; /**< +16 Bytes Command input buffer */ + union ta_securedisplay_cmd_output securedisplay_out_message; /**< +32 Bytes Command output buffer */ + /**@note Total 48 Bytes */ }; #endif //_TA_SECUREDISPLAY_IF_H diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c index 72fd963f178b..e08e25a3a1a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c @@ -57,13 +57,6 @@ static inline uint32_t get_umc_v6_7_reg_offset(struct amdgpu_device *adev, return adev->umc.channel_offs * ch_inst + UMC_V6_7_INST_DIST * umc_inst; } -static inline uint32_t get_umc_v6_7_channel_index(struct amdgpu_device *adev, - uint32_t umc_inst, - uint32_t ch_inst) -{ - return adev->umc.channel_idx_tbl[umc_inst * adev->umc.channel_inst_num + ch_inst]; -} - static void umc_v6_7_query_error_status_helper(struct amdgpu_device *adev, uint64_t mc_umc_status, uint32_t umc_reg_offset) { diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c index b7da4528cf0a..da394bc06bba 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c @@ -340,29 +340,13 @@ static void umc_v8_10_err_cnt_init(struct amdgpu_device *adev) } } -static uint32_t umc_v8_10_query_ras_poison_mode_per_channel( - struct amdgpu_device *adev, - uint32_t umc_reg_offset) -{ - uint32_t ecc_ctrl_addr, ecc_ctrl; - - ecc_ctrl_addr = - SOC15_REG_OFFSET(UMC, 0, regUMCCH0_0_GeccCtrl); - ecc_ctrl = RREG32_PCIE((ecc_ctrl_addr + - umc_reg_offset) * 4); - - return REG_GET_FIELD(ecc_ctrl, UMCCH0_0_GeccCtrl, UCFatalEn); -} - static bool umc_v8_10_query_ras_poison_mode(struct amdgpu_device *adev) { - uint32_t umc_reg_offset = 0; - - /* Enabling fatal error in umc node0 instance0 channel0 will be - * considered as fatal error mode + /* + * Force return true, because UMCCH0_0_GeccCtrl + * is not accessible from host side */ - umc_reg_offset = get_umc_v8_10_reg_offset(adev, 0, 0, 0); - return !umc_v8_10_query_ras_poison_mode_per_channel(adev, umc_reg_offset); + return true; } const struct amdgpu_ras_block_hw_ops umc_v8_10_ras_hw_ops = { diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index f0fbcda76f5e..c305b2cb8490 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -57,11 +57,12 @@ static void vcn_v1_0_idle_work_handler(struct work_struct *work); static void vcn_v1_0_ring_begin_use(struct amdgpu_ring *ring); /** - * vcn_v1_0_early_init - set function pointers + * vcn_v1_0_early_init - set function pointers and load microcode * * @handle: amdgpu_device pointer * * Set ring and irq function pointers + * Load microcode from filesystem */ static int vcn_v1_0_early_init(void *handle) { @@ -75,7 +76,7 @@ static int vcn_v1_0_early_init(void *handle) jpeg_v1_0_early_init(handle); - return 0; + return amdgpu_vcn_early_init(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index 08871bad9994..4b4cd88414e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -62,11 +62,12 @@ static int vcn_v2_0_pause_dpg_mode(struct amdgpu_device *adev, int inst_idx, struct dpg_pause_state *new_state); static int vcn_v2_0_start_sriov(struct amdgpu_device *adev); /** - * vcn_v2_0_early_init - set function pointers + * vcn_v2_0_early_init - set function pointers and load microcode * * @handle: amdgpu_device pointer * * Set ring and irq function pointers + * Load microcode from filesystem */ static int vcn_v2_0_early_init(void *handle) { @@ -81,7 +82,7 @@ static int vcn_v2_0_early_init(void *handle) vcn_v2_0_set_enc_ring_funcs(adev); vcn_v2_0_set_irq_funcs(adev); - return 0; + return amdgpu_vcn_early_init(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index ec87b00f2e05..b0b0e69c6a94 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -71,11 +71,12 @@ static int amdgpu_ih_clientid_vcns[] = { }; /** - * vcn_v2_5_early_init - set function pointers + * vcn_v2_5_early_init - set function pointers and load microcode * * @handle: amdgpu_device pointer * * Set ring and irq function pointers + * Load microcode from filesystem */ static int vcn_v2_5_early_init(void *handle) { @@ -107,7 +108,7 @@ static int vcn_v2_5_early_init(void *handle) vcn_v2_5_set_irq_funcs(adev); vcn_v2_5_set_ras_funcs(adev); - return 0; + return amdgpu_vcn_early_init(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 9c8b5fd99037..66439388faee 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -78,11 +78,12 @@ static void vcn_v3_0_dec_ring_set_wptr(struct amdgpu_ring *ring); static void vcn_v3_0_enc_ring_set_wptr(struct amdgpu_ring *ring); /** - * vcn_v3_0_early_init - set function pointers + * vcn_v3_0_early_init - set function pointers and load microcode * * @handle: amdgpu_device pointer * * Set ring and irq function pointers + * Load microcode from filesystem */ static int vcn_v3_0_early_init(void *handle) { @@ -109,7 +110,7 @@ static int vcn_v3_0_early_init(void *handle) vcn_v3_0_set_enc_ring_funcs(adev); vcn_v3_0_set_irq_funcs(adev); - return 0; + return amdgpu_vcn_early_init(adev); } /** @@ -1770,6 +1771,10 @@ static int vcn_v3_0_limit_sched(struct amdgpu_cs_parser *p, if (atomic_read(&job->base.entity->fence_seq)) return -EINVAL; + /* if VCN0 is harvested, we can't support AV1 */ + if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) + return -EINVAL; + scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_DEC] [AMDGPU_RING_PRIO_DEFAULT].sched; drm_sched_entity_modify_sched(job->base.entity, scheds, 1); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 1e2b22299975..efb22d0975b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -68,11 +68,12 @@ static void vcn_v4_0_unified_ring_set_wptr(struct amdgpu_ring *ring); static void vcn_v4_0_set_ras_funcs(struct amdgpu_device *adev); /** - * vcn_v4_0_early_init - set function pointers + * vcn_v4_0_early_init - set function pointers and load microcode * * @handle: amdgpu_device pointer * * Set ring and irq function pointers + * Load microcode from filesystem */ static int vcn_v4_0_early_init(void *handle) { @@ -88,7 +89,7 @@ static int vcn_v4_0_early_init(void *handle) vcn_v4_0_set_irq_funcs(adev); vcn_v4_0_set_ras_funcs(adev); - return 0; + return amdgpu_vcn_early_init(adev); } /** @@ -1631,6 +1632,10 @@ static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p, if (atomic_read(&job->base.entity->fence_seq)) return -EINVAL; + /* if VCN0 is harvested, we can't support AV1 */ + if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) + return -EINVAL; + scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_ENC] [AMDGPU_RING_PRIO_0].sched; drm_sched_entity_modify_sched(job->base.entity, scheds, 1); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 6d291aa6386b..f79b8e964140 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1127,8 +1127,13 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, } /* Update the VRAM usage count */ - if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) - WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + args->size); + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { + uint64_t size = args->size; + + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM) + size >>= 1; + WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + PAGE_ALIGN(size)); + } mutex_unlock(&p->mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index b8936340742b..3de7f616a001 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -262,23 +262,12 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) f2g = &gfx_v8_kfd2kgd; break; case CHIP_FIJI: - gfx_target_version = 80003; - f2g = &gfx_v8_kfd2kgd; - break; case CHIP_POLARIS10: gfx_target_version = 80003; f2g = &gfx_v8_kfd2kgd; break; case CHIP_POLARIS11: - gfx_target_version = 80003; - if (!vf) - f2g = &gfx_v8_kfd2kgd; - break; case CHIP_POLARIS12: - gfx_target_version = 80003; - if (!vf) - f2g = &gfx_v8_kfd2kgd; - break; case CHIP_VEGAM: gfx_target_version = 80003; if (!vf) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index ecb4c3abc629..c06ada0844ba 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -200,7 +200,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, queue_input.wptr_addr = (uint64_t)q->properties.write_ptr; if (q->wptr_bo) { - wptr_addr_off = (uint64_t)q->properties.write_ptr - (uint64_t)q->wptr_bo->kfd_bo->va; + wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1); queue_input.wptr_mc_addr = ((uint64_t)q->wptr_bo->tbo.resource->start << PAGE_SHIFT) + wptr_addr_off; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c index d119070956fb..8b2dd2670ab7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c @@ -59,30 +59,27 @@ static int update_qpd_v9(struct device_queue_manager *dqm, /* check if sh_mem_config register already configured */ if (qpd->sh_mem_config == 0) { - qpd->sh_mem_config = - SH_MEM_ALIGNMENT_MODE_UNALIGNED << + qpd->sh_mem_config = SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT; - if (KFD_GC_VERSION(dqm->dev) == IP_VERSION(9, 4, 2)) { - /* Aldebaran can safely support different XNACK modes - * per process - */ - if (!pdd->process->xnack_enabled) - qpd->sh_mem_config |= - 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT; - } else if (dqm->dev->noretry && - !dqm->dev->use_iommu_v2) { - qpd->sh_mem_config |= - 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT; - } + if (dqm->dev->noretry && !dqm->dev->use_iommu_v2) + qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT; qpd->sh_mem_ape1_limit = 0; qpd->sh_mem_ape1_base = 0; } + if (KFD_SUPPORT_XNACK_PER_PROCESS(dqm->dev)) { + if (!pdd->process->xnack_enabled) + qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT; + else + qpd->sh_mem_config &= ~(1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT); + } + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(pdd); - pr_debug("sh_mem_bases 0x%X\n", qpd->sh_mem_bases); + pr_debug("sh_mem_bases 0x%X sh_mem_config 0x%X\n", qpd->sh_mem_bases, + qpd->sh_mem_config); return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 10048ce16aea..de8ce72344fc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -1027,8 +1027,7 @@ int svm_migrate_init(struct amdgpu_device *adev) /* Disable SVM support capability */ pgmap->type = 0; if (pgmap->type == MEMORY_DEVICE_PRIVATE) - devm_release_mem_region(adev->dev, res->start, - res->end - res->start + 1); + devm_release_mem_region(adev->dev, res->start, resource_size(res)); return PTR_ERR(r); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 552c3ac85a13..bfa30d12406b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -206,6 +206,8 @@ enum cache_policy { #define KFD_GC_VERSION(dev) ((dev)->adev->ip_versions[GC_HWIP][0]) #define KFD_IS_SOC15(dev) ((KFD_GC_VERSION(dev)) >= (IP_VERSION(9, 0, 1))) +#define KFD_SUPPORT_XNACK_PER_PROCESS(dev)\ + (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 2)) struct kfd_event_interrupt_class { bool (*interrupt_isr)(struct kfd_dev *dev, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 51b1683ac5c1..72df6286e240 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1330,7 +1330,7 @@ bool kfd_process_xnack_mode(struct kfd_process *p, bool supported) * per-process XNACK mode selection. But let the dev->noretry * setting still influence the default XNACK mode. */ - if (supported && KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 2)) + if (supported && KFD_SUPPORT_XNACK_PER_PROCESS(dev)) continue; /* GFXv10 and later GPUs do not support shader preemption @@ -1563,6 +1563,8 @@ err_free_pdd: int kfd_process_device_init_vm(struct kfd_process_device *pdd, struct file *drm_file) { + struct amdgpu_fpriv *drv_priv; + struct amdgpu_vm *avm; struct kfd_process *p; struct kfd_dev *dev; int ret; @@ -1573,10 +1575,15 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, if (pdd->drm_priv) return -EBUSY; + ret = amdgpu_file_to_fpriv(drm_file, &drv_priv); + if (ret) + return ret; + avm = &drv_priv->vm; + p = pdd->process; dev = pdd->dev; - ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, drm_file, + ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, avm, &p->kgd_process_info, &p->ef); if (ret) { @@ -1593,7 +1600,7 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, if (ret) goto err_init_cwsr; - ret = amdgpu_amdkfd_gpuvm_set_vm_pasid(dev->adev, drm_file, p->pasid); + ret = amdgpu_amdkfd_gpuvm_set_vm_pasid(dev->adev, avm, p->pasid); if (ret) goto err_set_pasid; @@ -1607,6 +1614,7 @@ err_init_cwsr: kfd_process_device_destroy_ib_mem(pdd); err_reserve_ib_mem: pdd->drm_priv = NULL; + amdgpu_amdkfd_gpuvm_destroy_cb(dev->adev, avm); return ret; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 814f99888ab1..dc6fd6967050 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/sched/task.h> +#include <drm/ttm/ttm_tt.h> #include "amdgpu_sync.h" #include "amdgpu_object.h" #include "amdgpu_vm.h" @@ -570,6 +571,15 @@ svm_range_vram_node_new(struct amdgpu_device *adev, struct svm_range *prange, goto reserve_bo_failed; } + if (clear) { + r = amdgpu_bo_sync_wait(bo, AMDGPU_FENCE_OWNER_KFD, false); + if (r) { + pr_debug("failed %d to sync bo\n", r); + amdgpu_bo_unreserve(bo); + goto reserve_bo_failed; + } + } + r = dma_resv_reserve_fences(bo->tbo.base.resv, 1); if (r) { pr_debug("failed %d to reserve bo\n", r); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index bceb1a5b2518..3fdaba56be6f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -801,7 +801,7 @@ static int kfd_build_sysfs_node_entry(struct kfd_topology_device *dev, p2plink->attr.name = "properties"; p2plink->attr.mode = KFD_SYSFS_FILE_MODE; - sysfs_attr_init(&iolink->attr); + sysfs_attr_init(&p2plink->attr); ret = sysfs_create_file(p2plink->kobj, &p2plink->attr); if (ret < 0) return ret; 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 50c783e19f5a..8e4b668faa35 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -66,7 +66,7 @@ #include "ivsrcid/ivsrcid_vislands30.h" -#include "i2caux_interface.h" +#include <linux/backlight.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> @@ -210,7 +210,7 @@ static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm); static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, struct amdgpu_dm_connector *amdgpu_dm_connector, - uint32_t link_index, + u32 link_index, struct amdgpu_encoder *amdgpu_encoder); static int amdgpu_dm_encoder_init(struct drm_device *dev, struct amdgpu_encoder *aencoder, @@ -262,7 +262,7 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc) static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, u32 *vbl, u32 *position) { - uint32_t v_blank_start, v_blank_end, h_position, v_position; + u32 v_blank_start, v_blank_end, h_position, v_position; if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) return -EINVAL; @@ -361,7 +361,7 @@ static void dm_pflip_high_irq(void *interrupt_params) struct amdgpu_device *adev = irq_params->adev; unsigned long flags; struct drm_pending_vblank_event *e; - uint32_t vpos, hpos, v_blank_start, v_blank_end; + u32 vpos, hpos, v_blank_start, v_blank_end; bool vrr_active; amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP); @@ -648,7 +648,7 @@ static void dmub_hpd_callback(struct amdgpu_device *adev, struct drm_connector *connector; struct drm_connector_list_iter iter; struct dc_link *link; - uint8_t link_index = 0; + u8 link_index = 0; struct drm_device *dev; if (adev == NULL) @@ -749,7 +749,7 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) struct amdgpu_device *adev = irq_params->adev; struct amdgpu_display_manager *dm = &adev->dm; struct dmcub_trace_buf_entry entry = { 0 }; - uint32_t count = 0; + u32 count = 0; struct dmub_hpd_work *dmub_hpd_wrk; struct dc_link *plink = NULL; @@ -1015,7 +1015,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) struct dmub_srv_hw_params hw_params; enum dmub_status status; const unsigned char *fw_inst_const, *fw_bss_data; - uint32_t i, fw_inst_const_size, fw_bss_data_size; + u32 i, fw_inst_const_size, fw_bss_data_size; bool has_hw_support; if (!dmub_srv) @@ -1176,10 +1176,10 @@ static void dm_dmub_hw_resume(struct amdgpu_device *adev) static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config) { - uint64_t pt_base; - uint32_t logical_addr_low; - uint32_t logical_addr_high; - uint32_t agp_base, agp_bot, agp_top; + u64 pt_base; + u32 logical_addr_low; + u32 logical_addr_high; + u32 agp_base, agp_bot, agp_top; PHYSICAL_ADDRESS_LOC page_table_start, page_table_end, page_table_base; memset(pa_config, 0, sizeof(*pa_config)); @@ -1503,8 +1503,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) case IP_VERSION(3, 0, 1): case IP_VERSION(3, 1, 2): case IP_VERSION(3, 1, 3): - case IP_VERSION(3, 1, 4): - case IP_VERSION(3, 1, 5): case IP_VERSION(3, 1, 6): init_data.flags.gpu_vm_support = true; break; @@ -1642,7 +1640,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } #endif #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work(); + adev->dm.secure_display_ctxs = amdgpu_dm_crtc_secure_display_create_contexts(adev); + if (!adev->dm.secure_display_ctxs) { + DRM_ERROR("amdgpu: failed to initialize secure_display_ctxs.\n"); + } #endif if (dc_is_dmub_outbox_supported(adev->dm.dc)) { init_completion(&adev->dm.dmub_aux_transfer_done); @@ -1730,17 +1731,18 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) adev->dm.vblank_control_workqueue = NULL; } - for (i = 0; i < adev->dm.display_indexes_num; i++) { - drm_encoder_cleanup(&adev->dm.mst_encoders[i].base); - } - amdgpu_dm_destroy_drm_device(&adev->dm); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - if (adev->dm.crc_rd_wrk) { - flush_work(&adev->dm.crc_rd_wrk->notify_ta_work); - kfree(adev->dm.crc_rd_wrk); - adev->dm.crc_rd_wrk = NULL; + if (adev->dm.secure_display_ctxs) { + for (i = 0; i < adev->mode_info.num_crtc; i++) { + if (adev->dm.secure_display_ctxs[i].crtc) { + flush_work(&adev->dm.secure_display_ctxs[i].notify_ta_work); + flush_work(&adev->dm.secure_display_ctxs[i].forward_roi_work); + } + } + kfree(adev->dm.secure_display_ctxs); + adev->dm.secure_display_ctxs = NULL; } #endif #ifdef CONFIG_DRM_AMD_DC_HDCP @@ -1875,25 +1877,17 @@ static int load_dmcu_fw(struct amdgpu_device *adev) return 0; } - r = request_firmware_direct(&adev->dm.fw_dmcu, fw_name_dmcu, adev->dev); - if (r == -ENOENT) { + r = amdgpu_ucode_request(adev, &adev->dm.fw_dmcu, fw_name_dmcu); + if (r == -ENODEV) { /* DMCU firmware is not necessary, so don't raise a fuss if it's missing */ DRM_DEBUG_KMS("dm: DMCU firmware not found\n"); adev->dm.fw_dmcu = NULL; return 0; } if (r) { - dev_err(adev->dev, "amdgpu_dm: Can't load firmware \"%s\"\n", - fw_name_dmcu); - return r; - } - - r = amdgpu_ucode_validate(adev->dm.fw_dmcu); - if (r) { dev_err(adev->dev, "amdgpu_dm: Can't validate firmware \"%s\"\n", fw_name_dmcu); - release_firmware(adev->dm.fw_dmcu); - adev->dm.fw_dmcu = NULL; + amdgpu_ucode_release(&adev->dm.fw_dmcu); return r; } @@ -1939,7 +1933,6 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) struct dmub_srv_fb_info *fb_info; struct dmub_srv *dmub_srv; const struct dmcub_firmware_header_v1_0 *hdr; - const char *fw_name_dmub; enum dmub_asic dmub_asic; enum dmub_status status; int r; @@ -1947,73 +1940,43 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) switch (adev->ip_versions[DCE_HWIP][0]) { case IP_VERSION(2, 1, 0): dmub_asic = DMUB_ASIC_DCN21; - fw_name_dmub = FIRMWARE_RENOIR_DMUB; - if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) - fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB; break; case IP_VERSION(3, 0, 0): - if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0)) { - dmub_asic = DMUB_ASIC_DCN30; - fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB; - } else { - dmub_asic = DMUB_ASIC_DCN30; - fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB; - } + dmub_asic = DMUB_ASIC_DCN30; break; case IP_VERSION(3, 0, 1): dmub_asic = DMUB_ASIC_DCN301; - fw_name_dmub = FIRMWARE_VANGOGH_DMUB; break; case IP_VERSION(3, 0, 2): dmub_asic = DMUB_ASIC_DCN302; - fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB; break; case IP_VERSION(3, 0, 3): dmub_asic = DMUB_ASIC_DCN303; - fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB; break; case IP_VERSION(3, 1, 2): case IP_VERSION(3, 1, 3): dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31; - fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; break; case IP_VERSION(3, 1, 4): dmub_asic = DMUB_ASIC_DCN314; - fw_name_dmub = FIRMWARE_DCN_314_DMUB; break; case IP_VERSION(3, 1, 5): dmub_asic = DMUB_ASIC_DCN315; - fw_name_dmub = FIRMWARE_DCN_315_DMUB; break; case IP_VERSION(3, 1, 6): dmub_asic = DMUB_ASIC_DCN316; - fw_name_dmub = FIRMWARE_DCN316_DMUB; break; case IP_VERSION(3, 2, 0): dmub_asic = DMUB_ASIC_DCN32; - fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB; break; case IP_VERSION(3, 2, 1): dmub_asic = DMUB_ASIC_DCN321; - fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB; break; default: /* ASIC doesn't support DMUB. */ return 0; } - r = request_firmware_direct(&adev->dm.dmub_fw, fw_name_dmub, adev->dev); - if (r) { - DRM_ERROR("DMUB firmware loading failed: %d\n", r); - return 0; - } - - r = amdgpu_ucode_validate(adev->dm.dmub_fw); - if (r) { - DRM_ERROR("Couldn't validate DMUB firmware: %d\n", r); - return 0; - } - hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data; adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version); @@ -2080,7 +2043,9 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) * TODO: Move this into GART. */ r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &adev->dm.dmub_bo, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->dm.dmub_bo, &adev->dm.dmub_bo_gpu_addr, &adev->dm.dmub_bo_cpu_addr); if (r) @@ -2135,11 +2100,8 @@ static int dm_sw_fini(void *handle) adev->dm.dmub_srv = NULL; } - release_firmware(adev->dm.dmub_fw); - adev->dm.dmub_fw = NULL; - - release_firmware(adev->dm.fw_dmcu); - adev->dm.fw_dmcu = NULL; + amdgpu_ucode_release(&adev->dm.dmub_fw); + amdgpu_ucode_release(&adev->dm.fw_dmcu); return 0; } @@ -2165,6 +2127,8 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) DRM_ERROR("DM_MST: Failed to start MST\n"); aconnector->dc_link->type = dc_connection_single; + ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, + aconnector->dc_link); break; } } @@ -2486,7 +2450,7 @@ struct amdgpu_dm_connector * amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, struct drm_crtc *crtc) { - uint32_t i; + u32 i; struct drm_connector_state *new_con_state; struct drm_connector *connector; struct drm_crtc *crtc_from_state; @@ -2734,12 +2698,14 @@ static int dm_resume(void *handle) drm_for_each_connector_iter(connector, &iter) { aconnector = to_amdgpu_dm_connector(connector); + if (!aconnector->dc_link) + continue; + /* * this is the case when traversing through already created * MST connectors, should be skipped */ - if (aconnector->dc_link && - aconnector->dc_link->type == dc_connection_mst_branch) + if (aconnector->dc_link->type == dc_connection_mst_branch) continue; mutex_lock(&aconnector->hpd_lock); @@ -3117,8 +3083,8 @@ static void handle_hpd_irq(void *param) static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector) { - uint8_t esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 }; - uint8_t dret; + u8 esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 }; + u8 dret; bool new_irq_handled = false; int dpcd_addr; int dpcd_bytes_to_read; @@ -3146,7 +3112,7 @@ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector) while (dret == dpcd_bytes_to_read && process_count < max_process_count) { - uint8_t retry; + u8 retry; dret = 0; process_count++; @@ -3165,7 +3131,7 @@ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector) dpcd_bytes_to_read - 1; for (retry = 0; retry < 3; retry++) { - uint8_t wret; + u8 wret; wret = drm_dp_dpcd_write( &aconnector->dm_dp_aux.aux, @@ -4179,12 +4145,12 @@ static void amdgpu_set_panel_orientation(struct drm_connector *connector); static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) { struct amdgpu_display_manager *dm = &adev->dm; - int32_t i; + s32 i; struct amdgpu_dm_connector *aconnector = NULL; struct amdgpu_encoder *aencoder = NULL; struct amdgpu_mode_info *mode_info = &adev->mode_info; - uint32_t link_cnt; - int32_t primary_planes; + u32 link_cnt; + s32 primary_planes; enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; bool psr_feature_enabled = false; @@ -4361,6 +4327,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_set_panel_orientation(&aconnector->base); } + /* If we didn't find a panel, notify the acpi video detection */ + if (dm->adev->flags & AMD_IS_APU && dm->num_of_edps == 0) + acpi_video_report_nolcd(); + /* Software is initialized. Now we can register interrupt handlers. */ switch (adev->asic_type) { #if defined(CONFIG_DRM_AMD_DC_SI) @@ -4500,6 +4470,61 @@ DEVICE_ATTR_WO(s3_debug); #endif +static int dm_init_microcode(struct amdgpu_device *adev) +{ + char *fw_name_dmub; + int r; + + switch (adev->ip_versions[DCE_HWIP][0]) { + case IP_VERSION(2, 1, 0): + fw_name_dmub = FIRMWARE_RENOIR_DMUB; + if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) + fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB; + break; + case IP_VERSION(3, 0, 0): + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0)) + fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB; + else + fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB; + break; + case IP_VERSION(3, 0, 1): + fw_name_dmub = FIRMWARE_VANGOGH_DMUB; + break; + case IP_VERSION(3, 0, 2): + fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB; + break; + case IP_VERSION(3, 0, 3): + fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB; + break; + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; + break; + case IP_VERSION(3, 1, 4): + fw_name_dmub = FIRMWARE_DCN_314_DMUB; + break; + case IP_VERSION(3, 1, 5): + fw_name_dmub = FIRMWARE_DCN_315_DMUB; + break; + case IP_VERSION(3, 1, 6): + fw_name_dmub = FIRMWARE_DCN316_DMUB; + break; + case IP_VERSION(3, 2, 0): + fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB; + break; + case IP_VERSION(3, 2, 1): + fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB; + break; + default: + /* ASIC doesn't support DMUB. */ + return 0; + } + r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, fw_name_dmub); + if (r) + DRM_ERROR("DMUB firmware loading failed: %d\n", r); + return r; +} + static int dm_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -4632,7 +4657,7 @@ static int dm_early_init(void *handle) #endif adev->dc_enabled = true; - return 0; + return dm_init_microcode(adev); } static bool modereset_required(struct drm_crtc_state *crtc_state) @@ -4697,7 +4722,7 @@ fill_plane_color_attributes(const struct drm_plane_state *plane_state, static int fill_dc_plane_info_and_addr(struct amdgpu_device *adev, const struct drm_plane_state *plane_state, - const uint64_t tiling_flags, + const u64 tiling_flags, struct dc_plane_info *plane_info, struct dc_plane_address *address, bool tmz_surface, @@ -4872,7 +4897,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, static inline void fill_dc_dirty_rect(struct drm_plane *plane, struct rect *dirty_rect, int32_t x, - int32_t y, int32_t width, int32_t height, + s32 y, s32 width, s32 height, int *i, bool ffu) { if (*i > DC_MAX_DIRTY_RECTS) @@ -4928,11 +4953,11 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, { struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); struct rect *dirty_rects = flip_addrs->dirty_rects; - uint32_t num_clips; + u32 num_clips; struct drm_mode_rect *clips; bool bb_changed; bool fb_changed; - uint32_t i = 0; + u32 i = 0; /* * Cursor plane has it's own dirty rect update interface. See @@ -5078,7 +5103,7 @@ static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector, bool is_y420, int requested_bpc) { - uint8_t bpc; + u8 bpc; if (is_y420) { bpc = 8; @@ -5307,8 +5332,6 @@ static void fill_stream_properties_from_drm_display_mode( timing_out->aspect_ratio = get_aspect_ratio(mode_in); - stream->output_color_space = get_output_color_space(timing_out); - stream->out_transfer_func->type = TF_TYPE_PREDEFINED; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) { @@ -5319,6 +5342,8 @@ static void fill_stream_properties_from_drm_display_mode( adjust_colour_depth_from_display_info(timing_out, info); } } + + stream->output_color_space = get_output_color_space(timing_out); } static void fill_audio_info(struct audio_info *audio_info, @@ -5622,8 +5647,8 @@ static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector, uint32_t max_dsc_target_bpp_limit_override) { const struct dc_link_settings *verified_link_cap = NULL; - uint32_t link_bw_in_kbps; - uint32_t edp_min_bpp_x16, edp_max_bpp_x16; + u32 link_bw_in_kbps; + u32 edp_min_bpp_x16, edp_max_bpp_x16; struct dc *dc = sink->ctx->dc; struct dc_dsc_bw_range bw_range = {0}; struct dc_dsc_config dsc_cfg = {0}; @@ -5680,11 +5705,11 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, struct dsc_dec_dpcd_caps *dsc_caps) { struct drm_connector *drm_connector = &aconnector->base; - uint32_t link_bandwidth_kbps; + u32 link_bandwidth_kbps; struct dc *dc = sink->ctx->dc; - uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps; - uint32_t dsc_max_supported_bw_in_kbps; - uint32_t max_dsc_target_bpp_limit_override = + u32 max_supported_bw_in_kbps, timing_bw_in_kbps; + u32 dsc_max_supported_bw_in_kbps; + u32 max_dsc_target_bpp_limit_override = drm_connector->display_info.max_dsc_bpp; link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, @@ -5831,7 +5856,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ DRM_DEBUG_DRIVER("No preferred mode found\n"); } else { - recalculate_timing = is_freesync_video_mode(&mode, aconnector); + recalculate_timing = amdgpu_freesync_vid_mode && + is_freesync_video_mode(&mode, aconnector); if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); drm_mode_copy(&saved_mode, &mode); @@ -6905,7 +6931,7 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector) const struct drm_display_mode *m; struct drm_display_mode *new_mode; uint i; - uint32_t new_modes_count = 0; + u32 new_modes_count = 0; /* Standard FPS values * @@ -6919,7 +6945,7 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector) * 60 - Commonly used * 48,72,96,120 - Multiples of 24 */ - static const uint32_t common_rates[] = { + static const u32 common_rates[] = { 23976, 24000, 25000, 29970, 30000, 48000, 50000, 60000, 72000, 96000, 120000 }; @@ -6935,8 +6961,8 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector) return 0; for (i = 0; i < ARRAY_SIZE(common_rates); i++) { - uint64_t target_vtotal, target_vtotal_diff; - uint64_t num, den; + u64 target_vtotal, target_vtotal_diff; + u64 num, den; if (drm_mode_vrefresh(m) * 1000 < common_rates[i]) continue; @@ -6982,7 +7008,7 @@ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connect struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - if (!edid) + if (!(amdgpu_freesync_vid_mode && edid)) return; if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) @@ -7178,7 +7204,7 @@ create_i2c(struct ddc_service *ddc_service, */ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, struct amdgpu_dm_connector *aconnector, - uint32_t link_index, + u32 link_index, struct amdgpu_encoder *aencoder) { int res = 0; @@ -7363,27 +7389,55 @@ is_scaling_state_different(const struct dm_connector_state *dm_state, } #ifdef CONFIG_DRM_AMD_DC_HDCP -static bool is_content_protection_different(struct drm_connector_state *state, - const struct drm_connector_state *old_state, - const struct drm_connector *connector, struct hdcp_workqueue *hdcp_w) +static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state, + struct drm_crtc_state *old_crtc_state, + struct drm_connector_state *new_conn_state, + struct drm_connector_state *old_conn_state, + const struct drm_connector *connector, + struct hdcp_workqueue *hdcp_w) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); - /* Handle: Type0/1 change */ - if (old_state->hdcp_content_type != state->hdcp_content_type && - state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + pr_debug("[HDCP_DM] connector->index: %x connect_status: %x dpms: %x\n", + connector->index, connector->status, connector->dpms); + pr_debug("[HDCP_DM] state protection old: %x new: %x\n", + old_conn_state->content_protection, new_conn_state->content_protection); + + if (old_crtc_state) + pr_debug("[HDCP_DM] old crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n", + old_crtc_state->enable, + old_crtc_state->active, + old_crtc_state->mode_changed, + old_crtc_state->active_changed, + old_crtc_state->connectors_changed); + + if (new_crtc_state) + pr_debug("[HDCP_DM] NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n", + new_crtc_state->enable, + new_crtc_state->active, + new_crtc_state->mode_changed, + new_crtc_state->active_changed, + new_crtc_state->connectors_changed); + + /* hdcp content type change */ + if (old_conn_state->hdcp_content_type != new_conn_state->hdcp_content_type && + new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + pr_debug("[HDCP_DM] Type0/1 change %s :true\n", __func__); return true; } - /* CP is being re enabled, ignore this - * - * Handles: ENABLED -> DESIRED - */ - if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED && - state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { - state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; + /* CP is being re enabled, ignore this */ + if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED && + new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { + if (new_crtc_state && new_crtc_state->mode_changed) { + new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + pr_debug("[HDCP_DM] ENABLED->DESIRED & mode_changed %s :true\n", __func__); + return true; + } + new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; + pr_debug("[HDCP_DM] ENABLED -> DESIRED %s :false\n", __func__); return false; } @@ -7391,9 +7445,9 @@ static bool is_content_protection_different(struct drm_connector_state *state, * * Handles: UNDESIRED -> ENABLED */ - if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED && - state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) - state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED && + new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) + new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; /* Stream removed and re-enabled * @@ -7403,10 +7457,12 @@ static bool is_content_protection_different(struct drm_connector_state *state, * * Handles: DESIRED -> DESIRED (Special case) */ - if (!(old_state->crtc && old_state->crtc->enabled) && - state->crtc && state->crtc->enabled && + if (!(old_conn_state->crtc && old_conn_state->crtc->enabled) && + new_conn_state->crtc && new_conn_state->crtc->enabled && connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { dm_con_state->update_hdcp = false; + pr_debug("[HDCP_DM] DESIRED->DESIRED (Stream removed and re-enabled) %s :true\n", + __func__); return true; } @@ -7418,35 +7474,42 @@ static bool is_content_protection_different(struct drm_connector_state *state, * * Handles: DESIRED -> DESIRED (Special case) */ - if (dm_con_state->update_hdcp && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && - connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) { + if (dm_con_state->update_hdcp && + new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && + connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) { dm_con_state->update_hdcp = false; + pr_debug("[HDCP_DM] DESIRED->DESIRED (Hot-plug, headless s3, dpms) %s :true\n", + __func__); return true; } - /* - * Handles: UNDESIRED -> UNDESIRED - * DESIRED -> DESIRED - * ENABLED -> ENABLED - */ - if (old_state->content_protection == state->content_protection) + if (old_conn_state->content_protection == new_conn_state->content_protection) { + if (new_conn_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED) { + if (new_crtc_state && new_crtc_state->mode_changed) { + pr_debug("[HDCP_DM] DESIRED->DESIRED or ENABLE->ENABLE mode_change %s :true\n", + __func__); + return true; + } + pr_debug("[HDCP_DM] DESIRED->DESIRED & ENABLE->ENABLE %s :false\n", + __func__); + return false; + } + + pr_debug("[HDCP_DM] UNDESIRED->UNDESIRED %s :false\n", __func__); return false; + } - /* - * Handles: UNDESIRED -> DESIRED - * DESIRED -> UNDESIRED - * ENABLED -> UNDESIRED - */ - if (state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) + if (new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) { + pr_debug("[HDCP_DM] UNDESIRED->DESIRED or DESIRED->UNDESIRED or ENABLED->UNDESIRED %s :true\n", + __func__); return true; + } - /* - * Handles: DESIRED -> ENABLED - */ + pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__); return false; } - #endif + static void remove_stream(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc, struct dc_stream_state *stream) @@ -7662,8 +7725,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_crtc *pcrtc, bool wait_for_vblank) { - uint32_t i; - uint64_t timestamp_ns; + u32 i; + u64 timestamp_ns; struct drm_plane *plane; struct drm_plane_state *old_plane_state, *new_plane_state; struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc); @@ -7674,7 +7737,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc)); int planes_count = 0, vpos, hpos; unsigned long flags; - uint32_t target_vblank, last_flip_vblank; + u32 target_vblank, last_flip_vblank; bool vrr_active = amdgpu_dm_vrr_active(acrtc_state); bool cursor_update = false; bool pflip_present = false; @@ -8112,7 +8175,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_display_manager *dm = &adev->dm; struct dm_atomic_state *dm_state; struct dc_state *dc_state = NULL, *dc_state_temp = NULL; - uint32_t i, j; + u32 i, j; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; unsigned long flags; @@ -8286,10 +8349,61 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i); + + if (!connector) + continue; + + pr_debug("[HDCP_DM] connector->index: %x connect_status: %x dpms: %x\n", + connector->index, connector->status, connector->dpms); + pr_debug("[HDCP_DM] state protection old: %x new: %x\n", + old_con_state->content_protection, new_con_state->content_protection); + + if (aconnector->dc_sink) { + if (aconnector->dc_sink->sink_signal != SIGNAL_TYPE_VIRTUAL && + aconnector->dc_sink->sink_signal != SIGNAL_TYPE_NONE) { + pr_debug("[HDCP_DM] pipe_ctx dispname=%s\n", + aconnector->dc_sink->edid_caps.display_name); + } + } + new_crtc_state = NULL; + old_crtc_state = NULL; - if (acrtc) + if (acrtc) { new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); + old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); + } + + if (old_crtc_state) + pr_debug("old crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n", + old_crtc_state->enable, + old_crtc_state->active, + old_crtc_state->mode_changed, + old_crtc_state->active_changed, + old_crtc_state->connectors_changed); + + if (new_crtc_state) + pr_debug("NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n", + new_crtc_state->enable, + new_crtc_state->active, + new_crtc_state->mode_changed, + new_crtc_state->active_changed, + new_crtc_state->connectors_changed); + } + + for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { + struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + + new_crtc_state = NULL; + old_crtc_state = NULL; + + if (acrtc) { + new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); + old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); + } dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); @@ -8301,11 +8415,44 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) continue; } - if (is_content_protection_different(new_con_state, old_con_state, connector, adev->dm.hdcp_workqueue)) + if (is_content_protection_different(new_crtc_state, old_crtc_state, new_con_state, + old_con_state, connector, adev->dm.hdcp_workqueue)) { + /* when display is unplugged from mst hub, connctor will + * be destroyed within dm_dp_mst_connector_destroy. connector + * hdcp perperties, like type, undesired, desired, enabled, + * will be lost. So, save hdcp properties into hdcp_work within + * amdgpu_dm_atomic_commit_tail. if the same display is + * plugged back with same display index, its hdcp properties + * will be retrieved from hdcp_work within dm_dp_mst_get_modes + */ + + bool enable_encryption = false; + + if (new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) + enable_encryption = true; + + if (aconnector->dc_link && aconnector->dc_sink && + aconnector->dc_link->type == dc_connection_mst_branch) { + struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; + struct hdcp_workqueue *hdcp_w = + &hdcp_work[aconnector->dc_link->link_index]; + + hdcp_w->hdcp_content_type[connector->index] = + new_con_state->hdcp_content_type; + hdcp_w->content_protection[connector->index] = + new_con_state->content_protection; + } + + if (new_crtc_state && new_crtc_state->mode_changed && + new_con_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED) + enable_encryption = true; + + DRM_INFO("[HDCP_DM] hdcp_update_display enable_encryption = %x\n", enable_encryption); + hdcp_update_display( adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, - new_con_state->hdcp_content_type, - new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED); + new_con_state->hdcp_content_type, enable_encryption); + } } #endif @@ -8403,9 +8550,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); #ifdef CONFIG_DEBUG_FS enum amdgpu_dm_pipe_crc_source cur_crc_src; -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - struct crc_rd_work *crc_rd_wrk; -#endif #endif /* Count number of newly disabled CRTCs for dropping PM refs later. */ if (old_crtc_state->active && !new_crtc_state->active) @@ -8418,9 +8562,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) update_stream_irq_parameters(dm, dm_new_crtc_state); #ifdef CONFIG_DEBUG_FS -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - crc_rd_wrk = dm->crc_rd_wrk; -#endif spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); cur_crc_src = acrtc->dm_irq_params.crc_src; spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); @@ -8449,10 +8590,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) if (amdgpu_dm_crc_window_is_activated(crtc)) { spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); acrtc->dm_irq_params.window_param.update_win = true; + + /** + * It takes 2 frames for HW to stably generate CRC when + * resuming from suspend, so we set skip_frame_cnt 2. + */ acrtc->dm_irq_params.window_param.skip_frame_cnt = 2; - spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock); - crc_rd_wrk->crtc = crtc; - spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); } #endif @@ -8675,15 +8818,22 @@ static void get_freesync_config_for_crtc( struct drm_display_mode *mode = &new_crtc_state->base.mode; int vrefresh = drm_mode_vrefresh(mode); bool fs_vid_mode = false; + bool drr_active = false; new_crtc_state->vrr_supported = new_con_state->freesync_capable && vrefresh >= aconnector->min_vfreq && vrefresh <= aconnector->max_vfreq; - if (new_crtc_state->vrr_supported) { + drr_active = new_crtc_state->vrr_supported && + new_crtc_state->freesync_config.state != VRR_STATE_DISABLED && + new_crtc_state->freesync_config.state != VRR_STATE_INACTIVE && + new_crtc_state->freesync_config.state != VRR_STATE_UNSUPPORTED; + + if (drr_active) new_crtc_state->stream->ignore_msa_timing_param = true; - fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED; + if (new_crtc_state->vrr_supported) { + fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED; config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000; config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000; config.vsif_supported = true; @@ -8743,7 +8893,7 @@ is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, } static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) { - uint64_t num, den, res; + u64 num, den, res; struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base; dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED; @@ -8846,7 +8996,8 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * TODO: Refactor this function to allow this check to work * in all conditions. */ - if (dm_new_crtc_state->stream && + if (amdgpu_freesync_vid_mode && + dm_new_crtc_state->stream && is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state)) goto skip_modeset; @@ -8881,7 +9032,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, if (!dm_old_crtc_state->stream) goto skip_modeset; - if (dm_new_crtc_state->stream && + if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream && is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state)) { new_crtc_state->mode_changed = false; @@ -8893,7 +9044,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, set_freesync_fixed_config(dm_new_crtc_state); goto skip_modeset; - } else if (aconnector && + } else if (amdgpu_freesync_vid_mode && aconnector && is_freesync_video_mode(&new_crtc_state->mode, aconnector)) { struct drm_display_mode *high_mode; @@ -9524,8 +9675,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } - if (dm_old_con_state->abm_level != - dm_new_con_state->abm_level) + if (dm_old_con_state->abm_level != dm_new_con_state->abm_level || + dm_old_con_state->scaling != dm_new_con_state->scaling) new_crtc_state->connectors_changed = true; } @@ -9879,7 +10030,7 @@ fail: static bool is_dp_capable_without_timing_msa(struct dc *dc, struct amdgpu_dm_connector *amdgpu_dm_connector) { - uint8_t dpcd_data; + u8 dpcd_data; bool capable = false; if (amdgpu_dm_connector->dc_link && @@ -9898,7 +10049,7 @@ static bool is_dp_capable_without_timing_msa(struct dc *dc, static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, unsigned int offset, unsigned int total_length, - uint8_t *data, + u8 *data, unsigned int length, struct amdgpu_hdmi_vsdb_info *vsdb) { @@ -9953,7 +10104,7 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, } static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, - uint8_t *edid_ext, int len, + u8 *edid_ext, int len, struct amdgpu_hdmi_vsdb_info *vsdb_info) { int i; @@ -9994,7 +10145,7 @@ static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, } static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm, - uint8_t *edid_ext, int len, + u8 *edid_ext, int len, struct amdgpu_hdmi_vsdb_info *vsdb_info) { int i; @@ -10010,7 +10161,7 @@ static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm, } static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, - uint8_t *edid_ext, int len, + u8 *edid_ext, int len, struct amdgpu_hdmi_vsdb_info *vsdb_info) { struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); @@ -10024,7 +10175,7 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) { - uint8_t *edid_ext = NULL; + u8 *edid_ext = NULL; int i; bool valid_vsdb_found = false; @@ -10200,7 +10351,7 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) } void dm_write_reg_func(const struct dc_context *ctx, uint32_t address, - uint32_t value, const char *func_name) + u32 value, const char *func_name) { #ifdef DM_CHECK_ADDR_0 if (address == 0) { @@ -10215,7 +10366,7 @@ void dm_write_reg_func(const struct dc_context *ctx, uint32_t address, uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address, const char *func_name) { - uint32_t value; + u32 value; #ifdef DM_CHECK_ADDR_0 if (address == 0) { DC_ERR("invalid register read; address = 0\n"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index df3c25e32c65..abbbb3813c1e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -494,11 +494,12 @@ struct amdgpu_display_manager { #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) /** - * @crc_rd_wrk: + * @secure_display_ctxs: * - * Work to be executed in a separate thread to communicate with PSP. + * Store the ROI information and the work_struct to command dmub and psp for + * all crtcs. */ - struct crc_rd_work *crc_rd_wrk; + struct secure_display_context *secure_display_ctxs; #endif /** * @hpd_rx_offload_wq: diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 66df2394d7e4..8873ecada27c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -101,35 +101,44 @@ static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc) static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work) { - struct crc_rd_work *crc_rd_wrk; - struct amdgpu_device *adev; + struct secure_display_context *secure_display_ctx; struct psp_context *psp; - struct securedisplay_cmd *securedisplay_cmd; + struct ta_securedisplay_cmd *securedisplay_cmd; struct drm_crtc *crtc; - uint8_t phy_id; + struct dc_stream_state *stream; + uint8_t phy_inst; int ret; - crc_rd_wrk = container_of(work, struct crc_rd_work, notify_ta_work); - spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock); - crtc = crc_rd_wrk->crtc; + secure_display_ctx = container_of(work, struct secure_display_context, notify_ta_work); + crtc = secure_display_ctx->crtc; if (!crtc) { - spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); return; } - adev = drm_to_adev(crtc->dev); - psp = &adev->psp; - phy_id = crc_rd_wrk->phy_inst; - spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); + psp = &drm_to_adev(crtc->dev)->psp; + + if (!psp->securedisplay_context.context.initialized) { + DRM_DEBUG_DRIVER("Secure Display fails to notify PSP TA\n"); + return; + } + + stream = to_amdgpu_crtc(crtc)->dm_irq_params.stream; + phy_inst = stream->link->link_enc_hw_inst; + /* need lock for multiple crtcs to use the command buffer */ mutex_lock(&psp->securedisplay_context.mutex); psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC); - securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = - phy_id; + + securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = phy_inst; + + /* PSP TA is expected to finish data transmission over I2C within current frame, + * even there are up to 4 crtcs request to send in this frame. + */ ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC); + if (!ret) { if (securedisplay_cmd->status != TA_SECUREDISPLAY_STATUS__SUCCESS) { psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); @@ -142,17 +151,23 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work) static void amdgpu_dm_forward_crc_window(struct work_struct *work) { - struct crc_fw_work *crc_fw_wrk; + struct secure_display_context *secure_display_ctx; struct amdgpu_display_manager *dm; + struct drm_crtc *crtc; + struct dc_stream_state *stream; - crc_fw_wrk = container_of(work, struct crc_fw_work, forward_roi_work); - dm = crc_fw_wrk->dm; + secure_display_ctx = container_of(work, struct secure_display_context, forward_roi_work); + crtc = secure_display_ctx->crtc; + + if (!crtc) + return; + + dm = &drm_to_adev(crtc->dev)->dm; + stream = to_amdgpu_crtc(crtc)->dm_irq_params.stream; mutex_lock(&dm->dc_lock); - dc_stream_forward_crc_window(dm->dc, &crc_fw_wrk->rect, crc_fw_wrk->stream, crc_fw_wrk->is_stop_cmd); + dc_stream_forward_crc_window(stream, &secure_display_ctx->rect, false); mutex_unlock(&dm->dc_lock); - - kfree(crc_fw_wrk); } bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc) @@ -189,6 +204,9 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, struct dm_crtc_state *dm_crtc_state, enum amdgpu_dm_pipe_crc_source source) { +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + int i; +#endif struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc_stream_state *stream_state = dm_crtc_state->stream; bool enable = amdgpu_dm_is_valid_crc_source(source); @@ -200,21 +218,18 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, mutex_lock(&adev->dm.dc_lock); - /* Enable CRTC CRC generation if necessary. */ + /* Enable or disable CRTC CRC generation */ if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) { #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + /* Disable secure_display if it was enabled */ if (!enable) { - if (adev->dm.crc_rd_wrk) { - flush_work(&adev->dm.crc_rd_wrk->notify_ta_work); - spin_lock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock); - - if (adev->dm.crc_rd_wrk->crtc == crtc) { + for (i = 0; i < adev->mode_info.num_crtc; i++) { + if (adev->dm.secure_display_ctxs[i].crtc == crtc) { /* stop ROI update on this crtc */ - dc_stream_forward_crc_window(stream_state->ctx->dc, - NULL, stream_state, true); - adev->dm.crc_rd_wrk->crtc = NULL; + flush_work(&adev->dm.secure_display_ctxs[i].notify_ta_work); + flush_work(&adev->dm.secure_display_ctxs[i].forward_roi_work); + dc_stream_forward_crc_window(stream_state, NULL, true); } - spin_unlock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock); } } #endif @@ -347,6 +362,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) } #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + /* Reset secure_display when we change crc source from debugfs */ amdgpu_dm_set_crc_window_default(crtc); #endif @@ -456,14 +472,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc) #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) { - struct dc_stream_state *stream_state; struct drm_device *drm_dev = NULL; enum amdgpu_dm_pipe_crc_source cur_crc_src; struct amdgpu_crtc *acrtc = NULL; struct amdgpu_device *adev = NULL; - struct crc_rd_work *crc_rd_wrk; - struct crc_fw_work *crc_fw_wrk; - unsigned long flags1, flags2; + struct secure_display_context *secure_display_ctx = NULL; + unsigned long flags1; if (crtc == NULL) return; @@ -473,75 +487,76 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) drm_dev = crtc->dev; spin_lock_irqsave(&drm_dev->event_lock, flags1); - stream_state = acrtc->dm_irq_params.stream; cur_crc_src = acrtc->dm_irq_params.crc_src; /* Early return if CRC capture is not enabled. */ - if (!amdgpu_dm_is_valid_crc_source(cur_crc_src)) + if (!amdgpu_dm_is_valid_crc_source(cur_crc_src) || + !dm_is_crc_source_crtc(cur_crc_src)) goto cleanup; - if (!dm_is_crc_source_crtc(cur_crc_src)) + if (!acrtc->dm_irq_params.window_param.activated) goto cleanup; - if (!acrtc->dm_irq_params.window_param.activated) + if (acrtc->dm_irq_params.window_param.skip_frame_cnt) { + acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1; goto cleanup; + } - if (acrtc->dm_irq_params.window_param.update_win) { - if (acrtc->dm_irq_params.window_param.skip_frame_cnt) { - acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1; - goto cleanup; - } + secure_display_ctx = &adev->dm.secure_display_ctxs[acrtc->crtc_id]; + if (WARN_ON(secure_display_ctx->crtc != crtc)) { + /* We have set the crtc when creating secure_display_context, + * don't expect it to be changed here. + */ + secure_display_ctx->crtc = crtc; + } + if (acrtc->dm_irq_params.window_param.update_win) { /* prepare work for dmub to update ROI */ - crc_fw_wrk = kzalloc(sizeof(*crc_fw_wrk), GFP_ATOMIC); - if (!crc_fw_wrk) - goto cleanup; - - INIT_WORK(&crc_fw_wrk->forward_roi_work, amdgpu_dm_forward_crc_window); - crc_fw_wrk->dm = &adev->dm; - crc_fw_wrk->stream = stream_state; - crc_fw_wrk->rect.x = acrtc->dm_irq_params.window_param.x_start; - crc_fw_wrk->rect.y = acrtc->dm_irq_params.window_param.y_start; - crc_fw_wrk->rect.width = acrtc->dm_irq_params.window_param.x_end - + secure_display_ctx->rect.x = acrtc->dm_irq_params.window_param.x_start; + secure_display_ctx->rect.y = acrtc->dm_irq_params.window_param.y_start; + secure_display_ctx->rect.width = acrtc->dm_irq_params.window_param.x_end - acrtc->dm_irq_params.window_param.x_start; - crc_fw_wrk->rect.height = acrtc->dm_irq_params.window_param.y_end - + secure_display_ctx->rect.height = acrtc->dm_irq_params.window_param.y_end - acrtc->dm_irq_params.window_param.y_start; - schedule_work(&crc_fw_wrk->forward_roi_work); + schedule_work(&secure_display_ctx->forward_roi_work); acrtc->dm_irq_params.window_param.update_win = false; + + /* Statically skip 1 frame, because we may need to wait below things + * before sending ROI to dmub: + * 1. We defer the work by using system workqueue. + * 2. We may need to wait for dc_lock before accessing dmub. + */ acrtc->dm_irq_params.window_param.skip_frame_cnt = 1; } else { - if (acrtc->dm_irq_params.window_param.skip_frame_cnt) { - acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1; - goto cleanup; - } - - if (adev->dm.crc_rd_wrk) { - crc_rd_wrk = adev->dm.crc_rd_wrk; - spin_lock_irqsave(&crc_rd_wrk->crc_rd_work_lock, flags2); - crc_rd_wrk->phy_inst = stream_state->link->link_enc_hw_inst; - spin_unlock_irqrestore(&crc_rd_wrk->crc_rd_work_lock, flags2); - schedule_work(&crc_rd_wrk->notify_ta_work); - } + /* prepare work for psp to read ROI/CRC and send to I2C */ + schedule_work(&secure_display_ctx->notify_ta_work); } cleanup: spin_unlock_irqrestore(&drm_dev->event_lock, flags1); } -struct crc_rd_work *amdgpu_dm_crtc_secure_display_create_work(void) +struct secure_display_context * +amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device *adev) { - struct crc_rd_work *crc_rd_wrk = NULL; + struct secure_display_context *secure_display_ctxs = NULL; + int i; - crc_rd_wrk = kzalloc(sizeof(*crc_rd_wrk), GFP_KERNEL); + secure_display_ctxs = kcalloc(adev->mode_info.num_crtc, + sizeof(struct secure_display_context), + GFP_KERNEL); - if (!crc_rd_wrk) + if (!secure_display_ctxs) return NULL; - spin_lock_init(&crc_rd_wrk->crc_rd_work_lock); - INIT_WORK(&crc_rd_wrk->notify_ta_work, amdgpu_dm_crtc_notify_ta_to_read); + for (i = 0; i < adev->mode_info.num_crtc; i++) { + INIT_WORK(&secure_display_ctxs[i].forward_roi_work, amdgpu_dm_forward_crc_window); + INIT_WORK(&secure_display_ctxs[i].notify_ta_work, amdgpu_dm_crtc_notify_ta_to_read); + secure_display_ctxs[i].crtc = &adev->mode_info.crtcs[i]->base; + } - return crc_rd_wrk; + return secure_display_ctxs; } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h index 71bce608d751..935adca6f048 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -45,7 +45,7 @@ struct crc_window_param { uint16_t y_start; uint16_t x_end; uint16_t y_end; - /* CRC windwo is activated or not*/ + /* CRC window is activated or not*/ bool activated; /* Update crc window during vertical blank or not */ bool update_win; @@ -53,22 +53,17 @@ struct crc_window_param { int skip_frame_cnt; }; -/* read_work for driver to call PSP to read */ -struct crc_rd_work { +struct secure_display_context { + /* work to notify PSP TA*/ struct work_struct notify_ta_work; - /* To protect crc_rd_work carried fields*/ - spinlock_t crc_rd_work_lock; - struct drm_crtc *crtc; - uint8_t phy_inst; -}; -/* forward_work for driver to forward ROI to dmu */ -struct crc_fw_work { + /* work to forward ROI to dmcu/dmub */ struct work_struct forward_roi_work; - struct amdgpu_display_manager *dm; - struct dc_stream_state *stream; + + struct drm_crtc *crtc; + + /* Region of Interest (ROI) */ struct rect rect; - bool is_stop_cmd; }; #endif @@ -100,11 +95,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc); void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc); -struct crc_rd_work *amdgpu_dm_crtc_secure_display_create_work(void); +struct secure_display_context *amdgpu_dm_crtc_secure_display_create_contexts( + struct amdgpu_device *adev); #else #define amdgpu_dm_crc_window_is_activated(x) #define amdgpu_dm_crtc_handle_crc_window_irq(x) -#define amdgpu_dm_crtc_secure_display_create_work() +#define amdgpu_dm_crtc_secure_display_create_contexts() #endif #endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 22125daf9dcf..1e39d0939700 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -105,8 +105,7 @@ static void vblank_control_worker(struct work_struct *work) else if (dm->active_vblank_irq_count) dm->active_vblank_irq_count--; - dc_allow_idle_optimizations( - dm->dc, dm->active_vblank_irq_count == 0 ? true : false); + dc_allow_idle_optimizations(dm->dc, dm->active_vblank_irq_count == 0); DRM_DEBUG_KMS("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 461037a3dd75..704860e6ba84 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -35,6 +35,7 @@ #include "resource.h" #include "dsc.h" #include "dc_link_dp.h" +#include "dc_link.h" #include "link_hwss.h" #include "dc/dc_dmub_srv.h" @@ -1375,16 +1376,11 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -1481,12 +1477,12 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx || !pipe_ctx->stream) + if (!pipe_ctx->stream) goto done; // Get CRTC state @@ -1566,16 +1562,11 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -1670,12 +1661,12 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx || !pipe_ctx->stream) + if (!pipe_ctx->stream) goto done; // Safely get CRTC state @@ -1755,16 +1746,11 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -1859,12 +1845,12 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx || !pipe_ctx->stream) + if (!pipe_ctx->stream) goto done; // Get CRTC state @@ -1940,16 +1926,11 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -2041,12 +2022,12 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx || !pipe_ctx->stream) + if (!pipe_ctx->stream) goto done; // Get CRTC state @@ -2120,16 +2101,11 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -2181,16 +2157,11 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -2257,16 +2228,11 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -2333,16 +2299,11 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && + if (pipe_ctx->stream && pipe_ctx->stream->link == aconnector->dc_link) break; } - if (!pipe_ctx) { - kfree(rd_buf); - return -ENXIO; - } - dsc = pipe_ctx->stream_res.dsc; if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); @@ -3245,46 +3206,24 @@ DEFINE_DEBUGFS_ATTRIBUTE(crc_win_y_end_fops, crc_win_y_end_get, */ static int crc_win_update_set(void *data, u64 val) { - struct drm_crtc *new_crtc = data; - struct drm_crtc *old_crtc = NULL; - struct amdgpu_crtc *new_acrtc, *old_acrtc; - struct amdgpu_device *adev = drm_to_adev(new_crtc->dev); - struct crc_rd_work *crc_rd_wrk = adev->dm.crc_rd_wrk; - - if (!crc_rd_wrk) - return 0; + struct drm_crtc *crtc = data; + struct amdgpu_crtc *acrtc; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); if (val) { - new_acrtc = to_amdgpu_crtc(new_crtc); + acrtc = to_amdgpu_crtc(crtc); mutex_lock(&adev->dm.dc_lock); /* PSR may write to OTG CRC window control register, * so close it before starting secure_display. */ - amdgpu_dm_psr_disable(new_acrtc->dm_irq_params.stream); + amdgpu_dm_psr_disable(acrtc->dm_irq_params.stream); spin_lock_irq(&adev_to_drm(adev)->event_lock); - spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock); - if (crc_rd_wrk->crtc) { - old_crtc = crc_rd_wrk->crtc; - old_acrtc = to_amdgpu_crtc(old_crtc); - } - if (old_crtc && old_crtc != new_crtc) { - old_acrtc->dm_irq_params.window_param.activated = false; - old_acrtc->dm_irq_params.window_param.update_win = false; - old_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; + acrtc->dm_irq_params.window_param.activated = true; + acrtc->dm_irq_params.window_param.update_win = true; + acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; - new_acrtc->dm_irq_params.window_param.activated = true; - new_acrtc->dm_irq_params.window_param.update_win = true; - new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; - crc_rd_wrk->crtc = new_crtc; - } else { - new_acrtc->dm_irq_params.window_param.activated = true; - new_acrtc->dm_irq_params.window_param.update_win = true; - new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; - crc_rd_wrk->crtc = new_crtc; - } - spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); spin_unlock_irq(&adev_to_drm(adev)->event_lock); mutex_unlock(&adev->dm.dc_lock); } @@ -3457,7 +3396,7 @@ static int trigger_hpd_mst_set(void *data, u64 val) continue; link = aconnector->dc_link; - dp_receiver_power_ctrl(link, false); + dc_link_dp_receiver_power_ctrl(link, false); drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_port->mst_mgr, false); link->mst_stream_alloc_table.stream_count = 0; memset(link->mst_stream_alloc_table.stream_allocations, 0, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index a7fd98f57f94..8e572f07ec47 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -170,9 +170,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, struct mod_hdcp_display *display = &hdcp_work[link_index].display; struct mod_hdcp_link *link = &hdcp_work[link_index].link; struct mod_hdcp_display_query query; + unsigned int conn_index = aconnector->base.index; mutex_lock(&hdcp_w->mutex); - hdcp_w->aconnector = aconnector; + hdcp_w->aconnector[conn_index] = aconnector; query.display = NULL; mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query); @@ -204,7 +205,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS)); } else { display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION; - hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; cancel_delayed_work(&hdcp_w->property_validate_dwork); } @@ -223,9 +224,10 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, { struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; struct drm_connector_state *conn_state = aconnector->base.state; + unsigned int conn_index = aconnector->base.index; mutex_lock(&hdcp_w->mutex); - hdcp_w->aconnector = aconnector; + hdcp_w->aconnector[conn_index] = aconnector; /* the removal of display will invoke auth reset -> hdcp destroy and * we'd expect the Content Protection (CP) property changed back to @@ -247,13 +249,18 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index) { struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; + unsigned int conn_index; mutex_lock(&hdcp_w->mutex); mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output); cancel_delayed_work(&hdcp_w->property_validate_dwork); - hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) { + hdcp_w->encryption_status[conn_index] = + MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + } process_output(hdcp_w); @@ -290,49 +297,80 @@ static void event_callback(struct work_struct *work) } + static void event_property_update(struct work_struct *work) { - struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue, property_update_work); - struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector; - struct drm_device *dev = hdcp_work->aconnector->base.dev; + struct amdgpu_dm_connector *aconnector = NULL; + struct drm_device *dev; long ret; + unsigned int conn_index; + struct drm_connector *connector; + struct drm_connector_state *conn_state; - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - mutex_lock(&hdcp_work->mutex); + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) { + aconnector = hdcp_work->aconnector[conn_index]; + if (!aconnector) + continue; - if (aconnector->base.state && aconnector->base.state->commit) { - ret = wait_for_completion_interruptible_timeout(&aconnector->base.state->commit->hw_done, 10 * HZ); + connector = &aconnector->base; - if (ret == 0) { - DRM_ERROR("HDCP state unknown! Setting it to DESIRED"); - hdcp_work->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; - } - } + /* check if display connected */ + if (connector->status != connector_status_connected) + continue; - if (aconnector->base.state) { - if (hdcp_work->encryption_status != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) { - if (aconnector->base.state->hdcp_content_type == + conn_state = aconnector->base.state; + + if (!conn_state) + continue; + + dev = connector->dev; + + if (!dev) + continue; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&hdcp_work->mutex); + + if (conn_state->commit) { + ret = wait_for_completion_interruptible_timeout( + &conn_state->commit->hw_done, 10 * HZ); + if (ret == 0) { + DRM_ERROR( + "HDCP state unknown! Setting it to DESIRED"); + hdcp_work->encryption_status[conn_index] = + MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + } + } + if (hdcp_work->encryption_status[conn_index] != + MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) { + if (conn_state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 && - hdcp_work->encryption_status <= - MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) - drm_hdcp_update_content_protection(&aconnector->base, + hdcp_work->encryption_status[conn_index] <= + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) { + + DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_ENABLED\n"); + drm_hdcp_update_content_protection( + connector, DRM_MODE_CONTENT_PROTECTION_ENABLED); - else if (aconnector->base.state->hdcp_content_type == + } else if (conn_state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE1 && - hdcp_work->encryption_status == - MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) - drm_hdcp_update_content_protection(&aconnector->base, + hdcp_work->encryption_status[conn_index] == + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) { + drm_hdcp_update_content_protection( + connector, DRM_MODE_CONTENT_PROTECTION_ENABLED); + } } else { - drm_hdcp_update_content_protection(&aconnector->base, - DRM_MODE_CONTENT_PROTECTION_DESIRED); + DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n"); + drm_hdcp_update_content_protection( + connector, DRM_MODE_CONTENT_PROTECTION_DESIRED); + } + mutex_unlock(&hdcp_work->mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); } - - mutex_unlock(&hdcp_work->mutex); - drm_modeset_unlock(&dev->mode_config.connection_mutex); } static void event_property_validate(struct work_struct *work) @@ -340,19 +378,47 @@ static void event_property_validate(struct work_struct *work) struct hdcp_workqueue *hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue, property_validate_dwork); struct mod_hdcp_display_query query; - struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector; - - if (!aconnector) - return; + struct amdgpu_dm_connector *aconnector; + unsigned int conn_index; mutex_lock(&hdcp_work->mutex); - query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; - mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, &query); + for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; + conn_index++) { + aconnector = hdcp_work->aconnector[conn_index]; + + if (!aconnector) + continue; + + /* check if display connected */ + if (aconnector->base.status != connector_status_connected) + continue; - if (query.encryption_status != hdcp_work->encryption_status) { - hdcp_work->encryption_status = query.encryption_status; - schedule_work(&hdcp_work->property_update_work); + if (!aconnector->base.state) + continue; + + query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, + &query); + + DRM_DEBUG_DRIVER("[HDCP_DM] disp %d, connector->CP %u, (query, work): (%d, %d)\n", + aconnector->base.index, + aconnector->base.state->content_protection, + query.encryption_status, + hdcp_work->encryption_status[conn_index]); + + if (query.encryption_status != + hdcp_work->encryption_status[conn_index]) { + DRM_DEBUG_DRIVER("[HDCP_DM] encryption_status change from %x to %x\n", + hdcp_work->encryption_status[conn_index], query.encryption_status); + + hdcp_work->encryption_status[conn_index] = + query.encryption_status; + + DRM_DEBUG_DRIVER("[HDCP_DM] trigger property_update_work\n"); + + schedule_work(&hdcp_work->property_update_work); + } } mutex_unlock(&hdcp_work->mutex); @@ -686,6 +752,13 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c; hdcp_work[i].hdcp.config.ddc.funcs.write_dpcd = lp_write_dpcd; hdcp_work[i].hdcp.config.ddc.funcs.read_dpcd = lp_read_dpcd; + + memset(hdcp_work[i].aconnector, 0, + sizeof(struct amdgpu_dm_connector *) * + AMDGPU_DM_MAX_DISPLAY_INDEX); + memset(hdcp_work[i].encryption_status, 0, + sizeof(enum mod_hdcp_encryption_status) * + AMDGPU_DM_MAX_DISPLAY_INDEX); } cp_psp->funcs.update_stream_config = update_config; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h index 09294ff122fe..69b445b011c8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h @@ -43,7 +43,7 @@ struct hdcp_workqueue { struct delayed_work callback_dwork; struct delayed_work watchdog_timer_dwork; struct delayed_work property_validate_dwork; - struct amdgpu_dm_connector *aconnector; + struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_INDEX]; struct mutex mutex; struct mod_hdcp hdcp; @@ -51,7 +51,20 @@ struct hdcp_workqueue { struct mod_hdcp_display display; struct mod_hdcp_link link; - enum mod_hdcp_encryption_status encryption_status; + enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX]; + /* when display is unplugged from mst hub, connctor will be + * destroyed within dm_dp_mst_connector_destroy. connector + * hdcp perperties, like type, undesired, desired, enabled, + * will be lost. So, save hdcp properties into hdcp_work within + * amdgpu_dm_atomic_commit_tail. if the same display is + * plugged back with same display index, its hdcp properties + * will be retrieved from hdcp_work within dm_dp_mst_get_modes + */ + /* un-desired, desired, enabled */ + unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_INDEX]; + /* hdcp1.x, hdcp2.x */ + unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_INDEX]; + uint8_t max_link; uint8_t *srm; 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 1edf7385f8d8..5fa9bab95038 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 @@ -32,15 +32,17 @@ #include "amdgpu_dm.h" #include "amdgpu_dm_mst_types.h" +#ifdef CONFIG_DRM_AMD_DC_HDCP +#include "amdgpu_dm_hdcp.h" +#endif + #include "dc.h" #include "dm_helpers.h" -#include "dc_link_ddc.h" #include "dc_link_dp.h" #include "ddc_service_types.h" #include "dpcd_defs.h" -#include "i2caux_interface.h" #include "dmub_cmd.h" #if defined(CONFIG_DEBUG_FS) #include "amdgpu_dm_debugfs.h" @@ -344,6 +346,28 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) /* dc_link_add_remote_sink returns a new reference */ aconnector->dc_sink = dc_sink; + /* when display is unplugged from mst hub, connctor will be + * destroyed within dm_dp_mst_connector_destroy. connector + * hdcp perperties, like type, undesired, desired, enabled, + * will be lost. So, save hdcp properties into hdcp_work within + * amdgpu_dm_atomic_commit_tail. if the same display is + * plugged back with same display index, its hdcp properties + * will be retrieved from hdcp_work within dm_dp_mst_get_modes + */ +#ifdef CONFIG_DRM_AMD_DC_HDCP + if (aconnector->dc_sink && connector->state) { + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; + struct hdcp_workqueue *hdcp_w = &hdcp_work[aconnector->dc_link->link_index]; + + connector->state->hdcp_content_type = + hdcp_w->hdcp_content_type[connector->index]; + connector->state->content_protection = + hdcp_w->content_protection[connector->index]; + } +#endif + if (aconnector->dc_sink) { amdgpu_dm_update_freesync_caps( connector, aconnector->edid); @@ -468,7 +492,6 @@ static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); - kfree(encoder); } static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index 26291db0a3cf..872d06fe1436 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -122,6 +122,9 @@ bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream) psr_config.allow_multi_disp_optimizations = (amdgpu_dc_feature_mask & DC_PSR_ALLOW_MULTI_DISP_OPT); + if (!psr_su_set_y_granularity(dc, link, stream, &psr_config)) + return false; + ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context); } diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index b9effadfc4bb..98c508313350 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -64,9 +64,9 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI include $(AMD_DC) -DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \ -dc_surface.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \ -dc_link_enc_cfg.o dc_link_dpia.o dc_link_dpcd.o +DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \ +dc_surface.o dc_link_dp.o dc_debug.o dc_stream.o \ +dc_link_enc_cfg.o DISPLAY_CORE += dc_vm_helper.o diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index a1a00f432168..27af9d3c2b73 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -33,7 +33,6 @@ #include "include/gpio_service_interface.h" #include "include/grph_object_ctrl_defs.h" #include "include/bios_parser_interface.h" -#include "include/i2caux_interface.h" #include "include/logger_interface.h" #include "command_table.h" diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 074e70a5c458..e381de2429fa 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -32,7 +32,6 @@ #include "dc_bios_types.h" #include "include/grph_object_ctrl_defs.h" #include "include/bios_parser_interface.h" -#include "include/i2caux_interface.h" #include "include/logger_interface.h" #include "command_table2.h" @@ -1698,14 +1697,15 @@ static enum bp_result bios_parser_enable_disp_power_gating( static enum bp_result bios_parser_enable_lvtma_control( struct dc_bios *dcb, uint8_t uc_pwr_on, - uint8_t panel_instance) + uint8_t panel_instance, + uint8_t bypass_panel_control_wait) { struct bios_parser *bp = BP_FROM_DCB(dcb); if (!bp->cmd_tbl.enable_lvtma_control) return BP_RESULT_FAILURE; - return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance); + return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance, bypass_panel_control_wait); } static bool bios_parser_is_accelerated_mode( @@ -2929,7 +2929,6 @@ static enum bp_result construct_integrated_info( struct atom_common_table_header *header; struct atom_data_revision revision; - struct clock_voltage_caps temp = {0, 0}; uint32_t i; uint32_t j; @@ -3032,14 +3031,8 @@ static enum bp_result construct_integrated_info( for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { for (j = i; j > 0; --j) { if (info->disp_clk_voltage[j].max_supported_clk < - info->disp_clk_voltage[j-1].max_supported_clk - ) { - /* swap j and j - 1*/ - temp = info->disp_clk_voltage[j-1]; - info->disp_clk_voltage[j-1] = - info->disp_clk_voltage[j]; - info->disp_clk_voltage[j] = temp; - } + info->disp_clk_voltage[j-1].max_supported_clk) + swap(info->disp_clk_voltage[j-1], info->disp_clk_voltage[j]); } } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index f52f7ff7ead4..1ef9e4053bb7 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -986,7 +986,8 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) static enum bp_result enable_lvtma_control( struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance); + uint8_t panel_instance, + uint8_t bypass_panel_control_wait); static void init_enable_lvtma_control(struct bios_parser *bp) { @@ -998,7 +999,8 @@ static void init_enable_lvtma_control(struct bios_parser *bp) static void enable_lvtma_control_dmcub( struct dc_dmub_srv *dmcub, uint8_t uc_pwr_on, - uint8_t panel_instance) + uint8_t panel_instance, + uint8_t bypass_panel_control_wait) { union dmub_rb_cmd cmd; @@ -1012,6 +1014,8 @@ static void enable_lvtma_control_dmcub( uc_pwr_on; cmd.lvtma_control.data.panel_inst = panel_instance; + cmd.lvtma_control.data.bypass_panel_control_wait = + bypass_panel_control_wait; dc_dmub_srv_cmd_queue(dmcub, &cmd); dc_dmub_srv_cmd_execute(dmcub); dc_dmub_srv_wait_idle(dmcub); @@ -1021,7 +1025,8 @@ static void enable_lvtma_control_dmcub( static enum bp_result enable_lvtma_control( struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance) + uint8_t panel_instance, + uint8_t bypass_panel_control_wait) { enum bp_result result = BP_RESULT_FAILURE; @@ -1029,7 +1034,8 @@ static enum bp_result enable_lvtma_control( bp->base.ctx->dc->debug.dmub_command_table) { enable_lvtma_control_dmcub(bp->base.ctx->dmub_srv, uc_pwr_on, - panel_instance); + panel_instance, + bypass_panel_control_wait); return BP_RESULT_OK; } return result; diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h index be060b4b87db..b6d09bf6cf72 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h @@ -96,7 +96,8 @@ struct cmd_tbl { struct bios_parser *bp, uint8_t id); enum bp_result (*enable_lvtma_control)(struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance); + uint8_t panel_instance, + uint8_t bypass_panel_control_wait); }; void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c index 3ce0ee0d012f..694a9d3d92ae 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c @@ -577,8 +577,7 @@ void dcn3_clk_mgr_construct( void dcn3_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr) { - if (clk_mgr->base.bw_params) - kfree(clk_mgr->base.bw_params); + kfree(clk_mgr->base.bw_params); if (clk_mgr->wm_range_table) dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c index f47cfe6b42bd..0765334f0825 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c @@ -146,6 +146,9 @@ static int dcn314_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu && param == TABLE_WATERMARKS) DC_LOG_WARNING("Watermarks table not configured properly by SMU"); + else if (msg_id == VBIOSSMC_MSG_SetHardMinDcfclkByFreq || + msg_id == VBIOSSMC_MSG_SetMinDeepSleepDcfclk) + DC_LOG_WARNING("DCFCLK_DPM is not enabled by BIOS"); else ASSERT(0); REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index 200fcec19186..352c977d1495 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -34,6 +34,7 @@ #include "core_types.h" #include "dm_helpers.h" #include "dc_link_dp.h" +#include "link.h" #include "atomfirmware.h" #include "smu13_driver_if.h" @@ -255,6 +256,94 @@ static void dcn32_update_dppclk_dispclk_freq(struct clk_mgr_internal *clk_mgr, s } } +static void dcn32_update_clocks_update_dentist( + struct clk_mgr_internal *clk_mgr, + struct dc_state *context, + uint32_t old_dispclk_khz) +{ + uint32_t new_disp_divider = 0; + uint32_t old_disp_divider = 0; + uint32_t new_dispclk_wdivider = 0; + uint32_t old_dispclk_wdivider = 0; + uint32_t i; + + if (old_dispclk_khz == 0 || clk_mgr->base.clks.dispclk_khz == 0) + return; + + new_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz; + old_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->base.dentist_vco_freq_khz / old_dispclk_khz; + + new_dispclk_wdivider = dentist_get_did_from_divider(new_disp_divider); + old_dispclk_wdivider = dentist_get_did_from_divider(old_disp_divider); + + /* When changing divider to or from 127, some extra programming is required to prevent corruption */ + if (old_dispclk_wdivider == 127 && new_dispclk_wdivider != 127) { + for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + uint32_t fifo_level; + struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + int32_t N; + int32_t j; + + if (!pipe_ctx->stream) + continue; + /* Virtual encoders don't have this function */ + if (!stream_enc->funcs->get_fifo_cal_average_level) + continue; + fifo_level = stream_enc->funcs->get_fifo_cal_average_level( + stream_enc); + N = fifo_level / 4; + dccg->funcs->set_fifo_errdet_ovr_en( + dccg, + true); + for (j = 0; j < N - 4; j++) + dccg->funcs->otg_drop_pixel( + dccg, + pipe_ctx->stream_res.tg->inst); + dccg->funcs->set_fifo_errdet_ovr_en( + dccg, + false); + } + } else if (new_dispclk_wdivider == 127 && old_dispclk_wdivider != 127) { + /* request clock with 126 divider first */ + uint32_t temp_disp_divider = dentist_get_divider_from_did(126); + uint32_t temp_dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / temp_disp_divider; + + if (clk_mgr->smu_present) + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(temp_dispclk_khz)); + + for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + uint32_t fifo_level; + int32_t N; + int32_t j; + + if (!pipe_ctx->stream) + continue; + /* Virtual encoders don't have this function */ + if (!stream_enc->funcs->get_fifo_cal_average_level) + continue; + fifo_level = stream_enc->funcs->get_fifo_cal_average_level( + stream_enc); + N = fifo_level / 4; + dccg->funcs->set_fifo_errdet_ovr_en(dccg, true); + for (j = 0; j < 12 - N; j++) + dccg->funcs->otg_add_pixel(dccg, + pipe_ctx->stream_res.tg->inst); + dccg->funcs->set_fifo_errdet_ovr_en(dccg, false); + } + } + + /* do requested DISPCLK updates*/ + if (clk_mgr->smu_present) + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr->base.clks.dispclk_khz)); +} + static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool safe_to_lower) @@ -273,6 +362,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, bool p_state_change_support; bool fclk_p_state_change_support; int total_plane_count; + int old_dispclk_khz = clk_mgr_base->clks.dispclk_khz; if (dc->work_arounds.skip_clock_update) return; @@ -396,9 +486,6 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; - if (clk_mgr->smu_present) - dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz)); - update_dispclk = true; } @@ -418,13 +505,13 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, if (dpp_clock_lowered) { /* if clock is being lowered, increase DTO before lowering refclk */ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); - dcn20_update_clocks_update_dentist(clk_mgr, context); + dcn32_update_clocks_update_dentist(clk_mgr, context, old_dispclk_khz); if (clk_mgr->smu_present) dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz)); } else { /* if clock is being raised, increase refclk before lowering DTO */ if (update_dppclk || update_dispclk) - dcn20_update_clocks_update_dentist(clk_mgr, context); + dcn32_update_clocks_update_dentist(clk_mgr, context, old_dispclk_khz); /* There is a check inside dcn20_update_clocks_update_dpp_dto which ensures * that we do not lower dto when it is not safe to lower. We do not need to * compare the current and new dppclk before calling this function. @@ -783,8 +870,7 @@ void dcn32_clk_mgr_construct( void dcn32_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr) { - if (clk_mgr->base.bw_params) - kfree(clk_mgr->base.bw_params); + kfree(clk_mgr->base.bw_params); if (clk_mgr->wm_range_table) dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 0cb8d1f934d1..53e586fc1501 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -33,6 +33,7 @@ #include "resource.h" +#include "gpio_service_interface.h" #include "clk_mgr.h" #include "clock_source.h" #include "dc_bios_types.h" @@ -53,7 +54,7 @@ #include "link_enc_cfg.h" #include "dc_link.h" -#include "dc_link_ddc.h" +#include "link.h" #include "dm_helpers.h" #include "mem_input.h" @@ -68,8 +69,6 @@ #include "dmub/dmub_srv.h" -#include "i2caux_interface.h" - #include "dce/dmub_psr.h" #include "dce/dmub_hw_lock_mgr.h" @@ -382,16 +381,18 @@ static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace) } /** - * dc_stream_adjust_vmin_vmax: + * dc_stream_adjust_vmin_vmax - look up pipe context & update parts of DRR + * @dc: dc reference + * @stream: Initial dc stream state + * @adjust: Updated parameters for vertical_total_min and vertical_total_max * * Looks up the pipe context of dc_stream_state and updates the * vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh * Rate, which is a power-saving feature that targets reducing panel * refresh rate while the screen is static * - * @dc: dc reference - * @stream: Initial dc stream state - * @adjust: Updated parameters for vertical_total_min and vertical_total_max + * Return: %true if the pipe context is found and adjusted; + * %false if the pipe context is not found. */ bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_stream_state *stream, @@ -419,14 +420,17 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, } /** - * dc_stream_get_last_used_drr_vtotal - dc_stream_get_last_vrr_vtotal + * dc_stream_get_last_used_drr_vtotal - Looks up the pipe context of + * dc_stream_state and gets the last VTOTAL used by DRR (Dynamic Refresh Rate) * * @dc: [in] dc reference * @stream: [in] Initial dc stream state - * @adjust: [in] Updated parameters for vertical_total_min and + * @refresh_rate: [in] new refresh_rate * - * Looks up the pipe context of dc_stream_state and gets the last VTOTAL used - * by DRR (Dynamic Refresh Rate) + * Return: %true if the pipe context is found and there is an associated + * timing_generator for the DC; + * %false if the pipe context is not found or there is no + * timing_generator for the DC. */ bool dc_stream_get_last_used_drr_vtotal(struct dc *dc, struct dc_stream_state *stream, @@ -518,14 +522,15 @@ dc_stream_forward_dmcu_crc_window(struct dmcu *dmcu, } bool -dc_stream_forward_crc_window(struct dc *dc, - struct rect *rect, struct dc_stream_state *stream, bool is_stop) +dc_stream_forward_crc_window(struct dc_stream_state *stream, + struct rect *rect, bool is_stop) { struct dmcu *dmcu; struct dc_dmub_srv *dmub_srv; struct otg_phy_mux mux_mapping; struct pipe_ctx *pipe; int i; + struct dc *dc = stream->ctx->dc; for (i = 0; i < MAX_PIPES; i++) { pipe = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -566,7 +571,10 @@ dc_stream_forward_crc_window(struct dc *dc, * once. * * By default, only CRC0 is configured, and the entire frame is used to - * calculate the crc. + * calculate the CRC. + * + * Return: %false if the stream is not found or CRC capture is not supported; + * %true if the stream has been configured. */ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, struct crc_params *crc_window, bool enable, bool continuous) @@ -635,7 +643,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, * dc_stream_configure_crc needs to be called beforehand to enable CRCs. * * Return: - * false if stream is not found, or if CRCs are not enabled. + * %false if stream is not found, or if CRCs are not enabled. */ bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) @@ -862,6 +870,7 @@ static bool dc_construct_ctx(struct dc *dc, dc_ctx->perf_trace = dc_perf_trace_create(); if (!dc_ctx->perf_trace) { + kfree(dc_ctx); ASSERT_CRITICAL(false); return false; } @@ -1740,6 +1749,8 @@ void dc_z10_save_init(struct dc *dc) * * Applies given context to the hardware and copy it into current context. * It's up to the user to release the src context afterwards. + * + * Return: an enum dc_status result code for the operation */ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context) { @@ -2007,8 +2018,9 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) return result == DC_OK; } - if (!streams_changed(dc, context->streams, context->stream_count)) + if (!streams_changed(dc, context->streams, context->stream_count)) { return DC_OK; + } DC_LOG_DC("%s: %d streams\n", __func__, context->stream_count); @@ -3325,6 +3337,7 @@ static void commit_planes_for_stream(struct dc *dc, struct pipe_ctx *top_pipe_to_program = NULL; bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST); bool subvp_prev_use = false; + bool subvp_curr_use = false; // Once we apply the new subvp context to hardware it won't be in the // dc->current_state anymore, so we have to cache it before we apply @@ -3381,6 +3394,15 @@ static void commit_planes_for_stream(struct dc *dc, break; } + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + subvp_curr_use = true; + break; + } + } + if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) { struct pipe_ctx *mpcc_pipe; struct pipe_ctx *odm_pipe; @@ -3652,42 +3674,22 @@ static void commit_planes_for_stream(struct dc *dc, top_pipe_to_program->stream_res.tg); } - /* For phantom pipe OTG enable, it has to be done after any previous pipe - * that was in use has already been programmed at gotten its double buffer - * update for "disable". - */ - if (update_type != UPDATE_TYPE_FAST) { - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - /* If an active, non-phantom pipe is being transitioned into a phantom - * pipe, wait for the double buffer update to complete first before we do - * ANY phantom pipe programming. - */ - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM && - old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { - old_pipe->stream_res.tg->funcs->wait_for_state( - old_pipe->stream_res.tg, - CRTC_STATE_VBLANK); - old_pipe->stream_res.tg->funcs->wait_for_state( - old_pipe->stream_res.tg, - CRTC_STATE_VACTIVE); - } + if (subvp_curr_use) { + /* If enabling subvp or transitioning from subvp->subvp, enable the + * phantom streams before we program front end for the phantom pipes. + */ + if (update_type != UPDATE_TYPE_FAST) { + if (dc->hwss.enable_phantom_streams) + dc->hwss.enable_phantom_streams(dc, context); } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; + } - if ((new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) || - subvp_prev_use) { - // If old context or new context has phantom pipes, apply - // the phantom timings now. We can't change the phantom - // pipe configuration safely without driver acquiring - // the DMCUB lock first. - dc->hwss.apply_ctx_to_hw(dc, context); - break; - } - } + if (subvp_prev_use && !subvp_curr_use) { + /* If disabling subvp, disable phantom streams after front end + * programming has completed (we turn on phantom OTG in order + * to complete the plane disable for phantom pipes). + */ + dc->hwss.apply_ctx_to_hw(dc, context); } if (update_type != UPDATE_TYPE_FAST) @@ -4704,7 +4706,7 @@ bool dc_enable_dmub_notifications(struct dc *dc) /** * dc_enable_dmub_outbox - Enables DMUB unsolicited notification * - * dc: [in] dc structure + * @dc: [in] dc structure * * Enables DMUB unsolicited notifications to x86 via outbox. */ @@ -4905,8 +4907,8 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, /** * dc_process_dmub_dpia_hpd_int_enable - Submits DPIA DPD interruption * - * @dc [in]: dc structure - * @hpd_int_enable [in]: 1 for hpd int enable, 0 to disable + * @dc: [in] dc structure + * @hpd_int_enable: [in] 1 for hpd int enable, 0 to disable * * Submits dpia hpd int enable command to dmub via inbox message */ @@ -4987,7 +4989,7 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo } /** - * dc_extended_blank_supported 0 Decide whether extended blank is supported + * dc_extended_blank_supported - Decide whether extended blank is supported * * @dc: [in] Current DC state * @@ -4996,7 +4998,7 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo * ability to enter z9/z10. * * Return: - * Indicate whether extended blank is supported (true or false) + * Indicate whether extended blank is supported (%true or %false) */ bool dc_extended_blank_supported(struct dc *dc) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 471078fc3900..652270a0b498 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -90,8 +90,8 @@ static const struct out_csc_color_matrix_type output_csc_matrix[] = { { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3, 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }, { COLOR_SPACE_YCBCR2020_TYPE, - { 0x1000, 0xF149, 0xFEB7, 0x0000, 0x0868, 0x15B2, - 0x01E6, 0x0000, 0xFB88, 0xF478, 0x1000, 0x0000} }, + { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2, + 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }, { COLOR_SPACE_YCBCR709_BLACK_TYPE, { 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x1000} }, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 342e906ae26e..d9e490eca10f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -33,9 +33,10 @@ #include "gpio_service_interface.h" #include "core_status.h" #include "dc_link_dp.h" -#include "dc_link_dpia.h" -#include "dc_link_ddc.h" +#include "link/link_dp_dpia.h" +#include "link/link_ddc.h" #include "link_hwss.h" +#include "link.h" #include "opp.h" #include "link_encoder.h" @@ -50,8 +51,12 @@ #include "dmub/dmub_srv.h" #include "inc/hw/panel_cntl.h" #include "inc/link_enc_cfg.h" -#include "inc/link_dpcd.h" +#include "link/link_dpcd.h" #include "link/link_dp_trace.h" +#include "link/link_hpd.h" +#include "link/link_dp_training.h" +#include "link/link_dp_phy.h" +#include "link/link_dp_capability.h" #include "dc/dcn30/dcn30_vpg.h" @@ -78,7 +83,7 @@ static void dc_link_destruct(struct dc_link *link) } if (link->ddc) - dal_ddc_service_destroy(&link->ddc); + link_destroy_ddc_service(&link->ddc); if (link->panel_cntl) link->panel_cntl->funcs->destroy(&link->panel_cntl); @@ -102,108 +107,6 @@ static void dc_link_destruct(struct dc_link *link) dc_sink_release(link->remote_sinks[i]); } -struct gpio *get_hpd_gpio(struct dc_bios *dcb, - struct graphics_object_id link_id, - struct gpio_service *gpio_service) -{ - enum bp_result bp_result; - struct graphics_object_hpd_info hpd_info; - struct gpio_pin_info pin_info; - - if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK) - return NULL; - - bp_result = dcb->funcs->get_gpio_pin_info(dcb, - hpd_info.hpd_int_gpio_uid, &pin_info); - - if (bp_result != BP_RESULT_OK) { - ASSERT(bp_result == BP_RESULT_NORECORD); - return NULL; - } - - return dal_gpio_service_create_irq(gpio_service, - pin_info.offset, - pin_info.mask); -} - -/* - * Function: program_hpd_filter - * - * @brief - * Programs HPD filter on associated HPD line - * - * @param [in] delay_on_connect_in_ms: Connect filter timeout - * @param [in] delay_on_disconnect_in_ms: Disconnect filter timeout - * - * @return - * true on success, false otherwise - */ -static bool program_hpd_filter(const struct dc_link *link) -{ - bool result = false; - struct gpio *hpd; - int delay_on_connect_in_ms = 0; - int delay_on_disconnect_in_ms = 0; - - if (link->is_hpd_filter_disabled) - return false; - /* Verify feature is supported */ - switch (link->connector_signal) { - case SIGNAL_TYPE_DVI_SINGLE_LINK: - case SIGNAL_TYPE_DVI_DUAL_LINK: - case SIGNAL_TYPE_HDMI_TYPE_A: - /* Program hpd filter */ - delay_on_connect_in_ms = 500; - delay_on_disconnect_in_ms = 100; - break; - case SIGNAL_TYPE_DISPLAY_PORT: - case SIGNAL_TYPE_DISPLAY_PORT_MST: - /* Program hpd filter to allow DP signal to settle */ - /* 500: not able to detect MST <-> SST switch as HPD is low for - * only 100ms on DELL U2413 - * 0: some passive dongle still show aux mode instead of i2c - * 20-50: not enough to hide bouncing HPD with passive dongle. - * also see intermittent i2c read issues. - */ - delay_on_connect_in_ms = 80; - delay_on_disconnect_in_ms = 0; - break; - case SIGNAL_TYPE_LVDS: - case SIGNAL_TYPE_EDP: - default: - /* Don't program hpd filter */ - return false; - } - - /* Obtain HPD handle */ - hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, - link->ctx->gpio_service); - - if (!hpd) - return result; - - /* Setup HPD filtering */ - if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) { - struct gpio_hpd_config config; - - config.delay_on_connect = delay_on_connect_in_ms; - config.delay_on_disconnect = delay_on_disconnect_in_ms; - - dal_irq_setup_hpd_filter(hpd, &config); - - dal_gpio_close(hpd); - - result = true; - } else { - ASSERT_CRITICAL(false); - } - - /* Release HPD handle */ - dal_gpio_destroy_irq(&hpd); - - return result; -} - bool dc_link_wait_for_t12(struct dc_link *link) { if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) { @@ -226,7 +129,6 @@ bool dc_link_wait_for_t12(struct dc_link *link) bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type) { uint32_t is_hpd_high = 0; - struct gpio *hpd_pin; if (link->connector_signal == SIGNAL_TYPE_LVDS) { *type = dc_connection_single; @@ -250,17 +152,9 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type) return true; } - /* todo: may need to lock gpio access */ - hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, - link->ctx->gpio_service); - if (!hpd_pin) + if (!query_hpd_status(link, &is_hpd_high)) goto hpd_gpio_failure; - dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT); - dal_gpio_get_value(hpd_pin, &is_hpd_high); - dal_gpio_close(hpd_pin); - dal_gpio_destroy_irq(&hpd_pin); - if (is_hpd_high) { *type = dc_connection_single; /* TODO: need to do the actual detection */ @@ -386,7 +280,7 @@ bool dc_link_is_dp_sink_present(struct dc_link *link) (connector_id == CONNECTOR_ID_EDP) || (connector_id == CONNECTOR_ID_USBC)); - ddc = dal_ddc_service_get_ddc_pin(link->ddc); + ddc = get_ddc_pin(link->ddc); if (!ddc) { BREAK_TO_DEBUGGER(); @@ -531,11 +425,179 @@ static enum signal_type decide_signal_from_strap_and_dongle_type(enum display_do return signal; } +static bool i2c_read( + struct ddc_service *ddc, + uint32_t address, + uint8_t *buffer, + uint32_t len) +{ + uint8_t offs_data = 0; + struct i2c_payload payloads[2] = { + { + .write = true, + .address = address, + .length = 1, + .data = &offs_data }, + { + .write = false, + .address = address, + .length = len, + .data = buffer } }; + + struct i2c_command command = { + .payloads = payloads, + .number_of_payloads = 2, + .engine = DDC_I2C_COMMAND_ENGINE, + .speed = ddc->ctx->dc->caps.i2c_speed_in_khz }; + + return dm_helpers_submit_i2c( + ddc->ctx, + ddc->link, + &command); +} + +enum { + DP_SINK_CAP_SIZE = + DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1 +}; + +static void query_dp_dual_mode_adaptor( + struct ddc_service *ddc, + struct display_sink_capability *sink_cap) +{ + uint8_t i; + bool is_valid_hdmi_signature; + enum display_dongle_type *dongle = &sink_cap->dongle_type; + uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE]; + bool is_type2_dongle = false; + int retry_count = 2; + struct dp_hdmi_dongle_signature_data *dongle_signature; + + /* Assume we have no valid DP passive dongle connected */ + *dongle = DISPLAY_DONGLE_NONE; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; + + /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ + if (!i2c_read( + ddc, + DP_HDMI_DONGLE_ADDRESS, + type2_dongle_buf, + sizeof(type2_dongle_buf))) { + /* Passive HDMI dongles can sometimes fail here without retrying*/ + while (retry_count > 0) { + if (i2c_read(ddc, + DP_HDMI_DONGLE_ADDRESS, + type2_dongle_buf, + sizeof(type2_dongle_buf))) + break; + retry_count--; + } + if (retry_count == 0) { + *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; + + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), + "DP-DVI passive dongle %dMhz: ", + DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); + return; + } + } + + /* Check if Type 2 dongle.*/ + if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID) + is_type2_dongle = true; + + dongle_signature = + (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf; + + is_valid_hdmi_signature = true; + + /* Check EOT */ + if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) { + is_valid_hdmi_signature = false; + } + + /* Check signature */ + for (i = 0; i < sizeof(dongle_signature->id); ++i) { + /* If its not the right signature, + * skip mismatch in subversion byte.*/ + if (dongle_signature->id[i] != + dp_hdmi_dongle_signature_str[i] && i != 3) { + + if (is_type2_dongle) { + is_valid_hdmi_signature = false; + break; + } + + } + } + + if (is_type2_dongle) { + uint32_t max_tmds_clk = + type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK]; + + max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2; + + if (0 == max_tmds_clk || + max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK || + max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) { + *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; + + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, + sizeof(type2_dongle_buf), + "DP-DVI passive dongle %dMhz: ", + DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); + } else { + if (is_valid_hdmi_signature == true) { + *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; + + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, + sizeof(type2_dongle_buf), + "Type 2 DP-HDMI passive dongle %dMhz: ", + max_tmds_clk); + } else { + *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; + + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, + sizeof(type2_dongle_buf), + "Type 2 DP-HDMI passive dongle (no signature) %dMhz: ", + max_tmds_clk); + + } + + /* Multiply by 1000 to convert to kHz. */ + sink_cap->max_hdmi_pixel_clock = + max_tmds_clk * 1000; + } + sink_cap->is_dongle_type_one = false; + + } else { + if (is_valid_hdmi_signature == true) { + *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; + + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, + sizeof(type2_dongle_buf), + "Type 1 DP-HDMI passive dongle %dMhz: ", + sink_cap->max_hdmi_pixel_clock / 1000); + } else { + *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; + + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, + sizeof(type2_dongle_buf), + "Type 1 DP-HDMI passive dongle (no signature) %dMhz: ", + sink_cap->max_hdmi_pixel_clock / 1000); + } + sink_cap->is_dongle_type_one = true; + } + + return; +} + static enum signal_type dp_passive_dongle_detection(struct ddc_service *ddc, struct display_sink_capability *sink_cap, struct audio_support *audio_support) { - dal_ddc_service_i2c_query_dp_dual_mode_adaptor(ddc, sink_cap); + query_dp_dual_mode_adaptor(ddc, sink_cap); return decide_signal_from_strap_and_dongle_type(sink_cap->dongle_type, audio_support); @@ -775,7 +837,7 @@ static bool wait_for_entering_dp_alt_mode(struct dc_link *link) return true; is_in_alt_mode = link->link_enc->funcs->is_in_alt_mode(link->link_enc); - DC_LOG_WARNING("DP Alt mode state on HPD: %d\n", is_in_alt_mode); + DC_LOG_DC("DP Alt mode state on HPD: %d\n", is_in_alt_mode); if (is_in_alt_mode) return true; @@ -971,7 +1033,7 @@ static bool should_verify_link_capability_destructively(struct dc_link *link, dc_is_embedded_signal(link->local_sink->sink_signal) || link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { destrictive = false; - } else if (dp_get_link_encoding_format(&max_link_cap) == + } else if (link_dp_get_encoding_format(&max_link_cap) == DP_8b_10b_ENCODING) { if (link->dpcd_caps.is_mst_capable || is_link_enc_unavailable) { @@ -1155,11 +1217,11 @@ static bool detect_link_and_local_sink(struct dc_link *link, else link->dpcd_sink_count = 1; - dal_ddc_service_set_transaction_type(link->ddc, + set_ddc_transaction_type(link->ddc, sink_caps.transaction_type); link->aux_mode = - dal_ddc_service_is_in_aux_transaction_mode(link->ddc); + link_is_in_aux_transaction_mode(link->ddc); sink_init_data.link = link; sink_init_data.sink_signal = sink_caps.signal; @@ -1367,58 +1429,6 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) return is_local_sink_detect_success && !is_delegated_to_mst_top_mgr; } -bool dc_link_get_hpd_state(struct dc_link *dc_link) -{ - uint32_t state; - - dal_gpio_lock_pin(dc_link->hpd_gpio); - dal_gpio_get_value(dc_link->hpd_gpio, &state); - dal_gpio_unlock_pin(dc_link->hpd_gpio); - - return state; -} - -static enum hpd_source_id get_hpd_line(struct dc_link *link) -{ - struct gpio *hpd; - enum hpd_source_id hpd_id; - - hpd_id = HPD_SOURCEID_UNKNOWN; - - hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, - link->ctx->gpio_service); - - if (hpd) { - switch (dal_irq_get_source(hpd)) { - case DC_IRQ_SOURCE_HPD1: - hpd_id = HPD_SOURCEID1; - break; - case DC_IRQ_SOURCE_HPD2: - hpd_id = HPD_SOURCEID2; - break; - case DC_IRQ_SOURCE_HPD3: - hpd_id = HPD_SOURCEID3; - break; - case DC_IRQ_SOURCE_HPD4: - hpd_id = HPD_SOURCEID4; - break; - case DC_IRQ_SOURCE_HPD5: - hpd_id = HPD_SOURCEID5; - break; - case DC_IRQ_SOURCE_HPD6: - hpd_id = HPD_SOURCEID6; - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - dal_gpio_destroy_irq(&hpd); - } - - return hpd_id; -} - static enum channel_id get_ddc_line(struct dc_link *link) { struct ddc *ddc; @@ -1426,7 +1436,7 @@ static enum channel_id get_ddc_line(struct dc_link *link) channel = CHANNEL_ID_UNKNOWN; - ddc = dal_ddc_service_get_ddc_pin(link->ddc); + ddc = get_ddc_pin(link->ddc); if (ddc) { switch (dal_ddc_get_line(ddc)) { @@ -1583,7 +1593,7 @@ static bool dc_link_construct_legacy(struct dc_link *link, if (link->dc->res_pool->funcs->link_init) link->dc->res_pool->funcs->link_init(link); - link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, + link->hpd_gpio = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); if (link->hpd_gpio) { @@ -1663,7 +1673,7 @@ static bool dc_link_construct_legacy(struct dc_link *link, ddc_service_init_data.ctx = link->ctx; ddc_service_init_data.id = link->link_id; ddc_service_init_data.link = link; - link->ddc = dal_ddc_service_create(&ddc_service_init_data); + link->ddc = link_create_ddc_service(&ddc_service_init_data); if (!link->ddc) { DC_ERROR("Failed to create ddc_service!\n"); @@ -1676,7 +1686,7 @@ static bool dc_link_construct_legacy(struct dc_link *link, } link->ddc_hw_inst = - dal_ddc_get_line(dal_ddc_service_get_ddc_pin(link->ddc)); + dal_ddc_get_line(get_ddc_pin(link->ddc)); if (link->dc->res_pool->funcs->panel_cntl_create && @@ -1813,7 +1823,7 @@ link_enc_create_fail: if (link->panel_cntl != NULL) link->panel_cntl->funcs->destroy(&link->panel_cntl); panel_cntl_create_fail: - dal_ddc_service_destroy(&link->ddc); + link_destroy_ddc_service(&link->ddc); ddc_create_fail: create_fail: @@ -1871,7 +1881,7 @@ static bool dc_link_construct_dpia(struct dc_link *link, /* Set indicator for dpia link so that ddc won't be created */ ddc_service_init_data.is_dpia_link = true; - link->ddc = dal_ddc_service_create(&ddc_service_init_data); + link->ddc = link_create_ddc_service(&ddc_service_init_data); if (!link->ddc) { DC_ERROR("Failed to create ddc_service!\n"); goto ddc_create_fail; @@ -1916,12 +1926,6 @@ struct dc_link *link_create(const struct link_init_data *init_params) if (false == dc_link_construct(link, init_params)) goto construct_fail; - /* - * Must use preferred_link_setting, not reported_link_cap or verified_link_cap, - * since struct preferred_link_setting won't be reset after S3. - */ - link->preferred_link_setting.dpcd_source_device_specific_field_support = true; - return link; construct_fail: @@ -2002,7 +2006,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, * Temporary w/a to get DP2.0 link rates to work with SST. * TODO DP2.0 - Workaround: Remove w/a if and when the issue is resolved. */ - if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING && + if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING && pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && link->dc->debug.set_mst_en_for_sst) { dp_enable_mst_on_sink(link, true); @@ -2015,7 +2019,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, link->dc->hwss.edp_wait_for_hpd_ready(link, true); } - if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) { + if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) { /* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */ } else { pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = @@ -2056,7 +2060,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, else fec_enable = true; - if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) + if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) dp_set_fec_enable(link, fec_enable); // during mode set we do DP_SET_POWER off then on, aux writes are lost @@ -2172,7 +2176,7 @@ void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init) } if ((!link->wa_flags.dp_keep_receiver_powered) || hw_init) - dp_receiver_power_ctrl(link, false); + dc_link_dp_receiver_power_ctrl(link, false); } } @@ -2345,7 +2349,7 @@ static void write_i2c_retimer_setting( value = settings->reg_settings[i].i2c_reg_val; else { i2c_success = - dal_ddc_service_query_ddc_data( + link_query_ddc_data( pipe_ctx->stream->link->ddc, slave_address, &offset, 1, &value, 1); if (!i2c_success) @@ -2395,7 +2399,7 @@ static void write_i2c_retimer_setting( value = settings->reg_settings_6g[i].i2c_reg_val; else { i2c_success = - dal_ddc_service_query_ddc_data( + link_query_ddc_data( pipe_ctx->stream->link->ddc, slave_address, &offset, 1, &value, 1); if (!i2c_success) @@ -2637,7 +2641,7 @@ static void disable_link(struct dc_link *link, const struct link_resource *link_ if (dc_is_dp_sst_signal(signal) || link->mst_stream_alloc_table.stream_count == 0) { - if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) { + if (link_dp_get_encoding_format(&link_settings) == DP_8b_10b_ENCODING) { dp_set_fec_enable(link, false); dp_set_fec_ready(link, link_res, false); } @@ -2693,7 +2697,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) } if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) - dal_ddc_service_write_scdc_data( + write_scdc_data( stream->link->ddc, stream->phy_pix_clk, stream->timing.flags.LTE_340MCSC_SCRAMBLE); @@ -2714,7 +2718,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) stream->phy_pix_clk); if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) - dal_ddc_service_read_scdc_data(link->ddc); + read_scdc_data(link->ddc); } static void enable_link_lvds(struct pipe_ctx *pipe_ctx) @@ -3685,7 +3689,7 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx, } /* slot X.Y for SST payload allocate */ - if (allocate && dp_get_link_encoding_format(&link->cur_link_settings) == + if (allocate && link_dp_get_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING) { avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link); @@ -3768,7 +3772,7 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) /* program DP source TX for payload */ if (link_hwss->ext.update_stream_allocation_table == NULL || - dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { + link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { DC_LOG_ERROR("Failure: unknown encoding format\n"); return DC_ERROR_UNEXPECTED; } @@ -3884,7 +3888,7 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw /* update mst stream allocation table hardware state */ if (link_hwss->ext.update_stream_allocation_table == NULL || - dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { + link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { DC_LOG_ERROR("Failure: unknown encoding format\n"); return DC_ERROR_UNEXPECTED; } @@ -3951,7 +3955,7 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t /* update mst stream allocation table hardware state */ if (link_hwss->ext.update_stream_allocation_table == NULL || - dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { + link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { DC_LOG_ERROR("Failure: unknown encoding format\n"); return DC_ERROR_UNEXPECTED; } @@ -4064,7 +4068,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) /* update mst stream allocation table hardware state */ if (link_hwss->ext.update_stream_allocation_table == NULL || - dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { + link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) { DC_LOG_DEBUG("Unknown encoding format\n"); return DC_ERROR_UNEXPECTED; } @@ -4112,7 +4116,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) /* stream encoder index */ config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0; @@ -4121,7 +4125,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) /* link encoder index */ config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst; /* dio output index is dpia index for DPIA endpoint & dcio index by default */ @@ -4142,7 +4146,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0; config.mst_enabled = (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0; - config.dp2_enabled = is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0; + config.dp2_enabled = link_is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0; config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ? 1 : 0; config.dpms_off = dpms_off; @@ -4245,7 +4249,7 @@ void core_link_enable_stream( struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); @@ -4267,7 +4271,7 @@ void core_link_enable_stream( ASSERT(link_enc); if (!dc_is_virtual_signal(pipe_ctx->stream->signal) - && !is_dp_128b_132b_signal(pipe_ctx)) { + && !link_is_dp_128b_132b_signal(pipe_ctx)) { if (link_enc) link_enc->funcs->setup( link_enc, @@ -4277,7 +4281,7 @@ void core_link_enable_stream( pipe_ctx->stream->link->link_state_valid = true; if (pipe_ctx->stream_res.tg->funcs->set_out_mux) { - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) otg_out_dest = OUT_MUX_HPO_DP; else otg_out_dest = OUT_MUX_DIO; @@ -4379,7 +4383,7 @@ void core_link_enable_stream( * from transmitter control. */ if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) || - is_dp_128b_132b_signal(pipe_ctx))) + link_is_dp_128b_132b_signal(pipe_ctx))) if (link_enc) link_enc->funcs->setup( link_enc, @@ -4399,7 +4403,7 @@ void core_link_enable_stream( if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) dc_link_allocate_mst_payload(pipe_ctx); else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && - is_dp_128b_132b_signal(pipe_ctx)) + link_is_dp_128b_132b_signal(pipe_ctx)) dc_link_update_sst_payload(pipe_ctx, true); dc->hwss.unblank_stream(pipe_ctx, @@ -4417,7 +4421,7 @@ void core_link_enable_stream( dc->hwss.enable_audio_stream(pipe_ctx); } else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) fpga_dp_hpo_enable_link_and_stream(state, pipe_ctx); if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) @@ -4436,7 +4440,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) struct dc_link *link = stream->sink->link; struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg; - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); @@ -4469,7 +4473,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx); else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && - is_dp_128b_132b_signal(pipe_ctx)) + link_is_dp_128b_132b_signal(pipe_ctx)) dc_link_update_sst_payload(pipe_ctx, false); if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) { @@ -4479,7 +4483,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) unsigned short masked_chip_caps = link->chip_caps & EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK; //Need to inform that sink is going to use legacy HDMI mode. - dal_ddc_service_write_scdc_data( + write_scdc_data( link->ddc, 165000,//vbios only handles 165Mhz. false); @@ -4498,7 +4502,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) } if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && - !is_dp_128b_132b_signal(pipe_ctx)) { + !link_is_dp_128b_132b_signal(pipe_ctx)) { /* In DP1.x SST mode, our encoder will go to TPS1 * when link is on but stream is off. @@ -4518,7 +4522,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) if (dc_is_dp_signal(pipe_ctx->stream->signal)) dp_set_dsc_enable(pipe_ctx, false); } - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { if (pipe_ctx->stream_res.tg->funcs->set_out_mux) pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO); } @@ -4537,51 +4541,6 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) dc->hwss.set_avmute(pipe_ctx, enable); } -/** - * dc_link_enable_hpd_filter: - * If enable is true, programs HPD filter on associated HPD line using - * delay_on_disconnect/delay_on_connect values dependent on - * link->connector_signal - * - * If enable is false, programs HPD filter on associated HPD line with no - * delays on connect or disconnect - * - * @link: pointer to the dc link - * @enable: boolean specifying whether to enable hbd - */ -void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) -{ - struct gpio *hpd; - - if (enable) { - link->is_hpd_filter_disabled = false; - program_hpd_filter(link); - } else { - link->is_hpd_filter_disabled = true; - /* Obtain HPD handle */ - hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); - - if (!hpd) - return; - - /* Setup HPD filtering */ - if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) { - struct gpio_hpd_config config; - - config.delay_on_connect = 0; - config.delay_on_disconnect = 0; - - dal_irq_setup_hpd_filter(hpd, &config); - - dal_gpio_close(hpd); - } else { - ASSERT_CRITICAL(false); - } - /* Release HPD handle */ - dal_gpio_destroy_irq(&hpd); - } -} - void dc_link_set_drive_settings(struct dc *dc, struct link_training_settings *lt_settings, const struct dc_link *link) @@ -4638,7 +4597,7 @@ void dc_link_set_preferred_link_settings(struct dc *dc, if (link_stream->dpms_off) return; - if (decide_link_settings(link_stream, &store_settings)) + if (link_decide_link_settings(link_stream, &store_settings)) dp_retrain_link_dp_test(link, &store_settings, false); } @@ -4655,9 +4614,6 @@ void dc_link_set_preferred_training_settings(struct dc *dc, if (link_setting != NULL) { link->preferred_link_setting = *link_setting; - if (dp_get_link_encoding_format(link_setting) == DP_128b_132b_ENCODING) - /* TODO: add dc update for acquiring link res */ - skip_immediate_retrain = true; } else { link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN; link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN; @@ -4672,16 +4628,6 @@ void dc_link_set_preferred_training_settings(struct dc *dc, dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link); } -void dc_link_enable_hpd(const struct dc_link *link) -{ - dc_link_dp_enable_hpd(link); -} - -void dc_link_disable_hpd(const struct dc_link *link) -{ - dc_link_dp_disable_hpd(link); -} - void dc_link_set_test_pattern(struct dc_link *link, enum dp_test_pattern test_pattern, enum dp_test_pattern_color_space test_pattern_color_space, @@ -4706,7 +4652,7 @@ uint32_t dc_link_bandwidth_kbps( uint32_t total_data_bw_efficiency_x10000 = 0; uint32_t link_rate_per_lane_kbps = 0; - switch (dp_get_link_encoding_format(link_setting)) { + switch (link_dp_get_encoding_format(link_setting)) { case DP_8b_10b_ENCODING: /* For 8b/10b encoding: * link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane. @@ -4735,57 +4681,6 @@ uint32_t dc_link_bandwidth_kbps( return link_rate_per_lane_kbps * link_setting->lane_count / 10000 * total_data_bw_efficiency_x10000; } -const struct dc_link_settings *dc_link_get_link_cap( - const struct dc_link *link) -{ - if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN && - link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) - return &link->preferred_link_setting; - return &link->verified_link_cap; -} - -void dc_link_overwrite_extended_receiver_cap( - struct dc_link *link) -{ - dp_overwrite_extended_receiver_cap(link); -} - -bool dc_link_is_fec_supported(const struct dc_link *link) -{ - /* TODO - use asic cap instead of link_enc->features - * we no longer know which link enc to use for this link before commit - */ - struct link_encoder *link_enc = NULL; - - link_enc = link_enc_cfg_get_link_enc(link); - ASSERT(link_enc); - - return (dc_is_dp_signal(link->connector_signal) && link_enc && - link_enc->features.fec_supported && - link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && - !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment)); -} - -bool dc_link_should_enable_fec(const struct dc_link *link) -{ - bool force_disable = false; - - if (link->fec_state == dc_link_fec_enabled) - force_disable = false; - else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST && - link->local_sink && - link->local_sink->edid_caps.panel_patch.disable_fec) - force_disable = true; - else if (link->connector_signal == SIGNAL_TYPE_EDP - && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields. - dsc_support.DSC_SUPPORT == false - || link->panel_config.dsc.disable_dsc_edp - || !link->dc->caps.edp_dsc_support)) - force_disable = true; - - return !force_disable && dc_link_is_fec_supported(link); -} - uint32_t dc_bandwidth_in_kbps_from_timing( const struct dc_crtc_timing *timing) { @@ -4890,8 +4785,8 @@ void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map) for (i = 0; i < dc->caps.max_links; i++) { link = dc->links[i]; if (link->link_status.link_active && - dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING && - dp_get_link_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING) + link_dp_get_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING && + link_dp_get_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING) /* hpo dp link encoder is considered as recycled, when RX reports 128b/132b encoding capability * but current link doesn't use it. */ @@ -4934,7 +4829,7 @@ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map) if ((hpo_dp_recycle_map & (1 << i)) == 0) { link = dc->links[i]; if (link->type != dc_connection_none && - dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { + link_dp_get_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { if (available_hpo_dp_count > 0) available_hpo_dp_count--; else @@ -4948,7 +4843,7 @@ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map) if ((hpo_dp_recycle_map & (1 << i)) != 0) { link = dc->links[i]; if (link->type != dc_connection_none && - dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { + link_dp_get_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { if (available_hpo_dp_count > 0) available_hpo_dp_count--; else 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 dedd1246ce58..6747e4b199de 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 @@ -27,737 +27,31 @@ #include "dm_helpers.h" #include "opp.h" #include "dsc.h" -#include "clk_mgr.h" #include "resource.h" #include "inc/core_types.h" #include "link_hwss.h" -#include "dc_link_ddc.h" +#include "link/link_ddc.h" #include "core_status.h" #include "dpcd_defs.h" + #include "dc_dmub_srv.h" #include "dce/dmub_hw_lock_mgr.h" -#include "inc/dc_link_dpia.h" +#include "link/link_dp_dpia.h" #include "inc/link_enc_cfg.h" +#include "clk_mgr.h" #include "link/link_dp_trace.h" - -/*Travis*/ -static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT"; -/*Nutmeg*/ -static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; - +#include "link/link_dp_training.h" +#include "link/link_dp_training_fixed_vs_pe_retimer.h" +#include "link/link_dp_training_dpia.h" +#include "link/link_dp_training_auxless.h" +#include "link/link_dp_phy.h" +#include "link/link_dp_capability.h" #define DC_LOGGER \ link->ctx->logger -#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ - -#include "link_dpcd.h" - -#ifndef MAX -#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) -#endif -#ifndef MIN -#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) -#endif - - /* maximum pre emphasis level allowed for each voltage swing level*/ - static const enum dc_pre_emphasis - voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3, - PRE_EMPHASIS_LEVEL2, - PRE_EMPHASIS_LEVEL1, - PRE_EMPHASIS_DISABLED }; - -enum { - POST_LT_ADJ_REQ_LIMIT = 6, - POST_LT_ADJ_REQ_TIMEOUT = 200 -}; - -struct dp_lt_fallback_entry { - enum dc_lane_count lane_count; - enum dc_link_rate link_rate; -}; - -static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = { - /* This link training fallback array is ordered by - * link bandwidth from highest to lowest. - * DP specs makes it a normative policy to always - * choose the next highest link bandwidth during - * link training fallback. - */ - {LANE_COUNT_FOUR, LINK_RATE_UHBR20}, - {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5}, - {LANE_COUNT_TWO, LINK_RATE_UHBR20}, - {LANE_COUNT_FOUR, LINK_RATE_UHBR10}, - {LANE_COUNT_TWO, LINK_RATE_UHBR13_5}, - {LANE_COUNT_FOUR, LINK_RATE_HIGH3}, - {LANE_COUNT_ONE, LINK_RATE_UHBR20}, - {LANE_COUNT_TWO, LINK_RATE_UHBR10}, - {LANE_COUNT_FOUR, LINK_RATE_HIGH2}, - {LANE_COUNT_ONE, LINK_RATE_UHBR13_5}, - {LANE_COUNT_TWO, LINK_RATE_HIGH3}, - {LANE_COUNT_ONE, LINK_RATE_UHBR10}, - {LANE_COUNT_TWO, LINK_RATE_HIGH2}, - {LANE_COUNT_FOUR, LINK_RATE_HIGH}, - {LANE_COUNT_ONE, LINK_RATE_HIGH3}, - {LANE_COUNT_FOUR, LINK_RATE_LOW}, - {LANE_COUNT_ONE, LINK_RATE_HIGH2}, - {LANE_COUNT_TWO, LINK_RATE_HIGH}, - {LANE_COUNT_TWO, LINK_RATE_LOW}, - {LANE_COUNT_ONE, LINK_RATE_HIGH}, - {LANE_COUNT_ONE, LINK_RATE_LOW}, -}; - -static const struct dc_link_settings fail_safe_link_settings = { - .lane_count = LANE_COUNT_ONE, - .link_rate = LINK_RATE_LOW, - .link_spread = LINK_SPREAD_DISABLED, -}; - -static bool decide_fallback_link_setting( - struct dc_link *link, - struct dc_link_settings *max, - struct dc_link_settings *cur, - enum link_training_result training_result); -static void maximize_lane_settings(const struct link_training_settings *lt_settings, - struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); -static void override_lane_settings(const struct link_training_settings *lt_settings, - struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); - -static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link, - const struct dc_link_settings *link_settings) -{ - union training_aux_rd_interval training_rd_interval; - uint32_t wait_in_micro_secs = 100; - - memset(&training_rd_interval, 0, sizeof(training_rd_interval)); - if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING && - link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { - core_link_read_dpcd( - link, - DP_TRAINING_AUX_RD_INTERVAL, - (uint8_t *)&training_rd_interval, - sizeof(training_rd_interval)); - if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) - wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; - } - - return wait_in_micro_secs; -} - -static uint32_t get_eq_training_aux_rd_interval( - struct dc_link *link, - const struct dc_link_settings *link_settings) -{ - union training_aux_rd_interval training_rd_interval; - - memset(&training_rd_interval, 0, sizeof(training_rd_interval)); - if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) { - core_link_read_dpcd( - link, - DP_128b_132b_TRAINING_AUX_RD_INTERVAL, - (uint8_t *)&training_rd_interval, - sizeof(training_rd_interval)); - } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING && - link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { - core_link_read_dpcd( - link, - DP_TRAINING_AUX_RD_INTERVAL, - (uint8_t *)&training_rd_interval, - sizeof(training_rd_interval)); - } - - switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) { - case 0: return 400; - case 1: return 4000; - case 2: return 8000; - case 3: return 12000; - case 4: return 16000; - case 5: return 32000; - case 6: return 64000; - default: return 400; - } -} - -void dp_wait_for_training_aux_rd_interval( - struct dc_link *link, - uint32_t wait_in_micro_secs) -{ - if (wait_in_micro_secs > 1000) - msleep(wait_in_micro_secs/1000); - else - udelay(wait_in_micro_secs); - - DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", - __func__, - wait_in_micro_secs); -} - -enum dpcd_training_patterns - dc_dp_training_pattern_to_dpcd_training_pattern( - struct dc_link *link, - enum dc_dp_training_pattern pattern) -{ - enum dpcd_training_patterns dpcd_tr_pattern = - DPCD_TRAINING_PATTERN_VIDEOIDLE; - - switch (pattern) { - case DP_TRAINING_PATTERN_SEQUENCE_1: - dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; - break; - case DP_TRAINING_PATTERN_SEQUENCE_2: - dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; - break; - case DP_TRAINING_PATTERN_SEQUENCE_3: - dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; - break; - case DP_TRAINING_PATTERN_SEQUENCE_4: - dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; - break; - case DP_128b_132b_TPS1: - dpcd_tr_pattern = DPCD_128b_132b_TPS1; - break; - case DP_128b_132b_TPS2: - dpcd_tr_pattern = DPCD_128b_132b_TPS2; - break; - case DP_128b_132b_TPS2_CDS: - dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS; - break; - case DP_TRAINING_PATTERN_VIDEOIDLE: - dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; - break; - default: - ASSERT(0); - DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", - __func__, pattern); - break; - } - - return dpcd_tr_pattern; -} - -static void dpcd_set_training_pattern( - struct dc_link *link, - enum dc_dp_training_pattern training_pattern) -{ - union dpcd_training_pattern dpcd_pattern = {0}; - - dpcd_pattern.v1_4.TRAINING_PATTERN_SET = - dc_dp_training_pattern_to_dpcd_training_pattern( - link, training_pattern); - - core_link_write_dpcd( - link, - DP_TRAINING_PATTERN_SET, - &dpcd_pattern.raw, - 1); - - DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", - __func__, - DP_TRAINING_PATTERN_SET, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); -} - -static enum dc_dp_training_pattern decide_cr_training_pattern( - const struct dc_link_settings *link_settings) -{ - switch (dp_get_link_encoding_format(link_settings)) { - case DP_8b_10b_ENCODING: - default: - return DP_TRAINING_PATTERN_SEQUENCE_1; - case DP_128b_132b_ENCODING: - return DP_128b_132b_TPS1; - } -} - -static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, - const struct dc_link_settings *link_settings) -{ - struct link_encoder *link_enc; - struct encoder_feature_support *enc_caps; - struct dpcd_caps *rx_caps = &link->dpcd_caps; - enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2; - - link_enc = link_enc_cfg_get_link_enc(link); - ASSERT(link_enc); - enc_caps = &link_enc->features; - - switch (dp_get_link_encoding_format(link_settings)) { - case DP_8b_10b_ENCODING: - if (enc_caps->flags.bits.IS_TPS4_CAPABLE && - rx_caps->max_down_spread.bits.TPS4_SUPPORTED) - pattern = DP_TRAINING_PATTERN_SEQUENCE_4; - else if (enc_caps->flags.bits.IS_TPS3_CAPABLE && - rx_caps->max_ln_count.bits.TPS3_SUPPORTED) - pattern = DP_TRAINING_PATTERN_SEQUENCE_3; - else - pattern = DP_TRAINING_PATTERN_SEQUENCE_2; - break; - case DP_128b_132b_ENCODING: - pattern = DP_128b_132b_TPS2; - break; - default: - pattern = DP_TRAINING_PATTERN_SEQUENCE_2; - break; - } - return pattern; -} - -static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings) -{ - uint8_t link_rate = 0; - enum dp_link_encoding encoding = dp_get_link_encoding_format(link_settings); - - if (encoding == DP_128b_132b_ENCODING) - switch (link_settings->link_rate) { - case LINK_RATE_UHBR10: - link_rate = 0x1; - break; - case LINK_RATE_UHBR20: - link_rate = 0x2; - break; - case LINK_RATE_UHBR13_5: - link_rate = 0x4; - break; - default: - link_rate = 0; - break; - } - else if (encoding == DP_8b_10b_ENCODING) - link_rate = (uint8_t) link_settings->link_rate; - else - link_rate = 0; - - return link_rate; -} - -static void dp_fixed_vs_pe_read_lane_adjust( - struct dc_link *link, - union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]) -{ - const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63}; - const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63}; - const uint8_t offset = dp_convert_to_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - uint32_t vendor_lttpr_write_address = 0xF004F; - uint32_t vendor_lttpr_read_address = 0xF0053; - uint8_t dprx_vs = 0; - uint8_t dprx_pe = 0; - uint8_t lane; - - if (offset != 0xFF) { - vendor_lttpr_write_address += - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - vendor_lttpr_read_address += - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - } - - /* W/A to read lane settings requested by DPRX */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_vs[0], - sizeof(vendor_lttpr_write_data_vs)); - core_link_read_dpcd( - link, - vendor_lttpr_read_address, - &dprx_vs, - 1); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_pe[0], - sizeof(vendor_lttpr_write_data_pe)); - core_link_read_dpcd( - link, - vendor_lttpr_read_address, - &dprx_pe, - 1); - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3; - dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3; - } -} - -static void dp_fixed_vs_pe_set_retimer_lane_settings( - struct dc_link *link, - const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], - uint8_t lane_count) -{ - const uint8_t offset = dp_convert_to_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; - uint32_t vendor_lttpr_write_address = 0xF004F; - uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; - uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; - uint8_t lane = 0; - - if (offset != 0xFF) { - vendor_lttpr_write_address += - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - } - - for (lane = 0; lane < lane_count; lane++) { - vendor_lttpr_write_data_vs[3] |= - dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane); - vendor_lttpr_write_data_pe[3] |= - dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane); - } - - /* Force LTTPR to output desired VS and PE */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_reset[0], - sizeof(vendor_lttpr_write_data_reset)); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_vs[0], - sizeof(vendor_lttpr_write_data_vs)); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_pe[0], - sizeof(vendor_lttpr_write_data_pe)); -} - -enum dc_status dpcd_set_link_settings( - struct dc_link *link, - const struct link_training_settings *lt_settings) -{ - uint8_t rate; - enum dc_status status; - - union down_spread_ctrl downspread = {0}; - union lane_count_set lane_count_set = {0}; - - downspread.raw = (uint8_t) - (lt_settings->link_settings.link_spread); - - lane_count_set.bits.LANE_COUNT_SET = - lt_settings->link_settings.lane_count; - - lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; - - - if (link->ep_type == DISPLAY_ENDPOINT_PHY && - lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = - link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; - } - - status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, - &downspread.raw, sizeof(downspread)); - - status = core_link_write_dpcd(link, DP_LANE_COUNT_SET, - &lane_count_set.raw, 1); - - if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && - lt_settings->link_settings.use_link_rate_set == true) { - rate = 0; - /* WA for some MUX chips that will power down with eDP and lose supported - * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure - * MUX chip gets link rate set back before link training. - */ - if (link->connector_signal == SIGNAL_TYPE_EDP) { - uint8_t supported_link_rates[16]; - - core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, - supported_link_rates, sizeof(supported_link_rates)); - } - status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); - status = core_link_write_dpcd(link, DP_LINK_RATE_SET, - <_settings->link_settings.link_rate_set, 1); - } else { - rate = get_dpcd_link_rate(<_settings->link_settings); - - status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); - } - - if (rate) { - DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", - __func__, - DP_LINK_BW_SET, - lt_settings->link_settings.link_rate, - DP_LANE_COUNT_SET, - lt_settings->link_settings.lane_count, - lt_settings->enhanced_framing, - DP_DOWNSPREAD_CTRL, - lt_settings->link_settings.link_spread); - } else { - DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n", - __func__, - DP_LINK_RATE_SET, - lt_settings->link_settings.link_rate_set, - DP_LANE_COUNT_SET, - lt_settings->link_settings.lane_count, - lt_settings->enhanced_framing, - DP_DOWNSPREAD_CTRL, - lt_settings->link_settings.link_spread); - } - - return status; -} - -uint8_t dc_dp_initialize_scrambling_data_symbols( - struct dc_link *link, - enum dc_dp_training_pattern pattern) -{ - uint8_t disable_scrabled_data_symbols = 0; - - switch (pattern) { - case DP_TRAINING_PATTERN_SEQUENCE_1: - case DP_TRAINING_PATTERN_SEQUENCE_2: - case DP_TRAINING_PATTERN_SEQUENCE_3: - disable_scrabled_data_symbols = 1; - break; - case DP_TRAINING_PATTERN_SEQUENCE_4: - case DP_128b_132b_TPS1: - case DP_128b_132b_TPS2: - disable_scrabled_data_symbols = 0; - break; - default: - ASSERT(0); - DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", - __func__, pattern); - break; - } - return disable_scrabled_data_symbols; -} - -static inline bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset) -{ - return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0); -} - -static void dpcd_set_lt_pattern_and_lane_settings( - struct dc_link *link, - const struct link_training_settings *lt_settings, - enum dc_dp_training_pattern pattern, - uint32_t offset) -{ - uint32_t dpcd_base_lt_offset; - - uint8_t dpcd_lt_buffer[5] = {0}; - union dpcd_training_pattern dpcd_pattern = {0}; - uint32_t size_in_bytes; - bool edp_workaround = false; /* TODO link_prop.INTERNAL */ - dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; - - if (is_repeater(lt_settings, offset)) - dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - - /***************************************************************** - * DpcdAddress_TrainingPatternSet - *****************************************************************/ - dpcd_pattern.v1_4.TRAINING_PATTERN_SET = - dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern); - - dpcd_pattern.v1_4.SCRAMBLING_DISABLE = - dc_dp_initialize_scrambling_data_symbols(link, pattern); - - dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET] - = dpcd_pattern.raw; - - if (is_repeater(lt_settings, offset)) { - DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n", - __func__, - offset, - dpcd_base_lt_offset, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); - } else { - DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n", - __func__, - dpcd_base_lt_offset, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); - } - - /* concatenate everything into one buffer*/ - size_in_bytes = lt_settings->link_settings.lane_count * - sizeof(lt_settings->dpcd_lane_settings[0]); - - // 0x00103 - 0x00102 - memmove( - &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET], - lt_settings->dpcd_lane_settings, - size_in_bytes); - - if (is_repeater(lt_settings, offset)) { - if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_128b_132b_ENCODING) - DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" - " 0x%X TX_FFE_PRESET_VALUE = %x\n", - __func__, - offset, - dpcd_base_lt_offset, - lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); - else if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING) - DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" - " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", - __func__, - offset, - dpcd_base_lt_offset, - lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, - lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, - lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, - lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); - } else { - if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_128b_132b_ENCODING) - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", - __func__, - dpcd_base_lt_offset, - lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); - else if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING) - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", - __func__, - dpcd_base_lt_offset, - lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, - lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, - lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, - lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); - } - if (edp_workaround) { - /* for eDP write in 2 parts because the 5-byte burst is - * causing issues on some eDP panels (EPR#366724) - */ - core_link_write_dpcd( - link, - DP_TRAINING_PATTERN_SET, - &dpcd_pattern.raw, - sizeof(dpcd_pattern.raw)); - - core_link_write_dpcd( - link, - DP_TRAINING_LANE0_SET, - (uint8_t *)(lt_settings->dpcd_lane_settings), - size_in_bytes); - - } else if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_128b_132b_ENCODING) { - core_link_write_dpcd( - link, - dpcd_base_lt_offset, - dpcd_lt_buffer, - sizeof(dpcd_lt_buffer)); - } else - /* write it all in (1 + number-of-lanes)-byte burst*/ - core_link_write_dpcd( - link, - dpcd_base_lt_offset, - dpcd_lt_buffer, - size_in_bytes + sizeof(dpcd_pattern.raw)); -} - -bool dp_is_cr_done(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status) -{ - uint32_t lane; - /*LANEx_CR_DONE bits All 1's?*/ - for (lane = 0; lane < (uint32_t)(ln_count); lane++) { - if (!dpcd_lane_status[lane].bits.CR_DONE_0) - return false; - } - return true; -} - -bool dp_is_ch_eq_done(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status) -{ - bool done = true; - uint32_t lane; - for (lane = 0; lane < (uint32_t)(ln_count); lane++) - if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0) - done = false; - return done; -} - -bool dp_is_symbol_locked(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status) -{ - bool locked = true; - uint32_t lane; - for (lane = 0; lane < (uint32_t)(ln_count); lane++) - if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0) - locked = false; - return locked; -} - -bool dp_is_interlane_aligned(union lane_align_status_updated align_status) -{ - return align_status.bits.INTERLANE_ALIGN_DONE == 1; -} - -void dp_hw_to_dpcd_lane_settings( - const struct link_training_settings *lt_settings, - const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], - union dpcd_training_lane dpcd_lane_settings[]) -{ - uint8_t lane = 0; - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING) { - dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET = - (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING); - dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET = - (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS); - dpcd_lane_settings[lane].bits.MAX_SWING_REACHED = - (hw_lane_settings[lane].VOLTAGE_SWING == - VOLTAGE_SWING_MAX_LEVEL ? 1 : 0); - dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED = - (hw_lane_settings[lane].PRE_EMPHASIS == - PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); - } - else if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_128b_132b_ENCODING) { - dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE = - hw_lane_settings[lane].FFE_PRESET.settings.level; - } - } -} - -void dp_decide_lane_settings( - const struct link_training_settings *lt_settings, - const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], - struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], - union dpcd_training_lane dpcd_lane_settings[]) -{ - uint32_t lane; - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING) { - hw_lane_settings[lane].VOLTAGE_SWING = - (enum dc_voltage_swing)(ln_adjust[lane].bits. - VOLTAGE_SWING_LANE); - hw_lane_settings[lane].PRE_EMPHASIS = - (enum dc_pre_emphasis)(ln_adjust[lane].bits. - PRE_EMPHASIS_LANE); - } - else if (dp_get_link_encoding_format(<_settings->link_settings) == - DP_128b_132b_ENCODING) { - hw_lane_settings[lane].FFE_PRESET.raw = - ln_adjust[lane].tx_ffe.PRESET_VALUE; - } - } - dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); - - if (lt_settings->disallow_per_lane_settings) { - /* we find the maximum of the requested settings across all lanes*/ - /* and set this maximum for all lanes*/ - maximize_lane_settings(lt_settings, hw_lane_settings); - override_lane_settings(lt_settings, hw_lane_settings); - - if (lt_settings->always_match_dpcd_with_hw_lane_settings) - dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); - } -} +#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ +#include "link/link_dpcd.h" static uint8_t get_nibble_at_index(const uint8_t *buf, uint32_t index) @@ -773,2368 +67,7 @@ static uint8_t get_nibble_at_index(const uint8_t *buf, return nibble; } -static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing( - enum dc_voltage_swing voltage) -{ - enum dc_pre_emphasis pre_emphasis; - pre_emphasis = PRE_EMPHASIS_MAX_LEVEL; - - if (voltage <= VOLTAGE_SWING_MAX_LEVEL) - pre_emphasis = voltage_swing_to_pre_emphasis[voltage]; - - return pre_emphasis; - -} - -static void maximize_lane_settings(const struct link_training_settings *lt_settings, - struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) -{ - uint32_t lane; - struct dc_lane_settings max_requested; - - max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING; - max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS; - max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET; - - /* Determine what the maximum of the requested settings are*/ - for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) { - if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING) - max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING; - - if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS) - max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS; - if (lane_settings[lane].FFE_PRESET.settings.level > - max_requested.FFE_PRESET.settings.level) - max_requested.FFE_PRESET.settings.level = - lane_settings[lane].FFE_PRESET.settings.level; - } - - /* make sure the requested settings are - * not higher than maximum settings*/ - if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL) - max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL; - - if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL) - max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL; - if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL) - max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL; - - /* make sure the pre-emphasis matches the voltage swing*/ - if (max_requested.PRE_EMPHASIS > - get_max_pre_emphasis_for_voltage_swing( - max_requested.VOLTAGE_SWING)) - max_requested.PRE_EMPHASIS = - get_max_pre_emphasis_for_voltage_swing( - max_requested.VOLTAGE_SWING); - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING; - lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS; - lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET; - } -} - -static void override_lane_settings(const struct link_training_settings *lt_settings, - struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) -{ - uint32_t lane; - - if (lt_settings->voltage_swing == NULL && - lt_settings->pre_emphasis == NULL && - lt_settings->ffe_preset == NULL && - lt_settings->post_cursor2 == NULL) - - return; - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - if (lt_settings->voltage_swing) - lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing; - if (lt_settings->pre_emphasis) - lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis; - if (lt_settings->post_cursor2) - lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2; - if (lt_settings->ffe_preset) - lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset; - } -} - -enum dc_status dp_get_lane_status_and_lane_adjust( - struct dc_link *link, - const struct link_training_settings *link_training_setting, - union lane_status ln_status[LANE_COUNT_DP_MAX], - union lane_align_status_updated *ln_align, - union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], - uint32_t offset) -{ - unsigned int lane01_status_address = DP_LANE0_1_STATUS; - uint8_t lane_adjust_offset = 4; - unsigned int lane01_adjust_address; - uint8_t dpcd_buf[6] = {0}; - uint32_t lane; - enum dc_status status; - - if (is_repeater(link_training_setting, offset)) { - lane01_status_address = - DP_LANE0_1_STATUS_PHY_REPEATER1 + - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - lane_adjust_offset = 3; - } - - status = core_link_read_dpcd( - link, - lane01_status_address, - (uint8_t *)(dpcd_buf), - sizeof(dpcd_buf)); - - if (status != DC_OK) { - DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X," - " keep current lane status and lane adjust unchanged", - __func__, - lane01_status_address); - return status; - } - - for (lane = 0; lane < - (uint32_t)(link_training_setting->link_settings.lane_count); - lane++) { - - ln_status[lane].raw = - get_nibble_at_index(&dpcd_buf[0], lane); - ln_adjust[lane].raw = - get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane); - } - - ln_align->raw = dpcd_buf[2]; - - if (is_repeater(link_training_setting, offset)) { - DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" - " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", - __func__, - offset, - lane01_status_address, dpcd_buf[0], - lane01_status_address + 1, dpcd_buf[1]); - - lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 + - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - - DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" - " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", - __func__, - offset, - lane01_adjust_address, - dpcd_buf[lane_adjust_offset], - lane01_adjust_address + 1, - dpcd_buf[lane_adjust_offset + 1]); - } else { - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", - __func__, - lane01_status_address, dpcd_buf[0], - lane01_status_address + 1, dpcd_buf[1]); - - lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1; - - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", - __func__, - lane01_adjust_address, - dpcd_buf[lane_adjust_offset], - lane01_adjust_address + 1, - dpcd_buf[lane_adjust_offset + 1]); - } - - return status; -} - -static enum dc_status dpcd_128b_132b_set_lane_settings( - struct dc_link *link, - const struct link_training_settings *link_training_setting) -{ - enum dc_status status = core_link_write_dpcd(link, - DP_TRAINING_LANE0_SET, - (uint8_t *)(link_training_setting->dpcd_lane_settings), - sizeof(link_training_setting->dpcd_lane_settings)); - - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", - __func__, - DP_TRAINING_LANE0_SET, - link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); - return status; -} - - -enum dc_status dpcd_set_lane_settings( - struct dc_link *link, - const struct link_training_settings *link_training_setting, - uint32_t offset) -{ - unsigned int lane0_set_address; - enum dc_status status; - - lane0_set_address = DP_TRAINING_LANE0_SET; - - if (is_repeater(link_training_setting, offset)) - lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 + - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - - status = core_link_write_dpcd(link, - lane0_set_address, - (uint8_t *)(link_training_setting->dpcd_lane_settings), - link_training_setting->link_settings.lane_count); - - if (is_repeater(link_training_setting, offset)) { - DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n" - " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", - __func__, - offset, - lane0_set_address, - link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, - link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, - link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, - link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); - - } else { - DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", - __func__, - lane0_set_address, - link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, - link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, - link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, - link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); - } - - return status; -} - -bool dp_is_max_vs_reached( - const struct link_training_settings *lt_settings) -{ - uint32_t lane; - for (lane = 0; lane < - (uint32_t)(lt_settings->link_settings.lane_count); - lane++) { - if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET - == VOLTAGE_SWING_MAX_LEVEL) - return true; - } - return false; - -} - -static bool perform_post_lt_adj_req_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - enum dc_lane_count lane_count = - lt_settings->link_settings.lane_count; - - uint32_t adj_req_count; - uint32_t adj_req_timer; - bool req_drv_setting_changed; - uint32_t lane; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - union lane_align_status_updated dpcd_lane_status_updated = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - - req_drv_setting_changed = false; - for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT; - adj_req_count++) { - - req_drv_setting_changed = false; - - for (adj_req_timer = 0; - adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT; - adj_req_timer++) { - - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - DPRX); - - if (dpcd_lane_status_updated.bits. - POST_LT_ADJ_REQ_IN_PROGRESS == 0) - return true; - - if (!dp_is_cr_done(lane_count, dpcd_lane_status)) - return false; - - if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) || - !dp_is_symbol_locked(lane_count, dpcd_lane_status) || - !dp_is_interlane_aligned(dpcd_lane_status_updated)) - return false; - - for (lane = 0; lane < (uint32_t)(lane_count); lane++) { - - if (lt_settings-> - dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET != - dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE || - lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET != - dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) { - - req_drv_setting_changed = true; - break; - } - } - - if (req_drv_setting_changed) { - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - - dc_link_dp_set_drive_settings(link, - link_res, - lt_settings); - break; - } - - msleep(1); - } - - if (!req_drv_setting_changed) { - DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n", - __func__); - - ASSERT(0); - return true; - } - } - DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n", - __func__); - - ASSERT(0); - return true; - -} - -/* Only used for channel equalization */ -uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) -{ - unsigned int aux_rd_interval_us = 400; - - switch (dpcd_aux_read_interval) { - case 0x01: - aux_rd_interval_us = 4000; - break; - case 0x02: - aux_rd_interval_us = 8000; - break; - case 0x03: - aux_rd_interval_us = 12000; - break; - case 0x04: - aux_rd_interval_us = 16000; - break; - case 0x05: - aux_rd_interval_us = 32000; - break; - case 0x06: - aux_rd_interval_us = 64000; - break; - default: - break; - } - - return aux_rd_interval_us; -} - -enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status) -{ - enum link_training_result result = LINK_TRAINING_SUCCESS; - - if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0) - result = LINK_TRAINING_CR_FAIL_LANE0; - else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0) - result = LINK_TRAINING_CR_FAIL_LANE1; - else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0) - result = LINK_TRAINING_CR_FAIL_LANE23; - else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0) - result = LINK_TRAINING_CR_FAIL_LANE23; - return result; -} - -static enum link_training_result perform_channel_equalization_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings, - uint32_t offset) -{ - enum dc_dp_training_pattern tr_pattern; - uint32_t retries_ch_eq; - uint32_t wait_time_microsec; - enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_align_status_updated dpcd_lane_status_updated = {0}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - - /* Note: also check that TPS4 is a supported feature*/ - tr_pattern = lt_settings->pattern_for_eq; - - if (is_repeater(lt_settings, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) - tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; - - dp_set_hw_training_pattern(link, link_res, tr_pattern, offset); - - for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; - retries_ch_eq++) { - - dp_set_hw_lane_settings(link, link_res, lt_settings, offset); - - /* 2. update DPCD*/ - if (!retries_ch_eq) - /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration - */ - - dpcd_set_lt_pattern_and_lane_settings( - link, - lt_settings, - tr_pattern, offset); - else - dpcd_set_lane_settings(link, lt_settings, offset); - - /* 3. wait for receiver to lock-on*/ - wait_time_microsec = lt_settings->eq_pattern_time; - - if (is_repeater(lt_settings, offset)) - wait_time_microsec = - dp_translate_training_aux_read_interval( - link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); - - dp_wait_for_training_aux_rd_interval( - link, - wait_time_microsec); - - /* 4. Read lane status and requested - * drive settings as set by the sink*/ - - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - offset); - - /* 5. check CR done*/ - if (!dp_is_cr_done(lane_count, dpcd_lane_status)) - return dpcd_lane_status[0].bits.CR_DONE_0 ? - LINK_TRAINING_EQ_FAIL_CR_PARTIAL : - LINK_TRAINING_EQ_FAIL_CR; - - /* 6. check CHEQ done*/ - if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && - dp_is_symbol_locked(lane_count, dpcd_lane_status) && - dp_is_interlane_aligned(dpcd_lane_status_updated)) - return LINK_TRAINING_SUCCESS; - - /* 7. update VS/PE/PC2 in lt_settings*/ - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - } - - return LINK_TRAINING_EQ_FAIL_EQ; - -} - -static void start_clock_recovery_pattern_early(struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings, - uint32_t offset) -{ - DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n", - __func__); - dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); - dp_set_hw_lane_settings(link, link_res, lt_settings, offset); - udelay(400); -} - -static enum link_training_result perform_clock_recovery_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings, - uint32_t offset) -{ - uint32_t retries_cr; - uint32_t retry_count; - uint32_t wait_time_microsec; - enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; - union lane_align_status_updated dpcd_lane_status_updated; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - - retries_cr = 0; - retry_count = 0; - - memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); - memset(&dpcd_lane_status_updated, '\0', - sizeof(dpcd_lane_status_updated)); - - if (!link->ctx->dc->work_arounds.lt_early_cr_pattern) - dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); - - /* najeeb - The synaptics MST hub can put the LT in - * infinite loop by switching the VS - */ - /* between level 0 and level 1 continuously, here - * we try for CR lock for LinkTrainingMaxCRRetry count*/ - while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && - (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { - - - /* 1. call HWSS to set lane settings*/ - dp_set_hw_lane_settings( - link, - link_res, - lt_settings, - offset); - - /* 2. update DPCD of the receiver*/ - if (!retry_count) - /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration.*/ - dpcd_set_lt_pattern_and_lane_settings( - link, - lt_settings, - lt_settings->pattern_for_cr, - offset); - else - dpcd_set_lane_settings( - link, - lt_settings, - offset); - - /* 3. wait receiver to lock-on*/ - wait_time_microsec = lt_settings->cr_pattern_time; - - dp_wait_for_training_aux_rd_interval( - link, - wait_time_microsec); - - /* 4. Read lane status and requested drive - * settings as set by the sink - */ - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - offset); - - /* 5. check CR done*/ - if (dp_is_cr_done(lane_count, dpcd_lane_status)) - return LINK_TRAINING_SUCCESS; - - /* 6. max VS reached*/ - if ((dp_get_link_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING) && - dp_is_max_vs_reached(lt_settings)) - break; - - /* 7. same lane settings*/ - /* Note: settings are the same for all lanes, - * so comparing first lane is sufficient*/ - if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) && - lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == - dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) - retries_cr++; - else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) && - lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE == - dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE) - retries_cr++; - else - retries_cr = 0; - - /* 8. update VS/PE/PC2 in lt_settings*/ - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - retry_count++; - } - - if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { - ASSERT(0); - DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", - __func__, - LINK_TRAINING_MAX_CR_RETRY); - - } - - return dp_get_cr_failure(lane_count, dpcd_lane_status); -} - -static inline enum link_training_result dp_transition_to_video_idle( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings, - enum link_training_result status) -{ - union lane_count_set lane_count_set = {0}; - - /* 4. mainlink output idle pattern*/ - dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); - - /* - * 5. post training adjust if required - * If the upstream DPTX and downstream DPRX both support TPS4, - * TPS4 must be used instead of POST_LT_ADJ_REQ. - */ - if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 || - lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) { - /* delay 5ms after Main Link output idle pattern and then check - * DPCD 0202h. - */ - if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) { - msleep(5); - status = dp_check_link_loss_status(link, lt_settings); - } - return status; - } - - if (status == LINK_TRAINING_SUCCESS && - perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false) - status = LINK_TRAINING_LQA_FAIL; - - lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; - lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; - - core_link_write_dpcd( - link, - DP_LANE_COUNT_SET, - &lane_count_set.raw, - sizeof(lane_count_set)); - - return status; -} - -enum link_training_result dp_check_link_loss_status( - struct dc_link *link, - const struct link_training_settings *link_training_setting) -{ - enum link_training_result status = LINK_TRAINING_SUCCESS; - union lane_status lane_status; - uint8_t dpcd_buf[6] = {0}; - uint32_t lane; - - core_link_read_dpcd( - link, - DP_SINK_COUNT, - (uint8_t *)(dpcd_buf), - sizeof(dpcd_buf)); - - /*parse lane status*/ - for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { - /* - * check lanes status - */ - lane_status.raw = get_nibble_at_index(&dpcd_buf[2], lane); - - if (!lane_status.bits.CHANNEL_EQ_DONE_0 || - !lane_status.bits.CR_DONE_0 || - !lane_status.bits.SYMBOL_LOCKED_0) { - /* if one of the channel equalization, clock - * recovery or symbol lock is dropped - * consider it as (link has been - * dropped) dp sink status has changed - */ - status = LINK_TRAINING_LINK_LOSS; - break; - } - } - - return status; -} - -static inline void decide_8b_10b_training_settings( - struct dc_link *link, - const struct dc_link_settings *link_setting, - struct link_training_settings *lt_settings) -{ - memset(lt_settings, '\0', sizeof(struct link_training_settings)); - - /* Initialize link settings */ - lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set; - lt_settings->link_settings.link_rate_set = link_setting->link_rate_set; - lt_settings->link_settings.link_rate = link_setting->link_rate; - lt_settings->link_settings.lane_count = link_setting->lane_count; - /* TODO hard coded to SS for now - * lt_settings.link_settings.link_spread = - * dal_display_path_is_ss_supported( - * path_mode->display_path) ? - * LINK_SPREAD_05_DOWNSPREAD_30KHZ : - * LINK_SPREAD_DISABLED; - */ - lt_settings->link_settings.link_spread = link->dp_ss_off ? - LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ; - lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting); - lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting); - lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting); - lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); - lt_settings->enhanced_framing = 1; - lt_settings->should_set_fec_ready = true; - lt_settings->disallow_per_lane_settings = true; - lt_settings->always_match_dpcd_with_hw_lane_settings = true; - lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link); - dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); -} - -static inline void decide_128b_132b_training_settings(struct dc_link *link, - const struct dc_link_settings *link_settings, - struct link_training_settings *lt_settings) -{ - memset(lt_settings, 0, sizeof(*lt_settings)); - - lt_settings->link_settings = *link_settings; - /* TODO: should decide link spread when populating link_settings */ - lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED : - LINK_SPREAD_05_DOWNSPREAD_30KHZ; - - lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings); - lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings); - lt_settings->eq_pattern_time = 2500; - lt_settings->eq_wait_time_limit = 400000; - lt_settings->eq_loop_count_limit = 20; - lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS; - lt_settings->cds_pattern_time = 2500; - lt_settings->cds_wait_time_limit = (dp_convert_to_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000; - lt_settings->disallow_per_lane_settings = true; - lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link); - dp_hw_to_dpcd_lane_settings(lt_settings, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); -} - -void dp_decide_training_settings( - struct dc_link *link, - const struct dc_link_settings *link_settings, - struct link_training_settings *lt_settings) -{ - if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) - decide_8b_10b_training_settings(link, link_settings, lt_settings); - else if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) - decide_128b_132b_training_settings(link, link_settings, lt_settings); -} - -static void override_training_settings( - struct dc_link *link, - const struct dc_link_training_overrides *overrides, - struct link_training_settings *lt_settings) -{ - uint32_t lane; - - /* Override link spread */ - if (!link->dp_ss_off && overrides->downspread != NULL) - lt_settings->link_settings.link_spread = *overrides->downspread ? - LINK_SPREAD_05_DOWNSPREAD_30KHZ - : LINK_SPREAD_DISABLED; - - /* Override lane settings */ - if (overrides->voltage_swing != NULL) - lt_settings->voltage_swing = overrides->voltage_swing; - if (overrides->pre_emphasis != NULL) - lt_settings->pre_emphasis = overrides->pre_emphasis; - if (overrides->post_cursor2 != NULL) - lt_settings->post_cursor2 = overrides->post_cursor2; - if (overrides->ffe_preset != NULL) - lt_settings->ffe_preset = overrides->ffe_preset; - /* Override HW lane settings with BIOS forced values if present */ - if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && - lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { - lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING; - lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS; - lt_settings->always_match_dpcd_with_hw_lane_settings = false; - } - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = - lt_settings->voltage_swing != NULL ? - *lt_settings->voltage_swing : - VOLTAGE_SWING_LEVEL0; - lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = - lt_settings->pre_emphasis != NULL ? - *lt_settings->pre_emphasis - : PRE_EMPHASIS_DISABLED; - lt_settings->hw_lane_settings[lane].POST_CURSOR2 = - lt_settings->post_cursor2 != NULL ? - *lt_settings->post_cursor2 - : POST_CURSOR2_DISABLED; - } - - if (lt_settings->always_match_dpcd_with_hw_lane_settings) - dp_hw_to_dpcd_lane_settings(lt_settings, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - - /* Initialize training timings */ - if (overrides->cr_pattern_time != NULL) - lt_settings->cr_pattern_time = *overrides->cr_pattern_time; - - if (overrides->eq_pattern_time != NULL) - lt_settings->eq_pattern_time = *overrides->eq_pattern_time; - - if (overrides->pattern_for_cr != NULL) - lt_settings->pattern_for_cr = *overrides->pattern_for_cr; - if (overrides->pattern_for_eq != NULL) - lt_settings->pattern_for_eq = *overrides->pattern_for_eq; - - if (overrides->enhanced_framing != NULL) - lt_settings->enhanced_framing = *overrides->enhanced_framing; - - if (link->preferred_training_settings.fec_enable != NULL) - lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; - - #if defined(CONFIG_DRM_AMD_DC_DCN) - /* Check DP tunnel LTTPR mode debug option. */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr) - lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR; - -#endif - dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); - -} - -uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count) -{ - switch (lttpr_repeater_count) { - case 0x80: // 1 lttpr repeater - return 1; - case 0x40: // 2 lttpr repeaters - return 2; - case 0x20: // 3 lttpr repeaters - return 3; - case 0x10: // 4 lttpr repeaters - return 4; - case 0x08: // 5 lttpr repeaters - return 5; - case 0x04: // 6 lttpr repeaters - return 6; - case 0x02: // 7 lttpr repeaters - return 7; - case 0x01: // 8 lttpr repeaters - return 8; - default: - break; - } - return 0; // invalid value -} - -static enum dc_status configure_lttpr_mode_transparent(struct dc_link *link) -{ - uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; - - DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); - return core_link_write_dpcd(link, - DP_PHY_REPEATER_MODE, - (uint8_t *)&repeater_mode, - sizeof(repeater_mode)); -} - -static enum dc_status configure_lttpr_mode_non_transparent( - struct dc_link *link, - const struct link_training_settings *lt_settings) -{ - /* aux timeout is already set to extended */ - /* RESET/SET lttpr mode to enable non transparent mode */ - uint8_t repeater_cnt; - uint32_t aux_interval_address; - uint8_t repeater_id; - enum dc_status result = DC_ERROR_UNEXPECTED; - uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; - - enum dp_link_encoding encoding = dp_get_link_encoding_format(<_settings->link_settings); - - if (encoding == DP_8b_10b_ENCODING) { - DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); - result = core_link_write_dpcd(link, - DP_PHY_REPEATER_MODE, - (uint8_t *)&repeater_mode, - sizeof(repeater_mode)); - - } - - if (result == DC_OK) { - link->dpcd_caps.lttpr_caps.mode = repeater_mode; - } - - if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { - - DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__); - - repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT; - result = core_link_write_dpcd(link, - DP_PHY_REPEATER_MODE, - (uint8_t *)&repeater_mode, - sizeof(repeater_mode)); - - if (result == DC_OK) { - link->dpcd_caps.lttpr_caps.mode = repeater_mode; - } - - if (encoding == DP_8b_10b_ENCODING) { - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - - /* Driver does not need to train the first hop. Skip DPCD read and clear - * AUX_RD_INTERVAL for DPTX-to-DPIA hop. - */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) - link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0; - - for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) { - aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 + - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1)); - core_link_read_dpcd( - link, - aux_interval_address, - (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1], - sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1])); - link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F; - } - } - } - - return result; -} - -static void repeater_training_done(struct dc_link *link, uint32_t offset) -{ - union dpcd_training_pattern dpcd_pattern = {0}; - - const uint32_t dpcd_base_lt_offset = - DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - /* Set training not in progress*/ - dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; - - core_link_write_dpcd( - link, - dpcd_base_lt_offset, - &dpcd_pattern.raw, - 1); - - DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n", - __func__, - offset, - dpcd_base_lt_offset, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); -} - -static void print_status_message( - struct dc_link *link, - const struct link_training_settings *lt_settings, - enum link_training_result status) -{ - char *link_rate = "Unknown"; - char *lt_result = "Unknown"; - char *lt_spread = "Disabled"; - - switch (lt_settings->link_settings.link_rate) { - case LINK_RATE_LOW: - link_rate = "RBR"; - break; - case LINK_RATE_RATE_2: - link_rate = "R2"; - break; - case LINK_RATE_RATE_3: - link_rate = "R3"; - break; - case LINK_RATE_HIGH: - link_rate = "HBR"; - break; - case LINK_RATE_RBR2: - link_rate = "RBR2"; - break; - case LINK_RATE_RATE_6: - link_rate = "R6"; - break; - case LINK_RATE_HIGH2: - link_rate = "HBR2"; - break; - case LINK_RATE_HIGH3: - link_rate = "HBR3"; - break; - case LINK_RATE_UHBR10: - link_rate = "UHBR10"; - break; - case LINK_RATE_UHBR13_5: - link_rate = "UHBR13.5"; - break; - case LINK_RATE_UHBR20: - link_rate = "UHBR20"; - break; - default: - break; - } - - switch (status) { - case LINK_TRAINING_SUCCESS: - lt_result = "pass"; - break; - case LINK_TRAINING_CR_FAIL_LANE0: - lt_result = "CR failed lane0"; - break; - case LINK_TRAINING_CR_FAIL_LANE1: - lt_result = "CR failed lane1"; - break; - case LINK_TRAINING_CR_FAIL_LANE23: - lt_result = "CR failed lane23"; - break; - case LINK_TRAINING_EQ_FAIL_CR: - lt_result = "CR failed in EQ"; - break; - case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: - lt_result = "CR failed in EQ partially"; - break; - case LINK_TRAINING_EQ_FAIL_EQ: - lt_result = "EQ failed"; - break; - case LINK_TRAINING_LQA_FAIL: - lt_result = "LQA failed"; - break; - case LINK_TRAINING_LINK_LOSS: - lt_result = "Link loss"; - break; - case DP_128b_132b_LT_FAILED: - lt_result = "LT_FAILED received"; - break; - case DP_128b_132b_MAX_LOOP_COUNT_REACHED: - lt_result = "max loop count reached"; - break; - case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT: - lt_result = "channel EQ timeout"; - break; - case DP_128b_132b_CDS_DONE_TIMEOUT: - lt_result = "CDS timeout"; - break; - default: - break; - } - - switch (lt_settings->link_settings.link_spread) { - case LINK_SPREAD_DISABLED: - lt_spread = "Disabled"; - break; - case LINK_SPREAD_05_DOWNSPREAD_30KHZ: - lt_spread = "0.5% 30KHz"; - break; - case LINK_SPREAD_05_DOWNSPREAD_33KHZ: - lt_spread = "0.5% 33KHz"; - break; - default: - break; - } - - /* Connectivity log: link training */ - - /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */ - - CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s", - link_rate, - lt_settings->link_settings.lane_count, - lt_result, - lt_settings->hw_lane_settings[0].VOLTAGE_SWING, - lt_settings->hw_lane_settings[0].PRE_EMPHASIS, - lt_spread); -} - -void dc_link_dp_set_drive_settings( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - /* program ASIC PHY settings*/ - dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); - - dp_hw_to_dpcd_lane_settings(lt_settings, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - - /* Notify DP sink the PHY settings from source */ - dpcd_set_lane_settings(link, lt_settings, DPRX); -} - -bool dc_link_dp_perform_link_training_skip_aux( - struct dc_link *link, - const struct link_resource *link_res, - const struct dc_link_settings *link_setting) -{ - struct link_training_settings lt_settings = {0}; - - dp_decide_training_settings( - link, - link_setting, - <_settings); - override_training_settings( - link, - &link->preferred_training_settings, - <_settings); - - /* 1. Perform_clock_recovery_sequence. */ - - /* transmit training pattern for clock recovery */ - dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX); - - /* call HWSS to set lane settings*/ - dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); - - /* wait receiver to lock-on*/ - dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); - - /* 2. Perform_channel_equalization_sequence. */ - - /* transmit training pattern for channel equalization. */ - dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX); - - /* call HWSS to set lane settings*/ - dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); - - /* wait receiver to lock-on. */ - dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); - - /* 3. Perform_link_training_int. */ - - /* Mainlink output idle pattern. */ - dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); - - print_status_message(link, <_settings, LINK_TRAINING_SUCCESS); - - return true; -} - -enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings) -{ - enum dc_status status = DC_OK; - - if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) - status = configure_lttpr_mode_transparent(link); - - else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) - status = configure_lttpr_mode_non_transparent(link, lt_settings); - - return status; -} - -static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding) -{ - uint8_t sink_status = 0; - uint8_t i; - - /* clear training pattern set */ - dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); - - if (encoding == DP_128b_132b_ENCODING) { - /* poll for intra-hop disable */ - for (i = 0; i < 10; i++) { - if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) && - (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0) - break; - udelay(1000); - } - } -} - -enum dc_status dpcd_configure_channel_coding(struct dc_link *link, - struct link_training_settings *lt_settings) -{ - enum dp_link_encoding encoding = - dp_get_link_encoding_format( - <_settings->link_settings); - enum dc_status status; - - status = core_link_write_dpcd( - link, - DP_MAIN_LINK_CHANNEL_CODING_SET, - (uint8_t *) &encoding, - 1); - DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n", - __func__, - DP_MAIN_LINK_CHANNEL_CODING_SET, - encoding); - - return status; -} - -static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link, - uint32_t *interval_in_us) -{ - union dp_128b_132b_training_aux_rd_interval dpcd_interval; - uint32_t interval_unit = 0; - - dpcd_interval.raw = 0; - core_link_read_dpcd(link, DP_128b_132b_TRAINING_AUX_RD_INTERVAL, - &dpcd_interval.raw, sizeof(dpcd_interval.raw)); - interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */ - /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) * - * INTERVAL_UNIT. The maximum is 256 ms - */ - *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000; -} - -static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - uint8_t loop_count; - uint32_t aux_rd_interval = 0; - uint32_t wait_time = 0; - union lane_align_status_updated dpcd_lane_status_updated = {0}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - enum dc_status status = DC_OK; - enum link_training_result result = LINK_TRAINING_SUCCESS; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - - /* Transmit 128b/132b_TPS1 over Main-Link */ - dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX); - /* Set TRAINING_PATTERN_SET to 01h */ - dpcd_set_training_pattern(link, lt_settings->pattern_for_cr); - - /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */ - dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); - dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); - dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX); - - /* Set loop counter to start from 1 */ - loop_count = 1; - - /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */ - dpcd_set_lt_pattern_and_lane_settings(link, lt_settings, - lt_settings->pattern_for_eq, DPRX); - - /* poll for channel EQ done */ - while (result == LINK_TRAINING_SUCCESS) { - dp_wait_for_training_aux_rd_interval(link, aux_rd_interval); - wait_time += aux_rd_interval; - status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); - if (status != DC_OK) { - result = LINK_TRAINING_ABORT; - } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, - dpcd_lane_status)) { - /* pass */ - break; - } else if (loop_count >= lt_settings->eq_loop_count_limit) { - result = DP_128b_132b_MAX_LOOP_COUNT_REACHED; - } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { - result = DP_128b_132b_LT_FAILED; - } else { - dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); - dpcd_128b_132b_set_lane_settings(link, lt_settings); - } - loop_count++; - } - - /* poll for EQ interlane align done */ - while (result == LINK_TRAINING_SUCCESS) { - if (status != DC_OK) { - result = LINK_TRAINING_ABORT; - } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) { - /* pass */ - break; - } else if (wait_time >= lt_settings->eq_wait_time_limit) { - result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT; - } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { - result = DP_128b_132b_LT_FAILED; - } else { - dp_wait_for_training_aux_rd_interval(link, - lt_settings->eq_pattern_time); - wait_time += lt_settings->eq_pattern_time; - status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); - } - } - - return result; -} - -static enum link_training_result dp_perform_128b_132b_cds_done_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - /* Assumption: assume hardware has transmitted eq pattern */ - enum dc_status status = DC_OK; - enum link_training_result result = LINK_TRAINING_SUCCESS; - union lane_align_status_updated dpcd_lane_status_updated = {0}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - uint32_t wait_time = 0; - - /* initiate CDS done sequence */ - dpcd_set_training_pattern(link, lt_settings->pattern_for_cds); - - /* poll for CDS interlane align done and symbol lock */ - while (result == LINK_TRAINING_SUCCESS) { - dp_wait_for_training_aux_rd_interval(link, - lt_settings->cds_pattern_time); - wait_time += lt_settings->cds_pattern_time; - status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, - &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); - if (status != DC_OK) { - result = LINK_TRAINING_ABORT; - } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) && - dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) { - /* pass */ - break; - } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { - result = DP_128b_132b_LT_FAILED; - } else if (wait_time >= lt_settings->cds_wait_time_limit) { - result = DP_128b_132b_CDS_DONE_TIMEOUT; - } - } - - return result; -} - -static enum link_training_result dp_perform_8b_10b_link_training( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - enum link_training_result status = LINK_TRAINING_SUCCESS; - - uint8_t repeater_cnt; - uint8_t repeater_id; - uint8_t lane = 0; - - if (link->ctx->dc->work_arounds.lt_early_cr_pattern) - start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); - - /* 1. set link rate, lane count and spread. */ - dpcd_set_link_settings(link, lt_settings); - - if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { - - /* 2. perform link training (set link training done - * to false is done as well) - */ - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - - for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); - repeater_id--) { - status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); - - if (status != LINK_TRAINING_SUCCESS) { - repeater_training_done(link, repeater_id); - break; - } - - status = perform_channel_equalization_sequence(link, - link_res, - lt_settings, - repeater_id); - - repeater_training_done(link, repeater_id); - - if (status != LINK_TRAINING_SUCCESS) - break; - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - lt_settings->dpcd_lane_settings[lane].raw = 0; - lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; - lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; - } - } - } - - if (status == LINK_TRAINING_SUCCESS) { - status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX); - if (status == LINK_TRAINING_SUCCESS) { - status = perform_channel_equalization_sequence(link, - link_res, - lt_settings, - DPRX); - } - } - - return status; -} - -static enum link_training_result dp_perform_128b_132b_link_training( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - enum link_training_result result = LINK_TRAINING_SUCCESS; - - /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */ - if (link->dc->debug.legacy_dp2_lt) { - struct link_training_settings legacy_settings; - - decide_8b_10b_training_settings(link, - <_settings->link_settings, - &legacy_settings); - return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings); - } - - dpcd_set_link_settings(link, lt_settings); - - if (result == LINK_TRAINING_SUCCESS) - result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings); - - if (result == LINK_TRAINING_SUCCESS) - result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings); - - return result; -} - -static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - enum link_training_result status = LINK_TRAINING_SUCCESS; - uint8_t lane = 0; - uint8_t toggle_rate = 0x6; - uint8_t target_rate = 0x6; - bool apply_toggle_rate_wa = false; - uint8_t repeater_cnt; - uint8_t repeater_id; - - /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */ - if (lt_settings->cr_pattern_time < 16000) - lt_settings->cr_pattern_time = 16000; - - /* Fixed VS/PE specific: Toggle link rate */ - apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate); - target_rate = get_dpcd_link_rate(<_settings->link_settings); - toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; - - if (apply_toggle_rate_wa) - lt_settings->link_settings.link_rate = toggle_rate; - - if (link->ctx->dc->work_arounds.lt_early_cr_pattern) - start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); - - /* 1. set link rate, lane count and spread. */ - dpcd_set_link_settings(link, lt_settings); - - /* Fixed VS/PE specific: Toggle link rate back*/ - if (apply_toggle_rate_wa) { - core_link_write_dpcd( - link, - DP_LINK_BW_SET, - &target_rate, - 1); - } - - link->vendor_specific_lttpr_link_rate_wa = target_rate; - - if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { - - /* 2. perform link training (set link training done - * to false is done as well) - */ - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - - for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); - repeater_id--) { - status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); - - if (status != LINK_TRAINING_SUCCESS) { - repeater_training_done(link, repeater_id); - break; - } - - status = perform_channel_equalization_sequence(link, - link_res, - lt_settings, - repeater_id); - - repeater_training_done(link, repeater_id); - - if (status != LINK_TRAINING_SUCCESS) - break; - - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - lt_settings->dpcd_lane_settings[lane].raw = 0; - lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; - lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; - } - } - } - - if (status == LINK_TRAINING_SUCCESS) { - status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX); - if (status == LINK_TRAINING_SUCCESS) { - status = perform_channel_equalization_sequence(link, - link_res, - lt_settings, - DPRX); - } - } - - return status; -} - -static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; - const uint8_t offset = dp_convert_to_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; - const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; - uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; - uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; - uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; - uint32_t vendor_lttpr_write_address = 0xF004F; - enum link_training_result status = LINK_TRAINING_SUCCESS; - uint8_t lane = 0; - union down_spread_ctrl downspread = {0}; - union lane_count_set lane_count_set = {0}; - uint8_t toggle_rate; - uint8_t rate; - - /* Only 8b/10b is supported */ - ASSERT(dp_get_link_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING); - - if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { - status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); - return status; - } - - if (offset != 0xFF) { - vendor_lttpr_write_address += - ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); - - /* Certain display and cable configuration require extra delay */ - if (offset > 2) - pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; - } - - /* Vendor specific: Reset lane settings */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_reset[0], - sizeof(vendor_lttpr_write_data_reset)); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_vs[0], - sizeof(vendor_lttpr_write_data_vs)); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_pe[0], - sizeof(vendor_lttpr_write_data_pe)); - - /* Vendor specific: Enable intercept */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_intercept_en[0], - sizeof(vendor_lttpr_write_data_intercept_en)); - - /* 1. set link rate, lane count and spread. */ - - downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); - - lane_count_set.bits.LANE_COUNT_SET = - lt_settings->link_settings.lane_count; - - lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; - - - if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = - link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; - } - - core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, - &downspread.raw, sizeof(downspread)); - - core_link_write_dpcd(link, DP_LANE_COUNT_SET, - &lane_count_set.raw, 1); - - rate = get_dpcd_link_rate(<_settings->link_settings); - - /* Vendor specific: Toggle link rate */ - toggle_rate = (rate == 0x6) ? 0xA : 0x6; - - if (link->vendor_specific_lttpr_link_rate_wa == rate) { - core_link_write_dpcd( - link, - DP_LINK_BW_SET, - &toggle_rate, - 1); - } - - link->vendor_specific_lttpr_link_rate_wa = rate; - - core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); - - DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", - __func__, - DP_LINK_BW_SET, - lt_settings->link_settings.link_rate, - DP_LANE_COUNT_SET, - lt_settings->link_settings.lane_count, - lt_settings->enhanced_framing, - DP_DOWNSPREAD_CTRL, - lt_settings->link_settings.link_spread); - - /* 2. Perform link training */ - - /* Perform Clock Recovery Sequence */ - if (status == LINK_TRAINING_SUCCESS) { - const uint8_t max_vendor_dpcd_retries = 10; - uint32_t retries_cr; - uint32_t retry_count; - uint32_t wait_time_microsec; - enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; - union lane_align_status_updated dpcd_lane_status_updated; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - enum dc_status dpcd_status = DC_OK; - uint8_t i = 0; - - retries_cr = 0; - retry_count = 0; - - memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); - memset(&dpcd_lane_status_updated, '\0', - sizeof(dpcd_lane_status_updated)); - - while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && - (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { - - - /* 1. call HWSS to set lane settings */ - dp_set_hw_lane_settings( - link, - link_res, - lt_settings, - 0); - - /* 2. update DPCD of the receiver */ - if (!retry_count) { - /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration. - */ - dpcd_set_lt_pattern_and_lane_settings( - link, - lt_settings, - lt_settings->pattern_for_cr, - 0); - /* Vendor specific: Disable intercept */ - for (i = 0; i < max_vendor_dpcd_retries; i++) { - msleep(pre_disable_intercept_delay_ms); - dpcd_status = core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_intercept_dis[0], - sizeof(vendor_lttpr_write_data_intercept_dis)); - - if (dpcd_status == DC_OK) - break; - - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_intercept_en[0], - sizeof(vendor_lttpr_write_data_intercept_en)); - } - } else { - vendor_lttpr_write_data_vs[3] = 0; - vendor_lttpr_write_data_pe[3] = 0; - - for (lane = 0; lane < lane_count; lane++) { - vendor_lttpr_write_data_vs[3] |= - lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); - vendor_lttpr_write_data_pe[3] |= - lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); - } - - /* Vendor specific: Update VS and PE to DPRX requested value */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_vs[0], - sizeof(vendor_lttpr_write_data_vs)); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_pe[0], - sizeof(vendor_lttpr_write_data_pe)); - - dpcd_set_lane_settings( - link, - lt_settings, - 0); - } - - /* 3. wait receiver to lock-on*/ - wait_time_microsec = lt_settings->cr_pattern_time; - - dp_wait_for_training_aux_rd_interval( - link, - wait_time_microsec); - - /* 4. Read lane status and requested drive - * settings as set by the sink - */ - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - 0); - - /* 5. check CR done*/ - if (dp_is_cr_done(lane_count, dpcd_lane_status)) { - status = LINK_TRAINING_SUCCESS; - break; - } - - /* 6. max VS reached*/ - if (dp_is_max_vs_reached(lt_settings)) - break; - - /* 7. same lane settings */ - /* Note: settings are the same for all lanes, - * so comparing first lane is sufficient - */ - if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == - dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) - retries_cr++; - else - retries_cr = 0; - - /* 8. update VS/PE/PC2 in lt_settings*/ - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - retry_count++; - } - - if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { - ASSERT(0); - DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", - __func__, - LINK_TRAINING_MAX_CR_RETRY); - - } - - status = dp_get_cr_failure(lane_count, dpcd_lane_status); - } - - /* Perform Channel EQ Sequence */ - if (status == LINK_TRAINING_SUCCESS) { - enum dc_dp_training_pattern tr_pattern; - uint32_t retries_ch_eq; - uint32_t wait_time_microsec; - enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_align_status_updated dpcd_lane_status_updated = {0}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - - /* Note: also check that TPS4 is a supported feature*/ - tr_pattern = lt_settings->pattern_for_eq; - - dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); - - status = LINK_TRAINING_EQ_FAIL_EQ; - - for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; - retries_ch_eq++) { - - dp_set_hw_lane_settings(link, link_res, lt_settings, 0); - - vendor_lttpr_write_data_vs[3] = 0; - vendor_lttpr_write_data_pe[3] = 0; - - for (lane = 0; lane < lane_count; lane++) { - vendor_lttpr_write_data_vs[3] |= - lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); - vendor_lttpr_write_data_pe[3] |= - lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); - } - - /* Vendor specific: Update VS and PE to DPRX requested value */ - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_vs[0], - sizeof(vendor_lttpr_write_data_vs)); - core_link_write_dpcd( - link, - vendor_lttpr_write_address, - &vendor_lttpr_write_data_pe[0], - sizeof(vendor_lttpr_write_data_pe)); - - /* 2. update DPCD*/ - if (!retries_ch_eq) - /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration - */ - - dpcd_set_lt_pattern_and_lane_settings( - link, - lt_settings, - tr_pattern, 0); - else - dpcd_set_lane_settings(link, lt_settings, 0); - - /* 3. wait for receiver to lock-on*/ - wait_time_microsec = lt_settings->eq_pattern_time; - - dp_wait_for_training_aux_rd_interval( - link, - wait_time_microsec); - - /* 4. Read lane status and requested - * drive settings as set by the sink - */ - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - 0); - - /* 5. check CR done*/ - if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { - status = LINK_TRAINING_EQ_FAIL_CR; - break; - } - - /* 6. check CHEQ done*/ - if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && - dp_is_symbol_locked(lane_count, dpcd_lane_status) && - dp_is_interlane_aligned(dpcd_lane_status_updated)) { - status = LINK_TRAINING_SUCCESS; - break; - } - - /* 7. update VS/PE/PC2 in lt_settings*/ - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - } - } - - return status; -} - - -enum link_training_result dc_link_dp_perform_link_training( - struct dc_link *link, - const struct link_resource *link_res, - const struct dc_link_settings *link_settings, - bool skip_video_pattern) -{ - enum link_training_result status = LINK_TRAINING_SUCCESS; - struct link_training_settings lt_settings = {0}; - enum dp_link_encoding encoding = - dp_get_link_encoding_format(link_settings); - - /* decide training settings */ - dp_decide_training_settings( - link, - link_settings, - <_settings); - - override_training_settings( - link, - &link->preferred_training_settings, - <_settings); - - /* reset previous training states */ - dpcd_exit_training_mode(link, encoding); - - /* configure link prior to entering training mode */ - dpcd_configure_lttpr_mode(link, <_settings); - dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready); - dpcd_configure_channel_coding(link, <_settings); - - /* enter training mode: - * Per DP specs starting from here, DPTX device shall not issue - * Non-LT AUX transactions inside training mode. - */ - if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && encoding == DP_8b_10b_ENCODING) - status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); - else if (encoding == DP_8b_10b_ENCODING) - status = dp_perform_8b_10b_link_training(link, link_res, <_settings); - else if (encoding == DP_128b_132b_ENCODING) - status = dp_perform_128b_132b_link_training(link, link_res, <_settings); - else - ASSERT(0); - - /* exit training mode */ - dpcd_exit_training_mode(link, encoding); - - /* switch to video idle */ - if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) - status = dp_transition_to_video_idle(link, - link_res, - <_settings, - status); - - /* dump debug data */ - print_status_message(link, <_settings, status); - if (status != LINK_TRAINING_SUCCESS) - link->ctx->dc->debug_data.ltFailCount++; - return status; -} - -bool perform_link_training_with_retries( - const struct dc_link_settings *link_setting, - bool skip_video_pattern, - int attempts, - struct pipe_ctx *pipe_ctx, - enum signal_type signal, - bool do_fallback) -{ - int j; - uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - enum dp_panel_mode panel_mode = dp_get_panel_mode(link); - enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0; - struct dc_link_settings cur_link_settings = *link_setting; - struct dc_link_settings max_link_settings = *link_setting; - const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - int fail_count = 0; - bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */ - bool is_link_bw_min = /* RBR x 1 */ - (cur_link_settings.link_rate <= LINK_RATE_LOW) && - (cur_link_settings.lane_count <= LANE_COUNT_ONE); - - dp_trace_commit_lt_init(link); - - if (dp_get_link_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING) - /* We need to do this before the link training to ensure the idle - * pattern in SST mode will be sent right after the link training - */ - link_hwss->setup_stream_encoder(pipe_ctx); - - dp_trace_set_lt_start_timestamp(link, false); - j = 0; - while (j < attempts && fail_count < (attempts * 10)) { - - DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n", - __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count); - - dp_enable_link_phy( - link, - &pipe_ctx->link_res, - signal, - pipe_ctx->clock_source->id, - &cur_link_settings); - - if (stream->sink_patches.dppowerup_delay > 0) { - int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; - - msleep(delay_dp_power_up_in_ms); - } - -#ifdef CONFIG_DRM_AMD_DC_HDCP - if (panel_mode == DP_PANEL_MODE_EDP) { - struct cp_psp *cp_psp = &stream->ctx->cp_psp; - - if (cp_psp && cp_psp->funcs.enable_assr) - /* ASSR is bound to fail with unsigned PSP - * verstage used during devlopment phase. - * Report and continue with eDP panel mode to - * perform eDP link training with right settings - */ - cp_psp->funcs.enable_assr(cp_psp->handle, link); - } -#endif - - dp_set_panel_mode(link, panel_mode); - - if (link->aux_access_disabled) { - dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings); - return true; - } else { - /** @todo Consolidate USB4 DP and DPx.x training. */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { - status = dc_link_dpia_perform_link_training(link, - &pipe_ctx->link_res, - &cur_link_settings, - skip_video_pattern); - - /* Transmit idle pattern once training successful. */ - if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) { - dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); - /* Update verified link settings to current one - * Because DPIA LT might fallback to lower link setting. - */ - if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - link->verified_link_cap.link_rate = link->cur_link_settings.link_rate; - link->verified_link_cap.lane_count = link->cur_link_settings.lane_count; - dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link); - } - } - } else { - status = dc_link_dp_perform_link_training(link, - &pipe_ctx->link_res, - &cur_link_settings, - skip_video_pattern); - } - - dp_trace_lt_total_count_increment(link, false); - dp_trace_lt_result_update(link, status, false); - dp_trace_set_lt_end_timestamp(link, false); - if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) - return true; - } - - fail_count++; - dp_trace_lt_fail_count_update(link, fail_count, false); - if (link->ep_type == DISPLAY_ENDPOINT_PHY) { - /* latest link training still fail or link training is aborted - * skip delay and keep PHY on - */ - if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT)) - break; - } - - DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n", - __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count, status); - - dp_disable_link_phy(link, &pipe_ctx->link_res, signal); - - /* Abort link training if failure due to sink being unplugged. */ - if (status == LINK_TRAINING_ABORT) { - enum dc_connection_type type = dc_connection_none; - - dc_link_detect_sink(link, &type); - if (type == dc_connection_none) { - DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__); - break; - } - } - - /* Try to train again at original settings if: - * - not falling back between training attempts; - * - aborted previous attempt due to reasons other than sink unplug; - * - successfully trained but at a link rate lower than that required by stream; - * - reached minimum link bandwidth. - */ - if (!do_fallback || (status == LINK_TRAINING_ABORT) || - (status == LINK_TRAINING_SUCCESS && is_link_bw_low) || - is_link_bw_min) { - j++; - cur_link_settings = *link_setting; - delay_between_attempts += LINK_TRAINING_RETRY_DELAY; - is_link_bw_low = false; - is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) && - (cur_link_settings.lane_count <= LANE_COUNT_ONE); - - } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */ - uint32_t req_bw; - uint32_t link_bw; - - decide_fallback_link_setting(link, &max_link_settings, - &cur_link_settings, status); - /* Fail link training if reduced link bandwidth no longer meets - * stream requirements. - */ - req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); - link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings); - is_link_bw_low = (req_bw > link_bw); - is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) && - (cur_link_settings.lane_count <= LANE_COUNT_ONE)); - if (is_link_bw_low) - DC_LOG_WARNING( - "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n", - __func__, link->link_index, req_bw, link_bw); - } - - msleep(delay_between_attempts); - } - return false; -} - -static enum clock_source_id get_clock_source_id(struct dc_link *link) -{ - enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED; - struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source; - - if (dp_cs != NULL) { - dp_cs_id = dp_cs->id; - } else { - /* - * dp clock source is not initialized for some reason. - * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used - */ - ASSERT(dp_cs); - } - - return dp_cs_id; -} - -static void set_dp_mst_mode(struct dc_link *link, const struct link_resource *link_res, - bool mst_enable) -{ - if (mst_enable == false && - link->type == dc_connection_mst_branch) { - /* Disable MST on link. Use only local sink. */ - dp_disable_link_phy_mst(link, link_res, link->connector_signal); - - link->type = dc_connection_single; - link->local_sink = link->remote_sinks[0]; - link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; - dc_sink_retain(link->local_sink); - dm_helpers_dp_mst_stop_top_mgr(link->ctx, link); - } else if (mst_enable == true && - link->type == dc_connection_single && - link->remote_sinks[0] != NULL) { - /* Re-enable MST on link. */ - dp_disable_link_phy(link, link_res, link->connector_signal); - dp_enable_mst_on_sink(link, true); - - link->type = dc_connection_mst_branch; - link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST; - } -} - -bool dc_link_dp_sync_lt_begin(struct dc_link *link) -{ - /* Begin Sync LT. During this time, - * DPCD:600h must not be powered down. - */ - link->sync_lt_in_progress = true; - - /*Clear any existing preferred settings.*/ - memset(&link->preferred_training_settings, 0, - sizeof(struct dc_link_training_overrides)); - memset(&link->preferred_link_setting, 0, - sizeof(struct dc_link_settings)); - - return true; -} - -enum link_training_result dc_link_dp_sync_lt_attempt( - struct dc_link *link, - const struct link_resource *link_res, - struct dc_link_settings *link_settings, - struct dc_link_training_overrides *lt_overrides) -{ - struct link_training_settings lt_settings = {0}; - enum link_training_result lt_status = LINK_TRAINING_SUCCESS; - enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT; - enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; - bool fec_enable = false; - - dp_decide_training_settings( - link, - link_settings, - <_settings); - override_training_settings( - link, - lt_overrides, - <_settings); - /* Setup MST Mode */ - if (lt_overrides->mst_enable) - set_dp_mst_mode(link, link_res, *lt_overrides->mst_enable); - - /* Disable link */ - dp_disable_link_phy(link, link_res, link->connector_signal); - - /* Enable link */ - dp_cs_id = get_clock_source_id(link); - dp_enable_link_phy(link, link_res, link->connector_signal, - dp_cs_id, link_settings); - - /* Set FEC enable */ - if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { - fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable; - dp_set_fec_ready(link, NULL, fec_enable); - } - - if (lt_overrides->alternate_scrambler_reset) { - if (*lt_overrides->alternate_scrambler_reset) - panel_mode = DP_PANEL_MODE_EDP; - else - panel_mode = DP_PANEL_MODE_DEFAULT; - } else - panel_mode = dp_get_panel_mode(link); - - dp_set_panel_mode(link, panel_mode); - - /* Attempt to train with given link training settings */ - if (link->ctx->dc->work_arounds.lt_early_cr_pattern) - start_clock_recovery_pattern_early(link, link_res, <_settings, DPRX); - - /* Set link rate, lane count and spread. */ - dpcd_set_link_settings(link, <_settings); - - /* 2. perform link training (set link training done - * to false is done as well) - */ - lt_status = perform_clock_recovery_sequence(link, link_res, <_settings, DPRX); - if (lt_status == LINK_TRAINING_SUCCESS) { - lt_status = perform_channel_equalization_sequence(link, - link_res, - <_settings, - DPRX); - } - - /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/ - /* 4. print status message*/ - print_status_message(link, <_settings, lt_status); - - return lt_status; -} - -bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down) -{ - /* If input parameter is set, shut down phy. - * Still shouldn't turn off dp_receiver (DPCD:600h) - */ - if (link_down == true) { - struct dc_link_settings link_settings = link->cur_link_settings; - dp_disable_link_phy(link, NULL, link->connector_signal); - if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) - dp_set_fec_ready(link, NULL, false); - } - - link->sync_lt_in_progress = false; - return true; -} - -static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link) -{ - enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate; - - if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20) - lttpr_max_link_rate = LINK_RATE_UHBR20; - else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5) - lttpr_max_link_rate = LINK_RATE_UHBR13_5; - else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10) - lttpr_max_link_rate = LINK_RATE_UHBR10; - - return lttpr_max_link_rate; -} - -static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link) -{ - enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN; - - if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20) - cable_max_link_rate = LINK_RATE_UHBR20; - else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY) - cable_max_link_rate = LINK_RATE_UHBR13_5; - else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10) - cable_max_link_rate = LINK_RATE_UHBR10; - - return cable_max_link_rate; -} - -bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) -{ - struct link_encoder *link_enc = NULL; - - if (!max_link_enc_cap) { - DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__); - return false; - } - - link_enc = link_enc_cfg_get_link_enc(link); - ASSERT(link_enc); - - if (link_enc && link_enc->funcs->get_max_link_cap) { - link_enc->funcs->get_max_link_cap(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; -} - - -struct dc_link_settings dp_get_max_link_cap(struct dc_link *link) -{ - struct dc_link_settings max_link_cap = {0}; - enum dc_link_rate lttpr_max_link_rate; - enum dc_link_rate cable_max_link_rate; - struct link_encoder *link_enc = NULL; - - - link_enc = link_enc_cfg_get_link_enc(link); - ASSERT(link_enc); - - /* get max link encoder capability */ - if (link_enc) - link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap); - - /* Lower link settings based on sink's link cap */ - if (link->reported_link_cap.lane_count < max_link_cap.lane_count) - max_link_cap.lane_count = - link->reported_link_cap.lane_count; - if (link->reported_link_cap.link_rate < max_link_cap.link_rate) - max_link_cap.link_rate = - link->reported_link_cap.link_rate; - if (link->reported_link_cap.link_spread < - max_link_cap.link_spread) - max_link_cap.link_spread = - link->reported_link_cap.link_spread; - - /* Lower link settings based on cable attributes - * Cable ID is a DP2 feature to identify max certified link rate that - * a cable can carry. The cable identification method requires both - * cable and display hardware support. Since the specs comes late, it is - * anticipated that the first round of DP2 cables and displays may not - * be fully compatible to reliably return cable ID data. Therefore the - * decision of our cable id policy is that if the cable can return non - * zero cable id data, we will take cable's link rate capability into - * account. However if we get zero data, the cable link rate capability - * is considered inconclusive. In this case, we will not take cable's - * capability into account to avoid of over limiting hardware capability - * from users. The max overall link rate capability is still determined - * after actual dp pre-training. Cable id is considered as an auxiliary - * method of determining max link bandwidth capability. - */ - cable_max_link_rate = get_cable_max_link_rate(link); - - if (!link->dc->debug.ignore_cable_id && - cable_max_link_rate != LINK_RATE_UNKNOWN && - cable_max_link_rate < max_link_cap.link_rate) - max_link_cap.link_rate = cable_max_link_rate; - - /* account for lttpr repeaters cap - * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). - */ - if (dp_is_lttpr_present(link)) { - if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count) - max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count; - lttpr_max_link_rate = get_lttpr_max_link_rate(link); - - if (lttpr_max_link_rate < max_link_cap.link_rate) - max_link_cap.link_rate = lttpr_max_link_rate; - - DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n", - __func__, - max_link_cap.lane_count, - max_link_cap.link_rate); - } - - if (dp_get_link_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING && - link->dc->debug.disable_uhbr) - max_link_cap.link_rate = LINK_RATE_HIGH3; - - return max_link_cap; -} - -static enum dc_status read_hpd_rx_irq_data( +enum dc_status read_hpd_rx_irq_data( struct dc_link *link, union hpd_irq_data *irq_data) { @@ -3249,372 +182,6 @@ bool hpd_rx_irq_check_link_loss_status( return return_code; } -static bool dp_verify_link_cap( - struct dc_link *link, - struct dc_link_settings *known_limit_link_setting, - int *fail_count) -{ - struct dc_link_settings cur_link_settings = {0}; - struct dc_link_settings max_link_settings = *known_limit_link_setting; - bool success = false; - bool skip_video_pattern; - enum clock_source_id dp_cs_id = get_clock_source_id(link); - enum link_training_result status = LINK_TRAINING_SUCCESS; - union hpd_irq_data irq_data; - struct link_resource link_res; - - memset(&irq_data, 0, sizeof(irq_data)); - cur_link_settings = max_link_settings; - - /* Grant extended timeout request */ - if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) { - uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80; - - core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant)); - } - - do { - if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings)) - continue; - - skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW; - dp_enable_link_phy( - link, - &link_res, - link->connector_signal, - dp_cs_id, - &cur_link_settings); - - status = dc_link_dp_perform_link_training( - link, - &link_res, - &cur_link_settings, - skip_video_pattern); - - if (status == LINK_TRAINING_SUCCESS) { - success = true; - udelay(1000); - if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK && - hpd_rx_irq_check_link_loss_status( - link, - &irq_data)) - (*fail_count)++; - - } else { - (*fail_count)++; - } - dp_trace_lt_total_count_increment(link, true); - dp_trace_lt_result_update(link, status, true); - dp_disable_link_phy(link, &link_res, link->connector_signal); - } while (!success && decide_fallback_link_setting(link, - &max_link_settings, &cur_link_settings, status)); - - link->verified_link_cap = success ? - cur_link_settings : fail_safe_link_settings; - return success; -} - -static void apply_usbc_combo_phy_reset_wa(struct dc_link *link, - struct dc_link_settings *link_settings) -{ - /* Temporary Renoir-specific workaround PHY will sometimes be in bad - * state on hotplugging display from certain USB-C dongle, so add extra - * cycle of enabling and disabling the PHY before first link training. - */ - struct link_resource link_res = {0}; - enum clock_source_id dp_cs_id = get_clock_source_id(link); - - dp_enable_link_phy(link, &link_res, link->connector_signal, - dp_cs_id, link_settings); - dp_disable_link_phy(link, &link_res, link->connector_signal); -} - -bool dp_verify_link_cap_with_retries( - struct dc_link *link, - struct dc_link_settings *known_limit_link_setting, - int attempts) -{ - int i = 0; - bool success = false; - int fail_count = 0; - - dp_trace_detect_lt_init(link); - - if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C && - link->dc->debug.usbc_combo_phy_reset_wa) - apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting); - - dp_trace_set_lt_start_timestamp(link, false); - for (i = 0; i < attempts; i++) { - enum dc_connection_type type = dc_connection_none; - - memset(&link->verified_link_cap, 0, - sizeof(struct dc_link_settings)); - if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) { - link->verified_link_cap = fail_safe_link_settings; - break; - } else if (dp_verify_link_cap(link, known_limit_link_setting, - &fail_count) && fail_count == 0) { - success = true; - break; - } - msleep(10); - } - - dp_trace_lt_fail_count_update(link, fail_count, true); - dp_trace_set_lt_end_timestamp(link, true); - - return success; -} - -/* in DP compliance test, DPR-120 may have - * a random value in its MAX_LINK_BW dpcd field. - * We map it to the maximum supported link rate that - * is smaller than MAX_LINK_BW in this case. - */ -static enum dc_link_rate get_link_rate_from_max_link_bw( - uint8_t max_link_bw) -{ - enum dc_link_rate link_rate; - - if (max_link_bw >= LINK_RATE_HIGH3) { - link_rate = LINK_RATE_HIGH3; - } else if (max_link_bw < LINK_RATE_HIGH3 - && max_link_bw >= LINK_RATE_HIGH2) { - link_rate = LINK_RATE_HIGH2; - } else if (max_link_bw < LINK_RATE_HIGH2 - && max_link_bw >= LINK_RATE_HIGH) { - link_rate = LINK_RATE_HIGH; - } else if (max_link_bw < LINK_RATE_HIGH - && max_link_bw >= LINK_RATE_LOW) { - link_rate = LINK_RATE_LOW; - } else { - link_rate = LINK_RATE_UNKNOWN; - } - - return link_rate; -} - -static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count) -{ - return lane_count <= LANE_COUNT_ONE; -} - -static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate) -{ - return link_rate <= LINK_RATE_LOW; -} - -static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count) -{ - switch (lane_count) { - case LANE_COUNT_FOUR: - return LANE_COUNT_TWO; - case LANE_COUNT_TWO: - return LANE_COUNT_ONE; - case LANE_COUNT_ONE: - return LANE_COUNT_UNKNOWN; - default: - return LANE_COUNT_UNKNOWN; - } -} - -static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate) -{ - switch (link_rate) { - case LINK_RATE_UHBR20: - return LINK_RATE_UHBR13_5; - case LINK_RATE_UHBR13_5: - return LINK_RATE_UHBR10; - case LINK_RATE_UHBR10: - return LINK_RATE_HIGH3; - case LINK_RATE_HIGH3: - return LINK_RATE_HIGH2; - case LINK_RATE_HIGH2: - return LINK_RATE_HIGH; - case LINK_RATE_HIGH: - return LINK_RATE_LOW; - case LINK_RATE_LOW: - return LINK_RATE_UNKNOWN; - default: - return LINK_RATE_UNKNOWN; - } -} - -static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count) -{ - switch (lane_count) { - case LANE_COUNT_ONE: - return LANE_COUNT_TWO; - case LANE_COUNT_TWO: - return LANE_COUNT_FOUR; - default: - return LANE_COUNT_UNKNOWN; - } -} - -static enum dc_link_rate increase_link_rate(struct dc_link *link, - enum dc_link_rate link_rate) -{ - switch (link_rate) { - case LINK_RATE_LOW: - return LINK_RATE_HIGH; - case LINK_RATE_HIGH: - return LINK_RATE_HIGH2; - case LINK_RATE_HIGH2: - return LINK_RATE_HIGH3; - case LINK_RATE_HIGH3: - return LINK_RATE_UHBR10; - case LINK_RATE_UHBR10: - /* upto DP2.x specs UHBR13.5 is the only link rate that could be - * not supported by DPRX when higher link rate is supported. - * so we treat it as a special case for code simplicity. When we - * have new specs with more link rates like this, we should - * consider a more generic solution to handle discrete link - * rate capabilities. - */ - return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ? - LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20; - case LINK_RATE_UHBR13_5: - return LINK_RATE_UHBR20; - default: - return LINK_RATE_UNKNOWN; - } -} - -static bool decide_fallback_link_setting_max_bw_policy( - struct dc_link *link, - const struct dc_link_settings *max, - struct dc_link_settings *cur, - enum link_training_result training_result) -{ - uint8_t cur_idx = 0, next_idx; - bool found = false; - - if (training_result == LINK_TRAINING_ABORT) - return false; - - while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks)) - /* find current index */ - if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count && - dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate) - break; - else - cur_idx++; - - next_idx = cur_idx + 1; - - while (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) - /* find next index */ - if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count || - dp_lt_fallbacks[next_idx].link_rate > max->link_rate) - next_idx++; - else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 && - link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0) - /* upto DP2.x specs UHBR13.5 is the only link rate that - * could be not supported by DPRX when higher link rate - * is supported. so we treat it as a special case for - * code simplicity. When we have new specs with more - * link rates like this, we should consider a more - * generic solution to handle discrete link rate - * capabilities. - */ - next_idx++; - else - break; - - if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) { - cur->lane_count = dp_lt_fallbacks[next_idx].lane_count; - cur->link_rate = dp_lt_fallbacks[next_idx].link_rate; - found = true; - } - - return found; -} - -/* - * function: set link rate and lane count fallback based - * on current link setting and last link training result - * return value: - * true - link setting could be set - * false - has reached minimum setting - * and no further fallback could be done - */ -static bool decide_fallback_link_setting( - struct dc_link *link, - struct dc_link_settings *max, - struct dc_link_settings *cur, - enum link_training_result training_result) -{ - if (dp_get_link_encoding_format(max) == DP_128b_132b_ENCODING || - link->dc->debug.force_dp2_lt_fallback_method) - return decide_fallback_link_setting_max_bw_policy(link, max, cur, - training_result); - - switch (training_result) { - case LINK_TRAINING_CR_FAIL_LANE0: - case LINK_TRAINING_CR_FAIL_LANE1: - case LINK_TRAINING_CR_FAIL_LANE23: - case LINK_TRAINING_LQA_FAIL: - { - if (!reached_minimum_link_rate(cur->link_rate)) { - cur->link_rate = reduce_link_rate(cur->link_rate); - } else if (!reached_minimum_lane_count(cur->lane_count)) { - cur->link_rate = max->link_rate; - if (training_result == LINK_TRAINING_CR_FAIL_LANE0) - return false; - else if (training_result == LINK_TRAINING_CR_FAIL_LANE1) - cur->lane_count = LANE_COUNT_ONE; - else if (training_result == LINK_TRAINING_CR_FAIL_LANE23) - cur->lane_count = LANE_COUNT_TWO; - else - cur->lane_count = reduce_lane_count(cur->lane_count); - } else { - return false; - } - break; - } - case LINK_TRAINING_EQ_FAIL_EQ: - case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: - { - if (!reached_minimum_lane_count(cur->lane_count)) { - cur->lane_count = reduce_lane_count(cur->lane_count); - } else if (!reached_minimum_link_rate(cur->link_rate)) { - cur->link_rate = reduce_link_rate(cur->link_rate); - /* Reduce max link rate to avoid potential infinite loop. - * Needed so that any subsequent CR_FAIL fallback can't - * re-set the link rate higher than the link rate from - * the latest EQ_FAIL fallback. - */ - max->link_rate = cur->link_rate; - cur->lane_count = max->lane_count; - } else { - return false; - } - break; - } - case LINK_TRAINING_EQ_FAIL_CR: - { - if (!reached_minimum_link_rate(cur->link_rate)) { - cur->link_rate = reduce_link_rate(cur->link_rate); - /* Reduce max link rate to avoid potential infinite loop. - * Needed so that any subsequent CR_FAIL fallback can't - * re-set the link rate higher than the link rate from - * the latest EQ_FAIL fallback. - */ - max->link_rate = cur->link_rate; - cur->lane_count = max->lane_count; - } else { - return false; - } - break; - } - default: - return false; - } - return true; -} - bool dp_validate_mode_timing( struct dc_link *link, const struct dc_crtc_timing *timing) @@ -3666,306 +233,6 @@ bool dp_validate_mode_timing( return false; } -static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) -{ - struct dc_link_settings initial_link_setting = { - LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0}; - struct dc_link_settings current_link_setting = - initial_link_setting; - uint32_t link_bw; - - if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) - return false; - - /* search for the minimum link setting that: - * 1. is supported according to the link training result - * 2. could support the b/w requested by the timing - */ - while (current_link_setting.link_rate <= - link->verified_link_cap.link_rate) { - link_bw = dc_link_bandwidth_kbps( - link, - ¤t_link_setting); - if (req_bw <= link_bw) { - *link_setting = current_link_setting; - return true; - } - - if (current_link_setting.lane_count < - link->verified_link_cap.lane_count) { - current_link_setting.lane_count = - increase_lane_count( - current_link_setting.lane_count); - } else { - current_link_setting.link_rate = - increase_link_rate(link, - current_link_setting.link_rate); - current_link_setting.lane_count = - initial_link_setting.lane_count; - } - } - - return false; -} - -bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) -{ - struct dc_link_settings initial_link_setting; - struct dc_link_settings current_link_setting; - uint32_t link_bw; - - /* - * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. - * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" - */ - if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || - link->dpcd_caps.edp_supported_link_rates_count == 0) { - *link_setting = link->verified_link_cap; - return true; - } - - memset(&initial_link_setting, 0, sizeof(initial_link_setting)); - initial_link_setting.lane_count = LANE_COUNT_ONE; - initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; - initial_link_setting.link_spread = LINK_SPREAD_DISABLED; - initial_link_setting.use_link_rate_set = true; - initial_link_setting.link_rate_set = 0; - current_link_setting = initial_link_setting; - - /* search for the minimum link setting that: - * 1. is supported according to the link training result - * 2. could support the b/w requested by the timing - */ - while (current_link_setting.link_rate <= - link->verified_link_cap.link_rate) { - link_bw = dc_link_bandwidth_kbps( - link, - ¤t_link_setting); - if (req_bw <= link_bw) { - *link_setting = current_link_setting; - return true; - } - - if (current_link_setting.lane_count < - link->verified_link_cap.lane_count) { - current_link_setting.lane_count = - increase_lane_count( - current_link_setting.lane_count); - } else { - if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { - current_link_setting.link_rate_set++; - current_link_setting.link_rate = - link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; - current_link_setting.lane_count = - initial_link_setting.lane_count; - } else - break; - } - } - return false; -} - -static bool decide_edp_link_settings_with_dsc(struct dc_link *link, - struct dc_link_settings *link_setting, - uint32_t req_bw, - enum dc_link_rate max_link_rate) -{ - struct dc_link_settings initial_link_setting; - struct dc_link_settings current_link_setting; - uint32_t link_bw; - - unsigned int policy = 0; - - policy = link->panel_config.dsc.force_dsc_edp_policy; - if (max_link_rate == LINK_RATE_UNKNOWN) - max_link_rate = link->verified_link_cap.link_rate; - /* - * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. - * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" - */ - if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || - link->dpcd_caps.edp_supported_link_rates_count == 0)) { - /* for DSC enabled case, we search for minimum lane count */ - memset(&initial_link_setting, 0, sizeof(initial_link_setting)); - initial_link_setting.lane_count = LANE_COUNT_ONE; - initial_link_setting.link_rate = LINK_RATE_LOW; - initial_link_setting.link_spread = LINK_SPREAD_DISABLED; - initial_link_setting.use_link_rate_set = false; - initial_link_setting.link_rate_set = 0; - current_link_setting = initial_link_setting; - if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) - return false; - - /* search for the minimum link setting that: - * 1. is supported according to the link training result - * 2. could support the b/w requested by the timing - */ - while (current_link_setting.link_rate <= - max_link_rate) { - link_bw = dc_link_bandwidth_kbps( - link, - ¤t_link_setting); - if (req_bw <= link_bw) { - *link_setting = current_link_setting; - return true; - } - if (policy) { - /* minimize lane */ - if (current_link_setting.link_rate < max_link_rate) { - current_link_setting.link_rate = - increase_link_rate(link, - current_link_setting.link_rate); - } else { - if (current_link_setting.lane_count < - link->verified_link_cap.lane_count) { - current_link_setting.lane_count = - increase_lane_count( - current_link_setting.lane_count); - current_link_setting.link_rate = initial_link_setting.link_rate; - } else - break; - } - } else { - /* minimize link rate */ - if (current_link_setting.lane_count < - link->verified_link_cap.lane_count) { - current_link_setting.lane_count = - increase_lane_count( - current_link_setting.lane_count); - } else { - current_link_setting.link_rate = - increase_link_rate(link, - current_link_setting.link_rate); - current_link_setting.lane_count = - initial_link_setting.lane_count; - } - } - } - return false; - } - - /* if optimize edp link is supported */ - memset(&initial_link_setting, 0, sizeof(initial_link_setting)); - initial_link_setting.lane_count = LANE_COUNT_ONE; - initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; - initial_link_setting.link_spread = LINK_SPREAD_DISABLED; - initial_link_setting.use_link_rate_set = true; - initial_link_setting.link_rate_set = 0; - current_link_setting = initial_link_setting; - - /* search for the minimum link setting that: - * 1. is supported according to the link training result - * 2. could support the b/w requested by the timing - */ - while (current_link_setting.link_rate <= - max_link_rate) { - link_bw = dc_link_bandwidth_kbps( - link, - ¤t_link_setting); - if (req_bw <= link_bw) { - *link_setting = current_link_setting; - return true; - } - if (policy) { - /* minimize lane */ - if (current_link_setting.link_rate_set < - link->dpcd_caps.edp_supported_link_rates_count - && current_link_setting.link_rate < max_link_rate) { - current_link_setting.link_rate_set++; - current_link_setting.link_rate = - link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; - } else { - if (current_link_setting.lane_count < link->verified_link_cap.lane_count) { - current_link_setting.lane_count = - increase_lane_count( - current_link_setting.lane_count); - current_link_setting.link_rate_set = initial_link_setting.link_rate_set; - current_link_setting.link_rate = - link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; - } else - break; - } - } else { - /* minimize link rate */ - if (current_link_setting.lane_count < - link->verified_link_cap.lane_count) { - current_link_setting.lane_count = - increase_lane_count( - current_link_setting.lane_count); - } else { - if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { - current_link_setting.link_rate_set++; - current_link_setting.link_rate = - link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; - current_link_setting.lane_count = - initial_link_setting.lane_count; - } else - break; - } - } - } - return false; -} - -static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting) -{ - *link_setting = link->verified_link_cap; - return true; -} - -bool decide_link_settings(struct dc_stream_state *stream, - struct dc_link_settings *link_setting) -{ - struct dc_link *link = stream->link; - uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); - - memset(link_setting, 0, sizeof(*link_setting)); - - /* if preferred is specified through AMDDP, use it, if it's enough - * to drive the mode - */ - if (link->preferred_link_setting.lane_count != - LANE_COUNT_UNKNOWN && - link->preferred_link_setting.link_rate != - LINK_RATE_UNKNOWN) { - *link_setting = link->preferred_link_setting; - return true; - } - - /* MST doesn't perform link training for now - * TODO: add MST specific link training routine - */ - if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - decide_mst_link_settings(link, link_setting); - } else if (link->connector_signal == SIGNAL_TYPE_EDP) { - /* enable edp link optimization for DSC eDP case */ - if (stream->timing.flags.DSC) { - enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN; - - if (link->panel_config.dsc.force_dsc_edp_policy) { - /* calculate link max link rate cap*/ - struct dc_link_settings tmp_link_setting; - struct dc_crtc_timing tmp_timing = stream->timing; - uint32_t orig_req_bw; - - tmp_link_setting.link_rate = LINK_RATE_UNKNOWN; - tmp_timing.flags.DSC = 0; - orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing); - decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw); - max_link_rate = tmp_link_setting.link_rate; - } - decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate); - } else { - decide_edp_link_settings(link, link_setting, req_bw); - } - } else { - decide_dp_link_settings(link, link_setting, req_bw); - } - - return link_setting->lane_count != LANE_COUNT_UNKNOWN && - link_setting->link_rate != LINK_RATE_UNKNOWN; -} - /*************************Short Pulse IRQ***************************/ bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link) { @@ -4094,6 +361,12 @@ static void dp_test_send_link_training(struct dc_link *link) dp_retrain_link_dp_test(link, &link_settings, false); } +static bool is_dp_phy_sqaure_pattern(enum dp_test_pattern test_pattern) +{ + return (DP_TEST_PATTERN_SQUARE_BEGIN <= test_pattern && + test_pattern <= DP_TEST_PATTERN_SQUARE_END); +} + /* TODO Raven hbr2 compliance eye output is unstable * (toggling on and off) with debugger break * This caueses intermittent PHY automation failure @@ -4111,6 +384,8 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) union lane_adjust dpcd_lane_adjust; unsigned int lane; struct link_training_settings link_training_settings; + unsigned char no_preshoot = 0; + unsigned char no_deemphasis = 0; dpcd_test_pattern.raw = 0; memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment)); @@ -4131,7 +406,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) /* prepare link training settings */ link_training_settings.link_settings = link->cur_link_settings; - link_training_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link->cur_link_settings); + link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings); if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT) @@ -4204,8 +479,21 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) case PHY_TEST_PATTERN_264BIT_CUSTOM: test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM; break; - case PHY_TEST_PATTERN_SQUARE_PULSE: - test_pattern = DP_TEST_PATTERN_SQUARE_PULSE; + case PHY_TEST_PATTERN_SQUARE: + test_pattern = DP_TEST_PATTERN_SQUARE; + break; + case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: + test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED; + no_preshoot = 1; + break; + case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: + test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED; + no_deemphasis = 1; + break; + case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: + test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED; + no_preshoot = 1; + no_deemphasis = 1; break; default: test_pattern = DP_TEST_PATTERN_VIDEO_MODE; @@ -4222,7 +510,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) test_pattern_size); } - if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) { + if (is_dp_phy_sqaure_pattern(test_pattern)) { test_pattern_size = 1; // Square pattern data is 1 byte (DP spec) core_link_read_dpcd( link, @@ -4246,7 +534,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) lane++) { dpcd_lane_adjust.raw = get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane); - if (dp_get_link_encoding_format(&link->cur_link_settings) == + if (link_dp_get_encoding_format(&link->cur_link_settings) == DP_8b_10b_ENCODING) { link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING = (enum dc_voltage_swing) @@ -4257,10 +545,12 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) link_training_settings.hw_lane_settings[lane].POST_CURSOR2 = (enum dc_post_cursor2) ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03); - } else if (dp_get_link_encoding_format(&link->cur_link_settings) == + } else if (link_dp_get_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING) { - link_training_settings.hw_lane_settings[lane].FFE_PRESET.raw = + link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level = dpcd_lane_adjust.tx_ffe.PRESET_VALUE; + link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot; + link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis; } } @@ -4701,1164 +991,6 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd return status; } -/*query dpcd for version and mst cap addresses*/ -bool is_mst_supported(struct dc_link *link) -{ - bool mst = false; - enum dc_status st = DC_OK; - union dpcd_rev rev; - union mstm_cap cap; - - if (link->preferred_training_settings.mst_enable && - *link->preferred_training_settings.mst_enable == false) { - return false; - } - - rev.raw = 0; - cap.raw = 0; - - st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw, - sizeof(rev)); - - if (st == DC_OK && rev.raw >= DPCD_REV_12) { - - st = core_link_read_dpcd(link, DP_MSTM_CAP, - &cap.raw, sizeof(cap)); - if (st == DC_OK && cap.bits.MST_CAP == 1) - mst = true; - } - return mst; - -} - -bool is_dp_active_dongle(const struct dc_link *link) -{ - return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) && - (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER); -} - -bool is_dp_branch_device(const struct dc_link *link) -{ - return link->dpcd_caps.is_branch_dev; -} - -static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc) -{ - switch (bpc) { - case DOWN_STREAM_MAX_8BPC: - return 8; - case DOWN_STREAM_MAX_10BPC: - return 10; - case DOWN_STREAM_MAX_12BPC: - return 12; - case DOWN_STREAM_MAX_16BPC: - return 16; - default: - break; - } - - return -1; -} - -#if defined(CONFIG_DRM_AMD_DC_DCN) -uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw) -{ - switch (bw) { - case 0b001: - return 9000000; - case 0b010: - return 18000000; - case 0b011: - return 24000000; - case 0b100: - return 32000000; - case 0b101: - return 40000000; - case 0b110: - return 48000000; - } - - return 0; -} - -/* - * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw. - */ -static uint32_t intersect_frl_link_bw_support( - const uint32_t max_supported_frl_bw_in_kbps, - const union hdmi_encoded_link_bw hdmi_encoded_link_bw) -{ - uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps; - - // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode) - if (hdmi_encoded_link_bw.bits.FRL_MODE) { - if (hdmi_encoded_link_bw.bits.BW_48Gbps) - supported_bw_in_kbps = 48000000; - else if (hdmi_encoded_link_bw.bits.BW_40Gbps) - supported_bw_in_kbps = 40000000; - else if (hdmi_encoded_link_bw.bits.BW_32Gbps) - supported_bw_in_kbps = 32000000; - else if (hdmi_encoded_link_bw.bits.BW_24Gbps) - supported_bw_in_kbps = 24000000; - else if (hdmi_encoded_link_bw.bits.BW_18Gbps) - supported_bw_in_kbps = 18000000; - else if (hdmi_encoded_link_bw.bits.BW_9Gbps) - supported_bw_in_kbps = 9000000; - } - - return supported_bw_in_kbps; -} -#endif - -static void read_dp_device_vendor_id(struct dc_link *link) -{ - struct dp_device_vendor_id dp_id; - - /* read IEEE branch device id */ - core_link_read_dpcd( - link, - DP_BRANCH_OUI, - (uint8_t *)&dp_id, - sizeof(dp_id)); - - link->dpcd_caps.branch_dev_id = - (dp_id.ieee_oui[0] << 16) + - (dp_id.ieee_oui[1] << 8) + - dp_id.ieee_oui[2]; - - memmove( - link->dpcd_caps.branch_dev_name, - dp_id.ieee_device_id, - sizeof(dp_id.ieee_device_id)); -} - - - -static void get_active_converter_info( - uint8_t data, struct dc_link *link) -{ - union dp_downstream_port_present ds_port = { .byte = data }; - memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps)); - - /* decode converter info*/ - if (!ds_port.fields.PORT_PRESENT) { - link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; - ddc_service_set_dongle_type(link->ddc, - link->dpcd_caps.dongle_type); - link->dpcd_caps.is_branch_dev = false; - return; - } - - /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */ - link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT; - - switch (ds_port.fields.PORT_TYPE) { - case DOWNSTREAM_VGA: - link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER; - break; - case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS: - /* At this point we don't know is it DVI or HDMI or DP++, - * assume DVI.*/ - link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER; - break; - default: - link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; - break; - } - - if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) { - uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/ - union dwnstream_port_caps_byte0 *port_caps = - (union dwnstream_port_caps_byte0 *)det_caps; - if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0, - det_caps, sizeof(det_caps)) == DC_OK) { - - switch (port_caps->bits.DWN_STRM_PORTX_TYPE) { - /*Handle DP case as DONGLE_NONE*/ - case DOWN_STREAM_DETAILED_DP: - link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; - break; - case DOWN_STREAM_DETAILED_VGA: - link->dpcd_caps.dongle_type = - DISPLAY_DONGLE_DP_VGA_CONVERTER; - break; - case DOWN_STREAM_DETAILED_DVI: - link->dpcd_caps.dongle_type = - DISPLAY_DONGLE_DP_DVI_CONVERTER; - break; - case DOWN_STREAM_DETAILED_HDMI: - case DOWN_STREAM_DETAILED_DP_PLUS_PLUS: - /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/ - link->dpcd_caps.dongle_type = - DISPLAY_DONGLE_DP_HDMI_CONVERTER; - - link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type; - if (ds_port.fields.DETAILED_CAPS) { - - union dwnstream_port_caps_byte3_hdmi - hdmi_caps = {.raw = det_caps[3] }; - union dwnstream_port_caps_byte2 - hdmi_color_caps = {.raw = det_caps[2] }; - link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz = - det_caps[1] * 2500; - - link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter = - hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK; - /*YCBCR capability only for HDMI case*/ - if (port_caps->bits.DWN_STRM_PORTX_TYPE - == DOWN_STREAM_DETAILED_HDMI) { - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through = - hdmi_caps.bits.YCrCr422_PASS_THROUGH; - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through = - hdmi_caps.bits.YCrCr420_PASS_THROUGH; - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter = - hdmi_caps.bits.YCrCr422_CONVERSION; - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter = - hdmi_caps.bits.YCrCr420_CONVERSION; - } - - link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc = - translate_dpcd_max_bpc( - hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT); - -#if defined(CONFIG_DRM_AMD_DC_DCN) - if (link->dc->caps.dp_hdmi21_pcon_support) { - union hdmi_encoded_link_bw hdmi_encoded_link_bw; - - link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = - dc_link_bw_kbps_from_raw_frl_link_rate_data( - hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT); - - // Intersect reported max link bw support with the supported link rate post FRL link training - if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS, - &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) { - link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support( - link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps, - hdmi_encoded_link_bw); - } - - if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0) - link->dpcd_caps.dongle_caps.extendedCapValid = true; - } -#endif - - if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0) - link->dpcd_caps.dongle_caps.extendedCapValid = true; - } - - break; - } - } - } - - ddc_service_set_dongle_type(link->ddc, link->dpcd_caps.dongle_type); - - { - struct dp_sink_hw_fw_revision dp_hw_fw_revision; - - core_link_read_dpcd( - link, - DP_BRANCH_REVISION_START, - (uint8_t *)&dp_hw_fw_revision, - sizeof(dp_hw_fw_revision)); - - link->dpcd_caps.branch_hw_revision = - dp_hw_fw_revision.ieee_hw_rev; - - memmove( - link->dpcd_caps.branch_fw_revision, - dp_hw_fw_revision.ieee_fw_rev, - sizeof(dp_hw_fw_revision.ieee_fw_rev)); - } - if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && - link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { - union dp_dfp_cap_ext dfp_cap_ext; - memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext)); - core_link_read_dpcd( - link, - DP_DFP_CAPABILITY_EXTENSION_SUPPORT, - dfp_cap_ext.raw, - sizeof(dfp_cap_ext.raw)); - link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported; - link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps = - dfp_cap_ext.fields.max_pixel_rate_in_mps[0] + - (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8); - link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width = - dfp_cap_ext.fields.max_video_h_active_width[0] + - (dfp_cap_ext.fields.max_video_h_active_width[1] << 8); - link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height = - dfp_cap_ext.fields.max_video_v_active_height[0] + - (dfp_cap_ext.fields.max_video_v_active_height[1] << 8); - link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps = - dfp_cap_ext.fields.encoding_format_caps; - link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps = - dfp_cap_ext.fields.rgb_color_depth_caps; - link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps = - dfp_cap_ext.fields.ycbcr444_color_depth_caps; - link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps = - dfp_cap_ext.fields.ycbcr422_color_depth_caps; - link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps = - dfp_cap_ext.fields.ycbcr420_color_depth_caps; - DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index); - DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false"); - DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps); - DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width); - DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height); - } -} - -static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, - int length) -{ - int retry = 0; - - if (!link->dpcd_caps.dpcd_rev.raw) { - do { - dp_receiver_power_ctrl(link, true); - core_link_read_dpcd(link, DP_DPCD_REV, - dpcd_data, length); - link->dpcd_caps.dpcd_rev.raw = dpcd_data[ - DP_DPCD_REV - - DP_DPCD_REV]; - } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw); - } - - if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) { - switch (link->dpcd_caps.branch_dev_id) { - /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down - * all internal circuits including AUX communication preventing - * reading DPCD table and EDID (spec violation). - * Encoder will skip DP RX power down on disable_output to - * keep receiver powered all the time.*/ - case DP_BRANCH_DEVICE_ID_0010FA: - case DP_BRANCH_DEVICE_ID_0080E1: - case DP_BRANCH_DEVICE_ID_00E04C: - link->wa_flags.dp_keep_receiver_powered = true; - break; - - /* TODO: May need work around for other dongles. */ - default: - link->wa_flags.dp_keep_receiver_powered = false; - break; - } - } else - link->wa_flags.dp_keep_receiver_powered = false; -} - -/* Read additional sink caps defined in source specific DPCD area - * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP) - */ -static bool dpcd_read_sink_ext_caps(struct dc_link *link) -{ - uint8_t dpcd_data; - - if (!link) - return false; - - if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK) - return false; - - link->dpcd_sink_ext_caps.raw = dpcd_data; - return true; -} - -enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link) -{ - uint8_t lttpr_dpcd_data[8]; - enum dc_status status = DC_ERROR_UNEXPECTED; - bool is_lttpr_present = false; - - /* Logic to determine LTTPR support*/ - bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; - - if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support) - return false; - - /* By reading LTTPR capability, RX assumes that we will enable - * LTTPR extended aux timeout if LTTPR is present. - */ - status = core_link_read_dpcd(link, - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, - lttpr_dpcd_data, - sizeof(lttpr_dpcd_data)); - - link->dpcd_caps.lttpr_caps.revision.raw = - lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.max_link_rate = - lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.phy_repeater_cnt = - lttpr_dpcd_data[DP_PHY_REPEATER_CNT - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.max_lane_count = - lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.mode = - lttpr_dpcd_data[DP_PHY_REPEATER_MODE - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.max_ext_timeout = - lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw = - lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw = - lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES - - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; - - /* If this chip cap is set, at least one retimer must exist in the chain - * Override count to 1 if we receive a known bad count (0 or an invalid value) - */ - if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && - (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) { - ASSERT(0); - link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80; - DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - } - - /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */ - is_lttpr_present = dp_is_lttpr_present(link); - - if (is_lttpr_present) - CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); - - DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present); - return status; -} - -bool dp_is_lttpr_present(struct dc_link *link) -{ - return (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 && - link->dpcd_caps.lttpr_caps.max_lane_count > 0 && - link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && - link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); -} - -enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting) -{ - enum dp_link_encoding encoding = dp_get_link_encoding_format(link_setting); - - if (encoding == DP_8b_10b_ENCODING) - return dp_decide_8b_10b_lttpr_mode(link); - else if (encoding == DP_128b_132b_ENCODING) - return dp_decide_128b_132b_lttpr_mode(link); - - ASSERT(0); - return LTTPR_MODE_NON_LTTPR; -} - -void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override) -{ - if (!dp_is_lttpr_present(link)) - return; - - if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) { - *override = LTTPR_MODE_TRANSPARENT; - } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) { - *override = LTTPR_MODE_NON_TRANSPARENT; - } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) { - *override = LTTPR_MODE_NON_LTTPR; - } - DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override)); -} - -enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link) -{ - bool is_lttpr_present = dp_is_lttpr_present(link); - bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable; - bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware; - - if (!is_lttpr_present) - return LTTPR_MODE_NON_LTTPR; - - if (vbios_lttpr_aware) { - if (vbios_lttpr_force_non_transparent) { - DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n"); - return LTTPR_MODE_NON_TRANSPARENT; - } else { - DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n"); - return LTTPR_MODE_TRANSPARENT; - } - } - - if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A && - link->dc->caps.extended_aux_timeout_support) { - DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n"); - return LTTPR_MODE_NON_TRANSPARENT; - } - - DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n"); - return LTTPR_MODE_NON_LTTPR; -} - -enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link) -{ - enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR; - - if (dp_is_lttpr_present(link)) - mode = LTTPR_MODE_NON_TRANSPARENT; - - DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode); - return mode; -} - -static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id) -{ - union dmub_rb_cmd cmd; - - if (!link->ctx->dmub_srv || - link->ep_type != DISPLAY_ENDPOINT_PHY || - link->link_enc->features.flags.bits.DP_IS_USB_C == 0) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID; - cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data); - cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx( - link->dc, link->link_enc->transmitter); - if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) && - cmd.cable_id.header.ret_status == 1) { - cable_id->raw = cmd.cable_id.data.output_raw; - DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw); - } - return cmd.cable_id.header.ret_status == 1; -} - -static union dp_cable_id intersect_cable_id( - union dp_cable_id *a, union dp_cable_id *b) -{ - union dp_cable_id out; - - out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY, - b->bits.UHBR10_20_CAPABILITY); - out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY, - b->bits.UHBR13_5_CAPABILITY); - out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE); - - return out; -} - -static void retrieve_cable_id(struct dc_link *link) -{ - union dp_cable_id usbc_cable_id; - - link->dpcd_caps.cable_id.raw = 0; - core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX, - &link->dpcd_caps.cable_id.raw, sizeof(uint8_t)); - - if (get_usbc_cable_id(link, &usbc_cable_id)) - link->dpcd_caps.cable_id = intersect_cable_id( - &link->dpcd_caps.cable_id, &usbc_cable_id); -} - -static enum dc_status wake_up_aux_channel(struct dc_link *link) -{ - enum dc_status status = DC_ERROR_UNEXPECTED; - uint32_t aux_channel_retry_cnt = 0; - uint8_t dpcd_power_state = '\0'; - - while (status != DC_OK && aux_channel_retry_cnt < 10) { - status = core_link_read_dpcd(link, DP_SET_POWER, - &dpcd_power_state, sizeof(dpcd_power_state)); - - /* Delay 1 ms if AUX CH is in power down state. Based on spec - * section 2.3.1.2, if AUX CH may be powered down due to - * write to DPCD 600h = 2. Sink AUX CH is monitoring differential - * signal and may need up to 1 ms before being able to reply. - */ - if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) { - udelay(1000); - aux_channel_retry_cnt++; - } - } - - if (status != DC_OK) { - dpcd_power_state = DP_SET_POWER_D0; - status = core_link_write_dpcd( - link, - DP_SET_POWER, - &dpcd_power_state, - sizeof(dpcd_power_state)); - - dpcd_power_state = DP_SET_POWER_D3; - status = core_link_write_dpcd( - link, - DP_SET_POWER, - &dpcd_power_state, - sizeof(dpcd_power_state)); - return DC_ERROR_UNEXPECTED; - } - - return DC_OK; -} - -static bool retrieve_link_cap(struct dc_link *link) -{ - /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, - * which means size 16 will be good for both of those DPCD register block reads - */ - uint8_t dpcd_data[16]; - /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. - */ - uint8_t dpcd_dprx_data = '\0'; - - struct dp_device_vendor_id sink_id; - union down_stream_port_count down_strm_port_count; - union edp_configuration_cap edp_config_cap; - union dp_downstream_port_present ds_port = { 0 }; - enum dc_status status = DC_ERROR_UNEXPECTED; - uint32_t read_dpcd_retry_cnt = 3; - int i; - struct dp_sink_hw_fw_revision dp_hw_fw_revision; - const uint32_t post_oui_delay = 30; // 30ms - - memset(dpcd_data, '\0', sizeof(dpcd_data)); - memset(&down_strm_port_count, - '\0', sizeof(union down_stream_port_count)); - memset(&edp_config_cap, '\0', - sizeof(union edp_configuration_cap)); - - /* if extended timeout is supported in hardware, - * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer - * CTS 4.2.1.1 regression introduced by CTS specs requirement update. - */ - dc_link_aux_try_to_configure_timeout(link->ddc, - LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); - - status = dp_retrieve_lttpr_cap(link); - - if (status != DC_OK) { - status = wake_up_aux_channel(link); - if (status == DC_OK) - dp_retrieve_lttpr_cap(link); - else - return false; - } - - if (dp_is_lttpr_present(link)) - configure_lttpr_mode_transparent(link); - - /* Read DP tunneling information. */ - status = dpcd_get_tunneling_device_data(link); - - dpcd_set_source_specific_data(link); - /* Sink may need to configure internals based on vendor, so allow some - * time before proceeding with possibly vendor specific transactions - */ - msleep(post_oui_delay); - - for (i = 0; i < read_dpcd_retry_cnt; i++) { - status = core_link_read_dpcd( - link, - DP_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); - if (status == DC_OK) - break; - } - - if (status != DC_OK) { - dm_error("%s: Read receiver caps dpcd data failed.\n", __func__); - return false; - } - - if (!dp_is_lttpr_present(link)) - dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD); - - { - union training_aux_rd_interval aux_rd_interval; - - aux_rd_interval.raw = - dpcd_data[DP_TRAINING_AUX_RD_INTERVAL]; - - link->dpcd_caps.ext_receiver_cap_field_present = - aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1; - - if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) { - uint8_t ext_cap_data[16]; - - memset(ext_cap_data, '\0', sizeof(ext_cap_data)); - for (i = 0; i < read_dpcd_retry_cnt; i++) { - status = core_link_read_dpcd( - link, - DP_DP13_DPCD_REV, - ext_cap_data, - sizeof(ext_cap_data)); - if (status == DC_OK) { - memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data)); - break; - } - } - if (status != DC_OK) - dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__); - } - } - - link->dpcd_caps.dpcd_rev.raw = - dpcd_data[DP_DPCD_REV - DP_DPCD_REV]; - - if (link->dpcd_caps.ext_receiver_cap_field_present) { - for (i = 0; i < read_dpcd_retry_cnt; i++) { - status = core_link_read_dpcd( - link, - DP_DPRX_FEATURE_ENUMERATION_LIST, - &dpcd_dprx_data, - sizeof(dpcd_dprx_data)); - if (status == DC_OK) - break; - } - - link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data; - - if (status != DC_OK) - dm_error("%s: Read DPRX caps data failed.\n", __func__); - } - - else { - link->dpcd_caps.dprx_feature.raw = 0; - } - - - /* Error condition checking... - * It is impossible for Sink to report Max Lane Count = 0. - * It is possible for Sink to report Max Link Rate = 0, if it is - * an eDP device that is reporting specialized link rates in the - * SUPPORTED_LINK_RATE table. - */ - if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0) - return false; - - ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT - - DP_DPCD_REV]; - - read_dp_device_vendor_id(link); - - /* TODO - decouple raw mst capability from policy decision */ - link->dpcd_caps.is_mst_capable = is_mst_supported(link); - - get_active_converter_info(ds_port.byte, link); - - dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data)); - - down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT - - DP_DPCD_REV]; - - link->dpcd_caps.allow_invalid_MSA_timing_param = - down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM; - - link->dpcd_caps.max_ln_count.raw = dpcd_data[ - DP_MAX_LANE_COUNT - DP_DPCD_REV]; - - link->dpcd_caps.max_down_spread.raw = dpcd_data[ - DP_MAX_DOWNSPREAD - DP_DPCD_REV]; - - link->reported_link_cap.lane_count = - link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT; - link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw( - dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]); - link->reported_link_cap.link_spread = - link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ? - LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; - - edp_config_cap.raw = dpcd_data[ - DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV]; - link->dpcd_caps.panel_mode_edp = - edp_config_cap.bits.ALT_SCRAMBLER_RESET; - link->dpcd_caps.dpcd_display_control_capable = - edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; - link->dpcd_caps.channel_coding_cap.raw = - dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV]; - link->test_pattern_enabled = false; - link->compliance_test_state.raw = 0; - - /* read sink count */ - core_link_read_dpcd(link, - DP_SINK_COUNT, - &link->dpcd_caps.sink_count.raw, - sizeof(link->dpcd_caps.sink_count.raw)); - - /* read sink ieee oui */ - core_link_read_dpcd(link, - DP_SINK_OUI, - (uint8_t *)(&sink_id), - sizeof(sink_id)); - - link->dpcd_caps.sink_dev_id = - (sink_id.ieee_oui[0] << 16) + - (sink_id.ieee_oui[1] << 8) + - (sink_id.ieee_oui[2]); - - memmove( - link->dpcd_caps.sink_dev_id_str, - sink_id.ieee_device_id, - sizeof(sink_id.ieee_device_id)); - - /* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */ - { - uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 }; - - if ((link->dpcd_caps.sink_dev_id == 0x0010fa) && - !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017, - sizeof(str_mbp_2017))) { - link->reported_link_cap.link_rate = 0x0c; - } - } - - core_link_read_dpcd( - link, - DP_SINK_HW_REVISION_START, - (uint8_t *)&dp_hw_fw_revision, - sizeof(dp_hw_fw_revision)); - - link->dpcd_caps.sink_hw_revision = - dp_hw_fw_revision.ieee_hw_rev; - - memmove( - link->dpcd_caps.sink_fw_revision, - dp_hw_fw_revision.ieee_fw_rev, - sizeof(dp_hw_fw_revision.ieee_fw_rev)); - - /* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */ - { - uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 }; - uint8_t fwrev_mbp_2018[] = { 7, 4 }; - uint8_t fwrev_mbp_2018_vega[] = { 8, 4 }; - - /* We also check for the firmware revision as 16,1 models have an - * identical device id and are incorrectly quirked otherwise. - */ - if ((link->dpcd_caps.sink_dev_id == 0x0010fa) && - !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018, - sizeof(str_mbp_2018)) && - (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018, - sizeof(fwrev_mbp_2018)) || - !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega, - sizeof(fwrev_mbp_2018_vega)))) { - link->reported_link_cap.link_rate = LINK_RATE_RBR2; - } - } - - memset(&link->dpcd_caps.dsc_caps, '\0', - sizeof(link->dpcd_caps.dsc_caps)); - memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap)); - /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */ - if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) { - status = core_link_read_dpcd( - link, - DP_FEC_CAPABILITY, - &link->dpcd_caps.fec_cap.raw, - sizeof(link->dpcd_caps.fec_cap.raw)); - status = core_link_read_dpcd( - link, - DP_DSC_SUPPORT, - link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, - sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw)); - if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { - status = core_link_read_dpcd( - link, - DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, - link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, - sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw)); - DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index); - DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x", - link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0); - DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x", - link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1); - DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x", - link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH); - } - - /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode - * only if required. - */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && - link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around && - link->dpcd_caps.is_branch_dev && - link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 && - link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 && - (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE || - link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) { - /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA. - * Clear FEC and DSC capabilities as a work around if that is not the case. - */ - link->wa_flags.dpia_forced_tbt3_mode = true; - memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps)); - memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap)); - DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index); - } else - link->wa_flags.dpia_forced_tbt3_mode = false; - } - - if (!dpcd_read_sink_ext_caps(link)) - link->dpcd_sink_ext_caps.raw = 0; - - if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { - DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index); - - core_link_read_dpcd(link, - DP_128b_132b_SUPPORTED_LINK_RATES, - &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw, - sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw)); - if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20) - link->reported_link_cap.link_rate = LINK_RATE_UHBR20; - else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5) - link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5; - else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10) - link->reported_link_cap.link_rate = LINK_RATE_UHBR10; - else - dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__); - DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index); - DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz", - link->reported_link_cap.link_rate / 100, - link->reported_link_cap.link_rate % 100); - - core_link_read_dpcd(link, - DP_SINK_VIDEO_FALLBACK_FORMATS, - &link->dpcd_caps.fallback_formats.raw, - sizeof(link->dpcd_caps.fallback_formats.raw)); - DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index); - if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support) - DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported"); - if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support) - DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported"); - if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support) - DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported"); - if (link->dpcd_caps.fallback_formats.raw == 0) { - DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported"); - link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1; - } - - core_link_read_dpcd(link, - DP_FEC_CAPABILITY_1, - &link->dpcd_caps.fec_cap1.raw, - sizeof(link->dpcd_caps.fec_cap1.raw)); - DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index); - if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE) - DC_LOG_DP2("\tFEC aggregated error counters are supported"); - } - - retrieve_cable_id(link); - dpcd_write_cable_id_to_dprx(link); - - /* Connectivity log: detection */ - CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); - - return true; -} - -bool dp_overwrite_extended_receiver_cap(struct dc_link *link) -{ - uint8_t dpcd_data[16]; - uint32_t read_dpcd_retry_cnt = 3; - enum dc_status status = DC_ERROR_UNEXPECTED; - union dp_downstream_port_present ds_port = { 0 }; - union down_stream_port_count down_strm_port_count; - union edp_configuration_cap edp_config_cap; - - int i; - - for (i = 0; i < read_dpcd_retry_cnt; i++) { - status = core_link_read_dpcd( - link, - DP_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); - if (status == DC_OK) - break; - } - - link->dpcd_caps.dpcd_rev.raw = - dpcd_data[DP_DPCD_REV - DP_DPCD_REV]; - - if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0) - return false; - - ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT - - DP_DPCD_REV]; - - get_active_converter_info(ds_port.byte, link); - - down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT - - DP_DPCD_REV]; - - link->dpcd_caps.allow_invalid_MSA_timing_param = - down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM; - - link->dpcd_caps.max_ln_count.raw = dpcd_data[ - DP_MAX_LANE_COUNT - DP_DPCD_REV]; - - link->dpcd_caps.max_down_spread.raw = dpcd_data[ - DP_MAX_DOWNSPREAD - DP_DPCD_REV]; - - link->reported_link_cap.lane_count = - link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT; - link->reported_link_cap.link_rate = dpcd_data[ - DP_MAX_LINK_RATE - DP_DPCD_REV]; - link->reported_link_cap.link_spread = - link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ? - LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; - - edp_config_cap.raw = dpcd_data[ - DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV]; - link->dpcd_caps.panel_mode_edp = - edp_config_cap.bits.ALT_SCRAMBLER_RESET; - link->dpcd_caps.dpcd_display_control_capable = - edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; - - return true; -} - -bool detect_dp_sink_caps(struct dc_link *link) -{ - return retrieve_link_cap(link); -} - -static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz) -{ - enum dc_link_rate link_rate; - // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation. - switch (link_rate_in_khz) { - case 1620000: - link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane - break; - case 2160000: - link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane - break; - case 2430000: - link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane - break; - case 2700000: - link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane - break; - case 3240000: - link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2) - 3.24 Gbps/Lane - break; - case 4320000: - link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane - break; - case 5400000: - link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2) - 5.40 Gbps/Lane - break; - case 8100000: - link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3) - 8.10 Gbps/Lane - break; - default: - link_rate = LINK_RATE_UNKNOWN; - break; - } - return link_rate; -} - -void detect_edp_sink_caps(struct dc_link *link) -{ - uint8_t supported_link_rates[16]; - uint32_t entry; - uint32_t link_rate_in_khz; - enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; - uint8_t backlight_adj_cap; - uint8_t general_edp_cap; - - retrieve_link_cap(link); - link->dpcd_caps.edp_supported_link_rates_count = 0; - memset(supported_link_rates, 0, sizeof(supported_link_rates)); - - /* - * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. - * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" - */ - if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && - (link->panel_config.ilr.optimize_edp_link_rate || - link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) { - // Read DPCD 00010h - 0001Fh 16 bytes at one shot - core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, - supported_link_rates, sizeof(supported_link_rates)); - - for (entry = 0; entry < 16; entry += 2) { - // DPCD register reports per-lane link rate = 16-bit link rate capability - // value X 200 kHz. Need multiplier to find link rate in kHz. - link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 + - supported_link_rates[entry]) * 200; - - if (link_rate_in_khz != 0) { - link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); - link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate; - link->dpcd_caps.edp_supported_link_rates_count++; - - if (link->reported_link_cap.link_rate < link_rate) - link->reported_link_cap.link_rate = link_rate; - } - } - } - core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP, - &backlight_adj_cap, sizeof(backlight_adj_cap)); - - link->dpcd_caps.dynamic_backlight_capable_edp = - (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false; - - core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1, - &general_edp_cap, sizeof(general_edp_cap)); - - link->dpcd_caps.set_power_state_capable_edp = - (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false; - - dc_link_set_default_brightness_aux(link); - - core_link_read_dpcd(link, DP_EDP_DPCD_REV, - &link->dpcd_caps.edp_rev, - sizeof(link->dpcd_caps.edp_rev)); - /* - * PSR is only valid for eDP v1.3 or higher. - */ - if (link->dpcd_caps.edp_rev >= DP_EDP_13) { - core_link_read_dpcd(link, DP_PSR_SUPPORT, - &link->dpcd_caps.psr_info.psr_version, - sizeof(link->dpcd_caps.psr_info.psr_version)); - if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) - core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY, - &link->dpcd_caps.psr_info.force_psrsu_cap, - sizeof(link->dpcd_caps.psr_info.force_psrsu_cap)); - core_link_read_dpcd(link, DP_PSR_CAPS, - &link->dpcd_caps.psr_info.psr_dpcd_caps.raw, - sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw)); - if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) { - core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY, - &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap, - sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap)); - } - } - - /* - * ALPM is only valid for eDP v1.4 or higher. - */ - if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14) - core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP, - &link->dpcd_caps.alpm_caps.raw, - sizeof(link->dpcd_caps.alpm_caps.raw)); -} - -void dc_link_dp_enable_hpd(const struct dc_link *link) -{ - struct link_encoder *encoder = link->link_enc; - - if (encoder != NULL && encoder->funcs->enable_hpd != NULL) - encoder->funcs->enable_hpd(encoder); -} - -void dc_link_dp_disable_hpd(const struct dc_link *link) -{ - struct link_encoder *encoder = link->link_enc; - - if (encoder != NULL && encoder->funcs->enable_hpd != NULL) - encoder->funcs->disable_hpd(encoder); -} - static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern) { if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern && @@ -6114,7 +1246,7 @@ bool dc_link_dp_set_test_pattern( * MuteAudioEndpoint(pPathMode->pDisplayPath, true); */ /* Blank stream */ - pipes->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc); + link->dc->hwss.blank_stream(pipe_ctx); } dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, @@ -6178,8 +1310,17 @@ bool dc_link_dp_set_test_pattern( case DP_TEST_PATTERN_264BIT_CUSTOM: pattern = PHY_TEST_PATTERN_264BIT_CUSTOM; break; - case DP_TEST_PATTERN_SQUARE_PULSE: - pattern = PHY_TEST_PATTERN_SQUARE_PULSE; + case DP_TEST_PATTERN_SQUARE: + pattern = PHY_TEST_PATTERN_SQUARE; + break; + case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: + pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED; + break; + case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: + pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED; + break; + case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: + pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED; break; default: return false; @@ -6190,14 +1331,12 @@ bool dc_link_dp_set_test_pattern( return false; if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { -#if defined(CONFIG_DRM_AMD_DC_DCN) - if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) + if (is_dp_phy_sqaure_pattern(test_pattern)) core_link_write_dpcd(link, DP_LINK_SQUARE_PATTERN, p_custom_pattern, 1); -#endif /* tell receiver that we are sending qualification * pattern DP 1.2 or later - DP receiver's link quality * pattern is set using DPCD LINK_QUAL_LANEx_SET @@ -6512,96 +1651,6 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) } } -void dpcd_set_source_specific_data(struct dc_link *link) -{ - if (!link->dc->vendor_signature.is_valid) { - enum dc_status __maybe_unused result_write_min_hblank = DC_NOT_SUPPORTED; - struct dpcd_amd_signature amd_signature = {0}; - struct dpcd_amd_device_id amd_device_id = {0}; - - amd_device_id.device_id_byte1 = - (uint8_t)(link->ctx->asic_id.chip_id); - amd_device_id.device_id_byte2 = - (uint8_t)(link->ctx->asic_id.chip_id >> 8); - amd_device_id.dce_version = - (uint8_t)(link->ctx->dce_version); - amd_device_id.dal_version_byte1 = 0x0; // needed? where to get? - amd_device_id.dal_version_byte2 = 0x0; // needed? where to get? - - core_link_read_dpcd(link, DP_SOURCE_OUI, - (uint8_t *)(&amd_signature), - sizeof(amd_signature)); - - if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) && - (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) && - (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) { - - amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0; - amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0; - amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A; - - core_link_write_dpcd(link, DP_SOURCE_OUI, - (uint8_t *)(&amd_signature), - sizeof(amd_signature)); - } - - core_link_write_dpcd(link, DP_SOURCE_OUI+0x03, - (uint8_t *)(&amd_device_id), - sizeof(amd_device_id)); - - if (link->ctx->dce_version >= DCN_VERSION_2_0 && - link->dc->caps.min_horizontal_blanking_period != 0) { - - uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period; - - if (link->preferred_link_setting.dpcd_source_device_specific_field_support) { - result_write_min_hblank = core_link_write_dpcd(link, - DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size), - sizeof(hblank_size)); - - if (result_write_min_hblank == DC_ERROR_UNEXPECTED) - link->preferred_link_setting.dpcd_source_device_specific_field_support = false; - } else { - DC_LOG_DC("Sink device does not support 00340h DPCD write. Skipping on purpose.\n"); - } - } - - DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, - WPP_BIT_FLAG_DC_DETECTION_DP_CAPS, - "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'", - result_write_min_hblank, - link->link_index, - link->ctx->dce_version, - DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, - link->dc->caps.min_horizontal_blanking_period, - link->dpcd_caps.branch_dev_id, - link->dpcd_caps.branch_dev_name[0], - link->dpcd_caps.branch_dev_name[1], - link->dpcd_caps.branch_dev_name[2], - link->dpcd_caps.branch_dev_name[3], - link->dpcd_caps.branch_dev_name[4], - link->dpcd_caps.branch_dev_name[5]); - } else { - core_link_write_dpcd(link, DP_SOURCE_OUI, - link->dc->vendor_signature.data.raw, - sizeof(link->dc->vendor_signature.data.raw)); - } -} - -void dpcd_write_cable_id_to_dprx(struct dc_link *link) -{ - if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED || - link->dpcd_caps.cable_id.raw == 0 || - link->dprx_states.cable_id_written) - return; - - core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX, - &link->dpcd_caps.cable_id.raw, - sizeof(link->dpcd_caps.cable_id.raw)); - - link->dprx_states.cable_id_written = 1; -} - bool dc_link_set_backlight_level_nits(struct dc_link *link, bool isHDR, uint32_t backlight_millinits, @@ -6646,9 +1695,9 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link, link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) return false; - if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK, + if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK, dpcd_backlight_get.raw, - sizeof(union dpcd_source_backlight_get)) != DC_OK) + sizeof(union dpcd_source_backlight_get))) return false; *backlight_millinits_avg = @@ -6687,9 +1736,9 @@ bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_milli link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) return false; - if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, + if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, (uint8_t *) backlight_millinits, - sizeof(uint32_t)) != DC_OK) + sizeof(uint32_t))) return false; return true; @@ -6747,7 +1796,7 @@ bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timin req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing); if (!crtc_timing->flags.DSC) - decide_edp_link_settings(link, &link_setting, req_bw); + dc_link_decide_edp_link_settings(link, &link_setting, req_bw); else decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN); @@ -6761,35 +1810,6 @@ bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timin return false; } -enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings) -{ - if ((link_settings->link_rate >= LINK_RATE_LOW) && - (link_settings->link_rate <= LINK_RATE_HIGH3)) - return DP_8b_10b_ENCODING; - else if ((link_settings->link_rate >= LINK_RATE_UHBR10) && - (link_settings->link_rate <= LINK_RATE_UHBR20)) - return DP_128b_132b_ENCODING; - return DP_UNKNOWN_ENCODING; -} - -enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link) -{ - struct dc_link_settings link_settings = {0}; - - if (!dc_is_dp_signal(link->connector_signal)) - return DP_UNKNOWN_ENCODING; - - if (link->preferred_link_setting.lane_count != - LANE_COUNT_UNKNOWN && - link->preferred_link_setting.link_rate != - LINK_RATE_UNKNOWN) { - link_settings = link->preferred_link_setting; - } else { - decide_mst_link_settings(link, &link_settings); - } - - return dp_get_link_encoding_format(&link_settings); -} // TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST) static void get_lane_status( @@ -6988,15 +2008,6 @@ struct fixed31_32 calculate_sst_avg_time_slots_per_mtp( return avg_time_slots_per_mtp; } -bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx) -{ - /* If this assert is hit then we have a link encoder dynamic management issue */ - ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); - return (pipe_ctx->stream_res.hpo_dp_stream_enc && - pipe_ctx->link_res.hpo_dp_link_enc && - dc_is_dp_signal(pipe_ctx->stream->signal)); -} - void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd) { if (link->connector_signal != SIGNAL_TYPE_EDP) @@ -7014,20 +2025,6 @@ void dc_link_clear_dprx_states(struct dc_link *link) memset(&link->dprx_states, 0, sizeof(link->dprx_states)); } -void dp_receiver_power_ctrl(struct dc_link *link, bool on) -{ - uint8_t state; - - state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3; - - if (link->sync_lt_in_progress) - return; - - core_link_write_dpcd(link, DP_SET_POWER, &state, - sizeof(state)); - -} - void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode) { if (link != NULL && link->dc->debug.enable_driver_sequence_debug) @@ -7035,50 +2032,6 @@ void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode) &dp_test_mode, sizeof(dp_test_mode)); } - -static uint8_t convert_to_count(uint8_t lttpr_repeater_count) -{ - switch (lttpr_repeater_count) { - case 0x80: // 1 lttpr repeater - return 1; - case 0x40: // 2 lttpr repeaters - return 2; - case 0x20: // 3 lttpr repeaters - return 3; - case 0x10: // 4 lttpr repeaters - return 4; - case 0x08: // 5 lttpr repeaters - return 5; - case 0x04: // 6 lttpr repeaters - return 6; - case 0x02: // 7 lttpr repeaters - return 7; - case 0x01: // 8 lttpr repeaters - return 8; - default: - break; - } - return 0; // invalid value -} - -static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset) -{ - return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset); -} - -void dp_enable_link_phy( - struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - const struct dc_link_settings *link_settings) -{ - link->cur_link_settings = *link_settings; - link->dc->hwss.enable_dp_link_output(link, link_res, signal, - clock_source, link_settings); - dp_receiver_power_ctrl(link, true); -} - void edp_add_delay_for_T9(struct dc_link *link) { if (link && link->panel_config.pps.extra_delay_backlight_off > 0) @@ -7144,169 +2097,39 @@ bool edp_receiver_ready_T7(struct dc_link *link) return result; } -void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res, - enum signal_type signal) -{ - struct dc *dc = link->ctx->dc; - - if (!link->wa_flags.dp_keep_receiver_powered) - dp_receiver_power_ctrl(link, false); - - dc->hwss.disable_link_output(link, link_res, signal); - /* Clear current link setting.*/ - memset(&link->cur_link_settings, 0, - sizeof(link->cur_link_settings)); - - if (dc->clk_mgr->funcs->notify_link_rate_change) - dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); -} - -void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res, - enum signal_type signal) -{ - /* MST disable link only when no stream use the link */ - if (link->mst_stream_alloc_table.stream_count > 0) - return; - - dp_disable_link_phy(link, link_res, signal); - - /* set the sink to SST mode after disabling the link */ - dp_enable_mst_on_sink(link, false); -} - -bool dp_set_hw_training_pattern( - struct dc_link *link, - const struct link_resource *link_res, - enum dc_dp_training_pattern pattern, - uint32_t offset) -{ - enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; - - switch (pattern) { - case DP_TRAINING_PATTERN_SEQUENCE_1: - test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1; - break; - case DP_TRAINING_PATTERN_SEQUENCE_2: - test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2; - break; - case DP_TRAINING_PATTERN_SEQUENCE_3: - test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3; - break; - case DP_TRAINING_PATTERN_SEQUENCE_4: - test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; - break; - case DP_128b_132b_TPS1: - test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE; - break; - case DP_128b_132b_TPS2: - test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE; - break; - default: - break; - } - - dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0); - - return true; -} - -void dp_set_hw_lane_settings( - struct dc_link *link, - const struct link_resource *link_res, - const struct link_training_settings *link_settings, - uint32_t offset) -{ - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - - if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset)) - return; - - if (link_hwss->ext.set_dp_lane_settings) - link_hwss->ext.set_dp_lane_settings(link, link_res, - &link_settings->link_settings, - link_settings->hw_lane_settings); - - memmove(link->cur_lane_setting, - link_settings->hw_lane_settings, - sizeof(link->cur_lane_setting)); -} - -void dp_set_hw_test_pattern( - struct dc_link *link, - const struct link_resource *link_res, - enum dp_test_pattern test_pattern, - uint8_t *custom_pattern, - uint32_t custom_pattern_size) -{ - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - struct encoder_set_dp_phy_pattern_param pattern_param = {0}; - - pattern_param.dp_phy_pattern = test_pattern; - pattern_param.custom_pattern = custom_pattern; - pattern_param.custom_pattern_size = custom_pattern_size; - pattern_param.dp_panel_mode = dp_get_panel_mode(link); - - if (link_hwss->ext.set_dp_link_test_pattern) - link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param); -} - void dp_retrain_link_dp_test(struct dc_link *link, struct dc_link_settings *link_setting, bool skip_video_pattern) { - struct pipe_ctx *pipes = - &link->dc->current_state->res_ctx.pipe_ctx[0]; + struct pipe_ctx *pipe; unsigned int i; - bool do_fallback = false; + udelay(100); for (i = 0; i < MAX_PIPES; i++) { - if (pipes[i].stream != NULL && - !pipes[i].top_pipe && !pipes[i].prev_odm_pipe && - pipes[i].stream->link != NULL && - pipes[i].stream_res.stream_enc != NULL && - pipes[i].stream->link == link) { - udelay(100); - - pipes[i].stream_res.stream_enc->funcs->dp_blank(link, - pipes[i].stream_res.stream_enc); - - /* disable any test pattern that might be active */ - dp_set_hw_test_pattern(link, &pipes[i].link_res, - DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); - - dp_receiver_power_ctrl(link, false); - - link->dc->hwss.disable_stream(&pipes[i]); - if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only) - (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio); - - if (link->link_enc) - link->link_enc->funcs->disable_output( - link->link_enc, - SIGNAL_TYPE_DISPLAY_PORT); - - /* Clear current link setting. */ - memset(&link->cur_link_settings, 0, - sizeof(link->cur_link_settings)); - - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) - do_fallback = true; - - perform_link_training_with_retries( - link_setting, - skip_video_pattern, - LINK_TRAINING_ATTEMPTS, - &pipes[i], - SIGNAL_TYPE_DISPLAY_PORT, - do_fallback); - - link->dc->hwss.enable_stream(&pipes[i]); - - link->dc->hwss.unblank_stream(&pipes[i], - link_setting); + pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream != NULL && + pipe->stream->link == link && + !pipe->stream->dpms_off && + !pipe->top_pipe && !pipe->prev_odm_pipe) { + core_link_disable_stream(pipe); + pipe->link_config.dp_link_settings = *link_setting; + update_dp_encoder_resources_for_test_harness( + link->dc, + pipe->stream->ctx->dc->current_state, + pipe); + } + } - link->dc->hwss.enable_audio_stream(&pipes[i]); + for (i = 0; i < MAX_PIPES; i++) { + pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream != NULL && + pipe->stream->link == link && + !pipe->stream->dpms_off && + !pipe->top_pipe && !pipe->prev_odm_pipe) { + core_link_enable_stream( + pipe->stream->ctx->dc->current_state, + pipe); } } } @@ -7392,7 +2215,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) /* Enable DSC in encoder */ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) - && !is_dp_128b_132b_signal(pipe_ctx)) { + && !link_is_dp_128b_132b_signal(pipe_ctx)) { DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id); dsc_optc_config_log(dsc, &dsc_optc_cfg); pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, @@ -7418,7 +2241,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) /* disable DSC in stream encoder */ if (dc_is_dp_signal(stream->signal)) { - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.hpo_dp_stream_enc, false, @@ -7496,12 +2319,11 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_u dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; - DC_LOG_DSC(" "); dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]); memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps)); if (dc_is_dp_signal(stream->signal)) { DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id); - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.hpo_dp_stream_enc, true, @@ -7518,7 +2340,7 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_u /* disable DSC PPS in stream encoder */ memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps)); if (dc_is_dp_signal(stream->signal)) { - if (is_dp_128b_132b_signal(pipe_ctx)) + if (link_is_dp_128b_132b_signal(pipe_ctx)) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.hpo_dp_stream_enc, false, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c index 614f022d1cff..fa2ba3fc683b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c @@ -25,6 +25,7 @@ #include "link_enc_cfg.h" #include "resource.h" #include "dc_link_dp.h" +#include "link.h" #define DC_LOGGER dc->ctx->logger @@ -48,7 +49,7 @@ static bool is_dig_link_enc_stream(struct dc_stream_state *stream) /* DIGs do not support DP2.0 streams with 128b/132b encoding. */ struct dc_link_settings link_settings = {0}; - decide_link_settings(stream, &link_settings); + link_decide_link_settings(stream, &link_settings); if ((link_settings.link_rate >= LINK_RATE_LOW) && link_settings.link_rate <= LINK_RATE_HIGH3) { is_dig_stream = true; @@ -305,15 +306,17 @@ void link_enc_cfg_link_encs_assign( for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = streams[i]; + /* skip it if the link is mappable endpoint. */ + if (stream->link->is_dig_mapping_flexible) + continue; + /* Skip stream if not supported by DIG link encoder. */ if (!is_dig_link_enc_stream(stream)) continue; /* Physical endpoints have a fixed mapping to DIG link encoders. */ - if (!stream->link->is_dig_mapping_flexible) { - eng_id = stream->link->eng_id; - add_link_enc_assignment(state, stream, eng_id); - } + eng_id = stream->link->eng_id; + add_link_enc_assignment(state, stream, eng_id); } /* (b) Retain previous assignments for mappable endpoints if encoders still available. */ @@ -325,11 +328,12 @@ void link_enc_cfg_link_encs_assign( for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = state->streams[i]; - /* Skip stream if not supported by DIG link encoder. */ - if (!is_dig_link_enc_stream(stream)) + /* Skip it if the link is NOT mappable endpoint. */ + if (!stream->link->is_dig_mapping_flexible) continue; - if (!stream->link->is_dig_mapping_flexible) + /* Skip stream if not supported by DIG link encoder. */ + if (!is_dig_link_enc_stream(stream)) continue; for (j = 0; j < prev_state->stream_count; j++) { @@ -338,6 +342,7 @@ void link_enc_cfg_link_encs_assign( if (stream == prev_stream && stream->link == prev_stream->link && prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].valid) { eng_id = prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].eng_id; + if (is_avail_link_enc(state, eng_id, stream)) add_link_enc_assignment(state, stream, eng_id); } @@ -350,6 +355,15 @@ void link_enc_cfg_link_encs_assign( for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = streams[i]; + struct link_encoder *link_enc = NULL; + + /* Skip it if the link is NOT mappable endpoint. */ + if (!stream->link->is_dig_mapping_flexible) + continue; + + /* Skip if encoder assignment retained in step (b) above. */ + if (stream->link_enc) + continue; /* Skip stream if not supported by DIG link encoder. */ if (!is_dig_link_enc_stream(stream)) { @@ -358,24 +372,18 @@ void link_enc_cfg_link_encs_assign( } /* Mappable endpoints have a flexible mapping to DIG link encoders. */ - if (stream->link->is_dig_mapping_flexible) { - struct link_encoder *link_enc = NULL; - /* Skip if encoder assignment retained in step (b) above. */ - if (stream->link_enc) - continue; + /* For MST, multiple streams will share the same link / display + * endpoint. These streams should use the same link encoder + * assigned to that endpoint. + */ + link_enc = get_link_enc_used_by_link(state, stream->link); + if (link_enc == NULL) + eng_id = find_first_avail_link_enc(stream->ctx, state); + else + eng_id = link_enc->preferred_engine; - /* For MST, multiple streams will share the same link / display - * endpoint. These streams should use the same link encoder - * assigned to that endpoint. - */ - link_enc = get_link_enc_used_by_link(state, stream->link); - if (link_enc == NULL) - eng_id = find_first_avail_link_enc(stream->ctx, state); - else - eng_id = link_enc->preferred_engine; - add_link_enc_assignment(state, stream, eng_id); - } + add_link_enc_assignment(state, stream, eng_id); } link_enc_cfg_validate(dc, state); @@ -420,10 +428,6 @@ void link_enc_cfg_link_enc_unassign( { enum engine_id eng_id = ENGINE_ID_UNKNOWN; - /* Only DIG link encoders. */ - if (!is_dig_link_enc_stream(stream)) - return; - if (stream->link_enc) eng_id = stream->link_enc->preferred_engine; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index da164685547d..a5b5f8592c1b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -41,6 +41,7 @@ #include "dpcd_defs.h" #include "link_enc_cfg.h" #include "dc_link_dp.h" +#include "link.h" #include "virtual/virtual_link_hwss.h" #include "link/link_hwss_dio.h" #include "link/link_hwss_dpia.h" @@ -2213,7 +2214,7 @@ enum dc_status dc_remove_stream_from_ctx( del_pipe->stream_res.stream_enc, false); - if (is_dp_128b_132b_signal(del_pipe)) { + if (link_is_dp_128b_132b_signal(del_pipe)) { update_hpo_dp_stream_engine_usage( &new_ctx->res_ctx, dc->res_pool, del_pipe->stream_res.hpo_dp_stream_enc, @@ -2513,9 +2514,9 @@ enum dc_status resource_map_pool_resources( * and link settings */ if (dc_is_dp_signal(stream->signal)) { - if (!decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings)) + if (!link_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings)) return DC_FAIL_DP_LINK_BANDWIDTH; - if (dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { + if (link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { pipe_ctx->stream_res.hpo_dp_stream_enc = find_first_free_match_hpo_dp_stream_enc_for_link( &context->res_ctx, pool, stream); @@ -3763,7 +3764,7 @@ bool get_temp_dp_link_res(struct dc_link *link, memset(link_res, 0, sizeof(*link_res)); - if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) { + if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) { link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx, dc->res_pool, link); if (!link_res->hpo_dp_link_enc) @@ -3820,9 +3821,20 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, pipe_ctx_check = &context->res_ctx.pipe_ctx[i]; if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) && - IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) + IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) { + struct pipe_ctx *first_pipe = pipe_ctx_check; + + while (first_pipe->prev_odm_pipe) + first_pipe = first_pipe->prev_odm_pipe; + /* When ODM combine is enabled, this case is expected. If the disabled pipe + * is part of the ODM tree, then we should not print an error. + * */ + if (first_pipe->pipe_idx == disabled_master_pipe_idx) + continue; + DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n", - i, disabled_master_pipe_idx); + i, disabled_master_pipe_idx); + } } } @@ -3981,3 +3993,42 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm( return true; } + +enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc, + struct dc_state *context, + struct pipe_ctx *pipe_ctx) +{ + if (link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) { + if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) { + pipe_ctx->stream_res.hpo_dp_stream_enc = + find_first_free_match_hpo_dp_stream_enc_for_link( + &context->res_ctx, dc->res_pool, pipe_ctx->stream); + + if (!pipe_ctx->stream_res.hpo_dp_stream_enc) + return DC_NO_STREAM_ENC_RESOURCE; + + update_hpo_dp_stream_engine_usage( + &context->res_ctx, dc->res_pool, + pipe_ctx->stream_res.hpo_dp_stream_enc, + true); + } + + if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) { + if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream)) + return DC_NO_LINK_ENC_RESOURCE; + } + } else { + if (pipe_ctx->stream_res.hpo_dp_stream_enc) { + update_hpo_dp_stream_engine_usage( + &context->res_ctx, dc->res_pool, + pipe_ctx->stream_res.hpo_dp_stream_enc, + false); + pipe_ctx->stream_res.hpo_dp_stream_enc = NULL; + } + if (pipe_ctx->link_res.hpo_dp_link_enc) + remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream); + } + + return DC_OK; +} + diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stat.c b/drivers/gpu/drm/amd/display/dc/core/dc_stat.c index 4b372aa52801..6c06587dd88c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stat.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stat.c @@ -65,6 +65,7 @@ void dc_stat_get_dmub_notification(const struct dc *dc, struct dmub_notification /* For HPD/HPD RX, convert dpia port index into link index */ if (notify->type == DMUB_NOTIFICATION_HPD || notify->type == DMUB_NOTIFICATION_HPD_IRQ || + notify->type == DMUB_NOTIFICATION_DPIA_NOTIFICATION || notify->type == DMUB_NOTIFICATION_SET_CONFIG_REPLY) { notify->link_index = get_link_index_from_dpia_port_index(dc, notify->link_index); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 20e534f73513..72b261ad9587 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -408,7 +408,7 @@ bool dc_stream_set_cursor_position( struct dc_stream_state *stream, const struct dc_cursor_position *position) { - struct dc *dc = stream->ctx->dc; + struct dc *dc; bool reset_idle_optimizations = false; if (NULL == stream) { @@ -481,6 +481,7 @@ bool dc_stream_add_writeback(struct dc *dc, } if (!isDrc) { + ASSERT(stream->num_wb_info + 1 <= MAX_DWB_PIPES); stream->writeback_info[stream->num_wb_info++] = *wb_info; } @@ -526,6 +527,11 @@ bool dc_stream_remove_writeback(struct dc *dc, return false; } + if (stream->num_wb_info > MAX_DWB_PIPES) { + dm_error("DC: num_wb_info is invalid!\n"); + return false; + } + // stream->writeback_info[dwb_pipe_inst].wb_enabled = false; for (i = 0; i < stream->num_wb_info; i++) { /*dynamic update*/ @@ -540,7 +546,8 @@ bool dc_stream_remove_writeback(struct dc *dc, if (stream->writeback_info[i].wb_enabled) { if (j < i) /* trim the array */ - stream->writeback_info[j] = stream->writeback_info[i]; + memcpy(&stream->writeback_info[j], &stream->writeback_info[i], + sizeof(struct dc_writeback_info)); j++; } } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 85ebeaa2de18..22e754ad22c8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.215" +#define DC_VER "3.2.218" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -872,6 +872,8 @@ struct dc_debug_options { enum lttpr_mode lttpr_mode_override; unsigned int dsc_delay_factor_wa_x1000; unsigned int min_prefetch_in_strobe_ns; + bool disable_unbounded_requesting; + bool dig_fifo_off_in_blank; }; struct gpu_info_soc_bounding_box_v1_0; diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index 260ac4458870..be9aa1a71847 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -140,7 +140,8 @@ struct dc_vbios_funcs { enum bp_result (*enable_lvtma_control)( struct dc_bios *bios, uint8_t uc_pwr_on, - uint8_t panel_instance); + uint8_t panel_instance, + uint8_t bypass_panel_control_wait); enum bp_result (*get_soc_bb_info)( struct dc_bios *dcb, diff --git a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h index 7769bd099a5a..7b036a772b0c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h @@ -77,6 +77,32 @@ struct aux_reply_transaction_data { uint8_t *data; }; +struct aux_payload { + /* set following flag to read/write I2C data, + * reset it to read/write DPCD data */ + bool i2c_over_aux; + /* set following flag to write data, + * reset it to read data */ + bool write; + bool mot; + bool write_status_update; + + uint32_t address; + uint32_t length; + uint8_t *data; + /* + * used to return the reply type of the transaction + * ignored if NULL + */ + uint8_t *reply; + /* expressed in milliseconds + * zero means "use default value" + */ + uint32_t defer_delay; + +}; +#define DEFAULT_AUX_MAX_DATA_SIZE 16 + struct i2c_payload { bool write; uint8_t address; @@ -90,6 +116,8 @@ enum i2c_command_engine { I2C_COMMAND_ENGINE_HW }; +#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW + struct i2c_command { struct i2c_payload *payloads; uint8_t number_of_payloads; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 2c54b6e0498b..84da54358922 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -149,7 +149,6 @@ struct dc_link_settings { enum dc_link_spread link_spread; bool use_link_rate_set; uint8_t link_rate_set; - bool dpcd_source_device_specific_field_support; }; union dc_dp_ffe_preset { @@ -362,14 +361,10 @@ enum dpcd_downstream_port_detailed_type { union dwnstream_port_caps_byte2 { struct { uint8_t MAX_BITS_PER_COLOR_COMPONENT:2; -#if defined(CONFIG_DRM_AMD_DC_DCN) uint8_t MAX_ENCODED_LINK_BW_SUPPORT:3; uint8_t SOURCE_CONTROL_MODE_SUPPORT:1; uint8_t CONCURRENT_LINK_BRING_UP_SEQ_SUPPORT:1; uint8_t RESERVED:1; -#else - uint8_t RESERVED:6; -#endif } bits; uint8_t raw; }; @@ -407,7 +402,6 @@ union dwnstream_port_caps_byte3_hdmi { uint8_t raw; }; -#if defined(CONFIG_DRM_AMD_DC_DCN) union hdmi_sink_encoded_link_bw_support { struct { uint8_t HDMI_SINK_ENCODED_LINK_BW_SUPPORT:3; @@ -429,7 +423,6 @@ union hdmi_encoded_link_bw { } bits; uint8_t raw; }; -#endif /*4-byte structure for detailed capabilities of a down-stream port (DP-to-TMDS converter).*/ @@ -926,6 +919,9 @@ struct dpcd_usb4_dp_tunneling_info { #ifndef DP_128b_132b_TRAINING_AUX_RD_INTERVAL #define DP_128b_132b_TRAINING_AUX_RD_INTERVAL 0x2216 #endif +#ifndef DP_LINK_SQUARE_PATTERN +#define DP_LINK_SQUARE_PATTERN 0x10F +#endif #ifndef DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX #define DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX 0x2217 #endif @@ -973,6 +969,9 @@ struct dpcd_usb4_dp_tunneling_info { /* TODO - Use DRM header to replace above once available */ #endif // DP_INTRA_HOP_AUX_REPLY_INDICATION +#ifndef DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE +#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 +#endif union dp_main_line_channel_coding_cap { struct { uint8_t DP_8b_10b_SUPPORTED :1; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h new file mode 100644 index 000000000000..faf0d175bf19 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h @@ -0,0 +1,114 @@ +/* + * Copyright 2022 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: AMD + * + */ + +#ifndef DC_HDMI_TYPES_H +#define DC_HDMI_TYPES_H + +#include "os_types.h" + +/* Address range from 0x00 to 0x1F.*/ +#define DP_ADAPTOR_TYPE2_SIZE 0x20 +#define DP_ADAPTOR_TYPE2_REG_ID 0x10 +#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D +/* Identifies adaptor as Dual-mode adaptor */ +#define DP_ADAPTOR_TYPE2_ID 0xA0 +/* MHz*/ +#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600 +/* MHz*/ +#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25 +/* kHZ*/ +#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 +/* kHZ*/ +#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 + +struct dp_hdmi_dongle_signature_data { + int8_t id[15];/* "DP-HDMI ADAPTOR"*/ + uint8_t eot;/* end of transmition '\x4' */ +}; + +/* DP-HDMI dongle slave address for retrieving dongle signature*/ +#define DP_HDMI_DONGLE_ADDRESS 0x40 +static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR"; +#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04 + + +/* SCDC Address defines (HDMI 2.0)*/ +#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3 +#define HDMI_SCDC_ADDRESS 0x54 +#define HDMI_SCDC_SINK_VERSION 0x01 +#define HDMI_SCDC_SOURCE_VERSION 0x02 +#define HDMI_SCDC_UPDATE_0 0x10 +#define HDMI_SCDC_TMDS_CONFIG 0x20 +#define HDMI_SCDC_SCRAMBLER_STATUS 0x21 +#define HDMI_SCDC_CONFIG_0 0x30 +#define HDMI_SCDC_CONFIG_1 0x31 +#define HDMI_SCDC_SOURCE_TEST_REQ 0x35 +#define HDMI_SCDC_STATUS_FLAGS 0x40 +#define HDMI_SCDC_ERR_DETECT 0x50 +#define HDMI_SCDC_TEST_CONFIG 0xC0 + +union hdmi_scdc_update_read_data { + uint8_t byte[2]; + struct { + uint8_t STATUS_UPDATE:1; + uint8_t CED_UPDATE:1; + uint8_t RR_TEST:1; + uint8_t RESERVED:5; + uint8_t RESERVED2:8; + } fields; +}; + +union hdmi_scdc_status_flags_data { + uint8_t byte; + struct { + uint8_t CLOCK_DETECTED:1; + uint8_t CH0_LOCKED:1; + uint8_t CH1_LOCKED:1; + uint8_t CH2_LOCKED:1; + uint8_t RESERVED:4; + } fields; +}; + +union hdmi_scdc_ced_data { + uint8_t byte[11]; + struct { + uint8_t CH0_8LOW:8; + uint8_t CH0_7HIGH:7; + uint8_t CH0_VALID:1; + uint8_t CH1_8LOW:8; + uint8_t CH1_7HIGH:7; + uint8_t CH1_VALID:1; + uint8_t CH2_8LOW:8; + uint8_t CH2_7HIGH:7; + uint8_t CH2_VALID:1; + uint8_t CHECKSUM:8; + uint8_t RESERVED:8; + uint8_t RESERVED2:8; + uint8_t RESERVED3:8; + uint8_t RESERVED4:4; + } fields; +}; + +#endif /* DC_HDMI_TYPES_H */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 2e18bcf6b11a..48f6a5b09336 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -31,6 +31,7 @@ #include "grph_object_defs.h" struct link_resource; +enum aux_return_code_type; enum dc_link_fec_state { dc_link_fec_not_ready, @@ -158,11 +159,11 @@ struct dc_panel_config { struct dc_dpia_bw_alloc { int sink_verified_bw; // The Verified BW that sink can allocated and use that has been verified already int sink_allocated_bw; // The Actual Allocated BW that sink currently allocated - int padding_bw; // The Padding "Un-used" BW allocated by CM for padding reasons int sink_max_bw; // The Max BW that sink can require/support int estimated_bw; // The estimated available BW for this DPIA int bw_granularity; // BW Granularity bool bw_alloc_enabled; // The BW Alloc Mode Support is turned ON for all 3: DP-Tx & Dpia & CM + bool response_ready; // Response ready from the CM side }; /* @@ -293,6 +294,8 @@ struct dc_link { struct gpio *hpd_gpio; enum dc_link_fec_state fec_state; + bool link_powered_externally; // Used to bypass hardware sequencing delays when panel is powered down forcibly + struct dc_panel_config panel_config; struct phy_state phy_state; }; @@ -335,15 +338,17 @@ static inline bool dc_get_edp_link_panel_inst(const struct dc *dc, unsigned int *inst_out) { struct dc_link *edp_links[MAX_NUM_EDP]; - int edp_num; + int edp_num, i; + *inst_out = 0; if (link->connector_signal != SIGNAL_TYPE_EDP) return false; get_edp_links(dc, edp_links, &edp_num); - if ((edp_num > 1) && (link->link_index > edp_links[0]->link_index)) - *inst_out = 1; - else - *inst_out = 0; + for (i = 0; i < edp_num; i++) { + if (link == edp_links[i]) + break; + (*inst_out)++; + } return true; } @@ -456,31 +461,6 @@ void dc_link_dp_set_drive_settings( const struct link_resource *link_res, struct link_training_settings *lt_settings); -bool dc_link_dp_perform_link_training_skip_aux( - struct dc_link *link, - const struct link_resource *link_res, - const struct dc_link_settings *link_setting); - -enum link_training_result dc_link_dp_perform_link_training( - struct dc_link *link, - const struct link_resource *link_res, - const struct dc_link_settings *link_settings, - bool skip_video_pattern); - -bool dc_link_dp_sync_lt_begin(struct dc_link *link); - -enum link_training_result dc_link_dp_sync_lt_attempt( - struct dc_link *link, - const struct link_resource *link_res, - struct dc_link_settings *link_setting, - struct dc_link_training_overrides *lt_settings); - -bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down); - -void dc_link_dp_enable_hpd(const struct dc_link *link); - -void dc_link_dp_disable_hpd(const struct dc_link *link); - bool dc_link_dp_set_test_pattern( struct dc_link *link, enum dp_test_pattern test_pattern, @@ -491,6 +471,21 @@ bool dc_link_dp_set_test_pattern( bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap); +/** + ***************************************************************************** + * Function: dc_link_enable_hpd_filter + * + * @brief + * If enable is true, programs HPD filter on associated HPD line to default + * values dependent on link->connector_signal + * + * If enable is false, programs HPD filter on associated HPD line with no + * delays on connect or disconnect + * + * @param [in] link: pointer to the dc link + * @param [in] enable: boolean specifying whether to enable hbd + ***************************************************************************** + */ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); bool dc_link_is_dp_sink_present(struct dc_link *link); @@ -563,9 +558,6 @@ void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map); /* restore link resource allocation state from a snapshot */ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map); void dc_link_clear_dprx_states(struct dc_link *link); -struct gpio *get_hpd_gpio(struct dc_bios *dcb, - struct graphics_object_id link_id, - struct gpio_service *gpio_service); void dp_trace_reset(struct dc_link *link); bool dc_dp_trace_is_initialized(struct dc_link *link); unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link, @@ -581,4 +573,20 @@ unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link); /* Destruct the mst topology of the link and reset the allocated payload table */ bool reset_cur_dp_mst_topology(struct dc_link *link); + +/* Attempt to transfer the given aux payload. This function does not perform + * retries or handle error states. The reply is returned in the payload->reply + * and the result through operation_result. Returns the number of bytes + * transferred,or -1 on a failure. + */ +int dc_link_aux_transfer_raw(struct ddc_service *ddc, + struct aux_payload *payload, + enum aux_return_code_type *operation_result); + +enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link, + struct dc_link_settings *link_setting); +void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on); +bool dc_link_decide_edp_link_settings(struct dc_link *link, + struct dc_link_settings *link_setting, + uint32_t req_bw); #endif /* DC_LINK_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index dfd3df1d2f7e..ef33d7d8a2bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -543,9 +543,8 @@ bool dc_stream_get_crtc_position(struct dc *dc, unsigned int *nom_v_pos); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) -bool dc_stream_forward_crc_window(struct dc *dc, +bool dc_stream_forward_crc_window(struct dc_stream_state *stream, struct rect *rect, - struct dc_stream_state *stream, bool is_stop); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index dc78e2404b48..c73a655bd687 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -33,6 +33,7 @@ #include "fixed31_32.h" #include "irq_types.h" #include "dc_dp_types.h" +#include "dc_hdmi_types.h" #include "dc_hw_types.h" #include "dal_types.h" #include "grph_object_defs.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h index e69f1899fbf0..c850ed49281f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -26,7 +26,7 @@ #ifndef __DAL_AUX_ENGINE_DCE110_H__ #define __DAL_AUX_ENGINE_DCE110_H__ -#include "i2caux_interface.h" +#include "gpio_service_interface.h" #include "inc/hw/aux_engine.h" enum aux_return_code_type; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 09260c23c3bd..fa314493ffc5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -29,7 +29,6 @@ #include "link_encoder.h" #include "dce_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 913a1fe6b3da..a51bd21a796f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -46,6 +46,7 @@ #include "link_encoder.h" #include "link_enc_cfg.h" #include "link_hwss.h" +#include "link.h" #include "dc_link_dp.h" #include "dccg.h" #include "clock_source.h" @@ -54,7 +55,6 @@ #include "audio.h" #include "reg_helper.h" #include "panel_cntl.h" -#include "inc/link_dpcd.h" #include "dpcd_defs.h" /* include DCE11 register header files */ #include "dce/dce_11_0_d.h" @@ -737,7 +737,7 @@ void dce110_edp_wait_for_hpd_ready( /* obtain HPD */ /* TODO what to do with this? */ - hpd = get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service); + hpd = link_get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service); if (!hpd) { BREAK_TO_DEBUGGER(); @@ -875,14 +875,16 @@ void dce110_edp_power_control( if (ctx->dc->ctx->dmub_srv && ctx->dc->debug.dmub_command_table) { - if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) + + if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) { bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_POWER_ON, - panel_instance); - else + panel_instance, link->link_powered_externally); + } else { bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_POWER_OFF, - panel_instance); + panel_instance, link->link_powered_externally); + } } bp_result = link_transmitter_control(ctx->dc_bios, &cntl); @@ -941,7 +943,6 @@ void dce110_edp_wait_for_T12( msleep(t12_duration - time_since_edp_poweroff_ms); } } - /*todo: cloned in stream enc, fix*/ /* * @brief @@ -1020,16 +1021,20 @@ void dce110_edp_backlight_control( DC_LOG_DC("edp_receiver_ready_T7 skipped\n"); } + /* Setting link_powered_externally will bypass delays in the backlight + * as they are not required if the link is being powered by a different + * source. + */ if (ctx->dc->ctx->dmub_srv && ctx->dc->debug.dmub_command_table) { if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_LCD_BLON, - panel_instance); + panel_instance, link->link_powered_externally); else ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_LCD_BLOFF, - panel_instance); + panel_instance, link->link_powered_externally); } link_transmitter_control(ctx->dc_bios, &cntl); @@ -1142,6 +1147,10 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) struct dc_link *link = stream->link; struct dc *dc = pipe_ctx->stream->ctx->dc; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + struct dccg *dccg = dc->res_pool->dccg; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + struct dtbclk_dto_params dto_params = {0}; + int dp_hpo_inst; if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) { pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( @@ -1150,7 +1159,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.stream_enc); } - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets( pipe_ctx->stream_res.hpo_dp_stream_enc); } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) @@ -1161,7 +1170,16 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) link_hwss->reset_stream_encoder(pipe_ctx); - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { + dto_params.otg_inst = tg->inst; + dto_params.timing = &pipe_ctx->stream->timing; + dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); + dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); + } + + if (link_is_dp_128b_132b_signal(pipe_ctx)) { /* TODO: This looks like a bug to me as we are disabling HPO IO when * we are just disabling a single HPO stream. Shouldn't we disable HPO * HW control only when HPOs for all streams are disabled? @@ -1203,7 +1221,7 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx) link->dc->hwss.set_abm_immediate_disable(pipe_ctx); } - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank( pipe_ctx->stream_res.hpo_dp_stream_enc); @@ -1408,7 +1426,7 @@ static enum dc_status dce110_enable_stream_timing( if (false == pipe_ctx->clock_source->funcs->program_pix_clk( pipe_ctx->clock_source, &pipe_ctx->stream_res.pix_clk_params, - dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), + link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), &pipe_ctx->pll_settings)) { BREAK_TO_DEBUGGER(); return DC_ERROR_UNEXPECTED; @@ -1512,7 +1530,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( * To do so, move calling function enable_stream_timing to only be done AFTER calling * function core_link_enable_stream */ - if (!(hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx))) + if (!(hws->wa.dp_hpo_and_otg_sequence && link_is_dp_128b_132b_signal(pipe_ctx))) /* */ /* Do not touch stream timing on seamless boot optimization. */ if (!pipe_ctx->stream->apply_seamless_boot_optimization) @@ -1554,7 +1572,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( * To do so, move calling function enable_stream_timing to only be done AFTER calling * function core_link_enable_stream */ - if (hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)) { + if (hws->wa.dp_hpo_and_otg_sequence && link_is_dp_128b_132b_signal(pipe_ctx)) { if (!pipe_ctx->stream->apply_seamless_boot_optimization) hws->funcs.enable_stream_timing(pipe_ctx, context, dc); } @@ -3034,13 +3052,13 @@ void dce110_enable_dp_link_output( pipes[i].clock_source->funcs->program_pix_clk( pipes[i].clock_source, &pipes[i].stream_res.pix_clk_params, - dp_get_link_encoding_format(link_settings), + link_dp_get_encoding_format(link_settings), &pipes[i].pll_settings); } } } - if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { + if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) { if (dc->clk_mgr->funcs->notify_link_rate_change) dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index 758f4b3b0087..394d83a97f33 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -71,7 +71,7 @@ void dce110_optimize_bandwidth( struct dc *dc, struct dc_state *context); -void dp_receiver_power_ctrl(struct dc_link *link, bool on); +void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on); void dce110_edp_power_control( struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index ba1c0621f0f8..e8752077571a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -172,6 +172,10 @@ struct dcn_hubbub_registers { uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C; uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D; uint32_t SDPIF_REQUEST_RATE_LIMIT; + uint32_t DCHUBBUB_SDPIF_CFG0; + uint32_t DCHUBBUB_SDPIF_CFG1; + uint32_t DCHUBBUB_CLOCK_CNTL; + uint32_t DCHUBBUB_MEM_PWR_MODE_CTRL; }; #define HUBBUB_REG_FIELD_LIST_DCN32(type) \ @@ -362,7 +366,13 @@ struct dcn_hubbub_registers { type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C;\ type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D;\ type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D;\ - type SDPIF_REQUEST_RATE_LIMIT + type SDPIF_REQUEST_RATE_LIMIT;\ + type DISPCLK_R_DCHUBBUB_GATE_DIS;\ + type DCFCLK_R_DCHUBBUB_GATE_DIS;\ + type SDPIF_MAX_NUM_OUTSTANDING;\ + type DCHUBBUB_ARB_MAX_REQ_OUTSTAND;\ + type SDPIF_PORT_CONTROL;\ + type DET_MEM_PWR_LS_MODE struct dcn_hubbub_shift { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index fe2023f18b7d..0a0c930c1626 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -57,7 +57,7 @@ #include "dc_trace.h" #include "dce/dmub_outbox.h" #include "inc/dc_link_dp.h" -#include "inc/link_dpcd.h" +#include "link.h" #define DC_LOGGER_INIT(logger) @@ -921,7 +921,7 @@ enum dc_status dcn10_enable_stream_timing( if (false == pipe_ctx->clock_source->funcs->program_pix_clk( pipe_ctx->clock_source, &pipe_ctx->stream_res.pix_clk_params, - dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), + link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), &pipe_ctx->pll_settings)) { BREAK_TO_DEBUGGER(); return DC_ERROR_UNEXPECTED; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index fbccb7263ad2..c4287147b853 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -29,7 +29,6 @@ #include "link_encoder.h" #include "dcn10_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index 484e7cdf00b8..1527c3b4fb19 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -28,7 +28,7 @@ #include "dcn10_stream_encoder.h" #include "reg_helper.h" #include "hw_shared.h" -#include "inc/link_dpcd.h" +#include "dc_link_dp.h" #include "dpcd_defs.h" #include "dcn30/dcn30_afmt.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c index 784a8b6f360d..c08c01e05dcf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c @@ -200,7 +200,6 @@ static void dsc2_set_config(struct display_stream_compressor *dsc, const struct bool is_config_ok; struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - DC_LOG_DSC(" "); DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst); dsc_config_log(dsc, dsc_cfg); is_config_ok = dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, dsc_optc_cfg); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 6291a241158a..6bfa16d9135f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -52,10 +52,10 @@ #include "dc_dmub_srv.h" #include "dce/dmub_hw_lock_mgr.h" #include "hw_sequencer.h" -#include "inc/link_dpcd.h" #include "dpcd_defs.h" #include "inc/link_enc_cfg.h" #include "link_hwss.h" +#include "link.h" #define DC_LOGGER_INIT(logger) @@ -582,6 +582,9 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) if (pipe_ctx->stream_res.gsl_group != 0) dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); + if (hubp->funcs->hubp_update_mall_sel) + hubp->funcs->hubp_update_mall_sel(hubp, 0, false); + dc->hwss.set_flip_control_gsl(pipe_ctx, false); hubp->funcs->hubp_clk_cntl(hubp, false); @@ -605,6 +608,9 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) { + bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; + struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; + DC_LOGGER_INIT(dc->ctx->logger); if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) @@ -612,6 +618,12 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) dcn20_plane_atomic_disable(dc, pipe_ctx); + /* Turn back off the phantom OTG after the phantom plane is fully disabled + */ + if (is_phantom) + if (tg && tg->funcs->disable_phantom_crtc) + tg->funcs->disable_phantom_crtc(tg); + DC_LOG_DC("Power down front end %d\n", pipe_ctx->pipe_idx); } @@ -700,7 +712,7 @@ enum dc_status dcn20_enable_stream_timing( if (false == pipe_ctx->clock_source->funcs->program_pix_clk( pipe_ctx->clock_source, &pipe_ctx->stream_res.pix_clk_params, - dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), + link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), &pipe_ctx->pll_settings)) { BREAK_TO_DEBUGGER(); return DC_ERROR_UNEXPECTED; @@ -1803,6 +1815,18 @@ void dcn20_program_front_end_for_ctx( dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i], &context->res_ctx.pipe_ctx[i]); + /* When disabling phantom pipes, turn on phantom OTG first (so we can get double + * buffer updates properly) + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable + && dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { + struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; + + if (tg->funcs->enable_crtc) + tg->funcs->enable_crtc(tg); + } + /* OTG blank before disabling all front ends */ for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable @@ -2359,7 +2383,7 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, params.link_settings.link_rate = link_settings->link_rate; - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( pipe_ctx->stream_res.hpo_dp_stream_enc, @@ -2615,6 +2639,37 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->mpcc_id = mpcc_id; } +static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link) +{ + switch (link->link_enc->transmitter) { + case TRANSMITTER_UNIPHY_A: + return PHYD32CLKA; + case TRANSMITTER_UNIPHY_B: + return PHYD32CLKB; + case TRANSMITTER_UNIPHY_C: + return PHYD32CLKC; + case TRANSMITTER_UNIPHY_D: + return PHYD32CLKD; + case TRANSMITTER_UNIPHY_E: + return PHYD32CLKE; + default: + return PHYD32CLKA; + } +} + +static int get_odm_segment_count(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + int count = 1; + + while (odm_pipe != NULL) { + count++; + odm_pipe = odm_pipe->next_odm_pipe; + } + + return count; +} + void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) { enum dc_lane_count lane_count = @@ -2628,12 +2683,43 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) struct timing_generator *tg = pipe_ctx->stream_res.tg; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); struct dc *dc = pipe_ctx->stream->ctx->dc; + struct dtbclk_dto_params dto_params = {0}; + struct dccg *dccg = dc->res_pool->dccg; + enum phyd32clk_clock_source phyd32clk; + int dp_hpo_inst; + struct dce_hwseq *hws = dc->hwseq; + unsigned int k1_div = PIXEL_RATE_DIV_NA; + unsigned int k2_div = PIXEL_RATE_DIV_NA; - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { if (dc->hwseq->funcs.setup_hpo_hw_control) dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, true); } + if (link_is_dp_128b_132b_signal(pipe_ctx)) { + dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; + dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); + + phyd32clk = get_phyd32clk_src(link); + dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); + + dto_params.otg_inst = tg->inst; + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; + dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); + dto_params.timing = &pipe_ctx->stream->timing; + dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + } + + if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { + hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); + + dc->res_pool->dccg->funcs->set_pixel_rate_div( + dc->res_pool->dccg, + pipe_ctx->stream_res.tg->inst, + k1_div, k2_div); + } + link_hwss->setup_stream_encoder(pipe_ctx); if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c index 2f9bfaeaba8d..51a57dae1811 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c @@ -29,7 +29,6 @@ #include "link_encoder.h" #include "dcn20_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 8a0dd0d7134b..531f405d2554 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -62,7 +62,6 @@ #include "dml/display_mode_vba.h" #include "dcn20_dccg.h" #include "dcn20_vmid.h" -#include "dc_link_ddc.h" #include "dce/dce_panel_cntl.h" #include "navi10_ip_offset.h" @@ -90,6 +89,7 @@ #include "amdgpu_socbb.h" +#include "link.h" #define DC_LOGGER_INIT(logger) #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL @@ -1214,7 +1214,7 @@ static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) dcn20_pp_smu_destroy(&pool->base.pp_smu); if (pool->base.oem_device != NULL) - dal_ddc_service_destroy(&pool->base.oem_device); + link_destroy_ddc_service(&pool->base.oem_device); } struct hubp *dcn20_hubp_create( @@ -1389,6 +1389,9 @@ enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &dc_ctx->res_ctx.pipe_ctx[i]; + if (pipe_ctx->top_pipe) + continue; + if (pipe_ctx->stream != dc_stream) continue; @@ -2766,7 +2769,7 @@ static bool dcn20_resource_construct( ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; ddc_init_data.id.enum_id = 0; ddc_init_data.id.type = OBJECT_TYPE_GENERIC; - pool->base.oem_device = dal_ddc_service_create(&ddc_init_data); + pool->base.oem_device = link_create_ddc_service(&ddc_init_data); } else { pool->base.oem_device = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c index b40489e678f9..cacf3f5298b0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c @@ -29,7 +29,7 @@ #include "dcn20_stream_encoder.h" #include "reg_helper.h" #include "hw_shared.h" -#include "inc/link_dpcd.h" +#include "dc_link_dp.h" #include "dpcd_defs.h" #define DC_LOGGER \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c index 7f9ec59ef443..8d31fa131cd6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c @@ -29,7 +29,6 @@ #include "link_encoder.h" #include "dcn201_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c index 0a1ba6e7081c..eb9abb9f9698 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c @@ -31,7 +31,6 @@ #include "dcn21_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c index 6f3c2fb60790..1fb8fd7afc95 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c @@ -29,7 +29,6 @@ #include "link_encoder.h" #include "dcn30_dio_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" /* #include "dcn3ag/dcn3ag_phy_fw.h" */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 8c5045711264..7360b3ce4283 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -51,7 +51,6 @@ #include "../dcn20/dcn20_hwseq.h" #include "dcn30_resource.h" #include "inc/dc_link_dp.h" -#include "inc/link_dpcd.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index c18c52a60100..feb4bb491525 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -60,7 +60,7 @@ #include "dml/display_mode_vba.h" #include "dcn30/dcn30_dccg.h" #include "dcn10/dcn10_resource.h" -#include "dc_link_ddc.h" +#include "link.h" #include "dce/dce_panel_cntl.h" #include "dcn30/dcn30_dwb.h" @@ -1208,7 +1208,7 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) dcn_dccg_destroy(&pool->base.dccg); if (pool->base.oem_device != NULL) - dal_ddc_service_destroy(&pool->base.oem_device); + link_destroy_ddc_service(&pool->base.oem_device); } static struct hubp *dcn30_hubp_create( @@ -2590,7 +2590,7 @@ static bool dcn30_resource_construct( ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; ddc_init_data.id.enum_id = 0; ddc_init_data.id.type = OBJECT_TYPE_GENERIC; - pool->base.oem_device = dal_ddc_service_create(&ddc_init_data); + pool->base.oem_device = link_create_ddc_service(&ddc_init_data); } else { pool->base.oem_device = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c index c9fbaed23965..1b39a6e8a1ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c @@ -29,7 +29,6 @@ #include "link_encoder.h" #include "dcn301_dio_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index 8cf10351f271..ee62ae3eb98f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -1414,7 +1414,8 @@ static struct resource_funcs dcn301_res_pool_funcs = { .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut, .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, - .update_bw_bounding_box = dcn301_update_bw_bounding_box + .update_bw_bounding_box = dcn301_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state }; static bool dcn301_resource_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c index 47cffd0e6830..03ddf4f5f065 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c @@ -47,6 +47,7 @@ #include "dcn10/dcn10_resource.h" +#include "link.h" #include "dce/dce_abm.h" #include "dce/dce_audio.h" #include "dce/dce_aux.h" @@ -1125,6 +1126,9 @@ static void dcn302_resource_destruct(struct resource_pool *pool) if (pool->dccg != NULL) dcn_dccg_destroy(&pool->dccg); + + if (pool->oem_device != NULL) + link_destroy_ddc_service(&pool->oem_device); } static void dcn302_destroy_resource_pool(struct resource_pool **pool) @@ -1216,6 +1220,7 @@ static bool dcn302_resource_construct( int i; struct dc_context *ctx = dc->ctx; struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data = {0}; ctx->dc_bios->regs = &bios_regs; @@ -1497,6 +1502,17 @@ static bool dcn302_resource_construct( dc->cap_funcs = cap_funcs; + if (dc->ctx->dc_bios->fw_info.oem_i2c_present) { + ddc_init_data.ctx = dc->ctx; + ddc_init_data.link = NULL; + ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; + ddc_init_data.id.enum_id = 0; + ddc_init_data.id.type = OBJECT_TYPE_GENERIC; + pool->oem_device = link_create_ddc_service(&ddc_init_data); + } else { + pool->oem_device = NULL; + } + return true; create_fail: diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index c14d35894b2e..31e212064168 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -29,7 +29,7 @@ #include "dcn10/dcn10_resource.h" -#include "dc_link_ddc.h" +#include "link.h" #include "dce/dce_abm.h" #include "dce/dce_audio.h" @@ -1054,7 +1054,7 @@ static void dcn303_resource_destruct(struct resource_pool *pool) dcn_dccg_destroy(&pool->dccg); if (pool->oem_device != NULL) - dal_ddc_service_destroy(&pool->oem_device); + link_destroy_ddc_service(&pool->oem_device); } static void dcn303_destroy_resource_pool(struct resource_pool **pool) @@ -1421,7 +1421,7 @@ static bool dcn303_resource_construct( ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; ddc_init_data.id.enum_id = 0; ddc_init_data.id.type = OBJECT_TYPE_GENERIC; - pool->oem_device = dal_ddc_service_create(&ddc_init_data); + pool->oem_device = link_create_ddc_service(&ddc_init_data); } else { pool->oem_device = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c index ab70ebd8f223..275e78c06dee 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -30,7 +30,6 @@ #include "link_encoder.h" #include "dcn31_dio_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c index 80dfaa4d4d81..0b317ed31f91 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c @@ -242,7 +242,10 @@ void dcn31_hpo_dp_link_enc_set_link_test_pattern( REG_UPDATE(DP_DPHY_SYM32_CONTROL, MODE, DP2_TEST_PATTERN); break; - case DP_TEST_PATTERN_SQUARE_PULSE: + case DP_TEST_PATTERN_SQUARE: + case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: + case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: + case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: REG_SET(DP_DPHY_SYM32_TP_SQ_PULSE, 0, TP_SQ_PULSE_WIDTH, tp_params->custom_pattern[0]); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c index 6360dc9502e7..7e7cd5b64e6a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c @@ -1008,6 +1008,24 @@ static bool hubbub31_verify_allow_pstate_change_high(struct hubbub *hubbub) return false; } +void hubbub31_init(struct hubbub *hubbub) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + /*Enable clock gate*/ + if (hubbub->ctx->dc->debug.disable_clock_gate) { + /*done in hwseq*/ + /*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/ + REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL, + DISPCLK_R_DCHUBBUB_GATE_DIS, 0, + DCFCLK_R_DCHUBBUB_GATE_DIS, 0); + } + + /* + only the DCN will determine when to connect the SDP port + */ + REG_UPDATE(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, 1); +} static const struct hubbub_funcs hubbub31_funcs = { .update_dchub = hubbub2_update_dchub, .init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h index 70c60de448ac..e015e5a6c866 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h @@ -42,6 +42,10 @@ SR(DCHUBBUB_COMPBUF_CTRL),\ SR(COMPBUF_RESERVED_SPACE),\ SR(DCHUBBUB_DEBUG_CTRL_0),\ + SR(DCHUBBUB_CLOCK_CNTL),\ + SR(DCHUBBUB_SDPIF_CFG0),\ + SR(DCHUBBUB_SDPIF_CFG1),\ + SR(DCHUBBUB_MEM_PWR_MODE_CTRL),\ SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A),\ SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A),\ SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B),\ @@ -120,7 +124,11 @@ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_VMID, mask_sh), \ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_TABLE_LEVEL, mask_sh), \ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \ - HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh) + HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DISPCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DCFCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, mask_sh),\ + HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh) int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, struct dcn_hubbub_phys_addr_config *pa_config); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 4226a051df41..0e1949d9ea58 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -46,7 +46,7 @@ #include "dpcd_defs.h" #include "dce/dmub_outbox.h" #include "dc_link_dp.h" -#include "inc/link_dpcd.h" +#include "link.h" #include "dcn10/dcn10_hw_sequencer.h" #include "inc/link_enc_cfg.h" #include "dcn30/dcn30_vpg.h" @@ -415,7 +415,12 @@ void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( pipe_ctx->stream_res.stream_enc, &pipe_ctx->stream_res.encoder_info_frame); - else { + else if (link_is_dp_128b_132b_signal(pipe_ctx)) { + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets( + pipe_ctx->stream_res.hpo_dp_stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + return; + } else { pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( pipe_ctx->stream_res.stream_enc, &pipe_ctx->stream_res.encoder_info_frame); @@ -623,43 +628,3 @@ void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) if (hws->ctx->dc->debug.hpo_optimization) REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable); } -void dcn31_set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust) -{ - int i = 0; - struct drr_params params = {0}; - unsigned int event_triggers = 0x2;/*Bit[1]: OTG_TRIG_A*/ - unsigned int num_frames = 2; - params.vertical_total_max = adjust.v_total_max; - params.vertical_total_min = adjust.v_total_min; - params.vertical_total_mid = adjust.v_total_mid; - params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num; - for (i = 0; i < num_pipes; i++) { - if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) { - if (pipe_ctx[i]->stream_res.tg->funcs->set_drr) - pipe_ctx[i]->stream_res.tg->funcs->set_drr( - pipe_ctx[i]->stream_res.tg, ¶ms); - if (adjust.v_total_max != 0 && adjust.v_total_min != 0) - if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx[i]->stream_res.tg, - event_triggers, num_frames); - } - } -} -void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params) -{ - unsigned int i; - unsigned int triggers = 0; - if (params->triggers.surface_update) - triggers |= 0x600;/*bit 9 and bit10 : 110 0000 0000*/ - if (params->triggers.cursor_update) - triggers |= 0x10;/*bit4*/ - if (params->triggers.force_trigger) - triggers |= 0x1; - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs-> - set_static_screen_control(pipe_ctx[i]->stream_res.tg, - triggers, params->num_frames); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h index e7e03a8722e0..edfc01d6ad73 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h @@ -56,8 +56,4 @@ bool dcn31_is_abm_supported(struct dc *dc, void dcn31_init_pipes(struct dc *dc, struct dc_state *context); void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); -void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params); -void dcn31_set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust); #endif /* __DC_HWSS_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c index 7c2da70ffe21..3a32810bbe38 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c @@ -64,9 +64,9 @@ static const struct hw_sequencer_funcs dcn31_funcs = { .prepare_bandwidth = dcn20_prepare_bandwidth, .optimize_bandwidth = dcn20_optimize_bandwidth, .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn31_set_drr, + .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn31_set_static_screen_control, + .set_static_screen_control = dcn10_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c index fe449f7aa771..63a677c8ee27 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c @@ -40,7 +40,6 @@ #define FN(reg_name, field_name) \ optc1->tg_shift->field_name, optc1->tg_mask->field_name -#define STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN 0x2000 /*bit 13*/ static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, struct dc_crtc_timing *timing) { @@ -232,32 +231,6 @@ void optc3_init_odm(struct timing_generator *optc) OPTC_MEM_SEL, 0); optc1->opp_count = 1; } -void optc31_set_static_screen_control( - struct timing_generator *optc, - uint32_t event_triggers, - uint32_t num_frames) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t framecount; - uint32_t events; - - if (num_frames > 0xFF) - num_frames = 0xFF; - REG_GET_2(OTG_STATIC_SCREEN_CONTROL, - OTG_STATIC_SCREEN_EVENT_MASK, &events, - OTG_STATIC_SCREEN_FRAME_COUNT, &framecount); - - if (events == event_triggers && num_frames == framecount) - return; - if ((event_triggers & STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN) - != 0) - event_triggers = event_triggers & - ~STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN; - - REG_UPDATE_2(OTG_STATIC_SCREEN_CONTROL, - OTG_STATIC_SCREEN_EVENT_MASK, event_triggers, - OTG_STATIC_SCREEN_FRAME_COUNT, num_frames); -} static struct timing_generator_funcs dcn31_tg_funcs = { .validate_timing = optc1_validate_timing, @@ -293,7 +266,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = { .set_drr = optc31_set_drr, .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, .set_vtotal_min_max = optc1_set_vtotal_min_max, - .set_static_screen_control = optc31_set_static_screen_control, + .set_static_screen_control = optc1_set_static_screen_control, .program_stereo = optc1_program_stereo, .is_stereo_left_eye = optc1_is_stereo_left_eye, .tg_init = optc3_tg_init, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h index 5fc6c63580d7..30b81a448ce2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h @@ -263,8 +263,5 @@ bool optc31_immediate_disable_crtc(struct timing_generator *optc); void optc31_set_drr(struct timing_generator *optc, const struct drr_params *params); void optc3_init_odm(struct timing_generator *optc); -void optc31_set_static_screen_control( - struct timing_generator *optc, - uint32_t event_triggers, - uint32_t num_frames); + #endif /* __DC_OPTC_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c index 38842f938bed..67f4589f3e23 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c @@ -30,7 +30,7 @@ #include "dcn314_dio_stream_encoder.h" #include "reg_helper.h" #include "hw_shared.h" -#include "inc/link_dpcd.h" +#include "dc_link_dp.h" #include "dpcd_defs.h" #define DC_LOGGER \ @@ -278,10 +278,11 @@ static void enc314_stream_encoder_dp_blank( struct dc_link *link, struct stream_encoder *enc) { - /* New to DCN314 - disable the FIFO before VID stream disable. */ - enc314_disable_fifo(enc); - enc1_stream_encoder_dp_blank(link, enc); + + /* Disable FIFO after the DP vid stream is disabled to avoid corruption. */ + if (enc->ctx->dc->debug.dig_fifo_off_in_blank) + enc314_disable_fifo(enc); } static void enc314_stream_encoder_dp_unblank( diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c index a0741794db62..7980462e3abe 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c @@ -47,8 +47,8 @@ #include "dpcd_defs.h" #include "dce/dmub_outbox.h" #include "dc_link_dp.h" +#include "link.h" #include "inc/dc_link_dp.h" -#include "inc/link_dpcd.h" #include "dcn10/dcn10_hw_sequencer.h" #include "inc/link_enc_cfg.h" #include "dcn30/dcn30_vpg.h" @@ -348,7 +348,7 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); odm_combine_factor = get_odm_config(pipe_ctx, NULL); - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { *k1_div = PIXEL_RATE_DIV_BY_1; *k2_div = PIXEL_RATE_DIV_BY_1; } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index 31feb4b0edee..5b6c2d94ec71 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -66,9 +66,9 @@ static const struct hw_sequencer_funcs dcn314_funcs = { .prepare_bandwidth = dcn20_prepare_bandwidth, .optimize_bandwidth = dcn20_optimize_bandwidth, .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn31_set_drr, + .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn31_set_static_screen_control, + .set_static_screen_control = dcn10_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c index 41edbd64ea21..0086cafb0f7a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c @@ -228,7 +228,7 @@ static struct timing_generator_funcs dcn314_tg_funcs = { .set_drr = optc31_set_drr, .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, .set_vtotal_min_max = optc1_set_vtotal_min_max, - .set_static_screen_control = optc31_set_static_screen_control, + .set_static_screen_control = optc1_set_static_screen_control, .program_stereo = optc1_program_stereo, .is_stereo_left_eye = optc1_is_stereo_left_eye, .tg_init = optc3_tg_init, @@ -241,7 +241,6 @@ static struct timing_generator_funcs dcn314_tg_funcs = { .set_dsc_config = optc3_set_dsc_config, .get_dsc_status = optc2_get_dsc_status, .set_dwb_source = NULL, - .set_odm_combine = optc314_set_odm_combine, .get_optc_source = optc2_get_optc_source, .set_out_mux = optc3_set_out_mux, .set_drr_trigger_window = optc3_set_drr_trigger_window, diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c index b4d5076e124c..dc0b49506275 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c @@ -1776,7 +1776,7 @@ static bool dcn316_resource_construct( pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 600; dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; + dc->caps.i2c_speed_in_khz_hdcp = 5; /*1.5 w/a applied by default*/ dc->caps.max_cursor_size = 256; dc->caps.min_horizontal_blanking_period = 80; dc->caps.dmdata_alloc_size = 2048; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c index 076969d928af..501388014855 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c @@ -31,7 +31,6 @@ #include "dcn31/dcn31_dio_link_encoder.h" #include "dcn32_dio_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "link_enc_cfg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c index d19fc93dbc75..f01968f6d182 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c @@ -29,7 +29,7 @@ #include "dcn32_dio_stream_encoder.h" #include "reg_helper.h" #include "hw_shared.h" -#include "inc/link_dpcd.h" +#include "dc_link_dp.h" #include "dpcd_defs.h" #define DC_LOGGER \ @@ -421,6 +421,33 @@ static void enc32_set_dig_input_mode(struct stream_encoder *enc, unsigned int pi REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_OUTPUT_PIXEL_MODE, pix_per_container == 2 ? 0x1 : 0x0); } +static void enc32_reset_fifo(struct stream_encoder *enc, bool reset) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + uint32_t reset_val = reset ? 1 : 0; + uint32_t is_symclk_on; + + REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, reset_val); + REG_GET(DIG_FE_CNTL, DIG_SYMCLK_FE_ON, &is_symclk_on); + + if (is_symclk_on) + REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, reset_val, 10, 5000); + else + udelay(10); +} + +static void enc32_enable_fifo(struct stream_encoder *enc) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7); + + enc32_reset_fifo(enc, true); + enc32_reset_fifo(enc, false); + + REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 1); +} + static const struct stream_encoder_funcs dcn32_str_enc_funcs = { .dp_set_odm_combine = enc32_dp_set_odm_combine, @@ -466,6 +493,7 @@ static const struct stream_encoder_funcs dcn32_str_enc_funcs = { .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, .set_input_mode = enc32_set_dig_input_mode, + .enable_fifo = enc32_enable_fifo, }; void dcn32_dio_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c index 9501403a48a9..eb08ccc38e79 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c @@ -945,6 +945,35 @@ void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub) DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); } +void hubbub32_init(struct hubbub *hubbub) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + /* Enable clock gate*/ + if (hubbub->ctx->dc->debug.disable_clock_gate) { + /*done in hwseq*/ + /*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/ + + REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL, + DISPCLK_R_DCHUBBUB_GATE_DIS, 0, + DCFCLK_R_DCHUBBUB_GATE_DIS, 0); + } + /* + ignore the "df_pre_cstate_req" from the SDP port control. + only the DCN will determine when to connect the SDP port + */ + REG_UPDATE(DCHUBBUB_SDPIF_CFG0, + SDPIF_PORT_CONTROL, 1); + /*Set SDP's max outstanding request to 512 + must set the register back to 0 (max outstanding = 256) in zero frame buffer mode*/ + REG_UPDATE(DCHUBBUB_SDPIF_CFG1, + SDPIF_MAX_NUM_OUTSTANDING, 1); + /*must set the registers back to 256 in zero frame buffer mode*/ + REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND, + DCHUBBUB_ARB_MAX_REQ_OUTSTAND, 512, + DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 512); +} + static const struct hubbub_funcs hubbub32_funcs = { .update_dchub = hubbub2_update_dchub, .init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h index 786f9ce07f92..bdc146890fca 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h @@ -83,7 +83,12 @@ SR(DCN_VM_FAULT_ADDR_LSB),\ SR(DCN_VM_FAULT_CNTL),\ SR(DCN_VM_FAULT_STATUS),\ - SR(SDPIF_REQUEST_RATE_LIMIT) + SR(SDPIF_REQUEST_RATE_LIMIT),\ + SR(DCHUBBUB_CLOCK_CNTL),\ + SR(DCHUBBUB_SDPIF_CFG0),\ + SR(DCHUBBUB_SDPIF_CFG1),\ + SR(DCHUBBUB_MEM_PWR_MODE_CTRL) + #define HUBBUB_MASK_SH_LIST_DCN32(mask_sh)\ HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ @@ -96,6 +101,7 @@ HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MAX_REQ_OUTSTAND, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, mask_sh), \ @@ -161,7 +167,14 @@ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_TABLE_LEVEL, mask_sh), \ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh),\ - HUBBUB_SF(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, mask_sh) + HUBBUB_SF(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DISPCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DCFCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, mask_sh),\ + HUBBUB_SF(DCHUBBUB_SDPIF_CFG1, SDPIF_MAX_NUM_OUTSTANDING, mask_sh),\ + HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh) + + bool hubbub32_program_urgent_watermarks( struct hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c index ac1c6458dd55..fe0cd177744c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c @@ -155,7 +155,11 @@ void hubp32_cursor_set_attributes( else REG_UPDATE(DCHUBP_MALL_CONFIG, USE_MALL_FOR_CURSOR, false); } - +void hubp32_init(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + REG_WRITE(HUBPREQ_DEBUG_DB, 1 << 8); +} static struct hubp_funcs dcn32_hubp_funcs = { .hubp_enable_tripleBuffer = hubp2_enable_triplebuffer, .hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index b8767be1e4c5..3b44006e1a80 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -50,6 +50,7 @@ #include "dmub_subvp_state.h" #include "dce/dmub_hw_lock_mgr.h" #include "dcn32_resource.h" +#include "link.h" #include "dc_link_dp.h" #include "dmub/inc/dmub_subvp_state.h" @@ -188,7 +189,8 @@ static bool dcn32_check_no_memory_request_for_cab(struct dc *dc) /* First, check no-memory-request case */ for (i = 0; i < dc->current_state->stream_count; i++) { - if (dc->current_state->stream_status[i].plane_count) + if ((dc->current_state->stream_status[i].plane_count) && + (dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)) /* Fail eligibility on a visible stream */ break; } @@ -206,151 +208,31 @@ static bool dcn32_check_no_memory_request_for_cab(struct dc *dc) */ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) { - int i, j; - struct dc_stream_state *stream = NULL; - struct dc_plane_state *plane = NULL; - uint32_t cursor_size = 0; - uint32_t total_lines = 0; - uint32_t lines_per_way = 0; + int i; uint8_t num_ways = 0; - uint8_t bytes_per_pixel = 0; - uint8_t cursor_bpp = 0; - uint16_t mblk_width = 0; - uint16_t mblk_height = 0; - uint16_t mall_alloc_width_blk_aligned = 0; - uint16_t mall_alloc_height_blk_aligned = 0; - uint16_t num_mblks = 0; - uint32_t bytes_in_mall = 0; - uint32_t cache_lines_used = 0; - uint32_t cache_lines_per_plane = 0; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - /* If PSR is supported on an eDP panel that's connected, but that panel is - * not in PSR at the time of trying to enter MALL SS, we have to include it - * in the static screen CAB calculation - */ - if (!pipe->stream || !pipe->plane_state || - (pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED && - pipe->stream->link->psr_settings.psr_allow_active) || - pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4; - mblk_width = DCN3_2_MBLK_WIDTH; - mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE : DCN3_2_MBLK_HEIGHT_8BPE; - - /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) - - * FLOOR(vp_x_start, blk_width) - * - * mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c - */ - mall_alloc_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x + - pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) - - (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width); - - /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) - - * FLOOR(vp_y_start, blk_height) - * - * mall_alloc_height_blk_aligned_l/c = full_vp_height_blk_aligned_l/c - */ - mall_alloc_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y + - pipe->plane_res.scl_data.viewport.height + mblk_height - 1) / mblk_height * mblk_height) - - (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height); - - num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) * - ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height); - - /*For DCC: - * meta_num_mblk = CEILING(meta_pitch*full_vp_height*Bpe/256/mblk_bytes, 1) - */ - if (pipe->plane_state->dcc.enable) - num_mblks += (pipe->plane_state->dcc.meta_pitch * pipe->plane_res.scl_data.viewport.height * bytes_per_pixel + - (256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES); + uint32_t mall_ss_size_bytes = 0; - bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES; - - /* (cache lines used is total bytes / cache_line size. Add +2 for worst case alignment - * (MALL is 64-byte aligned) - */ - cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2; - cache_lines_used += cache_lines_per_plane; - } + mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes; + // TODO add additional logic for PSR active stream exclusion optimization + // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes; // Include cursor size for CAB allocation - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j]; - struct hubp *hubp = pipe->plane_res.hubp; - - if (pipe->stream && pipe->plane_state && hubp) - /* Find the cursor plane and use the exact size instead of - using the max for calculation */ - - if (hubp->curs_attr.width > 0) { - cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; - - switch (pipe->stream->cursor_attributes.color_format) { - case CURSOR_MODE_MONO: - cursor_size /= 2; - cursor_bpp = 4; - break; - case CURSOR_MODE_COLOR_1BIT_AND: - case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: - case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: - cursor_size *= 4; - cursor_bpp = 4; - break; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i]; - case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: - case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: - cursor_size *= 8; - cursor_bpp = 8; - break; - } + if (!pipe->stream || !pipe->plane_state) + continue; - if (pipe->stream->cursor_position.enable && !dc->debug.alloc_extra_way_for_cursor && - cursor_size > 16384) { - /* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1) - */ - cache_lines_used += (((cursor_size + DCN3_2_MALL_MBLK_SIZE_BYTES - 1) / - DCN3_2_MALL_MBLK_SIZE_BYTES) * DCN3_2_MALL_MBLK_SIZE_BYTES) / - dc->caps.cache_line_size + 2; - break; - } - } + mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false); } // Convert number of cache lines required to number of ways - total_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size; - lines_per_way = total_lines / dc->caps.cache_num_ways; - num_ways = cache_lines_used / lines_per_way; - - if (cache_lines_used % lines_per_way > 0) - num_ways++; - - for (i = 0; i < ctx->stream_count; i++) { - stream = ctx->streams[i]; - for (j = 0; j < ctx->stream_status[i].plane_count; j++) { - plane = ctx->stream_status[i].plane_states[j]; - - if (stream->cursor_position.enable && plane && - dc->debug.alloc_extra_way_for_cursor && - cursor_size > 16384) { - /* Cursor caching is not supported since it won't be on the same line. - * So we need an extra line to accommodate it. With large cursors and a single 4k monitor - * this case triggers corruption. If we're at the edge, then dont trigger display refresh - * from MALL. We only need to cache cursor if its greater that 64x64 at 4 bpp. - */ - num_ways++; - /* We only expect one cursor plane */ - break; - } - } - } if (dc->debug.force_mall_ss_num_ways > 0) { num_ways = dc->debug.force_mall_ss_num_ways; + } else { + num_ways = dcn32_helper_mall_bytes_to_ways(dc, mall_ss_size_bytes); } + return num_ways; } @@ -803,6 +685,25 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context) } } +static void dcn32_initialize_min_clocks(struct dc *dc) +{ + struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk; + + clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000; + clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000; + clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000; + clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000; + clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; + clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; + clocks->fclk_p_state_change_support = true; + clocks->p_state_change_support = true; + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + dc->current_state, + true); +} + void dcn32_init_hw(struct dc *dc) { struct abm **abms = dc->res_pool->multiple_abms; @@ -897,6 +798,8 @@ void dcn32_init_hw(struct dc *dc) if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + + dcn32_initialize_min_clocks(dc); } /* In headless boot cases, DIG may be turned @@ -1175,7 +1078,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); odm_combine_factor = get_odm_config(pipe_ctx, NULL); - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { *k1_div = PIXEL_RATE_DIV_BY_1; *k2_div = PIXEL_RATE_DIV_BY_1; } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { @@ -1239,7 +1142,7 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, params.link_settings.link_rate = link_settings->link_rate; - if (is_dp_128b_132b_signal(pipe_ctx)) { + if (link_is_dp_128b_132b_signal(pipe_ctx)) { /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( pipe_ctx->stream_res.hpo_dp_stream_enc, @@ -1266,7 +1169,7 @@ bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) if (!is_h_timing_divisible_by_2(pipe_ctx->stream)) return false; - if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) && + if (dc_is_dp_signal(pipe_ctx->stream->signal) && !link_is_dp_128b_132b_signal(pipe_ctx) && dc->debug.enable_dp_dig_pixel_rate_div_policy) return true; return false; @@ -1300,7 +1203,7 @@ static void apply_symclk_on_tx_off_wa(struct dc_link *link) pipe_ctx->clock_source->funcs->program_pix_clk( pipe_ctx->clock_source, &pipe_ctx->stream_res.pix_clk_params, - dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), + link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), &pipe_ctx->pll_settings); link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; break; @@ -1450,3 +1353,39 @@ void dcn32_update_dsc_pg(struct dc *dc, } } } + +void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) +{ + unsigned int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + /* If an active, non-phantom pipe is being transitioned into a phantom + * pipe, wait for the double buffer update to complete first before we do + * ANY phantom pipe programming. + */ + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM && + old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + old_pipe->stream_res.tg->funcs->wait_for_state( + old_pipe->stream_res.tg, + CRTC_STATE_VBLANK); + old_pipe->stream_res.tg->funcs->wait_for_state( + old_pipe->stream_res.tg, + CRTC_STATE_VACTIVE); + } + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; + + if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + // If old context or new context has phantom pipes, apply + // the phantom timings now. We can't change the phantom + // pipe configuration safely without driver acquiring + // the DMCUB lock first. + dc->hwss.apply_ctx_to_hw(dc, context); + break; + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h index 7de36529cf99..e9e9534f3668 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h @@ -102,4 +102,6 @@ void dcn32_update_dsc_pg(struct dc *dc, struct dc_state *context, bool safe_to_disable); +void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context); + #endif /* __DC_HWSS_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index dc4649458567..330d7cbc7398 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -106,6 +106,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .commit_subvp_config = dcn32_commit_subvp_config, + .enable_phantom_streams = dcn32_enable_phantom_streams, .subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock, .update_visual_confirm_color = dcn20_update_visual_confirm_color, .update_phantom_vp_position = dcn32_update_phantom_vp_position, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index e4dbc8353ea3..47dc96acdacb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -69,7 +69,7 @@ #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" -#include "dc_link_ddc.h" +#include "link.h" #include "dcn31/dcn31_panel_cntl.h" #include "dcn30/dcn30_dwb.h" @@ -726,6 +726,7 @@ static const struct dc_debug_options debug_defaults_drv = { .allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback" .alloc_extra_way_for_cursor = true, .min_prefetch_in_strobe_ns = 60000, // 60us + .disable_unbounded_requesting = false, }; static const struct dc_debug_options debug_defaults_diags = { @@ -1507,7 +1508,7 @@ static void dcn32_resource_destruct(struct dcn32_resource_pool *pool) dcn_dccg_destroy(&pool->base.dccg); if (pool->base.oem_device != NULL) - dal_ddc_service_destroy(&pool->base.oem_device); + link_destroy_ddc_service(&pool->base.oem_device); } @@ -2449,7 +2450,7 @@ static bool dcn32_resource_construct( ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; ddc_init_data.id.enum_id = 0; ddc_init_data.id.type = OBJECT_TYPE_GENERIC; - pool->base.oem_device = dal_ddc_service_create(&ddc_init_data); + pool->base.oem_device = link_create_ddc_service(&ddc_init_data); } else { pool->base.oem_device = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h index 13fbc574910b..b07d3b0e6a5c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h @@ -96,8 +96,17 @@ void dcn32_calculate_wm_and_dlg( int pipe_cnt, int vlevel); -uint32_t dcn32_helper_calculate_num_ways_for_subvp - (struct dc *dc, +uint32_t dcn32_helper_mall_bytes_to_ways( + struct dc *dc, + uint32_t total_size_in_mall_bytes); + +uint32_t dcn32_helper_calculate_mall_bytes_for_cursor( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool ignore_cursor_buf); + +uint32_t dcn32_helper_calculate_num_ways_for_subvp( + struct dc *dc, struct dc_state *context); void dcn32_merge_pipes_for_subvp(struct dc *dc, @@ -112,6 +121,7 @@ bool dcn32_subvp_in_use(struct dc *dc, bool dcn32_mpo_in_use(struct dc_state *context); bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context); +bool dcn32_is_center_timing(struct pipe_ctx *pipe); struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( struct dc_state *state, @@ -134,6 +144,8 @@ void dcn32_restore_mall_state(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config); +bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe); + /* definitions for run time init of reg offsets */ /* CLK SRC */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index 783935c4e664..0fc79d75ce76 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -33,13 +33,75 @@ static bool is_dual_plane(enum surface_pixel_format format) return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; } + +uint32_t dcn32_helper_mall_bytes_to_ways( + struct dc *dc, + uint32_t total_size_in_mall_bytes) +{ + uint32_t cache_lines_used, lines_per_way, total_cache_lines, num_ways; + + /* add 2 lines for worst case alignment */ + cache_lines_used = total_size_in_mall_bytes / dc->caps.cache_line_size + 2; + + total_cache_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size; + lines_per_way = total_cache_lines / dc->caps.cache_num_ways; + num_ways = cache_lines_used / lines_per_way; + if (cache_lines_used % lines_per_way > 0) + num_ways++; + + return num_ways; +} + +uint32_t dcn32_helper_calculate_mall_bytes_for_cursor( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool ignore_cursor_buf) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + uint32_t cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; + uint32_t cursor_bpp = 4; + uint32_t cursor_mall_size_bytes = 0; + + switch (pipe_ctx->stream->cursor_attributes.color_format) { + case CURSOR_MODE_MONO: + cursor_size /= 2; + cursor_bpp = 4; + break; + case CURSOR_MODE_COLOR_1BIT_AND: + case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: + case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: + cursor_size *= 4; + cursor_bpp = 4; + break; + + case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: + case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: + cursor_size *= 8; + cursor_bpp = 8; + break; + } + + /* only count if cursor is enabled, and if additional allocation needed outside of the + * DCN cursor buffer + */ + if (pipe_ctx->stream->cursor_position.enable && (ignore_cursor_buf || + cursor_size > 16384)) { + /* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1) + * Note: add 1 mblk in case of cursor misalignment + */ + cursor_mall_size_bytes = ((cursor_size + DCN3_2_MALL_MBLK_SIZE_BYTES - 1) / + DCN3_2_MALL_MBLK_SIZE_BYTES + 1) * DCN3_2_MALL_MBLK_SIZE_BYTES; + } + + return cursor_mall_size_bytes; +} + /** * ******************************************************************************************** * dcn32_helper_calculate_num_ways_for_subvp: Calculate number of ways needed for SubVP * - * This function first checks the bytes required per pixel on the SubVP pipe, then calculates - * the total number of pixels required in the SubVP MALL region. These are used to calculate - * the number of cache lines used (then number of ways required) for SubVP MCLK switching. + * Gets total allocation required for the phantom viewport calculated by DML in bytes and + * converts to number of cache ways. * * @param [in] dc: current dc state * @param [in] context: new dc state @@ -48,106 +110,19 @@ static bool is_dual_plane(enum surface_pixel_format format) * * ******************************************************************************************** */ -uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_state *context) +uint32_t dcn32_helper_calculate_num_ways_for_subvp( + struct dc *dc, + struct dc_state *context) { - uint32_t num_ways = 0; - uint32_t bytes_per_pixel = 0; - uint32_t cache_lines_used = 0; - uint32_t lines_per_way = 0; - uint32_t total_cache_lines = 0; - uint32_t bytes_in_mall = 0; - uint32_t num_mblks = 0; - uint32_t cache_lines_per_plane = 0; - uint32_t i = 0, j = 0; - uint16_t mblk_width = 0; - uint16_t mblk_height = 0; - uint32_t full_vp_width_blk_aligned = 0; - uint32_t full_vp_height_blk_aligned = 0; - uint32_t mall_alloc_width_blk_aligned = 0; - uint32_t mall_alloc_height_blk_aligned = 0; - uint16_t full_vp_height = 0; - bool subvp_in_use = false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - /* Find the phantom pipes. - * - For pipe split case we need to loop through the bottom and next ODM - * pipes or only half the viewport size is counted - */ - if (pipe->stream && pipe->plane_state && - pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - struct pipe_ctx *main_pipe = NULL; - - subvp_in_use = true; - /* Get full viewport height from main pipe (required for MBLK calculation) */ - for (j = 0; j < dc->res_pool->pipe_count; j++) { - main_pipe = &context->res_ctx.pipe_ctx[j]; - if (main_pipe->stream == pipe->stream->mall_stream_config.paired_stream) { - full_vp_height = main_pipe->plane_res.scl_data.viewport.height; - break; - } - } - - bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4; - mblk_width = DCN3_2_MBLK_WIDTH; - mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE : DCN3_2_MBLK_HEIGHT_8BPE; - - /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) - - * FLOOR(vp_x_start, blk_width) - */ - full_vp_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x + - pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) - - (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width); - - /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) - - * FLOOR(vp_y_start, blk_height) - */ - full_vp_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y + - full_vp_height + mblk_height - 1) / mblk_height * mblk_height) - - (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height); - - /* mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c */ - mall_alloc_width_blk_aligned = full_vp_width_blk_aligned; - - /* mall_alloc_height_blk_aligned_l/c = CEILING(sub_vp_height_l/c - 1, blk_height_l/c) + blk_height_l/c */ - mall_alloc_height_blk_aligned = (pipe->plane_res.scl_data.viewport.height - 1 + mblk_height - 1) / - mblk_height * mblk_height + mblk_height; - - /* full_mblk_width_ub_l/c = mall_alloc_width_blk_aligned_l/c; - * full_mblk_height_ub_l/c = mall_alloc_height_blk_aligned_l/c; - * num_mblk_l/c = (full_mblk_width_ub_l/c / mblk_width_l/c) * (full_mblk_height_ub_l/c / mblk_height_l/c); - * (Should be divisible, but round up if not) - */ - num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) * - ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height); - - /*For DCC: - * meta_num_mblk = CEILING(meta_pitch*full_vp_height*Bpe/256/mblk_bytes, 1) - */ - if (pipe->plane_state->dcc.enable) - num_mblks += (pipe->plane_state->dcc.meta_pitch * pipe->plane_res.scl_data.viewport.height * bytes_per_pixel + - (256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES); - - bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES; - // cache lines used is total bytes / cache_line size. Add +2 for worst case alignment - // (MALL is 64-byte aligned) - cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2; - - cache_lines_used += cache_lines_per_plane; + if (context->bw_ctx.bw.dcn.mall_subvp_size_bytes > 0) { + if (dc->debug.force_subvp_num_ways) { + return dc->debug.force_subvp_num_ways; + } else { + return dcn32_helper_mall_bytes_to_ways(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes); } + } else { + return 0; } - - total_cache_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size; - lines_per_way = total_cache_lines / dc->caps.cache_num_ways; - num_ways = cache_lines_used / lines_per_way; - if (cache_lines_used % lines_per_way > 0) - num_ways++; - - if (subvp_in_use && dc->debug.force_subvp_num_ways > 0) - num_ways = dc->debug.force_subvp_num_ways; - - return num_ways; } void dcn32_merge_pipes_for_subvp(struct dc *dc, @@ -255,6 +230,27 @@ bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context) return false; } +bool dcn32_is_center_timing(struct pipe_ctx *pipe) +{ + bool is_center_timing = false; + + if (pipe->stream) { + if (pipe->stream->timing.v_addressable != pipe->stream->dst.height || + pipe->stream->timing.v_addressable != pipe->stream->src.height) { + is_center_timing = true; + } + } + + if (pipe->plane_state) { + if (pipe->stream->timing.v_addressable != pipe->plane_state->dst_rect.height && + pipe->stream->timing.v_addressable != pipe->plane_state->src_rect.height) { + is_center_timing = true; + } + } + + return is_center_timing; +} + /** * ******************************************************************************************* * dcn32_determine_det_override: Determine DET allocation for each pipe @@ -357,6 +353,7 @@ void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, int i, pipe_cnt; struct resource_context *res_ctx = &context->res_ctx; struct pipe_ctx *pipe; + bool disable_unbounded_requesting = dc->debug.disable_z9_mpc || dc->debug.disable_unbounded_requesting; for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { @@ -373,7 +370,7 @@ void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, */ if (pipe_cnt == 1) { pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE; - if (pipe->plane_state && !dc->debug.disable_z9_mpc && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { + if (pipe->plane_state && !disable_unbounded_requesting && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { if (!is_dual_plane(pipe->plane_state->format)) { pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE; pipes[0].pipe.src.unbounded_req_mode = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c index fa9b6603cfd3..13be5f06d987 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c @@ -31,7 +31,6 @@ #include "dcn321_dio_link_encoder.h" #include "dcn31/dcn31_dio_link_encoder.h" #include "stream_encoder.h" -#include "i2caux_interface.h" #include "dc_bios_types.h" #include "gpio_service_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index d1f36df03c2e..260d71ca0205 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -73,7 +73,7 @@ #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" -#include "dc_link_ddc.h" +#include "link.h" #include "dcn31/dcn31_panel_cntl.h" #include "dcn30/dcn30_dwb.h" @@ -724,6 +724,7 @@ static const struct dc_debug_options debug_defaults_drv = { .allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback" .alloc_extra_way_for_cursor = true, .min_prefetch_in_strobe_ns = 60000, // 60us + .disable_unbounded_requesting = false, }; static const struct dc_debug_options debug_defaults_diags = { @@ -1492,7 +1493,7 @@ static void dcn321_resource_destruct(struct dcn321_resource_pool *pool) dcn_dccg_destroy(&pool->base.dccg); if (pool->base.oem_device != NULL) - dal_ddc_service_destroy(&pool->base.oem_device); + link_destroy_ddc_service(&pool->base.oem_device); } @@ -1990,7 +1991,7 @@ static bool dcn321_resource_construct( ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; ddc_init_data.id.enum_id = 0; ddc_init_data.id.type = OBJECT_TYPE_GENERIC; - pool->base.oem_device = dal_ddc_service_create(&ddc_init_data); + pool->base.oem_device = link_create_ddc_service(&ddc_init_data); } else { pool->base.oem_device = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index c26da3bb2892..d2b89c50be2a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -32,6 +32,7 @@ #include "dcn21/dcn21_resource.h" #include "clk_mgr/dcn21/rn_clk_mgr.h" +#include "link.h" #include "dcn20_fpu.h" #define DC_LOGGER_INIT(logger) @@ -938,7 +939,7 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) for (i = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) continue; - if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i])) + if (link_is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i])) return true; } return false; @@ -1302,7 +1303,7 @@ int dcn20_populate_dml_pipes_from_context( case SIGNAL_TYPE_DISPLAY_PORT_MST: case SIGNAL_TYPE_DISPLAY_PORT: pipes[pipe_cnt].dout.output_type = dm_dp; - if (is_dp_128b_132b_signal(&res_ctx->pipe_ctx[i])) + if (link_is_dp_128b_132b_signal(&res_ctx->pipe_ctx[i])) pipes[pipe_cnt].dout.output_type = dm_dp2p0; break; case SIGNAL_TYPE_EDP: diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index f94abd124021..7feb8759e475 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -31,6 +31,7 @@ // We need this includes for WATERMARKS_* defines #include "clk_mgr/dcn32/dcn32_smu13_driver_if.h" #include "dcn30/dcn30_resource.h" +#include "link.h" #define DC_LOGGER_INIT(logger) @@ -691,9 +692,11 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc, * to combine this with SubVP can cause issues with the scheduling). * - Not TMZ surface */ - if (pipe->plane_state && !pipe->top_pipe && + if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) && pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && !pipe->plane_state->address.tmz_surface && - vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { + (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0 || + (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 && + dcn32_allow_subvp_with_active_margin(pipe)))) { while (pipe) { num_pipes++; pipe = pipe->bottom_pipe; @@ -977,10 +980,12 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN) subvp_pipe = pipe; } - // Use ignore_msa_timing_param flag to identify as DRR - if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) { - // SUBVP + DRR case - schedulable = subvp_drr_schedulable(dc, context, &context->res_ctx.pipe_ctx[vblank_index]); + // Use ignore_msa_timing_param and VRR active, or Freesync flag to identify as DRR On + if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param && + (context->res_ctx.pipe_ctx[vblank_index].stream->allow_freesync || + context->res_ctx.pipe_ctx[vblank_index].stream->vrr_active_variable)) { + // SUBVP + DRR case -- only allowed if run through DRR validation path + schedulable = false; } else if (found) { main_timing = &subvp_pipe->stream->timing; phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing; @@ -1084,12 +1089,12 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, { struct vba_vars_st *vba = &context->bw_ctx.dml.vba; unsigned int dc_pipe_idx = 0; + int i = 0; bool found_supported_config = false; struct pipe_ctx *pipe = NULL; uint32_t non_subvp_pipes = 0; bool drr_pipe_found = false; uint32_t drr_pipe_index = 0; - uint32_t i = 0; dc_assert_fp_enabled(); @@ -1169,15 +1174,25 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, pipes[0].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, *pipe_cnt, 0); *vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt); + /* Check that vlevel requested supports pstate or not + * if not, select the lowest vlevel that supports it + */ + for (i = *vlevel; i < context->bw_ctx.dml.soc.num_states; i++) { + if (vba->DRAMClockChangeSupport[i][vba->maxMpcComb] != dm_dram_clock_change_unsupported) { + *vlevel = i; + break; + } + } + if (*vlevel < context->bw_ctx.dml.soc.num_states && vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported && subvp_validate_static_schedulability(dc, context, *vlevel)) { found_supported_config = true; - } else if (*vlevel < context->bw_ctx.dml.soc.num_states && - vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) { - /* Case where 1 SubVP is added, and DML reports MCLK unsupported. This handles - * the case for SubVP + DRR, where the DRR display does not support MCLK switch - * at it's native refresh rate / timing. + } else if (*vlevel < context->bw_ctx.dml.soc.num_states) { + /* Case where 1 SubVP is added, and DML reports MCLK unsupported or DRR is allowed. + * This handles the case for SubVP + DRR, where the DRR display does not support MCLK + * switch at it's native refresh rate / timing, or DRR is allowed for the non-subvp + * display. */ for (i = 0; i < dc->res_pool->pipe_count; i++) { pipe = &context->res_ctx.pipe_ctx[i]; @@ -1185,7 +1200,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, pipe->stream->mall_stream_config.type == SUBVP_NONE) { non_subvp_pipes++; // Use ignore_msa_timing_param flag to identify as DRR - if (pipe->stream->ignore_msa_timing_param) { + if (pipe->stream->ignore_msa_timing_param && pipe->stream->allow_freesync) { drr_pipe_found = true; drr_pipe_index = i; } @@ -1194,6 +1209,15 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, // If there is only 1 remaining non SubVP pipe that is DRR, check static // schedulability for SubVP + DRR. if (non_subvp_pipes == 1 && drr_pipe_found) { + /* find lowest vlevel that supports the config */ + for (i = *vlevel; i >= 0; i--) { + if (vba->ModeSupport[i][vba->maxMpcComb]) { + *vlevel = i; + } else { + break; + } + } + found_supported_config = subvp_drr_schedulable(dc, context, &context->res_ctx.pipe_ctx[drr_pipe_index]); } @@ -1242,7 +1266,7 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) for (i = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) continue; - if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i])) + if (link_is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i])) return true; } return false; @@ -1270,7 +1294,6 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, context->bw_ctx.bw.dcn.clk.p_state_change_support = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != dm_dram_clock_change_unsupported; - context->bw_ctx.bw.dcn.clk.num_ways = dcn32_helper_calculate_num_ways_for_subvp(dc, context); context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context); @@ -1294,6 +1317,10 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, unbounded_req_enabled = false; } + context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0; + context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0; + context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0; + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) continue; @@ -1325,6 +1352,29 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, else context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = 0; context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest; + + context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes = get_surface_size_in_mall(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); + + /* MALL Allocation Sizes */ + /* count from active, top pipes per plane only */ + if (context->res_ctx.pipe_ctx[i].stream && context->res_ctx.pipe_ctx[i].plane_state && + (context->res_ctx.pipe_ctx[i].top_pipe == NULL || + context->res_ctx.pipe_ctx[i].plane_state != context->res_ctx.pipe_ctx[i].top_pipe->plane_state) && + context->res_ctx.pipe_ctx[i].prev_odm_pipe == NULL) { + /* SS: all active surfaces stored in MALL */ + if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type != SUBVP_PHANTOM) { + context->bw_ctx.bw.dcn.mall_ss_size_bytes += context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes; + + if (context->res_ctx.pipe_ctx[i].stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED) { + /* SS PSR On: all active surfaces part of streams not supporting PSR stored in MALL */ + context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes += context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes; + } + } else if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { + /* SUBVP: phantom surfaces only stored in MALL */ + context->bw_ctx.bw.dcn.mall_subvp_size_bytes += context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes; + } + } + pipe_idx++; } /* If DCN isn't making memory requests we can allow pstate change and lower clocks */ @@ -1345,6 +1395,8 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz * 1000; + context->bw_ctx.bw.dcn.clk.num_ways = dcn32_helper_calculate_num_ways_for_subvp(dc, context); + context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes; for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -1645,6 +1697,7 @@ bool dcn32_internal_validate_bw(struct dc *dc, dcn20_release_dsc(&context->res_ctx, dc->res_pool, &pipe->stream_res.dsc); memset(&pipe->plane_res, 0, sizeof(pipe->plane_res)); memset(&pipe->stream_res, 0, sizeof(pipe->stream_res)); + memset(&pipe->link_res, 0, sizeof(pipe->link_res)); repopulate_pipes = true; } else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { struct pipe_ctx *top_pipe = pipe->top_pipe; @@ -1660,6 +1713,7 @@ bool dcn32_internal_validate_bw(struct dc *dc, pipe->stream = NULL; memset(&pipe->plane_res, 0, sizeof(pipe->plane_res)); memset(&pipe->stream_res, 0, sizeof(pipe->stream_res)); + memset(&pipe->link_res, 0, sizeof(pipe->link_res)); repopulate_pipes = true; } else ASSERT(0); /* Should never try to merge master pipe */ @@ -1834,7 +1888,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, bool subvp_in_use = dcn32_subvp_in_use(dc, context); unsigned int min_dram_speed_mts_margin; bool need_fclk_lat_as_dummy = false; - bool is_subvp_p_drr = true; + bool is_subvp_p_drr = false; dc_assert_fp_enabled(); @@ -1842,7 +1896,8 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, if (subvp_in_use) { /* Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK */ if (!pstate_en) { - context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp; + context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = dm_prefetch_support_fclk_and_stutter; pstate_en = true; is_subvp_p_drr = true; } @@ -1860,8 +1915,9 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false); + maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb; if (is_subvp_p_drr) { - context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp; } } @@ -2622,3 +2678,30 @@ void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes, pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0; } + +bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe) +{ + bool allow = false; + uint32_t refresh_rate = 0; + + /* Allow subvp on displays that have active margin for 2560x1440@60hz displays + * only for now. There must be no scaling as well. + * + * For now we only enable on 2560x1440@60hz displays to enable 4K60 + 1440p60 configs + * for p-state switching. + */ + if (pipe->stream && pipe->plane_state) { + refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 + + pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1) + / (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total); + if (pipe->stream->timing.v_addressable == 1440 && + pipe->stream->timing.h_addressable == 2560 && + refresh_rate >= 55 && refresh_rate <= 65 && + pipe->plane_state->src_rect.height == 1440 && + pipe->plane_state->src_rect.width == 2560 && + pipe->plane_state->dst_rect.height == 1440 && + pipe->plane_state->dst_rect.width == 2560) + allow = true; + } + return allow; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 4b8f5fa0f0ad..6c5ab5c26b38 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -387,6 +387,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman mode_lib->vba.NumberOfActiveSurfaces, mode_lib->vba.MALLAllocatedForDCNFinal, mode_lib->vba.UseMALLForStaticScreen, + mode_lib->vba.UsesMALLForPStateChange, mode_lib->vba.DCCEnable, mode_lib->vba.ViewportStationary, mode_lib->vba.ViewportXStartY, @@ -411,6 +412,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->BlockWidthC, v->BlockHeightY, v->BlockHeightC, + mode_lib->vba.DCCMetaPitchY, + mode_lib->vba.DCCMetaPitchC, /* Output */ v->SurfaceSizeInMALL, @@ -2626,6 +2629,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l mode_lib->vba.NumberOfActiveSurfaces, mode_lib->vba.MALLAllocatedForDCNFinal, mode_lib->vba.UseMALLForStaticScreen, + mode_lib->vba.UsesMALLForPStateChange, mode_lib->vba.DCCEnable, mode_lib->vba.ViewportStationary, mode_lib->vba.ViewportXStartY, @@ -2650,6 +2654,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l mode_lib->vba.MacroTileWidthC, mode_lib->vba.MacroTileHeightY, mode_lib->vba.MacroTileHeightC, + mode_lib->vba.DCCMetaPitchY, + mode_lib->vba.DCCMetaPitchC, /* Output */ mode_lib->vba.SurfaceSizeInMALL, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index 5af601cff1a0..0932f49cd819 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -1772,6 +1772,7 @@ void dml32_CalculateSurfaceSizeInMall( unsigned int NumberOfActiveSurfaces, unsigned int MALLAllocatedForDCN, enum dm_use_mall_for_static_screen_mode UseMALLForStaticScreen[], + enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[], bool DCCEnable[], bool ViewportStationary[], unsigned int ViewportXStartY[], @@ -1796,13 +1797,17 @@ void dml32_CalculateSurfaceSizeInMall( unsigned int ReadBlockWidthC[], unsigned int ReadBlockHeightY[], unsigned int ReadBlockHeightC[], + unsigned int DCCMetaPitchY[], + unsigned int DCCMetaPitchC[], /* Output */ unsigned int SurfaceSizeInMALL[], bool *ExceededMALLSize) { - unsigned int TotalSurfaceSizeInMALL = 0; unsigned int k; + unsigned int TotalSurfaceSizeInMALLForSS = 0; + unsigned int TotalSurfaceSizeInMALLForSubVP = 0; + unsigned int MALLAllocatedForDCNInBytes = MALLAllocatedForDCN * 1024 * 1024; for (k = 0; k < NumberOfActiveSurfaces; ++k) { if (ViewportStationary[k]) { @@ -1828,18 +1833,18 @@ void dml32_CalculateSurfaceSizeInMall( } if (DCCEnable[k] == true) { SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] + - dml_min(dml_ceil(SurfaceWidthY[k], 8 * Read256BytesBlockWidthY[k]), + (dml_min(dml_ceil(DCCMetaPitchY[k], 8 * Read256BytesBlockWidthY[k]), dml_floor(ViewportXStartY[k] + ViewportWidthY[k] + 8 * Read256BytesBlockWidthY[k] - 1, 8 * Read256BytesBlockWidthY[k]) - dml_floor(ViewportXStartY[k], 8 * Read256BytesBlockWidthY[k])) * dml_min(dml_ceil(SurfaceHeightY[k], 8 * Read256BytesBlockHeightY[k]), dml_floor(ViewportYStartY[k] + ViewportHeightY[k] + 8 * Read256BytesBlockHeightY[k] - 1, 8 * - Read256BytesBlockHeightY[k]) - dml_floor(ViewportYStartY[k], 8 - * Read256BytesBlockHeightY[k])) * BytesPerPixelY[k] / 256; + Read256BytesBlockHeightY[k]) - dml_floor(ViewportYStartY[k], 8 * + Read256BytesBlockHeightY[k])) * BytesPerPixelY[k] / 256) + (64 * 1024); if (Read256BytesBlockWidthC[k] > 0) { SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] + - dml_min(dml_ceil(SurfaceWidthC[k], 8 * + dml_min(dml_ceil(DCCMetaPitchC[k], 8 * Read256BytesBlockWidthC[k]), dml_floor(ViewportXStartC[k] + ViewportWidthC[k] + 8 * Read256BytesBlockWidthC[k] - 1, 8 * @@ -1872,16 +1877,16 @@ void dml32_CalculateSurfaceSizeInMall( } if (DCCEnable[k] == true) { SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] + - dml_ceil(dml_min(SurfaceWidthY[k], ViewportWidthY[k] + 8 * + (dml_ceil(dml_min(DCCMetaPitchY[k], ViewportWidthY[k] + 8 * Read256BytesBlockWidthY[k] - 1), 8 * Read256BytesBlockWidthY[k]) * dml_ceil(dml_min(SurfaceHeightY[k], ViewportHeightY[k] + 8 * Read256BytesBlockHeightY[k] - 1), 8 * - Read256BytesBlockHeightY[k]) * BytesPerPixelY[k] / 256; + Read256BytesBlockHeightY[k]) * BytesPerPixelY[k] / 256) + (64 * 1024); if (Read256BytesBlockWidthC[k] > 0) { SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] + - dml_ceil(dml_min(SurfaceWidthC[k], ViewportWidthC[k] + 8 * + dml_ceil(dml_min(DCCMetaPitchC[k], ViewportWidthC[k] + 8 * Read256BytesBlockWidthC[k] - 1), 8 * Read256BytesBlockWidthC[k]) * dml_ceil(dml_min(SurfaceHeightC[k], ViewportHeightC[k] + 8 * @@ -1894,10 +1899,14 @@ void dml32_CalculateSurfaceSizeInMall( } for (k = 0; k < NumberOfActiveSurfaces; ++k) { - if (UseMALLForStaticScreen[k] == dm_use_mall_static_screen_enable) - TotalSurfaceSizeInMALL = TotalSurfaceSizeInMALL + SurfaceSizeInMALL[k]; + /* SS and Subvp counted separate as they are never used at the same time */ + if (UsesMALLForPStateChange[k] == dm_use_mall_pstate_change_phantom_pipe) + TotalSurfaceSizeInMALLForSubVP = TotalSurfaceSizeInMALLForSubVP + SurfaceSizeInMALL[k]; + else if (UseMALLForStaticScreen[k] == dm_use_mall_static_screen_enable) + TotalSurfaceSizeInMALLForSS = TotalSurfaceSizeInMALLForSS + SurfaceSizeInMALL[k]; } - *ExceededMALLSize = (TotalSurfaceSizeInMALL > MALLAllocatedForDCN * 1024 * 1024); + *ExceededMALLSize = (TotalSurfaceSizeInMALLForSS > MALLAllocatedForDCNInBytes) || + (TotalSurfaceSizeInMALLForSubVP > MALLAllocatedForDCNInBytes); } // CalculateSurfaceSizeInMall void dml32_CalculateVMRowAndSwath( @@ -6245,7 +6254,7 @@ bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurface double PixelClock[], double VRatioY[], double VRatioC[], - enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[DC__NUM_DPP__MAX]) + enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[]) { int k; double SwathSizeAllSurfaces = 0; @@ -6257,12 +6266,12 @@ bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurface double SwathSizePerSurfaceC[DC__NUM_DPP__MAX]; bool NotEnoughDETSwathFillLatencyHiding = false; - /* calculate sum of single swath size for all pipes in bytes*/ + /* calculate sum of single swath size for all pipes in bytes */ for (k = 0; k < NumberOfActiveSurfaces; k++) { - SwathSizePerSurfaceY[k] += SwathHeightY[k] * SwathWidthY[k] * BytePerPixelInDETY[k] * NumOfDPP[k]; + SwathSizePerSurfaceY[k] = SwathHeightY[k] * SwathWidthY[k] * BytePerPixelInDETY[k] * NumOfDPP[k]; if (SwathHeightC[k] != 0) - SwathSizePerSurfaceC[k] += SwathHeightC[k] * SwathWidthC[k] * BytePerPixelInDETC[k] * NumOfDPP[k]; + SwathSizePerSurfaceC[k] = SwathHeightC[k] * SwathWidthC[k] * BytePerPixelInDETC[k] * NumOfDPP[k]; else SwathSizePerSurfaceC[k] = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h index 779c6805f599..d41c4d8b0c7a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h @@ -334,6 +334,7 @@ void dml32_CalculateSurfaceSizeInMall( unsigned int NumberOfActiveSurfaces, unsigned int MALLAllocatedForDCN, enum dm_use_mall_for_static_screen_mode UseMALLForStaticScreen[], + enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[], bool DCCEnable[], bool ViewportStationary[], unsigned int ViewportXStartY[], @@ -358,6 +359,8 @@ void dml32_CalculateSurfaceSizeInMall( unsigned int ReadBlockWidthC[], unsigned int ReadBlockHeightY[], unsigned int ReadBlockHeightC[], + unsigned int DCCMetaPitchY[], + unsigned int DCCMetaPitchC[], /* Output */ unsigned int SurfaceSizeInMALL[], @@ -1157,6 +1160,6 @@ bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurface double PixelClock[], double VRatioY[], double VRatioC[], - enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[DC__NUM_DPP__MAX]); + enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[]); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index f4b176599be7..0ea406145c1d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -136,7 +136,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, - .pct_ideal_sdp_bw_after_urgent = 100.0, + .pct_ideal_sdp_bw_after_urgent = 90.0, .pct_ideal_fabric_bw_after_urgent = 67.0, .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0, .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c index 8e6585dab20e..8cb28b7918db 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -202,6 +202,7 @@ dml_get_pipe_attr_func(vm_group_size_in_bytes, mode_lib->vba.vm_group_bytes); dml_get_pipe_attr_func(dpte_row_height_linear_l, mode_lib->vba.dpte_row_height_linear); dml_get_pipe_attr_func(pte_buffer_mode, mode_lib->vba.PTE_BUFFER_MODE); dml_get_pipe_attr_func(subviewport_lines_needed_in_mall, mode_lib->vba.SubViewportLinesNeededInMALL); +dml_get_pipe_attr_func(surface_size_in_mall, mode_lib->vba.SurfaceSizeInMALL) double get_total_immediate_flip_bytes( struct display_mode_lib *mode_lib, diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h index 81e53e67cd0b..876b9b517ea2 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -143,6 +143,7 @@ dml_get_pipe_attr_decl(vready_at_or_after_vsync); dml_get_pipe_attr_decl(min_dst_y_next_start); dml_get_pipe_attr_decl(vstartup_calculated); dml_get_pipe_attr_decl(subviewport_lines_needed_in_mall); +dml_get_pipe_attr_decl(surface_size_in_mall); double get_total_immediate_flip_bytes( struct display_mode_lib *mode_lib, diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c index 9b63c6c0cc84..e0bd0c722e00 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c @@ -138,7 +138,8 @@ static const struct ddc_sh_mask ddc_shift[] = { DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), - DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6), + DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT) }; static const struct ddc_sh_mask ddc_mask[] = { @@ -147,7 +148,8 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 3), DDC_MASK_SH_LIST_DCN2(_MASK, 4), DDC_MASK_SH_LIST_DCN2(_MASK, 5), - DDC_MASK_SH_LIST_DCN2(_MASK, 6) + DDC_MASK_SH_LIST_DCN2(_MASK, 6), + DDC_MASK_SH_LIST_DCN2_VGA(_MASK) }; #include "../generic_regs.h" diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c index 687d4f128480..36a5736c58c9 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c @@ -145,7 +145,8 @@ static const struct ddc_sh_mask ddc_shift[] = { DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), - DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6), + DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT) }; static const struct ddc_sh_mask ddc_mask[] = { @@ -154,7 +155,8 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 3), DDC_MASK_SH_LIST_DCN2(_MASK, 4), DDC_MASK_SH_LIST_DCN2(_MASK, 5), - DDC_MASK_SH_LIST_DCN2(_MASK, 6) + DDC_MASK_SH_LIST_DCN2(_MASK, 6), + DDC_MASK_SH_LIST_DCN2_VGA(_MASK) }; #include "../generic_regs.h" diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c index 9fd8b269dd79..985f10b39750 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c @@ -149,7 +149,8 @@ static const struct ddc_sh_mask ddc_shift[] = { DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), - DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6), + DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT) }; static const struct ddc_sh_mask ddc_mask[] = { @@ -158,7 +159,8 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 3), DDC_MASK_SH_LIST_DCN2(_MASK, 4), DDC_MASK_SH_LIST_DCN2(_MASK, 5), - DDC_MASK_SH_LIST_DCN2(_MASK, 6) + DDC_MASK_SH_LIST_DCN2(_MASK, 6), + DDC_MASK_SH_LIST_DCN2_VGA(_MASK) }; #include "../generic_regs.h" diff --git a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h index 308a543178a5..59884ef651b3 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h @@ -113,6 +113,13 @@ (PHY_AUX_CNTL__AUX## cd ##_PAD_RXSEL## mask_sh),\ (DC_GPIO_AUX_CTRL_5__DDC_PAD## cd ##_I2CMODE## mask_sh)} +#define DDC_MASK_SH_LIST_DCN2_VGA(mask_sh) \ + {DDC_MASK_SH_LIST_COMMON(mask_sh),\ + 0,\ + 0,\ + 0,\ + 0} + struct ddc_registers { struct gpio_registers gpio; uint32_t ddc_setup; diff --git a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c index 4233955e3c47..906a43e85f6d 100644 --- a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c +++ b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c @@ -28,12 +28,11 @@ #include "dm_services.h" #include "dm_helpers.h" #include "include/hdcp_types.h" -#include "include/i2caux_interface.h" #include "include/signal_types.h" #include "core_types.h" -#include "dc_link_ddc.h" +#include "link.h" #include "link_hwss.h" -#include "inc/link_dpcd.h" +#include "link/link_dpcd.h" #define DC_LOGGER \ link->ctx->logger diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 525f8f0b8732..bebfcf8737b3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -450,10 +450,11 @@ struct pipe_ctx { struct _vcs_dpi_display_e2e_pipe_params_st dml_input; int det_buffer_size_kb; bool unbounded_req; + unsigned int surface_size_in_mall_bytes; - union pipe_update_flags update_flags; struct dwbc *dwbc; struct mcif_wb *mcif_wb; + union pipe_update_flags update_flags; }; /* Data used for dynamic link encoder assignment. @@ -507,6 +508,9 @@ struct dcn_bw_output { struct dcn_watermark_set watermarks; struct dcn_bw_writeback bw_writeback; int compbuf_size_kb; + unsigned int mall_ss_size_bytes; + unsigned int mall_ss_psr_active_size_bytes; + unsigned int mall_subvp_size_bytes; unsigned int legacy_svp_drr_stream_index; bool legacy_svp_drr_stream_index_valid; }; @@ -547,15 +551,6 @@ struct dc_state { struct resource_context res_ctx; /** - * @bw_ctx: The output from bandwidth and watermark calculations and the DML - * - * Each context must have its own instance of VBA, and in order to - * initialize and obtain IP and SOC, the base DML instance from DC is - * initially copied into every context. - */ - struct bw_context bw_ctx; - - /** * @pp_display_cfg: PowerPlay clocks and settings * Note: this is a big struct, do *not* put on stack! */ @@ -570,6 +565,15 @@ struct dc_state { struct clk_mgr *clk_mgr; /** + * @bw_ctx: The output from bandwidth and watermark calculations and the DML + * + * Each context must have its own instance of VBA, and in order to + * initialize and obtain IP and SOC, the base DML instance from DC is + * initially copied into every context. + */ + struct bw_context bw_ctx; + + /** * @refcount: refcount reference * * Notice that dc_state is used around the code to capture the current diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h deleted file mode 100644 index 95fb61d62778..000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2012-15 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: AMD - * - */ - -#ifndef __DAL_DDC_SERVICE_H__ -#define __DAL_DDC_SERVICE_H__ - -#include "include/ddc_service_types.h" -#include "include/i2caux_interface.h" - -#define EDID_SEGMENT_SIZE 256 - -/* Address range from 0x00 to 0x1F.*/ -#define DP_ADAPTOR_TYPE2_SIZE 0x20 -#define DP_ADAPTOR_TYPE2_REG_ID 0x10 -#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D -/* Identifies adaptor as Dual-mode adaptor */ -#define DP_ADAPTOR_TYPE2_ID 0xA0 -/* MHz*/ -#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600 -/* MHz*/ -#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25 -/* kHZ*/ -#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 -/* kHZ*/ -#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 - -#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW - -struct ddc_service; -struct graphics_object_id; -enum ddc_result; -struct av_sync_data; -struct dp_receiver_id_info; - -struct i2c_payloads; -struct aux_payloads; -enum aux_return_code_type; - -void dal_ddc_i2c_payloads_add( - struct i2c_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write); - -struct ddc_service_init_data { - struct graphics_object_id id; - struct dc_context *ctx; - struct dc_link *link; - bool is_dpia_link; -}; - -struct ddc_service *dal_ddc_service_create( - struct ddc_service_init_data *ddc_init_data); - -void dal_ddc_service_destroy(struct ddc_service **ddc); - -enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc); - -void dal_ddc_service_set_transaction_type( - struct ddc_service *ddc, - enum ddc_transaction_type type); - -bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc); - -void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( - struct ddc_service *ddc, - struct display_sink_capability *sink_cap); - -bool dal_ddc_service_query_ddc_data( - struct ddc_service *ddc, - uint32_t address, - uint8_t *write_buf, - uint32_t write_size, - uint8_t *read_buf, - uint32_t read_size); - -bool dal_ddc_submit_aux_command(struct ddc_service *ddc, - struct aux_payload *payload); - -int dc_link_aux_transfer_raw(struct ddc_service *ddc, - struct aux_payload *payload, - enum aux_return_code_type *operation_result); - -bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, - struct aux_payload *payload); - -bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc, - uint32_t timeout); - -void dal_ddc_service_write_scdc_data( - struct ddc_service *ddc_service, - uint32_t pix_clk, - bool lte_340_scramble); - -void dal_ddc_service_read_scdc_data( - struct ddc_service *ddc_service); - -void ddc_service_set_dongle_type(struct ddc_service *ddc, - enum display_dongle_type dongle_type); - -void dal_ddc_service_set_ddc_pin( - struct ddc_service *ddc_service, - struct ddc *ddc); - -struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service); - -uint32_t get_defer_delay(struct ddc_service *ddc); - -#endif /* __DAL_DDC_SERVICE_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index e8d8c5cb1309..52e1aad1fce8 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -28,10 +28,7 @@ #define LINK_TRAINING_ATTEMPTS 4 #define LINK_TRAINING_RETRY_DELAY 50 /* ms */ -#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/ -#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/ #define MAX_MTP_SLOT_COUNT 64 -#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 #define TRAINING_AUX_RD_INTERVAL 100 //us #define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX. @@ -40,11 +37,6 @@ struct dc_stream_state; struct dc_link_settings; enum { - LINK_TRAINING_MAX_RETRY_COUNT = 5, - /* to avoid infinite loop where-in the receiver - * switches between different VS - */ - LINK_TRAINING_MAX_CR_RETRY = 100, /* * Some receivers fail to train on first try and are good * on subsequent tries. 2 retries should be plenty. If we @@ -55,7 +47,6 @@ enum { PEAK_FACTOR_X1000 = 1006, }; -struct dc_link_settings dp_get_max_link_cap(struct dc_link *link); bool dp_verify_link_cap_with_retries( struct dc_link *link, @@ -66,35 +57,11 @@ bool dp_validate_mode_timing( struct dc_link *link, const struct dc_crtc_timing *timing); -bool decide_edp_link_settings(struct dc_link *link, - struct dc_link_settings *link_setting, - uint32_t req_bw); - -bool decide_link_settings( - struct dc_stream_state *stream, - struct dc_link_settings *link_setting); - -bool perform_link_training_with_retries( - const struct dc_link_settings *link_setting, - bool skip_video_pattern, - int attempts, - struct pipe_ctx *pipe_ctx, - enum signal_type signal, - bool do_fallback); - -bool hpd_rx_irq_check_link_loss_status( +bool hpd_rx_irq_check_link_loss_status(struct dc_link *link, + union hpd_irq_data *hpd_irq_dpcd_data); +enum dc_status read_hpd_rx_irq_data( struct dc_link *link, - union hpd_irq_data *hpd_irq_dpcd_data); - -bool is_mst_supported(struct dc_link *link); - -bool detect_dp_sink_caps(struct dc_link *link); - -void detect_edp_sink_caps(struct dc_link *link); - -bool is_dp_active_dongle(const struct dc_link *link); - -bool is_dp_branch_device(const struct dc_link *link); + union hpd_irq_data *irq_data); bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing); @@ -103,69 +70,8 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable); enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); -bool dp_overwrite_extended_receiver_cap(struct dc_link *link); - -void dpcd_set_source_specific_data(struct dc_link *link); - void dpcd_write_cable_id_to_dprx(struct dc_link *link); -/* Write DPCD link configuration data. */ -enum dc_status dpcd_set_link_settings( - struct dc_link *link, - const struct link_training_settings *lt_settings); -/* Write DPCD drive settings. */ -enum dc_status dpcd_set_lane_settings( - struct dc_link *link, - const struct link_training_settings *link_training_setting, - uint32_t offset); -/* Read training status and adjustment requests from DPCD. */ -enum dc_status dp_get_lane_status_and_lane_adjust( - struct dc_link *link, - const struct link_training_settings *link_training_setting, - union lane_status ln_status[LANE_COUNT_DP_MAX], - union lane_align_status_updated *ln_align, - union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], - uint32_t offset); - -void dp_wait_for_training_aux_rd_interval( - struct dc_link *link, - uint32_t wait_in_micro_secs); - -bool dp_is_cr_done(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status); - -enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status); - -bool dp_is_ch_eq_done(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status); -bool dp_is_symbol_locked(enum dc_lane_count ln_count, - union lane_status *dpcd_lane_status); -bool dp_is_interlane_aligned(union lane_align_status_updated align_status); - -bool dp_is_max_vs_reached( - const struct link_training_settings *lt_settings); -void dp_hw_to_dpcd_lane_settings( - const struct link_training_settings *lt_settings, - const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], - union dpcd_training_lane dpcd_lane_settings[]); -void dp_decide_lane_settings( - const struct link_training_settings *lt_settings, - const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], - struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], - union dpcd_training_lane dpcd_lane_settings[]); - -uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval); - -enum dpcd_training_patterns - dc_dp_training_pattern_to_dpcd_training_pattern( - struct dc_link *link, - enum dc_dp_training_pattern pattern); - -uint8_t dc_dp_initialize_scrambling_data_symbols( - struct dc_link *link, - enum dc_dp_training_pattern pattern); - enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready); void dp_set_fec_enable(struct dc_link *link, bool enable); bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); @@ -180,35 +86,12 @@ void dp_decide_training_settings( const struct dc_link_settings *link_setting, struct link_training_settings *lt_settings); -/* Convert PHY repeater count read from DPCD uint8_t. */ -uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count); - -/* Check DPCD training status registers to detect link loss. */ -enum link_training_result dp_check_link_loss_status( - struct dc_link *link, - const struct link_training_settings *link_training_setting); - -enum dc_status dpcd_configure_lttpr_mode( - struct dc_link *link, - struct link_training_settings *lt_settings); - -enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings); -enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link); -bool dp_is_lttpr_present(struct dc_link *link); -enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting); -void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override); -enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link); -enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link); bool dpcd_write_128b_132b_sst_payload_allocation_table( const struct dc_stream_state *stream, struct dc_link *link, struct link_mst_stream_allocation_table *proposed_table, bool allocate); -enum dc_status dpcd_configure_channel_coding( - struct dc_link *link, - struct link_training_settings *lt_settings); - bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link); struct fixed31_32 calculate_sst_avg_time_slots_per_mtp( @@ -220,48 +103,15 @@ void enable_dp_hpo_output(struct dc_link *link, void disable_dp_hpo_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); - void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable); -bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx); void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd); -void dp_receiver_power_ctrl(struct dc_link *link, bool on); void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode); -void dp_enable_link_phy( - struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - const struct dc_link_settings *link_settings); void edp_add_delay_for_T9(struct dc_link *link); bool edp_receiver_ready_T9(struct dc_link *link); bool edp_receiver_ready_T7(struct dc_link *link); -void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res, - enum signal_type signal); - -void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res, - enum signal_type signal); - -bool dp_set_hw_training_pattern( - struct dc_link *link, - const struct link_resource *link_res, - enum dc_dp_training_pattern pattern, - uint32_t offset); - -void dp_set_hw_lane_settings( - struct dc_link *link, - const struct link_resource *link_res, - const struct link_training_settings *link_settings, - uint32_t offset); - -void dp_set_hw_test_pattern( - struct dc_link *link, - const struct link_resource *link_res, - enum dp_test_pattern test_pattern, - uint8_t *custom_pattern, - uint32_t custom_pattern_size); - void dp_retrain_link_dp_test(struct dc_link *link, struct dc_link_settings *link_setting, bool skip_video_pattern); + #endif /* __DC_LINK_DP_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h deleted file mode 100644 index 39c1d1d07357..000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h +++ /dev/null @@ -1,105 +0,0 @@ -/* 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: AMD - * - */ - -#ifndef __DC_LINK_DPIA_H__ -#define __DC_LINK_DPIA_H__ - -/* This module implements functionality for training DPIA links. */ - -struct dc_link; -struct dc_link_settings; - -/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */ -#define DPIA_CLK_SYNC_DELAY 16000 - -/* Extend interval between training status checks for manual testing. */ -#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000 - -/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */ -/* DPCD DP Tunneling over USB4 */ -#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d -#define DP_IN_ADAPTER_INFO 0xe000e -#define DP_USB4_DRIVER_ID 0xe000f -#define DP_USB4_ROUTER_TOPOLOGY_ID 0xe001b - -/* SET_CONFIG message types sent by driver. */ -enum dpia_set_config_type { - DPIA_SET_CFG_SET_LINK = 0x01, - DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05, - DPIA_SET_CFG_SET_TRAINING = 0x18, - DPIA_SET_CFG_SET_VSPE = 0x19 -}; - -/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */ -enum dpia_set_config_ts { - DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */ - DPIA_TS_TPS1 = 0x01, - DPIA_TS_TPS2 = 0x02, - DPIA_TS_TPS3 = 0x03, - DPIA_TS_TPS4 = 0x07, - DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */ -}; - -/* SET_CONFIG message data associated with messages sent by driver. */ -union dpia_set_config_data { - struct { - uint8_t mode : 1; - uint8_t reserved : 7; - } set_link; - struct { - uint8_t stage; - } set_training; - struct { - uint8_t swing : 2; - uint8_t max_swing_reached : 1; - uint8_t pre_emph : 2; - uint8_t max_pre_emph_reached : 1; - uint8_t reserved : 2; - } set_vspe; - uint8_t raw; -}; - -/* Read tunneling device capability from DPCD and update link capability - * accordingly. - */ -enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link); - -/* Query hot plug status of USB4 DP tunnel. - * Returns true if HPD high. - */ -bool dc_link_dpia_query_hpd_status(struct dc_link *link); - -/* Train DP tunneling link for USB4 DPIA display endpoint. - * DPIA equivalent of dc_link_dp_perfrorm_link_training. - * Aborts link training upon detection of sink unplug. - */ -enum link_training_result dc_link_dpia_perform_link_training( - struct dc_link *link, - const struct link_resource *link_res, - const struct dc_link_settings *link_setting, - bool skip_video_pattern); - -#endif /* __DC_LINK_DPIA_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h index 2ae630bf2aee..7254182b7c72 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h @@ -27,7 +27,6 @@ #define __DAL_AUX_ENGINE_H__ #include "dc_ddc_types.h" -#include "include/i2caux_interface.h" enum aux_return_code_type; @@ -81,7 +80,12 @@ enum i2c_default_speed { I2CAUX_DEFAULT_I2C_SW_SPEED = 50 }; -union aux_config; +union aux_config { + struct { + uint32_t ALLOW_AUX_WHEN_HPD_LOW:1; + } bits; + uint32_t raw; +}; struct aux_engine { uint32_t inst; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index 5b0265c0df61..beb26dc8a07f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -187,6 +187,7 @@ struct hubbub_funcs { void (*init_crb)(struct hubbub *hubbub); void (*force_usr_retraining_allow)(struct hubbub *hubbub, bool allow); void (*set_request_limit)(struct hubbub *hubbub, int memory_channel_count, int words_per_channel); + void (*dchubbub_init)(struct hubbub *hubbub); }; struct hubbub { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index c43523f9ff6d..88ac723d10aa 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -266,6 +266,7 @@ struct hw_sequencer_funcs { void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe); void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); + void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context); void (*subvp_pipe_control_lock)(struct dc *dc, struct dc_state *context, bool lock, diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h new file mode 100644 index 000000000000..3945522fb798 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/link.h @@ -0,0 +1,92 @@ +/* + * Copyright 2022 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: AMD + * + */ + +#ifndef __DC_LINK_H__ +#define __DC_LINK_H__ + +/* FILE POLICY AND INTENDED USAGE: + * + * This header declares link functions exposed to dc. All functions must have + * "link_" as prefix. For example link_run_my_function. This header is strictly + * private in dc and should never be included in other header files. dc + * components should include this header in their .c files in order to access + * functions in link folder. This file should never include any header files in + * link folder. If there is a need to expose a function declared in one of + * header files in side link folder, you need to move the function declaration + * into this file and prefix it with "link_". + */ +#include "core_types.h" +#include "dc_link.h" + +struct gpio *link_get_hpd_gpio(struct dc_bios *dcb, + struct graphics_object_id link_id, + struct gpio_service *gpio_service); + +struct ddc_service_init_data { + struct graphics_object_id id; + struct dc_context *ctx; + struct dc_link *link; + bool is_dpia_link; +}; + +struct ddc_service *link_create_ddc_service( + struct ddc_service_init_data *ddc_init_data); + +void link_destroy_ddc_service(struct ddc_service **ddc); + +bool link_is_in_aux_transaction_mode(struct ddc_service *ddc); + +bool link_query_ddc_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *write_buf, + uint32_t write_size, + uint8_t *read_buf, + uint32_t read_size); + + +/* Attempt to submit an aux payload, retrying on timeouts, defers, and busy + * states as outlined in the DP spec. Returns true if the request was + * successful. + * + * NOTE: The function requires explicit mutex on DM side in order to prevent + * potential race condition. DC components should call the dpcd read/write + * function in dm_helpers in order to access dpcd safely + */ +bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc, + struct aux_payload *payload); + +uint32_t link_get_aux_defer_delay(struct ddc_service *ddc); + +bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx); + +enum dp_link_encoding link_dp_get_encoding_format( + const struct dc_link_settings *link_settings); + +bool link_decide_link_settings( + struct dc_stream_state *stream, + struct dc_link_settings *link_setting); + +#endif /* __DC_LINK_HPD_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 5040836f404d..4ab029e3326d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -236,4 +236,13 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm( struct pipe_ctx *pri_pipe, struct pipe_ctx *sec_pipe, bool odm); + +/* A test harness interface that modifies dp encoder resources in the given dc + * state and bypasses the need to revalidate. The interface assumes that the + * test harness interface is called with pre-validated link config stored in the + * pipe_ctx and updates dp encoder resources according to the link config. + */ +enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc, + struct dc_state *context, + struct pipe_ctx *pipe_ctx); #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c index 5f4f6dd79511..27dc8c9955f4 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c @@ -136,11 +136,6 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { .ack = NULL }; -static const struct irq_source_info_funcs dmub_outbox_irq_info_funcs = { - .set = NULL, - .ack = NULL -}; - #undef BASE_INNER #define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile index 054c2a727eb2..4dee0e6248b1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/Makefile +++ b/drivers/gpu/drm/amd/display/dc/link/Makefile @@ -23,7 +23,11 @@ # It abstracts the control and status of back end pipe such as DIO, HPO, DPIA, # PHY, HPD, DDC and etc). -LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o +LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o \ +link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o link_dp_training.o \ +link_dp_training_8b_10b.o link_dp_training_128b_132b.o link_dp_training_dpia.o \ +link_dp_training_auxless.o link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o \ +link_dp_capability.o AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK)) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/link/link_ddc.c index ce8d6a54ca54..5269125bc2a4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_ddc.c @@ -23,20 +23,20 @@ * */ -#include "dm_services.h" -#include "dm_helpers.h" -#include "gpio_service_interface.h" -#include "include/ddc_service_types.h" -#include "include/grph_object_id.h" -#include "include/dpcd_defs.h" -#include "include/logger_interface.h" -#include "include/vector.h" -#include "core_types.h" -#include "dc_link_ddc.h" +/* FILE POLICY AND INTENDED USAGE: + * + * This file implements generic display communication protocols such as i2c, aux + * and scdc. The file should not contain any specific applications of these + * protocols such as display capability query, detection, or handshaking such as + * link training. + */ +#include "link_ddc.h" +#include "vector.h" #include "dce/dce_aux.h" -#include "dmub/inc/dmub_cmd.h" +#include "dal_asic_id.h" #include "link_dpcd.h" -#include "include/dal_asic_id.h" +#include "dm_helpers.h" +#include "atomfirmware.h" #define DC_LOGGER_INIT(logger) @@ -45,87 +45,6 @@ static const uint8_t DP_VGA_DONGLE_BRANCH_DEV_NAME[] = "DpVga"; static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa"; static const uint8_t DP_DVI_CONVERTER_ID_5[] = "3393N2"; -#define AUX_POWER_UP_WA_DELAY 500 -#define I2C_OVER_AUX_DEFER_WA_DELAY 70 -#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40 -#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1 - -/* CV smart dongle slave address for retrieving supported HDTV modes*/ -#define CV_SMART_DONGLE_ADDRESS 0x20 -/* DVI-HDMI dongle slave address for retrieving dongle signature*/ -#define DVI_HDMI_DONGLE_ADDRESS 0x68 -struct dvi_hdmi_dongle_signature_data { - int8_t vendor[3];/* "AMD" */ - uint8_t version[2]; - uint8_t size; - int8_t id[11];/* "6140063500G"*/ -}; -/* DP-HDMI dongle slave address for retrieving dongle signature*/ -#define DP_HDMI_DONGLE_ADDRESS 0x40 -static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR"; -#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04 - -struct dp_hdmi_dongle_signature_data { - int8_t id[15];/* "DP-HDMI ADAPTOR"*/ - uint8_t eot;/* end of transmition '\x4' */ -}; - -/* SCDC Address defines (HDMI 2.0)*/ -#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3 -#define HDMI_SCDC_ADDRESS 0x54 -#define HDMI_SCDC_SINK_VERSION 0x01 -#define HDMI_SCDC_SOURCE_VERSION 0x02 -#define HDMI_SCDC_UPDATE_0 0x10 -#define HDMI_SCDC_TMDS_CONFIG 0x20 -#define HDMI_SCDC_SCRAMBLER_STATUS 0x21 -#define HDMI_SCDC_CONFIG_0 0x30 -#define HDMI_SCDC_STATUS_FLAGS 0x40 -#define HDMI_SCDC_ERR_DETECT 0x50 -#define HDMI_SCDC_TEST_CONFIG 0xC0 -#define HDMI_SCDC_DEVICE_ID 0xD3 - -union hdmi_scdc_update_read_data { - uint8_t byte[2]; - struct { - uint8_t STATUS_UPDATE:1; - uint8_t CED_UPDATE:1; - uint8_t RR_TEST:1; - uint8_t RESERVED:5; - uint8_t RESERVED2:8; - } fields; -}; - -union hdmi_scdc_status_flags_data { - uint8_t byte; - struct { - uint8_t CLOCK_DETECTED:1; - uint8_t CH0_LOCKED:1; - uint8_t CH1_LOCKED:1; - uint8_t CH2_LOCKED:1; - uint8_t RESERVED:4; - } fields; -}; - -union hdmi_scdc_ced_data { - uint8_t byte[7]; - struct { - uint8_t CH0_8LOW:8; - uint8_t CH0_7HIGH:7; - uint8_t CH0_VALID:1; - uint8_t CH1_8LOW:8; - uint8_t CH1_7HIGH:7; - uint8_t CH1_VALID:1; - uint8_t CH2_8LOW:8; - uint8_t CH2_7HIGH:7; - uint8_t CH2_VALID:1; - uint8_t CHECKSUM:8; - uint8_t RESERVED:8; - uint8_t RESERVED2:8; - uint8_t RESERVED3:8; - uint8_t RESERVED4:4; - } fields; -}; - struct i2c_payloads { struct vector payloads; }; @@ -158,7 +77,7 @@ static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p) #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) -void dal_ddc_i2c_payloads_add( +static void i2c_payloads_add( struct i2c_payloads *payloads, uint32_t address, uint32_t len, @@ -226,7 +145,7 @@ static void ddc_service_construct( ddc_service->wa.raw = 0; } -struct ddc_service *dal_ddc_service_create( +struct ddc_service *link_create_ddc_service( struct ddc_service_init_data *init_data) { struct ddc_service *ddc_service; @@ -246,7 +165,7 @@ static void ddc_service_destruct(struct ddc_service *ddc) dal_gpio_destroy_ddc(&ddc->ddc_pin); } -void dal_ddc_service_destroy(struct ddc_service **ddc) +void link_destroy_ddc_service(struct ddc_service **ddc) { if (!ddc || !*ddc) { BREAK_TO_DEBUGGER(); @@ -257,19 +176,14 @@ void dal_ddc_service_destroy(struct ddc_service **ddc) *ddc = NULL; } -enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc) -{ - return DDC_SERVICE_TYPE_CONNECTOR; -} - -void dal_ddc_service_set_transaction_type( +void set_ddc_transaction_type( struct ddc_service *ddc, enum ddc_transaction_type type) { ddc->transaction_type = type; } -bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc) +bool link_is_in_aux_transaction_mode(struct ddc_service *ddc) { switch (ddc->transaction_type) { case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: @@ -282,7 +196,7 @@ bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc) return false; } -void ddc_service_set_dongle_type(struct ddc_service *ddc, +void set_dongle_type(struct ddc_service *ddc, enum display_dongle_type dongle_type) { ddc->dongle_type = dongle_type; @@ -324,7 +238,7 @@ static uint32_t defer_delay_converter_wa( #define DP_TRANSLATOR_DELAY 5 -uint32_t get_defer_delay(struct ddc_service *ddc) +uint32_t link_get_aux_defer_delay(struct ddc_service *ddc) { uint32_t defer_delay = 0; @@ -352,175 +266,45 @@ uint32_t get_defer_delay(struct ddc_service *ddc) return defer_delay; } -static bool i2c_read( - struct ddc_service *ddc, - uint32_t address, - uint8_t *buffer, - uint32_t len) -{ - uint8_t offs_data = 0; - struct i2c_payload payloads[2] = { - { - .write = true, - .address = address, - .length = 1, - .data = &offs_data }, - { - .write = false, - .address = address, - .length = len, - .data = buffer } }; - - struct i2c_command command = { - .payloads = payloads, - .number_of_payloads = 2, - .engine = DDC_I2C_COMMAND_ENGINE, - .speed = ddc->ctx->dc->caps.i2c_speed_in_khz }; - - return dm_helpers_submit_i2c( - ddc->ctx, - ddc->link, - &command); -} - -void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( - struct ddc_service *ddc, - struct display_sink_capability *sink_cap) +static bool submit_aux_command(struct ddc_service *ddc, + struct aux_payload *payload) { - uint8_t i; - bool is_valid_hdmi_signature; - enum display_dongle_type *dongle = &sink_cap->dongle_type; - uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE]; - bool is_type2_dongle = false; - int retry_count = 2; - struct dp_hdmi_dongle_signature_data *dongle_signature; - - /* Assume we have no valid DP passive dongle connected */ - *dongle = DISPLAY_DONGLE_NONE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; - - /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ - if (!i2c_read( - ddc, - DP_HDMI_DONGLE_ADDRESS, - type2_dongle_buf, - sizeof(type2_dongle_buf))) { - /* Passive HDMI dongles can sometimes fail here without retrying*/ - while (retry_count > 0) { - if (i2c_read(ddc, - DP_HDMI_DONGLE_ADDRESS, - type2_dongle_buf, - sizeof(type2_dongle_buf))) - break; - retry_count--; - } - if (retry_count == 0) { - *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; - - CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), - "DP-DVI passive dongle %dMhz: ", - DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); - return; - } - } - - /* Check if Type 2 dongle.*/ - if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID) - is_type2_dongle = true; - - dongle_signature = - (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf; + uint32_t retrieved = 0; + bool ret = false; - is_valid_hdmi_signature = true; + if (!ddc) + return false; - /* Check EOT */ - if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) { - is_valid_hdmi_signature = false; - } + if (!payload) + return false; - /* Check signature */ - for (i = 0; i < sizeof(dongle_signature->id); ++i) { - /* If its not the right signature, - * skip mismatch in subversion byte.*/ - if (dongle_signature->id[i] != - dp_hdmi_dongle_signature_str[i] && i != 3) { + do { + struct aux_payload current_payload; + bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >= + payload->length; + uint32_t payload_length = is_end_of_payload ? + payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE; - if (is_type2_dongle) { - is_valid_hdmi_signature = false; - break; - } + current_payload.address = payload->address; + current_payload.data = &payload->data[retrieved]; + current_payload.defer_delay = payload->defer_delay; + current_payload.i2c_over_aux = payload->i2c_over_aux; + current_payload.length = payload_length; + /* set mot (middle of transaction) to false if it is the last payload */ + current_payload.mot = is_end_of_payload ? payload->mot:true; + current_payload.write_status_update = false; + current_payload.reply = payload->reply; + current_payload.write = payload->write; - } - } + ret = link_aux_transfer_with_retries_no_mutex(ddc, ¤t_payload); - if (is_type2_dongle) { - uint32_t max_tmds_clk = - type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK]; - - max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2; - - if (0 == max_tmds_clk || - max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK || - max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) { - *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; - - CONN_DATA_DETECT(ddc->link, type2_dongle_buf, - sizeof(type2_dongle_buf), - "DP-DVI passive dongle %dMhz: ", - DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); - } else { - if (is_valid_hdmi_signature == true) { - *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; - - CONN_DATA_DETECT(ddc->link, type2_dongle_buf, - sizeof(type2_dongle_buf), - "Type 2 DP-HDMI passive dongle %dMhz: ", - max_tmds_clk); - } else { - *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; - - CONN_DATA_DETECT(ddc->link, type2_dongle_buf, - sizeof(type2_dongle_buf), - "Type 2 DP-HDMI passive dongle (no signature) %dMhz: ", - max_tmds_clk); - - } - - /* Multiply by 1000 to convert to kHz. */ - sink_cap->max_hdmi_pixel_clock = - max_tmds_clk * 1000; - } - sink_cap->is_dongle_type_one = false; - - } else { - if (is_valid_hdmi_signature == true) { - *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; - - CONN_DATA_DETECT(ddc->link, type2_dongle_buf, - sizeof(type2_dongle_buf), - "Type 1 DP-HDMI passive dongle %dMhz: ", - sink_cap->max_hdmi_pixel_clock / 1000); - } else { - *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; - - CONN_DATA_DETECT(ddc->link, type2_dongle_buf, - sizeof(type2_dongle_buf), - "Type 1 DP-HDMI passive dongle (no signature) %dMhz: ", - sink_cap->max_hdmi_pixel_clock / 1000); - } - sink_cap->is_dongle_type_one = true; - } + retrieved += payload_length; + } while (retrieved < payload->length && ret == true); - return; + return ret; } -enum { - DP_SINK_CAP_SIZE = - DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1 -}; - -bool dal_ddc_service_query_ddc_data( +bool link_query_ddc_data( struct ddc_service *ddc, uint32_t address, uint8_t *write_buf, @@ -530,7 +314,7 @@ bool dal_ddc_service_query_ddc_data( { bool success = true; uint32_t payload_size = - dal_ddc_service_is_in_aux_transaction_mode(ddc) ? + link_is_in_aux_transaction_mode(ddc) ? DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE; uint32_t write_payloads = @@ -544,13 +328,13 @@ bool dal_ddc_service_query_ddc_data( if (!payloads_num) return false; - if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { + if (link_is_in_aux_transaction_mode(ddc)) { struct aux_payload payload; payload.i2c_over_aux = true; payload.address = address; payload.reply = NULL; - payload.defer_delay = get_defer_delay(ddc); + payload.defer_delay = link_get_aux_defer_delay(ddc); payload.write_status_update = false; if (write_size != 0) { @@ -562,7 +346,7 @@ bool dal_ddc_service_query_ddc_data( payload.length = write_size; payload.data = write_buf; - success = dal_ddc_submit_aux_command(ddc, &payload); + success = submit_aux_command(ddc, &payload); } if (read_size != 0 && success) { @@ -574,7 +358,7 @@ bool dal_ddc_service_query_ddc_data( payload.length = read_size; payload.data = read_buf; - success = dal_ddc_submit_aux_command(ddc, &payload); + success = submit_aux_command(ddc, &payload); } } else { struct i2c_command command = {0}; @@ -588,10 +372,10 @@ bool dal_ddc_service_query_ddc_data( command.engine = DDC_I2C_COMMAND_ENGINE; command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz; - dal_ddc_i2c_payloads_add( + i2c_payloads_add( &payloads, address, write_size, write_buf, true); - dal_ddc_i2c_payloads_add( + i2c_payloads_add( &payloads, address, read_size, read_buf, false); command.number_of_payloads = @@ -608,51 +392,6 @@ bool dal_ddc_service_query_ddc_data( return success; } -bool dal_ddc_submit_aux_command(struct ddc_service *ddc, - struct aux_payload *payload) -{ - uint32_t retrieved = 0; - bool ret = false; - - if (!ddc) - return false; - - if (!payload) - return false; - - do { - struct aux_payload current_payload; - bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >= - payload->length; - uint32_t payload_length = is_end_of_payload ? - payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE; - - current_payload.address = payload->address; - current_payload.data = &payload->data[retrieved]; - current_payload.defer_delay = payload->defer_delay; - current_payload.i2c_over_aux = payload->i2c_over_aux; - current_payload.length = payload_length; - /* set mot (middle of transaction) to false if it is the last payload */ - current_payload.mot = is_end_of_payload ? payload->mot:true; - current_payload.write_status_update = false; - current_payload.reply = payload->reply; - current_payload.write = payload->write; - - ret = dc_link_aux_transfer_with_retries(ddc, ¤t_payload); - - retrieved += payload_length; - } while (retrieved < payload->length && ret == true); - - return ret; -} - -/* dc_link_aux_transfer_raw() - Attempt to transfer - * the given aux payload. This function does not perform - * retries or handle error states. The reply is returned - * in the payload->reply and the result through - * *operation_result. Returns the number of bytes transferred, - * or -1 on a failure. - */ int dc_link_aux_transfer_raw(struct ddc_service *ddc, struct aux_payload *payload, enum aux_return_code_type *operation_result) @@ -665,22 +404,14 @@ int dc_link_aux_transfer_raw(struct ddc_service *ddc, } } -/* dc_link_aux_transfer_with_retries() - Attempt to submit an - * aux payload, retrying on timeouts, defers, and busy states - * as outlined in the DP spec. Returns true if the request - * was successful. - * - * Unless you want to implement your own retry semantics, this - * is probably the one you want. - */ -bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, +bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc, struct aux_payload *payload) { return dce_aux_transfer_with_retries(ddc, payload); } -bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc, +bool try_to_configure_aux_timeout(struct ddc_service *ddc, uint32_t timeout) { bool result = false; @@ -713,20 +444,12 @@ bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc, return result; } -/*test only function*/ -void dal_ddc_service_set_ddc_pin( - struct ddc_service *ddc_service, - struct ddc *ddc) -{ - ddc_service->ddc_pin = ddc; -} - -struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service) +struct ddc *get_ddc_pin(struct ddc_service *ddc_service) { return ddc_service->ddc_pin; } -void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service, +void write_scdc_data(struct ddc_service *ddc_service, uint32_t pix_clk, bool lte_340_scramble) { @@ -741,13 +464,13 @@ void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service, ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite) return; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, + link_query_ddc_data(ddc_service, slave_address, &offset, sizeof(offset), &sink_version, sizeof(sink_version)); if (sink_version == 1) { /*Source Version = 1*/ write_buffer[0] = HDMI_SCDC_SOURCE_VERSION; write_buffer[1] = 1; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, + link_query_ddc_data(ddc_service, slave_address, write_buffer, sizeof(write_buffer), NULL, 0); /*Read Request from SCDC caps*/ } @@ -760,11 +483,11 @@ void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service, } else { write_buffer[1] = 0; } - dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer, + link_query_ddc_data(ddc_service, slave_address, write_buffer, sizeof(write_buffer), NULL, 0); } -void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service) +void read_scdc_data(struct ddc_service *ddc_service) { uint8_t slave_address = HDMI_SCDC_ADDRESS; uint8_t offset = HDMI_SCDC_TMDS_CONFIG; @@ -774,20 +497,19 @@ void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service) ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite) return; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, + link_query_ddc_data(ddc_service, slave_address, &offset, sizeof(offset), &tmds_config, sizeof(tmds_config)); if (tmds_config & 0x1) { union hdmi_scdc_status_flags_data status_data = {0}; uint8_t scramble_status = 0; offset = HDMI_SCDC_SCRAMBLER_STATUS; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, + link_query_ddc_data(ddc_service, slave_address, &offset, sizeof(offset), &scramble_status, sizeof(scramble_status)); offset = HDMI_SCDC_STATUS_FLAGS; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, + link_query_ddc_data(ddc_service, slave_address, &offset, sizeof(offset), &status_data.byte, sizeof(status_data.byte)); } } - diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/dc/link/link_ddc.h index 418fbf8c5c3a..86e9d2e886d6 100644 --- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_ddc.h @@ -23,60 +23,38 @@ * */ -#ifndef __DAL_I2CAUX_INTERFACE_H__ -#define __DAL_I2CAUX_INTERFACE_H__ +#ifndef __DAL_DDC_SERVICE_H__ +#define __DAL_DDC_SERVICE_H__ -#include "dc_types.h" -#include "gpio_service_interface.h" +#include "link.h" +#define AUX_POWER_UP_WA_DELAY 500 +#define I2C_OVER_AUX_DEFER_WA_DELAY 70 +#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40 +#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1 +#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/ -#define DEFAULT_AUX_MAX_DATA_SIZE 16 -#define AUX_MAX_DEFER_WRITE_RETRY 20 +#define EDID_SEGMENT_SIZE 256 -struct aux_payload { - /* set following flag to read/write I2C data, - * reset it to read/write DPCD data */ - bool i2c_over_aux; - /* set following flag to write data, - * reset it to read data */ - bool write; - bool mot; - bool write_status_update; +void set_ddc_transaction_type( + struct ddc_service *ddc, + enum ddc_transaction_type type); - uint32_t address; - uint32_t length; - uint8_t *data; - /* - * used to return the reply type of the transaction - * ignored if NULL - */ - uint8_t *reply; - /* expressed in milliseconds - * zero means "use default value" - */ - uint32_t defer_delay; +bool try_to_configure_aux_timeout(struct ddc_service *ddc, + uint32_t timeout); -}; +void write_scdc_data( + struct ddc_service *ddc_service, + uint32_t pix_clk, + bool lte_340_scramble); -struct aux_command { - struct aux_payload *payloads; - uint8_t number_of_payloads; +void read_scdc_data( + struct ddc_service *ddc_service); - /* expressed in milliseconds - * zero means "use default value" */ - uint32_t defer_delay; +void set_dongle_type(struct ddc_service *ddc, + enum display_dongle_type dongle_type); - /* zero means "use default value" */ - uint32_t max_defer_write_retry; +struct ddc *get_ddc_pin(struct ddc_service *ddc_service); - enum i2c_mot_mode mot; -}; +#endif /* __DAL_DDC_SERVICE_H__ */ -union aux_config { - struct { - uint32_t ALLOW_AUX_WHEN_HPD_LOW:1; - } bits; - uint32_t raw; -}; - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.c new file mode 100644 index 000000000000..e72ad1b8330f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.c @@ -0,0 +1,2169 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * This file implements dp specific link capability retrieval sequence. It is + * responsible for retrieving, parsing, overriding, deciding capability obtained + * from dp link. Link capability consists of encoders, DPRXs, cables, retimers, + * usb and all other possible backend capabilities. Other components should + * include this header file in order to access link capability. Accessing link + * capability by dereferencing dc_link outside dp_link_capability is not a + * recommended method as it makes the component dependent on the underlying data + * structure used to represent link capability instead of function interfaces. + */ + +#include "link_dp_capability.h" +#include "link_ddc.h" +#include "link_dpcd.h" +#include "link_dp_dpia.h" +#include "link_dp_phy.h" +#include "link_dp_trace.h" +#include "link_dp_training.h" +#include "atomfirmware.h" +#include "resource.h" +#include "link_enc_cfg.h" +#include "dc_link_dp.h" +#include "dc_dmub_srv.h" + +#define DC_LOGGER \ + link->ctx->logger +#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ + +#ifndef MAX +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif +#ifndef MIN +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif + +#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/ + +struct dp_lt_fallback_entry { + enum dc_lane_count lane_count; + enum dc_link_rate link_rate; +}; + +static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = { + /* This link training fallback array is ordered by + * link bandwidth from highest to lowest. + * DP specs makes it a normative policy to always + * choose the next highest link bandwidth during + * link training fallback. + */ + {LANE_COUNT_FOUR, LINK_RATE_UHBR20}, + {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5}, + {LANE_COUNT_TWO, LINK_RATE_UHBR20}, + {LANE_COUNT_FOUR, LINK_RATE_UHBR10}, + {LANE_COUNT_TWO, LINK_RATE_UHBR13_5}, + {LANE_COUNT_FOUR, LINK_RATE_HIGH3}, + {LANE_COUNT_ONE, LINK_RATE_UHBR20}, + {LANE_COUNT_TWO, LINK_RATE_UHBR10}, + {LANE_COUNT_FOUR, LINK_RATE_HIGH2}, + {LANE_COUNT_ONE, LINK_RATE_UHBR13_5}, + {LANE_COUNT_TWO, LINK_RATE_HIGH3}, + {LANE_COUNT_ONE, LINK_RATE_UHBR10}, + {LANE_COUNT_TWO, LINK_RATE_HIGH2}, + {LANE_COUNT_FOUR, LINK_RATE_HIGH}, + {LANE_COUNT_ONE, LINK_RATE_HIGH3}, + {LANE_COUNT_FOUR, LINK_RATE_LOW}, + {LANE_COUNT_ONE, LINK_RATE_HIGH2}, + {LANE_COUNT_TWO, LINK_RATE_HIGH}, + {LANE_COUNT_TWO, LINK_RATE_LOW}, + {LANE_COUNT_ONE, LINK_RATE_HIGH}, + {LANE_COUNT_ONE, LINK_RATE_LOW}, +}; + +static const struct dc_link_settings fail_safe_link_settings = { + .lane_count = LANE_COUNT_ONE, + .link_rate = LINK_RATE_LOW, + .link_spread = LINK_SPREAD_DISABLED, +}; + +bool is_dp_active_dongle(const struct dc_link *link) +{ + return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) && + (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER); +} + +bool is_dp_branch_device(const struct dc_link *link) +{ + return link->dpcd_caps.is_branch_dev; +} + +static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc) +{ + switch (bpc) { + case DOWN_STREAM_MAX_8BPC: + return 8; + case DOWN_STREAM_MAX_10BPC: + return 10; + case DOWN_STREAM_MAX_12BPC: + return 12; + case DOWN_STREAM_MAX_16BPC: + return 16; + default: + break; + } + + return -1; +} + +uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count) +{ + switch (lttpr_repeater_count) { + case 0x80: // 1 lttpr repeater + return 1; + case 0x40: // 2 lttpr repeaters + return 2; + case 0x20: // 3 lttpr repeaters + return 3; + case 0x10: // 4 lttpr repeaters + return 4; + case 0x08: // 5 lttpr repeaters + return 5; + case 0x04: // 6 lttpr repeaters + return 6; + case 0x02: // 7 lttpr repeaters + return 7; + case 0x01: // 8 lttpr repeaters + return 8; + default: + break; + } + return 0; // invalid value +} + +uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw) +{ + switch (bw) { + case 0b001: + return 9000000; + case 0b010: + return 18000000; + case 0b011: + return 24000000; + case 0b100: + return 32000000; + case 0b101: + return 40000000; + case 0b110: + return 48000000; + } + + return 0; +} + +static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz) +{ + enum dc_link_rate link_rate; + // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation. + switch (link_rate_in_khz) { + case 1620000: + link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane + break; + case 2160000: + link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane + break; + case 2430000: + link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane + break; + case 2700000: + link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane + break; + case 3240000: + link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2)- 3.24 Gbps/Lane + break; + case 4320000: + link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane + break; + case 5400000: + link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2)- 5.40 Gbps/Lane + break; + case 8100000: + link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3)- 8.10 Gbps/Lane + break; + default: + link_rate = LINK_RATE_UNKNOWN; + break; + } + return link_rate; +} + +static union dp_cable_id intersect_cable_id( + union dp_cable_id *a, union dp_cable_id *b) +{ + union dp_cable_id out; + + out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY, + b->bits.UHBR10_20_CAPABILITY); + out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY, + b->bits.UHBR13_5_CAPABILITY); + out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE); + + return out; +} + +/* + * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw. + */ +static uint32_t intersect_frl_link_bw_support( + const uint32_t max_supported_frl_bw_in_kbps, + const union hdmi_encoded_link_bw hdmi_encoded_link_bw) +{ + uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps; + + // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode) + if (hdmi_encoded_link_bw.bits.FRL_MODE) { + if (hdmi_encoded_link_bw.bits.BW_48Gbps) + supported_bw_in_kbps = 48000000; + else if (hdmi_encoded_link_bw.bits.BW_40Gbps) + supported_bw_in_kbps = 40000000; + else if (hdmi_encoded_link_bw.bits.BW_32Gbps) + supported_bw_in_kbps = 32000000; + else if (hdmi_encoded_link_bw.bits.BW_24Gbps) + supported_bw_in_kbps = 24000000; + else if (hdmi_encoded_link_bw.bits.BW_18Gbps) + supported_bw_in_kbps = 18000000; + else if (hdmi_encoded_link_bw.bits.BW_9Gbps) + supported_bw_in_kbps = 9000000; + } + + return supported_bw_in_kbps; +} + +static enum clock_source_id get_clock_source_id(struct dc_link *link) +{ + enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED; + struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source; + + if (dp_cs != NULL) { + dp_cs_id = dp_cs->id; + } else { + /* + * dp clock source is not initialized for some reason. + * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used + */ + ASSERT(dp_cs); + } + + return dp_cs_id; +} + +static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, + int length) +{ + int retry = 0; + union dp_downstream_port_present ds_port = { 0 }; + + if (!link->dpcd_caps.dpcd_rev.raw) { + do { + dc_link_dp_receiver_power_ctrl(link, true); + core_link_read_dpcd(link, DP_DPCD_REV, + dpcd_data, length); + link->dpcd_caps.dpcd_rev.raw = dpcd_data[ + DP_DPCD_REV - + DP_DPCD_REV]; + } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw); + } + + ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT - + DP_DPCD_REV]; + + if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) { + switch (link->dpcd_caps.branch_dev_id) { + /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down + * all internal circuits including AUX communication preventing + * reading DPCD table and EDID (spec violation). + * Encoder will skip DP RX power down on disable_output to + * keep receiver powered all the time.*/ + case DP_BRANCH_DEVICE_ID_0010FA: + case DP_BRANCH_DEVICE_ID_0080E1: + case DP_BRANCH_DEVICE_ID_00E04C: + link->wa_flags.dp_keep_receiver_powered = true; + break; + + /* TODO: May need work around for other dongles. */ + default: + link->wa_flags.dp_keep_receiver_powered = false; + break; + } + } else + link->wa_flags.dp_keep_receiver_powered = false; +} + +bool dc_link_is_fec_supported(const struct dc_link *link) +{ + /* TODO - use asic cap instead of link_enc->features + * we no longer know which link enc to use for this link before commit + */ + struct link_encoder *link_enc = NULL; + + link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link_enc); + + return (dc_is_dp_signal(link->connector_signal) && link_enc && + link_enc->features.fec_supported && + link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && + !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment)); +} + +bool dc_link_should_enable_fec(const struct dc_link *link) +{ + bool force_disable = false; + + if (link->fec_state == dc_link_fec_enabled) + force_disable = false; + else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST && + link->local_sink && + link->local_sink->edid_caps.panel_patch.disable_fec) + force_disable = true; + else if (link->connector_signal == SIGNAL_TYPE_EDP + && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields. + dsc_support.DSC_SUPPORT == false + || link->panel_config.dsc.disable_dsc_edp + || !link->dc->caps.edp_dsc_support)) + force_disable = true; + + return !force_disable && dc_link_is_fec_supported(link); +} + +bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx) +{ + /* If this assert is hit then we have a link encoder dynamic management issue */ + ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); + return (pipe_ctx->stream_res.hpo_dp_stream_enc && + pipe_ctx->link_res.hpo_dp_link_enc && + dc_is_dp_signal(pipe_ctx->stream->signal)); +} + +bool dp_is_lttpr_present(struct dc_link *link) +{ + return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 && + link->dpcd_caps.lttpr_caps.max_lane_count > 0 && + link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && + link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); +} + +/* in DP compliance test, DPR-120 may have + * a random value in its MAX_LINK_BW dpcd field. + * We map it to the maximum supported link rate that + * is smaller than MAX_LINK_BW in this case. + */ +static enum dc_link_rate get_link_rate_from_max_link_bw( + uint8_t max_link_bw) +{ + enum dc_link_rate link_rate; + + if (max_link_bw >= LINK_RATE_HIGH3) { + link_rate = LINK_RATE_HIGH3; + } else if (max_link_bw < LINK_RATE_HIGH3 + && max_link_bw >= LINK_RATE_HIGH2) { + link_rate = LINK_RATE_HIGH2; + } else if (max_link_bw < LINK_RATE_HIGH2 + && max_link_bw >= LINK_RATE_HIGH) { + link_rate = LINK_RATE_HIGH; + } else if (max_link_bw < LINK_RATE_HIGH + && max_link_bw >= LINK_RATE_LOW) { + link_rate = LINK_RATE_LOW; + } else { + link_rate = LINK_RATE_UNKNOWN; + } + + return link_rate; +} + +static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link) +{ + enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate; + + if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20) + lttpr_max_link_rate = LINK_RATE_UHBR20; + else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5) + lttpr_max_link_rate = LINK_RATE_UHBR13_5; + else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10) + lttpr_max_link_rate = LINK_RATE_UHBR10; + + return lttpr_max_link_rate; +} + +static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link) +{ + enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN; + + if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20) + cable_max_link_rate = LINK_RATE_UHBR20; + else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY) + cable_max_link_rate = LINK_RATE_UHBR13_5; + else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10) + cable_max_link_rate = LINK_RATE_UHBR10; + + return cable_max_link_rate; +} + +static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count) +{ + return lane_count <= LANE_COUNT_ONE; +} + +static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate) +{ + return link_rate <= LINK_RATE_LOW; +} + +static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count) +{ + switch (lane_count) { + case LANE_COUNT_FOUR: + return LANE_COUNT_TWO; + case LANE_COUNT_TWO: + return LANE_COUNT_ONE; + case LANE_COUNT_ONE: + return LANE_COUNT_UNKNOWN; + default: + return LANE_COUNT_UNKNOWN; + } +} + +static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate) +{ + switch (link_rate) { + case LINK_RATE_UHBR20: + return LINK_RATE_UHBR13_5; + case LINK_RATE_UHBR13_5: + return LINK_RATE_UHBR10; + case LINK_RATE_UHBR10: + return LINK_RATE_HIGH3; + case LINK_RATE_HIGH3: + return LINK_RATE_HIGH2; + case LINK_RATE_HIGH2: + return LINK_RATE_HIGH; + case LINK_RATE_HIGH: + return LINK_RATE_LOW; + case LINK_RATE_LOW: + return LINK_RATE_UNKNOWN; + default: + return LINK_RATE_UNKNOWN; + } +} + +static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count) +{ + switch (lane_count) { + case LANE_COUNT_ONE: + return LANE_COUNT_TWO; + case LANE_COUNT_TWO: + return LANE_COUNT_FOUR; + default: + return LANE_COUNT_UNKNOWN; + } +} + +static enum dc_link_rate increase_link_rate(struct dc_link *link, + enum dc_link_rate link_rate) +{ + switch (link_rate) { + case LINK_RATE_LOW: + return LINK_RATE_HIGH; + case LINK_RATE_HIGH: + return LINK_RATE_HIGH2; + case LINK_RATE_HIGH2: + return LINK_RATE_HIGH3; + case LINK_RATE_HIGH3: + return LINK_RATE_UHBR10; + case LINK_RATE_UHBR10: + /* upto DP2.x specs UHBR13.5 is the only link rate that could be + * not supported by DPRX when higher link rate is supported. + * so we treat it as a special case for code simplicity. When we + * have new specs with more link rates like this, we should + * consider a more generic solution to handle discrete link + * rate capabilities. + */ + return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ? + LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20; + case LINK_RATE_UHBR13_5: + return LINK_RATE_UHBR20; + default: + return LINK_RATE_UNKNOWN; + } +} + +static bool decide_fallback_link_setting_max_bw_policy( + struct dc_link *link, + const struct dc_link_settings *max, + struct dc_link_settings *cur, + enum link_training_result training_result) +{ + uint8_t cur_idx = 0, next_idx; + bool found = false; + + if (training_result == LINK_TRAINING_ABORT) + return false; + + while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks)) + /* find current index */ + if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count && + dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate) + break; + else + cur_idx++; + + next_idx = cur_idx + 1; + + while (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) + /* find next index */ + if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count || + dp_lt_fallbacks[next_idx].link_rate > max->link_rate) + next_idx++; + else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 && + link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0) + /* upto DP2.x specs UHBR13.5 is the only link rate that + * could be not supported by DPRX when higher link rate + * is supported. so we treat it as a special case for + * code simplicity. When we have new specs with more + * link rates like this, we should consider a more + * generic solution to handle discrete link rate + * capabilities. + */ + next_idx++; + else + break; + + if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) { + cur->lane_count = dp_lt_fallbacks[next_idx].lane_count; + cur->link_rate = dp_lt_fallbacks[next_idx].link_rate; + found = true; + } + + return found; +} + +/* + * function: set link rate and lane count fallback based + * on current link setting and last link training result + * return value: + * true - link setting could be set + * false - has reached minimum setting + * and no further fallback could be done + */ +bool decide_fallback_link_setting( + struct dc_link *link, + struct dc_link_settings *max, + struct dc_link_settings *cur, + enum link_training_result training_result) +{ + if (link_dp_get_encoding_format(max) == DP_128b_132b_ENCODING || + link->dc->debug.force_dp2_lt_fallback_method) + return decide_fallback_link_setting_max_bw_policy(link, max, + cur, training_result); + + switch (training_result) { + case LINK_TRAINING_CR_FAIL_LANE0: + case LINK_TRAINING_CR_FAIL_LANE1: + case LINK_TRAINING_CR_FAIL_LANE23: + case LINK_TRAINING_LQA_FAIL: + { + if (!reached_minimum_link_rate(cur->link_rate)) { + cur->link_rate = reduce_link_rate(cur->link_rate); + } else if (!reached_minimum_lane_count(cur->lane_count)) { + cur->link_rate = max->link_rate; + if (training_result == LINK_TRAINING_CR_FAIL_LANE0) + return false; + else if (training_result == LINK_TRAINING_CR_FAIL_LANE1) + cur->lane_count = LANE_COUNT_ONE; + else if (training_result == LINK_TRAINING_CR_FAIL_LANE23) + cur->lane_count = LANE_COUNT_TWO; + else + cur->lane_count = reduce_lane_count(cur->lane_count); + } else { + return false; + } + break; + } + case LINK_TRAINING_EQ_FAIL_EQ: + case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: + { + if (!reached_minimum_lane_count(cur->lane_count)) { + cur->lane_count = reduce_lane_count(cur->lane_count); + } else if (!reached_minimum_link_rate(cur->link_rate)) { + cur->link_rate = reduce_link_rate(cur->link_rate); + /* Reduce max link rate to avoid potential infinite loop. + * Needed so that any subsequent CR_FAIL fallback can't + * re-set the link rate higher than the link rate from + * the latest EQ_FAIL fallback. + */ + max->link_rate = cur->link_rate; + cur->lane_count = max->lane_count; + } else { + return false; + } + break; + } + case LINK_TRAINING_EQ_FAIL_CR: + { + if (!reached_minimum_link_rate(cur->link_rate)) { + cur->link_rate = reduce_link_rate(cur->link_rate); + /* Reduce max link rate to avoid potential infinite loop. + * Needed so that any subsequent CR_FAIL fallback can't + * re-set the link rate higher than the link rate from + * the latest EQ_FAIL fallback. + */ + max->link_rate = cur->link_rate; + cur->lane_count = max->lane_count; + } else { + return false; + } + break; + } + default: + return false; + } + return true; +} +static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) +{ + struct dc_link_settings initial_link_setting = { + LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0}; + struct dc_link_settings current_link_setting = + initial_link_setting; + uint32_t link_bw; + + if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) + return false; + + /* search for the minimum link setting that: + * 1. is supported according to the link training result + * 2. could support the b/w requested by the timing + */ + while (current_link_setting.link_rate <= + link->verified_link_cap.link_rate) { + link_bw = dc_link_bandwidth_kbps( + link, + ¤t_link_setting); + if (req_bw <= link_bw) { + *link_setting = current_link_setting; + return true; + } + + if (current_link_setting.lane_count < + link->verified_link_cap.lane_count) { + current_link_setting.lane_count = + increase_lane_count( + current_link_setting.lane_count); + } else { + current_link_setting.link_rate = + increase_link_rate(link, + current_link_setting.link_rate); + current_link_setting.lane_count = + initial_link_setting.lane_count; + } + } + + return false; +} + +bool dc_link_decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) +{ + struct dc_link_settings initial_link_setting; + struct dc_link_settings current_link_setting; + uint32_t link_bw; + + /* + * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. + * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" + */ + if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || + link->dpcd_caps.edp_supported_link_rates_count == 0) { + *link_setting = link->verified_link_cap; + return true; + } + + memset(&initial_link_setting, 0, sizeof(initial_link_setting)); + initial_link_setting.lane_count = LANE_COUNT_ONE; + initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; + initial_link_setting.link_spread = LINK_SPREAD_DISABLED; + initial_link_setting.use_link_rate_set = true; + initial_link_setting.link_rate_set = 0; + current_link_setting = initial_link_setting; + + /* search for the minimum link setting that: + * 1. is supported according to the link training result + * 2. could support the b/w requested by the timing + */ + while (current_link_setting.link_rate <= + link->verified_link_cap.link_rate) { + link_bw = dc_link_bandwidth_kbps( + link, + ¤t_link_setting); + if (req_bw <= link_bw) { + *link_setting = current_link_setting; + return true; + } + + if (current_link_setting.lane_count < + link->verified_link_cap.lane_count) { + current_link_setting.lane_count = + increase_lane_count( + current_link_setting.lane_count); + } else { + if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { + current_link_setting.link_rate_set++; + current_link_setting.link_rate = + link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; + current_link_setting.lane_count = + initial_link_setting.lane_count; + } else + break; + } + } + return false; +} + +bool decide_edp_link_settings_with_dsc(struct dc_link *link, + struct dc_link_settings *link_setting, + uint32_t req_bw, + enum dc_link_rate max_link_rate) +{ + struct dc_link_settings initial_link_setting; + struct dc_link_settings current_link_setting; + uint32_t link_bw; + + unsigned int policy = 0; + + policy = link->panel_config.dsc.force_dsc_edp_policy; + if (max_link_rate == LINK_RATE_UNKNOWN) + max_link_rate = link->verified_link_cap.link_rate; + /* + * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. + * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" + */ + if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || + link->dpcd_caps.edp_supported_link_rates_count == 0)) { + /* for DSC enabled case, we search for minimum lane count */ + memset(&initial_link_setting, 0, sizeof(initial_link_setting)); + initial_link_setting.lane_count = LANE_COUNT_ONE; + initial_link_setting.link_rate = LINK_RATE_LOW; + initial_link_setting.link_spread = LINK_SPREAD_DISABLED; + initial_link_setting.use_link_rate_set = false; + initial_link_setting.link_rate_set = 0; + current_link_setting = initial_link_setting; + if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) + return false; + + /* search for the minimum link setting that: + * 1. is supported according to the link training result + * 2. could support the b/w requested by the timing + */ + while (current_link_setting.link_rate <= + max_link_rate) { + link_bw = dc_link_bandwidth_kbps( + link, + ¤t_link_setting); + if (req_bw <= link_bw) { + *link_setting = current_link_setting; + return true; + } + if (policy) { + /* minimize lane */ + if (current_link_setting.link_rate < max_link_rate) { + current_link_setting.link_rate = + increase_link_rate(link, + current_link_setting.link_rate); + } else { + if (current_link_setting.lane_count < + link->verified_link_cap.lane_count) { + current_link_setting.lane_count = + increase_lane_count( + current_link_setting.lane_count); + current_link_setting.link_rate = initial_link_setting.link_rate; + } else + break; + } + } else { + /* minimize link rate */ + if (current_link_setting.lane_count < + link->verified_link_cap.lane_count) { + current_link_setting.lane_count = + increase_lane_count( + current_link_setting.lane_count); + } else { + current_link_setting.link_rate = + increase_link_rate(link, + current_link_setting.link_rate); + current_link_setting.lane_count = + initial_link_setting.lane_count; + } + } + } + return false; + } + + /* if optimize edp link is supported */ + memset(&initial_link_setting, 0, sizeof(initial_link_setting)); + initial_link_setting.lane_count = LANE_COUNT_ONE; + initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; + initial_link_setting.link_spread = LINK_SPREAD_DISABLED; + initial_link_setting.use_link_rate_set = true; + initial_link_setting.link_rate_set = 0; + current_link_setting = initial_link_setting; + + /* search for the minimum link setting that: + * 1. is supported according to the link training result + * 2. could support the b/w requested by the timing + */ + while (current_link_setting.link_rate <= + max_link_rate) { + link_bw = dc_link_bandwidth_kbps( + link, + ¤t_link_setting); + if (req_bw <= link_bw) { + *link_setting = current_link_setting; + return true; + } + if (policy) { + /* minimize lane */ + if (current_link_setting.link_rate_set < + link->dpcd_caps.edp_supported_link_rates_count + && current_link_setting.link_rate < max_link_rate) { + current_link_setting.link_rate_set++; + current_link_setting.link_rate = + link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; + } else { + if (current_link_setting.lane_count < link->verified_link_cap.lane_count) { + current_link_setting.lane_count = + increase_lane_count( + current_link_setting.lane_count); + current_link_setting.link_rate_set = initial_link_setting.link_rate_set; + current_link_setting.link_rate = + link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; + } else + break; + } + } else { + /* minimize link rate */ + if (current_link_setting.lane_count < + link->verified_link_cap.lane_count) { + current_link_setting.lane_count = + increase_lane_count( + current_link_setting.lane_count); + } else { + if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { + current_link_setting.link_rate_set++; + current_link_setting.link_rate = + link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; + current_link_setting.lane_count = + initial_link_setting.lane_count; + } else + break; + } + } + } + return false; +} + +static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting) +{ + *link_setting = link->verified_link_cap; + return true; +} + +bool link_decide_link_settings(struct dc_stream_state *stream, + struct dc_link_settings *link_setting) +{ + struct dc_link *link = stream->link; + uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); + + memset(link_setting, 0, sizeof(*link_setting)); + + /* if preferred is specified through AMDDP, use it, if it's enough + * to drive the mode + */ + if (link->preferred_link_setting.lane_count != + LANE_COUNT_UNKNOWN && + link->preferred_link_setting.link_rate != + LINK_RATE_UNKNOWN) { + *link_setting = link->preferred_link_setting; + return true; + } + + /* MST doesn't perform link training for now + * TODO: add MST specific link training routine + */ + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + decide_mst_link_settings(link, link_setting); + } else if (link->connector_signal == SIGNAL_TYPE_EDP) { + /* enable edp link optimization for DSC eDP case */ + if (stream->timing.flags.DSC) { + enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN; + + if (link->panel_config.dsc.force_dsc_edp_policy) { + /* calculate link max link rate cap*/ + struct dc_link_settings tmp_link_setting; + struct dc_crtc_timing tmp_timing = stream->timing; + uint32_t orig_req_bw; + + tmp_link_setting.link_rate = LINK_RATE_UNKNOWN; + tmp_timing.flags.DSC = 0; + orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing); + dc_link_decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw); + max_link_rate = tmp_link_setting.link_rate; + } + decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate); + } else { + dc_link_decide_edp_link_settings(link, link_setting, req_bw); + } + } else { + decide_dp_link_settings(link, link_setting, req_bw); + } + + return link_setting->lane_count != LANE_COUNT_UNKNOWN && + link_setting->link_rate != LINK_RATE_UNKNOWN; +} + +enum dp_link_encoding link_dp_get_encoding_format(const struct dc_link_settings *link_settings) +{ + if ((link_settings->link_rate >= LINK_RATE_LOW) && + (link_settings->link_rate <= LINK_RATE_HIGH3)) + return DP_8b_10b_ENCODING; + else if ((link_settings->link_rate >= LINK_RATE_UHBR10) && + (link_settings->link_rate <= LINK_RATE_UHBR20)) + return DP_128b_132b_ENCODING; + return DP_UNKNOWN_ENCODING; +} + +enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link) +{ + struct dc_link_settings link_settings = {0}; + + if (!dc_is_dp_signal(link->connector_signal)) + return DP_UNKNOWN_ENCODING; + + if (link->preferred_link_setting.lane_count != + LANE_COUNT_UNKNOWN && + link->preferred_link_setting.link_rate != + LINK_RATE_UNKNOWN) { + link_settings = link->preferred_link_setting; + } else { + decide_mst_link_settings(link, &link_settings); + } + + return link_dp_get_encoding_format(&link_settings); +} + +static void read_dp_device_vendor_id(struct dc_link *link) +{ + struct dp_device_vendor_id dp_id; + + /* read IEEE branch device id */ + core_link_read_dpcd( + link, + DP_BRANCH_OUI, + (uint8_t *)&dp_id, + sizeof(dp_id)); + + link->dpcd_caps.branch_dev_id = + (dp_id.ieee_oui[0] << 16) + + (dp_id.ieee_oui[1] << 8) + + dp_id.ieee_oui[2]; + + memmove( + link->dpcd_caps.branch_dev_name, + dp_id.ieee_device_id, + sizeof(dp_id.ieee_device_id)); +} + +static enum dc_status wake_up_aux_channel(struct dc_link *link) +{ + enum dc_status status = DC_ERROR_UNEXPECTED; + uint32_t aux_channel_retry_cnt = 0; + uint8_t dpcd_power_state = '\0'; + + while (status != DC_OK && aux_channel_retry_cnt < 10) { + status = core_link_read_dpcd(link, DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); + + /* Delay 1 ms if AUX CH is in power down state. Based on spec + * section 2.3.1.2, if AUX CH may be powered down due to + * write to DPCD 600h = 2. Sink AUX CH is monitoring differential + * signal and may need up to 1 ms before being able to reply. + */ + if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) { + udelay(1000); + aux_channel_retry_cnt++; + } + } + + if (status != DC_OK) { + dpcd_power_state = DP_SET_POWER_D0; + status = core_link_write_dpcd( + link, + DP_SET_POWER, + &dpcd_power_state, + sizeof(dpcd_power_state)); + + dpcd_power_state = DP_SET_POWER_D3; + status = core_link_write_dpcd( + link, + DP_SET_POWER, + &dpcd_power_state, + sizeof(dpcd_power_state)); + return DC_ERROR_UNEXPECTED; + } + + return DC_OK; +} + +static void get_active_converter_info( + uint8_t data, struct dc_link *link) +{ + union dp_downstream_port_present ds_port = { .byte = data }; + memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps)); + + /* decode converter info*/ + if (!ds_port.fields.PORT_PRESENT) { + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; + set_dongle_type(link->ddc, + link->dpcd_caps.dongle_type); + link->dpcd_caps.is_branch_dev = false; + return; + } + + /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */ + link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT; + + switch (ds_port.fields.PORT_TYPE) { + case DOWNSTREAM_VGA: + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER; + break; + case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS: + /* At this point we don't know is it DVI or HDMI or DP++, + * assume DVI.*/ + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER; + break; + default: + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; + break; + } + + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) { + uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/ + union dwnstream_port_caps_byte0 *port_caps = + (union dwnstream_port_caps_byte0 *)det_caps; + if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0, + det_caps, sizeof(det_caps)) == DC_OK) { + + switch (port_caps->bits.DWN_STRM_PORTX_TYPE) { + /*Handle DP case as DONGLE_NONE*/ + case DOWN_STREAM_DETAILED_DP: + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; + break; + case DOWN_STREAM_DETAILED_VGA: + link->dpcd_caps.dongle_type = + DISPLAY_DONGLE_DP_VGA_CONVERTER; + break; + case DOWN_STREAM_DETAILED_DVI: + link->dpcd_caps.dongle_type = + DISPLAY_DONGLE_DP_DVI_CONVERTER; + break; + case DOWN_STREAM_DETAILED_HDMI: + case DOWN_STREAM_DETAILED_DP_PLUS_PLUS: + /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/ + link->dpcd_caps.dongle_type = + DISPLAY_DONGLE_DP_HDMI_CONVERTER; + + link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type; + if (ds_port.fields.DETAILED_CAPS) { + + union dwnstream_port_caps_byte3_hdmi + hdmi_caps = {.raw = det_caps[3] }; + union dwnstream_port_caps_byte2 + hdmi_color_caps = {.raw = det_caps[2] }; + link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz = + det_caps[1] * 2500; + + link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter = + hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK; + /*YCBCR capability only for HDMI case*/ + if (port_caps->bits.DWN_STRM_PORTX_TYPE + == DOWN_STREAM_DETAILED_HDMI) { + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through = + hdmi_caps.bits.YCrCr422_PASS_THROUGH; + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through = + hdmi_caps.bits.YCrCr420_PASS_THROUGH; + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter = + hdmi_caps.bits.YCrCr422_CONVERSION; + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter = + hdmi_caps.bits.YCrCr420_CONVERSION; + } + + link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc = + translate_dpcd_max_bpc( + hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT); + + if (link->dc->caps.dp_hdmi21_pcon_support) { + union hdmi_encoded_link_bw hdmi_encoded_link_bw; + + link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = + dc_link_bw_kbps_from_raw_frl_link_rate_data( + hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT); + + // Intersect reported max link bw support with the supported link rate post FRL link training + if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS, + &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) { + link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support( + link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps, + hdmi_encoded_link_bw); + } + + if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0) + link->dpcd_caps.dongle_caps.extendedCapValid = true; + } + + if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0) + link->dpcd_caps.dongle_caps.extendedCapValid = true; + } + + break; + } + } + } + + set_dongle_type(link->ddc, link->dpcd_caps.dongle_type); + + { + struct dp_sink_hw_fw_revision dp_hw_fw_revision; + + core_link_read_dpcd( + link, + DP_BRANCH_REVISION_START, + (uint8_t *)&dp_hw_fw_revision, + sizeof(dp_hw_fw_revision)); + + link->dpcd_caps.branch_hw_revision = + dp_hw_fw_revision.ieee_hw_rev; + + memmove( + link->dpcd_caps.branch_fw_revision, + dp_hw_fw_revision.ieee_fw_rev, + sizeof(dp_hw_fw_revision.ieee_fw_rev)); + } + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && + link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { + union dp_dfp_cap_ext dfp_cap_ext; + memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext)); + core_link_read_dpcd( + link, + DP_DFP_CAPABILITY_EXTENSION_SUPPORT, + dfp_cap_ext.raw, + sizeof(dfp_cap_ext.raw)); + link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported; + link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps = + dfp_cap_ext.fields.max_pixel_rate_in_mps[0] + + (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8); + link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width = + dfp_cap_ext.fields.max_video_h_active_width[0] + + (dfp_cap_ext.fields.max_video_h_active_width[1] << 8); + link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height = + dfp_cap_ext.fields.max_video_v_active_height[0] + + (dfp_cap_ext.fields.max_video_v_active_height[1] << 8); + link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps = + dfp_cap_ext.fields.encoding_format_caps; + link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps = + dfp_cap_ext.fields.rgb_color_depth_caps; + link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps = + dfp_cap_ext.fields.ycbcr444_color_depth_caps; + link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps = + dfp_cap_ext.fields.ycbcr422_color_depth_caps; + link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps = + dfp_cap_ext.fields.ycbcr420_color_depth_caps; + DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index); + DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false"); + DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps); + DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width); + DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height); + } +} + +static void apply_usbc_combo_phy_reset_wa(struct dc_link *link, + struct dc_link_settings *link_settings) +{ + /* Temporary Renoir-specific workaround PHY will sometimes be in bad + * state on hotplugging display from certain USB-C dongle, so add extra + * cycle of enabling and disabling the PHY before first link training. + */ + struct link_resource link_res = {0}; + enum clock_source_id dp_cs_id = get_clock_source_id(link); + + dp_enable_link_phy(link, &link_res, link->connector_signal, + dp_cs_id, link_settings); + dp_disable_link_phy(link, &link_res, link->connector_signal); +} + +static bool dp_overwrite_extended_receiver_cap(struct dc_link *link) +{ + uint8_t dpcd_data[16]; + uint32_t read_dpcd_retry_cnt = 3; + enum dc_status status = DC_ERROR_UNEXPECTED; + union dp_downstream_port_present ds_port = { 0 }; + union down_stream_port_count down_strm_port_count; + union edp_configuration_cap edp_config_cap; + + int i; + + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( + link, + DP_DPCD_REV, + dpcd_data, + sizeof(dpcd_data)); + if (status == DC_OK) + break; + } + + link->dpcd_caps.dpcd_rev.raw = + dpcd_data[DP_DPCD_REV - DP_DPCD_REV]; + + if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0) + return false; + + ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT - + DP_DPCD_REV]; + + get_active_converter_info(ds_port.byte, link); + + down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT - + DP_DPCD_REV]; + + link->dpcd_caps.allow_invalid_MSA_timing_param = + down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM; + + link->dpcd_caps.max_ln_count.raw = dpcd_data[ + DP_MAX_LANE_COUNT - DP_DPCD_REV]; + + link->dpcd_caps.max_down_spread.raw = dpcd_data[ + DP_MAX_DOWNSPREAD - DP_DPCD_REV]; + + link->reported_link_cap.lane_count = + link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT; + link->reported_link_cap.link_rate = dpcd_data[ + DP_MAX_LINK_RATE - DP_DPCD_REV]; + link->reported_link_cap.link_spread = + link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ? + LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; + + edp_config_cap.raw = dpcd_data[ + DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV]; + link->dpcd_caps.panel_mode_edp = + edp_config_cap.bits.ALT_SCRAMBLER_RESET; + link->dpcd_caps.dpcd_display_control_capable = + edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; + + return true; +} + +void dc_link_overwrite_extended_receiver_cap( + struct dc_link *link) +{ + dp_overwrite_extended_receiver_cap(link); +} + +void dpcd_set_source_specific_data(struct dc_link *link) +{ + if (!link->dc->vendor_signature.is_valid) { + enum dc_status result_write_min_hblank = DC_NOT_SUPPORTED; + struct dpcd_amd_signature amd_signature = {0}; + struct dpcd_amd_device_id amd_device_id = {0}; + + amd_device_id.device_id_byte1 = + (uint8_t)(link->ctx->asic_id.chip_id); + amd_device_id.device_id_byte2 = + (uint8_t)(link->ctx->asic_id.chip_id >> 8); + amd_device_id.dce_version = + (uint8_t)(link->ctx->dce_version); + amd_device_id.dal_version_byte1 = 0x0; // needed? where to get? + amd_device_id.dal_version_byte2 = 0x0; // needed? where to get? + + core_link_read_dpcd(link, DP_SOURCE_OUI, + (uint8_t *)(&amd_signature), + sizeof(amd_signature)); + + if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) && + (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) && + (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) { + + amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0; + amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0; + amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A; + + core_link_write_dpcd(link, DP_SOURCE_OUI, + (uint8_t *)(&amd_signature), + sizeof(amd_signature)); + } + + core_link_write_dpcd(link, DP_SOURCE_OUI+0x03, + (uint8_t *)(&amd_device_id), + sizeof(amd_device_id)); + + if (link->ctx->dce_version >= DCN_VERSION_2_0 && + link->dc->caps.min_horizontal_blanking_period != 0) { + + uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period; + + result_write_min_hblank = core_link_write_dpcd(link, + DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size), + sizeof(hblank_size)); + } + DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, + WPP_BIT_FLAG_DC_DETECTION_DP_CAPS, + "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'", + result_write_min_hblank, + link->link_index, + link->ctx->dce_version, + DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, + link->dc->caps.min_horizontal_blanking_period, + link->dpcd_caps.branch_dev_id, + link->dpcd_caps.branch_dev_name[0], + link->dpcd_caps.branch_dev_name[1], + link->dpcd_caps.branch_dev_name[2], + link->dpcd_caps.branch_dev_name[3], + link->dpcd_caps.branch_dev_name[4], + link->dpcd_caps.branch_dev_name[5]); + } else { + core_link_write_dpcd(link, DP_SOURCE_OUI, + link->dc->vendor_signature.data.raw, + sizeof(link->dc->vendor_signature.data.raw)); + } +} + +void dpcd_write_cable_id_to_dprx(struct dc_link *link) +{ + if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED || + link->dpcd_caps.cable_id.raw == 0 || + link->dprx_states.cable_id_written) + return; + + core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX, + &link->dpcd_caps.cable_id.raw, + sizeof(link->dpcd_caps.cable_id.raw)); + + link->dprx_states.cable_id_written = 1; +} + +static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id) +{ + union dmub_rb_cmd cmd; + + if (!link->ctx->dmub_srv || + link->ep_type != DISPLAY_ENDPOINT_PHY || + link->link_enc->features.flags.bits.DP_IS_USB_C == 0) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID; + cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data); + cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx( + link->dc, link->link_enc->transmitter); + if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) && + cmd.cable_id.header.ret_status == 1) { + cable_id->raw = cmd.cable_id.data.output_raw; + DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw); + } + return cmd.cable_id.header.ret_status == 1; +} + +static void retrieve_cable_id(struct dc_link *link) +{ + union dp_cable_id usbc_cable_id; + + link->dpcd_caps.cable_id.raw = 0; + core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX, + &link->dpcd_caps.cable_id.raw, sizeof(uint8_t)); + + if (get_usbc_cable_id(link, &usbc_cable_id)) + link->dpcd_caps.cable_id = intersect_cable_id( + &link->dpcd_caps.cable_id, &usbc_cable_id); +} + +bool read_is_mst_supported(struct dc_link *link) +{ + bool mst = false; + enum dc_status st = DC_OK; + union dpcd_rev rev; + union mstm_cap cap; + + if (link->preferred_training_settings.mst_enable && + *link->preferred_training_settings.mst_enable == false) { + return false; + } + + rev.raw = 0; + cap.raw = 0; + + st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw, + sizeof(rev)); + + if (st == DC_OK && rev.raw >= DPCD_REV_12) { + + st = core_link_read_dpcd(link, DP_MSTM_CAP, + &cap.raw, sizeof(cap)); + if (st == DC_OK && cap.bits.MST_CAP == 1) + mst = true; + } + return mst; + +} + +/* Read additional sink caps defined in source specific DPCD area + * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP) + * TODO: Add FS caps and read from DP_SOURCE_SINK_FS_CAP as well + */ +static bool dpcd_read_sink_ext_caps(struct dc_link *link) +{ + uint8_t dpcd_data; + + if (!link) + return false; + + if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK) + return false; + + link->dpcd_sink_ext_caps.raw = dpcd_data; + return true; +} + +enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link) +{ + uint8_t lttpr_dpcd_data[8]; + enum dc_status status; + bool is_lttpr_present; + + /* Logic to determine LTTPR support*/ + bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; + + if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support) + return DC_ERROR_UNEXPECTED; + + /* By reading LTTPR capability, RX assumes that we will enable + * LTTPR extended aux timeout if LTTPR is present. + */ + status = core_link_read_dpcd( + link, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + lttpr_dpcd_data, + sizeof(lttpr_dpcd_data)); + + link->dpcd_caps.lttpr_caps.revision.raw = + lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_link_rate = + lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.phy_repeater_cnt = + lttpr_dpcd_data[DP_PHY_REPEATER_CNT - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_lane_count = + lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.mode = + lttpr_dpcd_data[DP_PHY_REPEATER_MODE - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_ext_timeout = + lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw = + lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw = + lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + /* If this chip cap is set, at least one retimer must exist in the chain + * Override count to 1 if we receive a known bad count (0 or an invalid value) */ + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) { + ASSERT(0); + link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80; + DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + } + + /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */ + is_lttpr_present = dp_is_lttpr_present(link); + + if (is_lttpr_present) + CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); + + DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present); + return status; +} + +static bool retrieve_link_cap(struct dc_link *link) +{ + /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, + * which means size 16 will be good for both of those DPCD register block reads + */ + uint8_t dpcd_data[16]; + /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. + */ + uint8_t dpcd_dprx_data = '\0'; + + struct dp_device_vendor_id sink_id; + union down_stream_port_count down_strm_port_count; + union edp_configuration_cap edp_config_cap; + union dp_downstream_port_present ds_port = { 0 }; + enum dc_status status = DC_ERROR_UNEXPECTED; + uint32_t read_dpcd_retry_cnt = 3; + int i; + struct dp_sink_hw_fw_revision dp_hw_fw_revision; + const uint32_t post_oui_delay = 30; // 30ms + + memset(dpcd_data, '\0', sizeof(dpcd_data)); + memset(&down_strm_port_count, + '\0', sizeof(union down_stream_port_count)); + memset(&edp_config_cap, '\0', + sizeof(union edp_configuration_cap)); + + /* if extended timeout is supported in hardware, + * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer + * CTS 4.2.1.1 regression introduced by CTS specs requirement update. + */ + try_to_configure_aux_timeout(link->ddc, + LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); + + status = dp_retrieve_lttpr_cap(link); + + if (status != DC_OK) { + status = wake_up_aux_channel(link); + if (status == DC_OK) + dp_retrieve_lttpr_cap(link); + else + return false; + } + + if (dp_is_lttpr_present(link)) + configure_lttpr_mode_transparent(link); + + /* Read DP tunneling information. */ + status = dpcd_get_tunneling_device_data(link); + + dpcd_set_source_specific_data(link); + /* Sink may need to configure internals based on vendor, so allow some + * time before proceeding with possibly vendor specific transactions + */ + msleep(post_oui_delay); + + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( + link, + DP_DPCD_REV, + dpcd_data, + sizeof(dpcd_data)); + if (status == DC_OK) + break; + } + + + if (status != DC_OK) { + dm_error("%s: Read receiver caps dpcd data failed.\n", __func__); + return false; + } + + if (!dp_is_lttpr_present(link)) + try_to_configure_aux_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD); + + + { + union training_aux_rd_interval aux_rd_interval; + + aux_rd_interval.raw = + dpcd_data[DP_TRAINING_AUX_RD_INTERVAL]; + + link->dpcd_caps.ext_receiver_cap_field_present = + aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1 ? true:false; + + if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) { + uint8_t ext_cap_data[16]; + + memset(ext_cap_data, '\0', sizeof(ext_cap_data)); + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( + link, + DP_DP13_DPCD_REV, + ext_cap_data, + sizeof(ext_cap_data)); + if (status == DC_OK) { + memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data)); + break; + } + } + if (status != DC_OK) + dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__); + } + } + + link->dpcd_caps.dpcd_rev.raw = + dpcd_data[DP_DPCD_REV - DP_DPCD_REV]; + + if (link->dpcd_caps.ext_receiver_cap_field_present) { + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( + link, + DP_DPRX_FEATURE_ENUMERATION_LIST, + &dpcd_dprx_data, + sizeof(dpcd_dprx_data)); + if (status == DC_OK) + break; + } + + link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data; + + if (status != DC_OK) + dm_error("%s: Read DPRX caps data failed.\n", __func__); + } + + else { + link->dpcd_caps.dprx_feature.raw = 0; + } + + + /* Error condition checking... + * It is impossible for Sink to report Max Lane Count = 0. + * It is possible for Sink to report Max Link Rate = 0, if it is + * an eDP device that is reporting specialized link rates in the + * SUPPORTED_LINK_RATE table. + */ + if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0) + return false; + + ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT - + DP_DPCD_REV]; + + read_dp_device_vendor_id(link); + + /* TODO - decouple raw mst capability from policy decision */ + link->dpcd_caps.is_mst_capable = read_is_mst_supported(link); + + get_active_converter_info(ds_port.byte, link); + + dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data)); + + down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT - + DP_DPCD_REV]; + + link->dpcd_caps.allow_invalid_MSA_timing_param = + down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM; + + link->dpcd_caps.max_ln_count.raw = dpcd_data[ + DP_MAX_LANE_COUNT - DP_DPCD_REV]; + + link->dpcd_caps.max_down_spread.raw = dpcd_data[ + DP_MAX_DOWNSPREAD - DP_DPCD_REV]; + + link->reported_link_cap.lane_count = + link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT; + link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw( + dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]); + link->reported_link_cap.link_spread = + link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ? + LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; + + edp_config_cap.raw = dpcd_data[ + DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV]; + link->dpcd_caps.panel_mode_edp = + edp_config_cap.bits.ALT_SCRAMBLER_RESET; + link->dpcd_caps.dpcd_display_control_capable = + edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; + link->dpcd_caps.channel_coding_cap.raw = + dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV]; + link->test_pattern_enabled = false; + link->compliance_test_state.raw = 0; + + /* read sink count */ + core_link_read_dpcd(link, + DP_SINK_COUNT, + &link->dpcd_caps.sink_count.raw, + sizeof(link->dpcd_caps.sink_count.raw)); + + /* read sink ieee oui */ + core_link_read_dpcd(link, + DP_SINK_OUI, + (uint8_t *)(&sink_id), + sizeof(sink_id)); + + link->dpcd_caps.sink_dev_id = + (sink_id.ieee_oui[0] << 16) + + (sink_id.ieee_oui[1] << 8) + + (sink_id.ieee_oui[2]); + + memmove( + link->dpcd_caps.sink_dev_id_str, + sink_id.ieee_device_id, + sizeof(sink_id.ieee_device_id)); + + core_link_read_dpcd( + link, + DP_SINK_HW_REVISION_START, + (uint8_t *)&dp_hw_fw_revision, + sizeof(dp_hw_fw_revision)); + + link->dpcd_caps.sink_hw_revision = + dp_hw_fw_revision.ieee_hw_rev; + + memmove( + link->dpcd_caps.sink_fw_revision, + dp_hw_fw_revision.ieee_fw_rev, + sizeof(dp_hw_fw_revision.ieee_fw_rev)); + + /* Quirk for Retina panels: wrong DP_MAX_LINK_RATE */ + { + uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 }; + uint8_t fwrev_mbp_2018[] = { 7, 4 }; + uint8_t fwrev_mbp_2018_vega[] = { 8, 4 }; + + /* We also check for the firmware revision as 16,1 models have an + * identical device id and are incorrectly quirked otherwise. + */ + if ((link->dpcd_caps.sink_dev_id == 0x0010fa) && + !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018, + sizeof(str_mbp_2018)) && + (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018, + sizeof(fwrev_mbp_2018)) || + !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega, + sizeof(fwrev_mbp_2018_vega)))) { + link->reported_link_cap.link_rate = LINK_RATE_RBR2; + } + } + + memset(&link->dpcd_caps.dsc_caps, '\0', + sizeof(link->dpcd_caps.dsc_caps)); + memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap)); + /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */ + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) { + status = core_link_read_dpcd( + link, + DP_FEC_CAPABILITY, + &link->dpcd_caps.fec_cap.raw, + sizeof(link->dpcd_caps.fec_cap.raw)); + status = core_link_read_dpcd( + link, + DP_DSC_SUPPORT, + link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, + sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw)); + if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { + status = core_link_read_dpcd( + link, + DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, + link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, + sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw)); + DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index); + DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x", + link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0); + DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x", + link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1); + DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x", + link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH); + } + + /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode + * only if required. + */ + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && + link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around && + link->dpcd_caps.is_branch_dev && + link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 && + link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 && + (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE || + link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) { + /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA. + * Clear FEC and DSC capabilities as a work around if that is not the case. + */ + link->wa_flags.dpia_forced_tbt3_mode = true; + memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps)); + memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap)); + DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index); + } else + link->wa_flags.dpia_forced_tbt3_mode = false; + } + + if (!dpcd_read_sink_ext_caps(link)) + link->dpcd_sink_ext_caps.raw = 0; + + if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { + DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index); + + core_link_read_dpcd(link, + DP_128B132B_SUPPORTED_LINK_RATES, + &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw, + sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw)); + if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20) + link->reported_link_cap.link_rate = LINK_RATE_UHBR20; + else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5) + link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5; + else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10) + link->reported_link_cap.link_rate = LINK_RATE_UHBR10; + else + dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__); + DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index); + DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz", + link->reported_link_cap.link_rate / 100, + link->reported_link_cap.link_rate % 100); + + core_link_read_dpcd(link, + DP_SINK_VIDEO_FALLBACK_FORMATS, + &link->dpcd_caps.fallback_formats.raw, + sizeof(link->dpcd_caps.fallback_formats.raw)); + DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index); + if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support) + DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported"); + if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support) + DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported"); + if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support) + DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported"); + if (link->dpcd_caps.fallback_formats.raw == 0) { + DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported"); + link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1; + } + + core_link_read_dpcd(link, + DP_FEC_CAPABILITY_1, + &link->dpcd_caps.fec_cap1.raw, + sizeof(link->dpcd_caps.fec_cap1.raw)); + DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index); + if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE) + DC_LOG_DP2("\tFEC aggregated error counters are supported"); + } + + retrieve_cable_id(link); + dpcd_write_cable_id_to_dprx(link); + + /* Connectivity log: detection */ + CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); + + return true; +} + +bool detect_dp_sink_caps(struct dc_link *link) +{ + return retrieve_link_cap(link); +} + +void detect_edp_sink_caps(struct dc_link *link) +{ + uint8_t supported_link_rates[16]; + uint32_t entry; + uint32_t link_rate_in_khz; + enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; + uint8_t backlight_adj_cap; + uint8_t general_edp_cap; + + retrieve_link_cap(link); + link->dpcd_caps.edp_supported_link_rates_count = 0; + memset(supported_link_rates, 0, sizeof(supported_link_rates)); + + /* + * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. + * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" + */ + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && + (link->panel_config.ilr.optimize_edp_link_rate || + link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) { + // Read DPCD 00010h - 0001Fh 16 bytes at one shot + core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, + supported_link_rates, sizeof(supported_link_rates)); + + for (entry = 0; entry < 16; entry += 2) { + // DPCD register reports per-lane link rate = 16-bit link rate capability + // value X 200 kHz. Need multiplier to find link rate in kHz. + link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 + + supported_link_rates[entry]) * 200; + + if (link_rate_in_khz != 0) { + link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); + link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate; + link->dpcd_caps.edp_supported_link_rates_count++; + + if (link->reported_link_cap.link_rate < link_rate) + link->reported_link_cap.link_rate = link_rate; + } + } + } + core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP, + &backlight_adj_cap, sizeof(backlight_adj_cap)); + + link->dpcd_caps.dynamic_backlight_capable_edp = + (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false; + + core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1, + &general_edp_cap, sizeof(general_edp_cap)); + + link->dpcd_caps.set_power_state_capable_edp = + (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false; + + dc_link_set_default_brightness_aux(link); + + core_link_read_dpcd(link, DP_EDP_DPCD_REV, + &link->dpcd_caps.edp_rev, + sizeof(link->dpcd_caps.edp_rev)); + /* + * PSR is only valid for eDP v1.3 or higher. + */ + if (link->dpcd_caps.edp_rev >= DP_EDP_13) { + core_link_read_dpcd(link, DP_PSR_SUPPORT, + &link->dpcd_caps.psr_info.psr_version, + sizeof(link->dpcd_caps.psr_info.psr_version)); + if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) + core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY, + &link->dpcd_caps.psr_info.force_psrsu_cap, + sizeof(link->dpcd_caps.psr_info.force_psrsu_cap)); + core_link_read_dpcd(link, DP_PSR_CAPS, + &link->dpcd_caps.psr_info.psr_dpcd_caps.raw, + sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw)); + if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) { + core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY, + &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap, + sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap)); + } + } + + /* + * ALPM is only valid for eDP v1.4 or higher. + */ + if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14) + core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP, + &link->dpcd_caps.alpm_caps.raw, + sizeof(link->dpcd_caps.alpm_caps.raw)); +} + +bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) +{ + struct link_encoder *link_enc = NULL; + + if (!max_link_enc_cap) { + DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__); + return false; + } + + link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link_enc); + + if (link_enc && link_enc->funcs->get_max_link_cap) { + link_enc->funcs->get_max_link_cap(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; +} + +const struct dc_link_settings *dc_link_get_link_cap( + const struct dc_link *link) +{ + if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN && + link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) + return &link->preferred_link_setting; + return &link->verified_link_cap; +} + +struct dc_link_settings dp_get_max_link_cap(struct dc_link *link) +{ + struct dc_link_settings max_link_cap = {0}; + enum dc_link_rate lttpr_max_link_rate; + enum dc_link_rate cable_max_link_rate; + struct link_encoder *link_enc = NULL; + + + link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link_enc); + + /* get max link encoder capability */ + if (link_enc) + link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap); + + /* Lower link settings based on sink's link cap */ + if (link->reported_link_cap.lane_count < max_link_cap.lane_count) + max_link_cap.lane_count = + link->reported_link_cap.lane_count; + if (link->reported_link_cap.link_rate < max_link_cap.link_rate) + max_link_cap.link_rate = + link->reported_link_cap.link_rate; + if (link->reported_link_cap.link_spread < + max_link_cap.link_spread) + max_link_cap.link_spread = + link->reported_link_cap.link_spread; + + /* Lower link settings based on cable attributes + * Cable ID is a DP2 feature to identify max certified link rate that + * a cable can carry. The cable identification method requires both + * cable and display hardware support. Since the specs comes late, it is + * anticipated that the first round of DP2 cables and displays may not + * be fully compatible to reliably return cable ID data. Therefore the + * decision of our cable id policy is that if the cable can return non + * zero cable id data, we will take cable's link rate capability into + * account. However if we get zero data, the cable link rate capability + * is considered inconclusive. In this case, we will not take cable's + * capability into account to avoid of over limiting hardware capability + * from users. The max overall link rate capability is still determined + * after actual dp pre-training. Cable id is considered as an auxiliary + * method of determining max link bandwidth capability. + */ + cable_max_link_rate = get_cable_max_link_rate(link); + + if (!link->dc->debug.ignore_cable_id && + cable_max_link_rate != LINK_RATE_UNKNOWN && + cable_max_link_rate < max_link_cap.link_rate) + max_link_cap.link_rate = cable_max_link_rate; + + /* account for lttpr repeaters cap + * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). + */ + if (dp_is_lttpr_present(link)) { + if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count) + max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count; + lttpr_max_link_rate = get_lttpr_max_link_rate(link); + + if (lttpr_max_link_rate < max_link_cap.link_rate) + max_link_cap.link_rate = lttpr_max_link_rate; + + DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n", + __func__, + max_link_cap.lane_count, + max_link_cap.link_rate); + } + + if (link_dp_get_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING && + link->dc->debug.disable_uhbr) + max_link_cap.link_rate = LINK_RATE_HIGH3; + + return max_link_cap; +} + +static bool dp_verify_link_cap( + struct dc_link *link, + struct dc_link_settings *known_limit_link_setting, + int *fail_count) +{ + struct dc_link_settings cur_link_settings = {0}; + struct dc_link_settings max_link_settings = *known_limit_link_setting; + bool success = false; + bool skip_video_pattern; + enum clock_source_id dp_cs_id = get_clock_source_id(link); + enum link_training_result status = LINK_TRAINING_SUCCESS; + union hpd_irq_data irq_data; + struct link_resource link_res; + + memset(&irq_data, 0, sizeof(irq_data)); + cur_link_settings = max_link_settings; + + /* Grant extended timeout request */ + if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) { + uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80; + + core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant)); + } + + do { + if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings)) + continue; + + skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW; + dp_enable_link_phy( + link, + &link_res, + link->connector_signal, + dp_cs_id, + &cur_link_settings); + + status = dp_perform_link_training( + link, + &link_res, + &cur_link_settings, + skip_video_pattern); + + if (status == LINK_TRAINING_SUCCESS) { + success = true; + udelay(1000); + if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK && + hpd_rx_irq_check_link_loss_status( + link, + &irq_data)) + (*fail_count)++; + + } else { + (*fail_count)++; + } + dp_trace_lt_total_count_increment(link, true); + dp_trace_lt_result_update(link, status, true); + dp_disable_link_phy(link, &link_res, link->connector_signal); + } while (!success && decide_fallback_link_setting(link, + &max_link_settings, &cur_link_settings, status)); + + link->verified_link_cap = success ? + cur_link_settings : fail_safe_link_settings; + return success; +} + +bool dp_verify_link_cap_with_retries( + struct dc_link *link, + struct dc_link_settings *known_limit_link_setting, + int attempts) +{ + int i = 0; + bool success = false; + int fail_count = 0; + + dp_trace_detect_lt_init(link); + + if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C && + link->dc->debug.usbc_combo_phy_reset_wa) + apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting); + + dp_trace_set_lt_start_timestamp(link, false); + for (i = 0; i < attempts; i++) { + enum dc_connection_type type = dc_connection_none; + + memset(&link->verified_link_cap, 0, + sizeof(struct dc_link_settings)); + if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) { + link->verified_link_cap = fail_safe_link_settings; + break; + } else if (dp_verify_link_cap(link, known_limit_link_setting, + &fail_count) && fail_count == 0) { + success = true; + break; + } + msleep(10); + } + + dp_trace_lt_fail_count_update(link, fail_count, true); + dp_trace_set_lt_end_timestamp(link, true); + + return success; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.h new file mode 100644 index 000000000000..5500744d2e47 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.h @@ -0,0 +1,66 @@ +/* + * Copyright 2022 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: AMD + * + */ + +#ifndef __DC_LINK_DP_CAPABILITY_H__ +#define __DC_LINK_DP_CAPABILITY_H__ + +#include "link.h" + +bool detect_dp_sink_caps(struct dc_link *link); + +void detect_edp_sink_caps(struct dc_link *link); + +struct dc_link_settings dp_get_max_link_cap(struct dc_link *link); + + +enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link); + +/* Convert PHY repeater count read from DPCD uint8_t. */ +uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count); + +bool dp_is_lttpr_present(struct dc_link *link); + +bool is_dp_active_dongle(const struct dc_link *link); + +bool is_dp_branch_device(const struct dc_link *link); + +bool decide_edp_link_settings_with_dsc(struct dc_link *link, + struct dc_link_settings *link_setting, + uint32_t req_bw, + enum dc_link_rate max_link_rate); + +void dpcd_set_source_specific_data(struct dc_link *link); + +/*query dpcd for version and mst cap addresses*/ +bool read_is_mst_supported(struct dc_link *link); + +bool decide_fallback_link_setting( + struct dc_link *link, + struct dc_link_settings *max, + struct dc_link_settings *cur, + enum link_training_result training_result); + + +#endif /* __DC_LINK_DP_CAPABILITY_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.c new file mode 100644 index 000000000000..6136db392548 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.c @@ -0,0 +1,107 @@ +// 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: AMD + * + */ + +#include "dc.h" +#include "inc/core_status.h" +#include "dc_link.h" +#include "dc_link_dp.h" +#include "dpcd_defs.h" + +#include "link_dp_dpia.h" +#include "link_hwss.h" +#include "dm_helpers.h" +#include "dmub/inc/dmub_cmd.h" +#include "link_dpcd.h" +#include "link_dp_training.h" +#include "dc_dmub_srv.h" + +#define DC_LOGGER \ + link->ctx->logger + +/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */ +/* DPCD DP Tunneling over USB4 */ +#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d +#define DP_IN_ADAPTER_INFO 0xe000e +#define DP_USB4_DRIVER_ID 0xe000f +#define DP_USB4_ROUTER_TOPOLOGY_ID 0xe001b + +enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link) +{ + enum dc_status status = DC_OK; + uint8_t dpcd_dp_tun_data[3] = {0}; + uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0}; + uint8_t i = 0; + + status = core_link_read_dpcd( + link, + DP_TUNNELING_CAPABILITIES_SUPPORT, + dpcd_dp_tun_data, + sizeof(dpcd_dp_tun_data)); + + status = core_link_read_dpcd( + link, + DP_USB4_ROUTER_TOPOLOGY_ID, + dpcd_topology_data, + sizeof(dpcd_topology_data)); + + link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw = + dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - DP_TUNNELING_CAPABILITIES_SUPPORT]; + link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw = + dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT]; + link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id = + dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT]; + + for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++) + link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i]; + + return status; +} + +bool dc_link_dpia_query_hpd_status(struct dc_link *link) +{ + union dmub_rb_cmd cmd = {0}; + struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv; + bool is_hpd_high = false; + + /* prepare QUERY_HPD command */ + cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE; + cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1; + cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA; + + /* Return HPD status reported by DMUB if query successfully executed. */ + if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS) + is_hpd_high = cmd.query_hpd.data.result; + + DC_LOG_DEBUG("%s: link(%d) dpia(%d) cmd_status(%d) result(%d)\n", + __func__, + link->link_index, + link->link_id.enum_id - ENUM_ID_1, + cmd.query_hpd.data.status, + cmd.query_hpd.data.result); + + return is_hpd_high; +} + diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.h new file mode 100644 index 000000000000..98935cc10bb7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.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: AMD + * + */ + +#ifndef __DC_LINK_DPIA_H__ +#define __DC_LINK_DPIA_H__ + +#include "link.h" + +/* Read tunneling device capability from DPCD and update link capability + * accordingly. + */ +enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link); + +/* Query hot plug status of USB4 DP tunnel. + * Returns true if HPD high. + */ +bool dc_link_dpia_query_hpd_status(struct dc_link *link); + + +#endif /* __DC_LINK_DPIA_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h index 669e995f825f..58eb7b581093 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h @@ -26,13 +26,13 @@ #ifndef DC_INC_LINK_DP_DPIA_BW_H_ #define DC_INC_LINK_DP_DPIA_BW_H_ -// XXX: TODO: Re-add for Phase 2 -/* Number of Host Routers per motherboard is 2 and 2 DPIA per host router */ -#define MAX_HR_NUM 2 - -struct dc_host_router_bw_alloc { - int max_bw[MAX_HR_NUM]; // The Max BW that each Host Router has available to be shared btw DPIAs - int total_estimated_bw[MAX_HR_NUM]; // The Total Verified and available BW that Host Router has +/* + * Host Router BW type + */ +enum bw_type { + HOST_ROUTER_BW_ESTIMATED, + HOST_ROUTER_BW_ALLOCATED, + HOST_ROUTER_BW_INVALID, }; /* @@ -61,9 +61,40 @@ void set_usb4_req_bw_req(struct dc_link *link, int req_bw); * find out the result of allocating on CM and update structs accordingly * * @link: pointer to the dc_link struct instance + * @bw: Allocated or Estimated BW depending on the result + * @result: Response type + * + * return: none + */ +void get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result); + +/* + * Return the response_ready flag from dc_link struct + * + * @link: pointer to the dc_link struct instance + * + * return: response_ready flag from dc_link struct + */ +bool get_cm_response_ready_flag(struct dc_link *link); + +/* + * Get the Max Available BW or Max Estimated BW for each Host Router + * + * @link: pointer to the dc_link struct instance + * @type: ESTIMATD BW or MAX AVAILABLE BW + * + * return: response_ready flag from dc_link struct + */ +int get_host_router_total_bw(struct dc_link *link, uint8_t type); + +/* + * Cleanup function for when the dpia is unplugged to reset struct + * and perform any required clean up + * + * @link: pointer to the dc_link struct instance * * return: none */ -void get_usb4_req_bw_resp(struct dc_link *link); +bool dpia_bw_alloc_unplug(struct dc_link *link); #endif /* DC_INC_LINK_DP_DPIA_BW_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.c new file mode 100644 index 000000000000..afe3b21335c2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.c @@ -0,0 +1,145 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * This file implements basic dp phy functionality such as enable/disable phy + * output and set lane/drive settings. This file is responsible for maintaining + * and update software state representing current phy status such as current + * link settings. + */ + +#include "link_dp_phy.h" +#include "link_dpcd.h" +#include "link_dp_training.h" +#include "link_dp_capability.h" +#include "clk_mgr.h" +#include "resource.h" +#include "dc_link_dp.h" + +#define DC_LOGGER \ + link->ctx->logger + +void dc_link_dp_set_drive_settings( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + /* program ASIC PHY settings*/ + dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); + + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, + lt_settings->dpcd_lane_settings); + + /* Notify DP sink the PHY settings from source */ + dpcd_set_lane_settings(link, lt_settings, DPRX); +} + +void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on) +{ + uint8_t state; + + state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3; + + if (link->sync_lt_in_progress) + return; + + core_link_write_dpcd(link, DP_SET_POWER, &state, + sizeof(state)); + +} + +void dp_enable_link_phy( + struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings) +{ + link->cur_link_settings = *link_settings; + link->dc->hwss.enable_dp_link_output(link, link_res, signal, + clock_source, link_settings); + dc_link_dp_receiver_power_ctrl(link, true); +} + +void dp_disable_link_phy(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + + if (!link->wa_flags.dp_keep_receiver_powered) + dc_link_dp_receiver_power_ctrl(link, false); + + dc->hwss.disable_link_output(link, link_res, signal); + /* Clear current link setting.*/ + memset(&link->cur_link_settings, 0, + sizeof(link->cur_link_settings)); + + if (dc->clk_mgr->funcs->notify_link_rate_change) + dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); +} + +void dp_disable_link_phy_mst(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + /* MST disable link only when no stream use the link */ + if (link->mst_stream_alloc_table.stream_count > 0) + return; + + dp_disable_link_phy(link, link_res, signal); + + /* set the sink to SST mode after disabling the link */ + dp_enable_mst_on_sink(link, false); +} + +static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset) +{ + return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == + offset); +} + +void dp_set_hw_lane_settings( + struct dc_link *link, + const struct link_resource *link_res, + const struct link_training_settings *link_settings, + uint32_t offset) +{ + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + + if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && + !is_immediate_downstream(link, offset)) + return; + + if (link_hwss->ext.set_dp_lane_settings) + link_hwss->ext.set_dp_lane_settings(link, link_res, + &link_settings->link_settings, + link_settings->hw_lane_settings); + + memmove(link->cur_lane_setting, + link_settings->hw_lane_settings, + sizeof(link->cur_lane_setting)); +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.h new file mode 100644 index 000000000000..717e078fd564 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.h @@ -0,0 +1,51 @@ +/* + * Copyright 2022 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: AMD + * + */ + +#ifndef __DC_LINK_DP_PHY_H__ +#define __DC_LINK_DP_PHY_H__ + +#include "link.h" +void dp_enable_link_phy( + struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings); + +void dp_disable_link_phy(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + +void dp_disable_link_phy_mst(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + +void dp_set_hw_lane_settings( + struct dc_link *link, + const struct link_resource *link_res, + const struct link_training_settings *link_settings, + uint32_t offset); + +#endif /* __DC_LINK_DP_PHY_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training.c new file mode 100644 index 000000000000..e49e0258a1bd --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training.c @@ -0,0 +1,1700 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * This file implements all generic dp link training helper functions and top + * level generic training sequence. All variations of dp link training sequence + * should be called inside the top level training functions in this file to + * ensure the integrity of our overall training procedure across different types + * of link encoding and back end hardware. + */ +#include "link_dp_training.h" +#include "link_dp_training_8b_10b.h" +#include "link_dp_training_128b_132b.h" +#include "link_dp_training_auxless.h" +#include "link_dp_training_dpia.h" +#include "link_dp_training_fixed_vs_pe_retimer.h" +#include "link_dpcd.h" +#include "link_dp_trace.h" +#include "link_dp_phy.h" +#include "link_dp_capability.h" +#include "dc_link_dp.h" +#include "atomfirmware.h" +#include "link_enc_cfg.h" +#include "resource.h" +#include "dm_helpers.h" + +#define DC_LOGGER \ + link->ctx->logger + +#define POST_LT_ADJ_REQ_LIMIT 6 +#define POST_LT_ADJ_REQ_TIMEOUT 200 + +void dp_log_training_result( + struct dc_link *link, + const struct link_training_settings *lt_settings, + enum link_training_result status) +{ + char *link_rate = "Unknown"; + char *lt_result = "Unknown"; + char *lt_spread = "Disabled"; + + switch (lt_settings->link_settings.link_rate) { + case LINK_RATE_LOW: + link_rate = "RBR"; + break; + case LINK_RATE_RATE_2: + link_rate = "R2"; + break; + case LINK_RATE_RATE_3: + link_rate = "R3"; + break; + case LINK_RATE_HIGH: + link_rate = "HBR"; + break; + case LINK_RATE_RBR2: + link_rate = "RBR2"; + break; + case LINK_RATE_RATE_6: + link_rate = "R6"; + break; + case LINK_RATE_HIGH2: + link_rate = "HBR2"; + break; + case LINK_RATE_HIGH3: + link_rate = "HBR3"; + break; + case LINK_RATE_UHBR10: + link_rate = "UHBR10"; + break; + case LINK_RATE_UHBR13_5: + link_rate = "UHBR13.5"; + break; + case LINK_RATE_UHBR20: + link_rate = "UHBR20"; + break; + default: + break; + } + + switch (status) { + case LINK_TRAINING_SUCCESS: + lt_result = "pass"; + break; + case LINK_TRAINING_CR_FAIL_LANE0: + lt_result = "CR failed lane0"; + break; + case LINK_TRAINING_CR_FAIL_LANE1: + lt_result = "CR failed lane1"; + break; + case LINK_TRAINING_CR_FAIL_LANE23: + lt_result = "CR failed lane23"; + break; + case LINK_TRAINING_EQ_FAIL_CR: + lt_result = "CR failed in EQ"; + break; + case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: + lt_result = "CR failed in EQ partially"; + break; + case LINK_TRAINING_EQ_FAIL_EQ: + lt_result = "EQ failed"; + break; + case LINK_TRAINING_LQA_FAIL: + lt_result = "LQA failed"; + break; + case LINK_TRAINING_LINK_LOSS: + lt_result = "Link loss"; + break; + case DP_128b_132b_LT_FAILED: + lt_result = "LT_FAILED received"; + break; + case DP_128b_132b_MAX_LOOP_COUNT_REACHED: + lt_result = "max loop count reached"; + break; + case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT: + lt_result = "channel EQ timeout"; + break; + case DP_128b_132b_CDS_DONE_TIMEOUT: + lt_result = "CDS timeout"; + break; + default: + break; + } + + switch (lt_settings->link_settings.link_spread) { + case LINK_SPREAD_DISABLED: + lt_spread = "Disabled"; + break; + case LINK_SPREAD_05_DOWNSPREAD_30KHZ: + lt_spread = "0.5% 30KHz"; + break; + case LINK_SPREAD_05_DOWNSPREAD_33KHZ: + lt_spread = "0.5% 33KHz"; + break; + default: + break; + } + + /* Connectivity log: link training */ + + /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */ + + CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s", + link_rate, + lt_settings->link_settings.lane_count, + lt_result, + lt_settings->hw_lane_settings[0].VOLTAGE_SWING, + lt_settings->hw_lane_settings[0].PRE_EMPHASIS, + lt_spread); +} + +uint8_t dp_initialize_scrambling_data_symbols( + struct dc_link *link, + enum dc_dp_training_pattern pattern) +{ + uint8_t disable_scrabled_data_symbols = 0; + + switch (pattern) { + case DP_TRAINING_PATTERN_SEQUENCE_1: + case DP_TRAINING_PATTERN_SEQUENCE_2: + case DP_TRAINING_PATTERN_SEQUENCE_3: + disable_scrabled_data_symbols = 1; + break; + case DP_TRAINING_PATTERN_SEQUENCE_4: + case DP_128b_132b_TPS1: + case DP_128b_132b_TPS2: + disable_scrabled_data_symbols = 0; + break; + default: + ASSERT(0); + DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", + __func__, pattern); + break; + } + return disable_scrabled_data_symbols; +} + +enum dpcd_training_patterns + dp_training_pattern_to_dpcd_training_pattern( + struct dc_link *link, + enum dc_dp_training_pattern pattern) +{ + enum dpcd_training_patterns dpcd_tr_pattern = + DPCD_TRAINING_PATTERN_VIDEOIDLE; + + switch (pattern) { + case DP_TRAINING_PATTERN_SEQUENCE_1: + dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; + break; + case DP_TRAINING_PATTERN_SEQUENCE_2: + dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; + break; + case DP_TRAINING_PATTERN_SEQUENCE_3: + dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; + break; + case DP_TRAINING_PATTERN_SEQUENCE_4: + dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; + break; + case DP_128b_132b_TPS1: + dpcd_tr_pattern = DPCD_128b_132b_TPS1; + break; + case DP_128b_132b_TPS2: + dpcd_tr_pattern = DPCD_128b_132b_TPS2; + break; + case DP_128b_132b_TPS2_CDS: + dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS; + break; + case DP_TRAINING_PATTERN_VIDEOIDLE: + dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; + break; + default: + ASSERT(0); + DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", + __func__, pattern); + break; + } + + return dpcd_tr_pattern; +} + +static uint8_t get_nibble_at_index(const uint8_t *buf, + uint32_t index) +{ + uint8_t nibble; + nibble = buf[index / 2]; + + if (index % 2) + nibble >>= 4; + else + nibble &= 0x0F; + + return nibble; +} + +void dp_wait_for_training_aux_rd_interval( + struct dc_link *link, + uint32_t wait_in_micro_secs) +{ + if (wait_in_micro_secs > 1000) + msleep(wait_in_micro_secs/1000); + else + udelay(wait_in_micro_secs); + + DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", + __func__, + wait_in_micro_secs); +} + +/* maximum pre emphasis level allowed for each voltage swing level*/ +static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { + PRE_EMPHASIS_LEVEL3, + PRE_EMPHASIS_LEVEL2, + PRE_EMPHASIS_LEVEL1, + PRE_EMPHASIS_DISABLED }; + +static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing( + enum dc_voltage_swing voltage) +{ + enum dc_pre_emphasis pre_emphasis; + pre_emphasis = PRE_EMPHASIS_MAX_LEVEL; + + if (voltage <= VOLTAGE_SWING_MAX_LEVEL) + pre_emphasis = voltage_swing_to_pre_emphasis[voltage]; + + return pre_emphasis; + +} + +static void maximize_lane_settings(const struct link_training_settings *lt_settings, + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) +{ + uint32_t lane; + struct dc_lane_settings max_requested; + + max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING; + max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS; + max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET; + + /* Determine what the maximum of the requested settings are*/ + for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) { + if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING) + max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING; + + if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS) + max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS; + if (lane_settings[lane].FFE_PRESET.settings.level > + max_requested.FFE_PRESET.settings.level) + max_requested.FFE_PRESET.settings.level = + lane_settings[lane].FFE_PRESET.settings.level; + } + + /* make sure the requested settings are + * not higher than maximum settings*/ + if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL) + max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL; + + if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL) + max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL; + if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL) + max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL; + + /* make sure the pre-emphasis matches the voltage swing*/ + if (max_requested.PRE_EMPHASIS > + get_max_pre_emphasis_for_voltage_swing( + max_requested.VOLTAGE_SWING)) + max_requested.PRE_EMPHASIS = + get_max_pre_emphasis_for_voltage_swing( + max_requested.VOLTAGE_SWING); + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING; + lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS; + lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET; + } +} + +void dp_hw_to_dpcd_lane_settings( + const struct link_training_settings *lt_settings, + const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]) +{ + uint8_t lane = 0; + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING) { + dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET = + (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING); + dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET = + (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS); + dpcd_lane_settings[lane].bits.MAX_SWING_REACHED = + (hw_lane_settings[lane].VOLTAGE_SWING == + VOLTAGE_SWING_MAX_LEVEL ? 1 : 0); + dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED = + (hw_lane_settings[lane].PRE_EMPHASIS == + PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); + } else if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_128b_132b_ENCODING) { + dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE = + hw_lane_settings[lane].FFE_PRESET.settings.level; + } + } +} + +uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings) +{ + uint8_t link_rate = 0; + enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings); + + if (encoding == DP_128b_132b_ENCODING) + switch (link_settings->link_rate) { + case LINK_RATE_UHBR10: + link_rate = 0x1; + break; + case LINK_RATE_UHBR20: + link_rate = 0x2; + break; + case LINK_RATE_UHBR13_5: + link_rate = 0x4; + break; + default: + link_rate = 0; + break; + } + else if (encoding == DP_8b_10b_ENCODING) + link_rate = (uint8_t) link_settings->link_rate; + else + link_rate = 0; + + return link_rate; +} + +/* Only used for channel equalization */ +uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) +{ + unsigned int aux_rd_interval_us = 400; + + switch (dpcd_aux_read_interval) { + case 0x01: + aux_rd_interval_us = 4000; + break; + case 0x02: + aux_rd_interval_us = 8000; + break; + case 0x03: + aux_rd_interval_us = 12000; + break; + case 0x04: + aux_rd_interval_us = 16000; + break; + case 0x05: + aux_rd_interval_us = 32000; + break; + case 0x06: + aux_rd_interval_us = 64000; + break; + default: + break; + } + + return aux_rd_interval_us; +} + +enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status) +{ + enum link_training_result result = LINK_TRAINING_SUCCESS; + + if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE0; + else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE1; + else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE23; + else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE23; + return result; +} + +bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset) +{ + return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0); +} + +bool dp_is_max_vs_reached( + const struct link_training_settings *lt_settings) +{ + uint32_t lane; + for (lane = 0; lane < + (uint32_t)(lt_settings->link_settings.lane_count); + lane++) { + if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET + == VOLTAGE_SWING_MAX_LEVEL) + return true; + } + return false; + +} + +bool dp_is_cr_done(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status) +{ + bool done = true; + uint32_t lane; + /*LANEx_CR_DONE bits All 1's?*/ + for (lane = 0; lane < (uint32_t)(ln_count); lane++) { + if (!dpcd_lane_status[lane].bits.CR_DONE_0) + done = false; + } + return done; + +} + +bool dp_is_ch_eq_done(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status) +{ + bool done = true; + uint32_t lane; + for (lane = 0; lane < (uint32_t)(ln_count); lane++) + if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0) + done = false; + return done; +} + +bool dp_is_symbol_locked(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status) +{ + bool locked = true; + uint32_t lane; + for (lane = 0; lane < (uint32_t)(ln_count); lane++) + if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0) + locked = false; + return locked; +} + +bool dp_is_interlane_aligned(union lane_align_status_updated align_status) +{ + return align_status.bits.INTERLANE_ALIGN_DONE == 1; +} + +enum link_training_result dp_check_link_loss_status( + struct dc_link *link, + const struct link_training_settings *link_training_setting) +{ + enum link_training_result status = LINK_TRAINING_SUCCESS; + union lane_status lane_status; + uint8_t dpcd_buf[6] = {0}; + uint32_t lane; + + core_link_read_dpcd( + link, + DP_SINK_COUNT, + (uint8_t *)(dpcd_buf), + sizeof(dpcd_buf)); + + /*parse lane status*/ + for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { + /* + * check lanes status + */ + lane_status.raw = get_nibble_at_index(&dpcd_buf[2], lane); + + if (!lane_status.bits.CHANNEL_EQ_DONE_0 || + !lane_status.bits.CR_DONE_0 || + !lane_status.bits.SYMBOL_LOCKED_0) { + /* if one of the channel equalization, clock + * recovery or symbol lock is dropped + * consider it as (link has been + * dropped) dp sink status has changed + */ + status = LINK_TRAINING_LINK_LOSS; + break; + } + } + + return status; +} + +enum dc_status dp_get_lane_status_and_lane_adjust( + struct dc_link *link, + const struct link_training_settings *link_training_setting, + union lane_status ln_status[LANE_COUNT_DP_MAX], + union lane_align_status_updated *ln_align, + union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + uint32_t offset) +{ + unsigned int lane01_status_address = DP_LANE0_1_STATUS; + uint8_t lane_adjust_offset = 4; + unsigned int lane01_adjust_address; + uint8_t dpcd_buf[6] = {0}; + uint32_t lane; + enum dc_status status; + + if (is_repeater(link_training_setting, offset)) { + lane01_status_address = + DP_LANE0_1_STATUS_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + lane_adjust_offset = 3; + } + + status = core_link_read_dpcd( + link, + lane01_status_address, + (uint8_t *)(dpcd_buf), + sizeof(dpcd_buf)); + + if (status != DC_OK) { + DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X," + " keep current lane status and lane adjust unchanged", + __func__, + lane01_status_address); + return status; + } + + for (lane = 0; lane < + (uint32_t)(link_training_setting->link_settings.lane_count); + lane++) { + + ln_status[lane].raw = + get_nibble_at_index(&dpcd_buf[0], lane); + ln_adjust[lane].raw = + get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane); + } + + ln_align->raw = dpcd_buf[2]; + + if (is_repeater(link_training_setting, offset)) { + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", + __func__, + offset, + lane01_status_address, dpcd_buf[0], + lane01_status_address + 1, dpcd_buf[1]); + + lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", + __func__, + offset, + lane01_adjust_address, + dpcd_buf[lane_adjust_offset], + lane01_adjust_address + 1, + dpcd_buf[lane_adjust_offset + 1]); + } else { + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", + __func__, + lane01_status_address, dpcd_buf[0], + lane01_status_address + 1, dpcd_buf[1]); + + lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1; + + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", + __func__, + lane01_adjust_address, + dpcd_buf[lane_adjust_offset], + lane01_adjust_address + 1, + dpcd_buf[lane_adjust_offset + 1]); + } + + return status; +} + +static void override_lane_settings(const struct link_training_settings *lt_settings, + struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) +{ + uint32_t lane; + + if (lt_settings->voltage_swing == NULL && + lt_settings->pre_emphasis == NULL && + lt_settings->ffe_preset == NULL && + lt_settings->post_cursor2 == NULL) + + return; + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + if (lt_settings->voltage_swing) + lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing; + if (lt_settings->pre_emphasis) + lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis; + if (lt_settings->post_cursor2) + lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2; + if (lt_settings->ffe_preset) + lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset; + } +} + +void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override) +{ + if (!dp_is_lttpr_present(link)) + return; + + if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) { + *override = LTTPR_MODE_TRANSPARENT; + } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) { + *override = LTTPR_MODE_NON_TRANSPARENT; + } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) { + *override = LTTPR_MODE_NON_LTTPR; + } + DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override)); +} + +void override_training_settings( + struct dc_link *link, + const struct dc_link_training_overrides *overrides, + struct link_training_settings *lt_settings) +{ + uint32_t lane; + + /* Override link spread */ + if (!link->dp_ss_off && overrides->downspread != NULL) + lt_settings->link_settings.link_spread = *overrides->downspread ? + LINK_SPREAD_05_DOWNSPREAD_30KHZ + : LINK_SPREAD_DISABLED; + + /* Override lane settings */ + if (overrides->voltage_swing != NULL) + lt_settings->voltage_swing = overrides->voltage_swing; + if (overrides->pre_emphasis != NULL) + lt_settings->pre_emphasis = overrides->pre_emphasis; + if (overrides->post_cursor2 != NULL) + lt_settings->post_cursor2 = overrides->post_cursor2; + if (overrides->ffe_preset != NULL) + lt_settings->ffe_preset = overrides->ffe_preset; + /* Override HW lane settings with BIOS forced values if present */ + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { + lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING; + lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS; + lt_settings->always_match_dpcd_with_hw_lane_settings = false; + } + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = + lt_settings->voltage_swing != NULL ? + *lt_settings->voltage_swing : + VOLTAGE_SWING_LEVEL0; + lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = + lt_settings->pre_emphasis != NULL ? + *lt_settings->pre_emphasis + : PRE_EMPHASIS_DISABLED; + lt_settings->hw_lane_settings[lane].POST_CURSOR2 = + lt_settings->post_cursor2 != NULL ? + *lt_settings->post_cursor2 + : POST_CURSOR2_DISABLED; + } + + if (lt_settings->always_match_dpcd_with_hw_lane_settings) + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + + /* Override training timings */ + if (overrides->cr_pattern_time != NULL) + lt_settings->cr_pattern_time = *overrides->cr_pattern_time; + if (overrides->eq_pattern_time != NULL) + lt_settings->eq_pattern_time = *overrides->eq_pattern_time; + if (overrides->pattern_for_cr != NULL) + lt_settings->pattern_for_cr = *overrides->pattern_for_cr; + if (overrides->pattern_for_eq != NULL) + lt_settings->pattern_for_eq = *overrides->pattern_for_eq; + if (overrides->enhanced_framing != NULL) + lt_settings->enhanced_framing = *overrides->enhanced_framing; + if (link->preferred_training_settings.fec_enable != NULL) + lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; + +#if defined(CONFIG_DRM_AMD_DC_DCN) + /* Check DP tunnel LTTPR mode debug option. */ + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr) + lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR; + +#endif + dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); + +} + +enum dc_dp_training_pattern decide_cr_training_pattern( + const struct dc_link_settings *link_settings) +{ + switch (link_dp_get_encoding_format(link_settings)) { + case DP_8b_10b_ENCODING: + default: + return DP_TRAINING_PATTERN_SEQUENCE_1; + case DP_128b_132b_ENCODING: + return DP_128b_132b_TPS1; + } +} + +enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, + const struct dc_link_settings *link_settings) +{ + struct link_encoder *link_enc; + struct encoder_feature_support *enc_caps; + struct dpcd_caps *rx_caps = &link->dpcd_caps; + enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2; + + link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link_enc); + enc_caps = &link_enc->features; + + switch (link_dp_get_encoding_format(link_settings)) { + case DP_8b_10b_ENCODING: + if (enc_caps->flags.bits.IS_TPS4_CAPABLE && + rx_caps->max_down_spread.bits.TPS4_SUPPORTED) + pattern = DP_TRAINING_PATTERN_SEQUENCE_4; + else if (enc_caps->flags.bits.IS_TPS3_CAPABLE && + rx_caps->max_ln_count.bits.TPS3_SUPPORTED) + pattern = DP_TRAINING_PATTERN_SEQUENCE_3; + else + pattern = DP_TRAINING_PATTERN_SEQUENCE_2; + break; + case DP_128b_132b_ENCODING: + pattern = DP_128b_132b_TPS2; + break; + default: + pattern = DP_TRAINING_PATTERN_SEQUENCE_2; + break; + } + return pattern; +} + +enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link, + struct dc_link_settings *link_setting) +{ + enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting); + + if (encoding == DP_8b_10b_ENCODING) + return dp_decide_8b_10b_lttpr_mode(link); + else if (encoding == DP_128b_132b_ENCODING) + return dp_decide_128b_132b_lttpr_mode(link); + + ASSERT(0); + return LTTPR_MODE_NON_LTTPR; +} + +void dp_decide_lane_settings( + const struct link_training_settings *lt_settings, + const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]) +{ + uint32_t lane; + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING) { + hw_lane_settings[lane].VOLTAGE_SWING = + (enum dc_voltage_swing)(ln_adjust[lane].bits. + VOLTAGE_SWING_LANE); + hw_lane_settings[lane].PRE_EMPHASIS = + (enum dc_pre_emphasis)(ln_adjust[lane].bits. + PRE_EMPHASIS_LANE); + } else if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_128b_132b_ENCODING) { + hw_lane_settings[lane].FFE_PRESET.raw = + ln_adjust[lane].tx_ffe.PRESET_VALUE; + } + } + dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); + + if (lt_settings->disallow_per_lane_settings) { + /* we find the maximum of the requested settings across all lanes*/ + /* and set this maximum for all lanes*/ + maximize_lane_settings(lt_settings, hw_lane_settings); + override_lane_settings(lt_settings, hw_lane_settings); + + if (lt_settings->always_match_dpcd_with_hw_lane_settings) + dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); + } + +} + +void dp_decide_training_settings( + struct dc_link *link, + const struct dc_link_settings *link_settings, + struct link_training_settings *lt_settings) +{ + if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) + decide_8b_10b_training_settings(link, link_settings, lt_settings); + else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) + decide_128b_132b_training_settings(link, link_settings, lt_settings); +} + + +enum dc_status configure_lttpr_mode_transparent(struct dc_link *link) +{ + uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; + + DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); + return core_link_write_dpcd(link, + DP_PHY_REPEATER_MODE, + (uint8_t *)&repeater_mode, + sizeof(repeater_mode)); +} + +static enum dc_status configure_lttpr_mode_non_transparent( + struct dc_link *link, + const struct link_training_settings *lt_settings) +{ + /* aux timeout is already set to extended */ + /* RESET/SET lttpr mode to enable non transparent mode */ + uint8_t repeater_cnt; + uint32_t aux_interval_address; + uint8_t repeater_id; + enum dc_status result = DC_ERROR_UNEXPECTED; + uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; + + enum dp_link_encoding encoding = link_dp_get_encoding_format(<_settings->link_settings); + + if (encoding == DP_8b_10b_ENCODING) { + DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); + result = core_link_write_dpcd(link, + DP_PHY_REPEATER_MODE, + (uint8_t *)&repeater_mode, + sizeof(repeater_mode)); + + } + + if (result == DC_OK) { + link->dpcd_caps.lttpr_caps.mode = repeater_mode; + } + + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + + DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__); + + repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT; + result = core_link_write_dpcd(link, + DP_PHY_REPEATER_MODE, + (uint8_t *)&repeater_mode, + sizeof(repeater_mode)); + + if (result == DC_OK) { + link->dpcd_caps.lttpr_caps.mode = repeater_mode; + } + + if (encoding == DP_8b_10b_ENCODING) { + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + + /* Driver does not need to train the first hop. Skip DPCD read and clear + * AUX_RD_INTERVAL for DPTX-to-DPIA hop. + */ + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0; + + for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) { + aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1)); + core_link_read_dpcd( + link, + aux_interval_address, + (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1], + sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1])); + link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F; + } + } + } + + return result; +} + +enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings) +{ + enum dc_status status = DC_OK; + + if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) + status = configure_lttpr_mode_transparent(link); + + else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) + status = configure_lttpr_mode_non_transparent(link, lt_settings); + + return status; +} + +void repeater_training_done(struct dc_link *link, uint32_t offset) +{ + union dpcd_training_pattern dpcd_pattern = {0}; + + const uint32_t dpcd_base_lt_offset = + DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + /* Set training not in progress*/ + dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; + + core_link_write_dpcd( + link, + dpcd_base_lt_offset, + &dpcd_pattern.raw, + 1); + + DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); +} + +static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding) +{ + uint8_t sink_status = 0; + uint8_t i; + + /* clear training pattern set */ + dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); + + if (encoding == DP_128b_132b_ENCODING) { + /* poll for intra-hop disable */ + for (i = 0; i < 10; i++) { + if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) && + (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0) + break; + udelay(1000); + } + } +} + +enum dc_status dpcd_configure_channel_coding(struct dc_link *link, + struct link_training_settings *lt_settings) +{ + enum dp_link_encoding encoding = + link_dp_get_encoding_format( + <_settings->link_settings); + enum dc_status status; + + status = core_link_write_dpcd( + link, + DP_MAIN_LINK_CHANNEL_CODING_SET, + (uint8_t *) &encoding, + 1); + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n", + __func__, + DP_MAIN_LINK_CHANNEL_CODING_SET, + encoding); + + return status; +} + +void dpcd_set_training_pattern( + struct dc_link *link, + enum dc_dp_training_pattern training_pattern) +{ + union dpcd_training_pattern dpcd_pattern = {0}; + + dpcd_pattern.v1_4.TRAINING_PATTERN_SET = + dp_training_pattern_to_dpcd_training_pattern( + link, training_pattern); + + core_link_write_dpcd( + link, + DP_TRAINING_PATTERN_SET, + &dpcd_pattern.raw, + 1); + + DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", + __func__, + DP_TRAINING_PATTERN_SET, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); +} + +enum dc_status dpcd_set_link_settings( + struct dc_link *link, + const struct link_training_settings *lt_settings) +{ + uint8_t rate; + enum dc_status status; + + union down_spread_ctrl downspread = {0}; + union lane_count_set lane_count_set = {0}; + + downspread.raw = (uint8_t) + (lt_settings->link_settings.link_spread); + + lane_count_set.bits.LANE_COUNT_SET = + lt_settings->link_settings.lane_count; + + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + + if (link->ep_type == DISPLAY_ENDPOINT_PHY && + lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + } + + status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &downspread.raw, sizeof(downspread)); + + status = core_link_write_dpcd(link, DP_LANE_COUNT_SET, + &lane_count_set.raw, 1); + + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && + lt_settings->link_settings.use_link_rate_set == true) { + rate = 0; + /* WA for some MUX chips that will power down with eDP and lose supported + * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure + * MUX chip gets link rate set back before link training. + */ + if (link->connector_signal == SIGNAL_TYPE_EDP) { + uint8_t supported_link_rates[16]; + + core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, + supported_link_rates, sizeof(supported_link_rates)); + } + status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + status = core_link_write_dpcd(link, DP_LINK_RATE_SET, + <_settings->link_settings.link_rate_set, 1); + } else { + rate = get_dpcd_link_rate(<_settings->link_settings); + + status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + } + + if (rate) { + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", + __func__, + DP_LINK_BW_SET, + lt_settings->link_settings.link_rate, + DP_LANE_COUNT_SET, + lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, + DP_DOWNSPREAD_CTRL, + lt_settings->link_settings.link_spread); + } else { + DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n", + __func__, + DP_LINK_RATE_SET, + lt_settings->link_settings.link_rate_set, + DP_LANE_COUNT_SET, + lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, + DP_DOWNSPREAD_CTRL, + lt_settings->link_settings.link_spread); + } + + return status; +} + +enum dc_status dpcd_set_lane_settings( + struct dc_link *link, + const struct link_training_settings *link_training_setting, + uint32_t offset) +{ + unsigned int lane0_set_address; + enum dc_status status; + lane0_set_address = DP_TRAINING_LANE0_SET; + + if (is_repeater(link_training_setting, offset)) + lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + status = core_link_write_dpcd(link, + lane0_set_address, + (uint8_t *)(link_training_setting->dpcd_lane_settings), + link_training_setting->link_settings.lane_count); + + if (is_repeater(link_training_setting, offset)) { + DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n" + " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + offset, + lane0_set_address, + link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); + + } else { + DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + lane0_set_address, + link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); + } + + return status; +} + +void dpcd_set_lt_pattern_and_lane_settings( + struct dc_link *link, + const struct link_training_settings *lt_settings, + enum dc_dp_training_pattern pattern, + uint32_t offset) +{ + uint32_t dpcd_base_lt_offset; + uint8_t dpcd_lt_buffer[5] = {0}; + union dpcd_training_pattern dpcd_pattern = {0}; + uint32_t size_in_bytes; + bool edp_workaround = false; /* TODO link_prop.INTERNAL */ + dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; + + if (is_repeater(lt_settings, offset)) + dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + /***************************************************************** + * DpcdAddress_TrainingPatternSet + *****************************************************************/ + dpcd_pattern.v1_4.TRAINING_PATTERN_SET = + dp_training_pattern_to_dpcd_training_pattern(link, pattern); + + dpcd_pattern.v1_4.SCRAMBLING_DISABLE = + dp_initialize_scrambling_data_symbols(link, pattern); + + dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET] + = dpcd_pattern.raw; + + if (is_repeater(lt_settings, offset)) { + DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); + } else { + DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n", + __func__, + dpcd_base_lt_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); + } + + /* concatenate everything into one buffer*/ + size_in_bytes = lt_settings->link_settings.lane_count * + sizeof(lt_settings->dpcd_lane_settings[0]); + + // 0x00103 - 0x00102 + memmove( + &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET], + lt_settings->dpcd_lane_settings, + size_in_bytes); + + if (is_repeater(lt_settings, offset)) { + if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_128b_132b_ENCODING) + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X TX_FFE_PRESET_VALUE = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); + else if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING) + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); + } else { + if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_128b_132b_ENCODING) + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", + __func__, + dpcd_base_lt_offset, + lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); + else if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING) + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + dpcd_base_lt_offset, + lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET, + lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET, + lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED, + lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED); + } + if (edp_workaround) { + /* for eDP write in 2 parts because the 5-byte burst is + * causing issues on some eDP panels (EPR#366724) + */ + core_link_write_dpcd( + link, + DP_TRAINING_PATTERN_SET, + &dpcd_pattern.raw, + sizeof(dpcd_pattern.raw)); + + core_link_write_dpcd( + link, + DP_TRAINING_LANE0_SET, + (uint8_t *)(lt_settings->dpcd_lane_settings), + size_in_bytes); + + } else if (link_dp_get_encoding_format(<_settings->link_settings) == + DP_128b_132b_ENCODING) { + core_link_write_dpcd( + link, + dpcd_base_lt_offset, + dpcd_lt_buffer, + sizeof(dpcd_lt_buffer)); + } else + /* write it all in (1 + number-of-lanes)-byte burst*/ + core_link_write_dpcd( + link, + dpcd_base_lt_offset, + dpcd_lt_buffer, + size_in_bytes + sizeof(dpcd_pattern.raw)); +} + +void start_clock_recovery_pattern_early(struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + uint32_t offset) +{ + DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n", + __func__); + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); + dp_set_hw_lane_settings(link, link_res, lt_settings, offset); + udelay(400); +} + +void dp_set_hw_test_pattern( + struct dc_link *link, + const struct link_resource *link_res, + enum dp_test_pattern test_pattern, + uint8_t *custom_pattern, + uint32_t custom_pattern_size) +{ + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct encoder_set_dp_phy_pattern_param pattern_param = {0}; + + pattern_param.dp_phy_pattern = test_pattern; + pattern_param.custom_pattern = custom_pattern; + pattern_param.custom_pattern_size = custom_pattern_size; + pattern_param.dp_panel_mode = dp_get_panel_mode(link); + + if (link_hwss->ext.set_dp_link_test_pattern) + link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param); +} + +bool dp_set_hw_training_pattern( + struct dc_link *link, + const struct link_resource *link_res, + enum dc_dp_training_pattern pattern, + uint32_t offset) +{ + enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; + + switch (pattern) { + case DP_TRAINING_PATTERN_SEQUENCE_1: + test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1; + break; + case DP_TRAINING_PATTERN_SEQUENCE_2: + test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2; + break; + case DP_TRAINING_PATTERN_SEQUENCE_3: + test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3; + break; + case DP_TRAINING_PATTERN_SEQUENCE_4: + test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; + break; + case DP_128b_132b_TPS1: + test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE; + break; + case DP_128b_132b_TPS2: + test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE; + break; + default: + break; + } + + dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0); + + return true; +} + +static bool perform_post_lt_adj_req_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + enum dc_lane_count lane_count = + lt_settings->link_settings.lane_count; + + uint32_t adj_req_count; + uint32_t adj_req_timer; + bool req_drv_setting_changed; + uint32_t lane; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + req_drv_setting_changed = false; + for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT; + adj_req_count++) { + + req_drv_setting_changed = false; + + for (adj_req_timer = 0; + adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT; + adj_req_timer++) { + + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + DPRX); + + if (dpcd_lane_status_updated.bits. + POST_LT_ADJ_REQ_IN_PROGRESS == 0) + return true; + + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) + return false; + + if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) || + !dp_is_symbol_locked(lane_count, dpcd_lane_status) || + !dp_is_interlane_aligned(dpcd_lane_status_updated)) + return false; + + for (lane = 0; lane < (uint32_t)(lane_count); lane++) { + + if (lt_settings-> + dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET != + dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE || + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET != + dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) { + + req_drv_setting_changed = true; + break; + } + } + + if (req_drv_setting_changed) { + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + + dc_link_dp_set_drive_settings(link, + link_res, + lt_settings); + break; + } + + msleep(1); + } + + if (!req_drv_setting_changed) { + DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n", + __func__); + + ASSERT(0); + return true; + } + } + DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n", + __func__); + + ASSERT(0); + return true; + +} + +static enum link_training_result dp_transition_to_video_idle( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + enum link_training_result status) +{ + union lane_count_set lane_count_set = {0}; + + /* 4. mainlink output idle pattern*/ + dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + + /* + * 5. post training adjust if required + * If the upstream DPTX and downstream DPRX both support TPS4, + * TPS4 must be used instead of POST_LT_ADJ_REQ. + */ + if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 || + lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) { + /* delay 5ms after Main Link output idle pattern and then check + * DPCD 0202h. + */ + if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) { + msleep(5); + status = dp_check_link_loss_status(link, lt_settings); + } + return status; + } + + if (status == LINK_TRAINING_SUCCESS && + perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false) + status = LINK_TRAINING_LQA_FAIL; + + lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + core_link_write_dpcd( + link, + DP_LANE_COUNT_SET, + &lane_count_set.raw, + sizeof(lane_count_set)); + + return status; +} + +enum link_training_result dp_perform_link_training( + struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_settings, + bool skip_video_pattern) +{ + enum link_training_result status = LINK_TRAINING_SUCCESS; + struct link_training_settings lt_settings = {0}; + enum dp_link_encoding encoding = + link_dp_get_encoding_format(link_settings); + + /* decide training settings */ + dp_decide_training_settings( + link, + link_settings, + <_settings); + + override_training_settings( + link, + &link->preferred_training_settings, + <_settings); + + /* reset previous training states */ + dpcd_exit_training_mode(link, encoding); + + /* configure link prior to entering training mode */ + dpcd_configure_lttpr_mode(link, <_settings); + dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready); + dpcd_configure_channel_coding(link, <_settings); + + /* enter training mode: + * Per DP specs starting from here, DPTX device shall not issue + * Non-LT AUX transactions inside training mode. + */ + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING) + status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); + else if (encoding == DP_8b_10b_ENCODING) + status = dp_perform_8b_10b_link_training(link, link_res, <_settings); + else if (encoding == DP_128b_132b_ENCODING) + status = dp_perform_128b_132b_link_training(link, link_res, <_settings); + else + ASSERT(0); + + /* exit training mode */ + dpcd_exit_training_mode(link, encoding); + + /* switch to video idle */ + if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) + status = dp_transition_to_video_idle(link, + link_res, + <_settings, + status); + + /* dump debug data */ + dp_log_training_result(link, <_settings, status); + if (status != LINK_TRAINING_SUCCESS) + link->ctx->dc->debug_data.ltFailCount++; + return status; +} + +bool perform_link_training_with_retries( + const struct dc_link_settings *link_setting, + bool skip_video_pattern, + int attempts, + struct pipe_ctx *pipe_ctx, + enum signal_type signal, + bool do_fallback) +{ + int j; + uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + enum dp_panel_mode panel_mode = dp_get_panel_mode(link); + enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0; + struct dc_link_settings cur_link_settings = *link_setting; + struct dc_link_settings max_link_settings = *link_setting; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + int fail_count = 0; + bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */ + bool is_link_bw_min = /* RBR x 1 */ + (cur_link_settings.link_rate <= LINK_RATE_LOW) && + (cur_link_settings.lane_count <= LANE_COUNT_ONE); + + dp_trace_commit_lt_init(link); + + + if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING) + /* We need to do this before the link training to ensure the idle + * pattern in SST mode will be sent right after the link training + */ + link_hwss->setup_stream_encoder(pipe_ctx); + + dp_trace_set_lt_start_timestamp(link, false); + j = 0; + while (j < attempts && fail_count < (attempts * 10)) { + + DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, + cur_link_settings.lane_count); + + dp_enable_link_phy( + link, + &pipe_ctx->link_res, + signal, + pipe_ctx->clock_source->id, + &cur_link_settings); + + if (stream->sink_patches.dppowerup_delay > 0) { + int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; + + msleep(delay_dp_power_up_in_ms); + } + +#ifdef CONFIG_DRM_AMD_DC_HDCP + if (panel_mode == DP_PANEL_MODE_EDP) { + struct cp_psp *cp_psp = &stream->ctx->cp_psp; + + if (cp_psp && cp_psp->funcs.enable_assr) { + /* ASSR is bound to fail with unsigned PSP + * verstage used during devlopment phase. + * Report and continue with eDP panel mode to + * perform eDP link training with right settings + */ + bool result; + result = cp_psp->funcs.enable_assr(cp_psp->handle, link); + } + } +#endif + + dp_set_panel_mode(link, panel_mode); + + if (link->aux_access_disabled) { + dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings); + return true; + } else { + /** @todo Consolidate USB4 DP and DPx.x training. */ + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + status = dc_link_dpia_perform_link_training( + link, + &pipe_ctx->link_res, + &cur_link_settings, + skip_video_pattern); + + /* Transmit idle pattern once training successful. */ + if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) { + dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + // Update verified link settings to current one + // Because DPIA LT might fallback to lower link setting. + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + link->verified_link_cap.link_rate = link->cur_link_settings.link_rate; + link->verified_link_cap.lane_count = link->cur_link_settings.lane_count; + dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link); + } + } + } else { + status = dp_perform_link_training( + link, + &pipe_ctx->link_res, + &cur_link_settings, + skip_video_pattern); + } + + dp_trace_lt_total_count_increment(link, false); + dp_trace_lt_result_update(link, status, false); + dp_trace_set_lt_end_timestamp(link, false); + if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) + return true; + } + + fail_count++; + dp_trace_lt_fail_count_update(link, fail_count, false); + if (link->ep_type == DISPLAY_ENDPOINT_PHY) { + /* latest link training still fail or link training is aborted + * skip delay and keep PHY on + */ + if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT)) + break; + } + + DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, + cur_link_settings.lane_count, status); + + dp_disable_link_phy(link, &pipe_ctx->link_res, signal); + + /* Abort link training if failure due to sink being unplugged. */ + if (status == LINK_TRAINING_ABORT) { + enum dc_connection_type type = dc_connection_none; + + dc_link_detect_sink(link, &type); + if (type == dc_connection_none) { + DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__); + break; + } + } + + /* Try to train again at original settings if: + * - not falling back between training attempts; + * - aborted previous attempt due to reasons other than sink unplug; + * - successfully trained but at a link rate lower than that required by stream; + * - reached minimum link bandwidth. + */ + if (!do_fallback || (status == LINK_TRAINING_ABORT) || + (status == LINK_TRAINING_SUCCESS && is_link_bw_low) || + is_link_bw_min) { + j++; + cur_link_settings = *link_setting; + delay_between_attempts += LINK_TRAINING_RETRY_DELAY; + is_link_bw_low = false; + is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) && + (cur_link_settings.lane_count <= LANE_COUNT_ONE); + + } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */ + uint32_t req_bw; + uint32_t link_bw; + + decide_fallback_link_setting(link, &max_link_settings, + &cur_link_settings, status); + /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to + * minimum link bandwidth. + */ + req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); + link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings); + is_link_bw_low = (req_bw > link_bw); + is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) && + (cur_link_settings.lane_count <= LANE_COUNT_ONE)); + + if (is_link_bw_low) + DC_LOG_WARNING( + "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n", + __func__, link->link_index, req_bw, link_bw); + } + + msleep(delay_between_attempts); + } + + return false; +} + diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training.h new file mode 100644 index 000000000000..376d370e3bbb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training.h @@ -0,0 +1,179 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_DP_TRAINING_H__ +#define __DC_LINK_DP_TRAINING_H__ +#include "link.h" + +bool perform_link_training_with_retries( + const struct dc_link_settings *link_setting, + bool skip_video_pattern, + int attempts, + struct pipe_ctx *pipe_ctx, + enum signal_type signal, + bool do_fallback); + +enum link_training_result dp_perform_link_training( + struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_settings, + bool skip_video_pattern); + +bool dp_set_hw_training_pattern( + struct dc_link *link, + const struct link_resource *link_res, + enum dc_dp_training_pattern pattern, + uint32_t offset); + +void dp_set_hw_test_pattern( + struct dc_link *link, + const struct link_resource *link_res, + enum dp_test_pattern test_pattern, + uint8_t *custom_pattern, + uint32_t custom_pattern_size); + +void dpcd_set_training_pattern( + struct dc_link *link, + enum dc_dp_training_pattern training_pattern); + +/* Write DPCD drive settings. */ +enum dc_status dpcd_set_lane_settings( + struct dc_link *link, + const struct link_training_settings *link_training_setting, + uint32_t offset); + +/* Write DPCD link configuration data. */ +enum dc_status dpcd_set_link_settings( + struct dc_link *link, + const struct link_training_settings *lt_settings); + +void dpcd_set_lt_pattern_and_lane_settings( + struct dc_link *link, + const struct link_training_settings *lt_settings, + enum dc_dp_training_pattern pattern, + uint32_t offset); + +/* Read training status and adjustment requests from DPCD. */ +enum dc_status dp_get_lane_status_and_lane_adjust( + struct dc_link *link, + const struct link_training_settings *link_training_setting, + union lane_status ln_status[LANE_COUNT_DP_MAX], + union lane_align_status_updated *ln_align, + union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + uint32_t offset); + +enum dc_status dpcd_configure_lttpr_mode( + struct dc_link *link, + struct link_training_settings *lt_settings); + +enum dc_status configure_lttpr_mode_transparent(struct dc_link *link); + +enum dc_status dpcd_configure_channel_coding( + struct dc_link *link, + struct link_training_settings *lt_settings); + +void repeater_training_done(struct dc_link *link, uint32_t offset); + +void start_clock_recovery_pattern_early(struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + uint32_t offset); + +void dp_decide_training_settings( + struct dc_link *link, + const struct dc_link_settings *link_settings, + struct link_training_settings *lt_settings); + +void dp_decide_lane_settings( + const struct link_training_settings *lt_settings, + const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]); + +enum dc_dp_training_pattern decide_cr_training_pattern( + const struct dc_link_settings *link_settings); + +enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, + const struct dc_link_settings *link_settings); + +void dp_get_lttpr_mode_override(struct dc_link *link, + enum lttpr_mode *override); + +void override_training_settings( + struct dc_link *link, + const struct dc_link_training_overrides *overrides, + struct link_training_settings *lt_settings); + +/* Check DPCD training status registers to detect link loss. */ +enum link_training_result dp_check_link_loss_status( + struct dc_link *link, + const struct link_training_settings *link_training_setting); + +bool dp_is_cr_done(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); + +bool dp_is_ch_eq_done(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); +bool dp_is_symbol_locked(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); +bool dp_is_interlane_aligned(union lane_align_status_updated align_status); + +bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset); + +bool dp_is_max_vs_reached( + const struct link_training_settings *lt_settings); + +uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings); + +enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status); + +void dp_hw_to_dpcd_lane_settings( + const struct link_training_settings *lt_settings, + const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], + union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]); + +void dp_wait_for_training_aux_rd_interval( + struct dc_link *link, + uint32_t wait_in_micro_secs); + +enum dpcd_training_patterns + dp_training_pattern_to_dpcd_training_pattern( + struct dc_link *link, + enum dc_dp_training_pattern pattern); + +uint8_t dp_initialize_scrambling_data_symbols( + struct dc_link *link, + enum dc_dp_training_pattern pattern); + +void dp_log_training_result( + struct dc_link *link, + const struct link_training_settings *lt_settings, + enum link_training_result status); + +uint32_t dp_translate_training_aux_read_interval( + uint32_t dpcd_aux_read_interval); +#endif /* __DC_LINK_DP_TRAINING_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c new file mode 100644 index 000000000000..bfabebed5868 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c @@ -0,0 +1,260 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * This file implements dp 128b/132b link training software policies and + * sequences. + */ +#include "link_dp_training_128b_132b.h" +#include "link_dp_training_8b_10b.h" +#include "link_dpcd.h" +#include "link_dp_phy.h" +#include "link_dp_capability.h" +#include "dc_link_dp.h" + +#define DC_LOGGER \ + link->ctx->logger + +static enum dc_status dpcd_128b_132b_set_lane_settings( + struct dc_link *link, + const struct link_training_settings *link_training_setting) +{ + enum dc_status status = core_link_write_dpcd(link, + DP_TRAINING_LANE0_SET, + (uint8_t *)(link_training_setting->dpcd_lane_settings), + sizeof(link_training_setting->dpcd_lane_settings)); + + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n", + __func__, + DP_TRAINING_LANE0_SET, + link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE); + return status; +} + +static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link, + uint32_t *interval_in_us) +{ + union dp_128b_132b_training_aux_rd_interval dpcd_interval; + uint32_t interval_unit = 0; + + dpcd_interval.raw = 0; + core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL, + &dpcd_interval.raw, sizeof(dpcd_interval.raw)); + interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */ + /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) * + * INTERVAL_UNIT. The maximum is 256 ms + */ + *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000; +} + +static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + uint8_t loop_count; + uint32_t aux_rd_interval = 0; + uint32_t wait_time = 0; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + enum dc_status status = DC_OK; + enum link_training_result result = LINK_TRAINING_SUCCESS; + + /* Transmit 128b/132b_TPS1 over Main-Link */ + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX); + + /* Set TRAINING_PATTERN_SET to 01h */ + dpcd_set_training_pattern(link, lt_settings->pattern_for_cr); + + /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */ + dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); + dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX); + + /* Set loop counter to start from 1 */ + loop_count = 1; + + /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */ + dpcd_set_lt_pattern_and_lane_settings(link, lt_settings, + lt_settings->pattern_for_eq, DPRX); + + /* poll for channel EQ done */ + while (result == LINK_TRAINING_SUCCESS) { + dp_wait_for_training_aux_rd_interval(link, aux_rd_interval); + wait_time += aux_rd_interval; + status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, + dpcd_lane_status)) { + /* pass */ + break; + } else if (loop_count >= lt_settings->eq_loop_count_limit) { + result = DP_128b_132b_MAX_LOOP_COUNT_REACHED; + } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { + result = DP_128b_132b_LT_FAILED; + } else { + dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); + dpcd_128b_132b_set_lane_settings(link, lt_settings); + } + loop_count++; + } + + /* poll for EQ interlane align done */ + while (result == LINK_TRAINING_SUCCESS) { + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) { + /* pass */ + break; + } else if (wait_time >= lt_settings->eq_wait_time_limit) { + result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT; + } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { + result = DP_128b_132b_LT_FAILED; + } else { + dp_wait_for_training_aux_rd_interval(link, + lt_settings->eq_pattern_time); + wait_time += lt_settings->eq_pattern_time; + status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); + } + } + + return result; +} + +static enum link_training_result dp_perform_128b_132b_cds_done_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + /* Assumption: assume hardware has transmitted eq pattern */ + enum dc_status status = DC_OK; + enum link_training_result result = LINK_TRAINING_SUCCESS; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + uint32_t wait_time = 0; + + /* initiate CDS done sequence */ + dpcd_set_training_pattern(link, lt_settings->pattern_for_cds); + + /* poll for CDS interlane align done and symbol lock */ + while (result == LINK_TRAINING_SUCCESS) { + dp_wait_for_training_aux_rd_interval(link, + lt_settings->cds_pattern_time); + wait_time += lt_settings->cds_pattern_time; + status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, + &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) && + dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) { + /* pass */ + break; + } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { + result = DP_128b_132b_LT_FAILED; + } else if (wait_time >= lt_settings->cds_wait_time_limit) { + result = DP_128b_132b_CDS_DONE_TIMEOUT; + } + } + + return result; +} + +enum link_training_result dp_perform_128b_132b_link_training( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + enum link_training_result result = LINK_TRAINING_SUCCESS; + + /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */ + if (link->dc->debug.legacy_dp2_lt) { + struct link_training_settings legacy_settings; + + decide_8b_10b_training_settings(link, + <_settings->link_settings, + &legacy_settings); + return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings); + } + + dpcd_set_link_settings(link, lt_settings); + + if (result == LINK_TRAINING_SUCCESS) + result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings); + + if (result == LINK_TRAINING_SUCCESS) + result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings); + + return result; +} + +void decide_128b_132b_training_settings(struct dc_link *link, + const struct dc_link_settings *link_settings, + struct link_training_settings *lt_settings) +{ + memset(lt_settings, 0, sizeof(*lt_settings)); + + lt_settings->link_settings = *link_settings; + /* TODO: should decide link spread when populating link_settings */ + lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED : + LINK_SPREAD_05_DOWNSPREAD_30KHZ; + + lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings); + lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings); + lt_settings->eq_pattern_time = 2500; + lt_settings->eq_wait_time_limit = 400000; + lt_settings->eq_loop_count_limit = 20; + lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS; + lt_settings->cds_pattern_time = 2500; + lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000; + lt_settings->disallow_per_lane_settings = true; + lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link); + dp_hw_to_dpcd_lane_settings(lt_settings, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); +} + +enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link) +{ + enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR; + + if (dp_is_lttpr_present(link)) + mode = LTTPR_MODE_NON_TRANSPARENT; + + DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode); + return mode; +} + diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.h new file mode 100644 index 000000000000..2147f24efc8b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.h @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_DP_TRAINING_128B_132B_H__ +#define __DC_LINK_DP_TRAINING_128B_132B_H__ +#include "link_dp_training.h" + +enum link_training_result dp_perform_128b_132b_link_training( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings); + +void decide_128b_132b_training_settings(struct dc_link *link, + const struct dc_link_settings *link_settings, + struct link_training_settings *lt_settings); + +enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link); + +#endif /* __DC_LINK_DP_TRAINING_128B_132B_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c new file mode 100644 index 000000000000..ec8b619d51c5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c @@ -0,0 +1,415 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * This file implements dp 8b/10b link training software policies and + * sequences. + */ +#include "link_dp_training_8b_10b.h" +#include "link_dpcd.h" +#include "link_dp_phy.h" +#include "link_dp_capability.h" +#include "dc_link_dp.h" + +#define DC_LOGGER \ + link->ctx->logger + +static int32_t get_cr_training_aux_rd_interval(struct dc_link *link, + const struct dc_link_settings *link_settings) +{ + union training_aux_rd_interval training_rd_interval; + uint32_t wait_in_micro_secs = 100; + + memset(&training_rd_interval, 0, sizeof(training_rd_interval)); + if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING && + link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { + core_link_read_dpcd( + link, + DP_TRAINING_AUX_RD_INTERVAL, + (uint8_t *)&training_rd_interval, + sizeof(training_rd_interval)); + if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) + wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; + } + return wait_in_micro_secs; +} + +static uint32_t get_eq_training_aux_rd_interval( + struct dc_link *link, + const struct dc_link_settings *link_settings) +{ + union training_aux_rd_interval training_rd_interval; + + memset(&training_rd_interval, 0, sizeof(training_rd_interval)); + if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) { + core_link_read_dpcd( + link, + DP_128B132B_TRAINING_AUX_RD_INTERVAL, + (uint8_t *)&training_rd_interval, + sizeof(training_rd_interval)); + } else if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING && + link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { + core_link_read_dpcd( + link, + DP_TRAINING_AUX_RD_INTERVAL, + (uint8_t *)&training_rd_interval, + sizeof(training_rd_interval)); + } + + switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) { + case 0: return 400; + case 1: return 4000; + case 2: return 8000; + case 3: return 12000; + case 4: return 16000; + case 5: return 32000; + case 6: return 64000; + default: return 400; + } +} + +void decide_8b_10b_training_settings( + struct dc_link *link, + const struct dc_link_settings *link_setting, + struct link_training_settings *lt_settings) +{ + memset(lt_settings, '\0', sizeof(struct link_training_settings)); + + /* Initialize link settings */ + lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set; + lt_settings->link_settings.link_rate_set = link_setting->link_rate_set; + lt_settings->link_settings.link_rate = link_setting->link_rate; + lt_settings->link_settings.lane_count = link_setting->lane_count; + /* TODO hard coded to SS for now + * lt_settings.link_settings.link_spread = + * dal_display_path_is_ss_supported( + * path_mode->display_path) ? + * LINK_SPREAD_05_DOWNSPREAD_30KHZ : + * LINK_SPREAD_DISABLED; + */ + lt_settings->link_settings.link_spread = link->dp_ss_off ? + LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ; + lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting); + lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting); + lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting); + lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); + lt_settings->enhanced_framing = 1; + lt_settings->should_set_fec_ready = true; + lt_settings->disallow_per_lane_settings = true; + lt_settings->always_match_dpcd_with_hw_lane_settings = true; + lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link); + dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); +} + +enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link) +{ + bool is_lttpr_present = dp_is_lttpr_present(link); + bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable; + bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware; + + if (!is_lttpr_present) + return LTTPR_MODE_NON_LTTPR; + + if (vbios_lttpr_aware) { + if (vbios_lttpr_force_non_transparent) { + DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n"); + return LTTPR_MODE_NON_TRANSPARENT; + } else { + DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n"); + return LTTPR_MODE_TRANSPARENT; + } + } + + if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A && + link->dc->caps.extended_aux_timeout_support) { + DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n"); + return LTTPR_MODE_NON_TRANSPARENT; + } + + DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n"); + return LTTPR_MODE_NON_LTTPR; +} + +enum link_training_result perform_8b_10b_clock_recovery_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + uint32_t offset) +{ + uint32_t retries_cr; + uint32_t retry_count; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; + union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + retries_cr = 0; + retry_count = 0; + + memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); + memset(&dpcd_lane_status_updated, '\0', + sizeof(dpcd_lane_status_updated)); + + if (!link->ctx->dc->work_arounds.lt_early_cr_pattern) + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); + + /* najeeb - The synaptics MST hub can put the LT in + * infinite loop by switching the VS + */ + /* between level 0 and level 1 continuously, here + * we try for CR lock for LinkTrainingMaxCRRetry count*/ + while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + + + /* 1. call HWSS to set lane settings*/ + dp_set_hw_lane_settings( + link, + link_res, + lt_settings, + offset); + + /* 2. update DPCD of the receiver*/ + if (!retry_count) + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration.*/ + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + lt_settings->pattern_for_cr, + offset); + else + dpcd_set_lane_settings( + link, + lt_settings, + offset); + + /* 3. wait receiver to lock-on*/ + wait_time_microsec = lt_settings->cr_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested drive + * settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + offset); + + /* 5. check CR done*/ + if (dp_is_cr_done(lane_count, dpcd_lane_status)) + return LINK_TRAINING_SUCCESS; + + /* 6. max VS reached*/ + if ((link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING) && + dp_is_max_vs_reached(lt_settings)) + break; + + /* 7. same lane settings*/ + /* Note: settings are the same for all lanes, + * so comparing first lane is sufficient*/ + if ((link_dp_get_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) && + lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + retries_cr++; + else if ((link_dp_get_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) && + lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE == + dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE) + retries_cr++; + else + retries_cr = 0; + + /* 8. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + retry_count++; + } + + if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { + ASSERT(0); + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + __func__, + LINK_TRAINING_MAX_CR_RETRY); + + } + + return dp_get_cr_failure(lane_count, dpcd_lane_status); +} + +enum link_training_result perform_8b_10b_channel_equalization_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + uint32_t offset) +{ + enum dc_dp_training_pattern tr_pattern; + uint32_t retries_ch_eq; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + /* Note: also check that TPS4 is a supported feature*/ + tr_pattern = lt_settings->pattern_for_eq; + + if (is_repeater(lt_settings, offset) && link_dp_get_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) + tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; + + dp_set_hw_training_pattern(link, link_res, tr_pattern, offset); + + for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; + retries_ch_eq++) { + + dp_set_hw_lane_settings(link, link_res, lt_settings, offset); + + /* 2. update DPCD*/ + if (!retries_ch_eq) + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration + */ + + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + tr_pattern, offset); + else + dpcd_set_lane_settings(link, lt_settings, offset); + + /* 3. wait for receiver to lock-on*/ + wait_time_microsec = lt_settings->eq_pattern_time; + + if (is_repeater(lt_settings, offset)) + wait_time_microsec = + dp_translate_training_aux_read_interval( + link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested + * drive settings as set by the sink*/ + + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + offset); + + /* 5. check CR done*/ + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) + return dpcd_lane_status[0].bits.CR_DONE_0 ? + LINK_TRAINING_EQ_FAIL_CR_PARTIAL : + LINK_TRAINING_EQ_FAIL_CR; + + /* 6. check CHEQ done*/ + if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && + dp_is_symbol_locked(lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) + return LINK_TRAINING_SUCCESS; + + /* 7. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + + return LINK_TRAINING_EQ_FAIL_EQ; + +} + +enum link_training_result dp_perform_8b_10b_link_training( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + enum link_training_result status = LINK_TRAINING_SUCCESS; + + uint8_t repeater_cnt; + uint8_t repeater_id; + uint8_t lane = 0; + + if (link->ctx->dc->work_arounds.lt_early_cr_pattern) + start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); + + /* 1. set link rate, lane count and spread. */ + dpcd_set_link_settings(link, lt_settings); + + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + + /* 2. perform link training (set link training done + * to false is done as well) + */ + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + + for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); + repeater_id--) { + status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); + + if (status != LINK_TRAINING_SUCCESS) { + repeater_training_done(link, repeater_id); + break; + } + + status = perform_8b_10b_channel_equalization_sequence(link, + link_res, + lt_settings, + repeater_id); + + repeater_training_done(link, repeater_id); + + if (status != LINK_TRAINING_SUCCESS) + break; + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + lt_settings->dpcd_lane_settings[lane].raw = 0; + lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; + lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; + } + } + } + + if (status == LINK_TRAINING_SUCCESS) { + status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX); + if (status == LINK_TRAINING_SUCCESS) { + status = perform_8b_10b_channel_equalization_sequence(link, + link_res, + lt_settings, + DPRX); + } + } + + return status; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.h new file mode 100644 index 000000000000..d26de15ce954 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.h @@ -0,0 +1,61 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_DP_TRAINING_8B_10B_H__ +#define __DC_LINK_DP_TRAINING_8B_10B_H__ +#include "link_dp_training.h" + +/* to avoid infinite loop where-in the receiver + * switches between different VS + */ +#define LINK_TRAINING_MAX_CR_RETRY 100 +#define LINK_TRAINING_MAX_RETRY_COUNT 5 + +enum link_training_result dp_perform_8b_10b_link_training( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings); + +enum link_training_result perform_8b_10b_clock_recovery_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + uint32_t offset); + +enum link_training_result perform_8b_10b_channel_equalization_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings, + uint32_t offset); + +enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link); + +void decide_8b_10b_training_settings( + struct dc_link *link, + const struct dc_link_settings *link_setting, + struct link_training_settings *lt_settings); + +#endif /* __DC_LINK_DP_TRAINING_8B_10B_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.c new file mode 100644 index 000000000000..f84b6ea53e8b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.c @@ -0,0 +1,80 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * + */ +#include "link_dp_training_auxless.h" +#include "link_dp_phy.h" +#include "dc_link_dp.h" +#define DC_LOGGER \ + link->ctx->logger +bool dc_link_dp_perform_link_training_skip_aux( + struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_setting) +{ + struct link_training_settings lt_settings = {0}; + + dp_decide_training_settings( + link, + link_setting, + <_settings); + override_training_settings( + link, + &link->preferred_training_settings, + <_settings); + + /* 1. Perform_clock_recovery_sequence. */ + + /* transmit training pattern for clock recovery */ + dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX); + + /* call HWSS to set lane settings*/ + dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); + + /* wait receiver to lock-on*/ + dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); + + /* 2. Perform_channel_equalization_sequence. */ + + /* transmit training pattern for channel equalization. */ + dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX); + + /* call HWSS to set lane settings*/ + dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); + + /* wait receiver to lock-on. */ + dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); + + /* 3. Perform_link_training_int. */ + + /* Mainlink output idle pattern. */ + dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + + dp_log_training_result(link, <_settings, LINK_TRAINING_SUCCESS); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.h new file mode 100644 index 000000000000..413999cd03c4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.h @@ -0,0 +1,35 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_DP_TRAINING_AUXLESS_H__ +#define __DC_LINK_DP_TRAINING_AUXLESS_H__ +#include "link_dp_training.h" + +bool dc_link_dp_perform_link_training_skip_aux( + struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_setting); +#endif /* __DC_LINK_DP_TRAINING_AUXLESS_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c index d130d58ac08e..cf47db1c2141 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c @@ -1,6 +1,5 @@ -// SPDX-License-Identifier: MIT /* - * Copyright 2021 Advanced Micro Devices, Inc. + * Copyright 2022 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"), @@ -24,76 +23,70 @@ * */ +/* FILE POLICY AND INTENDED USAGE: + * This module implements functionality for training DPIA links. + */ +#include "link_dp_training_dpia.h" #include "dc.h" -#include "dc_link_dpia.h" #include "inc/core_status.h" #include "dc_link.h" #include "dc_link_dp.h" #include "dpcd_defs.h" + +#include "link_dp_dpia.h" #include "link_hwss.h" #include "dm_helpers.h" #include "dmub/inc/dmub_cmd.h" -#include "inc/link_dpcd.h" +#include "link_dpcd.h" +#include "link_dp_training_8b_10b.h" +#include "link_dp_capability.h" #include "dc_dmub_srv.h" - #define DC_LOGGER \ link->ctx->logger -enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link) -{ - enum dc_status status = DC_OK; - uint8_t dpcd_dp_tun_data[3] = {0}; - uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0}; - uint8_t i = 0; - - status = core_link_read_dpcd(link, - DP_TUNNELING_CAPABILITIES_SUPPORT, - dpcd_dp_tun_data, - sizeof(dpcd_dp_tun_data)); - - status = core_link_read_dpcd(link, - DP_USB4_ROUTER_TOPOLOGY_ID, - dpcd_topology_data, - sizeof(dpcd_topology_data)); - - link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw = - dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - - DP_TUNNELING_CAPABILITIES_SUPPORT]; - link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw = - dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT]; - link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id = - dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT]; - - for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++) - link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i]; - - return status; -} - -bool dc_link_dpia_query_hpd_status(struct dc_link *link) -{ - union dmub_rb_cmd cmd = {0}; - struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv; - bool is_hpd_high = false; - - /* prepare QUERY_HPD command */ - cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE; - cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1; - cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA; - - /* Return HPD status reported by DMUB if query successfully executed. */ - if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS) - is_hpd_high = cmd.query_hpd.data.result; +/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */ +#define DPIA_CLK_SYNC_DELAY 16000 + +/* Extend interval between training status checks for manual testing. */ +#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000 + +/* SET_CONFIG message types sent by driver. */ +enum dpia_set_config_type { + DPIA_SET_CFG_SET_LINK = 0x01, + DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05, + DPIA_SET_CFG_SET_TRAINING = 0x18, + DPIA_SET_CFG_SET_VSPE = 0x19 +}; + +/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */ +enum dpia_set_config_ts { + DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */ + DPIA_TS_TPS1 = 0x01, + DPIA_TS_TPS2 = 0x02, + DPIA_TS_TPS3 = 0x03, + DPIA_TS_TPS4 = 0x07, + DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */ +}; + +/* SET_CONFIG message data associated with messages sent by driver. */ +union dpia_set_config_data { + struct { + uint8_t mode : 1; + uint8_t reserved : 7; + } set_link; + struct { + uint8_t stage; + } set_training; + struct { + uint8_t swing : 2; + uint8_t max_swing_reached : 1; + uint8_t pre_emph : 2; + uint8_t max_pre_emph_reached : 1; + uint8_t reserved : 2; + } set_vspe; + uint8_t raw; +}; - DC_LOG_DEBUG("%s: link(%d) dpia(%d) cmd_status(%d) result(%d)\n", - __func__, - link->link_index, - link->link_id.enum_id - ENUM_ID_1, - cmd.query_hpd.data.status, - cmd.query_hpd.data.result); - - return is_hpd_high; -} /* Configure link as prescribed in link_setting; set LTTPR mode; and * Initialize link training settings. @@ -113,11 +106,12 @@ static enum link_training_result dpia_configure_link( bool fec_enable; DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n", - __func__, - link->link_id.enum_id - ENUM_ID_1, - lt_settings->lttpr_mode); + __func__, + link->link_id.enum_id - ENUM_ID_1, + lt_settings->lttpr_mode); - dp_decide_training_settings(link, + dp_decide_training_settings( + link, link_setting, lt_settings); @@ -137,7 +131,7 @@ static enum link_training_result dpia_configure_link( if (status != DC_OK && link->is_hpd_pending) return LINK_TRAINING_ABORT; - if (link->preferred_training_settings.fec_enable) + if (link->preferred_training_settings.fec_enable != NULL) fec_enable = *link->preferred_training_settings.fec_enable; else fec_enable = true; @@ -148,7 +142,8 @@ static enum link_training_result dpia_configure_link( return LINK_TRAINING_SUCCESS; } -static enum dc_status core_link_send_set_config(struct dc_link *link, +static enum dc_status core_link_send_set_config( + struct dc_link *link, uint8_t msg_type, uint8_t msg_data) { @@ -160,8 +155,8 @@ static enum dc_status core_link_send_set_config(struct dc_link *link, payload.msg_data = msg_data; if (!link->ddc->ddc_pin && !link->aux_access_disabled && - (dm_helpers_dmub_set_config_sync(link->ctx, link, - &payload, &set_config_result) == -1)) { + (dm_helpers_dmub_set_config_sync(link->ctx, + link, &payload, &set_config_result) == -1)) { return DC_ERROR_UNEXPECTED; } @@ -170,7 +165,8 @@ static enum dc_status core_link_send_set_config(struct dc_link *link, } /* Build SET_CONFIG message data payload for specified message type. */ -static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type, +static uint8_t dpia_build_set_config_data( + enum dpia_set_config_type type, struct dc_link *link, struct link_training_settings *lt_settings) { @@ -189,11 +185,9 @@ static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type, data.set_vspe.swing = lt_settings->hw_lane_settings[0].VOLTAGE_SWING; data.set_vspe.pre_emph = lt_settings->hw_lane_settings[0].PRE_EMPHASIS; data.set_vspe.max_swing_reached = - lt_settings->hw_lane_settings[0].VOLTAGE_SWING == - VOLTAGE_SWING_MAX_LEVEL ? 1 : 0; + lt_settings->hw_lane_settings[0].VOLTAGE_SWING == VOLTAGE_SWING_MAX_LEVEL ? 1 : 0; data.set_vspe.max_pre_emph_reached = - lt_settings->hw_lane_settings[0].PRE_EMPHASIS == - PRE_EMPHASIS_MAX_LEVEL ? 1 : 0; + lt_settings->hw_lane_settings[0].PRE_EMPHASIS == PRE_EMPHASIS_MAX_LEVEL ? 1 : 0; break; default: ASSERT(false); /* Message type not supported by helper function. */ @@ -235,7 +229,8 @@ static enum dc_status convert_trng_ptn_to_trng_stg(enum dc_dp_training_pattern t } /* Write training pattern to DPCD. */ -static enum dc_status dpcd_set_lt_pattern(struct dc_link *link, +static enum dc_status dpcd_set_lt_pattern( + struct dc_link *link, enum dc_dp_training_pattern pattern, uint32_t hop) { @@ -249,28 +244,29 @@ static enum dc_status dpcd_set_lt_pattern(struct dc_link *link, /* DpcdAddress_TrainingPatternSet */ dpcd_pattern.v1_4.TRAINING_PATTERN_SET = - dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern); + dp_training_pattern_to_dpcd_training_pattern(link, pattern); dpcd_pattern.v1_4.SCRAMBLING_DISABLE = - dc_dp_initialize_scrambling_data_symbols(link, pattern); + dp_initialize_scrambling_data_symbols(link, pattern); if (hop != DPRX) { DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n", - __func__, - hop, - dpcd_tps_offset, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); + __func__, + hop, + dpcd_tps_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); } else { DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n", - __func__, - dpcd_tps_offset, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); + __func__, + dpcd_tps_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); } - status = core_link_write_dpcd(link, - dpcd_tps_offset, - &dpcd_pattern.raw, - sizeof(dpcd_pattern.raw)); + status = core_link_write_dpcd( + link, + dpcd_tps_offset, + &dpcd_pattern.raw, + sizeof(dpcd_pattern.raw)); return status; } @@ -284,7 +280,7 @@ static enum dc_status dpcd_set_lt_pattern(struct dc_link *link, * * @param link DPIA link being trained. * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ static enum link_training_result dpia_training_cr_non_transparent( struct dc_link *link, @@ -297,8 +293,7 @@ static enum link_training_result dpia_training_cr_non_transparent( enum dc_status status; uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */ uint32_t retry_count = 0; - /* From DP spec, CR read interval is always 100us. */ - uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL; + uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL; /* From DP spec, CR read interval is always 100us. */ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; union lane_align_status_updated dpcd_lane_status_updated = {0}; @@ -306,7 +301,7 @@ static enum link_training_result dpia_training_cr_non_transparent( uint8_t set_cfg_data; enum dpia_set_config_ts ts; - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery. * Fix inherited from perform_clock_recovery_sequence() - @@ -316,17 +311,20 @@ static enum link_training_result dpia_training_cr_non_transparent( * continuously. */ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && - (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + /* DPTX-to-DPIA */ if (hop == repeater_cnt) { /* Send SET_CONFIG(SET_LINK:LC,LR,LTTPR) to notify DPOA that * non-transparent link training has started. * This also enables the transmission of clk_sync packets. */ - set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_LINK, + set_cfg_data = dpia_build_set_config_data( + DPIA_SET_CFG_SET_LINK, link, lt_settings); - status = core_link_send_set_config(link, + status = core_link_send_set_config( + link, DPIA_SET_CFG_SET_LINK, set_cfg_data); /* CR for this hop is considered successful as long as @@ -347,6 +345,14 @@ static enum link_training_result dpia_training_cr_non_transparent( result = LINK_TRAINING_ABORT; break; } + status = core_link_send_set_config( + link, + DPIA_SET_CFG_SET_TRAINING, + ts); + if (status != DC_OK) { + result = LINK_TRAINING_ABORT; + break; + } status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, hop); if (status != DC_OK) { result = LINK_TRAINING_ABORT; @@ -358,10 +364,12 @@ static enum link_training_result dpia_training_cr_non_transparent( * drive settings for hops immediately downstream. */ if (hop == repeater_cnt - 1) { - set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE, + set_cfg_data = dpia_build_set_config_data( + DPIA_SET_CFG_SET_VSPE, link, lt_settings); - status = core_link_send_set_config(link, + status = core_link_send_set_config( + link, DPIA_SET_CFG_SET_VSPE, set_cfg_data); if (status != DC_OK) { @@ -468,7 +476,8 @@ static enum link_training_result dpia_training_cr_transparent( * continuously. */ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && - (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + /* Write TPS1 (not VS or PE) to DPCD to start CR phase. * DPIA sends SET_CONFIG(SET_LINK) to notify DPOA to * start link training. @@ -529,8 +538,7 @@ static enum link_training_result dpia_training_cr_transparent( if (link->is_hpd_pending) result = LINK_TRAINING_ABORT; - DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n" - " -hop(%d)\n - result(%d)\n - retries(%d)\n", + DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n", __func__, link->link_id.enum_id - ENUM_ID_1, DPRX, @@ -545,7 +553,7 @@ static enum link_training_result dpia_training_cr_transparent( * * @param link DPIA link being trained. * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ static enum link_training_result dpia_training_cr_phase( struct dc_link *link, @@ -564,7 +572,8 @@ static enum link_training_result dpia_training_cr_phase( } /* Return status read interval during equalization phase. */ -static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link, +static uint32_t dpia_get_eq_aux_rd_interval( + const struct dc_link *link, const struct link_training_settings *lt_settings, uint32_t hop) { @@ -590,12 +599,11 @@ static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link, * - TPSx is transmitted for any hops downstream of DPOA. * - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA. * - EQ for the first hop (DPTX-to-DPIA) is assumed to be successful. - * - DPRX EQ only reported successful when both DPRX and DPIA requirements - * (clk sync packets sent) fulfilled. + * - DPRX EQ only reported successful when both DPRX and DPIA requirements (clk sync packets sent) fulfilled. * * @param link DPIA link being trained. * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ static enum link_training_result dpia_training_eq_non_transparent( struct dc_link *link, @@ -624,9 +632,10 @@ static enum link_training_result dpia_training_eq_non_transparent( else tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) { + /* DPTX-to-DPIA equalization always successful. */ if (hop == repeater_cnt) { result = LINK_TRAINING_SUCCESS; @@ -640,7 +649,8 @@ static enum link_training_result dpia_training_eq_non_transparent( result = LINK_TRAINING_ABORT; break; } - status = core_link_send_set_config(link, + status = core_link_send_set_config( + link, DPIA_SET_CFG_SET_TRAINING, ts); if (status != DC_OK) { @@ -658,12 +668,14 @@ static enum link_training_result dpia_training_eq_non_transparent( * drive settings for hop immediately downstream. */ if (hop == repeater_cnt - 1) { - set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE, - link, - lt_settings); - status = core_link_send_set_config(link, - DPIA_SET_CFG_SET_VSPE, - set_cfg_data); + set_cfg_data = dpia_build_set_config_data( + DPIA_SET_CFG_SET_VSPE, + link, + lt_settings); + status = core_link_send_set_config( + link, + DPIA_SET_CFG_SET_VSPE, + set_cfg_data); if (status != DC_OK) { result = LINK_TRAINING_ABORT; break; @@ -679,7 +691,7 @@ static enum link_training_result dpia_training_eq_non_transparent( * ensure clock sync packets have been sent. */ if (hop == DPRX && retries_eq == 1) - wait_time_microsec = max(wait_time_microsec, (uint32_t)DPIA_CLK_SYNC_DELAY); + wait_time_microsec = max(wait_time_microsec, (uint32_t) DPIA_CLK_SYNC_DELAY); else wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, hop); @@ -705,8 +717,8 @@ static enum link_training_result dpia_training_eq_non_transparent( } if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && - dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) && - dp_is_interlane_aligned(dpcd_lane_status_updated)) { + dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) { result = LINK_TRAINING_SUCCESS; break; } @@ -741,7 +753,7 @@ static enum link_training_result dpia_training_eq_non_transparent( * * @param link DPIA link being trained. * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ static enum link_training_result dpia_training_eq_transparent( struct dc_link *link, @@ -761,6 +773,7 @@ static enum link_training_result dpia_training_eq_transparent( wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX); for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) { + if (retries_eq == 0) { status = dpcd_set_lt_pattern(link, tr_pattern, DPRX); if (status != DC_OK) { @@ -810,8 +823,7 @@ static enum link_training_result dpia_training_eq_transparent( if (link->is_hpd_pending) result = LINK_TRAINING_ABORT; - DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n" - " - hop(%d)\n - result(%d)\n - retries(%d)\n", + DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n", __func__, link->link_id.enum_id - ENUM_ID_1, DPRX, @@ -826,7 +838,7 @@ static enum link_training_result dpia_training_eq_transparent( * * @param link DPIA link being trained. * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ static enum link_training_result dpia_training_eq_phase( struct dc_link *link, @@ -845,7 +857,9 @@ static enum link_training_result dpia_training_eq_phase( } /* End training of specified hop in display path. */ -static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop) +static enum dc_status dpcd_clear_lt_pattern( + struct dc_link *link, + uint32_t hop) { union dpcd_training_pattern dpcd_pattern = {0}; uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET; @@ -855,7 +869,8 @@ static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop) dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1)); - status = core_link_write_dpcd(link, + status = core_link_write_dpcd( + link, dpcd_tps_offset, &dpcd_pattern.raw, sizeof(dpcd_pattern.raw)); @@ -873,9 +888,10 @@ static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop) * (DPTX-to-DPIA) and last hop (DPRX). * * @param link DPIA link being trained. - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ -static enum link_training_result dpia_training_end(struct dc_link *link, +static enum link_training_result dpia_training_end( + struct dc_link *link, struct link_training_settings *lt_settings, uint32_t hop) { @@ -884,13 +900,15 @@ static enum link_training_result dpia_training_end(struct dc_link *link, enum dc_status status; if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); if (hop == repeater_cnt) { /* DPTX-to-DPIA */ /* Send SET_CONFIG(SET_TRAINING:0xff) to notify DPOA that * DPTX-to-DPIA hop trained. No DPCD write needed for first hop. */ - status = core_link_send_set_config(link, + status = core_link_send_set_config( + link, DPIA_SET_CFG_SET_TRAINING, DPIA_TS_UFP_DONE); if (status != DC_OK) @@ -904,7 +922,8 @@ static enum link_training_result dpia_training_end(struct dc_link *link, /* Notify DPOA that non-transparent link training of DPRX done. */ if (hop == DPRX && result != LINK_TRAINING_ABORT) { - status = core_link_send_set_config(link, + status = core_link_send_set_config( + link, DPIA_SET_CFG_SET_TRAINING, DPIA_TS_DPRX_DONE); if (status != DC_OK) @@ -912,18 +931,20 @@ static enum link_training_result dpia_training_end(struct dc_link *link, } } else { /* non-LTTPR or transparent LTTPR. */ + /* Write 0x0 to TRAINING_PATTERN_SET */ status = dpcd_clear_lt_pattern(link, hop); if (status != DC_OK) result = LINK_TRAINING_ABORT; + } DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) end\n - hop(%d)\n - result(%d)\n - LTTPR mode(%d)\n", - __func__, - link->link_id.enum_id - ENUM_ID_1, - hop, - result, - lt_settings->lttpr_mode); + __func__, + link->link_id.enum_id - ENUM_ID_1, + hop, + result, + lt_settings->lttpr_mode); return result; } @@ -933,20 +954,21 @@ static enum link_training_result dpia_training_end(struct dc_link *link, * - Sending SET_CONFIG(SET_LINK) with lane count and link rate set to 0. * * @param link DPIA link being trained. - * @param hop The Hop in display path. DPRX = 0. + * @param hop Hop in display path. DPRX = 0. */ -static void dpia_training_abort(struct dc_link *link, - struct link_training_settings *lt_settings, - uint32_t hop) +static void dpia_training_abort( + struct dc_link *link, + struct link_training_settings *lt_settings, + uint32_t hop) { uint8_t data = 0; uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET; DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n", - __func__, - link->link_id.enum_id - ENUM_ID_1, - lt_settings->lttpr_mode, - link->is_hpd_pending); + __func__, + link->link_id.enum_id - ENUM_ID_1, + lt_settings->lttpr_mode, + link->is_hpd_pending); /* Abandon clean-up if sink unplugged. */ if (link->is_hpd_pending) @@ -975,7 +997,7 @@ enum link_training_result dc_link_dpia_perform_link_training( struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in - lt_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link_settings); + lt_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link_settings); /* Configure link as prescribed in link_setting and set LTTPR mode. */ result = dpia_configure_link(link, link_res, link_setting, <_settings); @@ -983,7 +1005,7 @@ enum link_training_result dc_link_dpia_perform_link_training( return result; if (lt_settings.lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) - repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); /* Train each hop in turn starting with the one closest to DPTX. * In transparent or non-LTTPR mode, train only the final hop (DPRX). @@ -1014,10 +1036,10 @@ enum link_training_result dc_link_dpia_perform_link_training( msleep(5); if (!link->is_automated) result = dp_check_link_loss_status(link, <_settings); - } else if (result == LINK_TRAINING_ABORT) { + } else if (result == LINK_TRAINING_ABORT) dpia_training_abort(link, <_settings, repeater_id); - } else { + else dpia_training_end(link, <_settings, repeater_id); - } + return result; } diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h new file mode 100644 index 000000000000..0150f2916421 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h @@ -0,0 +1,41 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_DP_TRAINING_DPIA_H__ +#define __DC_LINK_DP_TRAINING_DPIA_H__ +#include "link_dp_training.h" + +/* Train DP tunneling link for USB4 DPIA display endpoint. + * DPIA equivalent of dc_link_dp_perfrorm_link_training. + * Aborts link training upon detection of sink unplug. + */ +enum link_training_result dc_link_dpia_perform_link_training( + struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_setting, + bool skip_video_pattern); + +#endif /* __DC_LINK_DP_TRAINING_DPIA_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.c new file mode 100644 index 000000000000..860b5eea89aa --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.c @@ -0,0 +1,580 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * This file implements 8b/10b link training specially modified to support an + * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer. + * Unlike native dp connection this chip requires a modified link training + * protocol based on 8b/10b link training. Since this is a non standard sequence + * and we must support this hardware, we decided to isolate it in its own + * training sequence inside its own file. + */ +#include "link_dp_training_fixed_vs_pe_retimer.h" +#include "link_dp_training_8b_10b.h" +#include "link_dpcd.h" +#include "link_dp_phy.h" +#include "link_dp_capability.h" +#include "dc_link_dp.h" + +#define DC_LOGGER \ + link->ctx->logger + +void dp_fixed_vs_pe_read_lane_adjust( + struct dc_link *link, + union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]) +{ + const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63}; + const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63}; + const uint8_t offset = dp_parse_lttpr_repeater_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + uint32_t vendor_lttpr_write_address = 0xF004F; + uint32_t vendor_lttpr_read_address = 0xF0053; + uint8_t dprx_vs = 0; + uint8_t dprx_pe = 0; + uint8_t lane; + + if (offset != 0xFF) { + vendor_lttpr_write_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + vendor_lttpr_read_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + } + + /* W/A to read lane settings requested by DPRX */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_read_dpcd( + link, + vendor_lttpr_read_address, + &dprx_vs, + 1); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + core_link_read_dpcd( + link, + vendor_lttpr_read_address, + &dprx_pe, + 1); + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3; + dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3; + } +} + + +void dp_fixed_vs_pe_set_retimer_lane_settings( + struct dc_link *link, + const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], + uint8_t lane_count) +{ + const uint8_t offset = dp_parse_lttpr_repeater_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; + uint32_t vendor_lttpr_write_address = 0xF004F; + uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; + uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; + uint8_t lane = 0; + + if (offset != 0xFF) { + vendor_lttpr_write_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + } + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Force LTTPR to output desired VS and PE */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_reset[0], + sizeof(vendor_lttpr_write_data_reset)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); +} + +static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + enum link_training_result status = LINK_TRAINING_SUCCESS; + uint8_t lane = 0; + uint8_t toggle_rate = 0x6; + uint8_t target_rate = 0x6; + bool apply_toggle_rate_wa = false; + uint8_t repeater_cnt; + uint8_t repeater_id; + + /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */ + if (lt_settings->cr_pattern_time < 16000) + lt_settings->cr_pattern_time = 16000; + + /* Fixed VS/PE specific: Toggle link rate */ + apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate); + target_rate = get_dpcd_link_rate(<_settings->link_settings); + toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; + + if (apply_toggle_rate_wa) + lt_settings->link_settings.link_rate = toggle_rate; + + if (link->ctx->dc->work_arounds.lt_early_cr_pattern) + start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); + + /* 1. set link rate, lane count and spread. */ + dpcd_set_link_settings(link, lt_settings); + + /* Fixed VS/PE specific: Toggle link rate back*/ + if (apply_toggle_rate_wa) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, + &target_rate, + 1); + } + + link->vendor_specific_lttpr_link_rate_wa = target_rate; + + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + + /* 2. perform link training (set link training done + * to false is done as well) + */ + repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + + for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); + repeater_id--) { + status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); + + if (status != LINK_TRAINING_SUCCESS) { + repeater_training_done(link, repeater_id); + break; + } + + status = perform_8b_10b_channel_equalization_sequence(link, + link_res, + lt_settings, + repeater_id); + + repeater_training_done(link, repeater_id); + + if (status != LINK_TRAINING_SUCCESS) + break; + + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + lt_settings->dpcd_lane_settings[lane].raw = 0; + lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; + lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; + } + } + } + + if (status == LINK_TRAINING_SUCCESS) { + status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX); + if (status == LINK_TRAINING_SUCCESS) { + status = perform_8b_10b_channel_equalization_sequence(link, + link_res, + lt_settings, + DPRX); + } + } + + return status; +} + + +enum link_training_result dp_perform_fixed_vs_pe_training_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; + const uint8_t offset = dp_parse_lttpr_repeater_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; + const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; + uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; + uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; + uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; + uint32_t vendor_lttpr_write_address = 0xF004F; + enum link_training_result status = LINK_TRAINING_SUCCESS; + uint8_t lane = 0; + union down_spread_ctrl downspread = {0}; + union lane_count_set lane_count_set = {0}; + uint8_t toggle_rate; + uint8_t rate; + + /* Only 8b/10b is supported */ + ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING); + + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); + return status; + } + + if (offset != 0xFF) { + vendor_lttpr_write_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + /* Certain display and cable configuration require extra delay */ + if (offset > 2) + pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; + } + + /* Vendor specific: Reset lane settings */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_reset[0], + sizeof(vendor_lttpr_write_data_reset)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* Vendor specific: Enable intercept */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + + /* 1. set link rate, lane count and spread. */ + + downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); + + lane_count_set.bits.LANE_COUNT_SET = + lt_settings->link_settings.lane_count; + + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + + if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + } + + core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &downspread.raw, sizeof(downspread)); + + core_link_write_dpcd(link, DP_LANE_COUNT_SET, + &lane_count_set.raw, 1); + + rate = get_dpcd_link_rate(<_settings->link_settings); + + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; + + if (link->vendor_specific_lttpr_link_rate_wa == rate) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, + &toggle_rate, + 1); + } + + link->vendor_specific_lttpr_link_rate_wa = rate; + + core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", + __func__, + DP_LINK_BW_SET, + lt_settings->link_settings.link_rate, + DP_LANE_COUNT_SET, + lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, + DP_DOWNSPREAD_CTRL, + lt_settings->link_settings.link_spread); + + /* 2. Perform link training */ + + /* Perform Clock Recovery Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + const uint8_t max_vendor_dpcd_retries = 10; + uint32_t retries_cr; + uint32_t retry_count; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; + union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + enum dc_status dpcd_status = DC_OK; + uint8_t i = 0; + + retries_cr = 0; + retry_count = 0; + + memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); + memset(&dpcd_lane_status_updated, '\0', + sizeof(dpcd_lane_status_updated)); + + while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + + + /* 1. call HWSS to set lane settings */ + dp_set_hw_lane_settings( + link, + link_res, + lt_settings, + 0); + + /* 2. update DPCD of the receiver */ + if (!retry_count) { + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration. + */ + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + lt_settings->pattern_for_cr, + 0); + /* Vendor specific: Disable intercept */ + for (i = 0; i < max_vendor_dpcd_retries; i++) { + msleep(pre_disable_intercept_delay_ms); + dpcd_status = core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_dis[0], + sizeof(vendor_lttpr_write_data_intercept_dis)); + + if (dpcd_status == DC_OK) + break; + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + } + } else { + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + dpcd_set_lane_settings( + link, + lt_settings, + 0); + } + + /* 3. wait receiver to lock-on*/ + wait_time_microsec = lt_settings->cr_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested drive + * settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 6. max VS reached*/ + if (dp_is_max_vs_reached(lt_settings)) + break; + + /* 7. same lane settings */ + /* Note: settings are the same for all lanes, + * so comparing first lane is sufficient + */ + if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + retries_cr++; + else + retries_cr = 0; + + /* 8. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + retry_count++; + } + + if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { + ASSERT(0); + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + __func__, + LINK_TRAINING_MAX_CR_RETRY); + + } + + status = dp_get_cr_failure(lane_count, dpcd_lane_status); + } + + /* Perform Channel EQ Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + enum dc_dp_training_pattern tr_pattern; + uint32_t retries_ch_eq; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + /* Note: also check that TPS4 is a supported feature*/ + tr_pattern = lt_settings->pattern_for_eq; + + dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); + + status = LINK_TRAINING_EQ_FAIL_EQ; + + for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; + retries_ch_eq++) { + + dp_set_hw_lane_settings(link, link_res, lt_settings, 0); + + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* 2. update DPCD*/ + if (!retries_ch_eq) + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration + */ + + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + tr_pattern, 0); + else + dpcd_set_lane_settings(link, lt_settings, 0); + + /* 3. wait for receiver to lock-on*/ + wait_time_microsec = lt_settings->eq_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested + * drive settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_EQ_FAIL_CR; + break; + } + + /* 6. check CHEQ done*/ + if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && + dp_is_symbol_locked(lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 7. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + } + + return status; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.h new file mode 100644 index 000000000000..e61970e27661 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ +#define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ +#include "link_dp_training.h" + +enum link_training_result dp_perform_fixed_vs_pe_training_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings); + +void dp_fixed_vs_pe_set_retimer_lane_settings( + struct dc_link *link, + const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], + uint8_t lane_count); + +void dp_fixed_vs_pe_read_lane_adjust( + struct dc_link *link, + union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]); + +#endif /* __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.c index af110bf9470f..5c9a30211c10 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.c @@ -23,11 +23,14 @@ * */ -#include <inc/core_status.h> -#include <dc_link.h> -#include <inc/link_hwss.h> -#include <inc/link_dpcd.h> -#include <dc_dp_types.h> +/* FILE POLICY AND INTENDED USAGE: + * + * This file implements basic dpcd read/write functionality. It also does basic + * dpcd range check to ensure that every dpcd request is compliant with specs + * range requirements. + */ + +#include "link_dpcd.h" #include <drm/display/drm_dp_helper.h> #include "dm_helpers.h" diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.h index d561f86d503c..08d787a1e451 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.h @@ -25,9 +25,8 @@ #ifndef __LINK_DPCD_H__ #define __LINK_DPCD_H__ -#include <inc/core_status.h> -#include <dc_link.h> -#include <dc_link_dp.h> +#include "link.h" +#include "dpcd_defs.h" enum dc_status core_link_read_dpcd( struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hpd.c b/drivers/gpu/drm/amd/display/dc/link/link_hpd.c new file mode 100644 index 000000000000..5f39dfe06e9a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_hpd.c @@ -0,0 +1,240 @@ +/* + * Copyright 2022 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: AMD + * + */ + +/* FILE POLICY AND INTENDED USAGE: + * + * This file implements functions that manage basic HPD components such as gpio. + * It also provides wrapper functions to execute HPD related programming. This + * file only manages basic HPD functionality. It doesn't manage detection or + * feature or signal specific HPD behaviors. + */ +#include "link_hpd.h" +#include "gpio_service_interface.h" + +bool dc_link_get_hpd_state(struct dc_link *dc_link) +{ + uint32_t state; + + dal_gpio_lock_pin(dc_link->hpd_gpio); + dal_gpio_get_value(dc_link->hpd_gpio, &state); + dal_gpio_unlock_pin(dc_link->hpd_gpio); + + return state; +} + +void dc_link_enable_hpd(const struct dc_link *link) +{ + struct link_encoder *encoder = link->link_enc; + + if (encoder != NULL && encoder->funcs->enable_hpd != NULL) + encoder->funcs->enable_hpd(encoder); +} + +void dc_link_disable_hpd(const struct dc_link *link) +{ + struct link_encoder *encoder = link->link_enc; + + if (encoder != NULL && encoder->funcs->enable_hpd != NULL) + encoder->funcs->disable_hpd(encoder); +} + +void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) +{ + struct gpio *hpd; + + if (enable) { + link->is_hpd_filter_disabled = false; + program_hpd_filter(link); + } else { + link->is_hpd_filter_disabled = true; + /* Obtain HPD handle */ + hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); + + if (!hpd) + return; + + /* Setup HPD filtering */ + if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) { + struct gpio_hpd_config config; + + config.delay_on_connect = 0; + config.delay_on_disconnect = 0; + + dal_irq_setup_hpd_filter(hpd, &config); + + dal_gpio_close(hpd); + } else { + ASSERT_CRITICAL(false); + } + /* Release HPD handle */ + dal_gpio_destroy_irq(&hpd); + } +} + +struct gpio *link_get_hpd_gpio(struct dc_bios *dcb, + struct graphics_object_id link_id, + struct gpio_service *gpio_service) +{ + enum bp_result bp_result; + struct graphics_object_hpd_info hpd_info; + struct gpio_pin_info pin_info; + + if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK) + return NULL; + + bp_result = dcb->funcs->get_gpio_pin_info(dcb, + hpd_info.hpd_int_gpio_uid, &pin_info); + + if (bp_result != BP_RESULT_OK) { + ASSERT(bp_result == BP_RESULT_NORECORD); + return NULL; + } + + return dal_gpio_service_create_irq(gpio_service, + pin_info.offset, + pin_info.mask); +} + +bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high) +{ + struct gpio *hpd_pin = link_get_hpd_gpio( + link->ctx->dc_bios, link->link_id, + link->ctx->gpio_service); + if (!hpd_pin) + return false; + + dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT); + dal_gpio_get_value(hpd_pin, is_hpd_high); + dal_gpio_close(hpd_pin); + dal_gpio_destroy_irq(&hpd_pin); + return true; +} + +enum hpd_source_id get_hpd_line(struct dc_link *link) +{ + struct gpio *hpd; + enum hpd_source_id hpd_id; + + hpd_id = HPD_SOURCEID_UNKNOWN; + + hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, + link->ctx->gpio_service); + + if (hpd) { + switch (dal_irq_get_source(hpd)) { + case DC_IRQ_SOURCE_HPD1: + hpd_id = HPD_SOURCEID1; + break; + case DC_IRQ_SOURCE_HPD2: + hpd_id = HPD_SOURCEID2; + break; + case DC_IRQ_SOURCE_HPD3: + hpd_id = HPD_SOURCEID3; + break; + case DC_IRQ_SOURCE_HPD4: + hpd_id = HPD_SOURCEID4; + break; + case DC_IRQ_SOURCE_HPD5: + hpd_id = HPD_SOURCEID5; + break; + case DC_IRQ_SOURCE_HPD6: + hpd_id = HPD_SOURCEID6; + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + dal_gpio_destroy_irq(&hpd); + } + + return hpd_id; +} + +bool program_hpd_filter(const struct dc_link *link) +{ + bool result = false; + struct gpio *hpd; + int delay_on_connect_in_ms = 0; + int delay_on_disconnect_in_ms = 0; + + if (link->is_hpd_filter_disabled) + return false; + /* Verify feature is supported */ + switch (link->connector_signal) { + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + case SIGNAL_TYPE_HDMI_TYPE_A: + /* Program hpd filter */ + delay_on_connect_in_ms = 500; + delay_on_disconnect_in_ms = 100; + break; + case SIGNAL_TYPE_DISPLAY_PORT: + case SIGNAL_TYPE_DISPLAY_PORT_MST: + /* Program hpd filter to allow DP signal to settle */ + /* 500: not able to detect MST <-> SST switch as HPD is low for + * only 100ms on DELL U2413 + * 0: some passive dongle still show aux mode instead of i2c + * 20-50: not enough to hide bouncing HPD with passive dongle. + * also see intermittent i2c read issues. + */ + delay_on_connect_in_ms = 80; + delay_on_disconnect_in_ms = 0; + break; + case SIGNAL_TYPE_LVDS: + case SIGNAL_TYPE_EDP: + default: + /* Don't program hpd filter */ + return false; + } + + /* Obtain HPD handle */ + hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, + link->ctx->gpio_service); + + if (!hpd) + return result; + + /* Setup HPD filtering */ + if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) { + struct gpio_hpd_config config; + + config.delay_on_connect = delay_on_connect_in_ms; + config.delay_on_disconnect = delay_on_disconnect_in_ms; + + dal_irq_setup_hpd_filter(hpd, &config); + + dal_gpio_close(hpd); + + result = true; + } else { + ASSERT_CRITICAL(false); + } + + /* Release HPD handle */ + dal_gpio_destroy_irq(&hpd); + + return result; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hpd.h b/drivers/gpu/drm/amd/display/dc/link/link_hpd.h new file mode 100644 index 000000000000..3d122def0c88 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/link_hpd.h @@ -0,0 +1,47 @@ +/* + * Copyright 2022 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: AMD + * + */ + + +#ifndef __DC_LINK_HPD_H__ +#define __DC_LINK_HPD_H__ +#include "link.h" + +enum hpd_source_id get_hpd_line(struct dc_link *link); +/* + * Function: program_hpd_filter + * + * @brief + * Programs HPD filter on associated HPD line to default values. + * + * @return + * true on success, false otherwise + */ +bool program_hpd_filter(const struct dc_link *link); +/* Query hot plug status of USB4 DP tunnel. + * Returns true if HPD high. + */ +bool dpia_query_hpd_status(struct dc_link *link); +bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high); +#endif /* __DC_LINK_HPD_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c index 2f46e1ac4ce0..164d631e8809 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c @@ -87,57 +87,20 @@ static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx, hblank_min_symbol_width); } -static int get_odm_segment_count(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; - int count = 1; - - while (odm_pipe != NULL) { - count++; - odm_pipe = odm_pipe->next_odm_pipe; - } - - return count; -} - static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx) { - struct dc *dc = pipe_ctx->stream->ctx->dc; struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc; struct hpo_dp_link_encoder *link_enc = pipe_ctx->link_res.hpo_dp_link_enc; - struct dccg *dccg = dc->res_pool->dccg; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - struct dtbclk_dto_params dto_params = {0}; - enum phyd32clk_clock_source phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link); - dto_params.otg_inst = tg->inst; - dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; - dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); - dto_params.timing = &pipe_ctx->stream->timing; - dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); - - dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, stream_enc->inst); - dccg->funcs->enable_symclk32_se(dccg, stream_enc->inst, phyd32clk); - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); stream_enc->funcs->enable_stream(stream_enc); stream_enc->funcs->map_stream_to_link(stream_enc, stream_enc->inst, link_enc->inst); } static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx) { - struct dc *dc = pipe_ctx->stream->ctx->dc; struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc; - struct dccg *dccg = dc->res_pool->dccg; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - struct dtbclk_dto_params dto_params = {0}; - - dto_params.otg_inst = tg->inst; - dto_params.timing = &pipe_ctx->stream->timing; stream_enc->funcs->disable(stream_enc); - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); - dccg->funcs->disable_symclk32_se(dccg, stream_enc->inst); - dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, stream_enc->inst); } static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index eb5b7eb292ef..a391b939d709 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -126,10 +126,22 @@ enum dmub_notification_type { DMUB_NOTIFICATION_HPD, DMUB_NOTIFICATION_HPD_IRQ, DMUB_NOTIFICATION_SET_CONFIG_REPLY, + DMUB_NOTIFICATION_DPIA_NOTIFICATION, DMUB_NOTIFICATION_MAX }; /** + * DPIA NOTIFICATION Response Type + */ +enum dpia_notify_bw_alloc_status { + + DPIA_BW_REQ_FAILED = 0, + DPIA_BW_REQ_SUCCESS, + DPIA_EST_BW_CHANGED, + DPIA_BW_ALLOC_CAPS_CHANGED +}; + +/** * struct dmub_region - dmub hw memory region * @base: base address for region, must be 256 byte aligned * @top: top address for region @@ -453,6 +465,7 @@ struct dmub_srv { * @pending_notification: Indicates there are other pending notifications * @aux_reply: aux reply * @hpd_status: hpd status + * @bw_alloc_reply: BW Allocation reply from CM/DPIA */ struct dmub_notification { enum dmub_notification_type type; @@ -463,6 +476,10 @@ struct dmub_notification { struct aux_reply_data aux_reply; enum dp_hpd_status hpd_status; enum set_config_status sc_status; + /** + * DPIA notification command. + */ + struct dmub_rb_cmd_dpia_notification dpia_notification; }; }; diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 33907feefebb..06c553b61322 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -770,6 +770,10 @@ enum dmub_out_cmd_type { * Command type used for SET_CONFIG Reply notification */ DMUB_OUT_CMD__SET_CONFIG_REPLY = 3, + /** + * Command type used for USB4 DPIA notification + */ + DMUB_OUT_CMD__DPIA_NOTIFICATION = 5, }; /* DMUB_CMD__DPIA command sub-types. */ @@ -779,6 +783,11 @@ enum dmub_cmd_dpia_type { DMUB_CMD__DPIA_MST_ALLOC_SLOTS = 2, }; +/* DMUB_OUT_CMD__DPIA_NOTIFICATION command types. */ +enum dmub_cmd_dpia_notification_type { + DPIA_NOTIFY__BW_ALLOCATION = 0, +}; + #pragma pack(push, 1) /** @@ -1558,6 +1567,79 @@ struct dmub_rb_cmd_dp_set_config_reply { }; /** + * Definition of a DPIA notification header + */ +struct dpia_notification_header { + uint8_t instance; /**< DPIA Instance */ + uint8_t reserved[3]; + enum dmub_cmd_dpia_notification_type type; /**< DPIA notification type */ +}; + +/** + * Definition of the common data struct of DPIA notification + */ +struct dpia_notification_common { + uint8_t cmd_buffer[DMUB_RB_CMD_SIZE - sizeof(struct dmub_cmd_header) + - sizeof(struct dpia_notification_header)]; +}; + +/** + * Definition of a DPIA notification data + */ +struct dpia_bw_allocation_notify_data { + union { + struct { + uint16_t cm_bw_alloc_support: 1; /**< USB4 CM BW Allocation mode support */ + uint16_t bw_request_failed: 1; /**< BW_Request_Failed */ + uint16_t bw_request_succeeded: 1; /**< BW_Request_Succeeded */ + uint16_t est_bw_changed: 1; /**< Estimated_BW changed */ + uint16_t bw_alloc_cap_changed: 1; /**< BW_Allocation_Capabiity_Changed */ + uint16_t reserved: 11; /**< Reserved */ + } bits; + + uint16_t flags; + }; + + uint8_t cm_id; /**< CM ID */ + uint8_t group_id; /**< Group ID */ + uint8_t granularity; /**< BW Allocation Granularity */ + uint8_t estimated_bw; /**< Estimated_BW */ + uint8_t allocated_bw; /**< Allocated_BW */ + uint8_t reserved; +}; + +/** + * union dpia_notify_data_type - DPIA Notification in Outbox command + */ +union dpia_notification_data { + /** + * DPIA Notification for common data struct + */ + struct dpia_notification_common common_data; + + /** + * DPIA Notification for DP BW Allocation support + */ + struct dpia_bw_allocation_notify_data dpia_bw_alloc; +}; + +/** + * Definition of a DPIA notification payload + */ +struct dpia_notification_payload { + struct dpia_notification_header header; + union dpia_notification_data data; /**< DPIA notification payload data */ +}; + +/** + * Definition of a DMUB_OUT_CMD__DPIA_NOTIFICATION command. + */ +struct dmub_rb_cmd_dpia_notification { + struct dmub_cmd_header header; /**< DPIA notification header */ + struct dpia_notification_payload payload; /**< DPIA notification payload */ +}; + +/** * Data passed from driver to FW in a DMUB_CMD__QUERY_HPD_STATE command. */ struct dmub_cmd_hpd_state_query_data { @@ -3029,7 +3111,8 @@ struct dmub_rb_cmd_panel_cntl { */ struct dmub_cmd_lvtma_control_data { uint8_t uc_pwr_action; /**< LVTMA_ACTION */ - uint8_t reserved_0[3]; /**< For future use */ + uint8_t bypass_panel_control_wait; + uint8_t reserved_0[2]; uint8_t panel_inst; /**< LVTMA control instance */ uint8_t reserved_1[3]; /**< For future use */ }; @@ -3422,6 +3505,10 @@ union dmub_rb_out_cmd { * SET_CONFIG reply command. */ struct dmub_rb_cmd_dp_set_config_reply set_config_reply; + /** + * DPIA notification command. + */ + struct dmub_rb_cmd_dpia_notification dpia_notification; }; #pragma pack(pop) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c index 44502ec919a2..74189102eaec 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c @@ -92,6 +92,27 @@ enum dmub_status dmub_srv_stat_get_notification(struct dmub_srv *dmub, notify->link_index = cmd.set_config_reply.set_config_reply_control.instance; notify->sc_status = cmd.set_config_reply.set_config_reply_control.status; break; + case DMUB_OUT_CMD__DPIA_NOTIFICATION: + notify->type = DMUB_NOTIFICATION_DPIA_NOTIFICATION; + notify->link_index = cmd.dpia_notification.payload.header.instance; + + if (cmd.dpia_notification.payload.header.type == DPIA_NOTIFY__BW_ALLOCATION) { + + notify->dpia_notification.payload.data.dpia_bw_alloc.estimated_bw = + cmd.dpia_notification.payload.data.dpia_bw_alloc.estimated_bw; + notify->dpia_notification.payload.data.dpia_bw_alloc.allocated_bw = + cmd.dpia_notification.payload.data.dpia_bw_alloc.allocated_bw; + + if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.bw_request_failed) + notify->result = DPIA_BW_REQ_FAILED; + else if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.bw_request_succeeded) + notify->result = DPIA_BW_REQ_SUCCESS; + else if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.est_bw_changed) + notify->result = DPIA_EST_BW_CHANGED; + else if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.bw_alloc_cap_changed) + notify->result = DPIA_BW_ALLOC_CAPS_CHANGED; + } + break; default: notify->type = DMUB_NOTIFICATION_NO_DATA; break; diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h index a7ba5bd8dc16..3610f71891a3 100644 --- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h +++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h @@ -133,6 +133,11 @@ static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5}; static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u"; +/*Travis*/ +static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT"; +/*Nutmeg*/ +static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; + /*MST Dock*/ static const uint8_t SYNAPTICS_DEVICE_ID[] = "SYNA"; diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h index b2df07f9e91c..c062a44db078 100644 --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h @@ -88,7 +88,10 @@ enum dpcd_phy_test_patterns { PHY_TEST_PATTERN_PRBS23 = 0x30, PHY_TEST_PATTERN_PRBS31 = 0x38, PHY_TEST_PATTERN_264BIT_CUSTOM = 0x40, - PHY_TEST_PATTERN_SQUARE_PULSE = 0x48, + PHY_TEST_PATTERN_SQUARE = 0x48, + PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED = 0x49, + PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED = 0x4A, + PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED = 0x4B, }; enum dpcd_test_dyn_range { diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index d1e91d31d151..18b9173d5a96 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -165,7 +165,12 @@ enum dp_test_pattern { DP_TEST_PATTERN_PRBS23, DP_TEST_PATTERN_PRBS31, DP_TEST_PATTERN_264BIT_CUSTOM, - DP_TEST_PATTERN_SQUARE_PULSE, + DP_TEST_PATTERN_SQUARE_BEGIN, + DP_TEST_PATTERN_SQUARE = DP_TEST_PATTERN_SQUARE_BEGIN, + DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED, + DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED, + DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED, + DP_TEST_PATTERN_SQUARE_END = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED, /* Link Training Patterns */ DP_TEST_PATTERN_TRAINING_PATTERN1, diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index c2e00f7b8381..315da61ee897 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -616,7 +616,8 @@ static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr, } static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) + struct dc_info_packet *infopacket, + bool freesync_on_desktop) { unsigned int min_refresh; unsigned int max_refresh; @@ -649,9 +650,15 @@ static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr, infopacket->sb[6] |= 0x02; /* PB6 = [Bit 2 = FreeSync Active] */ - if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || + if (freesync_on_desktop) { + if (vrr->state != VRR_STATE_DISABLED && + vrr->state != VRR_STATE_UNSUPPORTED) + infopacket->sb[6] |= 0x04; + } else { + if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || vrr->state == VRR_STATE_ACTIVE_FIXED) - infopacket->sb[6] |= 0x04; + infopacket->sb[6] |= 0x04; + } min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000; max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000; @@ -898,52 +905,20 @@ static void build_vrr_infopacket_v2(enum signal_type signal, infopacket->valid = true; } -#ifndef TRIM_FSFT -static void build_vrr_infopacket_fast_transport_data( - bool ftActive, - unsigned int ftOutputRate, - struct dc_info_packet *infopacket) -{ - /* PB9 : bit7 - fast transport Active*/ - unsigned char activeBit = (ftActive) ? 1 << 7 : 0; - - infopacket->sb[1] &= ~activeBit; //clear bit - infopacket->sb[1] |= activeBit; //set bit - - /* PB13 : Target Output Pixel Rate [kHz] - bits 7:0 */ - infopacket->sb[13] = ftOutputRate & 0xFF; - - /* PB14 : Target Output Pixel Rate [kHz] - bits 15:8 */ - infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF; - - /* PB15 : Target Output Pixel Rate [kHz] - bits 23:16 */ - infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF; - -} -#endif static void build_vrr_infopacket_v3(enum signal_type signal, const struct mod_vrr_params *vrr, -#ifndef TRIM_FSFT - bool ftActive, unsigned int ftOutputRate, -#endif enum color_transfer_func app_tf, - struct dc_info_packet *infopacket) + struct dc_info_packet *infopacket, + bool freesync_on_desktop) { unsigned int payload_size = 0; build_vrr_infopacket_header_v3(signal, infopacket, &payload_size); - build_vrr_infopacket_data_v3(vrr, infopacket); + build_vrr_infopacket_data_v3(vrr, infopacket, freesync_on_desktop); build_vrr_infopacket_fs2_data(app_tf, infopacket); -#ifndef TRIM_FSFT - build_vrr_infopacket_fast_transport_data( - ftActive, - ftOutputRate, - infopacket); -#endif - build_vrr_infopacket_checksum(&payload_size, infopacket); infopacket->valid = true; @@ -985,18 +960,7 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, switch (packet_type) { case PACKET_TYPE_FS_V3: -#ifndef TRIM_FSFT - // always populate with pixel rate. - build_vrr_infopacket_v3( - stream->signal, vrr, - stream->timing.flags.FAST_TRANSPORT, - (stream->timing.flags.FAST_TRANSPORT) ? - stream->timing.fast_transport_output_rate_100hz : - stream->timing.pix_clk_100hz, - app_tf, infopacket); -#else - build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket); -#endif + build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop); break; case PACKET_TYPE_FS_V2: build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop); diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 9b5d9b2c9a6a..cf4fa87c7db6 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -916,3 +916,34 @@ bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_s { return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal); } + +bool psr_su_set_y_granularity(struct dc *dc, struct dc_link *link, + struct dc_stream_state *stream, + struct psr_config *config) +{ + uint16_t pic_height; + uint8_t slice_height; + + if ((link->connector_signal & SIGNAL_TYPE_EDP) && + (!dc->caps.edp_dsc_support || + link->panel_config.dsc.disable_dsc_edp || + !link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT || + !stream->timing.dsc_cfg.num_slices_v)) + return true; + + pic_height = stream->timing.v_addressable + + stream->timing.v_border_top + stream->timing.v_border_bottom; + slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v; + + if (slice_height) { + if (config->su_y_granularity && + (slice_height % config->su_y_granularity)) { + ASSERT(0); + return false; + } + + config->su_y_granularity = slice_height; + } + + return true; +} diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h index 316452e9dbc9..bb16b37b83da 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -59,4 +59,7 @@ void mod_power_calc_psr_configs(struct psr_config *psr_config, const struct dc_stream_state *stream); bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream); +bool psr_su_set_y_granularity(struct dc *dc, struct dc_link *link, + struct dc_stream_state *stream, + struct psr_config *config); #endif /* MODULES_POWER_POWER_HELPERS_H_ */ diff --git a/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h new file mode 100644 index 000000000000..fbb18e44ec52 --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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) 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 _df_4_3_OFFSET_HEADER +#define _df_4_3_OFFSET_HEADER + +#define regDF_CS_UMC_AON0_HardwareAssertMaskLow 0x0e3e +#define regDF_CS_UMC_AON0_HardwareAssertMaskLow_BASE_IDX 4 +#define regDF_NCS_PG0_HardwareAssertMaskHigh 0x0e3f +#define regDF_NCS_PG0_HardwareAssertMaskHigh_BASE_IDX 4 + +#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h new file mode 100644 index 000000000000..9c8f19ded4eb --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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) 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 _df_4_3_SH_MASK_HEADER +#define _df_4_3_SH_MASK_HEADER + +//DF_CS_UMC_AON0_HardwareAssertMaskLow +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk0__SHIFT 0x0 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk1__SHIFT 0x1 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk2__SHIFT 0x2 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk3__SHIFT 0x3 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk4__SHIFT 0x4 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk5__SHIFT 0x5 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk6__SHIFT 0x6 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk7__SHIFT 0x7 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk8__SHIFT 0x8 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk9__SHIFT 0x9 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk10__SHIFT 0xa +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk11__SHIFT 0xb +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk12__SHIFT 0xc +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk13__SHIFT 0xd +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk14__SHIFT 0xe +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk15__SHIFT 0xf +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk16__SHIFT 0x10 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk17__SHIFT 0x11 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk18__SHIFT 0x12 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk19__SHIFT 0x13 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk20__SHIFT 0x14 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk21__SHIFT 0x15 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk22__SHIFT 0x16 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk23__SHIFT 0x17 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk24__SHIFT 0x18 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk25__SHIFT 0x19 +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk26__SHIFT 0x1a +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk27__SHIFT 0x1b +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk28__SHIFT 0x1c +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk29__SHIFT 0x1d +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk30__SHIFT 0x1e +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk31__SHIFT 0x1f +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk0_MASK 0x00000001L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk1_MASK 0x00000002L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk2_MASK 0x00000004L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk3_MASK 0x00000008L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk4_MASK 0x00000010L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk5_MASK 0x00000020L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk6_MASK 0x00000040L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk7_MASK 0x00000080L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk8_MASK 0x00000100L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk9_MASK 0x00000200L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk10_MASK 0x00000400L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk11_MASK 0x00000800L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk12_MASK 0x00001000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk13_MASK 0x00002000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk14_MASK 0x00004000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk15_MASK 0x00008000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk16_MASK 0x00010000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk17_MASK 0x00020000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk18_MASK 0x00040000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk19_MASK 0x00080000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk20_MASK 0x00100000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk21_MASK 0x00200000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk22_MASK 0x00400000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk23_MASK 0x00800000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk24_MASK 0x01000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk25_MASK 0x02000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk26_MASK 0x04000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk27_MASK 0x08000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk28_MASK 0x10000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk29_MASK 0x20000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk30_MASK 0x40000000L +#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk31_MASK 0x80000000L + +//DF_NCS_PG0_HardwareAssertMaskHigh +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk0__SHIFT 0x0 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk1__SHIFT 0x1 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk2__SHIFT 0x2 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk3__SHIFT 0x3 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk4__SHIFT 0x4 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk5__SHIFT 0x5 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk6__SHIFT 0x6 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk7__SHIFT 0x7 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk8__SHIFT 0x8 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk9__SHIFT 0x9 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk10__SHIFT 0xa +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk11__SHIFT 0xb +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk12__SHIFT 0xc +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk13__SHIFT 0xd +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk14__SHIFT 0xe +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk15__SHIFT 0xf +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk16__SHIFT 0x10 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk17__SHIFT 0x11 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk18__SHIFT 0x12 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk19__SHIFT 0x13 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk20__SHIFT 0x14 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk21__SHIFT 0x15 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk22__SHIFT 0x16 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk23__SHIFT 0x17 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk24__SHIFT 0x18 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk25__SHIFT 0x19 +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk26__SHIFT 0x1a +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk27__SHIFT 0x1b +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk28__SHIFT 0x1c +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk29__SHIFT 0x1d +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk30__SHIFT 0x1e +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk31__SHIFT 0x1f +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk0_MASK 0x00000001L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk1_MASK 0x00000002L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk2_MASK 0x00000004L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk3_MASK 0x00000008L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk4_MASK 0x00000010L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk5_MASK 0x00000020L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk6_MASK 0x00000040L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk7_MASK 0x00000080L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk8_MASK 0x00000100L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk9_MASK 0x00000200L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk10_MASK 0x00000400L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk11_MASK 0x00000800L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk12_MASK 0x00001000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk13_MASK 0x00002000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk14_MASK 0x00004000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk15_MASK 0x00008000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk16_MASK 0x00010000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk17_MASK 0x00020000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk18_MASK 0x00040000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk19_MASK 0x00080000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk20_MASK 0x00100000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk21_MASK 0x00200000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk22_MASK 0x00400000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk23_MASK 0x00800000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk24_MASK 0x01000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk25_MASK 0x02000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk26_MASK 0x04000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk27_MASK 0x08000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk28_MASK 0x10000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk29_MASK 0x20000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk30_MASK 0x40000000L +#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk31_MASK 0x80000000L + +#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h index 3b95a59b196c..56e00252bff8 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h @@ -3593,6 +3593,14 @@ #define regGCL2TLB_PERFCOUNTER_RSLT_CNTL_BASE_IDX 1 +// addressBlock: gc_rlcsdec +// base address: 0x3b980 +#define regRLC_RLCS_FED_STATUS_0 0x4eff +#define regRLC_RLCS_FED_STATUS_0_BASE_IDX 1 +#define regRLC_RLCS_FED_STATUS_1 0x4f00 +#define regRLC_RLCS_FED_STATUS_1_BASE_IDX 1 + + // addressBlock: gc_gcvml2pspdec // base address: 0x3f900 #define regGCUTCL2_TRANSLATION_BYPASS_BY_VMID 0x5e41 diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h index ae3ef8a9e702..658e88a8e2ac 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h @@ -37642,6 +37642,56 @@ #define RLC_RLCG_DOORBELL_RANGE__LOWER_ADDR_MASK 0x00000FFCL #define RLC_RLCG_DOORBELL_RANGE__UPPER_ADDR_RESERVED_MASK 0x00030000L #define RLC_RLCG_DOORBELL_RANGE__UPPER_ADDR_MASK 0x0FFC0000L +//RLC_RLCS_FED_STATUS_0 +#define RLC_RLCS_FED_STATUS_0__RLC_FED_ERR__SHIFT 0x0 +#define RLC_RLCS_FED_STATUS_0__UTCL2_FED_ERR__SHIFT 0x1 +#define RLC_RLCS_FED_STATUS_0__GE_FED_ERR__SHIFT 0x2 +#define RLC_RLCS_FED_STATUS_0__CPC_FED_ERR__SHIFT 0x3 +#define RLC_RLCS_FED_STATUS_0__CPF_FED_ERR__SHIFT 0x4 +#define RLC_RLCS_FED_STATUS_0__CPG_FED_ERR__SHIFT 0x5 +#define RLC_RLCS_FED_STATUS_0__SDMA0_FED_ERR__SHIFT 0x6 +#define RLC_RLCS_FED_STATUS_0__SDMA1_FED_ERR__SHIFT 0x7 +#define RLC_RLCS_FED_STATUS_0__RLC_FED_ERR_MASK 0x00000001L +#define RLC_RLCS_FED_STATUS_0__UTCL2_FED_ERR_MASK 0x00000002L +#define RLC_RLCS_FED_STATUS_0__GE_FED_ERR_MASK 0x00000004L +#define RLC_RLCS_FED_STATUS_0__CPC_FED_ERR_MASK 0x00000008L +#define RLC_RLCS_FED_STATUS_0__CPF_FED_ERR_MASK 0x00000010L +#define RLC_RLCS_FED_STATUS_0__CPG_FED_ERR_MASK 0x00000020L +#define RLC_RLCS_FED_STATUS_0__SDMA0_FED_ERR_MASK 0x00000040L +#define RLC_RLCS_FED_STATUS_0__SDMA1_FED_ERR_MASK 0x00000080L +//RLC_RLCS_FED_STATUS_1 +#define RLC_RLCS_FED_STATUS_1__GL2C0_FED_ERR__SHIFT 0x0 +#define RLC_RLCS_FED_STATUS_1__GL2C1_FED_ERR__SHIFT 0x1 +#define RLC_RLCS_FED_STATUS_1__GL2C2_FED_ERR__SHIFT 0x2 +#define RLC_RLCS_FED_STATUS_1__GL2C3_FED_ERR__SHIFT 0x3 +#define RLC_RLCS_FED_STATUS_1__GL2C4_FED_ERR__SHIFT 0x4 +#define RLC_RLCS_FED_STATUS_1__GL2C5_FED_ERR__SHIFT 0x5 +#define RLC_RLCS_FED_STATUS_1__GL2C6_FED_ERR__SHIFT 0x6 +#define RLC_RLCS_FED_STATUS_1__GL2C7_FED_ERR__SHIFT 0x7 +#define RLC_RLCS_FED_STATUS_1__GL2C8_FED_ERR__SHIFT 0x8 +#define RLC_RLCS_FED_STATUS_1__GL2C9_FED_ERR__SHIFT 0x9 +#define RLC_RLCS_FED_STATUS_1__GL2C10_FED_ERR__SHIFT 0xa +#define RLC_RLCS_FED_STATUS_1__GL2C11_FED_ERR__SHIFT 0xb +#define RLC_RLCS_FED_STATUS_1__GL2C12_FED_ERR__SHIFT 0xc +#define RLC_RLCS_FED_STATUS_1__GL2C13_FED_ERR__SHIFT 0xd +#define RLC_RLCS_FED_STATUS_1__GL2C14_FED_ERR__SHIFT 0xe +#define RLC_RLCS_FED_STATUS_1__GL2C15_FED_ERR__SHIFT 0xf +#define RLC_RLCS_FED_STATUS_1__GL2C0_FED_ERR_MASK 0x00000001L +#define RLC_RLCS_FED_STATUS_1__GL2C1_FED_ERR_MASK 0x00000002L +#define RLC_RLCS_FED_STATUS_1__GL2C2_FED_ERR_MASK 0x00000004L +#define RLC_RLCS_FED_STATUS_1__GL2C3_FED_ERR_MASK 0x00000008L +#define RLC_RLCS_FED_STATUS_1__GL2C4_FED_ERR_MASK 0x00000010L +#define RLC_RLCS_FED_STATUS_1__GL2C5_FED_ERR_MASK 0x00000020L +#define RLC_RLCS_FED_STATUS_1__GL2C6_FED_ERR_MASK 0x00000040L +#define RLC_RLCS_FED_STATUS_1__GL2C7_FED_ERR_MASK 0x00000080L +#define RLC_RLCS_FED_STATUS_1__GL2C8_FED_ERR_MASK 0x00000100L +#define RLC_RLCS_FED_STATUS_1__GL2C9_FED_ERR_MASK 0x00000200L +#define RLC_RLCS_FED_STATUS_1__GL2C10_FED_ERR_MASK 0x00000400L +#define RLC_RLCS_FED_STATUS_1__GL2C11_FED_ERR_MASK 0x00000800L +#define RLC_RLCS_FED_STATUS_1__GL2C12_FED_ERR_MASK 0x00001000L +#define RLC_RLCS_FED_STATUS_1__GL2C13_FED_ERR_MASK 0x00002000L +#define RLC_RLCS_FED_STATUS_1__GL2C14_FED_ERR_MASK 0x00004000L +#define RLC_RLCS_FED_STATUS_1__GL2C15_FED_ERR_MASK 0x00008000L //RLC_CGTT_MGCG_OVERRIDE #define RLC_CGTT_MGCG_OVERRIDE__RLC_REPEATER_FGCG_OVERRIDE__SHIFT 0x0 #define RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE__SHIFT 0x1 diff --git a/drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h new file mode 100644 index 000000000000..c6c0cf1376a6 --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h @@ -0,0 +1,87 @@ +/* + * Copyright 2023 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. + * + */ + +#ifndef _xgmi_6_1_0_SH_MASK_HEADER +#define _xgmi_6_1_0_SH_MASK_HEADER + +//PCS_XGMI3X16_PCS_ERROR_STATUS +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataLossErr__SHIFT 0x0 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__TrainingErr__SHIFT 0x1 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlAckErr__SHIFT 0x2 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoUnderflowErr__SHIFT 0x3 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoOverflowErr__SHIFT 0x4 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__CRCErr__SHIFT 0x5 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__BERExceededErr__SHIFT 0x6 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxVcidDataErr__SHIFT 0x7 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayBufParityErr__SHIFT 0x8 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataParityErr__SHIFT 0x9 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoOverflowErr__SHIFT 0xa +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoUnderflowErr__SHIFT 0xb +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ElasticFifoOverflowErr__SHIFT 0xc +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DeskewErr__SHIFT 0xd +#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlCRCErr__SHIFT 0xe +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataStartupLimitErr__SHIFT 0xf +#define PCS_XGMI3X16_PCS_ERROR_STATUS__FCInitTimeoutErr__SHIFT 0x10 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryTimeoutErr__SHIFT 0x11 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialTimeoutErr__SHIFT 0x12 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialAttemptErr__SHIFT 0x13 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryAttemptErr__SHIFT 0x14 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryRelockAttemptErr__SHIFT 0x15 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayAttemptErr__SHIFT 0x16 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__SyncHdrErr__SHIFT 0x17 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxReplayTimeoutErr__SHIFT 0x18 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxReplayTimeoutErr__SHIFT 0x19 +#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubTxTimeoutErr__SHIFT 0x1a +#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubRxTimeoutErr__SHIFT 0x1b +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxCMDPktErr__SHIFT 0x1c +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataLossErr_MASK 0x00000001L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__TrainingErr_MASK 0x00000002L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlAckErr_MASK 0x00000004L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoUnderflowErr_MASK 0x00000008L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoOverflowErr_MASK 0x00000010L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__CRCErr_MASK 0x00000020L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__BERExceededErr_MASK 0x00000040L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxVcidDataErr_MASK 0x00000080L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayBufParityErr_MASK 0x00000100L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataParityErr_MASK 0x00000200L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoOverflowErr_MASK 0x00000400L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoUnderflowErr_MASK 0x00000800L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ElasticFifoOverflowErr_MASK 0x00001000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DeskewErr_MASK 0x00002000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlCRCErr_MASK 0x00004000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataStartupLimitErr_MASK 0x00008000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__FCInitTimeoutErr_MASK 0x00010000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryTimeoutErr_MASK 0x00020000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialTimeoutErr_MASK 0x00040000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialAttemptErr_MASK 0x00080000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryAttemptErr_MASK 0x00100000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryRelockAttemptErr_MASK 0x00200000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayAttemptErr_MASK 0x00400000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__SyncHdrErr_MASK 0x00800000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxReplayTimeoutErr_MASK 0x01000000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxReplayTimeoutErr_MASK 0x02000000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubTxTimeoutErr_MASK 0x04000000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubRxTimeoutErr_MASK 0x08000000L +#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxCMDPktErr_MASK 0x10000000L + +#endif diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h index 9e8ed9f4bb15..3a4670bc4449 100644 --- a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h +++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h @@ -49,6 +49,8 @@ #define GFX_11_0_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 65 // 0x41 GPF(Sem incomplete timeout) #define GFX_11_0_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 66 // 0x42 Semaphore wait fail timeout +#define GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT 128 // 0x80 FED Interrupt (for data poisoning) + #define GFX_11_0_0__SRCID__CP_GENERIC_INT 177 // 0xB1 CP_GENERIC int #define GFX_11_0_0__SRCID__CP_PM4_PKT_RSVD_BIT_ERROR 180 // 0xB4 PM4 Pkt Rsvd Bits Error #define GFX_11_0_0__SRCID__CP_EOP_INTERRUPT 181 // 0xB5 End-of-Pipe Interrupt diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index d18162e9ed1d..f3d64c78feaa 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -139,6 +139,8 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_MIN_FAN_RPM, AMDGPU_PP_SENSOR_MAX_FAN_RPM, AMDGPU_PP_SENSOR_VCN_POWER_STATE, + AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK, + AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK, }; enum amd_pp_task { diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 236657eece47..76b9ec64ca50 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3059,7 +3059,7 @@ static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev, * * hwmon interfaces for GPU power: * - * - power1_average: average power used by the GPU in microWatts + * - power1_average: average power used by the SoC in microWatts. On APUs this includes the CPU. * * - power1_cap_min: minimum cap supported in microWatts * diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c index 49c398ec0aaf..d6d9e3b1b2c0 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -7714,20 +7714,13 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); - err = request_firmware(&adev->pm.fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->pm.fw); - -out: + err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name); if (err) { DRM_ERROR("si_smc: Failed to load firmware. err = %d\"%s\"\n", err, fw_name); - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; + amdgpu_ucode_release(&adev->pm.fw); } return err; - } static int si_dpm_sw_init(void *handle) diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 304190d5c9d2..11b7b4cffaae 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -111,8 +111,7 @@ static int pp_sw_fini(void *handle) hwmgr_sw_fini(hwmgr); - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; + amdgpu_ucode_release(&adev->pm.fw); return 0; } @@ -769,10 +768,16 @@ static int pp_dpm_read_sensor(void *handle, int idx, switch (idx) { case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK: - *((uint32_t *)value) = hwmgr->pstate_sclk; + *((uint32_t *)value) = hwmgr->pstate_sclk * 100; return 0; case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK: - *((uint32_t *)value) = hwmgr->pstate_mclk; + *((uint32_t *)value) = hwmgr->pstate_mclk * 100; + return 0; + case AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK: + *((uint32_t *)value) = hwmgr->pstate_sclk_peak * 100; + return 0; + case AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK: + *((uint32_t *)value) = hwmgr->pstate_mclk_peak * 100; return 0; case AMDGPU_PP_SENSOR_MIN_FAN_RPM: *((uint32_t *)value) = hwmgr->thermal_controller.fanInfo.ulMinRPM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c index ede71de2343d..86d6e88c7386 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c @@ -375,6 +375,17 @@ static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr) return 0; } +static void smu10_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr) +{ + hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK; + hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK; + + smum_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetMaxGfxclkFrequency, + &hwmgr->pstate_sclk_peak); + hwmgr->pstate_mclk_peak = SMU10_UMD_PSTATE_PEAK_FCLK; +} + static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; @@ -398,6 +409,8 @@ static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) return ret; } + smu10_populate_umdpstate_clocks(hwmgr); + return 0; } @@ -574,9 +587,6 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; - hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK * 100; - hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK * 100; - /* enable the pp_od_clk_voltage sysfs file */ hwmgr->od_enabled = 1; /* disabled fine grain tuning function by default */ diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index 7ef7e81525a3..89fc32318d80 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -22,7 +22,6 @@ */ #include "pp_debug.h" #include <linux/delay.h> -#include <linux/fb.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> @@ -1501,6 +1500,65 @@ static int smu7_populate_edc_leakage_registers(struct pp_hwmgr *hwmgr) return ret; } +static void smu7_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct smu7_dpm_table *golden_dpm_table = &data->golden_dpm_table; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_sclk = + hwmgr->dyn_state.vddc_dependency_on_sclk; + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_sclk = + table_info->vdd_dep_on_sclk; + int32_t tmp_sclk, count, percentage; + + if (golden_dpm_table->mclk_table.count == 1) { + percentage = 70; + hwmgr->pstate_mclk = golden_dpm_table->mclk_table.dpm_levels[0].value; + } else { + percentage = 100 * golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value / + golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value; + hwmgr->pstate_mclk = golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 2].value; + } + + tmp_sclk = hwmgr->pstate_mclk * percentage / 100; + + if (hwmgr->pp_table_version == PP_TABLE_V0) { + for (count = vddc_dependency_on_sclk->count - 1; count >= 0; count--) { + if (tmp_sclk >= vddc_dependency_on_sclk->entries[count].clk) { + hwmgr->pstate_sclk = vddc_dependency_on_sclk->entries[count].clk; + break; + } + } + if (count < 0) + hwmgr->pstate_sclk = vddc_dependency_on_sclk->entries[0].clk; + + hwmgr->pstate_sclk_peak = + vddc_dependency_on_sclk->entries[vddc_dependency_on_sclk->count - 1].clk; + } else if (hwmgr->pp_table_version == PP_TABLE_V1) { + for (count = vdd_dep_on_sclk->count - 1; count >= 0; count--) { + if (tmp_sclk >= vdd_dep_on_sclk->entries[count].clk) { + hwmgr->pstate_sclk = vdd_dep_on_sclk->entries[count].clk; + break; + } + } + if (count < 0) + hwmgr->pstate_sclk = vdd_dep_on_sclk->entries[0].clk; + + hwmgr->pstate_sclk_peak = + vdd_dep_on_sclk->entries[vdd_dep_on_sclk->count - 1].clk; + } + + hwmgr->pstate_mclk_peak = + golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value; + + /* make sure the output is in Mhz */ + hwmgr->pstate_sclk /= 100; + hwmgr->pstate_mclk /= 100; + hwmgr->pstate_sclk_peak /= 100; + hwmgr->pstate_mclk_peak /= 100; +} + static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result = 0; @@ -1625,6 +1683,8 @@ static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((0 == tmp_result), "pcie performance request failed!", result = tmp_result); + smu7_populate_umdpstate_clocks(hwmgr); + return 0; } @@ -3143,15 +3203,12 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le for (count = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1; count >= 0; count--) { if (tmp_sclk >= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk) { - tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk; *sclk_mask = count; break; } } - if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { + if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) *sclk_mask = 0; - tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].clk; - } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) *sclk_mask = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1; @@ -3161,15 +3218,12 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le for (count = table_info->vdd_dep_on_sclk->count-1; count >= 0; count--) { if (tmp_sclk >= table_info->vdd_dep_on_sclk->entries[count].clk) { - tmp_sclk = table_info->vdd_dep_on_sclk->entries[count].clk; *sclk_mask = count; break; } } - if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { + if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) *sclk_mask = 0; - tmp_sclk = table_info->vdd_dep_on_sclk->entries[0].clk; - } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; @@ -3181,8 +3235,6 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le *mclk_mask = golden_dpm_table->mclk_table.count - 1; *pcie_mask = data->dpm_table.pcie_speed_table.count - 1; - hwmgr->pstate_sclk = tmp_sclk; - hwmgr->pstate_mclk = tmp_mclk; return 0; } @@ -3195,9 +3247,6 @@ static int smu7_force_dpm_level(struct pp_hwmgr *hwmgr, uint32_t mclk_mask = 0; uint32_t pcie_mask = 0; - if (hwmgr->pstate_sclk == 0) - smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask); - switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: ret = smu7_force_dpm_highest(hwmgr); @@ -4153,7 +4202,7 @@ static int smu7_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) if ((0 == data->sclk_dpm_key_disabled) && (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) { + (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) { PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr), "Trying to freeze SCLK DPM when DPM is disabled", ); @@ -4210,7 +4259,7 @@ static int smu7_populate_and_upload_sclk_mclk_dpm_levels( } if (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) { + (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) { result = smum_populate_all_graphic_levels(hwmgr); PP_ASSERT_WITH_CODE((0 == result), "Failed to populate SCLK during PopulateNewDPMClocksStates Function!", @@ -4218,7 +4267,7 @@ static int smu7_populate_and_upload_sclk_mclk_dpm_levels( } if (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) { + (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) { /*populate MCLK dpm table to SMU7 */ result = smum_populate_all_memory_levels(hwmgr); PP_ASSERT_WITH_CODE((0 == result), @@ -4309,7 +4358,7 @@ static int smu7_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) if ((0 == data->sclk_dpm_key_disabled) && (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) { + (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) { PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr), "Trying to Unfreeze SCLK DPM when DPM is disabled", diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c index b50fd4a4a3d1..b015a601b385 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c @@ -1016,6 +1016,18 @@ static void smu8_reset_acp_boot_level(struct pp_hwmgr *hwmgr) data->acp_boot_level = 0xff; } +static void smu8_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr) +{ + struct phm_clock_voltage_dependency_table *table = + hwmgr->dyn_state.vddc_dependency_on_sclk; + + hwmgr->pstate_sclk = table->entries[0].clk / 100; + hwmgr->pstate_mclk = 0; + + hwmgr->pstate_sclk_peak = table->entries[table->count - 1].clk / 100; + hwmgr->pstate_mclk_peak = 0; +} + static int smu8_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { smu8_program_voting_clients(hwmgr); @@ -1024,6 +1036,8 @@ static int smu8_enable_dpm_tasks(struct pp_hwmgr *hwmgr) smu8_program_bootup_state(hwmgr); smu8_reset_acp_boot_level(hwmgr); + smu8_populate_umdpstate_clocks(hwmgr); + return 0; } @@ -1167,8 +1181,6 @@ static int smu8_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr) data->sclk_dpm.soft_min_clk = table->entries[0].clk; data->sclk_dpm.hard_min_clk = table->entries[0].clk; - hwmgr->pstate_sclk = table->entries[0].clk; - hwmgr->pstate_mclk = 0; level = smu8_get_max_sclk_level(hwmgr) - 1; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c index c8c9fb827bda..99cd2e63afdd 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c @@ -22,7 +22,6 @@ */ #include <linux/delay.h> -#include <linux/fb.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> @@ -3008,6 +3007,30 @@ static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool return 0; } +static void vega10_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr) +{ + struct phm_ppt_v2_information *table_info = + (struct phm_ppt_v2_information *)(hwmgr->pptable); + + if (table_info->vdd_dep_on_sclk->count > VEGA10_UMD_PSTATE_GFXCLK_LEVEL && + table_info->vdd_dep_on_mclk->count > VEGA10_UMD_PSTATE_MCLK_LEVEL) { + hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[VEGA10_UMD_PSTATE_GFXCLK_LEVEL].clk; + hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[VEGA10_UMD_PSTATE_MCLK_LEVEL].clk; + } else { + hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk; + hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[0].clk; + } + + hwmgr->pstate_sclk_peak = table_info->vdd_dep_on_sclk->entries[table_info->vdd_dep_on_sclk->count - 1].clk; + hwmgr->pstate_mclk_peak = table_info->vdd_dep_on_mclk->entries[table_info->vdd_dep_on_mclk->count - 1].clk; + + /* make sure the output is in Mhz */ + hwmgr->pstate_sclk /= 100; + hwmgr->pstate_mclk /= 100; + hwmgr->pstate_sclk_peak /= 100; + hwmgr->pstate_mclk_peak /= 100; +} + static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = hwmgr->backend; @@ -3082,6 +3105,8 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) result = tmp_result); } + vega10_populate_umdpstate_clocks(hwmgr); + return result; } @@ -4169,8 +4194,6 @@ static int vega10_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo *sclk_mask = VEGA10_UMD_PSTATE_GFXCLK_LEVEL; *soc_mask = VEGA10_UMD_PSTATE_SOCCLK_LEVEL; *mclk_mask = VEGA10_UMD_PSTATE_MCLK_LEVEL; - hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[VEGA10_UMD_PSTATE_GFXCLK_LEVEL].clk; - hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[VEGA10_UMD_PSTATE_MCLK_LEVEL].clk; } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { @@ -4281,9 +4304,6 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, uint32_t mclk_mask = 0; uint32_t soc_mask = 0; - if (hwmgr->pstate_sclk == 0) - vega10_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask); - switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: ret = vega10_force_dpm_highest(hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c index 95b988823f50..bb90d8abf79b 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> -#include <linux/fb.h> #include "vega10_processpptables.h" #include "ppatomfwctrl.h" diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c index a2f4d6773d45..e9db137cd1c6 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c @@ -22,7 +22,6 @@ */ #include <linux/delay.h> -#include <linux/fb.h> #include <linux/module.h> #include <linux/slab.h> @@ -1026,6 +1025,25 @@ static int vega12_get_all_clock_ranges(struct pp_hwmgr *hwmgr) return 0; } +static void vega12_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + struct vega12_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table); + struct vega12_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table); + + if (gfx_dpm_table->count > VEGA12_UMD_PSTATE_GFXCLK_LEVEL && + mem_dpm_table->count > VEGA12_UMD_PSTATE_MCLK_LEVEL) { + hwmgr->pstate_sclk = gfx_dpm_table->dpm_levels[VEGA12_UMD_PSTATE_GFXCLK_LEVEL].value; + hwmgr->pstate_mclk = mem_dpm_table->dpm_levels[VEGA12_UMD_PSTATE_MCLK_LEVEL].value; + } else { + hwmgr->pstate_sclk = gfx_dpm_table->dpm_levels[0].value; + hwmgr->pstate_mclk = mem_dpm_table->dpm_levels[0].value; + } + + hwmgr->pstate_sclk_peak = gfx_dpm_table->dpm_levels[gfx_dpm_table->count].value; + hwmgr->pstate_mclk_peak = mem_dpm_table->dpm_levels[mem_dpm_table->count].value; +} + static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; @@ -1077,6 +1095,9 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(!result, "Failed to setup default DPM tables!", return result); + + vega12_populate_umdpstate_clocks(hwmgr); + return result; } diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c index bd54fbd393b9..89148f73b514 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c @@ -22,7 +22,6 @@ */ #include <linux/module.h> #include <linux/slab.h> -#include <linux/fb.h> #include "vega12/smu9_driver_if.h" #include "vega12_processpptables.h" diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c index b30684c84e20..0d4d4811527c 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c @@ -22,7 +22,6 @@ */ #include <linux/delay.h> -#include <linux/fb.h> #include <linux/module.h> #include <linux/slab.h> @@ -1555,26 +1554,23 @@ static int vega20_set_mclk_od( return 0; } -static int vega20_populate_umdpstate_clocks( - struct pp_hwmgr *hwmgr) +static void vega20_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr) { struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); struct vega20_single_dpm_table *gfx_table = &(data->dpm_table.gfx_table); struct vega20_single_dpm_table *mem_table = &(data->dpm_table.mem_table); - hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value; - hwmgr->pstate_mclk = mem_table->dpm_levels[0].value; - if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL && mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) { hwmgr->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; hwmgr->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; + } else { + hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value; + hwmgr->pstate_mclk = mem_table->dpm_levels[0].value; } - hwmgr->pstate_sclk = hwmgr->pstate_sclk * 100; - hwmgr->pstate_mclk = hwmgr->pstate_mclk * 100; - - return 0; + hwmgr->pstate_sclk_peak = gfx_table->dpm_levels[gfx_table->count - 1].value; + hwmgr->pstate_mclk_peak = mem_table->dpm_levels[mem_table->count - 1].value; } static int vega20_get_max_sustainable_clock(struct pp_hwmgr *hwmgr, @@ -1753,10 +1749,7 @@ static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr) "[EnableDPMTasks] Failed to initialize odn settings!", return result); - result = vega20_populate_umdpstate_clocks(hwmgr); - PP_ASSERT_WITH_CODE(!result, - "[EnableDPMTasks] Failed to populate umdpstate clocks!", - return result); + vega20_populate_umdpstate_clocks(hwmgr); result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetPptLimit, POWER_SOURCE_AC << 16, &hwmgr->default_power_limit); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c index 1f9082539457..79c817752a33 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c @@ -22,7 +22,6 @@ */ #include <linux/module.h> #include <linux/slab.h> -#include <linux/fb.h> #include "smu11_driver_if.h" #include "vega20_processpptables.h" diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index 27f8d0e0e6a8..5ce433e2c16a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -809,6 +809,8 @@ struct pp_hwmgr { uint32_t workload_prority[Workload_Policy_Max]; uint32_t workload_setting[Workload_Policy_Max]; bool gfxoff_state_changed_by_workload; + uint32_t pstate_sclk_peak; + uint32_t pstate_mclk_peak; }; int hwmgr_early_init(struct pp_hwmgr *hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c index 5ca3c422f7d4..4bc8db1be738 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c @@ -22,7 +22,6 @@ */ #include <linux/module.h> #include <linux/slab.h> -#include <linux/fb.h> #include "linux/delay.h" #include <linux/types.h> #include <linux/pci.h> @@ -2203,7 +2202,7 @@ static int ci_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); if (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK)) + (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK)) return ci_program_memory_timing_parameters(hwmgr); return 0; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c index 03df35dee8ba..060fc140c574 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c @@ -2165,7 +2165,7 @@ static int iceland_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); if (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK)) + (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK)) return iceland_program_memory_timing_parameters(hwmgr); return 0; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c index 88a5641465dc..7eeab84d421a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c @@ -250,9 +250,8 @@ static int smu10_smu_init(struct pp_hwmgr *hwmgr) /* allocate space for watermarks table */ r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - sizeof(Watermarks_t), - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + sizeof(Watermarks_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, &priv->smu_tables.entry[SMU10_WMTABLE].handle, &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, &priv->smu_tables.entry[SMU10_WMTABLE].table); @@ -266,9 +265,8 @@ static int smu10_smu_init(struct pp_hwmgr *hwmgr) /* allocate space for watermarks table */ r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - sizeof(DpmClocks_t), - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, + sizeof(DpmClocks_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, &priv->smu_tables.entry[SMU10_CLOCKTABLE].handle, &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr, &priv->smu_tables.entry[SMU10_CLOCKTABLE].table); diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c index 04b561f5d932..acbe41174d7e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c @@ -2554,7 +2554,7 @@ static int tonga_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); if (data->need_update_smu7_dpm_table & - (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK)) + (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK)) return tonga_program_memory_timing_parameters(hwmgr); return 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ca3beb5d8f27..ec52830dde24 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -623,6 +623,7 @@ static int smu_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu; + int r; smu = kzalloc(sizeof(struct smu_context), GFP_KERNEL); if (!smu) @@ -640,7 +641,10 @@ static int smu_early_init(void *handle) adev->powerplay.pp_handle = smu; adev->powerplay.pp_funcs = &swsmu_pm_funcs; - return smu_set_funcs(adev); + r = smu_set_funcs(adev); + if (r) + return r; + return smu_init_microcode(smu); } static int smu_set_default_dpm_table(struct smu_context *smu) @@ -1067,12 +1071,6 @@ static int smu_sw_init(void *handle) smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; smu->smu_dpm.requested_dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; - ret = smu_init_microcode(smu); - if (ret) { - dev_err(adev->dev, "Failed to load smu firmware!\n"); - return ret; - } - ret = smu_smc_table_sw_init(smu); if (ret) { dev_err(adev->dev, "Failed to sw init smc table!\n"); @@ -2473,6 +2471,14 @@ static int smu_read_sensor(void *handle, *((uint32_t *)data) = pstate_table->uclk_pstate.standard * 100; *size = 4; break; + case AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK: + *((uint32_t *)data) = pstate_table->gfxclk_pstate.peak * 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK: + *((uint32_t *)data) = pstate_table->uclk_pstate.peak * 100; + *size = 4; + break; case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: ret = smu_feature_get_enabled_mask(smu, (uint64_t *)data); *size = 8; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index e8c6febb8b64..913d3a8d7e2f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -244,11 +244,6 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, struct smu_13_0_dpm_table *single_dpm_table); -int smu_v13_0_get_dpm_level_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t *min_value, - uint32_t *max_value); - int smu_v13_0_get_current_pcie_link_width_level(struct smu_context *smu); int smu_v13_0_get_current_pcie_link_width(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index ad66d57aa102..6492d69e2e60 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -93,7 +93,7 @@ static void smu_v11_0_poll_baco_exit(struct smu_context *smu) int smu_v11_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - const char *chip_name; + char ucode_prefix[30]; char fw_name[SMU_FW_NAME_LEN]; int err = 0; const struct smc_firmware_header_v1_0 *hdr; @@ -105,43 +105,11 @@ int smu_v11_0_init_microcode(struct smu_context *smu) (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7)))) return 0; - switch (adev->ip_versions[MP1_HWIP][0]) { - case IP_VERSION(11, 0, 0): - chip_name = "navi10"; - break; - case IP_VERSION(11, 0, 5): - chip_name = "navi14"; - break; - case IP_VERSION(11, 0, 9): - chip_name = "navi12"; - break; - case IP_VERSION(11, 0, 7): - chip_name = "sienna_cichlid"; - break; - case IP_VERSION(11, 0, 11): - chip_name = "navy_flounder"; - break; - case IP_VERSION(11, 0, 12): - chip_name = "dimgrey_cavefish"; - break; - case IP_VERSION(11, 0, 13): - chip_name = "beige_goby"; - break; - case IP_VERSION(11, 0, 2): - chip_name = "arcturus"; - break; - default: - dev_err(adev->dev, "Unsupported IP version 0x%x\n", - adev->ip_versions[MP1_HWIP][0]); - return -EINVAL; - } + amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix)); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); - err = request_firmware(&adev->pm.fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->pm.fw); + err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name); if (err) goto out; @@ -159,12 +127,8 @@ int smu_v11_0_init_microcode(struct smu_context *smu) } out: - if (err) { - DRM_ERROR("smu_v11_0: Failed to load firmware \"%s\"\n", - fw_name); - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; - } + if (err) + amdgpu_ucode_release(&adev->pm.fw); return err; } @@ -172,8 +136,7 @@ void smu_v11_0_fini_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; + amdgpu_ucode_release(&adev->pm.fw); adev->pm.fw_version = 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index 85e22210963f..5cdc07165480 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1171,6 +1171,7 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu, int ret = 0; uint32_t apu_percent = 0; uint32_t dgpu_percent = 0; + struct amdgpu_device *adev = smu->adev; ret = smu_cmn_get_metrics_table(smu, @@ -1196,7 +1197,11 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageUvdActivity / 100; break; case METRICS_AVERAGE_SOCKETPOWER: - *value = (metrics->CurrentSocketPower << 8) / 1000; + if (((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1)) && (adev->pm.fw_version >= 0x40000f)) || + ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 0)) && (adev->pm.fw_version >= 0x373200))) + *value = metrics->CurrentSocketPower << 8; + else + *value = (metrics->CurrentSocketPower << 8) / 1000; break; case METRICS_TEMPERATURE_EDGE: *value = (metrics->GfxTemperature / 100) * diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index e54b760b875b..78945e79dbee 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -88,7 +88,6 @@ static const int link_speed[] = {25, 50, 80, 160}; int smu_v13_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - const char *chip_name; char fw_name[30]; char ucode_prefix[30]; int err = 0; @@ -100,21 +99,11 @@ int smu_v13_0_init_microcode(struct smu_context *smu) if (amdgpu_sriov_vf(adev)) return 0; - switch (adev->ip_versions[MP1_HWIP][0]) { - case IP_VERSION(13, 0, 2): - chip_name = "aldebaran_smc"; - break; - default: - amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix)); - chip_name = ucode_prefix; - } + amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix)); - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix); - err = request_firmware(&adev->pm.fw, fw_name, adev->dev); - if (err) - goto out; - err = amdgpu_ucode_validate(adev->pm.fw); + err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name); if (err) goto out; @@ -132,12 +121,8 @@ int smu_v13_0_init_microcode(struct smu_context *smu) } out: - if (err) { - DRM_ERROR("smu_v13_0: Failed to load firmware \"%s\"\n", - fw_name); - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; - } + if (err) + amdgpu_ucode_release(&adev->pm.fw); return err; } @@ -145,8 +130,7 @@ void smu_v13_0_fini_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - release_firmware(adev->pm.fw); - adev->pm.fw = NULL; + amdgpu_ucode_release(&adev->pm.fw); adev->pm.fw_version = 0; } @@ -1261,7 +1245,8 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) { struct amdgpu_device *adev = smu->adev; - uint32_t tach_period, crystal_clock_freq; + uint32_t crystal_clock_freq = 2500; + uint32_t tach_period; int ret; if (!speed) @@ -1271,7 +1256,6 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, if (ret) return ret; - crystal_clock_freq = amdgpu_asic_get_xclk(adev); tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); WREG32_SOC15(THM, 0, regCG_TACH_CTRL, REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_TACH_CTRL), @@ -2064,45 +2048,6 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu, return 0; } -int smu_v13_0_get_dpm_level_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t *min_value, - uint32_t *max_value) -{ - uint32_t level_count = 0; - int ret = 0; - - if (!min_value && !max_value) - return -EINVAL; - - if (min_value) { - /* by default, level 0 clock value as min value */ - ret = smu_v13_0_get_dpm_freq_by_index(smu, - clk_type, - 0, - min_value); - if (ret) - return ret; - } - - if (max_value) { - ret = smu_v13_0_get_dpm_level_count(smu, - clk_type, - &level_count); - if (ret) - return ret; - - ret = smu_v13_0_get_dpm_freq_by_index(smu, - clk_type, - level_count - 1, - max_value); - if (ret) - return ret; - } - - return ret; -} - int smu_v13_0_get_current_pcie_link_width_level(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2298,6 +2243,10 @@ bool smu_v13_0_baco_is_support(struct smu_context *smu) !smu_baco->platform_support) return false; + /* return true if ASIC is in BACO state already */ + if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER) + return true; + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) return false; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 9643b21c636a..d0cdc578344d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -213,6 +213,7 @@ static struct cmn2asic_mapping smu_v13_0_0_feature_mask_map[SMU_FEATURE_COUNT] = FEA_MAP(SOC_PCC), [SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, [SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, + [SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT}, }; static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = { @@ -240,6 +241,7 @@ static struct cmn2asic_mapping smu_v13_0_0_workload_map[PP_SMC_POWER_PROFILE_COU WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_WINDOW3D, WORKLOAD_PPLIB_WINDOW_3D_BIT), }; static const uint8_t smu_v13_0_0_throttler_map[] = { @@ -1555,7 +1557,7 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu, title[0], title[1], title[2], title[3], title[4], title[5], title[6], title[7], title[8], title[9]); - for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { + for (i = 0; i < PP_SMC_POWER_PROFILE_COUNT; i++) { /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ workload_type = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_WORKLOAD, @@ -1617,7 +1619,7 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, smu->power_profile_mode = input[size]; - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { + if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); return -EINVAL; } @@ -1902,15 +1904,51 @@ static int smu_v13_0_0_set_df_cstate(struct smu_context *smu, NULL); } +static void smu_v13_0_0_set_mode1_reset_param(struct smu_context *smu, + uint32_t supported_version, + uint32_t *param) +{ + uint32_t smu_version; + struct amdgpu_device *adev = smu->adev; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + + smu_cmn_get_smc_version(smu, NULL, &smu_version); + + if ((smu_version >= supported_version) && + ras && atomic_read(&ras->in_recovery)) + /* Set RAS fatal error reset flag */ + *param = 1 << 16; + else + *param = 0; +} + static int smu_v13_0_0_mode1_reset(struct smu_context *smu) { int ret; + uint32_t param; struct amdgpu_device *adev = smu->adev; - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10)) - ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset); - else + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(13, 0, 0): + /* SMU 13_0_0 PMFW supports RAS fatal error reset from 78.77 */ + smu_v13_0_0_set_mode1_reset_param(smu, 0x004e4d00, ¶m); + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_Mode1Reset, param, NULL); + break; + + case IP_VERSION(13, 0, 10): + /* SMU 13_0_10 PMFW supports RAS fatal error reset from 80.28 */ + smu_v13_0_0_set_mode1_reset_param(smu, 0x00501c00, ¶m); + + ret = smu_cmn_send_debug_smc_msg_with_param(smu, + DEBUGSMC_MSG_Mode1Reset, param); + break; + + default: ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL); + break; + } if (!ret) msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 5c6c6ad011ca..e87db7e02e8a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -192,6 +192,7 @@ static struct cmn2asic_mapping smu_v13_0_7_feature_mask_map[SMU_FEATURE_COUNT] = FEA_MAP(SOC_PCC), [SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, [SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, + [SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT}, }; static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 768b6e7dbd77..d5abafc5a682 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -404,6 +404,12 @@ int smu_cmn_send_debug_smc_msg(struct smu_context *smu, return __smu_cmn_send_debug_msg(smu, msg, 0); } +int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, + uint32_t msg, uint32_t param) +{ + return __smu_cmn_send_debug_msg(smu, msg, param); +} + int smu_cmn_to_asic_specific_index(struct smu_context *smu, enum smu_cmn2asic_mapping_type type, uint32_t index) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index f82cf76dd3a4..d7cd358a53bd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -45,6 +45,9 @@ int smu_cmn_send_smc_msg(struct smu_context *smu, int smu_cmn_send_debug_smc_msg(struct smu_context *smu, uint32_t msg); +int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, + uint32_t msg, uint32_t param); + int smu_cmn_wait_for_response(struct smu_context *smu); int smu_cmn_to_asic_specific_index(struct smu_context *smu, |