diff options
Diffstat (limited to 'drivers/gpu')
189 files changed, 2464 insertions, 941 deletions
| diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index dc3c6b3a00e5..269437b01328 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -758,7 +758,7 @@ enum amd_hw_ip_block_type {  	MAX_HWIP  }; -#define HWIP_MAX_INSTANCE	8 +#define HWIP_MAX_INSTANCE	10  struct amd_powerplay {  	void *pp_handle; @@ -1087,6 +1087,7 @@ struct amdgpu_device {  	bool                            no_hw_access;  	struct pci_saved_state          *pci_state; +	pci_channel_state_t		pci_channel_state;  	struct amdgpu_reset_control     *reset_cntl;  }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 3003ee1c9487..1d41c2c00623 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -192,6 +192,16 @@ void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool run_pm)  		kgd2kfd_suspend(adev->kfd.dev, run_pm);  } +int amdgpu_amdkfd_resume_iommu(struct amdgpu_device *adev) +{ +	int r = 0; + +	if (adev->kfd.dev) +		r = kgd2kfd_resume_iommu(adev->kfd.dev); + +	return r; +} +  int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool run_pm)  {  	int r = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index ec028cf963f5..3bc52b2c604f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -137,6 +137,7 @@ int amdgpu_amdkfd_init(void);  void amdgpu_amdkfd_fini(void);  void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool run_pm); +int amdgpu_amdkfd_resume_iommu(struct amdgpu_device *adev);  int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool run_pm);  void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev,  			const void *ih_ring_entry); @@ -327,6 +328,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,  			 const struct kgd2kfd_shared_resources *gpu_resources);  void kgd2kfd_device_exit(struct kfd_dev *kfd);  void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm); +int kgd2kfd_resume_iommu(struct kfd_dev *kfd);  int kgd2kfd_resume(struct kfd_dev *kfd, bool run_pm);  int kgd2kfd_pre_reset(struct kfd_dev *kfd);  int kgd2kfd_post_reset(struct kfd_dev *kfd); @@ -365,6 +367,11 @@ static inline void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm)  {  } +static int __maybe_unused kgd2kfd_resume_iommu(struct kfd_dev *kfd) +{ +	return 0; +} +  static inline int kgd2kfd_resume(struct kfd_dev *kfd, bool run_pm)  {  	return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 2d6b2d77b738..054c1a224def 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -563,6 +563,7 @@ kfd_mem_dmaunmap_userptr(struct kgd_mem *mem,  	dma_unmap_sgtable(adev->dev, ttm->sg, direction, 0);  	sg_free_table(ttm->sg); +	kfree(ttm->sg);  	ttm->sg = NULL;  } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 277128846dd1..463b9c0283f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1544,20 +1544,18 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)  	struct dentry *ent;  	int r, i; - -  	ent = debugfs_create_file("amdgpu_preempt_ib", 0600, root, adev,  				  &fops_ib_preempt); -	if (!ent) { +	if (IS_ERR(ent)) {  		DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n"); -		return -EIO; +		return PTR_ERR(ent);  	}  	ent = debugfs_create_file("amdgpu_force_sclk", 0200, root, adev,  				  &fops_sclk_set); -	if (!ent) { +	if (IS_ERR(ent)) {  		DRM_ERROR("unable to create amdgpu_set_sclk debugsfs file\n"); -		return -EIO; +		return PTR_ERR(ent);  	}  	/* Register debugfs entries for amdgpu_ttm */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 41c6b3aacd37..af9bdf16eefd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2432,6 +2432,10 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)  	if (!adev->gmc.xgmi.pending_reset)  		amdgpu_amdkfd_device_init(adev); +	r = amdgpu_amdkfd_resume_iommu(adev); +	if (r) +		goto init_failed; +  	amdgpu_fru_get_product_info(adev);  init_failed: @@ -3148,6 +3152,10 @@ static int amdgpu_device_ip_resume(struct amdgpu_device *adev)  {  	int r; +	r = amdgpu_amdkfd_resume_iommu(adev); +	if (r) +		return r; +  	r = amdgpu_device_ip_resume_phase1(adev);  	if (r)  		return r; @@ -4601,6 +4609,10 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle,  				dev_warn(tmp_adev->dev, "asic atom init failed!");  			} else {  				dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); +				r = amdgpu_amdkfd_resume_iommu(tmp_adev); +				if (r) +					goto out; +  				r = amdgpu_device_ip_resume_phase1(tmp_adev);  				if (r)  					goto out; @@ -5387,6 +5399,8 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta  		return PCI_ERS_RESULT_DISCONNECT;  	} +	adev->pci_channel_state = state; +  	switch (state) {  	case pci_channel_io_normal:  		return PCI_ERS_RESULT_CAN_RECOVER; @@ -5529,6 +5543,10 @@ void amdgpu_pci_resume(struct pci_dev *pdev)  	DRM_INFO("PCI error: resume callback!!\n"); +	/* Only continue execution for the case of pci_channel_io_frozen */ +	if (adev->pci_channel_state != pci_channel_io_frozen) +		return; +  	for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {  		struct amdgpu_ring *ring = adev->rings[i]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 7a7316731911..dc50c05f23fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -837,6 +837,28 @@ static int convert_tiling_flags_to_modifier(struct amdgpu_framebuffer *afb)  	return 0;  } +/* Mirrors the is_displayable check in radeonsi's gfx6_compute_surface */ +static int check_tiling_flags_gfx6(struct amdgpu_framebuffer *afb) +{ +	u64 micro_tile_mode; + +	/* Zero swizzle mode means linear */ +	if (AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0) +		return 0; + +	micro_tile_mode = AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE); +	switch (micro_tile_mode) { +	case 0: /* DISPLAY */ +	case 3: /* RENDER */ +		return 0; +	default: +		drm_dbg_kms(afb->base.dev, +			    "Micro tile mode %llu not supported for scanout\n", +			    micro_tile_mode); +		return -EINVAL; +	} +} +  static void get_block_dimensions(unsigned int block_log2, unsigned int cpp,  				 unsigned int *width, unsigned int *height)  { @@ -1103,6 +1125,7 @@ int amdgpu_display_framebuffer_init(struct drm_device *dev,  				    const struct drm_mode_fb_cmd2 *mode_cmd,  				    struct drm_gem_object *obj)  { +	struct amdgpu_device *adev = drm_to_adev(dev);  	int ret, i;  	/* @@ -1122,6 +1145,14 @@ int amdgpu_display_framebuffer_init(struct drm_device *dev,  	if (ret)  		return ret; +	if (!dev->mode_config.allow_fb_modifiers) { +		drm_WARN_ONCE(dev, adev->family >= AMDGPU_FAMILY_AI, +			      "GFX9+ requires FB check based on format modifier\n"); +		ret = check_tiling_flags_gfx6(rfb); +		if (ret) +			return ret; +	} +  	if (dev->mode_config.allow_fb_modifiers &&  	    !(rfb->base.flags & DRM_MODE_FB_MODIFIERS)) {  		ret = convert_tiling_flags_to_modifier(rfb); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index f18240f87387..7741195eb85e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -38,6 +38,7 @@  #include <drm/drm_probe_helper.h>  #include <linux/mmu_notifier.h>  #include <linux/suspend.h> +#include <linux/cc_platform.h>  #include "amdgpu.h"  #include "amdgpu_irq.h" @@ -1269,7 +1270,8 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,  	 * however, SME requires an indirect IOMMU mapping because the encryption  	 * bit is beyond the DMA mask of the chip.  	 */ -	if (mem_encrypt_active() && ((flags & AMD_ASIC_MASK) == CHIP_RAVEN)) { +	if (cc_platform_has(CC_ATTR_MEM_ENCRYPT) && +	    ((flags & AMD_ASIC_MASK) == CHIP_RAVEN)) {  		dev_info(&pdev->dev,  			 "SME is not compatible with RAVEN\n");  		return -ENOTSUPP; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index e7f06bd0f0cd..1916ec84dd71 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -31,6 +31,8 @@  /* delay 0.1 second to enable gfx off feature */  #define GFX_OFF_DELAY_ENABLE         msecs_to_jiffies(100) +#define GFX_OFF_NO_DELAY 0 +  /*   * GPU GFX IP block helpers function.   */ @@ -558,6 +560,8 @@ int amdgpu_gfx_enable_kcq(struct amdgpu_device *adev)  void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)  { +	unsigned long delay = GFX_OFF_DELAY_ENABLE; +  	if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))  		return; @@ -573,8 +577,14 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)  		adev->gfx.gfx_off_req_count--; -		if (adev->gfx.gfx_off_req_count == 0 && !adev->gfx.gfx_off_state) -			schedule_delayed_work(&adev->gfx.gfx_off_delay_work, GFX_OFF_DELAY_ENABLE); +		if (adev->gfx.gfx_off_req_count == 0 && +		    !adev->gfx.gfx_off_state) { +			/* If going to s2idle, no need to wait */ +			if (adev->in_s0ix) +				delay = GFX_OFF_NO_DELAY; +			schedule_delayed_work(&adev->gfx.gfx_off_delay_work, +					      delay); +		}  	} else {  		if (adev->gfx.gfx_off_req_count == 0) {  			cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index c7797eac83c3..9ff600a38559 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -598,7 +598,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)  		break;  	default:  		adev->gmc.tmz_enabled = false; -		dev_warn(adev->dev, +		dev_info(adev->dev,  			 "Trusted Memory Zone (TMZ) feature not supported\n");  		break;  	} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index dc44c946a244..98732518543e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -757,7 +757,7 @@ Out:  	return res;  } -inline uint32_t amdgpu_ras_eeprom_max_record_count(void) +uint32_t amdgpu_ras_eeprom_max_record_count(void)  {  	return RAS_MAX_RECORD_COUNT;  } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index f95fc61b3021..6bb00578bfbb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -120,7 +120,7 @@ int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control,  int amdgpu_ras_eeprom_append(struct amdgpu_ras_eeprom_control *control,  			     struct eeprom_table_record *records, const u32 num); -inline uint32_t amdgpu_ras_eeprom_max_record_count(void); +uint32_t amdgpu_ras_eeprom_max_record_count(void);  void amdgpu_ras_debugfs_set_ret_size(struct amdgpu_ras_eeprom_control *control); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 7b634a1517f9..0554576d3695 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -428,8 +428,8 @@ int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,  	ent = debugfs_create_file(name,  				  S_IFREG | S_IRUGO, root,  				  ring, &amdgpu_debugfs_ring_fops); -	if (!ent) -		return -ENOMEM; +	if (IS_ERR(ent)) +		return PTR_ERR(ent);  	i_size_write(ent->d_inode, ring->ring_size + 12);  	ring->ent = ent; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 38dade421d46..94126dc39688 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -515,6 +515,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,  		goto out;  	} +	if (bo->type == ttm_bo_type_device && +	    new_mem->mem_type == TTM_PL_VRAM && +	    old_mem->mem_type != TTM_PL_VRAM) { +		/* amdgpu_bo_fault_reserve_notify will re-set this if the CPU +		 * accesses the BO after it's moved. +		 */ +		abo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; +	} +  	if (adev->mman.buffer_funcs_enabled) {  		if (((old_mem->mem_type == TTM_PL_SYSTEM &&  		      new_mem->mem_type == TTM_PL_VRAM) || @@ -545,15 +554,6 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,  			return r;  	} -	if (bo->type == ttm_bo_type_device && -	    new_mem->mem_type == TTM_PL_VRAM && -	    old_mem->mem_type != TTM_PL_VRAM) { -		/* amdgpu_bo_fault_reserve_notify will re-set this if the CPU -		 * accesses the BO after it's moved. -		 */ -		abo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; -	} -  out:  	/* update statistics */  	atomic64_add(bo->base.size, &adev->num_bytes_moved); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 603c259b073b..025184a556ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3599,7 +3599,7 @@ static int gfx_v9_0_mqd_init(struct amdgpu_ring *ring)  	/* set static priority for a queue/ring */  	gfx_v9_0_mqd_set_priority(ring, mqd); -	mqd->cp_hqd_quantum = RREG32(mmCP_HQD_QUANTUM); +	mqd->cp_hqd_quantum = RREG32_SOC15(GC, 0, mmCP_HQD_QUANTUM);  	/* map_queues packet doesn't need activate the queue,  	 * so only kiq need set this field. diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 41c3a0d70b7c..e47104a1f559 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -1098,6 +1098,8 @@ static int gmc_v10_0_hw_fini(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	gmc_v10_0_gart_disable(adev); +  	if (amdgpu_sriov_vf(adev)) {  		/* full access mode, so don't touch any GMC register */  		DRM_DEBUG("For SRIOV client, shouldn't do anything.\n"); @@ -1106,7 +1108,6 @@ static int gmc_v10_0_hw_fini(void *handle)  	amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0);  	amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); -	gmc_v10_0_gart_disable(adev);  	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 d90c16a6b2b8..5551359d5dfd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1794,6 +1794,8 @@ static int gmc_v9_0_hw_fini(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	gmc_v9_0_gart_disable(adev); +  	if (amdgpu_sriov_vf(adev)) {  		/* full access mode, so don't touch any GMC register */  		DRM_DEBUG("For SRIOV client, shouldn't do anything.\n"); @@ -1802,7 +1804,6 @@ static int gmc_v9_0_hw_fini(void *handle)  	amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0);  	amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); -	gmc_v9_0_gart_disable(adev);  	return 0;  } diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index ff80786e3918..01efda4398e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -1257,7 +1257,7 @@ static int nv_common_early_init(void *handle)  			AMD_PG_SUPPORT_VCN_DPG |  			AMD_PG_SUPPORT_JPEG;  		if (adev->pdev->device == 0x1681) -			adev->external_rev_id = adev->rev_id + 0x19; +			adev->external_rev_id = 0x20;  		else  			adev->external_rev_id = adev->rev_id + 0x01;  		break; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index 779f5c911e11..e32efcfb0c8b 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -868,6 +868,12 @@ 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); @@ -876,6 +882,8 @@ 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); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 16a57b70cc1a..4a416231b24c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -468,6 +468,7 @@ static const struct kfd_device_info navi10_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 145,  	.num_sdma_engines = 2,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -487,6 +488,7 @@ static const struct kfd_device_info navi12_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 145,  	.num_sdma_engines = 2,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -506,6 +508,7 @@ static const struct kfd_device_info navi14_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 145,  	.num_sdma_engines = 2,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -525,6 +528,7 @@ static const struct kfd_device_info sienna_cichlid_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 92,  	.num_sdma_engines = 4,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -544,6 +548,7 @@ static const struct kfd_device_info navy_flounder_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 92,  	.num_sdma_engines = 2,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -562,7 +567,8 @@ static const struct kfd_device_info vangogh_device_info = {  	.mqd_size_aligned = MQD_SIZE_ALIGNED,  	.needs_iommu_device = false,  	.supports_cwsr = true, -	.needs_pci_atomics = false, +	.needs_pci_atomics = true, +	.no_atomic_fw_version = 92,  	.num_sdma_engines = 1,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 2, @@ -582,6 +588,7 @@ static const struct kfd_device_info dimgrey_cavefish_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 92,  	.num_sdma_engines = 2,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -601,6 +608,7 @@ static const struct kfd_device_info beige_goby_device_info = {  	.needs_iommu_device = false,  	.supports_cwsr = true,  	.needs_pci_atomics = true, +	.no_atomic_fw_version = 92,  	.num_sdma_engines = 1,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 8, @@ -619,7 +627,8 @@ static const struct kfd_device_info yellow_carp_device_info = {  	.mqd_size_aligned = MQD_SIZE_ALIGNED,  	.needs_iommu_device = false,  	.supports_cwsr = true, -	.needs_pci_atomics = false, +	.needs_pci_atomics = true, +	.no_atomic_fw_version = 92,  	.num_sdma_engines = 1,  	.num_xgmi_sdma_engines = 0,  	.num_sdma_queues_per_engine = 2, @@ -708,20 +717,6 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,  	if (!kfd)  		return NULL; -	/* Allow BIF to recode atomics to PCIe 3.0 AtomicOps. -	 * 32 and 64-bit requests are possible and must be -	 * supported. -	 */ -	kfd->pci_atomic_requested = amdgpu_amdkfd_have_atomics_support(kgd); -	if (device_info->needs_pci_atomics && -	    !kfd->pci_atomic_requested) { -		dev_info(kfd_device, -			 "skipped device %x:%x, PCI rejects atomics\n", -			 pdev->vendor, pdev->device); -		kfree(kfd); -		return NULL; -	} -  	kfd->kgd = kgd;  	kfd->device_info = device_info;  	kfd->pdev = pdev; @@ -821,6 +816,23 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,  	kfd->vm_info.vmid_num_kfd = kfd->vm_info.last_vmid_kfd  			- kfd->vm_info.first_vmid_kfd + 1; +	/* Allow BIF to recode atomics to PCIe 3.0 AtomicOps. +	 * 32 and 64-bit requests are possible and must be +	 * supported. +	 */ +	kfd->pci_atomic_requested = amdgpu_amdkfd_have_atomics_support(kfd->kgd); +	if (!kfd->pci_atomic_requested && +	    kfd->device_info->needs_pci_atomics && +	    (!kfd->device_info->no_atomic_fw_version || +	     kfd->mec_fw_version < kfd->device_info->no_atomic_fw_version)) { +		dev_info(kfd_device, +			 "skipped device %x:%x, PCI rejects atomics %d<%d\n", +			 kfd->pdev->vendor, kfd->pdev->device, +			 kfd->mec_fw_version, +			 kfd->device_info->no_atomic_fw_version); +		return false; +	} +  	/* Verify module parameters regarding mapped process number*/  	if ((hws_max_conc_proc < 0)  			|| (hws_max_conc_proc > kfd->vm_info.vmid_num_kfd)) { @@ -959,7 +971,6 @@ out:  void kgd2kfd_device_exit(struct kfd_dev *kfd)  {  	if (kfd->init_complete) { -		svm_migrate_fini((struct amdgpu_device *)kfd->kgd);  		device_queue_manager_uninit(kfd->dqm);  		kfd_interrupt_exit(kfd);  		kfd_topology_remove_device(kfd); @@ -1057,31 +1068,29 @@ int kgd2kfd_resume(struct kfd_dev *kfd, bool run_pm)  	return ret;  } -static int kfd_resume(struct kfd_dev *kfd) +int kgd2kfd_resume_iommu(struct kfd_dev *kfd)  {  	int err = 0;  	err = kfd_iommu_resume(kfd); -	if (err) { +	if (err)  		dev_err(kfd_device,  			"Failed to resume IOMMU for device %x:%x\n",  			kfd->pdev->vendor, kfd->pdev->device); -		return err; -	} +	return err; +} + +static int kfd_resume(struct kfd_dev *kfd) +{ +	int err = 0;  	err = kfd->dqm->ops.start(kfd->dqm); -	if (err) { +	if (err)  		dev_err(kfd_device,  			"Error starting queue manager for device %x:%x\n",  			kfd->pdev->vendor, kfd->pdev->device); -		goto dqm_start_error; -	}  	return err; - -dqm_start_error: -	kfd_iommu_suspend(kfd); -	return err;  }  static inline void kfd_queue_work(struct workqueue_struct *wq, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index dab290a4d19d..4a16e3c257b9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -891,9 +891,16 @@ int svm_migrate_init(struct amdgpu_device *adev)  	pgmap->ops = &svm_migrate_pgmap_ops;  	pgmap->owner = SVM_ADEV_PGMAP_OWNER(adev);  	pgmap->flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; + +	/* Device manager releases device-specific resources, memory region and +	 * pgmap when driver disconnects from device. +	 */  	r = devm_memremap_pages(adev->dev, pgmap);  	if (IS_ERR(r)) {  		pr_err("failed to register HMM device memory\n"); + +		/* Disable SVM support capability */ +		pgmap->type = 0;  		devm_release_mem_region(adev->dev, res->start,  					res->end - res->start + 1);  		return PTR_ERR(r); @@ -908,12 +915,3 @@ int svm_migrate_init(struct amdgpu_device *adev)  	return 0;  } - -void svm_migrate_fini(struct amdgpu_device *adev) -{ -	struct dev_pagemap *pgmap = &adev->kfd.dev->pgmap; - -	devm_memunmap_pages(adev->dev, pgmap); -	devm_release_mem_region(adev->dev, pgmap->range.start, -				pgmap->range.end - pgmap->range.start + 1); -} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h index 0de76b5d4973..2f5b3394c9ed 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h @@ -47,7 +47,6 @@ unsigned long  svm_migrate_addr_to_pfn(struct amdgpu_device *adev, unsigned long addr);  int svm_migrate_init(struct amdgpu_device *adev); -void svm_migrate_fini(struct amdgpu_device *adev);  #else @@ -55,10 +54,6 @@ static inline int svm_migrate_init(struct amdgpu_device *adev)  {  	return 0;  } -static inline void svm_migrate_fini(struct amdgpu_device *adev) -{ -	/* empty */ -}  #endif /* IS_ENABLED(CONFIG_HSA_AMD_SVM) */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index ab83b0de6b22..6d8f9bb2d905 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -207,6 +207,7 @@ struct kfd_device_info {  	bool supports_cwsr;  	bool needs_iommu_device;  	bool needs_pci_atomics; +	uint32_t no_atomic_fw_version;  	unsigned int num_sdma_engines;  	unsigned int num_xgmi_sdma_engines;  	unsigned int num_sdma_queues_per_engine; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 9fc8021bb0ab..9d0f65a90002 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -118,6 +118,13 @@ static void svm_range_remove_notifier(struct svm_range *prange)  		mmu_interval_notifier_remove(&prange->notifier);  } +static bool +svm_is_valid_dma_mapping_addr(struct device *dev, dma_addr_t dma_addr) +{ +	return dma_addr && !dma_mapping_error(dev, dma_addr) && +	       !(dma_addr & SVM_RANGE_VRAM_DOMAIN); +} +  static int  svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange,  		      unsigned long offset, unsigned long npages, @@ -139,8 +146,7 @@ svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange,  	addr += offset;  	for (i = 0; i < npages; i++) { -		if (WARN_ONCE(addr[i] && !dma_mapping_error(dev, addr[i]), -			      "leaking dma mapping\n")) +		if (svm_is_valid_dma_mapping_addr(dev, addr[i]))  			dma_unmap_page(dev, addr[i], PAGE_SIZE, dir);  		page = hmm_pfn_to_page(hmm_pfns[i]); @@ -209,7 +215,7 @@ void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr,  		return;  	for (i = offset; i < offset + npages; i++) { -		if (!dma_addr[i] || dma_mapping_error(dev, dma_addr[i])) +		if (!svm_is_valid_dma_mapping_addr(dev, dma_addr[i]))  			continue;  		pr_debug("dma unmapping 0x%llx\n", dma_addr[i] >> PAGE_SHIFT);  		dma_unmap_page(dev, dma_addr[i], PAGE_SIZE, dir); @@ -1165,7 +1171,7 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,  	unsigned long last_start;  	int last_domain;  	int r = 0; -	int64_t i; +	int64_t i, j;  	last_start = prange->start + offset; @@ -1178,7 +1184,11 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,  	for (i = offset; i < offset + npages; i++) {  		last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN;  		dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN; -		if ((prange->start + i) < prange->last && + +		/* Collect all pages in the same address range and memory domain +		 * that can be mapped with a single call to update mapping. +		 */ +		if (i < offset + npages - 1 &&  		    last_domain == (dma_addr[i + 1] & SVM_RANGE_VRAM_DOMAIN))  			continue; @@ -1201,6 +1211,10 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,  						NULL, dma_addr,  						&vm->last_update,  						&table_freed); + +		for (j = last_start - prange->start; j <= i; j++) +			dma_addr[j] |= last_domain; +  		if (r) {  			pr_debug("failed %d to map to gpu 0x%lx\n", r, prange->start);  			goto out; diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 7dffc04a557e..127667e549c1 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -25,6 +25,8 @@ config DRM_AMD_DC_HDCP  config DRM_AMD_DC_SI  	bool "AMD DC support for Southern Islands ASICs" +	depends on DRM_AMDGPU_SI +	depends on DRM_AMD_DC  	default n  	help  	  Choose this option to enable new AMD DC support for SI asics 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 9b1fc54555ee..1ea31dcc7a8b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -998,6 +998,8 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_  	uint32_t 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)); +  	logical_addr_low  = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18;  	pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); @@ -1113,6 +1115,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)  	init_data.asic_id.pci_revision_id = adev->pdev->revision;  	init_data.asic_id.hw_internal_rev = adev->external_rev_id; +	init_data.asic_id.chip_id = adev->pdev->device;  	init_data.asic_id.vram_width = adev->gmc.vram_width;  	/* TODO: initialize init_data.asic_id.vram_type here!!!! */ @@ -1717,6 +1720,7 @@ static int dm_late_init(void *handle)  		linear_lut[i] = 0xFFFF * i / 15;  	params.set = 0; +	params.backlight_ramping_override = false;  	params.backlight_ramping_start = 0xCCCC;  	params.backlight_ramping_reduction = 0xCCCCCCCC;  	params.backlight_lut_array_size = 16; @@ -6024,21 +6028,23 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)  		return 0;  #if defined(CONFIG_DRM_AMD_DC_DCN) -	work = kzalloc(sizeof(*work), GFP_ATOMIC); -	if (!work) -		return -ENOMEM; +	if (dm->vblank_control_workqueue) { +		work = kzalloc(sizeof(*work), GFP_ATOMIC); +		if (!work) +			return -ENOMEM; -	INIT_WORK(&work->work, vblank_control_worker); -	work->dm = dm; -	work->acrtc = acrtc; -	work->enable = enable; +		INIT_WORK(&work->work, vblank_control_worker); +		work->dm = dm; +		work->acrtc = acrtc; +		work->enable = enable; -	if (acrtc_state->stream) { -		dc_stream_retain(acrtc_state->stream); -		work->stream = acrtc_state->stream; -	} +		if (acrtc_state->stream) { +			dc_stream_retain(acrtc_state->stream); +			work->stream = acrtc_state->stream; +		} -	queue_work(dm->vblank_control_workqueue, &work->work); +		queue_work(dm->vblank_control_workqueue, &work->work); +	}  #endif  	return 0; @@ -6792,14 +6798,15 @@ const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {  #if defined(CONFIG_DRM_AMD_DC_DCN)  static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, -					    struct dc_state *dc_state) +					    struct dc_state *dc_state, +					    struct dsc_mst_fairness_vars *vars)  {  	struct dc_stream_state *stream = NULL;  	struct drm_connector *connector;  	struct drm_connector_state *new_con_state;  	struct amdgpu_dm_connector *aconnector;  	struct dm_connector_state *dm_conn_state; -	int i, j, clock, bpp; +	int i, j, clock;  	int vcpi, pbn_div, pbn = 0;  	for_each_new_connector_in_state(state, connector, new_con_state, i) { @@ -6838,9 +6845,15 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,  		}  		pbn_div = dm_mst_get_pbn_divider(stream->link); -		bpp = stream->timing.dsc_cfg.bits_per_pixel;  		clock = stream->timing.pix_clk_100hz / 10; -		pbn = drm_dp_calc_pbn_mode(clock, bpp, true); +		/* pbn is calculated by compute_mst_dsc_configs_for_state*/ +		for (j = 0; j < dc_state->stream_count; j++) { +			if (vars[j].aconnector == aconnector) { +				pbn = vars[j].pbn; +				break; +			} +		} +  		vcpi = drm_dp_mst_atomic_enable_dsc(state,  						    aconnector->port,  						    pbn, pbn_div, @@ -7519,6 +7532,32 @@ static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,  	}  } +static void amdgpu_set_panel_orientation(struct drm_connector *connector) +{ +	struct drm_encoder *encoder; +	struct amdgpu_encoder *amdgpu_encoder; +	const struct drm_display_mode *native_mode; + +	if (connector->connector_type != DRM_MODE_CONNECTOR_eDP && +	    connector->connector_type != DRM_MODE_CONNECTOR_LVDS) +		return; + +	encoder = amdgpu_dm_connector_to_encoder(connector); +	if (!encoder) +		return; + +	amdgpu_encoder = to_amdgpu_encoder(encoder); + +	native_mode = &amdgpu_encoder->native_mode; +	if (native_mode->hdisplay == 0 || native_mode->vdisplay == 0) +		return; + +	drm_connector_set_panel_orientation_with_quirk(connector, +						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN, +						       native_mode->hdisplay, +						       native_mode->vdisplay); +} +  static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,  					      struct edid *edid)  { @@ -7547,6 +7586,8 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,  		 * restored here.  		 */  		amdgpu_dm_update_freesync_caps(connector, edid); + +		amdgpu_set_panel_orientation(connector);  	} else {  		amdgpu_dm_connector->num_modes = 0;  	} @@ -8058,8 +8099,26 @@ static bool is_content_protection_different(struct drm_connector_state *state,  	    state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)  		state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; -	/* Check if something is connected/enabled, otherwise we start hdcp but nothing is connected/enabled -	 * hot-plug, headless s3, dpms +	/* Stream removed and re-enabled +	 * +	 * Can sometimes overlap with the HPD case, +	 * thus set update_hdcp to false to avoid +	 * setting HDCP multiple times. +	 * +	 * Handles:	DESIRED -> DESIRED (Special case) +	 */ +	if (!(old_state->crtc && old_state->crtc->enabled) && +		state->crtc && state->crtc->enabled && +		connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { +		dm_con_state->update_hdcp = false; +		return true; +	} + +	/* Hot-plug, headless s3, dpms +	 * +	 * Only start HDCP if the display is connected/enabled. +	 * update_hdcp flag will be set to false until the next +	 * HPD comes in.  	 *  	 * Handles:	DESIRED -> DESIRED (Special case)  	 */ @@ -8648,7 +8707,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,  		 * If PSR or idle optimizations are enabled then flush out  		 * any pending work before hardware programming.  		 */ -		flush_workqueue(dm->vblank_control_workqueue); +		if (dm->vblank_control_workqueue) +			flush_workqueue(dm->vblank_control_workqueue);  #endif  		bundle->stream_update.stream = acrtc_state->stream; @@ -8983,7 +9043,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)  		/* if there mode set or reset, disable eDP PSR */  		if (mode_set_reset_required) {  #if defined(CONFIG_DRM_AMD_DC_DCN) -			flush_workqueue(dm->vblank_control_workqueue); +			if (dm->vblank_control_workqueue) +				flush_workqueue(dm->vblank_control_workqueue);  #endif  			amdgpu_dm_psr_disable_all(dm);  		} @@ -10243,6 +10304,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,  	int ret, i;  	bool lock_and_validation_needed = false;  	struct dm_crtc_state *dm_old_crtc_state; +#if defined(CONFIG_DRM_AMD_DC_DCN) +	struct dsc_mst_fairness_vars vars[MAX_PIPES]; +#endif  	trace_amdgpu_dm_atomic_check_begin(state); @@ -10473,10 +10537,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,  			goto fail;  #if defined(CONFIG_DRM_AMD_DC_DCN) -		if (!compute_mst_dsc_configs_for_state(state, dm_state->context)) +		if (!compute_mst_dsc_configs_for_state(state, dm_state->context, vars))  			goto fail; -		ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context); +		ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars);  		if (ret)  			goto fail;  #endif @@ -10492,7 +10556,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,  			goto fail;  		status = dc_validate_global_state(dc, dm_state->context, false);  		if (status != DC_OK) { -			DC_LOG_WARNING("DC global validation failure: %s (%d)", +			drm_dbg_atomic(dev, +				       "DC global validation failure: %s (%d)",  				       dc_status_to_str(status), status);  			ret = -EINVAL;  			goto fail; 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 87daa78a32b8..8080bba5b7a7 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 @@ -263,7 +263,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,  	if (!wr_buf)  		return -ENOSPC; -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					   (long *)param, buf,  					   max_param_num,  					   ¶m_nums)) { @@ -487,7 +487,7 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf,  	if (!wr_buf)  		return -ENOSPC; -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					   (long *)param, buf,  					   max_param_num,  					   ¶m_nums)) { @@ -639,7 +639,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us  	if (!wr_buf)  		return -ENOSPC; -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					   (long *)param, buf,  					   max_param_num,  					   ¶m_nums)) { @@ -914,7 +914,7 @@ static ssize_t dp_dsc_passthrough_set(struct file *f, const char __user *buf,  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					   ¶m, buf,  					   max_param_num,  					   ¶m_nums)) { @@ -1211,7 +1211,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  						(long *)param, buf,  						max_param_num,  						¶m_nums)) { @@ -1396,7 +1396,7 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf,  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					    (long *)param, buf,  					    max_param_num,  					    ¶m_nums)) { @@ -1581,7 +1581,7 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf,  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					    (long *)param, buf,  					    max_param_num,  					    ¶m_nums)) { @@ -1766,7 +1766,7 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf,  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					    (long *)param, buf,  					    max_param_num,  					    ¶m_nums)) { @@ -1944,7 +1944,7 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					    (long *)param, buf,  					    max_param_num,  					    ¶m_nums)) { @@ -2382,7 +2382,7 @@ static ssize_t dp_max_bpc_write(struct file *f, const char __user *buf,  		return -ENOSPC;  	} -	if (parse_write_buffer_into_params(wr_buf, size, +	if (parse_write_buffer_into_params(wr_buf, wr_buf_size,  					   (long *)param, buf,  					   max_param_num,  					   ¶m_nums)) { 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 1bcba6943fd7..7af0d58c231b 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 @@ -518,12 +518,7 @@ struct dsc_mst_fairness_params {  	uint32_t num_slices_h;  	uint32_t num_slices_v;  	uint32_t bpp_overwrite; -}; - -struct dsc_mst_fairness_vars { -	int pbn; -	bool dsc_enabled; -	int bpp_x16; +	struct amdgpu_dm_connector *aconnector;  };  static int kbps_to_peak_pbn(int kbps) @@ -750,12 +745,12 @@ static void try_disable_dsc(struct drm_atomic_state *state,  static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,  					     struct dc_state *dc_state, -					     struct dc_link *dc_link) +					     struct dc_link *dc_link, +					     struct dsc_mst_fairness_vars *vars)  {  	int i;  	struct dc_stream_state *stream;  	struct dsc_mst_fairness_params params[MAX_PIPES]; -	struct dsc_mst_fairness_vars vars[MAX_PIPES];  	struct amdgpu_dm_connector *aconnector;  	int count = 0;  	bool debugfs_overwrite = false; @@ -776,6 +771,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,  		params[count].timing = &stream->timing;  		params[count].sink = stream->sink;  		aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; +		params[count].aconnector = aconnector;  		params[count].port = aconnector->port;  		params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable;  		if (params[count].clock_force_enable == DSC_CLK_FORCE_ENABLE) @@ -798,6 +794,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,  	}  	/* Try no compression */  	for (i = 0; i < count; i++) { +		vars[i].aconnector = params[i].aconnector;  		vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);  		vars[i].dsc_enabled = false;  		vars[i].bpp_x16 = 0; @@ -851,7 +848,8 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,  }  bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, -				       struct dc_state *dc_state) +				       struct dc_state *dc_state, +				       struct dsc_mst_fairness_vars *vars)  {  	int i, j;  	struct dc_stream_state *stream; @@ -882,7 +880,7 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,  			return false;  		mutex_lock(&aconnector->mst_mgr.lock); -		if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link)) { +		if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars)) {  			mutex_unlock(&aconnector->mst_mgr.lock);  			return false;  		} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index b38bd68121ce..900d3f7a8498 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -39,8 +39,17 @@ void  dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev);  #if defined(CONFIG_DRM_AMD_DC_DCN) + +struct dsc_mst_fairness_vars { +	int pbn; +	bool dsc_enabled; +	int bpp_x16; +	struct amdgpu_dm_connector *aconnector; +}; +  bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, -				       struct dc_state *dc_state); +				       struct dc_state *dc_state, +				       struct dsc_mst_fairness_vars *vars);  #endif  #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index c9f47d167472..b1bf80da3a55 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -62,7 +62,7 @@ inline void dc_assert_fp_enabled(void)  	depth = *pcpu;  	put_cpu_ptr(&fpu_recursion_depth); -	ASSERT(depth > 1); +	ASSERT(depth >= 1);  }  /** diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index 4a4894e9d9c9..377c4e53a2b3 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -366,32 +366,32 @@ static struct wm_table lpddr5_wm_table = {  			.wm_inst = WM_A,  			.wm_type = WM_TYPE_PSTATE_CHG,  			.pstate_latency_us = 11.65333, -			.sr_exit_time_us = 5.32, -			.sr_enter_plus_exit_time_us = 6.38, +			.sr_exit_time_us = 11.5, +			.sr_enter_plus_exit_time_us = 14.5,  			.valid = true,  		},  		{  			.wm_inst = WM_B,  			.wm_type = WM_TYPE_PSTATE_CHG,  			.pstate_latency_us = 11.65333, -			.sr_exit_time_us = 9.82, -			.sr_enter_plus_exit_time_us = 11.196, +			.sr_exit_time_us = 11.5, +			.sr_enter_plus_exit_time_us = 14.5,  			.valid = true,  		},  		{  			.wm_inst = WM_C,  			.wm_type = WM_TYPE_PSTATE_CHG,  			.pstate_latency_us = 11.65333, -			.sr_exit_time_us = 9.89, -			.sr_enter_plus_exit_time_us = 11.24, +			.sr_exit_time_us = 11.5, +			.sr_enter_plus_exit_time_us = 14.5,  			.valid = true,  		},  		{  			.wm_inst = WM_D,  			.wm_type = WM_TYPE_PSTATE_CHG,  			.pstate_latency_us = 11.65333, -			.sr_exit_time_us = 9.748, -			.sr_enter_plus_exit_time_us = 11.102, +			.sr_exit_time_us = 11.5, +			.sr_enter_plus_exit_time_us = 14.5,  			.valid = true,  		},  	} @@ -518,14 +518,21 @@ static unsigned int find_clk_for_voltage(  		unsigned int voltage)  {  	int i; +	int max_voltage = 0; +	int clock = 0;  	for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) { -		if (clock_table->SocVoltage[i] == voltage) +		if (clock_table->SocVoltage[i] == voltage) {  			return clocks[i]; +		} else if (clock_table->SocVoltage[i] >= max_voltage && +				clock_table->SocVoltage[i] < voltage) { +			max_voltage = clock_table->SocVoltage[i]; +			clock = clocks[i]; +		}  	} -	ASSERT(0); -	return 0; +	ASSERT(clock); +	return clock;  }  void dcn31_clk_mgr_helper_populate_bw_params( 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 8bd7f42a8053..1e44b13c1c7d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2586,13 +2586,21 @@ static struct abm *get_abm_from_stream_res(const struct dc_link *link)  int dc_link_get_backlight_level(const struct dc_link *link)  { -  	struct abm *abm = get_abm_from_stream_res(link); +	struct panel_cntl *panel_cntl = link->panel_cntl; +	struct dc  *dc = link->ctx->dc; +	struct dmcu *dmcu = dc->res_pool->dmcu; +	bool fw_set_brightness = true; -	if (abm == NULL || abm->funcs->get_current_backlight == NULL) -		return DC_ERROR_UNEXPECTED; +	if (dmcu) +		fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); -	return (int) abm->funcs->get_current_backlight(abm); +	if (!fw_set_brightness && panel_cntl->funcs->get_current_backlight) +		return panel_cntl->funcs->get_current_backlight(panel_cntl); +	else if (abm != NULL && abm->funcs->get_current_backlight != NULL) +		return (int) abm->funcs->get_current_backlight(abm); +	else +		return DC_ERROR_UNEXPECTED;  }  int dc_link_get_target_backlight_pwm(const struct dc_link *link) 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 330edd666b7d..6d655e158267 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 @@ -1,4 +1,26 @@ -/* Copyright 2015 Advanced Micro Devices, Inc. */ +/* + * Copyright 2015 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 "dm_services.h"  #include "dc.h"  #include "dc_link_dp.h" @@ -1284,12 +1306,6 @@ static void override_training_settings(  {  	uint32_t lane; -	/* Override link settings */ -	if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) -		lt_settings->link_settings.link_rate = link->preferred_link_setting.link_rate; -	if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN) -		lt_settings->link_settings.lane_count = link->preferred_link_setting.lane_count; -  	/* Override link spread */  	if (!link->dp_ss_off && overrides->downspread != NULL)  		lt_settings->link_settings.link_spread = *overrides->downspread ? @@ -1804,14 +1820,13 @@ bool perform_link_training_with_retries(  		if (panel_mode == DP_PANEL_MODE_EDP) {  			struct cp_psp *cp_psp = &stream->ctx->cp_psp; -			if (cp_psp && cp_psp->funcs.enable_assr) { -				if (!cp_psp->funcs.enable_assr(cp_psp->handle, link)) { -					/* since eDP implies ASSR on, change panel -					 * mode to disable ASSR -					 */ -					panel_mode = DP_PANEL_MODE_DEFAULT; -				} -			} +			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 @@ -1840,9 +1855,13 @@ bool perform_link_training_with_retries(  		dp_disable_link_phy(link, signal);  		/* Abort link training if failure due to sink being unplugged. */ -		if (status == LINK_TRAINING_ABORT) -			break; -		else if (do_fallback) { +		if (status == LINK_TRAINING_ABORT) { +			enum dc_connection_type type = dc_connection_none; + +			dc_link_detect_sink(link, &type); +			if (type == dc_connection_none) +				break; +		} else if (do_fallback) {  			decide_fallback_link_setting(*link_setting, ¤t_setting, status);  			/* Fail link training if reduced link bandwidth no longer meets  			 * stream requirements. diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index e14f99b4b0c3..3c3347341103 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -42,7 +42,7 @@  #define DC_LOGGER \  	engine->ctx->logger -#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ +#define DC_TRACE_LEVEL_MESSAGE(...) do { } while (0)  #define IS_DC_I2CAUX_LOGGING_ENABLED() (false)  #define LOG_FLAG_Error_I2cAux LOG_ERROR  #define LOG_FLAG_I2cAux_DceAux LOG_I2C_AUX @@ -76,7 +76,7 @@ enum {  #define DEFAULT_AUX_ENGINE_MULT   0  #define DEFAULT_AUX_ENGINE_LENGTH 69 -#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ +#define DC_TRACE_LEVEL_MESSAGE(...) do { } while (0)  static void release_engine(  	struct dce_aux *engine) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c index e92339235863..e8570060d007 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c @@ -49,7 +49,6 @@  static unsigned int dce_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_cntl)  {  	uint64_t current_backlight; -	uint32_t round_result;  	uint32_t bl_period, bl_int_count;  	uint32_t bl_pwm, fractional_duty_cycle_en;  	uint32_t bl_period_mask, bl_pwm_mask; @@ -84,15 +83,6 @@ static unsigned int dce_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_c  	current_backlight = div_u64(current_backlight, bl_period);  	current_backlight = (current_backlight + 1) >> 1; -	current_backlight = (uint64_t)(current_backlight) * bl_period; - -	round_result = (uint32_t)(current_backlight & 0xFFFFFFFF); - -	round_result = (round_result >> (bl_int_count-1)) & 1; - -	current_backlight >>= bl_int_count; -	current_backlight += round_result; -  	return (uint32_t)(current_backlight);  } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index d8b22618b79e..c337588231ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -118,6 +118,7 @@ struct dcn10_link_enc_registers {  	uint32_t RDPCSTX_PHY_CNTL4;  	uint32_t RDPCSTX_PHY_CNTL5;  	uint32_t RDPCSTX_PHY_CNTL6; +	uint32_t RDPCSPIPE_PHY_CNTL6;  	uint32_t RDPCSTX_PHY_CNTL7;  	uint32_t RDPCSTX_PHY_CNTL8;  	uint32_t RDPCSTX_PHY_CNTL9; 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 90127c1f9e35..b0892443fbd5 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 @@ -37,6 +37,7 @@  #include "link_enc_cfg.h"  #include "dc_dmub_srv.h" +#include "dal_asic_id.h"  #define CTX \  	enc10->base.ctx @@ -62,6 +63,10 @@  #define AUX_REG_WRITE(reg_name, val) \  			dm_write_reg(CTX, AUX_REG(reg_name), val) +#ifndef MIN +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif +  void dcn31_link_encoder_set_dio_phy_mux(  	struct link_encoder *enc,  	enum encoder_type_select sel, @@ -215,8 +220,8 @@ static const struct link_encoder_funcs dcn31_link_enc_funcs = {  	.fec_is_active = enc2_fec_is_active,  	.get_dig_frontend = dcn10_get_dig_frontend,  	.get_dig_mode = dcn10_get_dig_mode, -	.is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode, -	.get_max_link_cap = dcn20_link_encoder_get_max_link_cap, +	.is_in_alt_mode = dcn31_link_encoder_is_in_alt_mode, +	.get_max_link_cap = dcn31_link_encoder_get_max_link_cap,  	.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,  }; @@ -404,3 +409,60 @@ void dcn31_link_encoder_disable_output(  	}  } +bool dcn31_link_encoder_is_in_alt_mode(struct link_encoder *enc) +{ +	struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); +	uint32_t dp_alt_mode_disable; +	bool is_usb_c_alt_mode = false; + +	if (enc->features.flags.bits.DP_IS_USB_C) { +		if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { +			// [Note] no need to check hw_internal_rev once phy mux selection is ready +			REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable); +		} else { +		/* +		 * B0 phys use a new set of registers to check whether alt mode is disabled. +		 * if value == 1 alt mode is disabled, otherwise it is enabled. +		 */ +			if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) +					|| (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) +					|| (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { +				REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable); +			} else { +			// [Note] need to change TRANSMITTER_UNIPHY_C/D to F/G once phy mux selection is ready +				REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable); +			} +		} + +		is_usb_c_alt_mode = (dp_alt_mode_disable == 0); +	} + +	return is_usb_c_alt_mode; +} + +void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc, +										 struct dc_link_settings *link_settings) +{ +	struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); +	uint32_t is_in_usb_c_dp4_mode = 0; + +	dcn10_link_encoder_get_max_link_cap(enc, link_settings); + +	/* in usb c dp2 mode, max lane count is 2 */ +	if (enc->funcs->is_in_alt_mode && enc->funcs->is_in_alt_mode(enc)) { +		if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { +			// [Note] no need to check hw_internal_rev once phy mux selection is ready +			REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode); +		} else { +			if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) +					|| (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) +					|| (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { +				REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode); +			} else { +				REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode); +			} +		} +		if (!is_in_usb_c_dp4_mode) +			link_settings->lane_count = MIN(LANE_COUNT_TWO, link_settings->lane_count); +	} +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h index 32d146312838..3454f1e7c1f1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.h @@ -69,6 +69,7 @@  	SRI(RDPCSTX_PHY_CNTL4, RDPCSTX, id), \  	SRI(RDPCSTX_PHY_CNTL5, RDPCSTX, id), \  	SRI(RDPCSTX_PHY_CNTL6, RDPCSTX, id), \ +	SRI(RDPCSPIPE_PHY_CNTL6, RDPCSPIPE, id), \  	SRI(RDPCSTX_PHY_CNTL7, RDPCSTX, id), \  	SRI(RDPCSTX_PHY_CNTL8, RDPCSTX, id), \  	SRI(RDPCSTX_PHY_CNTL9, RDPCSTX, id), \ @@ -115,7 +116,9 @@  	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DP_TX2_MPLL_EN, mask_sh),\  	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DP_TX3_MPLL_EN, mask_sh),\  	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, mask_sh),\ -	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, mask_sh),\ +	LE_SF(RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, mask_sh),\ +	LE_SF(RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, mask_sh),\ +	LE_SF(RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE_ACK, mask_sh),\  	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL7, RDPCS_PHY_DP_MPLLB_FRACN_QUOT, mask_sh),\  	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL7, RDPCS_PHY_DP_MPLLB_FRACN_DEN, mask_sh),\  	LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL8, RDPCS_PHY_DP_MPLLB_SSC_PEAK, mask_sh),\ @@ -243,4 +246,13 @@ void dcn31_link_encoder_disable_output(  	struct link_encoder *enc,  	enum signal_type signal); +/* + * Check whether USB-C DP Alt mode is disabled + */ +bool dcn31_link_encoder_is_in_alt_mode( +	struct link_encoder *enc); + +void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc, +	struct dc_link_settings *link_settings); +  #endif /* __DC_LINK_ENCODER__DCN31_H__ */ 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 3f2333ec67e2..3afa1159a5f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -76,10 +76,6 @@ void dcn31_init_hw(struct dc *dc)  	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)  		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); -	// Initialize the dccg -	if (res_pool->dccg->funcs->dccg_init) -		res_pool->dccg->funcs->dccg_init(res_pool->dccg); -  	if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {  		REG_WRITE(REFCLK_CNTL, 0); @@ -106,6 +102,9 @@ void dcn31_init_hw(struct dc *dc)  		hws->funcs.bios_golden_init(dc);  		hws->funcs.disable_vga(dc->hwseq);  	} +	// Initialize the dccg +	if (res_pool->dccg->funcs->dccg_init) +		res_pool->dccg->funcs->dccg_init(res_pool->dccg);  	if (dc->debug.enable_mem_low_power.bits.dmcu) {  		// Force ERAM to shutdown if DMCU is not enabled diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index a7702d3c75cd..79e92ecca96c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -217,8 +217,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = {  	.num_states = 5,  	.sr_exit_time_us = 9.0,  	.sr_enter_plus_exit_time_us = 11.0, -	.sr_exit_z8_time_us = 402.0, -	.sr_enter_plus_exit_z8_time_us = 520.0, +	.sr_exit_z8_time_us = 442.0, +	.sr_enter_plus_exit_z8_time_us = 560.0,  	.writeback_latency_us = 12.0,  	.dram_channel_width_bytes = 4,  	.round_trip_ping_latency_dcfclk_cycles = 106, @@ -928,7 +928,7 @@ static const struct dc_debug_options debug_defaults_drv = {  	.disable_dcc = DCC_ENABLE,  	.vsr_support = true,  	.performance_trace = false, -	.max_downscale_src_width = 7680,/*upto 8K*/ +	.max_downscale_src_width = 4096,/*upto true 4K*/  	.disable_pplib_wm_range = false,  	.scl_reset_length10 = true,  	.sanity_checks = false, @@ -1284,6 +1284,12 @@ static struct stream_encoder *dcn31_stream_encoder_create(  	if (!enc1 || !vpg || !afmt)  		return NULL; +	if (ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && +			ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { +		if ((eng_id == ENGINE_ID_DIGC) || (eng_id == ENGINE_ID_DIGD)) +			eng_id = eng_id + 3; // For B0 only. C->F, D->G. +	} +  	dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,  					eng_id, vpg, afmt,  					&stream_enc_regs[eng_id], @@ -1584,6 +1590,13 @@ static int dcn31_populate_dml_pipes_from_context(  		pipe = &res_ctx->pipe_ctx[i];  		timing = &pipe->stream->timing; +		/* +		 * Immediate flip can be set dynamically after enabling the plane. +		 * We need to require support for immediate flip or underflow can be +		 * intermittently experienced depending on peak b/w requirements. +		 */ +		pipes[pipe_cnt].pipe.src.immediate_flip = true; +  		pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;  		pipes[pipe_cnt].pipe.src.gpuvm = true;  		pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index ce55c9caf9a2..d58925cff420 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -5398,9 +5398,9 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l  					v->MaximumReadBandwidthWithPrefetch =  							v->MaximumReadBandwidthWithPrefetch -									+ dml_max4( -											v->VActivePixelBandwidth[i][j][k], -											v->VActiveCursorBandwidth[i][j][k] +									+ dml_max3( +											v->VActivePixelBandwidth[i][j][k] +													+ v->VActiveCursorBandwidth[i][j][k]  													+ v->NoOfDPP[i][j][k]  															* (v->meta_row_bandwidth[i][j][k]  																	+ v->dpte_row_bandwidth[i][j][k]), diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index 381c17caace1..3d2f0817e40a 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -227,7 +227,7 @@ enum {  #define FAMILY_YELLOW_CARP                     146  #define YELLOW_CARP_A0 0x01 -#define YELLOW_CARP_B0 0x02		// TODO: DCN31 - update with correct B0 ID +#define YELLOW_CARP_B0 0x20  #define YELLOW_CARP_UNKNOWN 0xFF  #ifndef ASICREV_IS_YELLOW_CARP diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index e9bd84ec027d..be61975f1470 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -105,6 +105,7 @@ static enum mod_hdcp_status remove_display_from_topology_v3(  	dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE;  	psp_dtm_invoke(psp, dtm_cmd->cmd_id); +	mutex_unlock(&psp->dtm_context.mutex);  	if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) {  		status = remove_display_from_topology_v2(hdcp, index); @@ -115,8 +116,6 @@ static enum mod_hdcp_status remove_display_from_topology_v3(  		HDCP_TOP_REMOVE_DISPLAY_TRACE(hdcp, display->index);  	} -	mutex_unlock(&psp->dtm_context.mutex); -  	return status;  } @@ -205,6 +204,7 @@ static enum mod_hdcp_status add_display_to_topology_v3(  	dtm_cmd->dtm_in_message.topology_update_v3.link_hdcp_cap = link->hdcp_supported_informational;  	psp_dtm_invoke(psp, dtm_cmd->cmd_id); +	mutex_unlock(&psp->dtm_context.mutex);  	if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) {  		status = add_display_to_topology_v2(hdcp, display); @@ -214,8 +214,6 @@ static enum mod_hdcp_status add_display_to_topology_v3(  		HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, display->index);  	} -	mutex_unlock(&psp->dtm_context.mutex); -  	return status;  } diff --git a/drivers/gpu/drm/amd/include/asic_reg/dpcs/dpcs_4_2_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dpcs/dpcs_4_2_0_offset.h index 92caf8441d1e..01a56556cde1 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dpcs/dpcs_4_2_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dpcs/dpcs_4_2_0_offset.h @@ -11932,5 +11932,32 @@  #define ixDPCSSYS_CR4_RAWLANEX_DIG_PCS_XF_RX_OVRD_OUT_2                                                0xe0c7  #define ixDPCSSYS_CR4_RAWLANEX_DIG_PCS_XF_TX_OVRD_IN_2                                                 0xe0c8 +//RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6 +#define RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DP4__SHIFT                                            0x10 +#define RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE__SHIFT                                        0x11 +#define RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE_ACK__SHIFT                                    0x12 +#define RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DP4_MASK                                              0x00010000L +#define RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE_MASK                                          0x00020000L +#define RDPCSPIPE0_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE_ACK_MASK                                      0x00040000L + +//RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6 +#define RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DP4__SHIFT                                            0x10 +#define RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE__SHIFT                                        0x11 +#define RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE_ACK__SHIFT                                    0x12 +#define RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DP4_MASK                                              0x00010000L +#define RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE_MASK                                          0x00020000L +#define RDPCSPIPE1_RDPCSPIPE_PHY_CNTL6__RDPCS_PHY_DPALT_DISABLE_ACK_MASK                                      0x00040000L + +//[Note] Hack. RDPCSPIPE only has 2 instances. +#define regRDPCSPIPE0_RDPCSPIPE_PHY_CNTL6                                                              0x2d73 +#define regRDPCSPIPE0_RDPCSPIPE_PHY_CNTL6_BASE_IDX                                                     2 +#define regRDPCSPIPE1_RDPCSPIPE_PHY_CNTL6                                                              0x2e4b +#define regRDPCSPIPE1_RDPCSPIPE_PHY_CNTL6_BASE_IDX                                                     2 +#define regRDPCSPIPE2_RDPCSPIPE_PHY_CNTL6                                                              0x2d73 +#define regRDPCSPIPE2_RDPCSPIPE_PHY_CNTL6_BASE_IDX                                                     2 +#define regRDPCSPIPE3_RDPCSPIPE_PHY_CNTL6                                                              0x2e4b +#define regRDPCSPIPE3_RDPCSPIPE_PHY_CNTL6_BASE_IDX                                                     2 +#define regRDPCSPIPE4_RDPCSPIPE_PHY_CNTL6                                                              0x2d73 +#define regRDPCSPIPE4_RDPCSPIPE_PHY_CNTL6_BASE_IDX                                                     2  #endif diff --git a/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h index 8a08ecc34c69..4884a4e1f261 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h +++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h @@ -33,63 +33,47 @@  #define TABLE_PMSTATUSLOG        3 // Called by Tools for Agm logging  #define TABLE_DPMCLOCKS          4 // Called by Driver; defined here, but not used, for backward compatible  #define TABLE_MOMENTARY_PM       5 // Called by Tools; defined here, but not used, for backward compatible -#define TABLE_COUNT              6 +#define TABLE_SMU_METRICS        6 // Called by Driver +#define TABLE_COUNT              7 -#define NUM_DSPCLK_LEVELS		8 -#define NUM_SOCCLK_DPM_LEVELS	8 -#define NUM_DCEFCLK_DPM_LEVELS	4 -#define NUM_FCLK_DPM_LEVELS		4 -#define NUM_MEMCLK_DPM_LEVELS	4 +typedef struct SmuMetricsTable_t { +	//CPU status +	uint16_t CoreFrequency[6];              //[MHz] +	uint32_t CorePower[6];                  //[mW] +	uint16_t CoreTemperature[6];            //[centi-Celsius] +	uint16_t L3Frequency[2];                //[MHz] +	uint16_t L3Temperature[2];              //[centi-Celsius] +	uint16_t C0Residency[6];                //Percentage -#define NUMBER_OF_PSTATES		8 -#define NUMBER_OF_CORES			8 +	// GFX status +	uint16_t GfxclkFrequency;               //[MHz] +	uint16_t GfxTemperature;                //[centi-Celsius] -typedef enum { -	S3_TYPE_ENTRY, -	S5_TYPE_ENTRY, -} Sleep_Type_e; +	// SOC IP info +	uint16_t SocclkFrequency;               //[MHz] +	uint16_t VclkFrequency;                 //[MHz] +	uint16_t DclkFrequency;                 //[MHz] +	uint16_t MemclkFrequency;               //[MHz] -typedef enum { -	GFX_OFF = 0, -	GFX_ON  = 1, -} GFX_Mode_e; +	// power, VF info for CPU/GFX telemetry rails, and then socket power total +	uint32_t Voltage[2];                    //[mV] indices: VDDCR_VDD, VDDCR_GFX +	uint32_t Current[2];                    //[mA] indices: VDDCR_VDD, VDDCR_GFX +	uint32_t Power[2];                      //[mW] indices: VDDCR_VDD, VDDCR_GFX +	uint32_t CurrentSocketPower;            //[mW] -typedef enum { -	CPU_P0 = 0, -	CPU_P1, -	CPU_P2, -	CPU_P3, -	CPU_P4, -	CPU_P5, -	CPU_P6, -	CPU_P7 -} CPU_PState_e; +	uint16_t SocTemperature;                //[centi-Celsius] +	uint16_t EdgeTemperature; +	uint16_t ThrottlerStatus; +	uint16_t Spare; -typedef enum { -	CPU_CORE0 = 0, -	CPU_CORE1, -	CPU_CORE2, -	CPU_CORE3, -	CPU_CORE4, -	CPU_CORE5, -	CPU_CORE6, -	CPU_CORE7 -} CORE_ID_e; +} SmuMetricsTable_t; -typedef enum { -	DF_DPM0 = 0, -	DF_DPM1, -	DF_DPM2, -	DF_DPM3, -	DF_PState_Count -} DF_PState_e; - -typedef enum { -	GFX_DPM0 = 0, -	GFX_DPM1, -	GFX_DPM2, -	GFX_DPM3, -	GFX_PState_Count -} GFX_PState_e; +typedef struct SmuMetrics_t { +	SmuMetricsTable_t Current; +	SmuMetricsTable_t Average; +	uint32_t SampleStartTime; +	uint32_t SampleStopTime; +	uint32_t Accnt; +} SmuMetrics_t;  #endif diff --git a/drivers/gpu/drm/amd/pm/inc/smu_types.h b/drivers/gpu/drm/amd/pm/inc/smu_types.h index 6f1b1b50d527..18b862a90fbe 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_types.h @@ -226,7 +226,10 @@  	__SMU_DUMMY_MAP(SetUclkDpmMode),		\  	__SMU_DUMMY_MAP(LightSBR),			\  	__SMU_DUMMY_MAP(GfxDriverResetRecovery),	\ -	__SMU_DUMMY_MAP(BoardPowerCalibration), +	__SMU_DUMMY_MAP(BoardPowerCalibration),   \ +	__SMU_DUMMY_MAP(RequestGfxclk),           \ +	__SMU_DUMMY_MAP(ForceGfxVid),             \ +	__SMU_DUMMY_MAP(UnforceGfxVid),  #undef __SMU_DUMMY_MAP  #define __SMU_DUMMY_MAP(type)	SMU_MSG_##type diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h index 6e6088760b18..909a86aa60f3 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h @@ -65,6 +65,13 @@  #define PPSMC_MSG_SetDriverTableVMID                    0x34  #define PPSMC_MSG_SetSoftMinCclk                        0x35  #define PPSMC_MSG_SetSoftMaxCclk                        0x36 -#define PPSMC_Message_Count                             0x37 +#define PPSMC_MSG_GetGfxFrequency                       0x37 +#define PPSMC_MSG_GetGfxVid                             0x38 +#define PPSMC_MSG_ForceGfxFreq                          0x39 +#define PPSMC_MSG_UnForceGfxFreq                        0x3A +#define PPSMC_MSG_ForceGfxVid                           0x3B +#define PPSMC_MSG_UnforceGfxVid                         0x3C +#define PPSMC_MSG_GetEnabledSmuFeatures                 0x3D +#define PPSMC_Message_Count                             0x3E  #endif diff --git a/drivers/gpu/drm/amd/pm/powerplay/si_dpm.c b/drivers/gpu/drm/amd/pm/powerplay/si_dpm.c index bdbbeb959c68..81f82aa05ec2 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/powerplay/si_dpm.c @@ -6867,6 +6867,8 @@ static int si_dpm_enable(struct amdgpu_device *adev)  	si_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, true);  	si_thermal_start_thermal_controller(adev); +	ni_update_current_ps(adev, boot_ps); +  	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 3ab1ce4d3419..04863a797115 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1404,7 +1404,7 @@ static int smu_disable_dpms(struct smu_context *smu)  	 */  	if (smu->uploading_custom_pp_table &&  	    (adev->asic_type >= CHIP_NAVI10) && -	    (adev->asic_type <= CHIP_DIMGREY_CAVEFISH)) +	    (adev->asic_type <= CHIP_BEIGE_GOBY))  		return smu_disable_all_features_with_exception(smu,  							       true,  							       SMU_FEATURE_COUNT); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index e343cc218990..082f01893f3d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -771,8 +771,12 @@ static int arcturus_print_clk_levels(struct smu_context *smu,  	struct smu_11_0_dpm_context *dpm_context = NULL;  	uint32_t gen_speed, lane_width; -	if (amdgpu_ras_intr_triggered()) -		return sysfs_emit(buf, "unavailable\n"); +	smu_cmn_get_sysfs_buf(&buf, &size); + +	if (amdgpu_ras_intr_triggered()) { +		size += sysfs_emit_at(buf, size, "unavailable\n"); +		return size; +	}  	dpm_context = smu_dpm->dpm_context; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index b05f9541accc..3d4c65bc29dc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -44,6 +44,27 @@  #undef pr_info  #undef pr_debug +/* unit: MHz */ +#define CYAN_SKILLFISH_SCLK_MIN			1000 +#define CYAN_SKILLFISH_SCLK_MAX			2000 +#define CYAN_SKILLFISH_SCLK_DEFAULT			1800 + +/* unit: mV */ +#define CYAN_SKILLFISH_VDDC_MIN			700 +#define CYAN_SKILLFISH_VDDC_MAX			1129 +#define CYAN_SKILLFISH_VDDC_MAGIC			5118 // 0x13fe + +static struct gfx_user_settings { +	uint32_t sclk; +	uint32_t vddc; +} cyan_skillfish_user_settings; + +#define FEATURE_MASK(feature) (1ULL << feature) +#define SMC_DPM_FEATURE ( \ +	FEATURE_MASK(FEATURE_FCLK_DPM_BIT)	|	\ +	FEATURE_MASK(FEATURE_SOC_DPM_BIT)	|	\ +	FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +  static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = {  	MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,			0),  	MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,		0), @@ -52,14 +73,473 @@ static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT]  	MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverTableDramAddrLow,	0),  	MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,	0),  	MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,	0), +	MSG_MAP(GetEnabledSmuFeatures,          PPSMC_MSG_GetEnabledSmuFeatures,	0), +	MSG_MAP(RequestGfxclk,                  PPSMC_MSG_RequestGfxclk,		0), +	MSG_MAP(ForceGfxVid,                    PPSMC_MSG_ForceGfxVid,			0), +	MSG_MAP(UnforceGfxVid,                  PPSMC_MSG_UnforceGfxVid,		0), +}; + +static struct cmn2asic_mapping cyan_skillfish_table_map[SMU_TABLE_COUNT] = { +	TAB_MAP_VALID(SMU_METRICS),  }; +static int cyan_skillfish_tables_init(struct smu_context *smu) +{ +	struct smu_table_context *smu_table = &smu->smu_table; +	struct smu_table *tables = smu_table->tables; + +	SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, +				sizeof(SmuMetrics_t), +				PAGE_SIZE, +				AMDGPU_GEM_DOMAIN_VRAM); + +	smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); +	if (!smu_table->metrics_table) +		goto err0_out; + +	smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2); +	smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); +	if (!smu_table->gpu_metrics_table) +		goto err1_out; + +	smu_table->metrics_time = 0; + +	return 0; + +err1_out: +	smu_table->gpu_metrics_table_size = 0; +	kfree(smu_table->metrics_table); +err0_out: +	return -ENOMEM; +} + +static int cyan_skillfish_init_smc_tables(struct smu_context *smu) +{ +	int ret = 0; + +	ret = cyan_skillfish_tables_init(smu); +	if (ret) +		return ret; + +	return smu_v11_0_init_smc_tables(smu); +} + +static int cyan_skillfish_finit_smc_tables(struct smu_context *smu) +{ +	struct smu_table_context *smu_table = &smu->smu_table; + +	kfree(smu_table->metrics_table); +	smu_table->metrics_table = NULL; + +	kfree(smu_table->gpu_metrics_table); +	smu_table->gpu_metrics_table = NULL; +	smu_table->gpu_metrics_table_size = 0; + +	smu_table->metrics_time = 0; + +	return 0; +} + +static int +cyan_skillfish_get_smu_metrics_data(struct smu_context *smu, +					MetricsMember_t member, +					uint32_t *value) +{ +	struct smu_table_context *smu_table = &smu->smu_table; +	SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; +	int ret = 0; + +	mutex_lock(&smu->metrics_lock); + +	ret = smu_cmn_get_metrics_table_locked(smu, NULL, false); +	if (ret) { +		mutex_unlock(&smu->metrics_lock); +		return ret; +	} + +	switch (member) { +	case METRICS_CURR_GFXCLK: +		*value = metrics->Current.GfxclkFrequency; +		break; +	case METRICS_CURR_SOCCLK: +		*value = metrics->Current.SocclkFrequency; +		break; +	case METRICS_CURR_VCLK: +		*value = metrics->Current.VclkFrequency; +		break; +	case METRICS_CURR_DCLK: +		*value = metrics->Current.DclkFrequency; +		break; +	case METRICS_CURR_UCLK: +		*value = metrics->Current.MemclkFrequency; +		break; +	case METRICS_AVERAGE_SOCKETPOWER: +		*value = (metrics->Current.CurrentSocketPower << 8) / +				1000; +		break; +	case METRICS_TEMPERATURE_EDGE: +		*value = metrics->Current.GfxTemperature / 100 * +				SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; +		break; +	case METRICS_TEMPERATURE_HOTSPOT: +		*value = metrics->Current.SocTemperature / 100 * +				SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; +		break; +	case METRICS_VOLTAGE_VDDSOC: +		*value = metrics->Current.Voltage[0]; +		break; +	case METRICS_VOLTAGE_VDDGFX: +		*value = metrics->Current.Voltage[1]; +		break; +	case METRICS_THROTTLER_STATUS: +		*value = metrics->Current.ThrottlerStatus; +		break; +	default: +		*value = UINT_MAX; +		break; +	} + +	mutex_unlock(&smu->metrics_lock); + +	return ret; +} + +static int cyan_skillfish_read_sensor(struct smu_context *smu, +					enum amd_pp_sensors sensor, +					void *data, +					uint32_t *size) +{ +	int ret = 0; + +	if (!data || !size) +		return -EINVAL; + +	mutex_lock(&smu->sensor_lock); + +	switch (sensor) { +	case AMDGPU_PP_SENSOR_GFX_SCLK: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_CURR_GFXCLK, +						   (uint32_t *)data); +		*(uint32_t *)data *= 100; +		*size = 4; +		break; +	case AMDGPU_PP_SENSOR_GFX_MCLK: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_CURR_UCLK, +						   (uint32_t *)data); +		*(uint32_t *)data *= 100; +		*size = 4; +		break; +	case AMDGPU_PP_SENSOR_GPU_POWER: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_AVERAGE_SOCKETPOWER, +						   (uint32_t *)data); +		*size = 4; +		break; +	case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_TEMPERATURE_HOTSPOT, +						   (uint32_t *)data); +		*size = 4; +		break; +	case AMDGPU_PP_SENSOR_EDGE_TEMP: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_TEMPERATURE_EDGE, +						   (uint32_t *)data); +		*size = 4; +		break; +	case AMDGPU_PP_SENSOR_VDDNB: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_VOLTAGE_VDDSOC, +						   (uint32_t *)data); +		*size = 4; +		break; +	case AMDGPU_PP_SENSOR_VDDGFX: +		ret = cyan_skillfish_get_smu_metrics_data(smu, +						   METRICS_VOLTAGE_VDDGFX, +						   (uint32_t *)data); +		*size = 4; +		break; +	default: +		ret = -EOPNOTSUPP; +		break; +	} + +	mutex_unlock(&smu->sensor_lock); + +	return ret; +} + +static int cyan_skillfish_get_current_clk_freq(struct smu_context *smu, +						enum smu_clk_type clk_type, +						uint32_t *value) +{ +	MetricsMember_t member_type; + +	switch (clk_type) { +	case SMU_GFXCLK: +	case SMU_SCLK: +		member_type = METRICS_CURR_GFXCLK; +		break; +	case SMU_FCLK: +	case SMU_MCLK: +		member_type = METRICS_CURR_UCLK; +		break; +	case SMU_SOCCLK: +		member_type = METRICS_CURR_SOCCLK; +		break; +	case SMU_VCLK: +		member_type = METRICS_CURR_VCLK; +		break; +	case SMU_DCLK: +		member_type = METRICS_CURR_DCLK; +		break; +	default: +		return -EINVAL; +	} + +	return cyan_skillfish_get_smu_metrics_data(smu, member_type, value); +} + +static int cyan_skillfish_print_clk_levels(struct smu_context *smu, +					enum smu_clk_type clk_type, +					char *buf) +{ +	int ret = 0, size = 0; +	uint32_t cur_value = 0; + +	smu_cmn_get_sysfs_buf(&buf, &size); + +	switch (clk_type) { +	case SMU_OD_SCLK: +		ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cur_value); +		if (ret) +			return ret; +		size += sysfs_emit_at(buf, size,"%s:\n", "OD_SCLK"); +		size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value); +		break; +	case SMU_OD_VDDC_CURVE: +		ret  = cyan_skillfish_get_smu_metrics_data(smu, METRICS_VOLTAGE_VDDGFX, &cur_value); +		if (ret) +			return ret; +		size += sysfs_emit_at(buf, size,"%s:\n", "OD_VDDC"); +		size += sysfs_emit_at(buf, size, "0: %umV *\n", cur_value); +		break; +	case SMU_OD_RANGE: +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); +		size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", +						CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX); +		size += sysfs_emit_at(buf, size, "VDDC: %7umV  %10umV\n", +						CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX); +		break; +	case SMU_GFXCLK: +	case SMU_SCLK: +	case SMU_FCLK: +	case SMU_MCLK: +	case SMU_SOCCLK: +	case SMU_VCLK: +	case SMU_DCLK: +		ret = cyan_skillfish_get_current_clk_freq(smu, clk_type, &cur_value); +		if (ret) +			return ret; +		size += sysfs_emit_at(buf, size, "0: %uMhz *\n", cur_value); +		break; +	default: +		dev_warn(smu->adev->dev, "Unsupported clock type\n"); +		return ret; +	} + +	return size; +} + +static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) +{ +	struct amdgpu_device *adev = smu->adev; +	int ret = 0; +	uint32_t feature_mask[2]; +	uint64_t feature_enabled; + +	/* we need to re-init after suspend so return false */ +	if (adev->in_suspend) +		return false; + +	ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2); + +	if (ret) +		return false; + +	feature_enabled = (uint64_t)feature_mask[0] | +				((uint64_t)feature_mask[1] << 32); + +	return !!(feature_enabled & SMC_DPM_FEATURE); +} + +static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu, +						void **table) +{ +	struct smu_table_context *smu_table = &smu->smu_table; +	struct gpu_metrics_v2_2 *gpu_metrics = +		(struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table; +	SmuMetrics_t metrics; +	int i, ret = 0; + +	ret = smu_cmn_get_metrics_table(smu, &metrics, true); +	if (ret) +		return ret; + +	smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 2); + +	gpu_metrics->temperature_gfx = metrics.Current.GfxTemperature; +	gpu_metrics->temperature_soc = metrics.Current.SocTemperature; + +	gpu_metrics->average_socket_power = metrics.Current.CurrentSocketPower; +	gpu_metrics->average_soc_power = metrics.Current.Power[0]; +	gpu_metrics->average_gfx_power = metrics.Current.Power[1]; + +	gpu_metrics->average_gfxclk_frequency = metrics.Average.GfxclkFrequency; +	gpu_metrics->average_socclk_frequency = metrics.Average.SocclkFrequency; +	gpu_metrics->average_uclk_frequency = metrics.Average.MemclkFrequency; +	gpu_metrics->average_fclk_frequency = metrics.Average.MemclkFrequency; +	gpu_metrics->average_vclk_frequency = metrics.Average.VclkFrequency; +	gpu_metrics->average_dclk_frequency = metrics.Average.DclkFrequency; + +	gpu_metrics->current_gfxclk = metrics.Current.GfxclkFrequency; +	gpu_metrics->current_socclk = metrics.Current.SocclkFrequency; +	gpu_metrics->current_uclk = metrics.Current.MemclkFrequency; +	gpu_metrics->current_fclk = metrics.Current.MemclkFrequency; +	gpu_metrics->current_vclk = metrics.Current.VclkFrequency; +	gpu_metrics->current_dclk = metrics.Current.DclkFrequency; + +	for (i = 0; i < 6; i++) { +		gpu_metrics->temperature_core[i] = metrics.Current.CoreTemperature[i]; +		gpu_metrics->average_core_power[i] = metrics.Average.CorePower[i]; +		gpu_metrics->current_coreclk[i] = metrics.Current.CoreFrequency[i]; +	} + +	for (i = 0; i < 2; i++) { +		gpu_metrics->temperature_l3[i] = metrics.Current.L3Temperature[i]; +		gpu_metrics->current_l3clk[i] = metrics.Current.L3Frequency[i]; +	} + +	gpu_metrics->throttle_status = metrics.Current.ThrottlerStatus; +	gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + +	*table = (void *)gpu_metrics; + +	return sizeof(struct gpu_metrics_v2_2); +} + +static int cyan_skillfish_od_edit_dpm_table(struct smu_context *smu, +					enum PP_OD_DPM_TABLE_COMMAND type, +					long input[], uint32_t size) +{ +	int ret = 0; +	uint32_t vid; + +	switch (type) { +	case PP_OD_EDIT_VDDC_CURVE: +		if (size != 3 || input[0] != 0) { +			dev_err(smu->adev->dev, "Invalid parameter!\n"); +			return -EINVAL; +		} + +		if (input[1] <= CYAN_SKILLFISH_SCLK_MIN || +			input[1] > CYAN_SKILLFISH_SCLK_MAX) { +			dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n", +					CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX); +			return -EINVAL; +		} + +		if (input[2] <= CYAN_SKILLFISH_VDDC_MIN || +			input[2] > CYAN_SKILLFISH_VDDC_MAX) { +			dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n", +					CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX); +			return -EINVAL; +		} + +		cyan_skillfish_user_settings.sclk = input[1]; +		cyan_skillfish_user_settings.vddc = input[2]; + +		break; +	case PP_OD_RESTORE_DEFAULT_TABLE: +		if (size != 0) { +			dev_err(smu->adev->dev, "Invalid parameter!\n"); +			return -EINVAL; +		} + +		cyan_skillfish_user_settings.sclk = CYAN_SKILLFISH_SCLK_DEFAULT; +		cyan_skillfish_user_settings.vddc = CYAN_SKILLFISH_VDDC_MAGIC; + +		break; +	case PP_OD_COMMIT_DPM_TABLE: +		if (size != 0) { +			dev_err(smu->adev->dev, "Invalid parameter!\n"); +			return -EINVAL; +		} + +		if (cyan_skillfish_user_settings.sclk < CYAN_SKILLFISH_SCLK_MIN || +		    cyan_skillfish_user_settings.sclk > CYAN_SKILLFISH_SCLK_MAX) { +			dev_err(smu->adev->dev, "Invalid sclk! Valid sclk range: %uMHz - %uMhz\n", +					CYAN_SKILLFISH_SCLK_MIN, CYAN_SKILLFISH_SCLK_MAX); +			return -EINVAL; +		} + +		if ((cyan_skillfish_user_settings.vddc != CYAN_SKILLFISH_VDDC_MAGIC) && +			(cyan_skillfish_user_settings.vddc < CYAN_SKILLFISH_VDDC_MIN || +			cyan_skillfish_user_settings.vddc > CYAN_SKILLFISH_VDDC_MAX)) { +			dev_err(smu->adev->dev, "Invalid vddc! Valid vddc range: %umV - %umV\n", +					CYAN_SKILLFISH_VDDC_MIN, CYAN_SKILLFISH_VDDC_MAX); +			return -EINVAL; +		} + +		ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RequestGfxclk, +					cyan_skillfish_user_settings.sclk, NULL); +		if (ret) { +			dev_err(smu->adev->dev, "Set sclk failed!\n"); +			return ret; +		} + +		if (cyan_skillfish_user_settings.vddc == CYAN_SKILLFISH_VDDC_MAGIC) { +			ret = smu_cmn_send_smc_msg(smu, SMU_MSG_UnforceGfxVid, NULL); +			if (ret) { +				dev_err(smu->adev->dev, "Unforce vddc failed!\n"); +				return ret; +			} +		} else { +			/* +			 * PMFW accepts SVI2 VID code, convert voltage to VID: +			 * vid = (uint32_t)((1.55 - voltage) * 160.0 + 0.00001) +			 */ +			vid = (1550 - cyan_skillfish_user_settings.vddc) * 160 / 1000; +			ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ForceGfxVid, vid, NULL); +			if (ret) { +				dev_err(smu->adev->dev, "Force vddc failed!\n"); +				return ret; +			} +		} + +		break; +	default: +		return -EOPNOTSUPP; +	} + +	return ret; +} +  static const struct pptable_funcs cyan_skillfish_ppt_funcs = {  	.check_fw_status = smu_v11_0_check_fw_status,  	.check_fw_version = smu_v11_0_check_fw_version,  	.init_power = smu_v11_0_init_power,  	.fini_power = smu_v11_0_fini_power, +	.init_smc_tables = cyan_skillfish_init_smc_tables, +	.fini_smc_tables = cyan_skillfish_finit_smc_tables, +	.read_sensor = cyan_skillfish_read_sensor, +	.print_clk_levels = cyan_skillfish_print_clk_levels, +	.is_dpm_running = cyan_skillfish_is_dpm_running, +	.get_gpu_metrics = cyan_skillfish_get_gpu_metrics, +	.od_edit_dpm_table = cyan_skillfish_od_edit_dpm_table,  	.register_irq_handler = smu_v11_0_register_irq_handler,  	.notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,  	.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, @@ -72,5 +552,6 @@ void cyan_skillfish_set_ppt_funcs(struct smu_context *smu)  {  	smu->ppt_funcs = &cyan_skillfish_ppt_funcs;  	smu->message_map = cyan_skillfish_message_map; +	smu->table_map = cyan_skillfish_table_map;  	smu->is_apu = true;  } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index a5fc5d7cb6c7..b1ad451af06b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -1279,6 +1279,8 @@ static int navi10_print_clk_levels(struct smu_context *smu,  	struct smu_11_0_overdrive_table *od_settings = smu->od_settings;  	uint32_t min_value, max_value; +	smu_cmn_get_sysfs_buf(&buf, &size); +  	switch (clk_type) {  	case SMU_GFXCLK:  	case SMU_SCLK: @@ -1392,7 +1394,7 @@ static int navi10_print_clk_levels(struct smu_context *smu,  	case SMU_OD_RANGE:  		if (!smu->od_enabled || !od_table || !od_settings)  			break; -		size = sysfs_emit(buf, "%s:\n", "OD_RANGE"); +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");  		if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) {  			navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN, @@ -2272,7 +2274,27 @@ static int navi10_baco_enter(struct smu_context *smu)  {  	struct amdgpu_device *adev = smu->adev; -	if (adev->in_runpm) +	/* +	 * This aims the case below: +	 *   amdgpu driver loaded -> runpm suspend kicked -> sound driver loaded +	 * +	 * For NAVI10 and later ASICs, we rely on PMFW to handle the runpm. To +	 * make that possible, PMFW needs to acknowledge the dstate transition +	 * process for both gfx(function 0) and audio(function 1) function of +	 * the ASIC. +	 * +	 * The PCI device's initial runpm status is RUNPM_SUSPENDED. So as the +	 * device representing the audio function of the ASIC. And that means +	 * even if the sound driver(snd_hda_intel) was not loaded yet, it's still +	 * possible runpm suspend kicked on the ASIC. However without the dstate +	 * transition notification from audio function, pmfw cannot handle the +	 * BACO in/exit correctly. And that will cause driver hang on runpm +	 * resuming. +	 * +	 * To address this, we revert to legacy message way(driver masters the +	 * timing for BACO in/exit) on sound driver missing. +	 */ +	if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev))  		return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO);  	else  		return smu_v11_0_baco_enter(smu); @@ -2282,7 +2304,7 @@ static int navi10_baco_exit(struct smu_context *smu)  {  	struct amdgpu_device *adev = smu->adev; -	if (adev->in_runpm) { +	if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) {  		/* Wait for PMFW handling for the Dstate change */  		msleep(10);  		return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 5e292c3f5050..ca57221e3962 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -1058,6 +1058,8 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,  	uint32_t min_value, max_value;  	uint32_t smu_version; +	smu_cmn_get_sysfs_buf(&buf, &size); +  	switch (clk_type) {  	case SMU_GFXCLK:  	case SMU_SCLK: @@ -1180,7 +1182,7 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,  		if (!smu->od_enabled || !od_table || !od_settings)  			break; -		size = sysfs_emit(buf, "%s:\n", "OD_RANGE"); +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");  		if (sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS)) {  			sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMIN, @@ -2187,7 +2189,7 @@ static int sienna_cichlid_baco_enter(struct smu_context *smu)  {  	struct amdgpu_device *adev = smu->adev; -	if (adev->in_runpm) +	if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev))  		return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO);  	else  		return smu_v11_0_baco_enter(smu); @@ -2197,7 +2199,7 @@ static int sienna_cichlid_baco_exit(struct smu_context *smu)  {  	struct amdgpu_device *adev = smu->adev; -	if (adev->in_runpm) { +	if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) {  		/* Wait for PMFW handling for the Dstate change */  		msleep(10);  		return smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 3a3421452e57..f6ef0ce6e9e2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -589,10 +589,12 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,  	if (ret)  		return ret; +	smu_cmn_get_sysfs_buf(&buf, &size); +  	switch (clk_type) {  	case SMU_OD_SCLK:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { -			size = sysfs_emit(buf, "%s:\n", "OD_SCLK"); +			size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");  			size += sysfs_emit_at(buf, size, "0: %10uMhz\n",  			(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);  			size += sysfs_emit_at(buf, size, "1: %10uMhz\n", @@ -601,7 +603,7 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,  		break;  	case SMU_OD_CCLK:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { -			size = sysfs_emit(buf, "CCLK_RANGE in Core%d:\n",  smu->cpu_core_id_select); +			size += sysfs_emit_at(buf, size, "CCLK_RANGE in Core%d:\n",  smu->cpu_core_id_select);  			size += sysfs_emit_at(buf, size, "0: %10uMhz\n",  			(smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);  			size += sysfs_emit_at(buf, size, "1: %10uMhz\n", @@ -610,7 +612,7 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,  		break;  	case SMU_OD_RANGE:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { -			size = sysfs_emit(buf, "%s:\n", "OD_RANGE"); +			size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");  			size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",  				smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);  			size += sysfs_emit_at(buf, size, "CCLK: %7uMhz %10uMhz\n", @@ -688,10 +690,12 @@ static int vangogh_print_clk_levels(struct smu_context *smu,  	if (ret)  		return ret; +	smu_cmn_get_sysfs_buf(&buf, &size); +  	switch (clk_type) {  	case SMU_OD_SCLK:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { -			size = sysfs_emit(buf, "%s:\n", "OD_SCLK"); +			size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");  			size += sysfs_emit_at(buf, size, "0: %10uMhz\n",  			(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);  			size += sysfs_emit_at(buf, size, "1: %10uMhz\n", @@ -700,7 +704,7 @@ static int vangogh_print_clk_levels(struct smu_context *smu,  		break;  	case SMU_OD_CCLK:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { -			size = sysfs_emit(buf, "CCLK_RANGE in Core%d:\n",  smu->cpu_core_id_select); +			size += sysfs_emit_at(buf, size, "CCLK_RANGE in Core%d:\n",  smu->cpu_core_id_select);  			size += sysfs_emit_at(buf, size, "0: %10uMhz\n",  			(smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);  			size += sysfs_emit_at(buf, size, "1: %10uMhz\n", @@ -709,7 +713,7 @@ static int vangogh_print_clk_levels(struct smu_context *smu,  		break;  	case SMU_OD_RANGE:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { -			size = sysfs_emit(buf, "%s:\n", "OD_RANGE"); +			size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");  			size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",  				smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);  			size += sysfs_emit_at(buf, size, "CCLK: %7uMhz %10uMhz\n", 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 5aa175e12a78..145f13b8c977 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -497,6 +497,8 @@ static int renoir_print_clk_levels(struct smu_context *smu,  	if (ret)  		return ret; +	smu_cmn_get_sysfs_buf(&buf, &size); +  	switch (clk_type) {  	case SMU_OD_RANGE:  		if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index ab652028e003..5019903db492 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -733,15 +733,19 @@ static int aldebaran_print_clk_levels(struct smu_context *smu,  	uint32_t freq_values[3] = {0};  	uint32_t min_clk, max_clk; -	if (amdgpu_ras_intr_triggered()) -		return sysfs_emit(buf, "unavailable\n"); +	smu_cmn_get_sysfs_buf(&buf, &size); + +	if (amdgpu_ras_intr_triggered()) { +		size += sysfs_emit_at(buf, size, "unavailable\n"); +		return size; +	}  	dpm_context = smu_dpm->dpm_context;  	switch (type) {  	case SMU_OD_SCLK: -		size = sysfs_emit(buf, "%s:\n", "GFXCLK"); +		size += sysfs_emit_at(buf, size, "%s:\n", "GFXCLK");  		fallthrough;  	case SMU_SCLK:  		ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &now); @@ -795,7 +799,7 @@ static int aldebaran_print_clk_levels(struct smu_context *smu,  		break;  	case SMU_OD_MCLK: -		size = sysfs_emit(buf, "%s:\n", "MCLK"); +		size += sysfs_emit_at(buf, size, "%s:\n", "MCLK");  		fallthrough;  	case SMU_MCLK:  		ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_UCLK, &now); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 627ba2eec7fd..a403657151ba 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1052,16 +1052,18 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,  	int i, size = 0, ret = 0;  	uint32_t cur_value = 0, value = 0, count = 0; +	smu_cmn_get_sysfs_buf(&buf, &size); +  	switch (clk_type) {  	case SMU_OD_SCLK: -		size = sysfs_emit(buf, "%s:\n", "OD_SCLK"); +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK");  		size += sysfs_emit_at(buf, size, "0: %10uMhz\n",  		(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);  		size += sysfs_emit_at(buf, size, "1: %10uMhz\n",  		(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);  		break;  	case SMU_OD_RANGE: -		size = sysfs_emit(buf, "%s:\n", "OD_RANGE"); +		size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");  		size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",  						smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);  		break; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 66711ab24c15..843d2cbfc71d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1053,3 +1053,24 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,  	return ret;  } + +bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) +{ +	struct pci_dev *p = NULL; +	bool snd_driver_loaded; + +	/* +	 * If the ASIC comes with no audio function, we always assume +	 * it is "enabled". +	 */ +	p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus), +			adev->pdev->bus->number, 1); +	if (!p) +		return true; + +	snd_driver_loaded = pci_is_enabled(p) ? true : false; + +	pci_dev_put(p); + +	return snd_driver_loaded; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 16993daa2ae0..beea03810bca 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -110,5 +110,20 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);  int smu_cmn_set_mp1_state(struct smu_context *smu,  			  enum pp_mp1_state mp1_state); +/* + * Helper function to make sysfs_emit_at() happy. Align buf to + * the current page boundary and record the offset. + */ +static inline void smu_cmn_get_sysfs_buf(char **buf, int *offset) +{ +	if (!*buf || !offset) +		return; + +	*offset = offset_in_page(*buf); +	*buf -= *offset; +} + +bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev); +  #endif  #endif diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 6bfaefa01818..1e30eaeb0e1b 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1300,18 +1300,6 @@ static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,  	return flags;  } -static enum drm_connector_status ast_connector_detect(struct drm_connector -						   *connector, bool force) -{ -	int r; - -	r = ast_get_modes(connector); -	if (r <= 0) -		return connector_status_disconnected; - -	return connector_status_connected; -} -  static void ast_connector_destroy(struct drm_connector *connector)  {  	struct ast_connector *ast_connector = to_ast_connector(connector); @@ -1327,7 +1315,6 @@ static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {  static const struct drm_connector_funcs ast_connector_funcs = {  	.reset = drm_atomic_helper_connector_reset, -	.detect = ast_connector_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.destroy = ast_connector_destroy,  	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, @@ -1355,8 +1342,7 @@ static int ast_connector_init(struct drm_device *dev)  	connector->interlace_allowed = 0;  	connector->doublescan_allowed = 0; -	connector->polled = DRM_CONNECTOR_POLL_CONNECT | -						DRM_CONNECTOR_POLL_DISCONNECT; +	connector->polled = DRM_CONNECTOR_POLL_CONNECT;  	drm_connector_attach_encoder(connector, encoder); @@ -1425,8 +1411,6 @@ int ast_mode_config_init(struct ast_private *ast)  	drm_mode_config_reset(dev); -	drm_kms_helper_poll_init(dev); -  	return 0;  } diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 30cc59fe6ef7..f19d9acbe959 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -31,7 +31,7 @@  #include <linux/dma-buf-map.h>  #include <linux/export.h>  #include <linux/highmem.h> -#include <linux/mem_encrypt.h> +#include <linux/cc_platform.h>  #include <xen/xen.h>  #include <drm/drm_cache.h> @@ -204,7 +204,7 @@ bool drm_need_swiotlb(int dma_bits)  	 * Enforce dma_alloc_coherent when memory encryption is active as well  	 * for the same reasons as for Xen paravirtual hosts.  	 */ -	if (mem_encrypt_active()) +	if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))  		return true;  	for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6325877c5fd6..ea9a79bc9583 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1834,11 +1834,20 @@ static void connector_bad_edid(struct drm_connector *connector,  			       u8 *edid, int num_blocks)  {  	int i; -	u8 num_of_ext = edid[0x7e]; +	u8 last_block; + +	/* +	 * 0x7e in the EDID is the number of extension blocks. The EDID +	 * is 1 (base block) + num_ext_blocks big. That means we can think +	 * of 0x7e in the EDID of the _index_ of the last block in the +	 * combined chunk of memory. +	 */ +	last_block = edid[0x7e];  	/* Calculate real checksum for the last edid extension block data */ -	connector->real_edid_checksum = -		drm_edid_block_checksum(edid + num_of_ext * EDID_LENGTH); +	if (last_block < num_blocks) +		connector->real_edid_checksum = +			drm_edid_block_checksum(edid + last_block * EDID_LENGTH);  	if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS))  		return; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3ab078321045..8e7a124d6c5a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1506,6 +1506,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,  {  	struct drm_client_dev *client = &fb_helper->client;  	struct drm_device *dev = fb_helper->dev; +	struct drm_mode_config *config = &dev->mode_config;  	int ret = 0;  	int crtc_count = 0;  	struct drm_connector_list_iter conn_iter; @@ -1663,6 +1664,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,  	/* Handle our overallocation */  	sizes.surface_height *= drm_fbdev_overalloc;  	sizes.surface_height /= 100; +	if (sizes.surface_height > config->max_height) { +		drm_dbg_kms(dev, "Fbdev over-allocation too large; clamping height to %d\n", +			    config->max_height); +		sizes.surface_height = config->max_height; +	}  	/* push down into drivers */  	ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index fcfe1a03c4a1..bf8a6e823a15 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -248,7 +248,7 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,  	if (ctx->trylock_only) {  		lockdep_assert_held(&ctx->ww_ctx); -		if (!ww_mutex_trylock(&lock->mutex)) +		if (!ww_mutex_trylock(&lock->mutex, NULL))  			return -EBUSY;  		else  			return 0; diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index f6bdec7fa925..e1b2ce4921ae 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -134,6 +134,12 @@ static const struct dmi_system_id orientation_data[] = {  		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T103HAF"),  		},  		.driver_data = (void *)&lcd800x1280_rightside_up, +	}, {	/* AYA NEO 2021 */ +		.matches = { +		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYADEVICE"), +		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "AYA NEO 2021"), +		}, +		.driver_data = (void *)&lcd800x1280_rightside_up,  	}, {	/* GPD MicroPC (generic strings, also match on bios date) */  		.matches = {  		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"), @@ -185,6 +191,12 @@ static const struct dmi_system_id orientation_data[] = {  		  DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),  		},  		.driver_data = (void *)&gpd_win2, +	}, {	/* GPD Win 3 */ +		.matches = { +		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"), +		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1618-03") +		}, +		.driver_data = (void *)&lcd720x1280_rightside_up,  	}, {	/* I.T.Works TW891 */  		.matches = {  		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 76d38561c910..cf741c5c82d2 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -397,8 +397,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,  		if (switch_mmu_context) {  			struct etnaviv_iommu_context *old_context = gpu->mmu_context; -			etnaviv_iommu_context_get(mmu_context); -			gpu->mmu_context = mmu_context; +			gpu->mmu_context = etnaviv_iommu_context_get(mmu_context);  			etnaviv_iommu_context_put(old_context);  		} diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 8f1b5af47dd6..f0b2540e60e4 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -294,8 +294,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(  		list_del(&mapping->obj_node);  	} -	etnaviv_iommu_context_get(mmu_context); -	mapping->context = mmu_context; +	mapping->context = etnaviv_iommu_context_get(mmu_context);  	mapping->use = 1;  	ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 4dd7d9d541c0..486259e154af 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -532,8 +532,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,  		goto err_submit_objects;  	submit->ctx = file->driver_priv; -	etnaviv_iommu_context_get(submit->ctx->mmu); -	submit->mmu_context = submit->ctx->mmu; +	submit->mmu_context = etnaviv_iommu_context_get(submit->ctx->mmu);  	submit->exec_state = args->exec_state;  	submit->flags = args->flags; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index c297fffe06eb..cc5b07f86346 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -569,6 +569,12 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)  	/* We rely on the GPU running, so program the clock */  	etnaviv_gpu_update_clock(gpu); +	gpu->fe_running = false; +	gpu->exec_state = -1; +	if (gpu->mmu_context) +		etnaviv_iommu_context_put(gpu->mmu_context); +	gpu->mmu_context = NULL; +  	return 0;  } @@ -637,19 +643,23 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)  			  VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE |  			  VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch));  	} + +	gpu->fe_running = true;  } -static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu) +static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu, +					  struct etnaviv_iommu_context *context)  { -	u32 address = etnaviv_cmdbuf_get_va(&gpu->buffer, -				&gpu->mmu_context->cmdbuf_mapping);  	u16 prefetch; +	u32 address;  	/* setup the MMU */ -	etnaviv_iommu_restore(gpu, gpu->mmu_context); +	etnaviv_iommu_restore(gpu, context);  	/* Start command processor */  	prefetch = etnaviv_buffer_init(gpu); +	address = etnaviv_cmdbuf_get_va(&gpu->buffer, +					&gpu->mmu_context->cmdbuf_mapping);  	etnaviv_gpu_start_fe(gpu, address, prefetch);  } @@ -832,7 +842,6 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)  	/* Now program the hardware */  	mutex_lock(&gpu->lock);  	etnaviv_gpu_hw_init(gpu); -	gpu->exec_state = -1;  	mutex_unlock(&gpu->lock);  	pm_runtime_mark_last_busy(gpu->dev); @@ -1057,8 +1066,6 @@ void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu)  	spin_unlock(&gpu->event_spinlock);  	etnaviv_gpu_hw_init(gpu); -	gpu->exec_state = -1; -	gpu->mmu_context = NULL;  	mutex_unlock(&gpu->lock);  	pm_runtime_mark_last_busy(gpu->dev); @@ -1370,14 +1377,12 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit)  		goto out_unlock;  	} -	if (!gpu->mmu_context) { -		etnaviv_iommu_context_get(submit->mmu_context); -		gpu->mmu_context = submit->mmu_context; -		etnaviv_gpu_start_fe_idleloop(gpu); -	} else { -		etnaviv_iommu_context_get(gpu->mmu_context); -		submit->prev_mmu_context = gpu->mmu_context; -	} +	if (!gpu->fe_running) +		etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context); + +	if (submit->prev_mmu_context) +		etnaviv_iommu_context_put(submit->prev_mmu_context); +	submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context);  	if (submit->nr_pmrs) {  		gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; @@ -1579,7 +1584,7 @@ int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms)  static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)  { -	if (gpu->initialized && gpu->mmu_context) { +	if (gpu->initialized && gpu->fe_running) {  		/* Replace the last WAIT with END */  		mutex_lock(&gpu->lock);  		etnaviv_buffer_end(gpu); @@ -1592,8 +1597,7 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)  		 */  		etnaviv_gpu_wait_idle(gpu, 100); -		etnaviv_iommu_context_put(gpu->mmu_context); -		gpu->mmu_context = NULL; +		gpu->fe_running = false;  	}  	gpu->exec_state = -1; @@ -1741,6 +1745,9 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,  	etnaviv_gpu_hw_suspend(gpu);  #endif +	if (gpu->mmu_context) +		etnaviv_iommu_context_put(gpu->mmu_context); +  	if (gpu->initialized) {  		etnaviv_cmdbuf_free(&gpu->buffer);  		etnaviv_iommu_global_fini(gpu); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 8ea48697d132..1c75c8ed5bce 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -101,6 +101,7 @@ struct etnaviv_gpu {  	struct workqueue_struct *wq;  	struct drm_gpu_scheduler sched;  	bool initialized; +	bool fe_running;  	/* 'ring'-buffer: */  	struct etnaviv_cmdbuf buffer; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c index 1a7c89a67bea..afe5dd6a9925 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c @@ -92,6 +92,10 @@ static void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu,  	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);  	u32 pgtable; +	if (gpu->mmu_context) +		etnaviv_iommu_context_put(gpu->mmu_context); +	gpu->mmu_context = etnaviv_iommu_context_get(context); +  	/* set base addresses */  	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, context->global->memory_base);  	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, context->global->memory_base); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c index f8bf488e9d71..d664ae29ae20 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c @@ -172,6 +172,10 @@ static void etnaviv_iommuv2_restore_nonsec(struct etnaviv_gpu *gpu,  	if (gpu_read(gpu, VIVS_MMUv2_CONTROL) & VIVS_MMUv2_CONTROL_ENABLE)  		return; +	if (gpu->mmu_context) +		etnaviv_iommu_context_put(gpu->mmu_context); +	gpu->mmu_context = etnaviv_iommu_context_get(context); +  	prefetch = etnaviv_buffer_config_mmuv2(gpu,  				(u32)v2_context->mtlb_dma,  				(u32)context->global->bad_page_dma); @@ -192,6 +196,10 @@ static void etnaviv_iommuv2_restore_sec(struct etnaviv_gpu *gpu,  	if (gpu_read(gpu, VIVS_MMUv2_SEC_CONTROL) & VIVS_MMUv2_SEC_CONTROL_ENABLE)  		return; +	if (gpu->mmu_context) +		etnaviv_iommu_context_put(gpu->mmu_context); +	gpu->mmu_context = etnaviv_iommu_context_get(context); +  	gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_LOW,  		  lower_32_bits(context->global->v2.pta_dma));  	gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_HIGH, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index dab1b58006d8..9fb1a2aadbcb 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -199,6 +199,7 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context,  		 */  		list_for_each_entry_safe(m, n, &list, scan_node) {  			etnaviv_iommu_remove_mapping(context, m); +			etnaviv_iommu_context_put(m->context);  			m->context = NULL;  			list_del_init(&m->mmu_node);  			list_del_init(&m->scan_node); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h index d1d6902fd13b..e4a0b7d09c2e 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h @@ -105,9 +105,11 @@ void etnaviv_iommu_dump(struct etnaviv_iommu_context *ctx, void *buf);  struct etnaviv_iommu_context *  etnaviv_iommu_context_init(struct etnaviv_iommu_global *global,  			   struct etnaviv_cmdbuf_suballoc *suballoc); -static inline void etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx) +static inline struct etnaviv_iommu_context * +etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx)  {  	kref_get(&ctx->refcount); +	return ctx;  }  void etnaviv_iommu_context_put(struct etnaviv_iommu_context *ctx);  void etnaviv_iommu_restore(struct etnaviv_gpu *gpu, diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 9870c4e6af36..b5001db7a95c 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -793,7 +793,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev;  	struct decon_context *ctx; -	struct resource *res;  	int ret;  	int i; @@ -818,8 +817,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev)  		ctx->clks[i] = clk;  	} -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	ctx->addr = devm_ioremap_resource(dev, res); +	ctx->addr = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(ctx->addr))  		return PTR_ERR(ctx->addr); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index e39fac889edc..8d137857818c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1738,7 +1738,6 @@ static const struct component_ops exynos_dsi_component_ops = {  static int exynos_dsi_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; -	struct resource *res;  	struct exynos_dsi *dsi;  	int ret, i; @@ -1789,8 +1788,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)  		}  	} -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	dsi->reg_base = devm_ioremap_resource(dev, res); +	dsi->reg_base = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(dsi->reg_base))  		return PTR_ERR(dsi->reg_base); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index a3c718148c45..ecfd82d0afb7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -85,7 +85,6 @@ struct fimc_scaler {  /*   * A structure of fimc context.   * - * @regs_res: register resources.   * @regs: memory mapped io registers.   * @lock: locking of operations.   * @clocks: fimc clocks. @@ -103,7 +102,6 @@ struct fimc_context {  	struct exynos_drm_ipp_formats	*formats;  	unsigned int			num_formats; -	struct resource	*regs_res;  	void __iomem	*regs;  	spinlock_t	lock;  	struct clk	*clocks[FIMC_CLKS_MAX]; @@ -1327,8 +1325,7 @@ static int fimc_probe(struct platform_device *pdev)  	ctx->num_formats = num_formats;  	/* resource memory */ -	ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); +	ctx->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(ctx->regs))  		return PTR_ERR(ctx->regs); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 700ca4fa6665..c735e53939d8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1202,9 +1202,7 @@ static int fimd_probe(struct platform_device *pdev)  		return PTR_ERR(ctx->lcd_clk);  	} -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - -	ctx->regs = devm_ioremap_resource(dev, res); +	ctx->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(ctx->regs))  		return PTR_ERR(ctx->regs); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index b00230626c6a..471fd6c8135f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1449,7 +1449,6 @@ static const struct component_ops g2d_component_ops = {  static int g2d_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; -	struct resource *res;  	struct g2d_data *g2d;  	int ret; @@ -1491,9 +1490,7 @@ static int g2d_probe(struct platform_device *pdev)  	clear_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);  	clear_bit(G2D_BIT_ENGINE_BUSY, &g2d->flags); -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - -	g2d->regs = devm_ioremap_resource(dev, res); +	g2d->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(g2d->regs)) {  		ret = PTR_ERR(g2d->regs);  		goto err_put_clk; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 90d7bf906885..166a80262896 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -86,7 +86,6 @@ struct gsc_scaler {  /*   * A structure of gsc context.   * - * @regs_res: register resources.   * @regs: memory mapped io registers.   * @gsc_clk: gsc gate clock.   * @sc: scaler infomations. @@ -103,7 +102,6 @@ struct gsc_context {  	struct exynos_drm_ipp_formats	*formats;  	unsigned int			num_formats; -	struct resource	*regs_res;  	void __iomem	*regs;  	const char	**clk_names;  	struct clk	*clocks[GSC_MAX_CLOCKS]; @@ -1272,9 +1270,7 @@ static int gsc_probe(struct platform_device *pdev)  		}  	} -	/* resource memory */ -	ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); +	ctx->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(ctx->regs))  		return PTR_ERR(ctx->regs); diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index ee61be4cf152..dec7df35baa9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -278,7 +278,6 @@ static const struct component_ops rotator_component_ops = {  static int rotator_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; -	struct resource	*regs_res;  	struct rot_context *rot;  	const struct rot_variant *variant;  	int irq; @@ -292,8 +291,7 @@ static int rotator_probe(struct platform_device *pdev)  	rot->formats = variant->formats;  	rot->num_formats = variant->num_formats;  	rot->dev = dev; -	regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	rot->regs = devm_ioremap_resource(dev, regs_res); +	rot->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(rot->regs))  		return PTR_ERR(rot->regs); diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c index f9ae5b038d59..3a7851b7dc66 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c +++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c @@ -485,7 +485,6 @@ static const struct component_ops scaler_component_ops = {  static int scaler_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; -	struct resource	*regs_res;  	struct scaler_context *scaler;  	int irq;  	int ret, i; @@ -498,8 +497,7 @@ static int scaler_probe(struct platform_device *pdev)  		(struct scaler_data *)of_device_get_match_data(dev);  	scaler->dev = dev; -	regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	scaler->regs = devm_ioremap_resource(dev, regs_res); +	scaler->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(scaler->regs))  		return PTR_ERR(scaler->regs); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index c769dec576de..7655142a4651 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1957,7 +1957,6 @@ static int hdmi_probe(struct platform_device *pdev)  	struct hdmi_audio_infoframe *audio_infoframe;  	struct device *dev = &pdev->dev;  	struct hdmi_context *hdata; -	struct resource *res;  	int ret;  	hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); @@ -1979,8 +1978,7 @@ static int hdmi_probe(struct platform_device *pdev)  		return ret;  	} -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	hdata->regs = devm_ioremap_resource(dev, res); +	hdata->regs = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(hdata->regs)) {  		ret = PTR_ERR(hdata->regs);  		return ret; diff --git a/drivers/gpu/drm/hyperv/hyperv_drm.h b/drivers/gpu/drm/hyperv/hyperv_drm.h index 886add4f9cd0..d2d8582b36df 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm.h +++ b/drivers/gpu/drm/hyperv/hyperv_drm.h @@ -46,6 +46,7 @@ int hyperv_mode_config_init(struct hyperv_drm_device *hv);  int hyperv_update_vram_location(struct hv_device *hdev, phys_addr_t vram_pp);  int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp,  			    u32 w, u32 h, u32 pitch); +int hyperv_hide_hw_ptr(struct hv_device *hdev);  int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect);  int hyperv_connect_vsp(struct hv_device *hdev); diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index 6dd4717d3e1e..8c97a20dfe23 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -101,6 +101,7 @@ static void hyperv_pipe_enable(struct drm_simple_display_pipe *pipe,  	struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev);  	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); +	hyperv_hide_hw_ptr(hv->hdev);  	hyperv_update_situation(hv->hdev, 1,  hv->screen_depth,  				crtc_state->mode.hdisplay,  				crtc_state->mode.vdisplay, diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c index 6d4bdccfbd1a..c0155c6271bf 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -299,6 +299,55 @@ int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp,  	return 0;  } +/* + * Hyper-V supports a hardware cursor feature. It's not used by Linux VM, + * but the Hyper-V host still draws a point as an extra mouse pointer, + * which is unwanted, especially when Xorg is running. + * + * The hyperv_fb driver uses synthvid_send_ptr() to hide the unwanted + * pointer, by setting msg.ptr_pos.is_visible = 1 and setting the + * msg.ptr_shape.data. Note: setting msg.ptr_pos.is_visible to 0 doesn't + * work in tests. + * + * Copy synthvid_send_ptr() to hyperv_drm and rename it to + * hyperv_hide_hw_ptr(). Note: hyperv_hide_hw_ptr() is also called in the + * handler of the SYNTHVID_FEATURE_CHANGE event, otherwise the host still + * draws an extra unwanted mouse pointer after the VM Connection window is + * closed and reopened. + */ +int hyperv_hide_hw_ptr(struct hv_device *hdev) +{ +	struct synthvid_msg msg; + +	memset(&msg, 0, sizeof(struct synthvid_msg)); +	msg.vid_hdr.type = SYNTHVID_POINTER_POSITION; +	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + +		sizeof(struct synthvid_pointer_position); +	msg.ptr_pos.is_visible = 1; +	msg.ptr_pos.video_output = 0; +	msg.ptr_pos.image_x = 0; +	msg.ptr_pos.image_y = 0; +	hyperv_sendpacket(hdev, &msg); + +	memset(&msg, 0, sizeof(struct synthvid_msg)); +	msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE; +	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + +		sizeof(struct synthvid_pointer_shape); +	msg.ptr_shape.part_idx = SYNTHVID_CURSOR_COMPLETE; +	msg.ptr_shape.is_argb = 1; +	msg.ptr_shape.width = 1; +	msg.ptr_shape.height = 1; +	msg.ptr_shape.hot_x = 0; +	msg.ptr_shape.hot_y = 0; +	msg.ptr_shape.data[0] = 0; +	msg.ptr_shape.data[1] = 1; +	msg.ptr_shape.data[2] = 1; +	msg.ptr_shape.data[3] = 1; +	hyperv_sendpacket(hdev, &msg); + +	return 0; +} +  int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect)  {  	struct hyperv_drm_device *hv = hv_get_drvdata(hdev); @@ -392,8 +441,11 @@ static void hyperv_receive_sub(struct hv_device *hdev)  		return;  	} -	if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) +	if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {  		hv->dirt_needed = msg->feature_chg.is_dirt_needed; +		if (hv->dirt_needed) +			hyperv_hide_hw_ptr(hv->hdev); +	}  }  static void hyperv_receive(void *ctx) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 642a5b5a1b81..335ba9f43d8f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -19,7 +19,6 @@ subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers)  subdir-ccflags-y += $(call cc-disable-warning, unused-but-set-variable)  # clang warnings  subdir-ccflags-y += $(call cc-disable-warning, sign-compare) -subdir-ccflags-y += $(call cc-disable-warning, sometimes-uninitialized)  subdir-ccflags-y += $(call cc-disable-warning, initializer-overrides)  subdir-ccflags-y += $(call cc-disable-warning, frame-address)  subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 43ec7fcd3f5d..a3eae3f3eadc 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1577,8 +1577,14 @@ static void gen11_dsi_sync_state(struct intel_encoder *encoder,  				 const struct intel_crtc_state *crtc_state)  {  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); -	enum pipe pipe = intel_crtc->pipe; +	struct intel_crtc *intel_crtc; +	enum pipe pipe; + +	if (!crtc_state) +		return; + +	intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); +	pipe = intel_crtc->pipe;  	/* wa verify 1409054076:icl,jsl,ehl */  	if (DISPLAY_VER(dev_priv) == 11 && pipe == PIPE_B && diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c index 7cfe91fc05f2..68abeaf2d7d4 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.c +++ b/drivers/gpu/drm/i915/display/intel_acpi.c @@ -186,13 +186,16 @@ void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915)  {  	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);  	acpi_handle dhandle; +	union acpi_object *obj;  	dhandle = ACPI_HANDLE(&pdev->dev);  	if (!dhandle)  		return; -	acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID, -			  INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL); +	obj = acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID, +				INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL); +	if (obj) +		ACPI_FREE(obj);  }  /* diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 532237588511..4e0f96bf6158 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -1308,8 +1308,9 @@ static void i915_audio_component_init(struct drm_i915_private *dev_priv)  		else  			aud_freq = aud_freq_init; -		/* use BIOS provided value for TGL unless it is a known bad value */ -		if (IS_TIGERLAKE(dev_priv) && aud_freq_init != AUD_FREQ_TGL_BROKEN) +		/* use BIOS provided value for TGL and RKL unless it is a known bad value */ +		if ((IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) && +		    aud_freq_init != AUD_FREQ_TGL_BROKEN)  			aud_freq = aud_freq_init;  		drm_dbg_kms(&dev_priv->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n", diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index e86e6ed2d3bf..fd71346aac7b 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -451,13 +451,23 @@ parse_lfp_backlight(struct drm_i915_private *i915,  	}  	i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; -	if (bdb->version >= 191 && -	    get_blocksize(backlight_data) >= sizeof(*backlight_data)) { -		const struct lfp_backlight_control_method *method; +	if (bdb->version >= 191) { +		size_t exp_size; -		method = &backlight_data->backlight_control[panel_type]; -		i915->vbt.backlight.type = method->type; -		i915->vbt.backlight.controller = method->controller; +		if (bdb->version >= 236) +			exp_size = sizeof(struct bdb_lfp_backlight_data); +		else if (bdb->version >= 234) +			exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_234; +		else +			exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_191; + +		if (get_blocksize(backlight_data) >= exp_size) { +			const struct lfp_backlight_control_method *method; + +			method = &backlight_data->backlight_control[panel_type]; +			i915->vbt.backlight.type = method->type; +			i915->vbt.backlight.controller = method->controller; +		}  	}  	i915->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index e91e0e0191fb..4b94256d7319 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -222,31 +222,42 @@ static int icl_sagv_max_dclk(const struct intel_qgv_info *qi)  struct intel_sa_info {  	u16 displayrtids; -	u8 deburst, deprogbwlimit; +	u8 deburst, deprogbwlimit, derating;  };  static const struct intel_sa_info icl_sa_info = {  	.deburst = 8,  	.deprogbwlimit = 25, /* GB/s */  	.displayrtids = 128, +	.derating = 10,  };  static const struct intel_sa_info tgl_sa_info = {  	.deburst = 16,  	.deprogbwlimit = 34, /* GB/s */  	.displayrtids = 256, +	.derating = 10,  };  static const struct intel_sa_info rkl_sa_info = {  	.deburst = 16,  	.deprogbwlimit = 20, /* GB/s */  	.displayrtids = 128, +	.derating = 10,  };  static const struct intel_sa_info adls_sa_info = {  	.deburst = 16,  	.deprogbwlimit = 38, /* GB/s */  	.displayrtids = 256, +	.derating = 10, +}; + +static const struct intel_sa_info adlp_sa_info = { +	.deburst = 16, +	.deprogbwlimit = 38, /* GB/s */ +	.displayrtids = 256, +	.derating = 20,  };  static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel_sa_info *sa) @@ -302,7 +313,7 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel  			bw = icl_calc_bw(sp->dclk, clpchgroup * 32 * num_channels, ct);  			bi->deratedbw[j] = min(maxdebw, -					       bw * 9 / 10); /* 90% */ +					       bw * (100 - sa->derating) / 100);  			drm_dbg_kms(&dev_priv->drm,  				    "BW%d / QGV %d: num_planes=%d deratedbw=%u\n", @@ -400,7 +411,9 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv)  	if (IS_DG2(dev_priv))  		dg2_get_bw_info(dev_priv); -	else if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) +	else if (IS_ALDERLAKE_P(dev_priv)) +		icl_get_bw_info(dev_priv, &adlp_sa_info); +	else if (IS_ALDERLAKE_S(dev_priv))  		icl_get_bw_info(dev_priv, &adls_sa_info);  	else if (IS_ROCKETLAKE(dev_priv))  		icl_get_bw_info(dev_priv, &rkl_sa_info); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 9903a78df896..bd184325d0c7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3807,7 +3807,13 @@ void hsw_ddi_get_config(struct intel_encoder *encoder,  static void intel_ddi_sync_state(struct intel_encoder *encoder,  				 const struct intel_crtc_state *crtc_state)  { -	if (intel_crtc_has_dp_encoder(crtc_state)) +	struct drm_i915_private *i915 = to_i915(encoder->base.dev); +	enum phy phy = intel_port_to_phy(i915, encoder->port); + +	if (intel_phy_is_tc(i915, phy)) +		intel_tc_port_sanitize(enc_to_dig_port(encoder)); + +	if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))  		intel_dp_sync_state(encoder, crtc_state);  } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 134a6acbd8fb..17f44ffea586 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -13082,18 +13082,16 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)  	readout_plane_state(dev_priv);  	for_each_intel_encoder(dev, encoder) { +		struct intel_crtc_state *crtc_state = NULL; +  		pipe = 0;  		if (encoder->get_hw_state(encoder, &pipe)) { -			struct intel_crtc_state *crtc_state; -  			crtc = intel_get_crtc_for_pipe(dev_priv, pipe);  			crtc_state = to_intel_crtc_state(crtc->base.state);  			encoder->base.crtc = &crtc->base;  			intel_encoder_get_config(encoder, crtc_state); -			if (encoder->sync_state) -				encoder->sync_state(encoder, crtc_state);  			/* read out to slave crtc as well for bigjoiner */  			if (crtc_state->bigjoiner) { @@ -13108,6 +13106,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)  			encoder->base.crtc = NULL;  		} +		if (encoder->sync_state) +			encoder->sync_state(encoder, crtc_state); +  		drm_dbg_kms(&dev_priv->drm,  			    "[ENCODER:%d:%s] hw state readout: %s, pipe %c\n",  			    encoder->base.base.id, encoder->base.name, @@ -13390,17 +13391,6 @@ intel_modeset_setup_hw_state(struct drm_device *dev,  	intel_modeset_readout_hw_state(dev);  	/* HW state is read out, now we need to sanitize this mess. */ - -	/* Sanitize the TypeC port mode upfront, encoders depend on this */ -	for_each_intel_encoder(dev, encoder) { -		enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - -		/* We need to sanitize only the MST primary port. */ -		if (encoder->type != INTEL_OUTPUT_DP_MST && -		    intel_phy_is_tc(dev_priv, phy)) -			intel_tc_port_sanitize(enc_to_dig_port(encoder)); -	} -  	get_encoder_power_domains(dev_priv);  	if (HAS_PCH_IBX(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 3c3c6cb5c0df..b3c8e1c450ef 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -805,11 +805,14 @@ void intel_dmc_ucode_resume(struct drm_i915_private *dev_priv)   */  void intel_dmc_ucode_fini(struct drm_i915_private *dev_priv)  { +	int id; +  	if (!HAS_DMC(dev_priv))  		return;  	intel_dmc_ucode_suspend(dev_priv);  	drm_WARN_ON(&dev_priv->drm, dev_priv->dmc.wakeref); -	kfree(dev_priv->dmc.dmc_info[DMC_FW_MAIN].payload); +	for (id = 0; id < DMC_FW_MAX; id++) +		kfree(dev_priv->dmc.dmc_info[id].payload);  } diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 04175f359fd6..5cf152be4487 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1916,6 +1916,9 @@ void intel_dp_sync_state(struct intel_encoder *encoder,  {  	struct intel_dp *intel_dp = enc_to_intel_dp(encoder); +	if (!crtc_state) +		return; +  	/*  	 * Don't clobber DPCD if it's been already read out during output  	 * setup (eDP) or detect. @@ -2445,11 +2448,14 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)  	 */  	if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,  			     intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) == -			     sizeof(intel_dp->edp_dpcd)) +			     sizeof(intel_dp->edp_dpcd)) {  		drm_dbg_kms(&dev_priv->drm, "eDP DPCD: %*ph\n",  			    (int)sizeof(intel_dp->edp_dpcd),  			    intel_dp->edp_dpcd); +		intel_dp->use_max_params = intel_dp->edp_dpcd[0] < DP_EDP_14; +	} +  	/*  	 * This has to be called after intel_dp->edp_dpcd is filled, PSR checks  	 * for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1] diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 053a3c2f7267..508a514c5e37 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -848,7 +848,7 @@ intel_dp_link_train_all_phys(struct intel_dp *intel_dp,  	}  	if (ret) -		intel_dp_link_train_phy(intel_dp, crtc_state, DP_PHY_DPRX); +		ret = intel_dp_link_train_phy(intel_dp, crtc_state, DP_PHY_DPRX);  	if (intel_dp->set_idle_link_train)  		intel_dp->set_idle_link_train(intel_dp, crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index 330077c2e588..a2108a8f544d 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -814,6 +814,11 @@ struct lfp_brightness_level {  	u16 reserved;  } __packed; +#define EXP_BDB_LFP_BL_DATA_SIZE_REV_191 \ +	offsetof(struct bdb_lfp_backlight_data, brightness_level) +#define EXP_BDB_LFP_BL_DATA_SIZE_REV_234 \ +	offsetof(struct bdb_lfp_backlight_data, brightness_precision_bits) +  struct bdb_lfp_backlight_data {  	u8 entry_size;  	struct lfp_backlight_data_entry data[16]; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index cff72679ad7c..166bb46408a9 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -937,6 +937,10 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,  	unsigned int n;  	e = alloc_engines(num_engines); +	if (!e) +		return ERR_PTR(-ENOMEM); +	e->num_engines = num_engines; +  	for (n = 0; n < num_engines; n++) {  		struct intel_context *ce;  		int ret; @@ -970,7 +974,6 @@ static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,  			goto free_engines;  		}  	} -	e->num_engines = num_engines;  	return e; @@ -986,6 +989,9 @@ void i915_gem_context_release(struct kref *ref)  	trace_i915_context_free(ctx);  	GEM_BUG_ON(!i915_gem_context_is_closed(ctx)); +	if (ctx->syncobj) +		drm_syncobj_put(ctx->syncobj); +  	mutex_destroy(&ctx->engines_mutex);  	mutex_destroy(&ctx->lut_mutex); @@ -1205,9 +1211,6 @@ static void context_close(struct i915_gem_context *ctx)  	if (vm)  		i915_vm_close(vm); -	if (ctx->syncobj) -		drm_syncobj_put(ctx->syncobj); -  	ctx->file_priv = ERR_PTR(-EBADF);  	/* diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c index e382b7f2353b..5ab136ffdeb2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c @@ -118,7 +118,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,  	intel_wakeref_t wakeref = 0;  	unsigned long count = 0;  	unsigned long scanned = 0; -	int err; +	int err = 0;  	/* CHV + VTD workaround use stop_machine(); need to trylock vm->mutex */  	bool trylock_vm = !ww && intel_vm_no_concurrent_access_wa(i915); @@ -242,12 +242,15 @@ skip:  		list_splice_tail(&still_in_list, phase->list);  		spin_unlock_irqrestore(&i915->mm.obj_lock, flags);  		if (err) -			return err; +			break;  	}  	if (shrink & I915_SHRINK_BOUND)  		intel_runtime_pm_put(&i915->runtime_pm, wakeref); +	if (err) +		return err; +  	if (nr_scanned)  		*nr_scanned += scanned;  	return count; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 35eedc14f522..6ea13159bffc 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -356,11 +356,8 @@ static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo)  {  	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); -	if (likely(obj)) { -		/* This releases all gem object bindings to the backend. */ +	if (likely(obj))  		i915_ttm_free_cached_io_st(obj); -		__i915_gem_free_object(obj); -	}  }  static struct intel_memory_region * @@ -875,8 +872,12 @@ void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)  {  	struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); +	/* This releases all gem object bindings to the backend. */ +	__i915_gem_free_object(obj); +  	i915_gem_object_release_memory_region(obj);  	mutex_destroy(&obj->ttm.get_io_page.lock); +  	if (obj->ttm.created)  		call_rcu(&obj->rcu, __i915_gem_free_object_rcu);  } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index ffae7df5e4d7..4a6bb64c3a35 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -59,13 +59,13 @@ static int igt_dmabuf_import_self(void *arg)  		err = PTR_ERR(import);  		goto out_dmabuf;  	} +	import_obj = to_intel_bo(import);  	if (import != &obj->base) {  		pr_err("i915_gem_prime_import created a new object!\n");  		err = -EINVAL;  		goto out_import;  	} -	import_obj = to_intel_bo(import);  	i915_gem_object_lock(import_obj, NULL);  	err = __i915_gem_object_get_pages(import_obj); @@ -128,6 +128,8 @@ static int igt_dmabuf_import_same_driver_lmem(void *arg)  		pr_err("i915_gem_prime_import failed with the wrong err=%ld\n",  		       PTR_ERR(import));  		err = PTR_ERR(import); +	} else { +		err = 0;  	}  	dma_buf_put(dmabuf); @@ -176,6 +178,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,  		err = PTR_ERR(import);  		goto out_dmabuf;  	} +	import_obj = to_intel_bo(import);  	if (import == &obj->base) {  		pr_err("i915_gem_prime_import reused gem object!\n"); @@ -183,8 +186,6 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,  		goto out_import;  	} -	import_obj = to_intel_bo(import); -  	i915_gem_object_lock(import_obj, NULL);  	err = __i915_gem_object_get_pages(import_obj);  	if (err) { diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index b20f5621f62b..a2c34e5a1c54 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -581,6 +581,20 @@ static enum i915_mmap_type default_mapping(struct drm_i915_private *i915)  	return I915_MMAP_TYPE_GTT;  } +static struct drm_i915_gem_object * +create_sys_or_internal(struct drm_i915_private *i915, +		       unsigned long size) +{ +	if (HAS_LMEM(i915)) { +		struct intel_memory_region *sys_region = +			i915->mm.regions[INTEL_REGION_SMEM]; + +		return __i915_gem_object_create_user(i915, size, &sys_region, 1); +	} + +	return i915_gem_object_create_internal(i915, size); +} +  static bool assert_mmap_offset(struct drm_i915_private *i915,  			       unsigned long size,  			       int expected) @@ -589,7 +603,7 @@ static bool assert_mmap_offset(struct drm_i915_private *i915,  	u64 offset;  	int ret; -	obj = i915_gem_object_create_internal(i915, size); +	obj = create_sys_or_internal(i915, size);  	if (IS_ERR(obj))  		return expected && expected == PTR_ERR(obj); @@ -633,6 +647,7 @@ static int igt_mmap_offset_exhaustion(void *arg)  	struct drm_mm_node *hole, *next;  	int loop, err = 0;  	u64 offset; +	int enospc = HAS_LMEM(i915) ? -ENXIO : -ENOSPC;  	/* Disable background reaper */  	disable_retire_worker(i915); @@ -683,14 +698,14 @@ static int igt_mmap_offset_exhaustion(void *arg)  	}  	/* Too large */ -	if (!assert_mmap_offset(i915, 2 * PAGE_SIZE, -ENOSPC)) { +	if (!assert_mmap_offset(i915, 2 * PAGE_SIZE, enospc)) {  		pr_err("Unexpectedly succeeded in inserting too large object into single page hole\n");  		err = -EINVAL;  		goto out;  	}  	/* Fill the hole, further allocation attempts should then fail */ -	obj = i915_gem_object_create_internal(i915, PAGE_SIZE); +	obj = create_sys_or_internal(i915, PAGE_SIZE);  	if (IS_ERR(obj)) {  		err = PTR_ERR(obj);  		pr_err("Unable to create object for reclaimed hole\n"); @@ -703,7 +718,7 @@ static int igt_mmap_offset_exhaustion(void *arg)  		goto err_obj;  	} -	if (!assert_mmap_offset(i915, PAGE_SIZE, -ENOSPC)) { +	if (!assert_mmap_offset(i915, PAGE_SIZE, enospc)) {  		pr_err("Unexpectedly succeeded in inserting object into no holes!\n");  		err = -EINVAL;  		goto err_obj; @@ -839,10 +854,9 @@ static int wc_check(struct drm_i915_gem_object *obj)  static bool can_mmap(struct drm_i915_gem_object *obj, enum i915_mmap_type type)  { -	struct drm_i915_private *i915 = to_i915(obj->base.dev);  	bool no_map; -	if (HAS_LMEM(i915)) +	if (obj->ops->mmap_offset)  		return type == I915_MMAP_TYPE_FIXED;  	else if (type == I915_MMAP_TYPE_FIXED)  		return false; diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index 745e84c72c90..17ca4dc4d0cb 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -362,8 +362,9 @@ static int __intel_context_active(struct i915_active *active)  	return 0;  } -static int sw_fence_dummy_notify(struct i915_sw_fence *sf, -				 enum i915_sw_fence_notify state) +static int __i915_sw_fence_call +sw_fence_dummy_notify(struct i915_sw_fence *sf, +		      enum i915_sw_fence_notify state)  {  	return NOTIFY_DONE;  } @@ -420,6 +421,7 @@ void intel_context_fini(struct intel_context *ce)  	mutex_destroy(&ce->pin_mutex);  	i915_active_fini(&ce->active); +	i915_sw_fence_fini(&ce->guc_blocked);  }  void i915_context_module_exit(void) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index d812b27835f8..0a03fbed9f9b 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -882,8 +882,6 @@ void intel_rps_park(struct intel_rps *rps)  	if (!intel_rps_is_enabled(rps))  		return; -	GEM_BUG_ON(atomic_read(&rps->num_waiters)); -  	if (!intel_rps_clear_active(rps))  		return; @@ -1973,8 +1971,14 @@ u32 intel_rps_read_actual_frequency(struct intel_rps *rps)  u32 intel_rps_read_punit_req(struct intel_rps *rps)  {  	struct intel_uncore *uncore = rps_to_uncore(rps); +	struct intel_runtime_pm *rpm = rps_to_uncore(rps)->rpm; +	intel_wakeref_t wakeref; +	u32 freq = 0; -	return intel_uncore_read(uncore, GEN6_RPNSWREQ); +	with_intel_runtime_pm_if_in_use(rpm, wakeref) +		freq = intel_uncore_read(uncore, GEN6_RPNSWREQ); + +	return freq;  }  static u32 intel_rps_get_req(u32 pureq) diff --git a/drivers/gpu/drm/i915/gt/intel_timeline.c b/drivers/gpu/drm/i915/gt/intel_timeline.c index 1257f4f11e66..438bbc7b8147 100644 --- a/drivers/gpu/drm/i915/gt/intel_timeline.c +++ b/drivers/gpu/drm/i915/gt/intel_timeline.c @@ -64,7 +64,7 @@ intel_timeline_pin_map(struct intel_timeline *timeline)  	timeline->hwsp_map = vaddr;  	timeline->hwsp_seqno = memset(vaddr + ofs, 0, TIMELINE_SEQNO_BYTES); -	clflush(vaddr + ofs); +	drm_clflush_virt_range(vaddr + ofs, TIMELINE_SEQNO_BYTES);  	return 0;  } @@ -225,7 +225,7 @@ void intel_timeline_reset_seqno(const struct intel_timeline *tl)  	memset(hwsp_seqno + 1, 0, TIMELINE_SEQNO_BYTES - sizeof(*hwsp_seqno));  	WRITE_ONCE(*hwsp_seqno, tl->seqno); -	clflush(hwsp_seqno); +	drm_clflush_virt_range(hwsp_seqno, TIMELINE_SEQNO_BYTES);  }  void intel_timeline_enter(struct intel_timeline *tl) diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h index 99e1fad5ca20..c9086a600bce 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h @@ -102,11 +102,11 @@ static_assert(sizeof(struct guc_ct_buffer_desc) == 64);   *  |   +-------+--------------------------------------------------------------+   *  |   |   7:0 | NUM_DWORDS = length (in dwords) of the embedded HXG message  |   *  +---+-------+--------------------------------------------------------------+ - *  | 1 |  31:0 |  +--------------------------------------------------------+  | - *  +---+-------+  |                                                        |  | - *  |...|       |  |  Embedded `HXG Message`_                               |  | - *  +---+-------+  |                                                        |  | - *  | n |  31:0 |  +--------------------------------------------------------+  | + *  | 1 |  31:0 |                                                              | + *  +---+-------+                                                              | + *  |...|       | [Embedded `HXG Message`_]                                    | + *  +---+-------+                                                              | + *  | n |  31:0 |                                                              |   *  +---+-------+--------------------------------------------------------------+   */ diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h index bbf1ddb77434..9baa3cb07d13 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h @@ -38,11 +38,11 @@   *  +---+-------+--------------------------------------------------------------+   *  |   | Bits  | Description                                                  |   *  +===+=======+==============================================================+ - *  | 0 |  31:0 |  +--------------------------------------------------------+  | - *  +---+-------+  |                                                        |  | - *  |...|       |  |  Embedded `HXG Message`_                               |  | - *  +---+-------+  |                                                        |  | - *  | n |  31:0 |  +--------------------------------------------------------+  | + *  | 0 |  31:0 |                                                              | + *  +---+-------+                                                              | + *  |...|       | [Embedded `HXG Message`_]                                    | + *  +---+-------+                                                              | + *  | n |  31:0 |                                                              |   *  +---+-------+--------------------------------------------------------------+   */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index b104fb7607eb..86c318516e14 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -172,11 +172,6 @@ void intel_uc_driver_remove(struct intel_uc *uc)  	__uc_free_load_err_log(uc);  } -static inline bool guc_communication_enabled(struct intel_guc *guc) -{ -	return intel_guc_ct_enabled(&guc->ct); -} -  /*   * Events triggered while CT buffers are disabled are logged in the SCRATCH_15   * register using the same bits used in the CT message payload. Since our @@ -210,7 +205,7 @@ static void guc_get_mmio_msg(struct intel_guc *guc)  static void guc_handle_mmio_msg(struct intel_guc *guc)  {  	/* we need communication to be enabled to reply to GuC */ -	GEM_BUG_ON(!guc_communication_enabled(guc)); +	GEM_BUG_ON(!intel_guc_ct_enabled(&guc->ct));  	spin_lock_irq(&guc->irq_lock);  	if (guc->mmio_msg) { @@ -226,7 +221,7 @@ static int guc_enable_communication(struct intel_guc *guc)  	struct drm_i915_private *i915 = gt->i915;  	int ret; -	GEM_BUG_ON(guc_communication_enabled(guc)); +	GEM_BUG_ON(intel_guc_ct_enabled(&guc->ct));  	ret = i915_inject_probe_error(i915, -ENXIO);  	if (ret) @@ -662,7 +657,7 @@ static int __uc_resume(struct intel_uc *uc, bool enable_communication)  		return 0;  	/* Make sure we enable communication if and only if it's disabled */ -	GEM_BUG_ON(enable_communication == guc_communication_enabled(guc)); +	GEM_BUG_ON(enable_communication == intel_guc_ct_enabled(&guc->ct));  	if (enable_communication)  		guc_enable_communication(guc); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index b56a8e37a3cd..1bb1be5c48c8 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -576,7 +576,7 @@ retry:  			/* No one is going to touch shadow bb from now on. */  			i915_gem_object_flush_map(bb->obj); -			i915_gem_object_unlock(bb->obj); +			i915_gem_ww_ctx_fini(&ww);  		}  	}  	return 0; @@ -630,7 +630,7 @@ retry:  		return ret;  	} -	i915_gem_object_unlock(wa_ctx->indirect_ctx.obj); +	i915_gem_ww_ctx_fini(&ww);  	/* FIXME: we are not tracking our pinned VMA leaving it  	 * up to the core to fix up the stray pin_count upon diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 664970f2bc62..9023d4ecf3b3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8193,6 +8193,11 @@ enum {  #define  HSW_SPR_STRETCH_MAX_X1		REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 3)  #define  HSW_FBCQ_DIS			(1 << 22)  #define  BDW_DPRS_MASK_VBLANK_SRD	(1 << 0) +#define  SKL_PLANE1_STRETCH_MAX_MASK	REG_GENMASK(1, 0) +#define  SKL_PLANE1_STRETCH_MAX_X8	REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 0) +#define  SKL_PLANE1_STRETCH_MAX_X4	REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 1) +#define  SKL_PLANE1_STRETCH_MAX_X2	REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 2) +#define  SKL_PLANE1_STRETCH_MAX_X1	REG_FIELD_PREP(SKL_PLANE1_STRETCH_MAX_MASK, 3)  #define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)  #define _CHICKEN_TRANS_A	0x420c0 @@ -11043,12 +11048,6 @@ enum skl_power_gate {  #define  DC_STATE_DEBUG_MASK_CORES	(1 << 0)  #define  DC_STATE_DEBUG_MASK_MEMORY_UP	(1 << 1) -#define BXT_P_CR_MC_BIOS_REQ_0_0_0	_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7114) -#define  BXT_REQ_DATA_MASK			0x3F -#define  BXT_DRAM_CHANNEL_ACTIVE_SHIFT		12 -#define  BXT_DRAM_CHANNEL_ACTIVE_MASK		(0xF << 12) -#define  BXT_MEMORY_FREQ_MULTIPLIER_HZ		133333333 -  #define BXT_D_CR_DRP0_DUNIT8			0x1000  #define BXT_D_CR_DRP0_DUNIT9			0x1200  #define  BXT_D_CR_DRP0_DUNIT_START		8 @@ -11079,9 +11078,7 @@ enum skl_power_gate {  #define  BXT_DRAM_TYPE_LPDDR4			(0x2 << 22)  #define  BXT_DRAM_TYPE_DDR4			(0x4 << 22) -#define SKL_MEMORY_FREQ_MULTIPLIER_HZ		266666666  #define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU	_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5E04) -#define  SKL_REQ_DATA_MASK			(0xF << 0)  #define  DG1_GEAR_TYPE				REG_BIT(16)  #define SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5000) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index ce446716d092..79da5eca60af 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -829,8 +829,6 @@ static void __i915_request_ctor(void *arg)  	i915_sw_fence_init(&rq->submit, submit_notify);  	i915_sw_fence_init(&rq->semaphore, semaphore_notify); -	dma_fence_init(&rq->fence, &i915_fence_ops, &rq->lock, 0, 0); -  	rq->capture_list = NULL;  	init_llist_head(&rq->execute_cb); @@ -905,17 +903,12 @@ __i915_request_create(struct intel_context *ce, gfp_t gfp)  	rq->ring = ce->ring;  	rq->execution_mask = ce->engine->mask; -	kref_init(&rq->fence.refcount); -	rq->fence.flags = 0; -	rq->fence.error = 0; -	INIT_LIST_HEAD(&rq->fence.cb_list); -  	ret = intel_timeline_get_seqno(tl, rq, &seqno);  	if (ret)  		goto err_free; -	rq->fence.context = tl->fence_context; -	rq->fence.seqno = seqno; +	dma_fence_init(&rq->fence, &i915_fence_ops, &rq->lock, +		       tl->fence_context, seqno);  	RCU_INIT_POINTER(rq->timeline, tl);  	rq->hwsp_seqno = tl->hwsp_seqno; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 806ad688274b..63fec1c3c132 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -794,7 +794,6 @@ DECLARE_EVENT_CLASS(i915_request,  	    TP_STRUCT__entry(  			     __field(u32, dev)  			     __field(u64, ctx) -			     __field(u32, guc_id)  			     __field(u16, class)  			     __field(u16, instance)  			     __field(u32, seqno) @@ -805,16 +804,14 @@ DECLARE_EVENT_CLASS(i915_request,  			   __entry->dev = rq->engine->i915->drm.primary->index;  			   __entry->class = rq->engine->uabi_class;  			   __entry->instance = rq->engine->uabi_instance; -			   __entry->guc_id = rq->context->guc_id;  			   __entry->ctx = rq->fence.context;  			   __entry->seqno = rq->fence.seqno;  			   __entry->tail = rq->tail;  			   ), -	    TP_printk("dev=%u, engine=%u:%u, guc_id=%u, ctx=%llu, seqno=%u, tail=%u", +	    TP_printk("dev=%u, engine=%u:%u, ctx=%llu, seqno=%u, tail=%u",  		      __entry->dev, __entry->class, __entry->instance, -		      __entry->guc_id, __entry->ctx, __entry->seqno, -		      __entry->tail) +		      __entry->ctx, __entry->seqno, __entry->tail)  );  DEFINE_EVENT(i915_request, i915_request_add, diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index 5259edacde38..066a9118c374 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -30,6 +30,7 @@  #include <linux/sched.h>  #include <linux/types.h>  #include <linux/workqueue.h> +#include <linux/sched/clock.h>  struct drm_i915_private;  struct timer_list; diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index 91866520c173..7acce64b0941 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -244,7 +244,6 @@ static int  skl_get_dram_info(struct drm_i915_private *i915)  {  	struct dram_info *dram_info = &i915->dram_info; -	u32 mem_freq_khz, val;  	int ret;  	dram_info->type = skl_get_dram_type(i915); @@ -255,17 +254,6 @@ skl_get_dram_info(struct drm_i915_private *i915)  	if (ret)  		return ret; -	val = intel_uncore_read(&i915->uncore, -				SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU); -	mem_freq_khz = DIV_ROUND_UP((val & SKL_REQ_DATA_MASK) * -				    SKL_MEMORY_FREQ_MULTIPLIER_HZ, 1000); - -	if (dram_info->num_channels * mem_freq_khz == 0) { -		drm_info(&i915->drm, -			 "Couldn't get system memory bandwidth\n"); -		return -EINVAL; -	} -  	return 0;  } @@ -350,24 +338,10 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val)  static int bxt_get_dram_info(struct drm_i915_private *i915)  {  	struct dram_info *dram_info = &i915->dram_info; -	u32 dram_channels; -	u32 mem_freq_khz, val; -	u8 num_active_channels, valid_ranks = 0; +	u32 val; +	u8 valid_ranks = 0;  	int i; -	val = intel_uncore_read(&i915->uncore, BXT_P_CR_MC_BIOS_REQ_0_0_0); -	mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) * -				    BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000); - -	dram_channels = val & BXT_DRAM_CHANNEL_ACTIVE_MASK; -	num_active_channels = hweight32(dram_channels); - -	if (mem_freq_khz * num_active_channels == 0) { -		drm_info(&i915->drm, -			 "Couldn't get system memory bandwidth\n"); -		return -EINVAL; -	} -  	/*  	 * Now read each DUNIT8/9/10/11 to check the rank of each dimms.  	 */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 65bc3709f54c..a725792d5248 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -76,6 +76,8 @@ struct intel_wm_config {  static void gen9_init_clock_gating(struct drm_i915_private *dev_priv)  { +	enum pipe pipe; +  	if (HAS_LLC(dev_priv)) {  		/*  		 * WaCompressedResourceDisplayNewHashMode:skl,kbl @@ -89,6 +91,16 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv)  			   SKL_DE_COMPRESSED_HASH_MODE);  	} +	for_each_pipe(dev_priv, pipe) { +		/* +		 * "Plane N strech max must be programmed to 11b (x1) +		 *  when Async flips are enabled on that plane." +		 */ +		if (!IS_GEMINILAKE(dev_priv) && intel_vtd_active()) +			intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), +					 SKL_PLANE1_STRETCH_MAX_MASK, SKL_PLANE1_STRETCH_MAX_X1); +	} +  	/* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */  	intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1,  		   intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 44327bc629ca..06613ffeaaf8 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -66,7 +66,8 @@ static const struct drm_crtc_funcs kmb_crtc_funcs = {  	.disable_vblank = kmb_crtc_disable_vblank,  }; -static void kmb_crtc_set_mode(struct drm_crtc *crtc) +static void kmb_crtc_set_mode(struct drm_crtc *crtc, +			      struct drm_atomic_state *old_state)  {  	struct drm_device *dev = crtc->dev;  	struct drm_display_mode *m = &crtc->state->adjusted_mode; @@ -75,7 +76,7 @@ static void kmb_crtc_set_mode(struct drm_crtc *crtc)  	unsigned int val = 0;  	/* Initialize mipi */ -	kmb_dsi_mode_set(kmb->kmb_dsi, m, kmb->sys_clk_mhz); +	kmb_dsi_mode_set(kmb->kmb_dsi, m, kmb->sys_clk_mhz, old_state);  	drm_info(dev,  		 "vfp= %d vbp= %d vsync_len=%d hfp=%d hbp=%d hsync_len=%d\n",  		 m->crtc_vsync_start - m->crtc_vdisplay, @@ -138,7 +139,7 @@ static void kmb_crtc_atomic_enable(struct drm_crtc *crtc,  	struct kmb_drm_private *kmb = crtc_to_kmb_priv(crtc);  	clk_prepare_enable(kmb->kmb_clk.clk_lcd); -	kmb_crtc_set_mode(crtc); +	kmb_crtc_set_mode(crtc, state);  	drm_crtc_vblank_on(crtc);  } @@ -185,11 +186,45 @@ static void kmb_crtc_atomic_flush(struct drm_crtc *crtc,  	spin_unlock_irq(&crtc->dev->event_lock);  } +static enum drm_mode_status +		kmb_crtc_mode_valid(struct drm_crtc *crtc, +				    const struct drm_display_mode *mode) +{ +	int refresh; +	struct drm_device *dev = crtc->dev; +	int vfp = mode->vsync_start - mode->vdisplay; + +	if (mode->vdisplay < KMB_CRTC_MAX_HEIGHT) { +		drm_dbg(dev, "height = %d less than %d", +			mode->vdisplay, KMB_CRTC_MAX_HEIGHT); +		return MODE_BAD_VVALUE; +	} +	if (mode->hdisplay < KMB_CRTC_MAX_WIDTH) { +		drm_dbg(dev, "width = %d less than %d", +			mode->hdisplay, KMB_CRTC_MAX_WIDTH); +		return MODE_BAD_HVALUE; +	} +	refresh = drm_mode_vrefresh(mode); +	if (refresh < KMB_MIN_VREFRESH || refresh > KMB_MAX_VREFRESH) { +		drm_dbg(dev, "refresh = %d less than %d or greater than %d", +			refresh, KMB_MIN_VREFRESH, KMB_MAX_VREFRESH); +		return MODE_BAD; +	} + +	if (vfp < KMB_CRTC_MIN_VFP) { +		drm_dbg(dev, "vfp = %d less than %d", vfp, KMB_CRTC_MIN_VFP); +		return MODE_BAD; +	} + +	return MODE_OK; +} +  static const struct drm_crtc_helper_funcs kmb_crtc_helper_funcs = {  	.atomic_begin = kmb_crtc_atomic_begin,  	.atomic_enable = kmb_crtc_atomic_enable,  	.atomic_disable = kmb_crtc_atomic_disable,  	.atomic_flush = kmb_crtc_atomic_flush, +	.mode_valid = kmb_crtc_mode_valid,  };  int kmb_setup_crtc(struct drm_device *drm) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 1c2f4799f421..961ac6fb5fcf 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -172,10 +172,10 @@ static int kmb_setup_mode_config(struct drm_device *drm)  	ret = drmm_mode_config_init(drm);  	if (ret)  		return ret; -	drm->mode_config.min_width = KMB_MIN_WIDTH; -	drm->mode_config.min_height = KMB_MIN_HEIGHT; -	drm->mode_config.max_width = KMB_MAX_WIDTH; -	drm->mode_config.max_height = KMB_MAX_HEIGHT; +	drm->mode_config.min_width = KMB_FB_MIN_WIDTH; +	drm->mode_config.min_height = KMB_FB_MIN_HEIGHT; +	drm->mode_config.max_width = KMB_FB_MAX_WIDTH; +	drm->mode_config.max_height = KMB_FB_MAX_HEIGHT;  	drm->mode_config.funcs = &kmb_mode_config_funcs;  	ret = kmb_setup_crtc(drm); @@ -380,7 +380,7 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev)  		if (val & LAYER3_DMA_FIFO_UNDERFLOW)  			drm_dbg(&kmb->drm,  				"LAYER3:GL1 DMA UNDERFLOW val = 0x%lx", val); -		if (val & LAYER3_DMA_FIFO_UNDERFLOW) +		if (val & LAYER3_DMA_FIFO_OVERFLOW)  			drm_dbg(&kmb->drm,  				"LAYER3:GL1 DMA OVERFLOW val = 0x%lx", val);  	} diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index ebbaa5f422d5..bf085e95b28f 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -20,6 +20,18 @@  #define DRIVER_MAJOR			1  #define DRIVER_MINOR			1 +/* Platform definitions */ +#define KMB_CRTC_MIN_VFP		4 +#define KMB_CRTC_MAX_WIDTH		1920 /* max width in pixels */ +#define KMB_CRTC_MAX_HEIGHT		1080 /* max height in pixels */ +#define KMB_CRTC_MIN_WIDTH		1920 +#define KMB_CRTC_MIN_HEIGHT		1080 +#define KMB_FB_MAX_WIDTH		1920 +#define KMB_FB_MAX_HEIGHT		1080 +#define KMB_FB_MIN_WIDTH		1 +#define KMB_FB_MIN_HEIGHT		1 +#define KMB_MIN_VREFRESH		59    /*vertical refresh in Hz */ +#define KMB_MAX_VREFRESH		60    /*vertical refresh in Hz */  #define KMB_LCD_DEFAULT_CLK		200000000  #define KMB_SYS_CLK_MHZ			500 @@ -45,6 +57,7 @@ struct kmb_drm_private {  	spinlock_t			irq_lock;  	int				irq_lcd;  	int				sys_clk_mhz; +	struct disp_cfg			init_disp_cfg[KMB_MAX_PLANES];  	struct layer_status		plane_status[KMB_MAX_PLANES];  	int				kmb_under_flow;  	int				kmb_flush_done; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 1793cd31b117..f6071882054c 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -482,6 +482,10 @@ static u32 mipi_tx_fg_section_cfg(struct kmb_dsi *kmb_dsi,  	return 0;  } +#define CLK_DIFF_LOW 50 +#define CLK_DIFF_HI 60 +#define SYSCLK_500  500 +  static void mipi_tx_fg_cfg_regs(struct kmb_dsi *kmb_dsi, u8 frame_gen,  				struct mipi_tx_frame_timing_cfg *fg_cfg)  { @@ -492,7 +496,12 @@ static void mipi_tx_fg_cfg_regs(struct kmb_dsi *kmb_dsi, u8 frame_gen,  	/* 500 Mhz system clock minus 50 to account for the difference in  	 * MIPI clock speed in RTL tests  	 */ -	sysclk = kmb_dsi->sys_clk_mhz - 50; +	if (kmb_dsi->sys_clk_mhz == SYSCLK_500) { +		sysclk = kmb_dsi->sys_clk_mhz - CLK_DIFF_LOW; +	} else { +		/* 700 Mhz clk*/ +		sysclk = kmb_dsi->sys_clk_mhz - CLK_DIFF_HI; +	}  	/* PPL-Pixel Packing Layer, LLP-Low Level Protocol  	 * Frame genartor timing parameters are clocked on the system clock, @@ -1322,7 +1331,8 @@ static u32 mipi_tx_init_dphy(struct kmb_dsi *kmb_dsi,  	return 0;  } -static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi) +static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi, +				struct drm_atomic_state *old_state)  {  	struct regmap *msscam; @@ -1331,7 +1341,7 @@ static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi)  		dev_dbg(kmb_dsi->dev, "failed to get msscam syscon");  		return;  	} - +	drm_atomic_bridge_chain_enable(adv_bridge, old_state);  	/* DISABLE MIPI->CIF CONNECTION */  	regmap_write(msscam, MSS_MIPI_CIF_CFG, 0); @@ -1342,7 +1352,7 @@ static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi)  }  int kmb_dsi_mode_set(struct kmb_dsi *kmb_dsi, struct drm_display_mode *mode, -		     int sys_clk_mhz) +		     int sys_clk_mhz, struct drm_atomic_state *old_state)  {  	u64 data_rate; @@ -1384,18 +1394,13 @@ int kmb_dsi_mode_set(struct kmb_dsi *kmb_dsi, struct drm_display_mode *mode,  		mipi_tx_init_cfg.lane_rate_mbps = data_rate;  	} -	kmb_write_mipi(kmb_dsi, DPHY_ENABLE, 0); -	kmb_write_mipi(kmb_dsi, DPHY_INIT_CTRL0, 0); -	kmb_write_mipi(kmb_dsi, DPHY_INIT_CTRL1, 0); -	kmb_write_mipi(kmb_dsi, DPHY_INIT_CTRL2, 0); -  	/* Initialize mipi controller */  	mipi_tx_init_cntrl(kmb_dsi, &mipi_tx_init_cfg);  	/* Dphy initialization */  	mipi_tx_init_dphy(kmb_dsi, &mipi_tx_init_cfg); -	connect_lcd_to_mipi(kmb_dsi); +	connect_lcd_to_mipi(kmb_dsi, old_state);  	dev_info(kmb_dsi->dev, "mipi hw initialized");  	return 0; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index 66b7c500d9bc..09dc88743d77 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -380,7 +380,7 @@ int kmb_dsi_host_bridge_init(struct device *dev);  struct kmb_dsi *kmb_dsi_init(struct platform_device *pdev);  void kmb_dsi_host_unregister(struct kmb_dsi *kmb_dsi);  int kmb_dsi_mode_set(struct kmb_dsi *kmb_dsi, struct drm_display_mode *mode, -		     int sys_clk_mhz); +		     int sys_clk_mhz, struct drm_atomic_state *old_state);  int kmb_dsi_map_mmio(struct kmb_dsi *kmb_dsi);  int kmb_dsi_clk_init(struct kmb_dsi *kmb_dsi);  int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi); diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index ecee6782612d..00404ba4126d 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -67,8 +67,21 @@ static const u32 kmb_formats_v[] = {  static unsigned int check_pixel_format(struct drm_plane *plane, u32 format)  { +	struct kmb_drm_private *kmb; +	struct kmb_plane *kmb_plane = to_kmb_plane(plane);  	int i; +	int plane_id = kmb_plane->id; +	struct disp_cfg init_disp_cfg; +	kmb = to_kmb(plane->dev); +	init_disp_cfg = kmb->init_disp_cfg[plane_id]; +	/* Due to HW limitations, changing pixel format after initial +	 * plane configuration is not supported. +	 */ +	if (init_disp_cfg.format && init_disp_cfg.format != format) { +		drm_dbg(&kmb->drm, "Cannot change format after initial plane configuration"); +		return -EINVAL; +	}  	for (i = 0; i < plane->format_count; i++) {  		if (plane->format_types[i] == format)  			return 0; @@ -81,11 +94,17 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,  {  	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,  										 plane); +	struct kmb_drm_private *kmb; +	struct kmb_plane *kmb_plane = to_kmb_plane(plane); +	int plane_id = kmb_plane->id; +	struct disp_cfg init_disp_cfg;  	struct drm_framebuffer *fb;  	int ret;  	struct drm_crtc_state *crtc_state;  	bool can_position; +	kmb = to_kmb(plane->dev); +	init_disp_cfg = kmb->init_disp_cfg[plane_id];  	fb = new_plane_state->fb;  	if (!fb || !new_plane_state->crtc)  		return 0; @@ -94,10 +113,21 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,  	if (ret)  		return ret; -	if (new_plane_state->crtc_w > KMB_MAX_WIDTH || new_plane_state->crtc_h > KMB_MAX_HEIGHT) +	if (new_plane_state->crtc_w > KMB_FB_MAX_WIDTH || +	    new_plane_state->crtc_h > KMB_FB_MAX_HEIGHT || +	    new_plane_state->crtc_w < KMB_FB_MIN_WIDTH || +	    new_plane_state->crtc_h < KMB_FB_MIN_HEIGHT)  		return -EINVAL; -	if (new_plane_state->crtc_w < KMB_MIN_WIDTH || new_plane_state->crtc_h < KMB_MIN_HEIGHT) + +	/* Due to HW limitations, changing plane height or width after +	 * initial plane configuration is not supported. +	 */ +	if ((init_disp_cfg.width && init_disp_cfg.height) && +	    (init_disp_cfg.width != fb->width || +	    init_disp_cfg.height != fb->height)) { +		drm_dbg(&kmb->drm, "Cannot change plane height or width after initial configuration");  		return -EINVAL; +	}  	can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);  	crtc_state =  		drm_atomic_get_existing_crtc_state(state, @@ -277,6 +307,44 @@ static void config_csc(struct kmb_drm_private *kmb, int plane_id)  	kmb_write_lcd(kmb, LCD_LAYERn_CSC_OFF3(plane_id), csc_coef_lcd[11]);  } +static void kmb_plane_set_alpha(struct kmb_drm_private *kmb, +				const struct drm_plane_state *state, +				unsigned char plane_id, +				unsigned int *val) +{ +	u16 plane_alpha = state->alpha; +	u16 pixel_blend_mode = state->pixel_blend_mode; +	int has_alpha = state->fb->format->has_alpha; + +	if (plane_alpha != DRM_BLEND_ALPHA_OPAQUE) +		*val |= LCD_LAYER_ALPHA_STATIC; + +	if (has_alpha) { +		switch (pixel_blend_mode) { +		case DRM_MODE_BLEND_PIXEL_NONE: +			break; +		case DRM_MODE_BLEND_PREMULTI: +			*val |= LCD_LAYER_ALPHA_EMBED | LCD_LAYER_ALPHA_PREMULT; +			break; +		case DRM_MODE_BLEND_COVERAGE: +			*val |= LCD_LAYER_ALPHA_EMBED; +			break; +		default: +			DRM_DEBUG("Missing pixel blend mode case (%s == %ld)\n", +				  __stringify(pixel_blend_mode), +				  (long)pixel_blend_mode); +			break; +		} +	} + +	if (plane_alpha == DRM_BLEND_ALPHA_OPAQUE && !has_alpha) { +		*val &= LCD_LAYER_ALPHA_DISABLED; +		return; +	} + +	kmb_write_lcd(kmb, LCD_LAYERn_ALPHA(plane_id), plane_alpha); +} +  static void kmb_plane_atomic_update(struct drm_plane *plane,  				    struct drm_atomic_state *state)  { @@ -296,6 +364,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	unsigned char plane_id;  	int num_planes;  	static dma_addr_t addr[MAX_SUB_PLANES]; +	struct disp_cfg *init_disp_cfg;  	if (!plane || !new_plane_state || !old_plane_state)  		return; @@ -303,11 +372,12 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	fb = new_plane_state->fb;  	if (!fb)  		return; +  	num_planes = fb->format->num_planes;  	kmb_plane = to_kmb_plane(plane); -	plane_id = kmb_plane->id;  	kmb = to_kmb(plane->dev); +	plane_id = kmb_plane->id;  	spin_lock_irq(&kmb->irq_lock);  	if (kmb->kmb_under_flow || kmb->kmb_flush_done) { @@ -317,7 +387,8 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	}  	spin_unlock_irq(&kmb->irq_lock); -	src_w = (new_plane_state->src_w >> 16); +	init_disp_cfg = &kmb->init_disp_cfg[plane_id]; +	src_w = new_plane_state->src_w >> 16;  	src_h = new_plane_state->src_h >> 16;  	crtc_x = new_plane_state->crtc_x;  	crtc_y = new_plane_state->crtc_y; @@ -400,20 +471,32 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  		config_csc(kmb, plane_id);  	} +	kmb_plane_set_alpha(kmb, plane->state, plane_id, &val); +  	kmb_write_lcd(kmb, LCD_LAYERn_CFG(plane_id), val); +	/* Configure LCD_CONTROL */ +	ctrl = kmb_read_lcd(kmb, LCD_CONTROL); + +	/* Set layer blending config */ +	ctrl &= ~LCD_CTRL_ALPHA_ALL; +	ctrl |= LCD_CTRL_ALPHA_BOTTOM_VL1 | +		LCD_CTRL_ALPHA_BLEND_VL2; + +	ctrl &= ~LCD_CTRL_ALPHA_BLEND_BKGND_DISABLE; +  	switch (plane_id) {  	case LAYER_0: -		ctrl = LCD_CTRL_VL1_ENABLE; +		ctrl |= LCD_CTRL_VL1_ENABLE;  		break;  	case LAYER_1: -		ctrl = LCD_CTRL_VL2_ENABLE; +		ctrl |= LCD_CTRL_VL2_ENABLE;  		break;  	case LAYER_2: -		ctrl = LCD_CTRL_GL1_ENABLE; +		ctrl |= LCD_CTRL_GL1_ENABLE;  		break;  	case LAYER_3: -		ctrl = LCD_CTRL_GL2_ENABLE; +		ctrl |= LCD_CTRL_GL2_ENABLE;  		break;  	} @@ -425,7 +508,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	 */  	ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; -	kmb_set_bitmask_lcd(kmb, LCD_CONTROL, ctrl); +	kmb_write_lcd(kmb, LCD_CONTROL, ctrl);  	/* Enable pipeline AXI read transactions for the DMA  	 * after setting graphics layers. This must be done @@ -448,6 +531,16 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	/* Enable DMA */  	kmb_write_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id), dma_cfg); + +	/* Save initial display config */ +	if (!init_disp_cfg->width || +	    !init_disp_cfg->height || +	    !init_disp_cfg->format) { +		init_disp_cfg->width = width; +		init_disp_cfg->height = height; +		init_disp_cfg->format = fb->format->format; +	} +  	drm_dbg(&kmb->drm, "dma_cfg=0x%x LCD_DMA_CFG=0x%x\n", dma_cfg,  		kmb_read_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id))); @@ -490,6 +583,9 @@ struct kmb_plane *kmb_plane_init(struct drm_device *drm)  	enum drm_plane_type plane_type;  	const u32 *plane_formats;  	int num_plane_formats; +	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | +				  BIT(DRM_MODE_BLEND_PREMULTI)   | +				  BIT(DRM_MODE_BLEND_COVERAGE);  	for (i = 0; i < KMB_MAX_PLANES; i++) {  		plane = drmm_kzalloc(drm, sizeof(*plane), GFP_KERNEL); @@ -521,8 +617,16 @@ struct kmb_plane *kmb_plane_init(struct drm_device *drm)  		drm_dbg(drm, "%s : %d i=%d type=%d",  			__func__, __LINE__,  			  i, plane_type); +		drm_plane_create_alpha_property(&plane->base_plane); + +		drm_plane_create_blend_mode_property(&plane->base_plane, +						     blend_caps); + +		drm_plane_create_zpos_immutable_property(&plane->base_plane, i); +  		drm_plane_helper_add(&plane->base_plane,  				     &kmb_plane_helper_funcs); +  		if (plane_type == DRM_PLANE_TYPE_PRIMARY) {  			primary = plane;  			kmb->plane = plane; diff --git a/drivers/gpu/drm/kmb/kmb_plane.h b/drivers/gpu/drm/kmb/kmb_plane.h index 486490f7a3ec..b51144044fe8 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.h +++ b/drivers/gpu/drm/kmb/kmb_plane.h @@ -35,6 +35,9 @@  #define POSSIBLE_CRTCS 1  #define to_kmb_plane(x) container_of(x, struct kmb_plane, base_plane) +#define POSSIBLE_CRTCS		1 +#define KMB_MAX_PLANES		2 +  enum layer_id {  	LAYER_0,  	LAYER_1, @@ -43,8 +46,6 @@ enum layer_id {  	/* KMB_MAX_PLANES */  }; -#define KMB_MAX_PLANES 1 -  enum sub_plane_id {  	Y_PLANE,  	U_PLANE, @@ -62,6 +63,12 @@ struct layer_status {  	u32 ctrl;  }; +struct disp_cfg { +	unsigned int width; +	unsigned int height; +	unsigned int format; +}; +  struct kmb_plane *kmb_plane_init(struct drm_device *drm);  void kmb_plane_destroy(struct drm_plane *plane);  #endif /* __KMB_PLANE_H__ */ diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index 48150569f702..9756101b0d32 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -43,8 +43,10 @@  #define LCD_CTRL_OUTPUT_ENABLED			  BIT(19)  #define LCD_CTRL_BPORCH_ENABLE			  BIT(21)  #define LCD_CTRL_FPORCH_ENABLE			  BIT(22) +#define LCD_CTRL_ALPHA_BLEND_BKGND_DISABLE	  BIT(23)  #define LCD_CTRL_PIPELINE_DMA			  BIT(28)  #define LCD_CTRL_VHSYNC_IDLE_LVL		  BIT(31) +#define LCD_CTRL_ALPHA_ALL			  (0xff << 6)  /* interrupts */  #define LCD_INT_STATUS				(0x4 * 0x001) @@ -115,6 +117,7 @@  #define LCD_LAYER_ALPHA_EMBED			BIT(5)  #define LCD_LAYER_ALPHA_COMBI			(LCD_LAYER_ALPHA_STATIC | \  						      LCD_LAYER_ALPHA_EMBED) +#define LCD_LAYER_ALPHA_DISABLED		~(LCD_LAYER_ALPHA_COMBI)  /* RGB multiplied with alpha */  #define LCD_LAYER_ALPHA_PREMULT			BIT(6)  #define LCD_LAYER_INVERT_COL			BIT(7) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 5f81489fc60c..a4e80e499674 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -4,8 +4,6 @@   */  #include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/mailbox_controller.h>  #include <linux/pm_runtime.h>  #include <linux/soc/mediatek/mtk-cmdq.h>  #include <linux/soc/mediatek/mtk-mmsys.h> @@ -52,11 +50,8 @@ struct mtk_drm_crtc {  	bool				pending_async_planes;  #if IS_REACHABLE(CONFIG_MTK_CMDQ) -	struct mbox_client		cmdq_cl; -	struct mbox_chan		*cmdq_chan; -	struct cmdq_pkt			cmdq_handle; +	struct cmdq_client		*cmdq_client;  	u32				cmdq_event; -	u32				cmdq_vblank_cnt;  #endif  	struct device			*mmsys_dev; @@ -227,79 +222,9 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc,  }  #if IS_REACHABLE(CONFIG_MTK_CMDQ) -static int mtk_drm_cmdq_pkt_create(struct mbox_chan *chan, struct cmdq_pkt *pkt, -				    size_t size) +static void ddp_cmdq_cb(struct cmdq_cb_data data)  { -	struct device *dev; -	dma_addr_t dma_addr; - -	pkt->va_base = kzalloc(size, GFP_KERNEL); -	if (!pkt->va_base) { -		kfree(pkt); -		return -ENOMEM; -	} -	pkt->buf_size = size; - -	dev = chan->mbox->dev; -	dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, -				  DMA_TO_DEVICE); -	if (dma_mapping_error(dev, dma_addr)) { -		dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); -		kfree(pkt->va_base); -		kfree(pkt); -		return -ENOMEM; -	} - -	pkt->pa_base = dma_addr; - -	return 0; -} - -static void mtk_drm_cmdq_pkt_destroy(struct mbox_chan *chan, struct cmdq_pkt *pkt) -{ -	dma_unmap_single(chan->mbox->dev, pkt->pa_base, pkt->buf_size, -			 DMA_TO_DEVICE); -	kfree(pkt->va_base); -	kfree(pkt); -} - -static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) -{ -	struct mtk_drm_crtc *mtk_crtc = container_of(cl, struct mtk_drm_crtc, cmdq_cl); -	struct cmdq_cb_data *data = mssg; -	struct mtk_crtc_state *state; -	unsigned int i; - -	state = to_mtk_crtc_state(mtk_crtc->base.state); - -	state->pending_config = false; - -	if (mtk_crtc->pending_planes) { -		for (i = 0; i < mtk_crtc->layer_nr; i++) { -			struct drm_plane *plane = &mtk_crtc->planes[i]; -			struct mtk_plane_state *plane_state; - -			plane_state = to_mtk_plane_state(plane->state); - -			plane_state->pending.config = false; -		} -		mtk_crtc->pending_planes = false; -	} - -	if (mtk_crtc->pending_async_planes) { -		for (i = 0; i < mtk_crtc->layer_nr; i++) { -			struct drm_plane *plane = &mtk_crtc->planes[i]; -			struct mtk_plane_state *plane_state; - -			plane_state = to_mtk_plane_state(plane->state); - -			plane_state->pending.async_config = false; -		} -		mtk_crtc->pending_async_planes = false; -	} - -	mtk_crtc->cmdq_vblank_cnt = 0; -	mtk_drm_cmdq_pkt_destroy(mtk_crtc->cmdq_chan, data->pkt); +	cmdq_pkt_destroy(data.data);  }  #endif @@ -453,8 +378,7 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,  				    state->pending_vrefresh, 0,  				    cmdq_handle); -		if (!cmdq_handle) -			state->pending_config = false; +		state->pending_config = false;  	}  	if (mtk_crtc->pending_planes) { @@ -474,12 +398,9 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,  				mtk_ddp_comp_layer_config(comp, local_layer,  							  plane_state,  							  cmdq_handle); -			if (!cmdq_handle) -				plane_state->pending.config = false; +			plane_state->pending.config = false;  		} - -		if (!cmdq_handle) -			mtk_crtc->pending_planes = false; +		mtk_crtc->pending_planes = false;  	}  	if (mtk_crtc->pending_async_planes) { @@ -499,12 +420,9 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,  				mtk_ddp_comp_layer_config(comp, local_layer,  							  plane_state,  							  cmdq_handle); -			if (!cmdq_handle) -				plane_state->pending.async_config = false; +			plane_state->pending.async_config = false;  		} - -		if (!cmdq_handle) -			mtk_crtc->pending_async_planes = false; +		mtk_crtc->pending_async_planes = false;  	}  } @@ -512,7 +430,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,  				       bool needs_vblank)  {  #if IS_REACHABLE(CONFIG_MTK_CMDQ) -	struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle; +	struct cmdq_pkt *cmdq_handle;  #endif  	struct drm_crtc *crtc = &mtk_crtc->base;  	struct mtk_drm_private *priv = crtc->dev->dev_private; @@ -550,24 +468,14 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,  		mtk_mutex_release(mtk_crtc->mutex);  	}  #if IS_REACHABLE(CONFIG_MTK_CMDQ) -	if (mtk_crtc->cmdq_chan) { -		mbox_flush(mtk_crtc->cmdq_chan, 2000); -		cmdq_handle->cmd_buf_size = 0; +	if (mtk_crtc->cmdq_client) { +		mbox_flush(mtk_crtc->cmdq_client->chan, 2000); +		cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);  		cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);  		cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);  		mtk_crtc_ddp_config(crtc, cmdq_handle);  		cmdq_pkt_finalize(cmdq_handle); -		dma_sync_single_for_device(mtk_crtc->cmdq_chan->mbox->dev, -					    cmdq_handle->pa_base, -					    cmdq_handle->cmd_buf_size, -					    DMA_TO_DEVICE); -		/* -		 * CMDQ command should execute in next vblank, -		 * If it fail to execute in next 2 vblank, timeout happen. -		 */ -		mtk_crtc->cmdq_vblank_cnt = 2; -		mbox_send_message(mtk_crtc->cmdq_chan, cmdq_handle); -		mbox_client_txdone(mtk_crtc->cmdq_chan, 0); +		cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);  	}  #endif  	mtk_crtc->config_updating = false; @@ -581,15 +489,12 @@ static void mtk_crtc_ddp_irq(void *data)  	struct mtk_drm_private *priv = crtc->dev->dev_private;  #if IS_REACHABLE(CONFIG_MTK_CMDQ) -	if (!priv->data->shadow_register && !mtk_crtc->cmdq_chan) -		mtk_crtc_ddp_config(crtc, NULL); -	else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0) -		DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n", -			  drm_crtc_index(&mtk_crtc->base)); +	if (!priv->data->shadow_register && !mtk_crtc->cmdq_client)  #else  	if (!priv->data->shadow_register) -		mtk_crtc_ddp_config(crtc, NULL);  #endif +		mtk_crtc_ddp_config(crtc, NULL); +  	mtk_drm_finish_page_flip(mtk_crtc);  } @@ -924,20 +829,16 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,  	mutex_init(&mtk_crtc->hw_lock);  #if IS_REACHABLE(CONFIG_MTK_CMDQ) -	mtk_crtc->cmdq_cl.dev = mtk_crtc->mmsys_dev; -	mtk_crtc->cmdq_cl.tx_block = false; -	mtk_crtc->cmdq_cl.knows_txdone = true; -	mtk_crtc->cmdq_cl.rx_callback = ddp_cmdq_cb; -	mtk_crtc->cmdq_chan = -			mbox_request_channel(&mtk_crtc->cmdq_cl, -					      drm_crtc_index(&mtk_crtc->base)); -	if (IS_ERR(mtk_crtc->cmdq_chan)) { +	mtk_crtc->cmdq_client = +			cmdq_mbox_create(mtk_crtc->mmsys_dev, +					 drm_crtc_index(&mtk_crtc->base)); +	if (IS_ERR(mtk_crtc->cmdq_client)) {  		dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n",  			drm_crtc_index(&mtk_crtc->base)); -		mtk_crtc->cmdq_chan = NULL; +		mtk_crtc->cmdq_client = NULL;  	} -	if (mtk_crtc->cmdq_chan) { +	if (mtk_crtc->cmdq_client) {  		ret = of_property_read_u32_index(priv->mutex_node,  						 "mediatek,gce-events",  						 drm_crtc_index(&mtk_crtc->base), @@ -945,18 +846,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,  		if (ret) {  			dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",  				drm_crtc_index(&mtk_crtc->base)); -			mbox_free_channel(mtk_crtc->cmdq_chan); -			mtk_crtc->cmdq_chan = NULL; -		} else { -			ret = mtk_drm_cmdq_pkt_create(mtk_crtc->cmdq_chan, -						       &mtk_crtc->cmdq_handle, -						       PAGE_SIZE); -			if (ret) { -				dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n", -					drm_crtc_index(&mtk_crtc->base)); -				mbox_free_channel(mtk_crtc->cmdq_chan); -				mtk_crtc->cmdq_chan = NULL; -			} +			cmdq_mbox_destroy(mtk_crtc->cmdq_client); +			mtk_crtc->cmdq_client = NULL;  		}  	}  #endif diff --git a/drivers/gpu/drm/mga/mga_ioc32.c b/drivers/gpu/drm/mga/mga_ioc32.c index 4fd4de16cd32..894472921c30 100644 --- a/drivers/gpu/drm/mga/mga_ioc32.c +++ b/drivers/gpu/drm/mga/mga_ioc32.c @@ -38,16 +38,18 @@  typedef struct drm32_mga_init {  	int func;  	u32 sarea_priv_offset; -	int chipset; -	int sgram; -	unsigned int maccess; -	unsigned int fb_cpp; -	unsigned int front_offset, front_pitch; -	unsigned int back_offset, back_pitch; -	unsigned int depth_cpp; -	unsigned int depth_offset, depth_pitch; -	unsigned int texture_offset[MGA_NR_TEX_HEAPS]; -	unsigned int texture_size[MGA_NR_TEX_HEAPS]; +	struct_group(always32bit, +		int chipset; +		int sgram; +		unsigned int maccess; +		unsigned int fb_cpp; +		unsigned int front_offset, front_pitch; +		unsigned int back_offset, back_pitch; +		unsigned int depth_cpp; +		unsigned int depth_offset, depth_pitch; +		unsigned int texture_offset[MGA_NR_TEX_HEAPS]; +		unsigned int texture_size[MGA_NR_TEX_HEAPS]; +	);  	u32 fb_offset;  	u32 mmio_offset;  	u32 status_offset; @@ -67,9 +69,8 @@ static int compat_mga_init(struct file *file, unsigned int cmd,  	init.func = init32.func;  	init.sarea_priv_offset = init32.sarea_priv_offset; -	memcpy(&init.chipset, &init32.chipset, -		offsetof(drm_mga_init_t, fb_offset) - -		offsetof(drm_mga_init_t, chipset)); +	memcpy(&init.always32bit, &init32.always32bit, +	       sizeof(init32.always32bit));  	init.fb_offset = init32.fb_offset;  	init.mmio_offset = init32.mmio_offset;  	init.status_offset = init32.status_offset; diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index e9c6af78b1d7..3ddf739a6f9b 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -17,7 +17,7 @@ config DRM_MSM  	select DRM_SCHED  	select SHMEM  	select TMPFS -	select QCOM_SCM if ARCH_QCOM +	select QCOM_SCM  	select WANT_DEV_COREDUMP  	select SND_SOC_HDMI_CODEC if SND_SOC  	select SYNC_FILE @@ -55,7 +55,7 @@ config DRM_MSM_GPU_SUDO  config DRM_MSM_HDMI_HDCP  	bool "Enable HDMI HDCP support in MSM DRM driver" -	depends on DRM_MSM && QCOM_SCM +	depends on DRM_MSM  	default y  	help  	  Choose this option to enable HDCP state machine diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 4534633fe7cd..8fb847c174ff 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -571,13 +571,14 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)  	}  	icc_path = devm_of_icc_get(&pdev->dev, "gfx-mem"); -	ret = IS_ERR(icc_path); -	if (ret) +	if (IS_ERR(icc_path)) { +		ret = PTR_ERR(icc_path);  		goto fail; +	}  	ocmem_icc_path = devm_of_icc_get(&pdev->dev, "ocmem"); -	ret = IS_ERR(ocmem_icc_path); -	if (ret) { +	if (IS_ERR(ocmem_icc_path)) { +		ret = PTR_ERR(ocmem_icc_path);  		/* allow -ENODATA, ocmem icc is optional */  		if (ret != -ENODATA)  			goto fail; diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 82bebb40234d..a96ee79cc5e0 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -699,13 +699,14 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)  	}  	icc_path = devm_of_icc_get(&pdev->dev, "gfx-mem"); -	ret = IS_ERR(icc_path); -	if (ret) +	if (IS_ERR(icc_path)) { +		ret = PTR_ERR(icc_path);  		goto fail; +	}  	ocmem_icc_path = devm_of_icc_get(&pdev->dev, "ocmem"); -	ret = IS_ERR(ocmem_icc_path); -	if (ret) { +	if (IS_ERR(ocmem_icc_path)) { +		ret = PTR_ERR(ocmem_icc_path);  		/* allow -ENODATA, ocmem icc is optional */  		if (ret != -ENODATA)  			goto fail; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index a7c58018959f..8b73f70766a4 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -296,6 +296,8 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)  	u32 val;  	int request, ack; +	WARN_ON_ONCE(!mutex_is_locked(&gmu->lock)); +  	if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits))  		return -EINVAL; @@ -337,6 +339,8 @@ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)  {  	int bit; +	WARN_ON_ONCE(!mutex_is_locked(&gmu->lock)); +  	if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits))  		return; @@ -1482,6 +1486,8 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)  	if (!pdev)  		return -ENODEV; +	mutex_init(&gmu->lock); +  	gmu->dev = &pdev->dev;  	of_dma_configure(gmu->dev, node, true); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index 3c74f64e3126..84bd516f01e8 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -44,6 +44,9 @@ struct a6xx_gmu_bo {  struct a6xx_gmu {  	struct device *dev; +	/* For serializing communication with the GMU: */ +	struct mutex lock; +  	struct msm_gem_address_space *aspace;  	void * __iomem mmio; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 40c9fef457a4..267a880811d6 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -106,7 +106,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,  	u32 asid;  	u64 memptr = rbmemptr(ring, ttbr0); -	if (ctx == a6xx_gpu->cur_ctx) +	if (ctx->seqno == a6xx_gpu->cur_ctx_seqno)  		return;  	if (msm_iommu_pagetable_params(ctx->aspace->mmu, &ttbr, &asid)) @@ -139,7 +139,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,  	OUT_PKT7(ring, CP_EVENT_WRITE, 1);  	OUT_RING(ring, 0x31); -	a6xx_gpu->cur_ctx = ctx; +	a6xx_gpu->cur_ctx_seqno = ctx->seqno;  }  static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) @@ -881,7 +881,7 @@ static int a6xx_zap_shader_init(struct msm_gpu *gpu)  	  A6XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \  	  A6XX_RBBM_INT_0_MASK_UCHE_TRAP_INTR) -static int a6xx_hw_init(struct msm_gpu *gpu) +static int hw_init(struct msm_gpu *gpu)  {  	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);  	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); @@ -1081,7 +1081,7 @@ static int a6xx_hw_init(struct msm_gpu *gpu)  	/* Always come up on rb 0 */  	a6xx_gpu->cur_ring = gpu->rb[0]; -	a6xx_gpu->cur_ctx = NULL; +	a6xx_gpu->cur_ctx_seqno = 0;  	/* Enable the SQE_to start the CP engine */  	gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 1); @@ -1135,6 +1135,19 @@ out:  	return ret;  } +static int a6xx_hw_init(struct msm_gpu *gpu) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); +	int ret; + +	mutex_lock(&a6xx_gpu->gmu.lock); +	ret = hw_init(gpu); +	mutex_unlock(&a6xx_gpu->gmu.lock); + +	return ret; +} +  static void a6xx_dump(struct msm_gpu *gpu)  {  	DRM_DEV_INFO(&gpu->pdev->dev, "status:   %08x\n", @@ -1509,7 +1522,9 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)  	trace_msm_gpu_resume(0); +	mutex_lock(&a6xx_gpu->gmu.lock);  	ret = a6xx_gmu_resume(a6xx_gpu); +	mutex_unlock(&a6xx_gpu->gmu.lock);  	if (ret)  		return ret; @@ -1532,7 +1547,9 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)  	msm_devfreq_suspend(gpu); +	mutex_lock(&a6xx_gpu->gmu.lock);  	ret = a6xx_gmu_stop(a6xx_gpu); +	mutex_unlock(&a6xx_gpu->gmu.lock);  	if (ret)  		return ret; @@ -1547,18 +1564,19 @@ static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)  {  	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);  	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); -	static DEFINE_MUTEX(perfcounter_oob); -	mutex_lock(&perfcounter_oob); +	mutex_lock(&a6xx_gpu->gmu.lock);  	/* Force the GPU power on so we can read this register */  	a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);  	*value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO, -		REG_A6XX_CP_ALWAYS_ON_COUNTER_HI); +			    REG_A6XX_CP_ALWAYS_ON_COUNTER_HI);  	a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); -	mutex_unlock(&perfcounter_oob); + +	mutex_unlock(&a6xx_gpu->gmu.lock); +  	return 0;  } @@ -1622,6 +1640,16 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu)  	return (unsigned long)busy_time;  } +void a6xx_gpu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp) +{ +	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + +	mutex_lock(&a6xx_gpu->gmu.lock); +	a6xx_gmu_set_freq(gpu, opp); +	mutex_unlock(&a6xx_gpu->gmu.lock); +} +  static struct msm_gem_address_space *  a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev)  { @@ -1766,7 +1794,7 @@ static const struct adreno_gpu_funcs funcs = {  #endif  		.gpu_busy = a6xx_gpu_busy,  		.gpu_get_freq = a6xx_gmu_get_freq, -		.gpu_set_freq = a6xx_gmu_set_freq, +		.gpu_set_freq = a6xx_gpu_set_freq,  #if defined(CONFIG_DRM_MSM_GPU_STATE)  		.gpu_state_get = a6xx_gpu_state_get,  		.gpu_state_put = a6xx_gpu_state_put, @@ -1810,6 +1838,13 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)  			adreno_cmp_rev(ADRENO_REV(6, 3, 5, ANY_ID), info->rev)))  		adreno_gpu->base.hw_apriv = true; +	/* +	 * For now only clamp to idle freq for devices where this is known not +	 * to cause power supply issues: +	 */ +	if (info && (info->revn == 618)) +		gpu->clamp_to_idle = true; +  	a6xx_llc_slices_init(pdev, a6xx_gpu);  	ret = a6xx_set_supported_hw(&pdev->dev, config->rev); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 0bc2d062f54a..8e5527c881b1 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -19,7 +19,16 @@ struct a6xx_gpu {  	uint64_t sqe_iova;  	struct msm_ringbuffer *cur_ring; -	struct msm_file_private *cur_ctx; + +	/** +	 * cur_ctx_seqno: +	 * +	 * The ctx->seqno value of the context with current pgtables +	 * installed.  Tracked by seqno rather than pointer value to +	 * avoid dangling pointers, and cases where a ctx can be freed +	 * and a new one created with the same address. +	 */ +	int cur_ctx_seqno;  	struct a6xx_gmu gmu; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index b131fd376192..700d65e39feb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -794,7 +794,7 @@ static const struct dpu_pingpong_cfg sm8150_pp[] = {  			DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30),  			-1),  	PP_BLK("pingpong_5", PINGPONG_5, 0x72800, MERGE_3D_2, sdm845_pp_sblk, -			DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), +			DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31),  			-1),  }; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index f482e0911d03..bb7d066618e6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -1125,6 +1125,20 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc)  	__drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base);  } +static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = { +	.set_config = drm_atomic_helper_set_config, +	.destroy = mdp5_crtc_destroy, +	.page_flip = drm_atomic_helper_page_flip, +	.reset = mdp5_crtc_reset, +	.atomic_duplicate_state = mdp5_crtc_duplicate_state, +	.atomic_destroy_state = mdp5_crtc_destroy_state, +	.atomic_print_state = mdp5_crtc_atomic_print_state, +	.get_vblank_counter = mdp5_crtc_get_vblank_counter, +	.enable_vblank  = msm_crtc_enable_vblank, +	.disable_vblank = msm_crtc_disable_vblank, +	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, +}; +  static const struct drm_crtc_funcs mdp5_crtc_funcs = {  	.set_config = drm_atomic_helper_set_config,  	.destroy = mdp5_crtc_destroy, @@ -1313,6 +1327,8 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,  	mdp5_crtc->lm_cursor_enabled = cursor_plane ? false : true;  	drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane, +				  cursor_plane ? +				  &mdp5_crtc_no_lm_cursor_funcs :  				  &mdp5_crtc_funcs, NULL);  	drm_flip_work_init(&mdp5_crtc->unref_cursor_work, diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index fbe4c2cd52a3..a0392e4d8134 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1309,14 +1309,14 @@ static int dp_pm_resume(struct device *dev)  	 * can not declared display is connected unless  	 * HDMI cable is plugged in and sink_count of  	 * dongle become 1 +	 * also only signal audio when disconnected  	 */ -	if (dp->link->sink_count) +	if (dp->link->sink_count) {  		dp->dp_display.is_connected = true; -	else +	} else {  		dp->dp_display.is_connected = false; - -	dp_display_handle_plugged_change(g_dp_display, -				dp->dp_display.is_connected); +		dp_display_handle_plugged_change(g_dp_display, false); +	}  	DRM_DEBUG_DP("After, sink_count=%d is_connected=%d core_inited=%d power_on=%d\n",  			dp->link->sink_count, dp->dp_display.is_connected, diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 614dc7f26f2c..75ae3008b68f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -215,8 +215,10 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,  		goto fail;  	} -	if (!msm_dsi_manager_validate_current_config(msm_dsi->id)) +	if (!msm_dsi_manager_validate_current_config(msm_dsi->id)) { +		ret = -EINVAL;  		goto fail; +	}  	msm_dsi->encoder = encoder; diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index e269df285136..c86b5090fae6 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -451,7 +451,7 @@ static int dsi_bus_clk_enable(struct msm_dsi_host *msm_host)  	return 0;  err: -	for (; i > 0; i--) +	while (--i >= 0)  		clk_disable_unprepare(msm_host->bus_clks[i]);  	return ret; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index d13552b2213b..5b4e991f220d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -110,14 +110,13 @@ static struct dsi_pll_14nm *pll_14nm_list[DSI_MAX];  static bool pll_14nm_poll_for_ready(struct dsi_pll_14nm *pll_14nm,  				    u32 nb_tries, u32 timeout_us)  { -	bool pll_locked = false; +	bool pll_locked = false, pll_ready = false;  	void __iomem *base = pll_14nm->phy->pll_base;  	u32 tries, val;  	tries = nb_tries;  	while (tries--) { -		val = dsi_phy_read(base + -			       REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); +		val = dsi_phy_read(base + REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS);  		pll_locked = !!(val & BIT(5));  		if (pll_locked) @@ -126,23 +125,24 @@ static bool pll_14nm_poll_for_ready(struct dsi_pll_14nm *pll_14nm,  		udelay(timeout_us);  	} -	if (!pll_locked) { -		tries = nb_tries; -		while (tries--) { -			val = dsi_phy_read(base + -				REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); -			pll_locked = !!(val & BIT(0)); +	if (!pll_locked) +		goto out; -			if (pll_locked) -				break; +	tries = nb_tries; +	while (tries--) { +		val = dsi_phy_read(base + REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); +		pll_ready = !!(val & BIT(0)); -			udelay(timeout_us); -		} +		if (pll_ready) +			break; + +		udelay(timeout_us);  	} -	DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); +out: +	DBG("DSI PLL is %slocked, %sready", pll_locked ? "" : "*not* ", pll_ready ? "" : "*not* "); -	return pll_locked; +	return pll_locked && pll_ready;  }  static void dsi_pll_14nm_config_init(struct dsi_pll_config *pconf) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index aaa37456f4ee..71ed4aa0dc67 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -428,7 +428,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov  	bytediv->reg = pll_28nm->phy->pll_base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9;  	snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->phy->id); -	snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->phy->id); +	snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->phy->id + 1);  	bytediv_init.name = clk_name;  	bytediv_init.ops = &clk_bytediv_ops; @@ -442,7 +442,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **prov  		return ret;  	provided_clocks[DSI_BYTE_PLL_CLK] = &bytediv->hw; -	snprintf(clk_name, 32, "dsi%dpll", pll_28nm->phy->id); +	snprintf(clk_name, 32, "dsi%dpll", pll_28nm->phy->id + 1);  	/* DIV3 */  	hw = devm_clk_hw_register_divider(dev, clk_name,  				parent_name, 0, pll_28nm->phy->pll_base + diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 4fb397ee7c84..fe1366b4c49f 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -1116,7 +1116,7 @@ void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on)  int msm_edp_ctrl_init(struct msm_edp *edp)  {  	struct edp_ctrl *ctrl = NULL; -	struct device *dev = &edp->pdev->dev; +	struct device *dev;  	int ret;  	if (!edp) { @@ -1124,6 +1124,7 @@ int msm_edp_ctrl_init(struct msm_edp *edp)  		return -EINVAL;  	} +	dev = &edp->pdev->dev;  	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);  	if (!ctrl)  		return -ENOMEM; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 2e6fc185e54d..d4e09703a87d 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -630,10 +630,11 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)  	if (ret)  		goto err_msm_uninit; -	ret = msm_disp_snapshot_init(ddev); -	if (ret) -		DRM_DEV_ERROR(dev, "msm_disp_snapshot_init failed ret = %d\n", ret); - +	if (kms) { +		ret = msm_disp_snapshot_init(ddev); +		if (ret) +			DRM_DEV_ERROR(dev, "msm_disp_snapshot_init failed ret = %d\n", ret); +	}  	drm_mode_config_reset(ddev);  #ifdef CONFIG_DRM_FBDEV_EMULATION @@ -682,6 +683,7 @@ static void load_gpu(struct drm_device *dev)  static int context_init(struct drm_device *dev, struct drm_file *file)  { +	static atomic_t ident = ATOMIC_INIT(0);  	struct msm_drm_private *priv = dev->dev_private;  	struct msm_file_private *ctx; @@ -689,12 +691,17 @@ static int context_init(struct drm_device *dev, struct drm_file *file)  	if (!ctx)  		return -ENOMEM; +	INIT_LIST_HEAD(&ctx->submitqueues); +	rwlock_init(&ctx->queuelock); +  	kref_init(&ctx->ref);  	msm_submitqueue_init(dev, ctx);  	ctx->aspace = msm_gpu_create_private_address_space(priv->gpu, current);  	file->driver_priv = ctx; +	ctx->seqno = atomic_inc_return(&ident); +  	return 0;  } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 8b005d1ac899..c552f0c3890c 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -53,14 +53,6 @@ struct msm_disp_state;  #define FRAC_16_16(mult, div)    (((mult) << 16) / (div)) -struct msm_file_private { -	rwlock_t queuelock; -	struct list_head submitqueues; -	int queueid; -	struct msm_gem_address_space *aspace; -	struct kref ref; -}; -  enum msm_mdp_plane_property {  	PLANE_PROP_ZPOS,  	PLANE_PROP_ALPHA, @@ -488,41 +480,6 @@ void msm_writel(u32 data, void __iomem *addr);  u32 msm_readl(const void __iomem *addr);  void msm_rmw(void __iomem *addr, u32 mask, u32 or); -struct msm_gpu_submitqueue; -int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx); -struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_file_private *ctx, -		u32 id); -int msm_submitqueue_create(struct drm_device *drm, -		struct msm_file_private *ctx, -		u32 prio, u32 flags, u32 *id); -int msm_submitqueue_query(struct drm_device *drm, struct msm_file_private *ctx, -		struct drm_msm_submitqueue_query *args); -int msm_submitqueue_remove(struct msm_file_private *ctx, u32 id); -void msm_submitqueue_close(struct msm_file_private *ctx); - -void msm_submitqueue_destroy(struct kref *kref); - -static inline void __msm_file_private_destroy(struct kref *kref) -{ -	struct msm_file_private *ctx = container_of(kref, -		struct msm_file_private, ref); - -	msm_gem_address_space_put(ctx->aspace); -	kfree(ctx); -} - -static inline void msm_file_private_put(struct msm_file_private *ctx) -{ -	kref_put(&ctx->ref, __msm_file_private_destroy); -} - -static inline struct msm_file_private *msm_file_private_get( -	struct msm_file_private *ctx) -{ -	kref_get(&ctx->ref); -	return ctx; -} -  #define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)  #define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__) @@ -547,7 +504,7 @@ static inline int align_pitch(int width, int bpp)  static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)  {  	ktime_t now = ktime_get(); -	unsigned long remaining_jiffies; +	s64 remaining_jiffies;  	if (ktime_compare(*timeout, now) < 0) {  		remaining_jiffies = 0; @@ -556,7 +513,7 @@ static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)  		remaining_jiffies = ktime_divns(rem, NSEC_PER_SEC / HZ);  	} -	return remaining_jiffies; +	return clamp(remaining_jiffies, 0LL, (s64)INT_MAX);  }  #endif /* __MSM_DRV_H__ */ diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index fdc5367aecaa..151d19e4453c 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -46,7 +46,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,  	if (!submit)  		return ERR_PTR(-ENOMEM); -	ret = drm_sched_job_init(&submit->base, &queue->entity, queue); +	ret = drm_sched_job_init(&submit->base, queue->entity, queue);  	if (ret) {  		kfree(submit);  		return ERR_PTR(ret); @@ -171,7 +171,8 @@ out:  static int submit_lookup_cmds(struct msm_gem_submit *submit,  		struct drm_msm_gem_submit *args, struct drm_file *file)  { -	unsigned i, sz; +	unsigned i; +	size_t sz;  	int ret = 0;  	for (i = 0; i < args->nr_cmds; i++) { @@ -907,7 +908,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,  	/* The scheduler owns a ref now: */  	msm_gem_submit_get(submit); -	drm_sched_entity_push_job(&submit->base, &queue->entity); +	drm_sched_entity_push_job(&submit->base, queue->entity);  	args->fence = submit->fence_id; diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 0e4b45bff2e6..ee25d556c8a1 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -203,6 +203,10 @@ struct msm_gpu {  	uint32_t suspend_count;  	struct msm_gpu_state *crashstate; + +	/* Enable clamping to idle freq when inactive: */ +	bool clamp_to_idle; +  	/* True if the hardware supports expanded apriv (a650 and newer) */  	bool hw_apriv; @@ -258,6 +262,39 @@ struct msm_gpu_perfcntr {  #define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_HIGH - DRM_SCHED_PRIORITY_MIN)  /** + * struct msm_file_private - per-drm_file context + * + * @queuelock:    synchronizes access to submitqueues list + * @submitqueues: list of &msm_gpu_submitqueue created by userspace + * @queueid:      counter incremented each time a submitqueue is created, + *                used to assign &msm_gpu_submitqueue.id + * @aspace:       the per-process GPU address-space + * @ref:          reference count + * @seqno:        unique per process seqno + */ +struct msm_file_private { +	rwlock_t queuelock; +	struct list_head submitqueues; +	int queueid; +	struct msm_gem_address_space *aspace; +	struct kref ref; +	int seqno; + +	/** +	 * entities: +	 * +	 * Table of per-priority-level sched entities used by submitqueues +	 * associated with this &drm_file.  Because some userspace apps +	 * make assumptions about rendering from multiple gl contexts +	 * (of the same priority) within the process happening in FIFO +	 * order without requiring any fencing beyond MakeCurrent(), we +	 * create at most one &drm_sched_entity per-process per-priority- +	 * level. +	 */ +	struct drm_sched_entity *entities[NR_SCHED_PRIORITIES * MSM_GPU_MAX_RINGS]; +}; + +/**   * msm_gpu_convert_priority - Map userspace priority to ring # and sched priority   *   * @gpu:        the gpu instance @@ -304,6 +341,8 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio,  }  /** + * struct msm_gpu_submitqueues - Userspace created context. + *   * A submitqueue is associated with a gl context or vk queue (or equiv)   * in userspace.   * @@ -321,7 +360,7 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio,   *             seqno, protected by submitqueue lock   * @lock:      submitqueue lock   * @ref:       reference count - * @entity: the submit job-queue + * @entity:    the submit job-queue   */  struct msm_gpu_submitqueue {  	int id; @@ -333,7 +372,7 @@ struct msm_gpu_submitqueue {  	struct idr fence_idr;  	struct mutex lock;  	struct kref ref; -	struct drm_sched_entity entity; +	struct drm_sched_entity *entity;  };  struct msm_gpu_state_bo { @@ -421,6 +460,33 @@ static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)  int msm_gpu_pm_suspend(struct msm_gpu *gpu);  int msm_gpu_pm_resume(struct msm_gpu *gpu); +int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx); +struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_file_private *ctx, +		u32 id); +int msm_submitqueue_create(struct drm_device *drm, +		struct msm_file_private *ctx, +		u32 prio, u32 flags, u32 *id); +int msm_submitqueue_query(struct drm_device *drm, struct msm_file_private *ctx, +		struct drm_msm_submitqueue_query *args); +int msm_submitqueue_remove(struct msm_file_private *ctx, u32 id); +void msm_submitqueue_close(struct msm_file_private *ctx); + +void msm_submitqueue_destroy(struct kref *kref); + +void __msm_file_private_destroy(struct kref *kref); + +static inline void msm_file_private_put(struct msm_file_private *ctx) +{ +	kref_put(&ctx->ref, __msm_file_private_destroy); +} + +static inline struct msm_file_private *msm_file_private_get( +	struct msm_file_private *ctx) +{ +	kref_get(&ctx->ref); +	return ctx; +} +  void msm_devfreq_init(struct msm_gpu *gpu);  void msm_devfreq_cleanup(struct msm_gpu *gpu);  void msm_devfreq_resume(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index 0a1ee20296a2..20006d060b5b 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -151,6 +151,9 @@ void msm_devfreq_active(struct msm_gpu *gpu)  	unsigned int idle_time;  	unsigned long target_freq = df->idle_freq; +	if (!df->devfreq) +		return; +  	/*  	 * Hold devfreq lock to synchronize with get_dev_status()/  	 * target() callbacks @@ -186,6 +189,9 @@ void msm_devfreq_idle(struct msm_gpu *gpu)  	struct msm_gpu_devfreq *df = &gpu->devfreq;  	unsigned long idle_freq, target_freq = 0; +	if (!df->devfreq) +		return; +  	/*  	 * Hold devfreq lock to synchronize with get_dev_status()/  	 * target() callbacks @@ -194,7 +200,8 @@ void msm_devfreq_idle(struct msm_gpu *gpu)  	idle_freq = get_freq(gpu); -	msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); +	if (gpu->clamp_to_idle) +		msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0);  	df->idle_time = ktime_get();  	df->idle_freq = idle_freq; diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/msm/msm_submitqueue.c index 32a55d81b58b..b8621c6e0554 100644 --- a/drivers/gpu/drm/msm/msm_submitqueue.c +++ b/drivers/gpu/drm/msm/msm_submitqueue.c @@ -7,6 +7,24 @@  #include "msm_gpu.h" +void __msm_file_private_destroy(struct kref *kref) +{ +	struct msm_file_private *ctx = container_of(kref, +		struct msm_file_private, ref); +	int i; + +	for (i = 0; i < ARRAY_SIZE(ctx->entities); i++) { +		if (!ctx->entities[i]) +			continue; + +		drm_sched_entity_destroy(ctx->entities[i]); +		kfree(ctx->entities[i]); +	} + +	msm_gem_address_space_put(ctx->aspace); +	kfree(ctx); +} +  void msm_submitqueue_destroy(struct kref *kref)  {  	struct msm_gpu_submitqueue *queue = container_of(kref, @@ -14,8 +32,6 @@ void msm_submitqueue_destroy(struct kref *kref)  	idr_destroy(&queue->fence_idr); -	drm_sched_entity_destroy(&queue->entity); -  	msm_file_private_put(queue->ctx);  	kfree(queue); @@ -61,13 +77,47 @@ void msm_submitqueue_close(struct msm_file_private *ctx)  	}  } +static struct drm_sched_entity * +get_sched_entity(struct msm_file_private *ctx, struct msm_ringbuffer *ring, +		 unsigned ring_nr, enum drm_sched_priority sched_prio) +{ +	static DEFINE_MUTEX(entity_lock); +	unsigned idx = (ring_nr * NR_SCHED_PRIORITIES) + sched_prio; + +	/* We should have already validated that the requested priority is +	 * valid by the time we get here. +	 */ +	if (WARN_ON(idx >= ARRAY_SIZE(ctx->entities))) +		return ERR_PTR(-EINVAL); + +	mutex_lock(&entity_lock); + +	if (!ctx->entities[idx]) { +		struct drm_sched_entity *entity; +		struct drm_gpu_scheduler *sched = &ring->sched; +		int ret; + +		entity = kzalloc(sizeof(*ctx->entities[idx]), GFP_KERNEL); + +		ret = drm_sched_entity_init(entity, sched_prio, &sched, 1, NULL); +		if (ret) { +			kfree(entity); +			return ERR_PTR(ret); +		} + +		ctx->entities[idx] = entity; +	} + +	mutex_unlock(&entity_lock); + +	return ctx->entities[idx]; +} +  int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,  		u32 prio, u32 flags, u32 *id)  {  	struct msm_drm_private *priv = drm->dev_private;  	struct msm_gpu_submitqueue *queue; -	struct msm_ringbuffer *ring; -	struct drm_gpu_scheduler *sched;  	enum drm_sched_priority sched_prio;  	unsigned ring_nr;  	int ret; @@ -91,12 +141,10 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,  	queue->flags = flags;  	queue->ring_nr = ring_nr; -	ring = priv->gpu->rb[ring_nr]; -	sched = &ring->sched; - -	ret = drm_sched_entity_init(&queue->entity, -			sched_prio, &sched, 1, NULL); -	if (ret) { +	queue->entity = get_sched_entity(ctx, priv->gpu->rb[ring_nr], +					 ring_nr, sched_prio); +	if (IS_ERR(queue->entity)) { +		ret = PTR_ERR(queue->entity);  		kfree(queue);  		return ret;  	} @@ -140,10 +188,6 @@ int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx)  	 */  	default_prio = DIV_ROUND_UP(max_priority, 2); -	INIT_LIST_HEAD(&ctx->submitqueues); - -	rwlock_init(&ctx->queuelock); -  	return msm_submitqueue_create(drm, ctx, default_prio, 0, NULL);  } diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index ec0432fe1bdf..86d78634a979 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -173,7 +173,11 @@ static void mxsfb_irq_disable(struct drm_device *drm)  	struct mxsfb_drm_private *mxsfb = drm->dev_private;  	mxsfb_enable_axi_clk(mxsfb); -	mxsfb->crtc.funcs->disable_vblank(&mxsfb->crtc); + +	/* Disable and clear VBLANK IRQ */ +	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); +	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); +  	mxsfb_disable_axi_clk(mxsfb);  } diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index b8c31b697797..66f32d965c72 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -704,6 +704,7 @@ static const struct file_operations nv50_crc_flip_threshold_fops = {  	.open = nv50_crc_debugfs_flip_threshold_open,  	.read = seq_read,  	.write = nv50_crc_debugfs_flip_threshold_set, +	.release = single_release,  };  int nv50_head_crc_late_register(struct nv50_head *head) diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index d66f97280282..72099d1e4816 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -52,6 +52,7 @@ nv50_head_flush_clr(struct nv50_head *head,  void  nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh)  { +	if (asyh->set.curs   ) head->func->curs_set(head, asyh);  	if (asyh->set.olut   ) {  		asyh->olut.offset = nv50_lut_load(&head->olut,  						  asyh->olut.buffer, @@ -67,7 +68,6 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)  	if (asyh->set.view   ) head->func->view    (head, asyh);  	if (asyh->set.mode   ) head->func->mode    (head, asyh);  	if (asyh->set.core   ) head->func->core_set(head, asyh); -	if (asyh->set.curs   ) head->func->curs_set(head, asyh);  	if (asyh->set.base   ) head->func->base    (head, asyh);  	if (asyh->set.ovly   ) head->func->ovly    (head, asyh);  	if (asyh->set.dither ) head->func->dither  (head, asyh); diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index c68cc957248e..a582c0cb0cb0 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -71,6 +71,7 @@  #define PASCAL_CHANNEL_GPFIFO_A                       /* cla06f.h */ 0x0000c06f  #define VOLTA_CHANNEL_GPFIFO_A                        /* clc36f.h */ 0x0000c36f  #define TURING_CHANNEL_GPFIFO_A                       /* clc36f.h */ 0x0000c46f +#define AMPERE_CHANNEL_GPFIFO_B                       /* clc36f.h */ 0x0000c76f  #define NV50_DISP                                     /* cl5070.h */ 0x00005070  #define G82_DISP                                      /* cl5070.h */ 0x00008270 @@ -200,6 +201,7 @@  #define PASCAL_DMA_COPY_B                                            0x0000c1b5  #define VOLTA_DMA_COPY_A                                             0x0000c3b5  #define TURING_DMA_COPY_A                                            0x0000c5b5 +#define AMPERE_DMA_COPY_B                                            0x0000c7b5  #define FERMI_DECOMPRESS                                             0x000090b8 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 54fab7cc36c1..64ee82c7c1be 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -77,4 +77,5 @@ int gp100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct  int gp10b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);  int gv100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);  int tu102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **); +int ga102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);  #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6d07e653f82d..c58bcdba2c7a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -844,6 +844,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)  			    struct ttm_resource *, struct ttm_resource *);  		int (*init)(struct nouveau_channel *, u32 handle);  	} _methods[] = { +		{  "COPY", 4, 0xc7b5, nve0_bo_move_copy, nve0_bo_move_init },  		{  "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },  		{  "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init },  		{  "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init }, diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 80099ef75702..ea7769135b0d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -250,7 +250,8 @@ static int  nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,  		    u64 runlist, bool priv, struct nouveau_channel **pchan)  { -	static const u16 oclasses[] = { TURING_CHANNEL_GPFIFO_A, +	static const u16 oclasses[] = { AMPERE_CHANNEL_GPFIFO_B, +					TURING_CHANNEL_GPFIFO_A,  					VOLTA_CHANNEL_GPFIFO_A,  					PASCAL_CHANNEL_GPFIFO_A,  					MAXWELL_CHANNEL_GPFIFO_A, @@ -386,7 +387,8 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)  	nvif_object_map(&chan->user, NULL, 0); -	if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) { +	if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO && +	    chan->user.oclass < AMPERE_CHANNEL_GPFIFO_B) {  		ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled",  				       nouveau_channel_killed,  				       true, NV906F_V0_NTFY_KILLED, diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index c2bc05eb2e54..1cbe01048b93 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -207,6 +207,7 @@ static const struct file_operations nouveau_pstate_fops = {  	.open = nouveau_debugfs_pstate_open,  	.read = seq_read,  	.write = nouveau_debugfs_pstate_set, +	.release = single_release,  };  static struct drm_info_list nouveau_debugfs_list[] = { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 1f828c9f691c..6109cd9e3399 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -345,6 +345,9 @@ nouveau_accel_gr_init(struct nouveau_drm *drm)  	u32 arg0, arg1;  	int ret; +	if (device->info.family >= NV_DEVICE_INFO_V0_AMPERE) +		return; +  	/* Allocate channel that has access to the graphics engine. */  	if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {  		arg0 = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR); @@ -469,6 +472,7 @@ nouveau_accel_init(struct nouveau_drm *drm)  		case PASCAL_CHANNEL_GPFIFO_A:  		case VOLTA_CHANNEL_GPFIFO_A:  		case TURING_CHANNEL_GPFIFO_A: +		case AMPERE_CHANNEL_GPFIFO_B:  			ret = nvc0_fence_create(drm);  			break;  		default: diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5b27845075a1..8c2ecc282723 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -247,10 +247,8 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain,  	}  	ret = nouveau_bo_init(nvbo, size, align, domain, NULL, NULL); -	if (ret) { -		nouveau_bo_ref(NULL, &nvbo); +	if (ret)  		return ret; -	}  	/* we restrict allowed domains on nv50+ to only the types  	 * that were requested at creation time.  not possibly on diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index b0c3422cb01f..1a896a24288a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -992,7 +992,7 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id)  	if (ret)  		return ret; -	buffer->fault = kvzalloc(sizeof(*buffer->fault) * buffer->entries, GFP_KERNEL); +	buffer->fault = kvcalloc(sizeof(*buffer->fault), buffer->entries, GFP_KERNEL);  	if (!buffer->fault)  		return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 7c9c928c3196..c3526a8622e3 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -204,7 +204,7 @@ nv84_fence_create(struct nouveau_drm *drm)  	priv->base.context_new = nv84_fence_context_new;  	priv->base.context_del = nv84_fence_context_del; -	priv->base.uevent = true; +	priv->base.uevent = drm->client.device.info.family < NV_DEVICE_INFO_V0_AMPERE;  	mutex_init(&priv->mutex); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 93ddf63d1114..ca75c5f6ecaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2602,6 +2602,7 @@ nv172_chipset = {  	.top      = { 0x00000001, ga100_top_new },  	.disp     = { 0x00000001, ga102_disp_new },  	.dma      = { 0x00000001, gv100_dma_new }, +	.fifo     = { 0x00000001, ga102_fifo_new },  };  static const struct nvkm_device_chip @@ -2622,6 +2623,7 @@ nv174_chipset = {  	.top      = { 0x00000001, ga100_top_new },  	.disp     = { 0x00000001, ga102_disp_new },  	.dma      = { 0x00000001, gv100_dma_new }, +	.fifo     = { 0x00000001, ga102_fifo_new },  };  static const struct nvkm_device_chip @@ -2642,6 +2644,7 @@ nv177_chipset = {  	.top      = { 0x00000001, ga100_top_new },  	.disp     = { 0x00000001, ga102_disp_new },  	.dma      = { 0x00000001, gv100_dma_new }, +	.fifo     = { 0x00000001, ga102_fifo_new },  };  static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c index b0ece71aefde..ce774579c89d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c @@ -57,7 +57,7 @@ nvkm_control_mthd_pstate_info(struct nvkm_control *ctrl, void *data, u32 size)  		args->v0.count = 0;  		args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;  		args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE; -		args->v0.pwrsrc = -ENOSYS; +		args->v0.pwrsrc = -ENODEV;  		args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;  	} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 3209eb7af65f..5e831d347a95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -18,6 +18,7 @@ nvkm-y += nvkm/engine/fifo/gp100.o  nvkm-y += nvkm/engine/fifo/gp10b.o  nvkm-y += nvkm/engine/fifo/gv100.o  nvkm-y += nvkm/engine/fifo/tu102.o +nvkm-y += nvkm/engine/fifo/ga102.o  nvkm-y += nvkm/engine/fifo/chan.o  nvkm-y += nvkm/engine/fifo/channv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c index 353b77d9b3dc..3492c561f2cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c @@ -82,7 +82,7 @@ g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base,  	if (offset < 0)  		return 0; -	engn = fifo->base.func->engine_id(&fifo->base, engine); +	engn = fifo->base.func->engine_id(&fifo->base, engine) - 1;  	save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn);  	nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12);  	done = nvkm_msec(device, 2000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c new file mode 100644 index 000000000000..c630dbd2911a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c @@ -0,0 +1,311 @@ +/* + * Copyright 2021 Red Hat 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. + */ +#define ga102_fifo(p) container_of((p), struct ga102_fifo, base.engine) +#define ga102_chan(p) container_of((p), struct ga102_chan, object) +#include <engine/fifo.h> +#include "user.h" + +#include <core/memory.h> +#include <subdev/mmu.h> +#include <subdev/timer.h> +#include <subdev/top.h> + +#include <nvif/cl0080.h> +#include <nvif/clc36f.h> +#include <nvif/class.h> + +struct ga102_fifo { +	struct nvkm_fifo base; +}; + +struct ga102_chan { +	struct nvkm_object object; + +	struct { +		u32 runl; +		u32 chan; +	} ctrl; + +	struct nvkm_memory *mthd; +	struct nvkm_memory *inst; +	struct nvkm_memory *user; +	struct nvkm_memory *runl; + +	struct nvkm_vmm *vmm; +}; + +static int +ga102_chan_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) +{ +	if (index == 0) { +		oclass->ctor = nvkm_object_new; +		oclass->base = (struct nvkm_sclass) { -1, -1, AMPERE_DMA_COPY_B }; +		return 0; +	} + +	return -EINVAL; +} + +static int +ga102_chan_map(struct nvkm_object *object, void *argv, u32 argc, +	       enum nvkm_object_map *type, u64 *addr, u64 *size) +{ +	struct ga102_chan *chan = ga102_chan(object); +	struct nvkm_device *device = chan->object.engine->subdev.device; +	u64 bar2 = nvkm_memory_bar2(chan->user); + +	if (bar2 == ~0ULL) +		return -EFAULT; + +	*type = NVKM_OBJECT_MAP_IO; +	*addr = device->func->resource_addr(device, 3) + bar2; +	*size = 0x1000; +	return 0; +} + +static int +ga102_chan_fini(struct nvkm_object *object, bool suspend) +{ +	struct ga102_chan *chan = ga102_chan(object); +	struct nvkm_device *device = chan->object.engine->subdev.device; + +	nvkm_wr32(device, chan->ctrl.chan, 0x00000003); + +	nvkm_wr32(device, chan->ctrl.runl + 0x098, 0x01000000); +	nvkm_msec(device, 2000, +		if (!(nvkm_rd32(device, chan->ctrl.runl + 0x098) & 0x00100000)) +			break; +	); + +	nvkm_wr32(device, chan->ctrl.runl + 0x088, 0); + +	nvkm_wr32(device, chan->ctrl.chan, 0xffffffff); +	return 0; +} + +static int +ga102_chan_init(struct nvkm_object *object) +{ +	struct ga102_chan *chan = ga102_chan(object); +	struct nvkm_device *device = chan->object.engine->subdev.device; + +	nvkm_mask(device, chan->ctrl.runl + 0x300, 0x80000000, 0x80000000); + +	nvkm_wr32(device, chan->ctrl.runl + 0x080, lower_32_bits(nvkm_memory_addr(chan->runl))); +	nvkm_wr32(device, chan->ctrl.runl + 0x084, upper_32_bits(nvkm_memory_addr(chan->runl))); +	nvkm_wr32(device, chan->ctrl.runl + 0x088, 2); + +	nvkm_wr32(device, chan->ctrl.chan, 0x00000002); +	nvkm_wr32(device, chan->ctrl.runl + 0x0090, 0); +	return 0; +} + +static void * +ga102_chan_dtor(struct nvkm_object *object) +{ +	struct ga102_chan *chan = ga102_chan(object); + +	if (chan->vmm) { +		nvkm_vmm_part(chan->vmm, chan->inst); +		nvkm_vmm_unref(&chan->vmm); +	} + +	nvkm_memory_unref(&chan->runl); +	nvkm_memory_unref(&chan->user); +	nvkm_memory_unref(&chan->inst); +	nvkm_memory_unref(&chan->mthd); +	return chan; +} + +static const struct nvkm_object_func +ga102_chan = { +	.dtor = ga102_chan_dtor, +	.init = ga102_chan_init, +	.fini = ga102_chan_fini, +	.map = ga102_chan_map, +	.sclass = ga102_chan_sclass, +}; + +static int +ga102_chan_new(struct nvkm_device *device, +	       const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) +{ +	struct volta_channel_gpfifo_a_v0 *args = argv; +	struct nvkm_top_device *tdev; +	struct nvkm_vmm *vmm; +	struct ga102_chan *chan; +	int ret; + +	if (argc != sizeof(*args)) +		return -ENOSYS; + +	vmm = nvkm_uvmm_search(oclass->client, args->vmm); +	if (IS_ERR(vmm)) +		return PTR_ERR(vmm); + +	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) +		return -ENOMEM; + +	nvkm_object_ctor(&ga102_chan, oclass, &chan->object); +	*pobject = &chan->object; + +	list_for_each_entry(tdev, &device->top->device, head) { +		if (tdev->type == NVKM_ENGINE_CE) { +			chan->ctrl.runl = tdev->runlist; +			break; +		} +	} + +	if (!chan->ctrl.runl) +		return -ENODEV; + +	chan->ctrl.chan = nvkm_rd32(device, chan->ctrl.runl + 0x004) & 0xfffffff0; + +	args->chid = 0; +	args->inst = 0; +	args->token = nvkm_rd32(device, chan->ctrl.runl + 0x008) & 0xffff0000; + +	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->mthd); +	if (ret) +		return ret; + +	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->inst); +	if (ret) +		return ret; + +	nvkm_kmap(chan->inst); +	nvkm_wo32(chan->inst, 0x010, 0x0000face); +	nvkm_wo32(chan->inst, 0x030, 0x7ffff902); +	nvkm_wo32(chan->inst, 0x048, lower_32_bits(args->ioffset)); +	nvkm_wo32(chan->inst, 0x04c, upper_32_bits(args->ioffset) | +				     (order_base_2(args->ilength / 8) << 16)); +	nvkm_wo32(chan->inst, 0x084, 0x20400000); +	nvkm_wo32(chan->inst, 0x094, 0x30000001); +	nvkm_wo32(chan->inst, 0x0ac, 0x00020000); +	nvkm_wo32(chan->inst, 0x0e4, 0x00000000); +	nvkm_wo32(chan->inst, 0x0e8, 0); +	nvkm_wo32(chan->inst, 0x0f4, 0x00001000); +	nvkm_wo32(chan->inst, 0x0f8, 0x10003080); +	nvkm_mo32(chan->inst, 0x218, 0x00000000, 0x00000000); +	nvkm_wo32(chan->inst, 0x220, lower_32_bits(nvkm_memory_bar2(chan->mthd))); +	nvkm_wo32(chan->inst, 0x224, upper_32_bits(nvkm_memory_bar2(chan->mthd))); +	nvkm_done(chan->inst); + +	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->user); +	if (ret) +		return ret; + +	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, true, &chan->runl); +	if (ret) +		return ret; + +	nvkm_kmap(chan->runl); +	nvkm_wo32(chan->runl, 0x00, 0x80030001); +	nvkm_wo32(chan->runl, 0x04, 1); +	nvkm_wo32(chan->runl, 0x08, 0); +	nvkm_wo32(chan->runl, 0x0c, 0x00000000); +	nvkm_wo32(chan->runl, 0x10, lower_32_bits(nvkm_memory_addr(chan->user))); +	nvkm_wo32(chan->runl, 0x14, upper_32_bits(nvkm_memory_addr(chan->user))); +	nvkm_wo32(chan->runl, 0x18, lower_32_bits(nvkm_memory_addr(chan->inst))); +	nvkm_wo32(chan->runl, 0x1c, upper_32_bits(nvkm_memory_addr(chan->inst))); +	nvkm_done(chan->runl); + +	ret = nvkm_vmm_join(vmm, chan->inst); +	if (ret) +		return ret; + +	chan->vmm = nvkm_vmm_ref(vmm); +	return 0; +} + +static const struct nvkm_device_oclass +ga102_chan_oclass = { +	.ctor = ga102_chan_new, +}; + +static int +ga102_user_new(struct nvkm_device *device, +	       const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) +{ +	return tu102_fifo_user_new(oclass, argv, argc, pobject); +} + +static const struct nvkm_device_oclass +ga102_user_oclass = { +	.ctor = ga102_user_new, +}; + +static int +ga102_fifo_sclass(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class) +{ +	if (index == 0) { +		oclass->base = (struct nvkm_sclass) { -1, -1, VOLTA_USERMODE_A }; +		*class = &ga102_user_oclass; +		return 0; +	} else +	if (index == 1) { +		oclass->base = (struct nvkm_sclass) { 0, 0, AMPERE_CHANNEL_GPFIFO_B }; +		*class = &ga102_chan_oclass; +		return 0; +	} + +	return 2; +} + +static int +ga102_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data) +{ +	switch (mthd) { +	case NV_DEVICE_HOST_CHANNELS: *data = 1; return 0; +	default: +		break; +	} + +	return -ENOSYS; +} + +static void * +ga102_fifo_dtor(struct nvkm_engine *engine) +{ +	return ga102_fifo(engine); +} + +static const struct nvkm_engine_func +ga102_fifo = { +	.dtor = ga102_fifo_dtor, +	.info = ga102_fifo_info, +	.base.sclass = ga102_fifo_sclass, +}; + +int +ga102_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, +	       struct nvkm_fifo **pfifo) +{ +	struct ga102_fifo *fifo; + +	if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) +		return -ENOMEM; + +	nvkm_engine_ctor(&ga102_fifo, device, type, inst, true, &fifo->base.engine); +	*pfifo = &fifo->base; +	return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c index 31933f3e5a07..c982d834c8d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/ga100.c @@ -54,7 +54,7 @@ ga100_top_oneinit(struct nvkm_top *top)  			info->reset   = (data & 0x0000001f);  			break;  		case 2: -			info->runlist = (data & 0x0000fc00) >> 10; +			info->runlist = (data & 0x00fffc00);  			info->engine  = (data & 0x00000003);  			break;  		default: @@ -85,9 +85,10 @@ ga100_top_oneinit(struct nvkm_top *top)  		}  		nvkm_debug(subdev, "%02x.%d (%8s): addr %06x fault %2d " -				   "runlist %2d engine %2d reset %2d\n", type, inst, +				   "runlist %6x engine %2d reset %2d\n", type, inst,  			   info->type == NVKM_SUBDEV_NR ? "????????" : nvkm_subdev_type[info->type], -			   info->addr, info->fault, info->runlist, info->engine, info->reset); +			   info->addr, info->fault, info->runlist < 0 ? 0 : info->runlist, +			   info->engine, info->reset);  		info = NULL;  	} diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index beb581b96ecd..418638e6e3b0 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -295,6 +295,7 @@ config DRM_PANEL_OLIMEX_LCD_OLINUXINO  	depends on OF  	depends on I2C  	depends on BACKLIGHT_CLASS_DEVICE +	select CRC32  	help  	  The panel is used with different sizes LCDs, from 480x272 to  	  1280x800, and 24 bit per pixel. diff --git a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c index 2d8794d495d0..3d8a9ab47cae 100644 --- a/drivers/gpu/drm/panel/panel-abt-y030xx067a.c +++ b/drivers/gpu/drm/panel/panel-abt-y030xx067a.c @@ -146,8 +146,8 @@ static const struct reg_sequence y030xx067a_init_sequence[] = {  	{ 0x09, REG09_SUB_BRIGHT_R(0x20) },  	{ 0x0a, REG0A_SUB_BRIGHT_B(0x20) },  	{ 0x0b, REG0B_HD_FREERUN | REG0B_VD_FREERUN }, -	{ 0x0c, REG0C_CONTRAST_R(0x10) }, -	{ 0x0d, REG0D_CONTRAST_G(0x10) }, +	{ 0x0c, REG0C_CONTRAST_R(0x00) }, +	{ 0x0d, REG0D_CONTRAST_G(0x00) },  	{ 0x0e, REG0E_CONTRAST_B(0x10) },  	{ 0x0f, 0 },  	{ 0x10, REG10_BRIGHT(0x7f) }, diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 0145129d7c66..534dd7414d42 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -590,14 +590,14 @@ static const struct drm_display_mode k101_im2byl02_default_mode = {  	.clock		= 69700,  	.hdisplay	= 800, -	.hsync_start	= 800 + 6, -	.hsync_end	= 800 + 6 + 15, -	.htotal		= 800 + 6 + 15 + 16, +	.hsync_start	= 800 + 52, +	.hsync_end	= 800 + 52 + 8, +	.htotal		= 800 + 52 + 8 + 48,  	.vdisplay	= 1280, -	.vsync_start	= 1280 + 8, -	.vsync_end	= 1280 + 8 + 48, -	.vtotal		= 1280 + 8 + 48 + 52, +	.vsync_start	= 1280 + 16, +	.vsync_end	= 1280 + 16 + 6, +	.vtotal		= 1280 + 16 + 6 + 15,  	.width_mm	= 135,  	.height_mm	= 217, diff --git a/drivers/gpu/drm/r128/ati_pcigart.c b/drivers/gpu/drm/r128/ati_pcigart.c index 0ecccf25a3c7..d2a0f5394fef 100644 --- a/drivers/gpu/drm/r128/ati_pcigart.c +++ b/drivers/gpu/drm/r128/ati_pcigart.c @@ -214,7 +214,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga  	}  	ret = 0; -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_X86  	wbinvd();  #else  	mb(); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 0473583dcdac..482fb0ae6cb5 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -119,7 +119,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)  #endif  	if (pci_find_capability(pdev, PCI_CAP_ID_AGP)) -		rdev->agp = radeon_agp_head_init(rdev->ddev); +		rdev->agp = radeon_agp_head_init(dev);  	if (rdev->agp) {  		rdev->agp->agp_mtrr = arch_phys_wc_add(  			rdev->agp->agp_info.aper_base, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 0daa8bba50f5..4bf4e25d7f01 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -86,12 +86,20 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,  	}  	/* -	 * Create and initialize the encoder. On Gen3 skip the LVDS1 output if +	 * Create and initialize the encoder. On Gen3, skip the LVDS1 output if  	 * the LVDS1 encoder is used as a companion for LVDS0 in dual-link -	 * mode. +	 * mode, or any LVDS output if it isn't connected. The latter may happen +	 * on D3 or E3 as the LVDS encoders are needed to provide the pixel +	 * clock to the DU, even when the LVDS outputs are not used.  	 */ -	if (rcdu->info->gen >= 3 && output == RCAR_DU_OUTPUT_LVDS1) { -		if (rcar_lvds_dual_link(bridge)) +	if (rcdu->info->gen >= 3) { +		if (output == RCAR_DU_OUTPUT_LVDS1 && +		    rcar_lvds_dual_link(bridge)) +			return -ENOLINK; + +		if ((output == RCAR_DU_OUTPUT_LVDS0 || +		     output == RCAR_DU_OUTPUT_LVDS1) && +		    !rcar_lvds_is_connected(bridge))  			return -ENOLINK;  	} diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index d061b8de748f..b672c5bd72ee 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -576,6 +576,9 @@ static int rcar_lvds_attach(struct drm_bridge *bridge,  {  	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); +	if (!lvds->next_bridge) +		return 0; +  	return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge,  				 flags);  } @@ -598,6 +601,14 @@ bool rcar_lvds_dual_link(struct drm_bridge *bridge)  }  EXPORT_SYMBOL_GPL(rcar_lvds_dual_link); +bool rcar_lvds_is_connected(struct drm_bridge *bridge) +{ +	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); + +	return lvds->next_bridge != NULL; +} +EXPORT_SYMBOL_GPL(rcar_lvds_is_connected); +  /* -----------------------------------------------------------------------------   * Probe & Remove   */ diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/rcar-du/rcar_lvds.h index 222ec0e60785..eb7c6ef03b00 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.h @@ -16,6 +16,7 @@ struct drm_bridge;  int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq);  void rcar_lvds_clk_disable(struct drm_bridge *bridge);  bool rcar_lvds_dual_link(struct drm_bridge *bridge); +bool rcar_lvds_is_connected(struct drm_bridge *bridge);  #else  static inline int rcar_lvds_clk_enable(struct drm_bridge *bridge,  				       unsigned long freq) @@ -27,6 +28,10 @@ static inline bool rcar_lvds_dual_link(struct drm_bridge *bridge)  {  	return false;  } +static inline bool rcar_lvds_is_connected(struct drm_bridge *bridge) +{ +	return false; +}  #endif /* CONFIG_DRM_RCAR_LVDS */  #endif /* __RCAR_LVDS_H__ */ diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 8ab3247dbc4a..13c6b857158f 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1123,7 +1123,7 @@ static int cdn_dp_suspend(struct device *dev)  	return ret;  } -static int cdn_dp_resume(struct device *dev) +static __maybe_unused int cdn_dp_resume(struct device *dev)  {  	struct cdn_dp_device *dp = dev_get_drvdata(dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ba9e14da41b4..a25b98b7f5bd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1174,26 +1174,24 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,  	 *  	 * Action plan:  	 * -	 * 1. When DRM gives us a mode, we should add 999 Hz to it.  That way -	 *    if the clock we need is 60000001 Hz (~60 MHz) and DRM tells us to -	 *    make 60000 kHz then the clock framework will actually give us -	 *    the right clock. +	 * 1. Try to set the exact rate first, and confirm the clock framework +	 *    can provide it.  	 * -	 *    NOTE: if the PLL (maybe through a divider) could actually make -	 *    a clock rate 999 Hz higher instead of the one we want then this -	 *    could be a problem.  Unfortunately there's not much we can do -	 *    since it's baked into DRM to use kHz.  It shouldn't matter in -	 *    practice since Rockchip PLLs are controlled by tables and -	 *    even if there is a divider in the middle I wouldn't expect PLL -	 *    rates in the table that are just a few kHz different. +	 * 2. If the clock framework cannot provide the exact rate, we should +	 *    add 999 Hz to the requested rate.  That way if the clock we need +	 *    is 60000001 Hz (~60 MHz) and DRM tells us to make 60000 kHz then +	 *    the clock framework will actually give us the right clock.  	 * -	 * 2. Get the clock framework to round the rate for us to tell us +	 * 3. Get the clock framework to round the rate for us to tell us  	 *    what it will actually make.  	 * -	 * 3. Store the rounded up rate so that we don't need to worry about +	 * 4. Store the rounded up rate so that we don't need to worry about  	 *    this in the actual clk_set_rate().  	 */ -	rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000 + 999); +	rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000); +	if (rate / 1000 != adjusted_mode->clock) +		rate = clk_round_rate(vop->dclk, +				      adjusted_mode->clock * 1000 + 999);  	adjusted_mode->clock = DIV_ROUND_UP(rate, 1000);  	return true; diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c index 1c19a5d3eefb..8d8d8e214c28 100644 --- a/drivers/gpu/drm/selftests/test-drm_damage_helper.c +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c @@ -30,6 +30,7 @@ static void mock_setup(struct drm_plane_state *state)  	mock_device.driver = &mock_driver;  	mock_device.mode_config.prop_fb_damage_clips = &mock_prop;  	mock_plane.dev = &mock_device; +	mock_obj_props.count = 0;  	mock_plane.base.properties = &mock_obj_props;  	mock_prop.base.id = 1; /* 0 is an invalid id */  	mock_prop.dev = &mock_device; diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index f75fb157f2ff..016b877051da 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -216,11 +216,13 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,  		goto err_disable_clk_tmds;  	} +	ret = sun8i_hdmi_phy_init(hdmi->phy); +	if (ret) +		goto err_disable_clk_tmds; +  	drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);  	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); -	sun8i_hdmi_phy_init(hdmi->phy); -  	plat_data->mode_valid = hdmi->quirks->mode_valid;  	plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe;  	sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data); @@ -262,6 +264,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,  	struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);  	dw_hdmi_unbind(hdmi->hdmi); +	sun8i_hdmi_phy_deinit(hdmi->phy);  	clk_disable_unprepare(hdmi->clk_tmds);  	reset_control_assert(hdmi->rst_ctrl);  	gpiod_set_value(hdmi->ddc_en, 0); diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 74f6ed0e2570..bffe1b9cd3dc 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -169,6 +169,7 @@ struct sun8i_hdmi_phy {  	struct clk			*clk_phy;  	struct clk			*clk_pll0;  	struct clk			*clk_pll1; +	struct device			*dev;  	unsigned int			rcal;  	struct regmap			*regs;  	struct reset_control		*rst_phy; @@ -205,7 +206,8 @@ encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)  int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node); -void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); +int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); +void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy);  void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,  			    struct dw_hdmi_plat_data *plat_data); diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index c9239708d398..b64d93da651d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -506,9 +506,60 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)  	phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;  } -void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) +int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)  { +	int ret; + +	ret = reset_control_deassert(phy->rst_phy); +	if (ret) { +		dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret); +		return ret; +	} + +	ret = clk_prepare_enable(phy->clk_bus); +	if (ret) { +		dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret); +		goto err_assert_rst_phy; +	} + +	ret = clk_prepare_enable(phy->clk_mod); +	if (ret) { +		dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret); +		goto err_disable_clk_bus; +	} + +	if (phy->variant->has_phy_clk) { +		ret = sun8i_phy_clk_create(phy, phy->dev, +					   phy->variant->has_second_pll); +		if (ret) { +			dev_err(phy->dev, "Couldn't create the PHY clock\n"); +			goto err_disable_clk_mod; +		} + +		clk_prepare_enable(phy->clk_phy); +	} +  	phy->variant->phy_init(phy); + +	return 0; + +err_disable_clk_mod: +	clk_disable_unprepare(phy->clk_mod); +err_disable_clk_bus: +	clk_disable_unprepare(phy->clk_bus); +err_assert_rst_phy: +	reset_control_assert(phy->rst_phy); + +	return ret; +} + +void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy) +{ +	clk_disable_unprepare(phy->clk_mod); +	clk_disable_unprepare(phy->clk_bus); +	clk_disable_unprepare(phy->clk_phy); + +	reset_control_assert(phy->rst_phy);  }  void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, @@ -638,6 +689,7 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev)  		return -ENOMEM;  	phy->variant = (struct sun8i_hdmi_phy_variant *)match->data; +	phy->dev = dev;  	ret = of_address_to_resource(node, 0, &res);  	if (ret) { @@ -696,47 +748,10 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev)  		goto err_put_clk_pll1;  	} -	ret = reset_control_deassert(phy->rst_phy); -	if (ret) { -		dev_err(dev, "Cannot deassert phy reset control: %d\n", ret); -		goto err_put_rst_phy; -	} - -	ret = clk_prepare_enable(phy->clk_bus); -	if (ret) { -		dev_err(dev, "Cannot enable bus clock: %d\n", ret); -		goto err_deassert_rst_phy; -	} - -	ret = clk_prepare_enable(phy->clk_mod); -	if (ret) { -		dev_err(dev, "Cannot enable mod clock: %d\n", ret); -		goto err_disable_clk_bus; -	} - -	if (phy->variant->has_phy_clk) { -		ret = sun8i_phy_clk_create(phy, dev, -					   phy->variant->has_second_pll); -		if (ret) { -			dev_err(dev, "Couldn't create the PHY clock\n"); -			goto err_disable_clk_mod; -		} - -		clk_prepare_enable(phy->clk_phy); -	} -  	platform_set_drvdata(pdev, phy);  	return 0; -err_disable_clk_mod: -	clk_disable_unprepare(phy->clk_mod); -err_disable_clk_bus: -	clk_disable_unprepare(phy->clk_bus); -err_deassert_rst_phy: -	reset_control_assert(phy->rst_phy); -err_put_rst_phy: -	reset_control_put(phy->rst_phy);  err_put_clk_pll1:  	clk_put(phy->clk_pll1);  err_put_clk_pll0: @@ -753,12 +768,6 @@ static int sun8i_hdmi_phy_remove(struct platform_device *pdev)  {  	struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev); -	clk_disable_unprepare(phy->clk_mod); -	clk_disable_unprepare(phy->clk_bus); -	clk_disable_unprepare(phy->clk_phy); - -	reset_control_assert(phy->rst_phy); -  	reset_control_put(phy->rst_phy);  	clk_put(phy->clk_pll0); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 16c7aabb94d3..a29d64f87563 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1845,7 +1845,6 @@ tegra_crtc_update_memory_bandwidth(struct drm_crtc *crtc,  				   bool prepare_bandwidth_transition)  {  	const struct tegra_plane_state *old_tegra_state, *new_tegra_state; -	const struct tegra_dc_state *old_dc_state, *new_dc_state;  	u32 i, new_avg_bw, old_avg_bw, new_peak_bw, old_peak_bw;  	const struct drm_plane_state *old_plane_state;  	const struct drm_crtc_state *old_crtc_state; @@ -1858,8 +1857,6 @@ tegra_crtc_update_memory_bandwidth(struct drm_crtc *crtc,  		return;  	old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); -	old_dc_state = to_const_dc_state(old_crtc_state); -	new_dc_state = to_const_dc_state(crtc->state);  	if (!crtc->state->active) {  		if (!old_crtc_state->active) diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index f0cb691852a1..40378308d527 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -35,12 +35,6 @@ static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)  	return NULL;  } -static inline const struct tegra_dc_state * -to_const_dc_state(const struct drm_crtc_state *state) -{ -	return to_dc_state((struct drm_crtc_state *)state); -} -  struct tegra_dc_stats {  	unsigned long frames;  	unsigned long vblank; diff --git a/drivers/gpu/drm/tegra/uapi.c b/drivers/gpu/drm/tegra/uapi.c index dc16a24f4dbe..690a339c52ec 100644 --- a/drivers/gpu/drm/tegra/uapi.c +++ b/drivers/gpu/drm/tegra/uapi.c @@ -222,7 +222,7 @@ int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_f  		mapping->iova = sg_dma_address(mapping->sgt->sgl);  	} -	mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->size; +	mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;  	err = xa_alloc(&context->mappings, &args->mapping, mapping, XA_LIMIT(1, U32_MAX),  		       GFP_KERNEL); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 1c5ffe2935af..abf2d7a4fdf1 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -190,6 +190,7 @@ static void ttm_transfered_destroy(struct ttm_buffer_object *bo)  	struct ttm_transfer_obj *fbo;  	fbo = container_of(bo, struct ttm_transfer_obj, base); +	dma_resv_fini(&fbo->base.base._resv);  	ttm_bo_put(fbo->bo);  	kfree(fbo);  } diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index cb38b1a17b09..82cbb29a05aa 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -383,7 +383,8 @@ int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt,  	else  		gfp_flags |= GFP_HIGHUSER; -	for (order = min(MAX_ORDER - 1UL, __fls(num_pages)); num_pages; +	for (order = min_t(unsigned int, MAX_ORDER - 1, __fls(num_pages)); +	     num_pages;  	     order = min_t(unsigned int, order, __fls(num_pages))) {  		bool apply_caching = false;  		struct ttm_pool_type *pt; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 4a1115043114..ed8a4b7f8b6e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -167,8 +167,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)  	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);  	bool connected = false; -	WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); -  	if (vc4_hdmi->hpd_gpio &&  	    gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {  		connected = true; @@ -189,12 +187,10 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)  			}  		} -		pm_runtime_put(&vc4_hdmi->pdev->dev);  		return connector_status_connected;  	}  	cec_phys_addr_invalidate(vc4_hdmi->cec_adap); -	pm_runtime_put(&vc4_hdmi->pdev->dev);  	return connector_status_disconnected;  } @@ -436,7 +432,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)  	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);  	struct drm_connector *connector = &vc4_hdmi->connector;  	struct drm_connector_state *cstate = connector->state; -	struct drm_crtc *crtc = cstate->crtc; +	struct drm_crtc *crtc = encoder->crtc;  	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;  	union hdmi_infoframe frame;  	int ret; @@ -541,11 +537,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,  static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)  { +	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;  	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -	struct drm_connector *connector = &vc4_hdmi->connector; -	struct drm_connector_state *cstate = connector->state; -	struct drm_crtc *crtc = cstate->crtc; -	struct drm_display_mode *mode = &crtc->state->adjusted_mode;  	if (!vc4_hdmi_supports_scrambling(encoder, mode))  		return; @@ -566,18 +559,17 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)  static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)  {  	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -	struct drm_connector *connector = &vc4_hdmi->connector; -	struct drm_connector_state *cstate = connector->state; +	struct drm_crtc *crtc = encoder->crtc;  	/* -	 * At boot, connector->state will be NULL. Since we don't know the +	 * At boot, encoder->crtc will be NULL. Since we don't know the  	 * state of the scrambler and in order to avoid any  	 * inconsistency, let's disable it all the time.  	 */ -	if (cstate && !vc4_hdmi_supports_scrambling(encoder, &cstate->crtc->mode)) +	if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))  		return; -	if (cstate && !vc4_hdmi_mode_needs_scrambling(&cstate->crtc->mode)) +	if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))  		return;  	if (delayed_work_pending(&vc4_hdmi->scrambling_work)) @@ -635,6 +627,7 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,  		vc4_hdmi->variant->phy_disable(vc4_hdmi);  	clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock); +	clk_disable_unprepare(vc4_hdmi->hsm_clock);  	clk_disable_unprepare(vc4_hdmi->pixel_clock);  	ret = pm_runtime_put(&vc4_hdmi->pdev->dev); @@ -898,9 +891,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,  		vc4_hdmi_encoder_get_connector_state(encoder, state);  	struct vc4_hdmi_connector_state *vc4_conn_state =  		conn_state_to_vc4_hdmi_conn_state(conn_state); -	struct drm_crtc_state *crtc_state = -		drm_atomic_get_new_crtc_state(state, conn_state->crtc); -	struct drm_display_mode *mode = &crtc_state->adjusted_mode; +	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;  	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);  	unsigned long bvb_rate, pixel_rate, hsm_rate;  	int ret; @@ -947,6 +938,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,  		return;  	} +	ret = clk_prepare_enable(vc4_hdmi->hsm_clock); +	if (ret) { +		DRM_ERROR("Failed to turn on HSM clock: %d\n", ret); +		clk_disable_unprepare(vc4_hdmi->pixel_clock); +		return; +	} +  	vc4_hdmi_cec_update_clk_div(vc4_hdmi);  	if (pixel_rate > 297000000) @@ -959,6 +957,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,  	ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);  	if (ret) {  		DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret); +		clk_disable_unprepare(vc4_hdmi->hsm_clock);  		clk_disable_unprepare(vc4_hdmi->pixel_clock);  		return;  	} @@ -966,6 +965,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,  	ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);  	if (ret) {  		DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret); +		clk_disable_unprepare(vc4_hdmi->hsm_clock);  		clk_disable_unprepare(vc4_hdmi->pixel_clock);  		return;  	} @@ -985,11 +985,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,  static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,  					     struct drm_atomic_state *state)  { -	struct drm_connector_state *conn_state = -		vc4_hdmi_encoder_get_connector_state(encoder, state); -	struct drm_crtc_state *crtc_state = -		drm_atomic_get_new_crtc_state(state, conn_state->crtc); -	struct drm_display_mode *mode = &crtc_state->adjusted_mode; +	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;  	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);  	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); @@ -1012,11 +1008,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,  static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,  					      struct drm_atomic_state *state)  { -	struct drm_connector_state *conn_state = -		vc4_hdmi_encoder_get_connector_state(encoder, state); -	struct drm_crtc_state *crtc_state = -		drm_atomic_get_new_crtc_state(state, conn_state->crtc); -	struct drm_display_mode *mode = &crtc_state->adjusted_mode; +	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;  	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);  	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);  	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; @@ -1204,8 +1196,8 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,  static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)  { -	struct drm_connector *connector = &vc4_hdmi->connector; -	struct drm_crtc *crtc = connector->state->crtc; +	struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +	struct drm_crtc *crtc = encoder->crtc;  	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;  	u32 n, cts;  	u64 tmp; @@ -1238,13 +1230,13 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)  static int vc4_hdmi_audio_startup(struct device *dev, void *data)  {  	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); -	struct drm_connector *connector = &vc4_hdmi->connector; +	struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;  	/*  	 * If the HDMI encoder hasn't probed, or the encoder is  	 * currently in DVI mode, treat the codec dai as missing.  	 */ -	if (!connector->state || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & +	if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &  				VC4_HDMI_RAM_PACKET_ENABLE))  		return -ENODEV; @@ -1403,14 +1395,6 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,  	return 0;  } -static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = { -	SND_SOC_DAPM_OUTPUT("TX"), -}; - -static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = { -	{ "TX", NULL, "Playback" }, -}; -  static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = {  	.name = "vc4-hdmi-cpu-dai-component",  }; @@ -2114,29 +2098,6 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)  	return 0;  } -#ifdef CONFIG_PM -static int vc4_hdmi_runtime_suspend(struct device *dev) -{ -	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); - -	clk_disable_unprepare(vc4_hdmi->hsm_clock); - -	return 0; -} - -static int vc4_hdmi_runtime_resume(struct device *dev) -{ -	struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); -	int ret; - -	ret = clk_prepare_enable(vc4_hdmi->hsm_clock); -	if (ret) -		return ret; - -	return 0; -} -#endif -  static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)  {  	const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev); @@ -2391,18 +2352,11 @@ static const struct of_device_id vc4_hdmi_dt_match[] = {  	{}  }; -static const struct dev_pm_ops vc4_hdmi_pm_ops = { -	SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend, -			   vc4_hdmi_runtime_resume, -			   NULL) -}; -  struct platform_driver vc4_hdmi_driver = {  	.probe = vc4_hdmi_dev_probe,  	.remove = vc4_hdmi_dev_remove,  	.driver = {  		.name = "vc4_hdmi",  		.of_match_table = vc4_hdmi_dt_match, -		.pm = &vc4_hdmi_pm_ops,  	},  }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index ab9a1750e1df..bfd71c86faa5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -29,7 +29,7 @@  #include <linux/dma-mapping.h>  #include <linux/module.h>  #include <linux/pci.h> -#include <linux/mem_encrypt.h> +#include <linux/cc_platform.h>  #include <drm/drm_aperture.h>  #include <drm/drm_drv.h> @@ -666,7 +666,7 @@ static int vmw_dma_select_mode(struct vmw_private *dev_priv)  		[vmw_dma_map_bind] = "Giving up DMA mappings early."};  	/* TTM currently doesn't fully support SEV encryption. */ -	if (mem_encrypt_active()) +	if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))  		return -EINVAL;  	if (vmw_force_coherent) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index e50fb82a3030..2aceac7856e2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -28,7 +28,7 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/slab.h> -#include <linux/mem_encrypt.h> +#include <linux/cc_platform.h>  #include <asm/hypervisor.h>  #include <drm/drm_ioctl.h> @@ -160,7 +160,7 @@ static unsigned long vmw_port_hb_out(struct rpc_channel *channel,  	unsigned long msg_len = strlen(msg);  	/* HB port can't access encrypted memory. */ -	if (hb && !mem_encrypt_active()) { +	if (hb && !cc_platform_has(CC_ATTR_MEM_ENCRYPT)) {  		unsigned long bp = channel->cookie_high;  		u32 channel_id = (channel->channel_id << 16); @@ -216,7 +216,7 @@ static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,  	unsigned long si, di, eax, ebx, ecx, edx;  	/* HB port can't access encrypted memory */ -	if (hb && !mem_encrypt_active()) { +	if (hb && !cc_platform_has(CC_ATTR_MEM_ENCRYPT)) {  		unsigned long bp = channel->cookie_low;  		u32 channel_id = (channel->channel_id << 16); diff --git a/drivers/gpu/host1x/fence.c b/drivers/gpu/host1x/fence.c index 6941add95d0f..ecab72882192 100644 --- a/drivers/gpu/host1x/fence.c +++ b/drivers/gpu/host1x/fence.c @@ -15,7 +15,7 @@  #include "intr.h"  #include "syncpt.h" -DEFINE_SPINLOCK(lock); +static DEFINE_SPINLOCK(lock);  struct host1x_syncpt_fence {  	struct dma_fence base; @@ -152,8 +152,10 @@ struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold)  		return ERR_PTR(-ENOMEM);  	fence->waiter = kzalloc(sizeof(*fence->waiter), GFP_KERNEL); -	if (!fence->waiter) +	if (!fence->waiter) { +		kfree(fence);  		return ERR_PTR(-ENOMEM); +	}  	fence->sp = sp;  	fence->threshold = threshold; diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 8ae301eef643..a9639d098893 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -259,10 +259,24 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,  		cfg->data_width = IPU_CSI_DATA_WIDTH_8;  		break;  	case MEDIA_BUS_FMT_UYVY8_1X16: +		if (mbus_type == V4L2_MBUS_BT656) { +			cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; +			cfg->data_width = IPU_CSI_DATA_WIDTH_8; +		} else { +			cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; +			cfg->data_width = IPU_CSI_DATA_WIDTH_16; +		} +		cfg->mipi_dt = MIPI_DT_YUV422; +		break;  	case MEDIA_BUS_FMT_YUYV8_1X16: -		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; +		if (mbus_type == V4L2_MBUS_BT656) { +			cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; +			cfg->data_width = IPU_CSI_DATA_WIDTH_8; +		} else { +			cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; +			cfg->data_width = IPU_CSI_DATA_WIDTH_16; +		}  		cfg->mipi_dt = MIPI_DT_YUV422; -		cfg->data_width = IPU_CSI_DATA_WIDTH_16;  		break;  	case MEDIA_BUS_FMT_SBGGR8_1X8:  	case MEDIA_BUS_FMT_SGBRG8_1X8: @@ -332,7 +346,7 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,  			    const struct v4l2_mbus_config *mbus_cfg,  			    const struct v4l2_mbus_framefmt *mbus_fmt)  { -	int ret; +	int ret, is_bt1120;  	memset(csicfg, 0, sizeof(*csicfg)); @@ -353,11 +367,18 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,  		break;  	case V4L2_MBUS_BT656:  		csicfg->ext_vsync = 0; +		/* UYVY10_1X20 etc. should be supported as well */ +		is_bt1120 = mbus_fmt->code == MEDIA_BUS_FMT_UYVY8_1X16 || +			    mbus_fmt->code == MEDIA_BUS_FMT_YUYV8_1X16;  		if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||  		    mbus_fmt->field == V4L2_FIELD_ALTERNATE) -			csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; +			csicfg->clk_mode = is_bt1120 ? +				IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR : +				IPU_CSI_CLK_MODE_CCIR656_INTERLACED;  		else -			csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; +			csicfg->clk_mode = is_bt1120 ? +				IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR : +				IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;  		break;  	case V4L2_MBUS_CSI2_DPHY:  		/* | 
