diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 170 | 
1 files changed, 147 insertions, 23 deletions
| diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 1b4ad9b2a755..400fc74bbae2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -111,9 +111,10 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)  			version_major, version_minor, family_id);  	} -	bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) -		  +  AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_HEAP_SIZE +	bo_size = AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_HEAP_SIZE  		  +  AMDGPU_VCN_SESSION_SIZE * 40; +	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) +		bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);  	r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,  				    AMDGPU_GEM_DOMAIN_VRAM, &adev->vcn.vcpu_bo,  				    &adev->vcn.gpu_addr, &adev->vcn.cpu_addr); @@ -129,7 +130,7 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)  {  	int i; -	kfree(adev->vcn.saved_bo); +	kvfree(adev->vcn.saved_bo);  	amdgpu_bo_free_kernel(&adev->vcn.vcpu_bo,  			      &adev->vcn.gpu_addr, @@ -140,6 +141,8 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)  	for (i = 0; i < adev->vcn.num_enc_rings; ++i)  		amdgpu_ring_fini(&adev->vcn.ring_enc[i]); +	amdgpu_ring_fini(&adev->vcn.ring_jpeg); +  	release_firmware(adev->vcn.fw);  	return 0; @@ -150,15 +153,15 @@ int amdgpu_vcn_suspend(struct amdgpu_device *adev)  	unsigned size;  	void *ptr; +	cancel_delayed_work_sync(&adev->vcn.idle_work); +  	if (adev->vcn.vcpu_bo == NULL)  		return 0; -	cancel_delayed_work_sync(&adev->vcn.idle_work); -  	size = amdgpu_bo_size(adev->vcn.vcpu_bo);  	ptr = adev->vcn.cpu_addr; -	adev->vcn.saved_bo = kmalloc(size, GFP_KERNEL); +	adev->vcn.saved_bo = kvmalloc(size, GFP_KERNEL);  	if (!adev->vcn.saved_bo)  		return -ENOMEM; @@ -180,18 +183,20 @@ int amdgpu_vcn_resume(struct amdgpu_device *adev)  	if (adev->vcn.saved_bo != NULL) {  		memcpy_toio(ptr, adev->vcn.saved_bo, size); -		kfree(adev->vcn.saved_bo); +		kvfree(adev->vcn.saved_bo);  		adev->vcn.saved_bo = NULL;  	} else {  		const struct common_firmware_header *hdr;  		unsigned offset;  		hdr = (const struct common_firmware_header *)adev->vcn.fw->data; -		offset = le32_to_cpu(hdr->ucode_array_offset_bytes); -		memcpy_toio(adev->vcn.cpu_addr, adev->vcn.fw->data + offset, -			    le32_to_cpu(hdr->ucode_size_bytes)); -		size -= le32_to_cpu(hdr->ucode_size_bytes); -		ptr += le32_to_cpu(hdr->ucode_size_bytes); +		if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { +			offset = le32_to_cpu(hdr->ucode_array_offset_bytes); +			memcpy_toio(adev->vcn.cpu_addr, adev->vcn.fw->data + offset, +				    le32_to_cpu(hdr->ucode_size_bytes)); +			size -= le32_to_cpu(hdr->ucode_size_bytes); +			ptr += le32_to_cpu(hdr->ucode_size_bytes); +		}  		memset_io(ptr, 0, size);  	} @@ -209,6 +214,8 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work)  		fences += amdgpu_fence_count_emitted(&adev->vcn.ring_enc[i]);  	} +	fences += amdgpu_fence_count_emitted(&adev->vcn.ring_jpeg); +  	if (fences == 0) {  		if (adev->pm.dpm_enabled)  			amdgpu_dpm_enable_uvd(adev, false); @@ -225,7 +232,7 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)  	struct amdgpu_device *adev = ring->adev;  	bool set_clocks = !cancel_delayed_work_sync(&adev->vcn.idle_work); -	if (set_clocks && adev->pm.dpm_enabled) { +	if (set_clocks) {  		if (adev->pm.dpm_enabled)  			amdgpu_dpm_enable_uvd(adev, true);  		else @@ -304,13 +311,10 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,  	}  	ib->length_dw = 16; -	r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); -	job->fence = dma_fence_get(f); +	r = amdgpu_job_submit_direct(job, ring, &f);  	if (r)  		goto err_free; -	amdgpu_job_free(job); -  	amdgpu_bo_fence(bo, f, false);  	amdgpu_bo_unreserve(bo);  	amdgpu_bo_unref(&bo); @@ -495,12 +499,10 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand  	for (i = ib->length_dw; i < ib_size_dw; ++i)  		ib->ptr[i] = 0x0; -	r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); -	job->fence = dma_fence_get(f); +	r = amdgpu_job_submit_direct(job, ring, &f);  	if (r)  		goto err; -	amdgpu_job_free(job);  	if (fence)  		*fence = dma_fence_get(f);  	dma_fence_put(f); @@ -549,12 +551,10 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han  	for (i = ib->length_dw; i < ib_size_dw; ++i)  		ib->ptr[i] = 0x0; -	r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); -	job->fence = dma_fence_get(f); +	r = amdgpu_job_submit_direct(job, ring, &f);  	if (r)  		goto err; -	amdgpu_job_free(job);  	if (fence)  		*fence = dma_fence_get(f);  	dma_fence_put(f); @@ -597,3 +597,127 @@ error:  	dma_fence_put(fence);  	return r;  } + +int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring) +{ +	struct amdgpu_device *adev = ring->adev; +	uint32_t tmp = 0; +	unsigned i; +	int r; + +	WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0xCAFEDEAD); +	r = amdgpu_ring_alloc(ring, 3); + +	if (r) { +		DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", +				  ring->idx, r); +		return r; +	} + +	amdgpu_ring_write(ring, +		PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0, 0, 0)); +	amdgpu_ring_write(ring, 0xDEADBEEF); +	amdgpu_ring_commit(ring); + +	for (i = 0; i < adev->usec_timeout; i++) { +		tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID)); +		if (tmp == 0xDEADBEEF) +			break; +		DRM_UDELAY(1); +	} + +	if (i < adev->usec_timeout) { +		DRM_DEBUG("ring test on %d succeeded in %d usecs\n", +				  ring->idx, i); +	} else { +		DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n", +				  ring->idx, tmp); +		r = -EINVAL; +	} + +	return r; +} + +static int amdgpu_vcn_jpeg_set_reg(struct amdgpu_ring *ring, uint32_t handle, +		struct dma_fence **fence) +{ +	struct amdgpu_device *adev = ring->adev; +	struct amdgpu_job *job; +	struct amdgpu_ib *ib; +	struct dma_fence *f = NULL; +	const unsigned ib_size_dw = 16; +	int i, r; + +	r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); +	if (r) +		return r; + +	ib = &job->ibs[0]; + +	ib->ptr[0] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH), 0, 0, PACKETJ_TYPE0); +	ib->ptr[1] = 0xDEADBEEF; +	for (i = 2; i < 16; i += 2) { +		ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); +		ib->ptr[i+1] = 0; +	} +	ib->length_dw = 16; + +	r = amdgpu_job_submit_direct(job, ring, &f); +	if (r) +		goto err; + +	if (fence) +		*fence = dma_fence_get(f); +	dma_fence_put(f); + +	return 0; + +err: +	amdgpu_job_free(job); +	return r; +} + +int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout) +{ +	struct amdgpu_device *adev = ring->adev; +	uint32_t tmp = 0; +	unsigned i; +	struct dma_fence *fence = NULL; +	long r = 0; + +	r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence); +	if (r) { +		DRM_ERROR("amdgpu: failed to set jpeg register (%ld).\n", r); +		goto error; +	} + +	r = dma_fence_wait_timeout(fence, false, timeout); +	if (r == 0) { +		DRM_ERROR("amdgpu: IB test timed out.\n"); +		r = -ETIMEDOUT; +		goto error; +	} else if (r < 0) { +		DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); +		goto error; +	} else +		r = 0; + +	for (i = 0; i < adev->usec_timeout; i++) { +		tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH)); +		if (tmp == 0xDEADBEEF) +			break; +		DRM_UDELAY(1); +	} + +	if (i < adev->usec_timeout) +		DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx); +	else { +		DRM_ERROR("ib test failed (0x%08X)\n", tmp); +		r = -EINVAL; +	} + +	dma_fence_put(fence); + +error: +	return r; +} |