diff options
Diffstat (limited to 'drivers/gpu/drm')
72 files changed, 1198 insertions, 520 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index aa2dcf578dd6..668939a14206 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -98,6 +98,9 @@ extern int amdgpu_sched_hw_submission;  #define AMDGPU_MAX_COMPUTE_RINGS		8  #define AMDGPU_MAX_VCE_RINGS			2 +/* max number of IP instances */ +#define AMDGPU_MAX_SDMA_INSTANCES		2 +  /* number of hw syncs before falling back on blocking */  #define AMDGPU_NUM_SYNCS			4 @@ -262,7 +265,7 @@ struct amdgpu_buffer_funcs {  	unsigned	fill_num_dw;  	/* used for buffer clearing */ -	void (*emit_fill_buffer)(struct amdgpu_ring *ring, +	void (*emit_fill_buffer)(struct amdgpu_ib *ib,  				 /* value to write to memory */  				 uint32_t src_data,  				 /* dst addr in bytes */ @@ -340,6 +343,8 @@ struct amdgpu_ring_funcs {  	int (*test_ring)(struct amdgpu_ring *ring);  	int (*test_ib)(struct amdgpu_ring *ring);  	bool (*is_lockup)(struct amdgpu_ring *ring); +	/* insert NOP packets */ +	void (*insert_nop)(struct amdgpu_ring *ring, uint32_t count);  };  /* @@ -440,12 +445,11 @@ int amdgpu_fence_wait_next(struct amdgpu_ring *ring);  int amdgpu_fence_wait_empty(struct amdgpu_ring *ring);  unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring); -signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, -				       struct fence **array, -				       uint32_t count, -				       bool wait_all, -				       bool intr, -				       signed long t); +signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, +				  struct fence **array, +				  uint32_t count, +				  bool intr, +				  signed long t);  struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence);  void amdgpu_fence_unref(struct amdgpu_fence **fence); @@ -717,6 +721,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev,  		     void *owner);  int amdgpu_sync_rings(struct amdgpu_sync *sync,  		      struct amdgpu_ring *ring); +struct fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync);  int amdgpu_sync_wait(struct amdgpu_sync *sync);  void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync,  		      struct fence *fence); @@ -1214,6 +1219,7 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev);  void amdgpu_ring_free_size(struct amdgpu_ring *ring);  int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw);  int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw); +void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count);  void amdgpu_ring_commit(struct amdgpu_ring *ring);  void amdgpu_ring_unlock_commit(struct amdgpu_ring *ring);  void amdgpu_ring_undo(struct amdgpu_ring *ring); @@ -1665,7 +1671,6 @@ struct amdgpu_uvd {  	struct amdgpu_bo	*vcpu_bo;  	void			*cpu_addr;  	uint64_t		gpu_addr; -	void			*saved_bo;  	atomic_t		handles[AMDGPU_MAX_UVD_HANDLES];  	struct drm_file		*filp[AMDGPU_MAX_UVD_HANDLES];  	struct delayed_work	idle_work; @@ -1709,6 +1714,7 @@ struct amdgpu_sdma {  	uint32_t		feature_version;  	struct amdgpu_ring	ring; +	bool			burst_nop;  };  /* @@ -2057,7 +2063,7 @@ struct amdgpu_device {  	struct amdgpu_gfx		gfx;  	/* sdma */ -	struct amdgpu_sdma		sdma[2]; +	struct amdgpu_sdma		sdma[AMDGPU_MAX_SDMA_INSTANCES];  	struct amdgpu_irq_src		sdma_trap_irq;  	struct amdgpu_irq_src		sdma_illegal_inst_irq; @@ -2196,6 +2202,21 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)  	ring->ring_free_dw--;  } +static inline struct amdgpu_sdma * amdgpu_get_sdma_instance(struct amdgpu_ring *ring) +{ +	struct amdgpu_device *adev = ring->adev; +	int i; + +	for (i = 0; i < AMDGPU_MAX_SDMA_INSTANCES; i++) +		if (&adev->sdma[i].ring == ring) +			break; + +	if (i < AMDGPU_MAX_SDMA_INSTANCES) +		return &adev->sdma[i]; +	else +		return NULL; +} +  /*   * ASICs macro.   */ @@ -2248,7 +2269,7 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)  #define amdgpu_display_stop_mc_access(adev, s) (adev)->mode_info.funcs->stop_mc_access((adev), (s))  #define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s))  #define amdgpu_emit_copy_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((ib),  (s), (d), (b)) -#define amdgpu_emit_fill_buffer(adev, r, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((r), (s), (d), (b)) +#define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))  #define amdgpu_dpm_get_temperature(adev) (adev)->pm.funcs->get_temperature((adev))  #define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev))  #define amdgpu_dpm_set_power_state(adev) (adev)->pm.funcs->set_power_state((adev)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 6a206f15635f..3b355aeb62fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -354,7 +354,7 @@ int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p)  			 * into account. We don't want to disallow buffer moves  			 * completely.  			 */ -			if (current_domain != AMDGPU_GEM_DOMAIN_CPU && +			if ((lobj->allowed_domains & current_domain) != 0 &&  			    (domain & current_domain) == 0 && /* will be moved */  			    bytes_moved > bytes_moved_threshold) {  				/* don't move it */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 42d1a22c1199..6ff6ae945794 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -244,7 +244,8 @@ static int amdgpu_vram_scratch_init(struct amdgpu_device *adev)  	if (adev->vram_scratch.robj == NULL) {  		r = amdgpu_bo_create(adev, AMDGPU_GPU_PAGE_SIZE, -				     PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0, +				     PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, +				     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,  				     NULL, &adev->vram_scratch.robj);  		if (r) {  			return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 81b821247dde..8a122b1b7786 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -126,8 +126,8 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,  	aligned_size = ALIGN(size, PAGE_SIZE);  	ret = amdgpu_gem_object_create(adev, aligned_size, 0,  				       AMDGPU_GEM_DOMAIN_VRAM, -				       0, true, -				       &gobj); +				       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +				       true, &gobj);  	if (ret) {  		printk(KERN_ERR "failed to allocate framebuffer (%d)\n",  		       aligned_size); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index f446bf2fedc9..1be2bd6d07ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -851,22 +851,6 @@ static bool amdgpu_test_signaled_any(struct fence **fences, uint32_t count)  	return false;  } -static bool amdgpu_test_signaled_all(struct fence **fences, uint32_t count) -{ -	int idx; -	struct fence *fence; - -	for (idx = 0; idx < count; ++idx) { -		fence = fences[idx]; -		if (fence) { -			if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) -				return false; -		} -	} - -	return true; -} -  struct amdgpu_wait_cb {  	struct fence_cb base;  	struct task_struct *task; @@ -885,7 +869,7 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr,  	struct amdgpu_fence *fence = to_amdgpu_fence(f);  	struct amdgpu_device *adev = fence->ring->adev; -	return amdgpu_fence_wait_multiple(adev, &f, 1, false, intr, t); +	return amdgpu_fence_wait_any(adev, &f, 1, intr, t);  }  /** @@ -894,23 +878,18 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr,   * @adev:     amdgpu device   * @array:    the fence array with amdgpu fence pointer   * @count:    the number of the fence array - * @wait_all: the flag of wait all(true) or wait any(false)   * @intr:     when sleep, set the current task interruptable or not   * @t:        timeout to wait   * - * If wait_all is true, it will return when all fences are signaled or timeout. - * If wait_all is false, it will return when any fence is signaled or timeout. + * It will return when any fence is signaled or timeout.   */ -signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, -				       struct fence **array, -				       uint32_t count, -				       bool wait_all, -				       bool intr, -				       signed long t) -{ -	long idx = 0; +signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, +				  struct fence **array, uint32_t count, +				  bool intr, signed long t) +{  	struct amdgpu_wait_cb *cb;  	struct fence *fence; +	unsigned idx;  	BUG_ON(!array); @@ -927,10 +906,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev,  			if (fence_add_callback(fence,  					&cb[idx].base, amdgpu_fence_wait_cb)) {  				/* The fence is already signaled */ -				if (wait_all) -					continue; -				else -					goto fence_rm_cb; +				goto fence_rm_cb;  			}  		}  	} @@ -945,9 +921,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev,  		 * amdgpu_test_signaled_any must be called after  		 * set_current_state to prevent a race with wake_up_process  		 */ -		if (!wait_all && amdgpu_test_signaled_any(array, count)) -			break; -		if (wait_all && amdgpu_test_signaled_all(array, count)) +		if (amdgpu_test_signaled_any(array, count))  			break;  		if (adev->needs_reset) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index e02db0b2e839..cbd3a486c5c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -125,7 +125,8 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)  	if (adev->gart.robj == NULL) {  		r = amdgpu_bo_create(adev, adev->gart.table_size, -				     PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0, +				     PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, +				     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,  				     NULL, &adev->gart.robj);  		if (r) {  			return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 4afc507820c0..5839fab374bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -615,6 +615,7 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,  		info.alignment = robj->tbo.mem.page_alignment << PAGE_SHIFT;  		info.domains = robj->initial_domain;  		info.domain_flags = robj->flags; +		amdgpu_bo_unreserve(robj);  		if (copy_to_user(out, &info, sizeof(info)))  			r = -EFAULT;  		break; @@ -622,17 +623,19 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,  	case AMDGPU_GEM_OP_SET_PLACEMENT:  		if (amdgpu_ttm_tt_has_userptr(robj->tbo.ttm)) {  			r = -EPERM; +			amdgpu_bo_unreserve(robj);  			break;  		}  		robj->initial_domain = args->value & (AMDGPU_GEM_DOMAIN_VRAM |  						      AMDGPU_GEM_DOMAIN_GTT |  						      AMDGPU_GEM_DOMAIN_CPU); +		amdgpu_bo_unreserve(robj);  		break;  	default: +		amdgpu_bo_unreserve(robj);  		r = -EINVAL;  	} -	amdgpu_bo_unreserve(robj);  out:  	drm_gem_object_unreference_unlocked(gobj);  	return r; @@ -653,7 +656,8 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv,  	r = amdgpu_gem_object_create(adev, args->size, 0,  				     AMDGPU_GEM_DOMAIN_VRAM, -				     0, ttm_bo_type_device, +				     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +				     ttm_bo_type_device,  				     &gobj);  	if (r)  		return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 57adcad2f7ba..08b09d55b96f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -127,7 +127,7 @@ static void amdgpu_ttm_placement_init(struct amdgpu_device *adev,  			placements[c].fpfn =  				adev->mc.visible_vram_size >> PAGE_SHIFT;  			placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | -				TTM_PL_FLAG_VRAM; +				TTM_PL_FLAG_VRAM | TTM_PL_FLAG_TOPDOWN;  		}  		placements[c].fpfn = 0;  		placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 7d442c51063e..9bec91484c24 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -131,6 +131,21 @@ int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw)  	return 0;  } +/** amdgpu_ring_insert_nop - insert NOP packets + * + * @ring: amdgpu_ring structure holding ring information + * @count: the number of NOP packets to insert + * + * This is the generic insert_nop function for rings except SDMA + */ +void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ +	int i; + +	for (i = 0; i < count; i++) +		amdgpu_ring_write(ring, ring->nop); +} +  /**   * amdgpu_ring_commit - tell the GPU to execute the new   * commands on the ring buffer @@ -143,10 +158,13 @@ int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw)   */  void amdgpu_ring_commit(struct amdgpu_ring *ring)  { +	uint32_t count; +  	/* We pad to match fetch size */ -	while (ring->wptr & ring->align_mask) { -		amdgpu_ring_write(ring, ring->nop); -	} +	count = ring->align_mask + 1 - (ring->wptr & ring->align_mask); +	count %= ring->align_mask + 1; +	ring->funcs->insert_nop(ring, count); +  	mb();  	amdgpu_ring_set_wptr(ring);  } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index b92525329d6c..74dad270362c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -367,8 +367,8 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev,  		} while (amdgpu_sa_bo_next_hole(sa_manager, fences, tries));  		spin_unlock(&sa_manager->wq.lock); -		t = amdgpu_fence_wait_multiple(adev, fences, AMDGPU_MAX_RINGS, false, false, -						MAX_SCHEDULE_TIMEOUT); +		t = amdgpu_fence_wait_any(adev, fences, AMDGPU_MAX_RINGS, +					  false, MAX_SCHEDULE_TIMEOUT);  		r = (t > 0) ? 0 : t;  		spin_lock(&sa_manager->wq.lock);  		/* if we have nothing to wait for block */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index f93fb3541488..de98fbd2971e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -27,6 +27,12 @@  #include <drm/drmP.h>  #include "amdgpu.h" +static struct fence *amdgpu_sched_dependency(struct amd_sched_job *job) +{ +	struct amdgpu_job *sched_job = (struct amdgpu_job *)job; +	return amdgpu_sync_get_fence(&sched_job->ibs->sync); +} +  static struct fence *amdgpu_sched_run_job(struct amd_sched_job *job)  {  	struct amdgpu_job *sched_job; @@ -75,6 +81,7 @@ static void amdgpu_sched_process_job(struct amd_sched_job *job)  }  struct amd_sched_backend_ops amdgpu_sched_ops = { +	.dependency = amdgpu_sched_dependency,  	.run_job = amdgpu_sched_run_job,  	.process_job = amdgpu_sched_process_job  }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 4fffb2539331..068aeaff7183 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -142,6 +142,18 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync,  	return 0;  } +static void *amdgpu_sync_get_owner(struct fence *f) +{ +	struct amdgpu_fence *a_fence = to_amdgpu_fence(f); +	struct amd_sched_fence *s_fence = to_amd_sched_fence(f); + +	if (s_fence) +		return s_fence->owner; +	else if (a_fence) +		return a_fence->owner; +	return AMDGPU_FENCE_OWNER_UNDEFINED; +} +  /**   * amdgpu_sync_resv - use the semaphores to sync to a reservation object   * @@ -158,7 +170,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev,  {  	struct reservation_object_list *flist;  	struct fence *f; -	struct amdgpu_fence *fence; +	void *fence_owner;  	unsigned i;  	int r = 0; @@ -176,22 +188,22 @@ int amdgpu_sync_resv(struct amdgpu_device *adev,  	for (i = 0; i < flist->shared_count; ++i) {  		f = rcu_dereference_protected(flist->shared[i],  					      reservation_object_held(resv)); -		fence = f ? to_amdgpu_fence(f) : NULL; -		if (fence && fence->ring->adev == adev) { +		if (amdgpu_sync_same_dev(adev, f)) {  			/* VM updates are only interesting  			 * for other VM updates and moves.  			 */ +			fence_owner = amdgpu_sync_get_owner(f);  			if ((owner != AMDGPU_FENCE_OWNER_MOVE) && -			    (fence->owner != AMDGPU_FENCE_OWNER_MOVE) && +			    (fence_owner != AMDGPU_FENCE_OWNER_MOVE) &&  			    ((owner == AMDGPU_FENCE_OWNER_VM) != -			     (fence->owner == AMDGPU_FENCE_OWNER_VM))) +			     (fence_owner == AMDGPU_FENCE_OWNER_VM)))  				continue;  			/* Ignore fence from the same owner as  			 * long as it isn't undefined.  			 */  			if (owner != AMDGPU_FENCE_OWNER_UNDEFINED && -			    fence->owner == owner) +			    fence_owner == owner)  				continue;  		} @@ -202,6 +214,28 @@ int amdgpu_sync_resv(struct amdgpu_device *adev,  	return r;  } +struct fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync) +{ +	struct amdgpu_sync_entry *e; +	struct hlist_node *tmp; +	struct fence *f; +	int i; + +	hash_for_each_safe(sync->fences, i, tmp, e, node) { + +		f = e->fence; + +		hash_del(&e->node); +		kfree(e); + +		if (!fence_is_signaled(f)) +			return f; + +		fence_put(f); +	} +	return NULL; +} +  int amdgpu_sync_wait(struct amdgpu_sync *sync)  {  	struct amdgpu_sync_entry *e; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 399143541d8a..b5abd5cde413 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -859,7 +859,8 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)  	amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size);  	r = amdgpu_bo_create(adev, 256 * 1024, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,  			     NULL, &adev->stollen_vga_memory);  	if (r) {  		return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index b87355ccfb1d..2cf6c6b06e3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -154,7 +154,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)  	bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)  		 +  AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE;  	r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->uvd.vcpu_bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &adev->uvd.vcpu_bo);  	if (r) {  		dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r);  		return r; @@ -221,31 +223,32 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)  int amdgpu_uvd_suspend(struct amdgpu_device *adev)  { -	unsigned size; -	void *ptr; -	const struct common_firmware_header *hdr; -	int i; +	struct amdgpu_ring *ring = &adev->uvd.ring; +	int i, r;  	if (adev->uvd.vcpu_bo == NULL)  		return 0; -	for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) -		if (atomic_read(&adev->uvd.handles[i])) -			break; - -	if (i == AMDGPU_MAX_UVD_HANDLES) -		return 0; +	for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) { +		uint32_t handle = atomic_read(&adev->uvd.handles[i]); +		if (handle != 0) { +			struct fence *fence; -	hdr = (const struct common_firmware_header *)adev->uvd.fw->data; +			amdgpu_uvd_note_usage(adev); -	size = amdgpu_bo_size(adev->uvd.vcpu_bo); -	size -= le32_to_cpu(hdr->ucode_size_bytes); +			r = amdgpu_uvd_get_destroy_msg(ring, handle, &fence); +			if (r) { +				DRM_ERROR("Error destroying UVD (%d)!\n", r); +				continue; +			} -	ptr = adev->uvd.cpu_addr; -	ptr += le32_to_cpu(hdr->ucode_size_bytes); +			fence_wait(fence, false); +			fence_put(fence); -	adev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); -	memcpy(adev->uvd.saved_bo, ptr, size); +			adev->uvd.filp[i] = NULL; +			atomic_set(&adev->uvd.handles[i], 0); +		} +	}  	return 0;  } @@ -270,12 +273,7 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)  	ptr = adev->uvd.cpu_addr;  	ptr += le32_to_cpu(hdr->ucode_size_bytes); -	if (adev->uvd.saved_bo != NULL) { -		memcpy(ptr, adev->uvd.saved_bo, size); -		kfree(adev->uvd.saved_bo); -		adev->uvd.saved_bo = NULL; -	} else -		memset(ptr, 0, size); +	memset(ptr, 0, size);  	return 0;  } @@ -905,7 +903,9 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,  	int r, i;  	r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &bo);  	if (r)  		return r; @@ -952,7 +952,9 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,  	int r, i;  	r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &bo);  	if (r)  		return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1a984c934b1f..3cab96c42aa8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -141,7 +141,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)  	/* allocate firmware, stack and heap BO */  	r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->vce.vcpu_bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &adev->vce.vcpu_bo);  	if (r) {  		dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r);  		return r; @@ -836,6 +838,10 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring)  	struct fence *fence = NULL;  	int r; +	/* skip vce ring1 ib test for now, since it's not reliable */ +	if (ring == &ring->adev->vce.ring[1]) +		return 0; +  	r = amdgpu_vce_get_create_msg(ring, 1, NULL);  	if (r) {  		DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 83b7ce6f5f72..f68b7cdc370a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -627,9 +627,14 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev,  {  	uint64_t mask = AMDGPU_VM_PTE_COUNT - 1;  	uint64_t last_pte = ~0, last_dst = ~0; +	void *owner = AMDGPU_FENCE_OWNER_VM;  	unsigned count = 0;  	uint64_t addr; +	/* sync to everything on unmapping */ +	if (!(flags & AMDGPU_PTE_VALID)) +		owner = AMDGPU_FENCE_OWNER_UNDEFINED; +  	/* walk over the address space and update the page tables */  	for (addr = start; addr < end; ) {  		uint64_t pt_idx = addr >> amdgpu_vm_block_size; @@ -638,8 +643,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev,  		uint64_t pte;  		int r; -		amdgpu_sync_resv(adev, &ib->sync, pt->tbo.resv, -				 AMDGPU_FENCE_OWNER_VM); +		amdgpu_sync_resv(adev, &ib->sync, pt->tbo.resv, owner);  		r = reservation_object_reserve_shared(pt->tbo.resv);  		if (r)  			return r; @@ -790,17 +794,6 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,  	ib->length_dw = 0; -	if (!(flags & AMDGPU_PTE_VALID)) { -		unsigned i; - -		for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { -			struct amdgpu_fence *f = vm->ids[i].last_id_use; -			r = amdgpu_sync_fence(adev, &ib->sync, &f->base); -			if (r) -				return r; -		} -	} -  	r = amdgpu_vm_update_ptes(adev, vm, ib, mapping->it.start,  				  mapping->it.last + 1, addr + mapping->offset,  				  flags, gtt_flags); @@ -1106,7 +1099,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,  		r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,  				     AMDGPU_GPU_PAGE_SIZE, true, -				     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &pt); +				     AMDGPU_GEM_DOMAIN_VRAM, +				     AMDGPU_GEM_CREATE_NO_CPU_ACCESS, +				     NULL, &pt);  		if (r)  			goto error_free; @@ -1306,7 +1301,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)  	vm->page_directory_fence = NULL;  	r = amdgpu_bo_create(adev, pd_size, align, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_NO_CPU_ACCESS,  			     NULL, &vm->page_directory);  	if (r)  		return r; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 9ba0a7d5bc8e..92b6acadfc52 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -139,7 +139,8 @@ amdgpu_atombios_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *m  	tx_buf[0] = msg->address & 0xff;  	tx_buf[1] = msg->address >> 8; -	tx_buf[2] = msg->request << 4; +	tx_buf[2] = (msg->request << 4) | +		((msg->address >> 16) & 0xf);  	tx_buf[3] = msg->size ? (msg->size - 1) : 0;  	switch (msg->request & ~DP_AUX_I2C_MOT) { diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index 3920c1e346f8..9ea9de457da3 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -188,6 +188,19 @@ static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring)  	WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], (ring->wptr << 2) & 0x3fffc);  } +static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ +	struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); +	int i; + +	for (i = 0; i < count; i++) +		if (sdma && sdma->burst_nop && (i == 0)) +			amdgpu_ring_write(ring, ring->nop | +					  SDMA_NOP_COUNT(count - 1)); +		else +			amdgpu_ring_write(ring, ring->nop); +} +  /**   * cik_sdma_ring_emit_ib - Schedule an IB on the DMA engine   * @@ -213,8 +226,8 @@ static void cik_sdma_ring_emit_ib(struct amdgpu_ring *ring,  	amdgpu_ring_write(ring, next_rptr);  	/* IB packet must end on a 8 DW boundary */ -	while ((ring->wptr & 7) != 4) -		amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0)); +	cik_sdma_ring_insert_nop(ring, (12 - (ring->wptr & 7)) % 8); +  	amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));  	amdgpu_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */  	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff); @@ -501,6 +514,8 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev)  		fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;  		adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);  		adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); +		if (adev->sdma[i].feature_version >= 20) +			adev->sdma[i].burst_nop = true;  		fw_data = (const __le32 *)  			(adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));  		WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); @@ -815,8 +830,19 @@ static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib,   */  static void cik_sdma_vm_pad_ib(struct amdgpu_ib *ib)  { -	while (ib->length_dw & 0x7) -		ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0); +	struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); +	u32 pad_count; +	int i; + +	pad_count = (8 - (ib->length_dw & 0x7)) % 8; +	for (i = 0; i < pad_count; i++) +		if (sdma && sdma->burst_nop && (i == 0)) +			ib->ptr[ib->length_dw++] = +					SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0) | +					SDMA_NOP_COUNT(pad_count - 1); +		else +			ib->ptr[ib->length_dw++] = +					SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0);  }  /** @@ -1303,6 +1329,7 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = {  	.test_ring = cik_sdma_ring_test_ring,  	.test_ib = cik_sdma_ring_test_ib,  	.is_lockup = cik_sdma_ring_is_lockup, +	.insert_nop = cik_sdma_ring_insert_nop,  };  static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) @@ -1363,16 +1390,16 @@ static void cik_sdma_emit_copy_buffer(struct amdgpu_ib *ib,   *   * Fill GPU buffers using the DMA engine (CIK).   */ -static void cik_sdma_emit_fill_buffer(struct amdgpu_ring *ring, +static void cik_sdma_emit_fill_buffer(struct amdgpu_ib *ib,  				      uint32_t src_data,  				      uint64_t dst_offset,  				      uint32_t byte_count)  { -	amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0, 0)); -	amdgpu_ring_write(ring, lower_32_bits(dst_offset)); -	amdgpu_ring_write(ring, upper_32_bits(dst_offset)); -	amdgpu_ring_write(ring, src_data); -	amdgpu_ring_write(ring, byte_count); +	ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0, 0); +	ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); +	ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); +	ib->ptr[ib->length_dw++] = src_data; +	ib->ptr[ib->length_dw++] = byte_count;  }  static const struct amdgpu_buffer_funcs cik_sdma_buffer_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h index a3e3dfaa01a4..7f6d457f250a 100644 --- a/drivers/gpu/drm/amd/amdgpu/cikd.h +++ b/drivers/gpu/drm/amd/amdgpu/cikd.h @@ -487,6 +487,7 @@  					 (((op) & 0xFF) << 0))  /* sDMA opcodes */  #define	SDMA_OPCODE_NOP					  0 +#	define SDMA_NOP_COUNT(x)			  (((x) & 0x3FFF) << 16)  #define	SDMA_OPCODE_COPY				  1  #       define SDMA_COPY_SUB_OPCODE_LINEAR                0  #       define SDMA_COPY_SUB_OPCODE_TILED                 1 diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index ace870afc7d4..44fa96ad4709 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c @@ -1596,9 +1596,9 @@ static int cz_dpm_update_low_memory_pstate(struct amdgpu_device *adev)  	if (pi->sys_info.nb_dpm_enable) {  		if (ps->force_high) -			cz_dpm_nbdpm_lm_pstate_enable(adev, true); -		else  			cz_dpm_nbdpm_lm_pstate_enable(adev, false); +		else +			cz_dpm_nbdpm_lm_pstate_enable(adev, true);  	}  	return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 4b255ac3043c..e4d101b1252a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1353,7 +1353,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,  	tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 2);  	WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp);  	tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset); -	tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a); +	tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_b);  	tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time);  	WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp);  	/* restore original selection */ diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 70eee807421f..6411e8244671 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1329,7 +1329,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,  	tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 2);  	WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp);  	tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset); -	tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a); +	tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_b);  	tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time);  	WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp);  	/* restore original selection */ diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c index 493c8c9c7faa..322edea65857 100644 --- a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c @@ -762,7 +762,9 @@ int fiji_smu_init(struct amdgpu_device *adev)  	/* Allocate FW image data structure and header buffer */  	ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, -				true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); +			       true, AMDGPU_GEM_DOMAIN_VRAM, +			       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			       NULL, toc_buf);  	if (ret) {  		DRM_ERROR("Failed to allocate memory for TOC buffer\n");  		return -ENOMEM; @@ -770,7 +772,9 @@ int fiji_smu_init(struct amdgpu_device *adev)  	/* Allocate buffer for SMU internal buffer */  	ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, -				true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, smu_buf); +			       true, AMDGPU_GEM_DOMAIN_VRAM, +			       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			       NULL, smu_buf);  	if (ret) {  		DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");  		return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index fab7b236f37f..4bd1e5cf65ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -3786,7 +3786,9 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)  		/* save restore block */  		if (adev->gfx.rlc.save_restore_obj == NULL) {  			r = amdgpu_bo_create(adev, dws * 4, PAGE_SIZE, true, -					     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->gfx.rlc.save_restore_obj); +					     AMDGPU_GEM_DOMAIN_VRAM, +					     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +					     NULL, &adev->gfx.rlc.save_restore_obj);  			if (r) {  				dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);  				return r; @@ -3827,7 +3829,9 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)  		if (adev->gfx.rlc.clear_state_obj == NULL) {  			r = amdgpu_bo_create(adev, dws * 4, PAGE_SIZE, true, -					     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->gfx.rlc.clear_state_obj); +					     AMDGPU_GEM_DOMAIN_VRAM, +					     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +					     NULL, &adev->gfx.rlc.clear_state_obj);  			if (r) {  				dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);  				gfx_v7_0_rlc_fini(adev); @@ -3864,7 +3868,9 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)  	if (adev->gfx.rlc.cp_table_size) {  		if (adev->gfx.rlc.cp_table_obj == NULL) {  			r = amdgpu_bo_create(adev, adev->gfx.rlc.cp_table_size, PAGE_SIZE, true, -					     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->gfx.rlc.cp_table_obj); +					     AMDGPU_GEM_DOMAIN_VRAM, +					     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +					     NULL, &adev->gfx.rlc.cp_table_obj);  			if (r) {  				dev_warn(adev->dev, "(%d) create RLC cp table bo failed\n", r);  				gfx_v7_0_rlc_fini(adev); @@ -5598,6 +5604,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {  	.test_ring = gfx_v7_0_ring_test_ring,  	.test_ib = gfx_v7_0_ring_test_ib,  	.is_lockup = gfx_v7_0_ring_is_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { @@ -5614,6 +5621,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {  	.test_ring = gfx_v7_0_ring_test_ring,  	.test_ib = gfx_v7_0_ring_test_ib,  	.is_lockup = gfx_v7_0_ring_is_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void gfx_v7_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 818edb37fa9c..53f07439a512 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -2005,7 +2005,7 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev,  }  /** - * gmc_v8_0_init_compute_vmid - gart enable + * gfx_v8_0_init_compute_vmid - gart enable   *   * @rdev: amdgpu_device pointer   * @@ -2015,7 +2015,7 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev,  #define DEFAULT_SH_MEM_BASES	(0x6000)  #define FIRST_COMPUTE_VMID	(8)  #define LAST_COMPUTE_VMID	(16) -static void gmc_v8_0_init_compute_vmid(struct amdgpu_device *adev) +static void gfx_v8_0_init_compute_vmid(struct amdgpu_device *adev)  {  	int i;  	uint32_t sh_mem_config; @@ -2282,7 +2282,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)  	vi_srbm_select(adev, 0, 0, 0, 0);  	mutex_unlock(&adev->srbm_mutex); -	gmc_v8_0_init_compute_vmid(adev); +	gfx_v8_0_init_compute_vmid(adev);  	mutex_lock(&adev->grbm_idx_mutex);  	/* @@ -3240,7 +3240,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)  		/* enable the doorbell if requested */  		if (use_doorbell) { -			if (adev->asic_type == CHIP_CARRIZO) { +			if ((adev->asic_type == CHIP_CARRIZO) || +			    (adev->asic_type == CHIP_FIJI)) {  				WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,  				       AMDGPU_DOORBELL_KIQ << 2);  				WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, @@ -4378,6 +4379,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {  	.test_ring = gfx_v8_0_ring_test_ring,  	.test_ib = gfx_v8_0_ring_test_ib,  	.is_lockup = gfx_v8_0_ring_is_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { @@ -4394,6 +4396,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {  	.test_ring = gfx_v8_0_ring_test_ring,  	.test_ib = gfx_v8_0_ring_test_ib,  	.is_lockup = gfx_v8_0_ring_is_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 10218828face..774528ab8704 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -523,17 +523,11 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)  	tmp = RREG32(mmVM_CONTEXT1_CNTL);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_DEPTH, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_BLOCK_SIZE,  			    amdgpu_vm_block_size - 9); @@ -852,6 +846,13 @@ static int gmc_v7_0_early_init(void *handle)  	return 0;  } +static int gmc_v7_0_late_init(void *handle) +{ +	struct amdgpu_device *adev = (struct amdgpu_device *)handle; + +	return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); +} +  static int gmc_v7_0_sw_init(void *handle)  {  	int r; @@ -976,6 +977,7 @@ static int gmc_v7_0_hw_fini(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	amdgpu_irq_put(adev, &adev->mc.vm_fault, 0);  	gmc_v7_0_gart_disable(adev);  	return 0; @@ -1301,7 +1303,7 @@ static int gmc_v7_0_set_powergating_state(void *handle,  const struct amd_ip_funcs gmc_v7_0_ip_funcs = {  	.early_init = gmc_v7_0_early_init, -	.late_init = NULL, +	.late_init = gmc_v7_0_late_init,  	.sw_init = gmc_v7_0_sw_init,  	.sw_fini = gmc_v7_0_sw_fini,  	.hw_init = gmc_v7_0_hw_init, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 78109b750d29..9a07742620d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -653,19 +653,12 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)  	tmp = RREG32(mmVM_CONTEXT1_CNTL);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_DEPTH, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); -	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, 1);  	tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_BLOCK_SIZE,  			    amdgpu_vm_block_size - 9); @@ -852,6 +845,13 @@ static int gmc_v8_0_early_init(void *handle)  	return 0;  } +static int gmc_v8_0_late_init(void *handle) +{ +	struct amdgpu_device *adev = (struct amdgpu_device *)handle; + +	return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); +} +  static int gmc_v8_0_sw_init(void *handle)  {  	int r; @@ -978,6 +978,7 @@ static int gmc_v8_0_hw_fini(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	amdgpu_irq_put(adev, &adev->mc.vm_fault, 0);  	gmc_v8_0_gart_disable(adev);  	return 0; @@ -1288,7 +1289,7 @@ static int gmc_v8_0_set_powergating_state(void *handle,  const struct amd_ip_funcs gmc_v8_0_ip_funcs = {  	.early_init = gmc_v8_0_early_init, -	.late_init = NULL, +	.late_init = gmc_v8_0_late_init,  	.sw_init = gmc_v8_0_sw_init,  	.sw_fini = gmc_v8_0_sw_fini,  	.hw_init = gmc_v8_0_hw_init, diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h b/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h index c723602c7b0c..ee6a041cb288 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h +++ b/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h @@ -2163,5 +2163,10 @@  #define SDMA_PKT_NOP_HEADER_sub_op_shift  8  #define SDMA_PKT_NOP_HEADER_SUB_OP(x) (((x) & SDMA_PKT_NOP_HEADER_sub_op_mask) << SDMA_PKT_NOP_HEADER_sub_op_shift) +/*define for count field*/ +#define SDMA_PKT_NOP_HEADER_count_offset 0 +#define SDMA_PKT_NOP_HEADER_count_mask   0x00003FFF +#define SDMA_PKT_NOP_HEADER_count_shift  16 +#define SDMA_PKT_NOP_HEADER_COUNT(x) (((x) & SDMA_PKT_NOP_HEADER_count_mask) << SDMA_PKT_NOP_HEADER_count_shift)  #endif /* __ICELAND_SDMA_PKT_OPEN_H_ */ diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c index c6f1e2f12b5f..c900aa942ade 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c @@ -623,7 +623,9 @@ int iceland_smu_init(struct amdgpu_device *adev)  	/* Allocate FW image data structure and header buffer */  	ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, -			       true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); +			       true, AMDGPU_GEM_DOMAIN_VRAM, +			       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			       NULL, toc_buf);  	if (ret) {  		DRM_ERROR("Failed to allocate memory for TOC buffer\n");  		return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 715e02d3bfba..14e87234171a 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -146,6 +146,8 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)  		hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;  		adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);  		adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); +		if (adev->sdma[i].feature_version >= 20) +			adev->sdma[i].burst_nop = true;  		if (adev->firmware.smu_load) {  			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; @@ -218,6 +220,19 @@ static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring)  	WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], ring->wptr << 2);  } +static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ +	struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); +	int i; + +	for (i = 0; i < count; i++) +		if (sdma && sdma->burst_nop && (i == 0)) +			amdgpu_ring_write(ring, ring->nop | +				SDMA_PKT_NOP_HEADER_COUNT(count - 1)); +		else +			amdgpu_ring_write(ring, ring->nop); +} +  /**   * sdma_v2_4_ring_emit_ib - Schedule an IB on the DMA engine   * @@ -245,8 +260,8 @@ static void sdma_v2_4_ring_emit_ib(struct amdgpu_ring *ring,  	amdgpu_ring_write(ring, next_rptr);  	/* IB packet must end on a 8 DW boundary */ -	while ((ring->wptr & 7) != 2) -		amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_NOP)); +	sdma_v2_4_ring_insert_nop(ring, (10 - (ring->wptr & 7)) % 8); +  	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) |  			  SDMA_PKT_INDIRECT_HEADER_VMID(vmid));  	/* base must be 32 byte aligned */ @@ -879,8 +894,19 @@ static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib,   */  static void sdma_v2_4_vm_pad_ib(struct amdgpu_ib *ib)  { -	while (ib->length_dw & 0x7) -		ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_NOP); +	struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); +	u32 pad_count; +	int i; + +	pad_count = (8 - (ib->length_dw & 0x7)) % 8; +	for (i = 0; i < pad_count; i++) +		if (sdma && sdma->burst_nop && (i == 0)) +			ib->ptr[ib->length_dw++] = +				SDMA_PKT_HEADER_OP(SDMA_OP_NOP) | +				SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1); +		else +			ib->ptr[ib->length_dw++] = +				SDMA_PKT_HEADER_OP(SDMA_OP_NOP);  }  /** @@ -1314,6 +1340,7 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = {  	.test_ring = sdma_v2_4_ring_test_ring,  	.test_ib = sdma_v2_4_ring_test_ib,  	.is_lockup = sdma_v2_4_ring_is_lockup, +	.insert_nop = sdma_v2_4_ring_insert_nop,  };  static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) @@ -1375,16 +1402,16 @@ static void sdma_v2_4_emit_copy_buffer(struct amdgpu_ib *ib,   *   * Fill GPU buffers using the DMA engine (VI).   */ -static void sdma_v2_4_emit_fill_buffer(struct amdgpu_ring *ring, +static void sdma_v2_4_emit_fill_buffer(struct amdgpu_ib *ib,  				       uint32_t src_data,  				       uint64_t dst_offset,  				       uint32_t byte_count)  { -	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL)); -	amdgpu_ring_write(ring, lower_32_bits(dst_offset)); -	amdgpu_ring_write(ring, upper_32_bits(dst_offset)); -	amdgpu_ring_write(ring, src_data); -	amdgpu_ring_write(ring, byte_count); +	ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL); +	ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); +	ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); +	ib->ptr[ib->length_dw++] = src_data; +	ib->ptr[ib->length_dw++] = byte_count;  }  static const struct amdgpu_buffer_funcs sdma_v2_4_buffer_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 67128c8e78b8..9bfe92df15f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -218,6 +218,8 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)  		hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;  		adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);  		adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); +		if (adev->sdma[i].feature_version >= 20) +			adev->sdma[i].burst_nop = true;  		if (adev->firmware.smu_load) {  			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; @@ -304,6 +306,19 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring)  	}  } +static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ +	struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); +	int i; + +	for (i = 0; i < count; i++) +		if (sdma && sdma->burst_nop && (i == 0)) +			amdgpu_ring_write(ring, ring->nop | +				SDMA_PKT_NOP_HEADER_COUNT(count - 1)); +		else +			amdgpu_ring_write(ring, ring->nop); +} +  /**   * sdma_v3_0_ring_emit_ib - Schedule an IB on the DMA engine   * @@ -330,8 +345,7 @@ static void sdma_v3_0_ring_emit_ib(struct amdgpu_ring *ring,  	amdgpu_ring_write(ring, next_rptr);  	/* IB packet must end on a 8 DW boundary */ -	while ((ring->wptr & 7) != 2) -		amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_NOP)); +	sdma_v3_0_ring_insert_nop(ring, (10 - (ring->wptr & 7)) % 8);  	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) |  			  SDMA_PKT_INDIRECT_HEADER_VMID(vmid)); @@ -999,8 +1013,19 @@ static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib,   */  static void sdma_v3_0_vm_pad_ib(struct amdgpu_ib *ib)  { -	while (ib->length_dw & 0x7) -		ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_NOP); +	struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); +	u32 pad_count; +	int i; + +	pad_count = (8 - (ib->length_dw & 0x7)) % 8; +	for (i = 0; i < pad_count; i++) +		if (sdma && sdma->burst_nop && (i == 0)) +			ib->ptr[ib->length_dw++] = +				SDMA_PKT_HEADER_OP(SDMA_OP_NOP) | +				SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1); +		else +			ib->ptr[ib->length_dw++] = +				SDMA_PKT_HEADER_OP(SDMA_OP_NOP);  }  /** @@ -1438,6 +1463,7 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = {  	.test_ring = sdma_v3_0_ring_test_ring,  	.test_ib = sdma_v3_0_ring_test_ib,  	.is_lockup = sdma_v3_0_ring_is_lockup, +	.insert_nop = sdma_v3_0_ring_insert_nop,  };  static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) @@ -1499,16 +1525,16 @@ static void sdma_v3_0_emit_copy_buffer(struct amdgpu_ib *ib,   *   * Fill GPU buffers using the DMA engine (VI).   */ -static void sdma_v3_0_emit_fill_buffer(struct amdgpu_ring *ring, +static void sdma_v3_0_emit_fill_buffer(struct amdgpu_ib *ib,  				       uint32_t src_data,  				       uint64_t dst_offset,  				       uint32_t byte_count)  { -	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL)); -	amdgpu_ring_write(ring, lower_32_bits(dst_offset)); -	amdgpu_ring_write(ring, upper_32_bits(dst_offset)); -	amdgpu_ring_write(ring, src_data); -	amdgpu_ring_write(ring, byte_count); +	ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL); +	ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); +	ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); +	ib->ptr[ib->length_dw++] = src_data; +	ib->ptr[ib->length_dw++] = byte_count;  }  static const struct amdgpu_buffer_funcs sdma_v3_0_buffer_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h b/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h index 099b7b56113c..e5ebd084288d 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h +++ b/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h @@ -2236,5 +2236,10 @@  #define SDMA_PKT_NOP_HEADER_sub_op_shift  8  #define SDMA_PKT_NOP_HEADER_SUB_OP(x) (((x) & SDMA_PKT_NOP_HEADER_sub_op_mask) << SDMA_PKT_NOP_HEADER_sub_op_shift) +/*define for count field*/ +#define SDMA_PKT_NOP_HEADER_count_offset 0 +#define SDMA_PKT_NOP_HEADER_count_mask   0x00003FFF +#define SDMA_PKT_NOP_HEADER_count_shift  16 +#define SDMA_PKT_NOP_HEADER_COUNT(x) (((x) & SDMA_PKT_NOP_HEADER_count_mask) << SDMA_PKT_NOP_HEADER_count_shift)  #endif /* __TONGA_SDMA_PKT_OPEN_H_ */ diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c index 5fc53a40c7ac..1f5ac941a610 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c @@ -761,7 +761,9 @@ int tonga_smu_init(struct amdgpu_device *adev)  	/* Allocate FW image data structure and header buffer */  	ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, -				true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); +			       true, AMDGPU_GEM_DOMAIN_VRAM, +			       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			       NULL, toc_buf);  	if (ret) {  		DRM_ERROR("Failed to allocate memory for TOC buffer\n");  		return -ENOMEM; @@ -769,7 +771,9 @@ int tonga_smu_init(struct amdgpu_device *adev)  	/* Allocate buffer for SMU internal buffer */  	ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, -				true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, smu_buf); +			       true, AMDGPU_GEM_DOMAIN_VRAM, +			       AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			       NULL, smu_buf);  	if (ret) {  		DRM_ERROR("Failed to allocate memory for SMU internal buffer\n");  		return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 9ac383bc6c1f..5fac5da694f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -886,6 +886,7 @@ static const struct amdgpu_ring_funcs uvd_v4_2_ring_funcs = {  	.test_ring = uvd_v4_2_ring_test_ring,  	.test_ib = uvd_v4_2_ring_test_ib,  	.is_lockup = amdgpu_ring_test_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void uvd_v4_2_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index de4b3f57902d..2d5c59c318af 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c @@ -825,6 +825,7 @@ static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = {  	.test_ring = uvd_v5_0_ring_test_ring,  	.test_ib = uvd_v5_0_ring_test_ib,  	.is_lockup = amdgpu_ring_test_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void uvd_v5_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 66c975870e97..d9f553fce531 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -805,6 +805,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_funcs = {  	.test_ring = uvd_v6_0_ring_test_ring,  	.test_ib = uvd_v6_0_ring_test_ib,  	.is_lockup = amdgpu_ring_test_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void uvd_v6_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 303d961d57bd..cd16df543f64 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c @@ -643,6 +643,7 @@ static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = {  	.test_ring = amdgpu_vce_ring_test_ring,  	.test_ib = amdgpu_vce_ring_test_ib,  	.is_lockup = amdgpu_ring_test_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 4349658081ff..f0656dfb53f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -32,8 +32,8 @@  #include "vid.h"  #include "vce/vce_3_0_d.h"  #include "vce/vce_3_0_sh_mask.h" -#include "oss/oss_2_0_d.h" -#include "oss/oss_2_0_sh_mask.h" +#include "oss/oss_3_0_d.h" +#include "oss/oss_3_0_sh_mask.h"  #include "gca/gfx_8_0_d.h"  #include "smu/smu_7_1_2_d.h"  #include "smu/smu_7_1_2_sh_mask.h" @@ -426,17 +426,41 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)  static bool vce_v3_0_is_idle(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	u32 mask = 0; +	int idx; -	return !(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK); +	for (idx = 0; idx < 2; ++idx) { +		if (adev->vce.harvest_config & (1 << idx)) +			continue; + +		if (idx == 0) +			mask |= SRBM_STATUS2__VCE0_BUSY_MASK; +		else +			mask |= SRBM_STATUS2__VCE1_BUSY_MASK; +	} + +	return !(RREG32(mmSRBM_STATUS2) & mask);  }  static int vce_v3_0_wait_for_idle(void *handle)  {  	unsigned i;  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	u32 mask = 0; +	int idx; + +	for (idx = 0; idx < 2; ++idx) { +		if (adev->vce.harvest_config & (1 << idx)) +			continue; + +		if (idx == 0) +			mask |= SRBM_STATUS2__VCE0_BUSY_MASK; +		else +			mask |= SRBM_STATUS2__VCE1_BUSY_MASK; +	}  	for (i = 0; i < adev->usec_timeout; i++) { -		if (!(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK)) +		if (!(RREG32(mmSRBM_STATUS2) & mask))  			return 0;  	}  	return -ETIMEDOUT; @@ -445,9 +469,21 @@ static int vce_v3_0_wait_for_idle(void *handle)  static int vce_v3_0_soft_reset(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; +	u32 mask = 0; +	int idx; + +	for (idx = 0; idx < 2; ++idx) { +		if (adev->vce.harvest_config & (1 << idx)) +			continue; -	WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK, -			~SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK); +		if (idx == 0) +			mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK; +		else +			mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK; +	} +	WREG32_P(mmSRBM_SOFT_RESET, mask, +		 ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK | +		   SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK));  	mdelay(5);  	return vce_v3_0_start(adev); @@ -608,6 +644,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = {  	.test_ring = amdgpu_vce_ring_test_ring,  	.test_ib = amdgpu_vce_ring_test_ib,  	.is_lockup = amdgpu_ring_test_lockup, +	.insert_nop = amdgpu_ring_insert_nop,  };  static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index d99fe90991dc..9259f1b6664c 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -27,6 +27,8 @@  #include <drm/drmP.h>  #include "gpu_scheduler.h" +static struct amd_sched_job * +amd_sched_entity_pop_job(struct amd_sched_entity *entity);  static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);  /* Initialize a given run queue struct */ @@ -56,34 +58,36 @@ static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,  }  /** - * Select next entity from a specified run queue with round robin policy. - * It could return the same entity as current one if current is the only - * available one in the queue. Return NULL if nothing available. + * Select next job from a specified run queue with round robin policy. + * Return NULL if nothing available.   */ -static struct amd_sched_entity * -amd_sched_rq_select_entity(struct amd_sched_rq *rq) +static struct amd_sched_job * +amd_sched_rq_select_job(struct amd_sched_rq *rq)  {  	struct amd_sched_entity *entity; +	struct amd_sched_job *job;  	spin_lock(&rq->lock);  	entity = rq->current_entity;  	if (entity) {  		list_for_each_entry_continue(entity, &rq->entities, list) { -			if (!kfifo_is_empty(&entity->job_queue)) { +			job = amd_sched_entity_pop_job(entity); +			if (job) {  				rq->current_entity = entity;  				spin_unlock(&rq->lock); -				return rq->current_entity; +				return job;  			}  		}  	}  	list_for_each_entry(entity, &rq->entities, list) { -		if (!kfifo_is_empty(&entity->job_queue)) { +		job = amd_sched_entity_pop_job(entity); +		if (job) {  			rq->current_entity = entity;  			spin_unlock(&rq->lock); -			return rq->current_entity; +			return job;  		}  		if (entity == rq->current_entity) @@ -188,6 +192,39 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,  	kfifo_free(&entity->job_queue);  } +static void amd_sched_entity_wakeup(struct fence *f, struct fence_cb *cb) +{ +	struct amd_sched_entity *entity = +		container_of(cb, struct amd_sched_entity, cb); +	entity->dependency = NULL; +	fence_put(f); +	amd_sched_wakeup(entity->scheduler); +} + +static struct amd_sched_job * +amd_sched_entity_pop_job(struct amd_sched_entity *entity) +{ +	struct amd_gpu_scheduler *sched = entity->scheduler; +	struct amd_sched_job *job; + +	if (ACCESS_ONCE(entity->dependency)) +		return NULL; + +	if (!kfifo_out_peek(&entity->job_queue, &job, sizeof(job))) +		return NULL; + +	while ((entity->dependency = sched->ops->dependency(job))) { + +		if (fence_add_callback(entity->dependency, &entity->cb, +				       amd_sched_entity_wakeup)) +			fence_put(entity->dependency); +		else +			return NULL; +	} + +	return job; +} +  /**   * Helper to submit a job to the job queue   * @@ -227,7 +264,6 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job)  	struct amd_sched_entity *entity = sched_job->s_entity;  	struct amd_sched_fence *fence = amd_sched_fence_create(  		entity, sched_job->owner); -	int r;  	if (!fence)  		return -ENOMEM; @@ -235,10 +271,10 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job)  	fence_get(&fence->base);  	sched_job->s_fence = fence; -	r = wait_event_interruptible(entity->scheduler->job_scheduled, -				     amd_sched_entity_in(sched_job)); +	wait_event(entity->scheduler->job_scheduled, +		   amd_sched_entity_in(sched_job)); -	return r; +	return 0;  }  /** @@ -260,22 +296,22 @@ static void amd_sched_wakeup(struct amd_gpu_scheduler *sched)  }  /** - * Select next entity containing real IB submissions + * Select next to run  */ -static struct amd_sched_entity * -amd_sched_select_context(struct amd_gpu_scheduler *sched) +static struct amd_sched_job * +amd_sched_select_job(struct amd_gpu_scheduler *sched)  { -	struct amd_sched_entity *tmp; +	struct amd_sched_job *job;  	if (!amd_sched_ready(sched))  		return NULL;  	/* Kernel run queue has higher priority than normal run queue*/ -	tmp = amd_sched_rq_select_entity(&sched->kernel_rq); -	if (tmp == NULL) -		tmp = amd_sched_rq_select_entity(&sched->sched_rq); +	job = amd_sched_rq_select_job(&sched->kernel_rq); +	if (job == NULL) +		job = amd_sched_rq_select_job(&sched->sched_rq); -	return tmp; +	return job;  }  static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) @@ -296,27 +332,24 @@ static int amd_sched_main(void *param)  {  	struct sched_param sparam = {.sched_priority = 1};  	struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param; -	int r; +	int r, count;  	sched_setscheduler(current, SCHED_FIFO, &sparam);  	while (!kthread_should_stop()) { -		struct amd_sched_entity *c_entity = NULL; +		struct amd_sched_entity *entity;  		struct amd_sched_job *job;  		struct fence *fence;  		wait_event_interruptible(sched->wake_up_worker,  			kthread_should_stop() || -			(c_entity = amd_sched_select_context(sched))); +			(job = amd_sched_select_job(sched))); -		if (!c_entity) +		if (!job)  			continue; -		r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); -		if (r != sizeof(void *)) -			continue; +		entity = job->s_entity;  		atomic_inc(&sched->hw_rq_count); -  		fence = sched->ops->run_job(job);  		if (fence) {  			r = fence_add_callback(fence, &job->cb, @@ -328,6 +361,8 @@ static int amd_sched_main(void *param)  			fence_put(fence);  		} +		count = kfifo_out(&entity->job_queue, &job, sizeof(job)); +		WARN_ON(count != sizeof(job));  		wake_up(&sched->job_scheduled);  	}  	return 0; diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index e797796dcad7..2af0e4d4d817 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -45,6 +45,8 @@ struct amd_sched_entity {  	spinlock_t			queue_lock;  	struct amd_gpu_scheduler	*scheduler;  	uint64_t                        fence_context; +	struct fence			*dependency; +	struct fence_cb			cb;  };  /** @@ -89,6 +91,7 @@ static inline struct amd_sched_fence *to_amd_sched_fence(struct fence *f)   * these functions should be implemented in driver side  */  struct amd_sched_backend_ops { +	struct fence *(*dependency)(struct amd_sched_job *job);  	struct fence *(*run_job)(struct amd_sched_job *job);  	void (*process_job)(struct amd_sched_job *job);  }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 59ebbe547290..084280859589 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -23,7 +23,6 @@  #include "exynos_drm_drv.h"  #include "exynos_drm_fb.h"  #include "exynos_drm_fbdev.h" -#include "exynos_drm_gem.h"  #include "exynos_drm_iommu.h"  #include "exynos_drm_crtc.h" @@ -33,12 +32,10 @@   * exynos specific framebuffer structure.   *   * @fb: drm framebuffer obejct. - * @buf_cnt: a buffer count to drm framebuffer.   * @exynos_gem_obj: array of exynos specific gem object containing a gem object.   */  struct exynos_drm_fb {  	struct drm_framebuffer		fb; -	unsigned int			buf_cnt;  	struct exynos_drm_gem_obj	*exynos_gem_obj[MAX_FB_BUFFER];  }; @@ -98,10 +95,6 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,  {  	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); -	/* This fb should have only one gem object. */ -	if (WARN_ON(exynos_fb->buf_cnt != 1)) -		return -EINVAL; -  	return drm_gem_handle_create(file_priv,  			&exynos_fb->exynos_gem_obj[0]->base, handle);  } @@ -122,119 +115,77 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {  	.dirty		= exynos_drm_fb_dirty,  }; -void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, -						unsigned int cnt) -{ -	struct exynos_drm_fb *exynos_fb; - -	exynos_fb = to_exynos_fb(fb); - -	exynos_fb->buf_cnt = cnt; -} - -unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) -{ -	struct exynos_drm_fb *exynos_fb; - -	exynos_fb = to_exynos_fb(fb); - -	return exynos_fb->buf_cnt; -} -  struct drm_framebuffer *  exynos_drm_framebuffer_init(struct drm_device *dev,  			    struct drm_mode_fb_cmd2 *mode_cmd, -			    struct drm_gem_object *obj) +			    struct exynos_drm_gem_obj **gem_obj, +			    int count)  {  	struct exynos_drm_fb *exynos_fb; -	struct exynos_drm_gem_obj *exynos_gem_obj; +	int i;  	int ret; -	exynos_gem_obj = to_exynos_gem_obj(obj); - -	ret = check_fb_gem_memory_type(dev, exynos_gem_obj); -	if (ret < 0) -		return ERR_PTR(ret); -  	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);  	if (!exynos_fb)  		return ERR_PTR(-ENOMEM); +	for (i = 0; i < count; i++) { +		ret = check_fb_gem_memory_type(dev, gem_obj[i]); +		if (ret < 0) +			goto err; + +		exynos_fb->exynos_gem_obj[i] = gem_obj[i]; +	} +  	drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); -	exynos_fb->exynos_gem_obj[0] = exynos_gem_obj;  	ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); -	if (ret) { -		kfree(exynos_fb); +	if (ret < 0) {  		DRM_ERROR("failed to initialize framebuffer\n"); -		return ERR_PTR(ret); +		goto err;  	}  	return &exynos_fb->fb; + +err: +	kfree(exynos_fb); +	return ERR_PTR(ret);  }  static struct drm_framebuffer *  exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,  		      struct drm_mode_fb_cmd2 *mode_cmd)  { +	struct exynos_drm_gem_obj *gem_objs[MAX_FB_BUFFER];  	struct drm_gem_object *obj; -	struct exynos_drm_gem_obj *exynos_gem_obj; -	struct exynos_drm_fb *exynos_fb; -	int i, ret; - -	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); -	if (!exynos_fb) -		return ERR_PTR(-ENOMEM); - -	obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); -	if (!obj) { -		DRM_ERROR("failed to lookup gem object\n"); -		ret = -ENOENT; -		goto err_free; -	} - -	drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); -	exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); -	exynos_fb->buf_cnt = drm_format_num_planes(mode_cmd->pixel_format); - -	DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); +	struct drm_framebuffer *fb; +	int i; +	int ret; -	for (i = 1; i < exynos_fb->buf_cnt; i++) { +	for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {  		obj = drm_gem_object_lookup(dev, file_priv, -				mode_cmd->handles[i]); +					    mode_cmd->handles[i]);  		if (!obj) {  			DRM_ERROR("failed to lookup gem object\n");  			ret = -ENOENT; -			exynos_fb->buf_cnt = i; -			goto err_unreference; +			goto err;  		} -		exynos_gem_obj = to_exynos_gem_obj(obj); -		exynos_fb->exynos_gem_obj[i] = exynos_gem_obj; - -		ret = check_fb_gem_memory_type(dev, exynos_gem_obj); -		if (ret < 0) -			goto err_unreference; +		gem_objs[i] = to_exynos_gem_obj(obj);  	} -	ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); -	if (ret) { -		DRM_ERROR("failed to init framebuffer.\n"); -		goto err_unreference; +	fb = exynos_drm_framebuffer_init(dev, mode_cmd, gem_objs, i); +	if (IS_ERR(fb)) { +		ret = PTR_ERR(fb); +		goto err;  	} -	return &exynos_fb->fb; +	return fb; -err_unreference: -	for (i = 0; i < exynos_fb->buf_cnt; i++) { -		struct drm_gem_object *obj; +err: +	while (i--) +		drm_gem_object_unreference_unlocked(&gem_objs[i]->base); -		obj = &exynos_fb->exynos_gem_obj[i]->base; -		if (obj) -			drm_gem_object_unreference_unlocked(obj); -	} -err_free: -	kfree(exynos_fb);  	return ERR_PTR(ret);  } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 1c9e27c32cd1..85e4445b920e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -14,10 +14,13 @@  #ifndef _EXYNOS_DRM_FB_H_  #define _EXYNOS_DRM_FB_H +#include "exynos_drm_gem.h" +  struct drm_framebuffer *  exynos_drm_framebuffer_init(struct drm_device *dev,  			    struct drm_mode_fb_cmd2 *mode_cmd, -			    struct drm_gem_object *obj); +			    struct exynos_drm_gem_obj **gem_obj, +			    int count);  /* get gem object of a drm framebuffer */  struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, @@ -25,11 +28,4 @@ struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,  void exynos_drm_mode_config_init(struct drm_device *dev); -/* set a buffer count to drm framebuffer. */ -void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, -						unsigned int cnt); - -/* get a buffer count to drm framebuffer. */ -unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb); -  #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 624595afbce0..a221f753ad9c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -21,7 +21,6 @@  #include "exynos_drm_drv.h"  #include "exynos_drm_fb.h"  #include "exynos_drm_fbdev.h" -#include "exynos_drm_gem.h"  #include "exynos_drm_iommu.h"  #define MAX_CONNECTOR		4 @@ -32,7 +31,7 @@  struct exynos_drm_fbdev {  	struct drm_fb_helper		drm_fb_helper; -	struct exynos_drm_gem_obj	*exynos_gem_obj; +	struct exynos_drm_gem_obj	*obj;  };  static int exynos_drm_fb_mmap(struct fb_info *info, @@ -40,7 +39,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,  {  	struct drm_fb_helper *helper = info->par;  	struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); -	struct exynos_drm_gem_obj *obj = exynos_fbd->exynos_gem_obj; +	struct exynos_drm_gem_obj *obj = exynos_fbd->obj;  	unsigned long vm_size;  	int ret; @@ -75,37 +74,38 @@ static struct fb_ops exynos_drm_fb_ops = {  };  static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, -				     struct drm_fb_helper_surface_size *sizes, -				     struct drm_framebuffer *fb) +				   struct drm_fb_helper_surface_size *sizes, +				   struct exynos_drm_gem_obj *obj)  { -	struct fb_info *fbi = helper->fbdev; -	struct exynos_drm_gem_obj *obj; +	struct fb_info *fbi; +	struct drm_framebuffer *fb = helper->fb;  	unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);  	unsigned int nr_pages;  	unsigned long offset; +	fbi = drm_fb_helper_alloc_fbi(helper); +	if (IS_ERR(fbi)) { +		DRM_ERROR("failed to allocate fb info.\n"); +		return PTR_ERR(fbi); +	} + +	fbi->par = helper; +	fbi->flags = FBINFO_FLAG_DEFAULT; +	fbi->fbops = &exynos_drm_fb_ops; +  	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);  	drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); -	/* RGB formats use only one buffer */ -	obj = exynos_drm_fb_gem_obj(fb, 0); -	if (!obj) { -		DRM_DEBUG_KMS("gem object is null.\n"); -		return -EFAULT; -	} -  	nr_pages = obj->size >> PAGE_SHIFT;  	obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP,  			pgprot_writecombine(PAGE_KERNEL));  	if (!obj->kvaddr) {  		DRM_ERROR("failed to map pages to kernel space.\n"); +		drm_fb_helper_release_fbi(helper);  		return -EIO;  	} -	/* buffer count to framebuffer always is 1 at booting time. */ -	exynos_drm_fb_set_buf_cnt(fb, 1); -  	offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);  	offset += fbi->var.yoffset * fb->pitches[0]; @@ -120,9 +120,8 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,  				    struct drm_fb_helper_surface_size *sizes)  {  	struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); -	struct exynos_drm_gem_obj *exynos_gem_obj; +	struct exynos_drm_gem_obj *obj;  	struct drm_device *dev = helper->dev; -	struct fb_info *fbi;  	struct drm_mode_fb_cmd2 mode_cmd = { 0 };  	struct platform_device *pdev = dev->platformdev;  	unsigned long size; @@ -140,47 +139,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,  	mutex_lock(&dev->struct_mutex); -	fbi = drm_fb_helper_alloc_fbi(helper); -	if (IS_ERR(fbi)) { -		DRM_ERROR("failed to allocate fb info.\n"); -		ret = PTR_ERR(fbi); -		goto out; -	} -  	size = mode_cmd.pitches[0] * mode_cmd.height; -	exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); +	obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);  	/*  	 * If physically contiguous memory allocation fails and if IOMMU is  	 * supported then try to get buffer from non physically contiguous  	 * memory area.  	 */ -	if (IS_ERR(exynos_gem_obj) && is_drm_iommu_supported(dev)) { +	if (IS_ERR(obj) && is_drm_iommu_supported(dev)) {  		dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); -		exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, -							size); +		obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, size);  	} -	if (IS_ERR(exynos_gem_obj)) { -		ret = PTR_ERR(exynos_gem_obj); -		goto err_release_fbi; +	if (IS_ERR(obj)) { +		ret = PTR_ERR(obj); +		goto out;  	} -	exynos_fbdev->exynos_gem_obj = exynos_gem_obj; +	exynos_fbdev->obj = obj; -	helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, -			&exynos_gem_obj->base); +	helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj, 1);  	if (IS_ERR(helper->fb)) {  		DRM_ERROR("failed to create drm framebuffer.\n");  		ret = PTR_ERR(helper->fb);  		goto err_destroy_gem;  	} -	fbi->par = helper; -	fbi->flags = FBINFO_FLAG_DEFAULT; -	fbi->fbops = &exynos_drm_fb_ops; - -	ret = exynos_drm_fbdev_update(helper, sizes, helper->fb); +	ret = exynos_drm_fbdev_update(helper, sizes, obj);  	if (ret < 0)  		goto err_destroy_framebuffer; @@ -190,9 +176,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,  err_destroy_framebuffer:  	drm_framebuffer_cleanup(helper->fb);  err_destroy_gem: -	exynos_drm_gem_destroy(exynos_gem_obj); -err_release_fbi: -	drm_fb_helper_release_fbi(helper); +	exynos_drm_gem_destroy(obj);  /*   * if failed, all resources allocated above would be released by @@ -285,11 +269,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,  				      struct drm_fb_helper *fb_helper)  {  	struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper); -	struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; +	struct exynos_drm_gem_obj *obj = exynos_fbd->obj;  	struct drm_framebuffer *fb; -	if (exynos_gem_obj->kvaddr) -		vunmap(exynos_gem_obj->kvaddr); +	if (obj->kvaddr) +		vunmap(obj->kvaddr);  	/* release drm framebuffer and real buffer */  	if (fb_helper->fb && fb_helper->fb->funcs) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index ba008391a2fc..535b4ad6c4b1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -48,11 +48,13 @@  /* registers for base address */  #define G2D_SRC_BASE_ADDR		0x0304 +#define G2D_SRC_STRIDE_REG		0x0308  #define G2D_SRC_COLOR_MODE		0x030C  #define G2D_SRC_LEFT_TOP		0x0310  #define G2D_SRC_RIGHT_BOTTOM		0x0314  #define G2D_SRC_PLANE2_BASE_ADDR	0x0318  #define G2D_DST_BASE_ADDR		0x0404 +#define G2D_DST_STRIDE_REG		0x0408  #define G2D_DST_COLOR_MODE		0x040C  #define G2D_DST_LEFT_TOP		0x0410  #define G2D_DST_RIGHT_BOTTOM		0x0414 @@ -148,6 +150,7 @@ struct g2d_cmdlist {   * A structure of buffer description   *   * @format: color format + * @stride: buffer stride/pitch in bytes   * @left_x: the x coordinates of left top corner   * @top_y: the y coordinates of left top corner   * @right_x: the x coordinates of right bottom corner @@ -156,6 +159,7 @@ struct g2d_cmdlist {   */  struct g2d_buf_desc {  	unsigned int	format; +	unsigned int	stride;  	unsigned int	left_x;  	unsigned int	top_y;  	unsigned int	right_x; @@ -589,6 +593,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)  	switch (reg_offset) {  	case G2D_SRC_BASE_ADDR: +	case G2D_SRC_STRIDE_REG:  	case G2D_SRC_COLOR_MODE:  	case G2D_SRC_LEFT_TOP:  	case G2D_SRC_RIGHT_BOTTOM: @@ -598,6 +603,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)  		reg_type = REG_TYPE_SRC_PLANE2;  		break;  	case G2D_DST_BASE_ADDR: +	case G2D_DST_STRIDE_REG:  	case G2D_DST_COLOR_MODE:  	case G2D_DST_LEFT_TOP:  	case G2D_DST_RIGHT_BOTTOM: @@ -652,8 +658,8 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,  						enum g2d_reg_type reg_type,  						unsigned long size)  { -	unsigned int width, height; -	unsigned long area; +	int width, height; +	unsigned long bpp, last_pos;  	/*  	 * check source and destination buffers only. @@ -662,22 +668,37 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,  	if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)  		return true; -	width = buf_desc->right_x - buf_desc->left_x; +	/* This check also makes sure that right_x > left_x. */ +	width = (int)buf_desc->right_x - (int)buf_desc->left_x;  	if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) { -		DRM_ERROR("width[%u] is out of range!\n", width); +		DRM_ERROR("width[%d] is out of range!\n", width);  		return false;  	} -	height = buf_desc->bottom_y - buf_desc->top_y; +	/* This check also makes sure that bottom_y > top_y. */ +	height = (int)buf_desc->bottom_y - (int)buf_desc->top_y;  	if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) { -		DRM_ERROR("height[%u] is out of range!\n", height); +		DRM_ERROR("height[%d] is out of range!\n", height);  		return false;  	} -	area = (unsigned long)width * (unsigned long)height * -					g2d_get_buf_bpp(buf_desc->format); -	if (area > size) { -		DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size); +	bpp = g2d_get_buf_bpp(buf_desc->format); + +	/* Compute the position of the last byte that the engine accesses. */ +	last_pos = ((unsigned long)buf_desc->bottom_y - 1) * +		(unsigned long)buf_desc->stride + +		(unsigned long)buf_desc->right_x * bpp - 1; + +	/* +	 * Since right_x > left_x and bottom_y > top_y we already know +	 * that the first_pos < last_pos (first_pos being the position +	 * of the first byte the engine accesses), it just remains to +	 * check if last_pos is smaller then the buffer size. +	 */ + +	if (last_pos >= size) { +		DRM_ERROR("last engine access position [%lu] " +			"is out of range [%lu]!\n", last_pos, size);  		return false;  	} @@ -973,8 +994,6 @@ static int g2d_check_reg_offset(struct device *dev,  				goto err;  			reg_type = g2d_get_reg_type(reg_offset); -			if (reg_type == REG_TYPE_NONE) -				goto err;  			/* check userptr buffer type. */  			if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { @@ -983,14 +1002,22 @@ static int g2d_check_reg_offset(struct device *dev,  			} else  				buf_info->types[reg_type] = BUF_TYPE_GEM;  			break; +		case G2D_SRC_STRIDE_REG: +		case G2D_DST_STRIDE_REG: +			if (for_addr) +				goto err; + +			reg_type = g2d_get_reg_type(reg_offset); + +			buf_desc = &buf_info->descs[reg_type]; +			buf_desc->stride = cmdlist->data[index + 1]; +			break;  		case G2D_SRC_COLOR_MODE:  		case G2D_DST_COLOR_MODE:  			if (for_addr)  				goto err;  			reg_type = g2d_get_reg_type(reg_offset); -			if (reg_type == REG_TYPE_NONE) -				goto err;  			buf_desc = &buf_info->descs[reg_type];  			value = cmdlist->data[index + 1]; @@ -1003,8 +1030,6 @@ static int g2d_check_reg_offset(struct device *dev,  				goto err;  			reg_type = g2d_get_reg_type(reg_offset); -			if (reg_type == REG_TYPE_NONE) -				goto err;  			buf_desc = &buf_info->descs[reg_type];  			value = cmdlist->data[index + 1]; @@ -1018,8 +1043,6 @@ static int g2d_check_reg_offset(struct device *dev,  				goto err;  			reg_type = g2d_get_reg_type(reg_offset); -			if (reg_type == REG_TYPE_NONE) -				goto err;  			buf_desc = &buf_info->descs[reg_type];  			value = cmdlist->data[index + 1]; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 865d6eb0c845..714822441467 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -126,7 +126,7 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,  	if (!state->fb)  		return 0; -	nr = exynos_drm_fb_get_buf_cnt(state->fb); +	nr = drm_format_num_planes(state->fb->pixel_format);  	for (i = 0; i < nr; i++) {  		struct exynos_drm_gem_obj *obj =  					exynos_drm_fb_gem_obj(state->fb, i); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 33aabc79813b..e3ec9049081f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2562,6 +2562,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain)  		return "PORT_DDI_D_2_LANES";  	case POWER_DOMAIN_PORT_DDI_D_4_LANES:  		return "PORT_DDI_D_4_LANES"; +	case POWER_DOMAIN_PORT_DDI_E_2_LANES: +		return "PORT_DDI_E_2_LANES";  	case POWER_DOMAIN_PORT_DSI:  		return "PORT_DSI";  	case POWER_DOMAIN_PORT_CRT: diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1d887459e37f..8edcec8ae592 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -662,15 +662,18 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)  	pci_disable_device(drm_dev->pdev);  	/* -	 * During hibernation on some GEN4 platforms the BIOS may try to access +	 * During hibernation on some platforms the BIOS may try to access  	 * the device even though it's already in D3 and hang the machine. So  	 * leave the device in D0 on those platforms and hope the BIOS will -	 * power down the device properly. Platforms where this was seen: -	 * Lenovo Thinkpad X301, X61s +	 * power down the device properly. The issue was seen on multiple old +	 * GENs with different BIOS vendors, so having an explicit blacklist +	 * is inpractical; apply the workaround on everything pre GEN6. The +	 * platforms where the issue was seen: +	 * Lenovo Thinkpad X301, X61s, X60, T60, X41 +	 * Fujitsu FSC S7110 +	 * Acer Aspire 1830T  	 */ -	if (!(hibernation && -	      drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && -	      INTEL_INFO(dev_priv)->gen == 4)) +	if (!(hibernation && INTEL_INFO(dev_priv)->gen < 6))  		pci_set_power_state(drm_dev->pdev, PCI_D3hot);  	return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 089459b39771..b06e03080771 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -182,6 +182,7 @@ enum intel_display_power_domain {  	POWER_DOMAIN_PORT_DDI_C_4_LANES,  	POWER_DOMAIN_PORT_DDI_D_2_LANES,  	POWER_DOMAIN_PORT_DDI_D_4_LANES, +	POWER_DOMAIN_PORT_DDI_E_2_LANES,  	POWER_DOMAIN_PORT_DSI,  	POWER_DOMAIN_PORT_CRT,  	POWER_DOMAIN_PORT_OTHER, @@ -1416,6 +1417,10 @@ enum modeset_restore {  #define DP_AUX_C 0x20  #define DP_AUX_D 0x30 +#define DDC_PIN_B  0x05 +#define DDC_PIN_C  0x04 +#define DDC_PIN_D  0x06 +  struct ddi_vbt_port_info {  	/*  	 * This is an index in the HDMI/DVI DDI buffer translation table. @@ -1430,6 +1435,7 @@ struct ddi_vbt_port_info {  	uint8_t supports_dp:1;  	uint8_t alternate_aux_channel; +	uint8_t alternate_ddc_pin;  	uint8_t dp_boost_level;  	uint8_t hdmi_boost_level; @@ -1922,6 +1928,8 @@ struct drm_i915_private {  			struct skl_wm_values skl_hw;  			struct vlv_wm_values vlv;  		}; + +		uint8_t max_level;  	} wm;  	struct i915_runtime_pm pm; @@ -3377,13 +3385,13 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);  #define I915_READ64(reg)	dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)  #define I915_READ64_2x32(lower_reg, upper_reg) ({			\ -	u32 upper, lower, tmp;						\ -	tmp = I915_READ(upper_reg);					\ +	u32 upper, lower, old_upper, loop = 0;				\ +	upper = I915_READ(upper_reg);					\  	do {								\ -		upper = tmp;						\ +		old_upper = upper;					\  		lower = I915_READ(lower_reg);				\ -		tmp = I915_READ(upper_reg);				\ -	} while (upper != tmp);						\ +		upper = I915_READ(upper_reg);				\ +	} while (upper != old_upper && loop++ < 2);			\  	(u64)upper << 32 | lower; })  #define POSTING_READ(reg)	(void)I915_READ_NOTRACE(reg) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 923a3c4bf0b7..a953d4975b8c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1032,6 +1032,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,  		u32 old_read = obj->base.read_domains;  		u32 old_write = obj->base.write_domain; +		obj->dirty = 1; /* be paranoid  */  		obj->base.write_domain = obj->base.pending_write_domain;  		if (obj->base.write_domain == 0)  			obj->base.pending_read_domains |= obj->base.read_domains; @@ -1039,7 +1040,6 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,  		i915_vma_move_to_active(vma, req);  		if (obj->base.write_domain) { -			obj->dirty = 1;  			i915_gem_request_assign(&obj->last_write_req, req);  			intel_fb_obj_invalidate(obj, ORIGIN_CS); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d94c92d842fb..a2bceb70a3fd 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1558,7 +1558,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)  		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;  		intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, -				   hotplug_trigger, hpd_status_g4x, +				   hotplug_trigger, hpd_status_i915,  				   i9xx_port_hotplug_long_detect);  		intel_hpd_irq_handler(dev, pin_mask, long_mask);  	} diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index be83b77aa018..b3e437b3bb54 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -905,23 +905,23 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,  	uint8_t hdmi_level_shift;  	int i, j;  	bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; -	uint8_t aux_channel; +	uint8_t aux_channel, ddc_pin;  	/* Each DDI port can have more than one value on the "DVO Port" field,  	 * so look for all the possible values for each port and abort if more  	 * than one is found. */ -	int dvo_ports[][2] = { -		{DVO_PORT_HDMIA, DVO_PORT_DPA}, -		{DVO_PORT_HDMIB, DVO_PORT_DPB}, -		{DVO_PORT_HDMIC, DVO_PORT_DPC}, -		{DVO_PORT_HDMID, DVO_PORT_DPD}, -		{DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, +	int dvo_ports[][3] = { +		{DVO_PORT_HDMIA, DVO_PORT_DPA, -1}, +		{DVO_PORT_HDMIB, DVO_PORT_DPB, -1}, +		{DVO_PORT_HDMIC, DVO_PORT_DPC, -1}, +		{DVO_PORT_HDMID, DVO_PORT_DPD, -1}, +		{DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE},  	};  	/* Find the child device to use, abort if more than one found. */  	for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {  		it = dev_priv->vbt.child_dev + i; -		for (j = 0; j < 2; j++) { +		for (j = 0; j < 3; j++) {  			if (dvo_ports[port][j] == -1)  				break; @@ -939,6 +939,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,  		return;  	aux_channel = child->raw[25]; +	ddc_pin = child->common.ddc_pin;  	is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;  	is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; @@ -970,11 +971,27 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,  		DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port));  	if (is_dvi) { -		if (child->common.ddc_pin == 0x05 && port != PORT_B) +		if (port == PORT_E) { +			info->alternate_ddc_pin = ddc_pin; +			/* if DDIE share ddc pin with other port, then +			 * dvi/hdmi couldn't exist on the shared port. +			 * Otherwise they share the same ddc bin and system +			 * couldn't communicate with them seperately. */ +			if (ddc_pin == DDC_PIN_B) { +				dev_priv->vbt.ddi_port_info[PORT_B].supports_dvi = 0; +				dev_priv->vbt.ddi_port_info[PORT_B].supports_hdmi = 0; +			} else if (ddc_pin == DDC_PIN_C) { +				dev_priv->vbt.ddi_port_info[PORT_C].supports_dvi = 0; +				dev_priv->vbt.ddi_port_info[PORT_C].supports_hdmi = 0; +			} else if (ddc_pin == DDC_PIN_D) { +				dev_priv->vbt.ddi_port_info[PORT_D].supports_dvi = 0; +				dev_priv->vbt.ddi_port_info[PORT_D].supports_hdmi = 0; +			} +		} else if (ddc_pin == DDC_PIN_B && port != PORT_B)  			DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); -		if (child->common.ddc_pin == 0x04 && port != PORT_C) +		else if (ddc_pin == DDC_PIN_C && port != PORT_C)  			DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); -		if (child->common.ddc_pin == 0x06 && port != PORT_D) +		else if (ddc_pin == DDC_PIN_D && port != PORT_D)  			DRM_DEBUG_KMS("Unexpected DDC pin for port D\n");  	} diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 06d0dbde2be6..46cd5c7ebacd 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -758,11 +758,6 @@ int intel_parse_bios(struct drm_device *dev);  #define		DVO_C		2  #define		DVO_D		3 -/* define the PORT for DP output type */ -#define		PORT_IDPB	7 -#define		PORT_IDPC	8 -#define		PORT_IDPD	9 -  /* Possible values for the "DVO Port" field for versions >= 155: */  #define DVO_PORT_HDMIA	0  #define DVO_PORT_HDMIB	1 @@ -775,6 +770,8 @@ int intel_parse_bios(struct drm_device *dev);  #define DVO_PORT_DPC	8  #define DVO_PORT_DPD	9  #define DVO_PORT_DPA	10 +#define DVO_PORT_DPE	11 +#define DVO_PORT_HDMIE	12  #define DVO_PORT_MIPIA	21  #define DVO_PORT_MIPIB	22  #define DVO_PORT_MIPIC	23 diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index ba1ae031e6fd..d0f1b8d833cd 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -350,7 +350,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)  	}  	csr->mmio_count = dmc_header->mmio_count;  	for (i = 0; i < dmc_header->mmio_count; i++) { -		if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE && +		if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE ||  			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {  			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",  						dmc_header->mmioaddr[i]); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 19004557c868..61575f67a626 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1554,17 +1554,14 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,  			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |  			 wrpll_params.central_freq;  	} else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { -		struct drm_encoder *encoder = &intel_encoder->base; -		struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - -		switch (intel_dp->link_bw) { -		case DP_LINK_BW_1_62: +		switch (crtc_state->port_clock / 2) { +		case 81000:  			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);  			break; -		case DP_LINK_BW_2_7: +		case 135000:  			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);  			break; -		case DP_LINK_BW_5_4: +		case 270000:  			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);  			break;  		} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 53f5476bc4bb..8cc9264f7809 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5150,7 +5150,6 @@ static enum intel_display_power_domain port_to_power_domain(enum port port)  {  	switch (port) {  	case PORT_A: -	case PORT_E:  		return POWER_DOMAIN_PORT_DDI_A_4_LANES;  	case PORT_B:  		return POWER_DOMAIN_PORT_DDI_B_4_LANES; @@ -5158,6 +5157,8 @@ static enum intel_display_power_domain port_to_power_domain(enum port port)  		return POWER_DOMAIN_PORT_DDI_C_4_LANES;  	case PORT_D:  		return POWER_DOMAIN_PORT_DDI_D_4_LANES; +	case PORT_E: +		return POWER_DOMAIN_PORT_DDI_E_2_LANES;  	default:  		WARN_ON_ONCE(1);  		return POWER_DOMAIN_PORT_OTHER; @@ -5712,16 +5713,13 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv)  	/* enable PG1 and Misc I/O */  	intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); -	/* DPLL0 already enabed !? */ -	if (I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE) { -		DRM_DEBUG_DRIVER("DPLL0 already running\n"); -		return; +	/* DPLL0 not enabled (happens on early BIOS versions) */ +	if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) { +		/* enable DPLL0 */ +		required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); +		skl_dpll0_enable(dev_priv, required_vco);  	} -	/* enable DPLL0 */ -	required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); -	skl_dpll0_enable(dev_priv, required_vco); -  	/* set CDCLK to the frequency the BIOS chose */  	skl_set_cdclk(dev_priv, dev_priv->skl_boot_cdclk); @@ -6307,7 +6305,7 @@ static void intel_connector_check_state(struct intel_connector *connector)  		      connector->base.name);  	if (connector->get_hw_state(connector)) { -		struct drm_encoder *encoder = &connector->encoder->base; +		struct intel_encoder *encoder = connector->encoder;  		struct drm_connector_state *conn_state = connector->base.state;  		I915_STATE_WARN(!crtc, @@ -6319,13 +6317,13 @@ static void intel_connector_check_state(struct intel_connector *connector)  		I915_STATE_WARN(!crtc->state->active,  		      "connector is active, but attached crtc isn't\n"); -		if (!encoder) +		if (!encoder || encoder->type == INTEL_OUTPUT_DP_MST)  			return; -		I915_STATE_WARN(conn_state->best_encoder != encoder, +		I915_STATE_WARN(conn_state->best_encoder != &encoder->base,  			"atomic encoder doesn't match attached encoder\n"); -		I915_STATE_WARN(conn_state->crtc != encoder->crtc, +		I915_STATE_WARN(conn_state->crtc != encoder->base.crtc,  			"attached encoder crtc differs from connector crtc\n");  	} else {  		I915_STATE_WARN(crtc && crtc->state->active, @@ -13963,6 +13961,15 @@ static void intel_setup_outputs(struct drm_device *dev)  			intel_ddi_init(dev, PORT_C);  		if (found & SFUSE_STRAP_DDID_DETECTED)  			intel_ddi_init(dev, PORT_D); +		/* +		 * On SKL we don't have a way to detect DDI-E so we rely on VBT. +		 */ +		if (IS_SKYLAKE(dev) && +		    (dev_priv->vbt.ddi_port_info[PORT_E].supports_dp || +		     dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi || +		     dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi)) +			intel_ddi_init(dev, PORT_E); +  	} else if (HAS_PCH_SPLIT(dev)) {  		int found;  		dpd_is_edp = intel_dp_is_edp(dev, PORT_D); @@ -14733,6 +14740,24 @@ void intel_modeset_init(struct drm_device *dev)  	if (INTEL_INFO(dev)->num_pipes == 0)  		return; +	/* +	 * There may be no VBT; and if the BIOS enabled SSC we can +	 * just keep using it to avoid unnecessary flicker.  Whereas if the +	 * BIOS isn't using it, don't assume it will work even if the VBT +	 * indicates as much. +	 */ +	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { +		bool bios_lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) & +					    DREF_SSC1_ENABLE); + +		if (dev_priv->vbt.lvds_use_ssc != bios_lvds_use_ssc) { +			DRM_DEBUG_KMS("SSC %sabled by BIOS, overriding VBT which says %sabled\n", +				     bios_lvds_use_ssc ? "en" : "dis", +				     dev_priv->vbt.lvds_use_ssc ? "en" : "dis"); +			dev_priv->vbt.lvds_use_ssc = bios_lvds_use_ssc; +		} +	} +  	intel_init_display(dev);  	intel_init_audio(dev); @@ -15292,7 +15317,6 @@ err:  void intel_modeset_gem_init(struct drm_device *dev)  { -	struct drm_i915_private *dev_priv = dev->dev_private;  	struct drm_crtc *c;  	struct drm_i915_gem_object *obj;  	int ret; @@ -15301,16 +15325,6 @@ void intel_modeset_gem_init(struct drm_device *dev)  	intel_init_gt_powersave(dev);  	mutex_unlock(&dev->struct_mutex); -	/* -	 * There may be no VBT; and if the BIOS enabled SSC we can -	 * just keep using it to avoid unnecessary flicker.  Whereas if the -	 * BIOS isn't using it, don't assume it will work even if the VBT -	 * indicates as much. -	 */ -	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) -		dev_priv->vbt.lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) & -						DREF_SSC1_ENABLE); -  	intel_modeset_init_hw(dev);  	intel_setup_overlay(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3781cd3e358a..0a2e33fbf20d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -48,28 +48,28 @@  #define INTEL_DP_RESOLUTION_FAILSAFE	(3 << INTEL_DP_RESOLUTION_SHIFT_MASK)  struct dp_link_dpll { -	int link_bw; +	int clock;  	struct dpll dpll;  };  static const struct dp_link_dpll gen4_dpll[] = { -	{ DP_LINK_BW_1_62, +	{ 162000,  		{ .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } }, -	{ DP_LINK_BW_2_7, +	{ 270000,  		{ .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } }  };  static const struct dp_link_dpll pch_dpll[] = { -	{ DP_LINK_BW_1_62, +	{ 162000,  		{ .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } }, -	{ DP_LINK_BW_2_7, +	{ 270000,  		{ .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } }  };  static const struct dp_link_dpll vlv_dpll[] = { -	{ DP_LINK_BW_1_62, +	{ 162000,  		{ .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } }, -	{ DP_LINK_BW_2_7, +	{ 270000,  		{ .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } }  }; @@ -83,11 +83,11 @@ static const struct dp_link_dpll chv_dpll[] = {  	 * m2 is stored in fixed point format using formula below  	 * (m2_int << 22) | m2_fraction  	 */ -	{ DP_LINK_BW_1_62,	/* m2_int = 32, m2_fraction = 1677722 */ +	{ 162000,	/* m2_int = 32, m2_fraction = 1677722 */  		{ .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } }, -	{ DP_LINK_BW_2_7,	/* m2_int = 27, m2_fraction = 0 */ +	{ 270000,	/* m2_int = 27, m2_fraction = 0 */  		{ .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }, -	{ DP_LINK_BW_5_4,	/* m2_int = 27, m2_fraction = 0 */ +	{ 540000,	/* m2_int = 27, m2_fraction = 0 */  		{ .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }  }; @@ -1130,7 +1130,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)  }  static void -skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) +skl_edp_set_pll_config(struct intel_crtc_state *pipe_config)  {  	u32 ctrl1; @@ -1142,7 +1142,7 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock)  	pipe_config->dpll_hw_state.cfgcr2 = 0;  	ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0); -	switch (link_clock / 2) { +	switch (pipe_config->port_clock / 2) {  	case 81000:  		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,  					      SKL_DPLL0); @@ -1175,20 +1175,20 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock)  	pipe_config->dpll_hw_state.ctrl1 = ctrl1;  } -static void -hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw) +void +hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config)  {  	memset(&pipe_config->dpll_hw_state, 0,  	       sizeof(pipe_config->dpll_hw_state)); -	switch (link_bw) { -	case DP_LINK_BW_1_62: +	switch (pipe_config->port_clock / 2) { +	case 81000:  		pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810;  		break; -	case DP_LINK_BW_2_7: +	case 135000:  		pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350;  		break; -	case DP_LINK_BW_5_4: +	case 270000:  		pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700;  		break;  	} @@ -1245,7 +1245,7 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates)  static void  intel_dp_set_clock(struct intel_encoder *encoder, -		   struct intel_crtc_state *pipe_config, int link_bw) +		   struct intel_crtc_state *pipe_config)  {  	struct drm_device *dev = encoder->base.dev;  	const struct dp_link_dpll *divisor = NULL; @@ -1267,7 +1267,7 @@ intel_dp_set_clock(struct intel_encoder *encoder,  	if (divisor && count) {  		for (i = 0; i < count; i++) { -			if (link_bw == divisor[i].link_bw) { +			if (pipe_config->port_clock == divisor[i].clock) {  				pipe_config->dpll = divisor[i].dpll;  				pipe_config->clock_set = true;  				break; @@ -1544,13 +1544,13 @@ found:  	}  	if (IS_SKYLAKE(dev) && is_edp(intel_dp)) -		skl_edp_set_pll_config(pipe_config, common_rates[clock]); +		skl_edp_set_pll_config(pipe_config);  	else if (IS_BROXTON(dev))  		/* handled in ddi */;  	else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) -		hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw); +		hsw_dp_set_ddi_pll_sel(pipe_config);  	else -		intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); +		intel_dp_set_clock(encoder, pipe_config);  	return true;  } @@ -4961,9 +4961,12 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)  		intel_dp_probe_oui(intel_dp); -		if (!intel_dp_probe_mst(intel_dp)) +		if (!intel_dp_probe_mst(intel_dp)) { +			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +			intel_dp_check_link_status(intel_dp); +			drm_modeset_unlock(&dev->mode_config.connection_mutex);  			goto mst_fail; - +		}  	} else {  		if (intel_dp->is_mst) {  			if (intel_dp_check_mst_status(intel_dp) == -EINVAL) @@ -4971,10 +4974,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)  		}  		if (!intel_dp->is_mst) { -			/* -			 * we'll check the link status via the normal hot plug path later - -			 * but for short hpds we should check it now -			 */  			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);  			intel_dp_check_link_status(intel_dp);  			drm_modeset_unlock(&dev->mode_config.connection_mutex); @@ -5016,16 +5015,17 @@ intel_trans_dp_port_sel(struct drm_crtc *crtc)  	return -1;  } -/* check the VBT to see whether the eDP is on DP-D port */ +/* check the VBT to see whether the eDP is on another port */  bool intel_dp_is_edp(struct drm_device *dev, enum port port)  {  	struct drm_i915_private *dev_priv = dev->dev_private;  	union child_device_config *p_child;  	int i;  	static const short port_mapping[] = { -		[PORT_B] = PORT_IDPB, -		[PORT_C] = PORT_IDPC, -		[PORT_D] = PORT_IDPD, +		[PORT_B] = DVO_PORT_DPB, +		[PORT_C] = DVO_PORT_DPC, +		[PORT_D] = DVO_PORT_DPD, +		[PORT_E] = DVO_PORT_DPE,  	};  	if (port == PORT_A) diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 369f8b6b804f..3e4be5a3becd 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -33,6 +33,7 @@  static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,  					struct intel_crtc_state *pipe_config)  { +	struct drm_device *dev = encoder->base.dev;  	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);  	struct intel_digital_port *intel_dig_port = intel_mst->primary;  	struct intel_dp *intel_dp = &intel_dig_port->dp; @@ -97,6 +98,10 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,  			       &pipe_config->dp_m_n);  	pipe_config->dp_m_n.tu = slots; + +	if (IS_HASWELL(dev) || IS_BROADWELL(dev)) +		hsw_dp_set_ddi_pll_sel(pipe_config); +  	return true;  } @@ -168,6 +173,11 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)  		return;  	} +	/* MST encoders are bound to a crtc, not to a connector, +	 * force the mapping here for get_hw_state. +	 */ +	found->encoder = encoder; +  	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);  	intel_mst->port = found->port; @@ -395,7 +405,7 @@ static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {  static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)  { -	if (connector->encoder) { +	if (connector->encoder && connector->base.state->crtc) {  		enum pipe pipe;  		if (!connector->encoder->get_hw_state(connector->encoder, &pipe))  			return false; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 93008fbb815d..2b9e6f9775c5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1185,6 +1185,7 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp);  void intel_edp_drrs_invalidate(struct drm_device *dev,  		unsigned frontbuffer_bits);  void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits); +void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);  /* intel_dp_mst.c */  int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 4a601cf90f16..32a6c7184ca4 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1048,11 +1048,7 @@ void intel_dsi_init(struct drm_device *dev)  	intel_connector->unregister = intel_connector_unregister;  	/* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */ -	if (dev_priv->vbt.dsi.config->dual_link) { -		/* XXX: does dual link work on either pipe? */ -		intel_encoder->crtc_mask = (1 << PIPE_A); -		intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C)); -	} else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) { +	if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) {  		intel_encoder->crtc_mask = (1 << PIPE_A);  		intel_dsi->ports = (1 << PORT_A);  	} else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) { @@ -1060,6 +1056,9 @@ void intel_dsi_init(struct drm_device *dev)  		intel_dsi->ports = (1 << PORT_C);  	} +	if (dev_priv->vbt.dsi.config->dual_link) +		intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C)); +  	/* Create a DSI host (and a device) for each port. */  	for_each_dsi_port(port, intel_dsi->ports) {  		struct intel_dsi_host *host; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 51cbea8247fe..dcd336bcdfe7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1958,6 +1958,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,  	struct drm_device *dev = intel_encoder->base.dev;  	struct drm_i915_private *dev_priv = dev->dev_private;  	enum port port = intel_dig_port->port; +	uint8_t alternate_ddc_pin;  	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,  			   DRM_MODE_CONNECTOR_HDMIA); @@ -1991,6 +1992,26 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,  			intel_hdmi->ddc_bus = GMBUS_PIN_DPD;  		intel_encoder->hpd_pin = HPD_PORT_D;  		break; +	case PORT_E: +		/* On SKL PORT E doesn't have seperate GMBUS pin +		 *  We rely on VBT to set a proper alternate GMBUS pin. */ +		alternate_ddc_pin = +			dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin; +		switch (alternate_ddc_pin) { +		case DDC_PIN_B: +			intel_hdmi->ddc_bus = GMBUS_PIN_DPB; +			break; +		case DDC_PIN_C: +			intel_hdmi->ddc_bus = GMBUS_PIN_DPC; +			break; +		case DDC_PIN_D: +			intel_hdmi->ddc_bus = GMBUS_PIN_DPD; +			break; +		default: +			MISSING_CASE(alternate_ddc_pin); +		} +		intel_encoder->hpd_pin = HPD_PORT_E; +		break;  	case PORT_A:  		intel_encoder->hpd_pin = HPD_PORT_A;  		/* Internal port only for eDP. */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fff0c22682ee..ddbb7ed0a193 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -955,8 +955,6 @@ enum vlv_wm_level {  	VLV_WM_LEVEL_PM2,  	VLV_WM_LEVEL_PM5,  	VLV_WM_LEVEL_DDR_DVFS, -	CHV_WM_NUM_LEVELS, -	VLV_WM_NUM_LEVELS = 1,  };  /* latency must be in 0.1us units. */ @@ -982,9 +980,13 @@ static void vlv_setup_wm_latency(struct drm_device *dev)  	/* all latencies in usec */  	dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM2] = 3; +	dev_priv->wm.max_level = VLV_WM_LEVEL_PM2; +  	if (IS_CHERRYVIEW(dev_priv)) {  		dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM5] = 12;  		dev_priv->wm.pri_latency[VLV_WM_LEVEL_DDR_DVFS] = 33; + +		dev_priv->wm.max_level = VLV_WM_LEVEL_DDR_DVFS;  	}  } @@ -1137,10 +1139,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc)  	memset(wm_state, 0, sizeof(*wm_state));  	wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed; -	if (IS_CHERRYVIEW(dev)) -		wm_state->num_levels = CHV_WM_NUM_LEVELS; -	else -		wm_state->num_levels = VLV_WM_NUM_LEVELS; +	wm_state->num_levels = to_i915(dev)->wm.max_level + 1;  	wm_state->num_active_planes = 0; @@ -1220,7 +1219,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc)  	}  	/* clear any (partially) filled invalid levels */ -	for (level = wm_state->num_levels; level < CHV_WM_NUM_LEVELS; level++) { +	for (level = wm_state->num_levels; level < to_i915(dev)->wm.max_level + 1; level++) {  		memset(&wm_state->wm[level], 0, sizeof(wm_state->wm[level]));  		memset(&wm_state->sr[level], 0, sizeof(wm_state->sr[level]));  	} @@ -1324,10 +1323,7 @@ static void vlv_merge_wm(struct drm_device *dev,  	struct intel_crtc *crtc;  	int num_active_crtcs = 0; -	if (IS_CHERRYVIEW(dev)) -		wm->level = VLV_WM_LEVEL_DDR_DVFS; -	else -		wm->level = VLV_WM_LEVEL_PM2; +	wm->level = to_i915(dev)->wm.max_level;  	wm->cxsr = true;  	for_each_intel_crtc(dev, crtc) { @@ -4083,9 +4079,29 @@ void vlv_wm_get_hw_state(struct drm_device *dev)  		if (val & DSP_MAXFIFO_PM5_ENABLE)  			wm->level = VLV_WM_LEVEL_PM5; +		/* +		 * If DDR DVFS is disabled in the BIOS, Punit +		 * will never ack the request. So if that happens +		 * assume we don't have to enable/disable DDR DVFS +		 * dynamically. To test that just set the REQ_ACK +		 * bit to poke the Punit, but don't change the +		 * HIGH/LOW bits so that we don't actually change +		 * the current state. +		 */  		val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2); -		if ((val & FORCE_DDR_HIGH_FREQ) == 0) -			wm->level = VLV_WM_LEVEL_DDR_DVFS; +		val |= FORCE_DDR_FREQ_REQ_ACK; +		vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val); + +		if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) & +			      FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) { +			DRM_DEBUG_KMS("Punit not acking DDR DVFS request, " +				      "assuming DDR DVFS is disabled\n"); +			dev_priv->wm.max_level = VLV_WM_LEVEL_PM5; +		} else { +			val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2); +			if ((val & FORCE_DDR_HIGH_FREQ) == 0) +				wm->level = VLV_WM_LEVEL_DDR_DVFS; +		}  		mutex_unlock(&dev_priv->rps.hw_lock);  	} diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 821644d1b544..af7fdb3bd663 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -297,6 +297,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,  	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |		\  	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |		\  	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |		\ +	BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) |		\  	BIT(POWER_DOMAIN_AUX_B) |                       \  	BIT(POWER_DOMAIN_AUX_C) |			\  	BIT(POWER_DOMAIN_AUX_D) |			\ @@ -316,6 +317,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,  #define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS (		\  	BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |		\  	BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |		\ +	BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) |		\  	BIT(POWER_DOMAIN_INIT))  #define SKL_DISPLAY_DDI_B_POWER_DOMAINS (		\  	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |		\ diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index a8dbb3ef4e3c..7c6225c84ba6 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -160,9 +160,35 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector,  	*pwidth = head->width;  	*pheight = head->height;  	drm_mode_probed_add(connector, mode); +	/* remember the last custom size for mode validation */ +	qdev->monitors_config_width = mode->hdisplay; +	qdev->monitors_config_height = mode->vdisplay;  	return 1;  } +static struct mode_size { +	int w; +	int h; +} common_modes[] = { +	{ 640,  480}, +	{ 720,  480}, +	{ 800,  600}, +	{ 848,  480}, +	{1024,  768}, +	{1152,  768}, +	{1280,  720}, +	{1280,  800}, +	{1280,  854}, +	{1280,  960}, +	{1280, 1024}, +	{1440,  900}, +	{1400, 1050}, +	{1680, 1050}, +	{1600, 1200}, +	{1920, 1080}, +	{1920, 1200} +}; +  static int qxl_add_common_modes(struct drm_connector *connector,                                  unsigned pwidth,                                  unsigned pheight) @@ -170,29 +196,6 @@ static int qxl_add_common_modes(struct drm_connector *connector,  	struct drm_device *dev = connector->dev;  	struct drm_display_mode *mode = NULL;  	int i; -	struct mode_size { -		int w; -		int h; -	} common_modes[] = { -		{ 640,  480}, -		{ 720,  480}, -		{ 800,  600}, -		{ 848,  480}, -		{1024,  768}, -		{1152,  768}, -		{1280,  720}, -		{1280,  800}, -		{1280,  854}, -		{1280,  960}, -		{1280, 1024}, -		{1440,  900}, -		{1400, 1050}, -		{1680, 1050}, -		{1600, 1200}, -		{1920, 1080}, -		{1920, 1200} -	}; -  	for (i = 0; i < ARRAY_SIZE(common_modes); i++) {  		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h,  				    60, false, false, false); @@ -823,11 +826,22 @@ static int qxl_conn_get_modes(struct drm_connector *connector)  static int qxl_conn_mode_valid(struct drm_connector *connector,  			       struct drm_display_mode *mode)  { +	struct drm_device *ddev = connector->dev; +	struct qxl_device *qdev = ddev->dev_private; +	int i; +  	/* TODO: is this called for user defined modes? (xrandr --add-mode)  	 * TODO: check that the mode fits in the framebuffer */ -	DRM_DEBUG("%s: %dx%d status=%d\n", mode->name, mode->hdisplay, -		  mode->vdisplay, mode->status); -	return MODE_OK; + +	if(qdev->monitors_config_width == mode->hdisplay && +	   qdev->monitors_config_height == mode->vdisplay) +		return MODE_OK; + +	for (i = 0; i < ARRAY_SIZE(common_modes); i++) { +		if (common_modes[i].w == mode->hdisplay && common_modes[i].h == mode->vdisplay) +			return MODE_OK; +	} +	return MODE_BAD;  }  static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index d8549690801d..01a86948eb8c 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -325,6 +325,8 @@ struct qxl_device {  	struct work_struct fb_work;  	struct drm_property *hotplug_mode_update_property; +	int monitors_config_width; +	int monitors_config_height;  };  /* forward declaration for QXL_INFO_IO */ diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index f81e0d7d0232..9cd49c584263 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -171,8 +171,9 @@ radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  		return -E2BIG;  	tx_buf[0] = msg->address & 0xff; -	tx_buf[1] = msg->address >> 8; -	tx_buf[2] = msg->request << 4; +	tx_buf[1] = (msg->address >> 8) & 0xff; +	tx_buf[2] = (msg->request << 4) | +		((msg->address >> 16) & 0xf);  	tx_buf[3] = msg->size ? (msg->size - 1) : 0;  	switch (msg->request & ~DP_AUX_I2C_MOT) { diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index fbc8d88d6e5d..2c02e99b5f95 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -522,13 +522,15 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,  		return err;  	} -	if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { -		if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) -			frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; -		else -			frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; -	} else { -		frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; +	if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) { +		if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { +			if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) +				frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; +			else +				frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; +		} else { +			frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; +		}  	}  	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index c097d3a82bda..a9b01bcf7d0a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3387,6 +3387,14 @@ void radeon_combios_asic_init(struct drm_device *dev)  	    rdev->pdev->subsystem_device == 0x30ae)  		return; +	/* quirk for rs4xx HP Compaq dc5750 Small Form Factor to make it resume +	 * - it hangs on resume inside the dynclk 1 table. +	 */ +	if (rdev->family == CHIP_RS480 && +	    rdev->pdev->subsystem_vendor == 0x103c && +	    rdev->pdev->subsystem_device == 0x280a) +		return; +  	/* DYN CLK 1 */  	table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);  	if (table) diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c index fcbd60bb0349..3b0c229d7dcd 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_auxch.c +++ b/drivers/gpu/drm/radeon/radeon_dp_auxch.c @@ -116,8 +116,8 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg  	       AUX_SW_WR_BYTES(bytes));  	/* write the data header into the registers */ -	/* request, addres, msg size */ -	byte = (msg->request << 4); +	/* request, address, msg size */ +	byte = (msg->request << 4) | ((msg->address >> 16) & 0xf);  	WREG32(AUX_SW_DATA + aux_offset[instance],  	       AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 34b78e736532..5d8ae5e49c44 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -50,6 +50,8 @@  #define VOP_WIN_SET(x, win, name, v) \  		REG_SET(x, win->base, win->phy->name, v, RELAXED) +#define VOP_SCL_SET(x, win, name, v) \ +		REG_SET(x, win->base, win->phy->scl->name, v, RELAXED)  #define VOP_CTRL_SET(x, name, v) \  		REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL) @@ -164,7 +166,37 @@ struct vop_ctrl {  	struct vop_reg vpost_st_end;  }; +struct vop_scl_regs { +	struct vop_reg cbcr_vsd_mode; +	struct vop_reg cbcr_vsu_mode; +	struct vop_reg cbcr_hsd_mode; +	struct vop_reg cbcr_ver_scl_mode; +	struct vop_reg cbcr_hor_scl_mode; +	struct vop_reg yrgb_vsd_mode; +	struct vop_reg yrgb_vsu_mode; +	struct vop_reg yrgb_hsd_mode; +	struct vop_reg yrgb_ver_scl_mode; +	struct vop_reg yrgb_hor_scl_mode; +	struct vop_reg line_load_mode; +	struct vop_reg cbcr_axi_gather_num; +	struct vop_reg yrgb_axi_gather_num; +	struct vop_reg vsd_cbcr_gt2; +	struct vop_reg vsd_cbcr_gt4; +	struct vop_reg vsd_yrgb_gt2; +	struct vop_reg vsd_yrgb_gt4; +	struct vop_reg bic_coe_sel; +	struct vop_reg cbcr_axi_gather_en; +	struct vop_reg yrgb_axi_gather_en; + +	struct vop_reg lb_mode; +	struct vop_reg scale_yrgb_x; +	struct vop_reg scale_yrgb_y; +	struct vop_reg scale_cbcr_x; +	struct vop_reg scale_cbcr_y; +}; +  struct vop_win_phy { +	const struct vop_scl_regs *scl;  	const uint32_t *data_formats;  	uint32_t nformats; @@ -222,7 +254,36 @@ static const uint32_t formats_234[] = {  	DRM_FORMAT_BGR565,  }; +static const struct vop_scl_regs win_full_scl = { +	.cbcr_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 31), +	.cbcr_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 30), +	.cbcr_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 28), +	.cbcr_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 26), +	.cbcr_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 24), +	.yrgb_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 23), +	.yrgb_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 22), +	.yrgb_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 20), +	.yrgb_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 18), +	.yrgb_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 16), +	.line_load_mode = VOP_REG(WIN0_CTRL1, 0x1, 15), +	.cbcr_axi_gather_num = VOP_REG(WIN0_CTRL1, 0x7, 12), +	.yrgb_axi_gather_num = VOP_REG(WIN0_CTRL1, 0xf, 8), +	.vsd_cbcr_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 7), +	.vsd_cbcr_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 6), +	.vsd_yrgb_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 5), +	.vsd_yrgb_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 4), +	.bic_coe_sel = VOP_REG(WIN0_CTRL1, 0x3, 2), +	.cbcr_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 1), +	.yrgb_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 0), +	.lb_mode = VOP_REG(WIN0_CTRL0, 0x7, 5), +	.scale_yrgb_x = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), +	.scale_yrgb_y = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 16), +	.scale_cbcr_x = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), +	.scale_cbcr_y = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; +  static const struct vop_win_phy win01_data = { +	.scl = &win_full_scl,  	.data_formats = formats_01,  	.nformats = ARRAY_SIZE(formats_01),  	.enable = VOP_REG(WIN0_CTRL0, 0x1, 0), @@ -279,6 +340,12 @@ static const struct vop_reg_data vop_init_reg_table[] = {  	{DSP_CTRL0, 0x00000000},  	{WIN0_CTRL0, 0x00000080},  	{WIN1_CTRL0, 0x00000080}, +	/* TODO: Win2/3 support multiple area function, but we haven't found +	 * a suitable way to use it yet, so let's just use them as other windows +	 * with only area 0 enabled. +	 */ +	{WIN2_CTRL0, 0x00000010}, +	{WIN3_CTRL0, 0x00000010},  };  /* @@ -393,6 +460,18 @@ static enum vop_data_format vop_convert_format(uint32_t format)  	}  } +static bool is_yuv_support(uint32_t format) +{ +	switch (format) { +	case DRM_FORMAT_NV12: +	case DRM_FORMAT_NV16: +	case DRM_FORMAT_NV24: +		return true; +	default: +		return false; +	} +} +  static bool is_alpha_support(uint32_t format)  {  	switch (format) { @@ -404,6 +483,126 @@ static bool is_alpha_support(uint32_t format)  	}  } +static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, +				  uint32_t dst, bool is_horizontal, +				  int vsu_mode, int *vskiplines) +{ +	uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT; + +	if (is_horizontal) { +		if (mode == SCALE_UP) +			val = GET_SCL_FT_BIC(src, dst); +		else if (mode == SCALE_DOWN) +			val = GET_SCL_FT_BILI_DN(src, dst); +	} else { +		if (mode == SCALE_UP) { +			if (vsu_mode == SCALE_UP_BIL) +				val = GET_SCL_FT_BILI_UP(src, dst); +			else +				val = GET_SCL_FT_BIC(src, dst); +		} else if (mode == SCALE_DOWN) { +			if (vskiplines) { +				*vskiplines = scl_get_vskiplines(src, dst); +				val = scl_get_bili_dn_vskip(src, dst, +							    *vskiplines); +			} else { +				val = GET_SCL_FT_BILI_DN(src, dst); +			} +		} +	} + +	return val; +} + +static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, +			     uint32_t src_w, uint32_t src_h, uint32_t dst_w, +			     uint32_t dst_h, uint32_t pixel_format) +{ +	uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode; +	uint16_t cbcr_hor_scl_mode = SCALE_NONE; +	uint16_t cbcr_ver_scl_mode = SCALE_NONE; +	int hsub = drm_format_horz_chroma_subsampling(pixel_format); +	int vsub = drm_format_vert_chroma_subsampling(pixel_format); +	bool is_yuv = is_yuv_support(pixel_format); +	uint16_t cbcr_src_w = src_w / hsub; +	uint16_t cbcr_src_h = src_h / vsub; +	uint16_t vsu_mode; +	uint16_t lb_mode; +	uint32_t val; +	int vskiplines; + +	if (dst_w > 3840) { +		DRM_ERROR("Maximum destination width (3840) exceeded\n"); +		return; +	} + +	yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w); +	yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h); + +	if (is_yuv) { +		cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); +		cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); +		if (cbcr_hor_scl_mode == SCALE_DOWN) +			lb_mode = scl_vop_cal_lb_mode(dst_w, true); +		else +			lb_mode = scl_vop_cal_lb_mode(cbcr_src_w, true); +	} else { +		if (yrgb_hor_scl_mode == SCALE_DOWN) +			lb_mode = scl_vop_cal_lb_mode(dst_w, false); +		else +			lb_mode = scl_vop_cal_lb_mode(src_w, false); +	} + +	VOP_SCL_SET(vop, win, lb_mode, lb_mode); +	if (lb_mode == LB_RGB_3840X2) { +		if (yrgb_ver_scl_mode != SCALE_NONE) { +			DRM_ERROR("ERROR : not allow yrgb ver scale\n"); +			return; +		} +		if (cbcr_ver_scl_mode != SCALE_NONE) { +			DRM_ERROR("ERROR : not allow cbcr ver scale\n"); +			return; +		} +		vsu_mode = SCALE_UP_BIL; +	} else if (lb_mode == LB_RGB_2560X4) { +		vsu_mode = SCALE_UP_BIL; +	} else { +		vsu_mode = SCALE_UP_BIC; +	} + +	val = scl_vop_cal_scale(yrgb_hor_scl_mode, src_w, dst_w, +				true, 0, NULL); +	VOP_SCL_SET(vop, win, scale_yrgb_x, val); +	val = scl_vop_cal_scale(yrgb_ver_scl_mode, src_h, dst_h, +				false, vsu_mode, &vskiplines); +	VOP_SCL_SET(vop, win, scale_yrgb_y, val); + +	VOP_SCL_SET(vop, win, vsd_yrgb_gt4, vskiplines == 4); +	VOP_SCL_SET(vop, win, vsd_yrgb_gt2, vskiplines == 2); + +	VOP_SCL_SET(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode); +	VOP_SCL_SET(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode); +	VOP_SCL_SET(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL); +	VOP_SCL_SET(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL); +	VOP_SCL_SET(vop, win, yrgb_vsu_mode, vsu_mode); +	if (is_yuv) { +		val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w, +					dst_w, true, 0, NULL); +		VOP_SCL_SET(vop, win, scale_cbcr_x, val); +		val = scl_vop_cal_scale(cbcr_ver_scl_mode, cbcr_src_h, +					dst_h, false, vsu_mode, &vskiplines); +		VOP_SCL_SET(vop, win, scale_cbcr_y, val); + +		VOP_SCL_SET(vop, win, vsd_cbcr_gt4, vskiplines == 4); +		VOP_SCL_SET(vop, win, vsd_cbcr_gt2, vskiplines == 2); +		VOP_SCL_SET(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode); +		VOP_SCL_SET(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode); +		VOP_SCL_SET(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL); +		VOP_SCL_SET(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL); +		VOP_SCL_SET(vop, win, cbcr_vsu_mode, vsu_mode); +	} +} +  static void vop_dsp_hold_valid_irq_enable(struct vop *vop)  {  	unsigned long flags; @@ -478,6 +677,7 @@ static void vop_enable(struct drm_crtc *crtc)  		goto err_disable_aclk;  	} +	memcpy(vop->regs, vop->regsbak, vop->len);  	/*  	 * At here, vop clock & iommu is enable, R/W vop regs would be safe.  	 */ @@ -598,17 +798,22 @@ static int vop_update_plane_event(struct drm_plane *plane,  	struct vop *vop = to_vop(crtc);  	struct drm_gem_object *obj;  	struct rockchip_gem_object *rk_obj; +	struct drm_gem_object *uv_obj; +	struct rockchip_gem_object *rk_uv_obj;  	unsigned long offset;  	unsigned int actual_w;  	unsigned int actual_h;  	unsigned int dsp_stx;  	unsigned int dsp_sty;  	unsigned int y_vir_stride; +	unsigned int uv_vir_stride = 0;  	dma_addr_t yrgb_mst; +	dma_addr_t uv_mst = 0;  	enum vop_data_format format;  	uint32_t val;  	bool is_alpha;  	bool rb_swap; +	bool is_yuv;  	bool visible;  	int ret;  	struct drm_rect dest = { @@ -629,11 +834,15 @@ static int vop_update_plane_event(struct drm_plane *plane,  		.y2 = crtc->mode.vdisplay,  	};  	bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY; +	int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : +					DRM_PLANE_HELPER_NO_SCALING; +	int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : +					DRM_PLANE_HELPER_NO_SCALING;  	ret = drm_plane_helper_check_update(plane, crtc, fb,  					    &src, &dest, &clip, -					    DRM_PLANE_HELPER_NO_SCALING, -					    DRM_PLANE_HELPER_NO_SCALING, +					    min_scale, +					    max_scale,  					    can_position, false, &visible);  	if (ret)  		return ret; @@ -643,6 +852,8 @@ static int vop_update_plane_event(struct drm_plane *plane,  	is_alpha = is_alpha_support(fb->pixel_format);  	rb_swap = has_rb_swapped(fb->pixel_format); +	is_yuv = is_yuv_support(fb->pixel_format); +  	format = vop_convert_format(fb->pixel_format);  	if (format < 0)  		return format; @@ -655,19 +866,46 @@ static int vop_update_plane_event(struct drm_plane *plane,  	rk_obj = to_rockchip_obj(obj); +	if (is_yuv) { +		/* +		 * Src.x1 can be odd when do clip, but yuv plane start point +		 * need align with 2 pixel. +		 */ +		val = (src.x1 >> 16) % 2; +		src.x1 += val << 16; +		src.x2 += val << 16; +	} +  	actual_w = (src.x2 - src.x1) >> 16;  	actual_h = (src.y2 - src.y1) >> 16; -	crtc_x = max(0, crtc_x); -	crtc_y = max(0, crtc_y); -	dsp_stx = crtc_x + crtc->mode.htotal - crtc->mode.hsync_start; -	dsp_sty = crtc_y + crtc->mode.vtotal - crtc->mode.vsync_start; +	dsp_stx = dest.x1 + crtc->mode.htotal - crtc->mode.hsync_start; +	dsp_sty = dest.y1 + crtc->mode.vtotal - crtc->mode.vsync_start; -	offset = (src.x1 >> 16) * (fb->bits_per_pixel >> 3); +	offset = (src.x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);  	offset += (src.y1 >> 16) * fb->pitches[0]; -	yrgb_mst = rk_obj->dma_addr + offset; -	y_vir_stride = fb->pitches[0] / (fb->bits_per_pixel >> 3); +	yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; +	y_vir_stride = fb->pitches[0] >> 2; + +	if (is_yuv) { +		int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); +		int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); +		int bpp = drm_format_plane_cpp(fb->pixel_format, 1); + +		uv_obj = rockchip_fb_get_gem_obj(fb, 1); +		if (!uv_obj) { +			DRM_ERROR("fail to get uv object from framebuffer\n"); +			return -EINVAL; +		} +		rk_uv_obj = to_rockchip_obj(uv_obj); +		uv_vir_stride = fb->pitches[1] >> 2; + +		offset = (src.x1 >> 16) * bpp / hsub; +		offset += (src.y1 >> 16) * fb->pitches[1] / vsub; + +		uv_mst = rk_uv_obj->dma_addr + offset + fb->offsets[1]; +	}  	/*  	 * If this plane update changes the plane's framebuffer, (or more @@ -704,9 +942,22 @@ static int vop_update_plane_event(struct drm_plane *plane,  	VOP_WIN_SET(vop, win, format, format);  	VOP_WIN_SET(vop, win, yrgb_vir, y_vir_stride);  	VOP_WIN_SET(vop, win, yrgb_mst, yrgb_mst); +	if (is_yuv) { +		VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride); +		VOP_WIN_SET(vop, win, uv_mst, uv_mst); +	} + +	if (win->phy->scl) +		scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, +				    dest.x2 - dest.x1, dest.y2 - dest.y1, +				    fb->pixel_format); +  	val = (actual_h - 1) << 16;  	val |= (actual_w - 1) & 0xffff;  	VOP_WIN_SET(vop, win, act_info, val); + +	val = (dest.y2 - dest.y1 - 1) << 16; +	val |= (dest.x2 - dest.x1 - 1) & 0xffff;  	VOP_WIN_SET(vop, win, dsp_info, val);  	val = (dsp_sty - 1) << 16;  	val |= (dsp_stx - 1) & 0xffff; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 63e9b3a084c5..a2d4ddb896fa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -198,4 +198,92 @@ enum factor_mode {  	ALPHA_SRC_GLOBAL,  }; +enum scale_mode { +	SCALE_NONE = 0x0, +	SCALE_UP   = 0x1, +	SCALE_DOWN = 0x2 +}; + +enum lb_mode { +	LB_YUV_3840X5 = 0x0, +	LB_YUV_2560X8 = 0x1, +	LB_RGB_3840X2 = 0x2, +	LB_RGB_2560X4 = 0x3, +	LB_RGB_1920X5 = 0x4, +	LB_RGB_1280X8 = 0x5 +}; + +enum sacle_up_mode { +	SCALE_UP_BIL = 0x0, +	SCALE_UP_BIC = 0x1 +}; + +enum scale_down_mode { +	SCALE_DOWN_BIL = 0x0, +	SCALE_DOWN_AVG = 0x1 +}; + +#define FRAC_16_16(mult, div)    (((mult) << 16) / (div)) +#define SCL_FT_DEFAULT_FIXPOINT_SHIFT	12 +#define SCL_MAX_VSKIPLINES		4 +#define MIN_SCL_FT_AFTER_VSKIP		1 + +static inline uint16_t scl_cal_scale(int src, int dst, int shift) +{ +	return ((src * 2 - 3) << (shift - 1)) / (dst - 1); +} + +#define GET_SCL_FT_BILI_DN(src, dst)	scl_cal_scale(src, dst, 12) +#define GET_SCL_FT_BILI_UP(src, dst)	scl_cal_scale(src, dst, 16) +#define GET_SCL_FT_BIC(src, dst)	scl_cal_scale(src, dst, 16) + +static inline uint16_t scl_get_bili_dn_vskip(int src_h, int dst_h, +					     int vskiplines) +{ +	int act_height; + +	act_height = (src_h + vskiplines - 1) / vskiplines; + +	return GET_SCL_FT_BILI_DN(act_height, dst_h); +} + +static inline enum scale_mode scl_get_scl_mode(int src, int dst) +{ +	if (src < dst) +		return SCALE_UP; +	else if (src > dst) +		return SCALE_DOWN; + +	return SCALE_NONE; +} + +static inline int scl_get_vskiplines(uint32_t srch, uint32_t dsth) +{ +	uint32_t vskiplines; + +	for (vskiplines = SCL_MAX_VSKIPLINES; vskiplines > 1; vskiplines /= 2) +		if (srch >= vskiplines * dsth * MIN_SCL_FT_AFTER_VSKIP) +			break; + +	return vskiplines; +} + +static inline int scl_vop_cal_lb_mode(int width, bool is_yuv) +{ +	int lb_mode; + +	if (width > 2560) +		lb_mode = LB_RGB_3840X2; +	else if (width > 1920) +		lb_mode = LB_RGB_2560X4; +	else if (!is_yuv) +		lb_mode = LB_RGB_1920X5; +	else if (width > 1280) +		lb_mode = LB_YUV_3840X5; +	else +		lb_mode = LB_YUV_2560X8; + +	return lb_mode; +} +  #endif /* _ROCKCHIP_DRM_VOP_H */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 03854d606d58..e13b20bd9908 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1052,10 +1052,15 @@ static struct vmw_master *vmw_master_check(struct drm_device *dev,  	}  	/* -	 * Check if we were previously master, but now dropped. +	 * Check if we were previously master, but now dropped. In that +	 * case, allow at least render node functionality.  	 */  	if (vmw_fp->locked_master) {  		mutex_unlock(&dev->master_mutex); + +		if (flags & DRM_RENDER_ALLOW) +			return NULL; +  		DRM_ERROR("Dropped master trying to access ioctl that "  			  "requires authentication.\n");  		return ERR_PTR(-EACCES); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 5b8595b78429..3361769842f4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -911,6 +911,12 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,  				  "surface reference.\n");  			return -EACCES;  		} +		if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) { +			DRM_ERROR("Locked master refused legacy " +				  "surface reference.\n"); +			return -EACCES; +		} +  		handle = u_handle;  	}  | 
